/*********************************************************************** * Copyright (c) 2006-2007 The Apache Software Foundation. * * All rights reserved. * * ------------------------------------------------------------------- * * Licensed under the Apache License, Version 2.0 (the "License"); you * * may not use this file except in compliance with the License. You * * may obtain a copy of the License at: * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * * implied. See the License for the specific language governing * * permissions and limitations under the License. * ***********************************************************************/ package org.apache.vysper.xmpp.protocol; import junit.framework.TestCase; import org.apache.vysper.xml.fragment.XMLElement; import org.apache.vysper.xml.fragment.XMLElementVerifier; import org.apache.vysper.xml.fragment.XMLSemanticError; import org.apache.vysper.xmpp.addressing.Entity; import org.apache.vysper.xmpp.addressing.EntityImpl; import org.apache.vysper.xmpp.delivery.StanzaReceiverRelay; import org.apache.vysper.xmpp.server.DefaultServerRuntimeContext; import org.apache.vysper.xmpp.server.SessionState; import org.apache.vysper.xmpp.server.TestSessionContext; import org.apache.vysper.xmpp.stanza.IQStanza; import org.apache.vysper.xmpp.stanza.IQStanzaType; import org.apache.vysper.xmpp.stanza.Stanza; import org.apache.vysper.xmpp.stanza.StanzaBuilder; import org.apache.vysper.xmpp.stanza.XMPPCoreStanza; import org.apache.vysper.xmpp.state.resourcebinding.BindException; /** * test basic behavior of ProtocolWorker.processStanza() */ public class ProtocolWorkerProcessTestCase extends TestCase { private ProtocolWorker protocolWorker; private NamespaceHandlerDictionary namespaceHandlerDictionary; private DefaultServerRuntimeContext serverRuntimeContext; private TestSessionContext sessionContext; private static Entity serverEnitity = new EntityImpl(null, "test", null); private SessionStateHolder sessionStateHolder; @Override protected void setUp() throws Exception { super.setUp(); protocolWorker = new ProtocolWorker(); namespaceHandlerDictionary = new NamespaceHandlerDictionary("testNSURI"); StanzaReceiverRelay receiverRelay = new StanzaReceiverRelay(); serverRuntimeContext = new DefaultServerRuntimeContext(serverEnitity, receiverRelay); receiverRelay.setServerRuntimeContext(serverRuntimeContext); serverRuntimeContext.addDictionary(namespaceHandlerDictionary); sessionStateHolder = new SessionStateHolder(); sessionContext = new TestSessionContext(serverRuntimeContext, sessionStateHolder); } public void testProcessUnknownStanza() { sessionContext.setSessionState(SessionState.AUTHENTICATED); Stanza stanza = new StanzaBuilder("ProtocolWorkerProcessTestCase", "testNSURI").build(); protocolWorker.processStanza(sessionContext.getServerRuntimeContext(), sessionContext, stanza, sessionStateHolder); Stanza recordedResponse = sessionContext.getNextRecordedResponse(); XMLElementVerifier verifier = recordedResponse.getVerifier(); assertTrue("error", verifier.nameEquals("error")); assertTrue("unsupported stanza type", verifier.subElementPresent(StreamErrorCondition.UNSUPPORTED_STANZA_TYPE .value())); } public void testProcessStanzaNoResponse() { sessionContext.setSessionState(SessionState.AUTHENTICATED); CallTestStanzaHandler stanzaHandler = new CallTestStanzaHandler("ProtocolWorkerProcessTestCase"); namespaceHandlerDictionary.register(stanzaHandler); Stanza stanza = new StanzaBuilder("ProtocolWorkerProcessTestCase", "testNSURI").build(); protocolWorker.processStanza(sessionContext.getServerRuntimeContext(), sessionContext, stanza, sessionStateHolder); stanzaHandler.assertHandlerCalled(); Stanza recordedResponse = sessionContext.getNextRecordedResponse(); assertNull("no emmitter, no response", recordedResponse); } public void testProcessStanzaWithResponse() { sessionContext.setSessionState(SessionState.AUTHENTICATED); CallTestStanzaHandlerResponse stanzaHandler = new CallTestStanzaHandlerResponse("ProtocolWorkerProcessTestCase"); namespaceHandlerDictionary.register(stanzaHandler); Stanza stanza = new StanzaBuilder("ProtocolWorkerProcessTestCase", "testNSURI").build(); Stanza responseStanza = new StanzaBuilder("response").build(); stanzaHandler.setResponseStanza(responseStanza); protocolWorker.processStanza(sessionContext.getServerRuntimeContext(), sessionContext, stanza, sessionStateHolder); stanzaHandler.assertHandlerCalled(); Stanza recordedResponse = sessionContext.getNextRecordedResponse(); assertEquals("response handled", responseStanza, recordedResponse); stanzaHandler.setResponseStanza(null); protocolWorker.processStanza(sessionContext.getServerRuntimeContext(), sessionContext, stanza, sessionStateHolder); assertNull("handler emmitted null as response", stanzaHandler.getResponseStanza()); } public void testHandlerThrowProtocolException() { sessionContext.setSessionState(SessionState.AUTHENTICATED); CallTestStanzaHandler stanzaHandler = new CallTestStanzaHandler("ProtocolWorkerProcessTestCase"); namespaceHandlerDictionary.register(stanzaHandler); stanzaHandler.setProtocolException(new ProtocolException("forced error")); Stanza stanza = new StanzaBuilder("ProtocolWorkerProcessTestCase", "testNSURI").build(); protocolWorker.processStanza(sessionContext.getServerRuntimeContext(), sessionContext, stanza, sessionStateHolder); Stanza recordedResponse = sessionContext.getNextRecordedResponse(); assertEquals("bad format", "error", recordedResponse.getName()); assertTrue("closed", sessionContext.isClosed()); } public void testProcessWrongStartStanza() { sessionContext.setSessionState(SessionState.INITIATED); CallTestStanzaHandler stanzaHandler = new CallTestStanzaHandler("ProtocolWorkerProcessTestCase"); namespaceHandlerDictionary.register(stanzaHandler); Stanza stanza = new StanzaBuilder("ProtocolWorkerProcessTestCase", "testNSURI").build(); protocolWorker.processStanza(sessionContext.getServerRuntimeContext(), sessionContext, stanza, sessionStateHolder); try { stanzaHandler.assertHandlerCalled(); fail("handler called"); } catch (Exception e) { // not called, OK } Stanza recordedResponse = sessionContext.getNextRecordedResponse(); assertEquals("open stream", "stream", recordedResponse.getName()); XMLElementVerifier xmlElementVerifier = recordedResponse.getVerifier(); assertTrue("error embedded", xmlElementVerifier.subElementPresent("error")); XMLElement error = (XMLElement) recordedResponse.getInnerFragments().get(0); assertEquals("bad format", "error", error.getName()); assertTrue("closed", sessionContext.isClosed()); } public void testDetectWrongFromAddress() throws XMLSemanticError { Entity server = sessionContext.getServerRuntimeContext().getServerEnitity(); sessionContext.setSessionState(SessionState.AUTHENTICATED); // the session is running for 'mark' sessionContext.setInitiatingEntity(new EntityImpl("mark", server.getDomain(), null)); CallTestStanzaHandler stanzaHandler = new CallTestStanzaHandler("iq"); namespaceHandlerDictionary.register(stanzaHandler); StanzaBuilder stanzaBuilder = StanzaBuilder.createIQStanza(null, null, IQStanzaType.GET, "test"); // we set a different from user name 'ernest'! stanzaBuilder.addAttribute("from", new EntityImpl("ernest", server.getDomain(), null).getFullQualifiedName()); stanzaBuilder.startInnerElement("query", "jabber:iq:roster").endInnerElement(); protocolWorker.processStanza(sessionContext.getServerRuntimeContext(), sessionContext, stanzaBuilder.build(), sessionStateHolder); try { stanzaHandler.assertHandlerCalled(); fail("handler called"); } catch (Exception e) { // not called, OK } Stanza recordedResponse = sessionContext.getNextRecordedResponse(); assertUnknownSenderError(recordedResponse); } public void testAllowProperFromResourceId() throws XMLSemanticError, BindException { Entity server = sessionContext.getServerRuntimeContext().getServerEnitity(); sessionContext.setSessionState(SessionState.AUTHENTICATED); // the session is running for 'charlotte' sessionContext.setInitiatingEntity(new EntityImpl("charlotte", server.getDomain(), null)); CallTestStanzaHandler stanzaHandler = new CallTestStanzaHandler("iq", "testNSURI"); namespaceHandlerDictionary.register(stanzaHandler); String onlyBoundResource = sessionContext.bindResource(); StanzaBuilder stanzaBuilder = StanzaBuilder.createIQStanza(null, null, IQStanzaType.GET, "test"); stanzaBuilder.addAttribute("from", new EntityImpl("charlotte", server.getDomain(), onlyBoundResource) .getFullQualifiedName()); stanzaBuilder.startInnerElement("query", "testNSURI").endInnerElement(); protocolWorker.processStanza(sessionContext.getServerRuntimeContext(), sessionContext, stanzaBuilder.build(), sessionStateHolder); stanzaHandler.assertHandlerCalled(); } public void testDetectWrongFromResourceId() throws XMLSemanticError, BindException { Entity server = sessionContext.getServerRuntimeContext().getServerEnitity(); sessionContext.setSessionState(SessionState.AUTHENTICATED); // the session is running for 'charlotte' sessionContext.setInitiatingEntity(new EntityImpl("charlotte", server.getDomain(), null)); CallTestStanzaHandler stanzaHandler = new CallTestStanzaHandler("iq", "testNSURI"); namespaceHandlerDictionary.register(stanzaHandler); String onlyBoundResource = sessionContext.bindResource(); String arbitraryUnboundResource = "unboundResourceID"; StanzaBuilder stanzaBuilder = StanzaBuilder.createIQStanza(null, null, IQStanzaType.GET, "test"); stanzaBuilder.addAttribute("from", new EntityImpl("charlotte", server.getDomain(), arbitraryUnboundResource) .getFullQualifiedName()); stanzaBuilder.startInnerElement("query", "testNSURI").endInnerElement(); protocolWorker.processStanza(sessionContext.getServerRuntimeContext(), sessionContext, stanzaBuilder.build(), sessionStateHolder); try { stanzaHandler.assertHandlerCalled(); fail("handler called"); } catch (Exception e) { // not called, OK } Stanza recordedResponse = sessionContext.getNextRecordedResponse(); assertUnknownSenderError(recordedResponse); } public void testAllowBareFromEntityOnlyOnSingleBoundResource() throws XMLSemanticError, BindException { // from="client@vysper.org" is only allowed when a single resource is bound // if there is more than one resource bound in the same session, from must come // fully qualified, e.g. from="client@vysper.org/resourceId" Entity server = sessionContext.getServerRuntimeContext().getServerEnitity(); sessionContext.setSessionState(SessionState.AUTHENTICATED); // the session is running for 'lea' sessionContext.setInitiatingEntity(new EntityImpl("lea", server.getDomain(), null)); CallTestStanzaHandler stanzaHandler = new CallTestStanzaHandler("iq", "testNSURI"); namespaceHandlerDictionary.register(stanzaHandler); String firstBoundResource = sessionContext.bindResource(); String secondBoundResource = sessionContext.bindResource(); StanzaBuilder stanzaBuilder = StanzaBuilder.createIQStanza(null, null, IQStanzaType.GET, "test"); stanzaBuilder.addAttribute("from", new EntityImpl("lea", server.getDomain(), null).getFullQualifiedName()); stanzaBuilder.startInnerElement("query", "testNSURI").endInnerElement(); protocolWorker.processStanza(sessionContext.getServerRuntimeContext(), sessionContext, stanzaBuilder.build(), sessionStateHolder); Stanza recordedResponse = sessionContext.getNextRecordedResponse(); assertUnknownSenderError(recordedResponse); // not allowed, bare id without resource and two resources bound sessionContext.reset(); // unbind second resource, leaving only one boolean noResourceRemains = sessionContext.getServerRuntimeContext().getResourceRegistry().unbindResource( secondBoundResource); assertFalse(noResourceRemains); // bare id allowed, only one resource is bound stanzaBuilder = StanzaBuilder.createIQStanza(null, null, IQStanzaType.GET, "test"); stanzaBuilder.addAttribute("from", new EntityImpl("lea", server.getDomain(), null).getFullQualifiedName()); stanzaBuilder.startInnerElement("query", "testNSURI").endInnerElement(); protocolWorker.processStanza(sessionContext.getServerRuntimeContext(), sessionContext, stanzaBuilder.build(), sessionStateHolder); stanzaHandler.assertHandlerCalled(); sessionContext.reset(); // second resource is now invalid and cannot be used anymore in a full qualified entity stanzaBuilder = StanzaBuilder.createIQStanza(null, null, IQStanzaType.GET, "test"); stanzaBuilder.addAttribute("from", new EntityImpl("lea", server.getDomain(), secondBoundResource) .getFullQualifiedName()); stanzaBuilder.startInnerElement("query", "testNSURI").endInnerElement(); protocolWorker.processStanza(sessionContext.getServerRuntimeContext(), sessionContext, stanzaBuilder.build(), sessionStateHolder); recordedResponse = sessionContext.getNextRecordedResponse(); assertUnknownSenderError(recordedResponse); } private void assertUnknownSenderError(Stanza recordedResponse) throws XMLSemanticError { XMLElementVerifier verifier = recordedResponse.getVerifier(); assertEquals("iq stanza error", "iq", recordedResponse.getName()); IQStanza iqStanza = (IQStanza) XMPPCoreStanza.getWrapper(recordedResponse); assertEquals("error", iqStanza.getType()); assertTrue("error embedded", verifier.subElementPresent("error")); XMLElement errorInner = recordedResponse.getSingleInnerElementsNamed("error"); assertEquals("modify", errorInner.getAttributeValue("type")); XMLElementVerifier errorVerifier = errorInner.getVerifier(); errorVerifier.subElementPresent("unknown-sender"); } }