powered by Jive Software

Problem with initial connection

I am having a problem with some integration testing that I am trying to run. I have a simple test case to make sure the server is responding with a “stream:error” of “host-unknown” when an invalid service name is given to the XMPP server. What I am seeing is that the XMPPConnection is saying that the connection has been established properly even though there was an error during the connection.

Here is my test case:

@Test
     public void testConnection_InvalidServiceName() {
          // mock
          ConnectionCreationListener connectionCreationListener = mock(ConnectionCreationListener.class);

          // setup
          ConnectionConfiguration connectionConfiguration = new ConnectionConfiguration("localhost", 5222, "invalid.com");
          XMPPConnection xmppConnection = new XMPPConnection(connectionConfiguration);
          
          XMPPConnection.addConnectionCreationListener(connectionCreationListener);

          // execute
          try {
               xmppConnection.connect();

               // assert
               assertThat(xmppConnection.isConnected(), is(false));
               verify(connectionCreationListener, never()).connectionCreated(xmppConnection);
          } catch (XMPPException e) {
               e.printStackTrace();
               fail("Unable to connect");
          }
     }

Within this test the xmppConnection.isConnected() assertion is failing because the method is returning true. At the same time the connectionCreationListener is being called stating that the connection was created.

Looking into the Smack code I see that within the XMPPConnection.initConnection() there is the packetWriter.startup() and during the startup the code gets to the PacketWriter.writePackets(). Within this method there is the openStream() method. This is the method that sends the XMPP initial stream:stream xml that includes the service name that was provided. This is the message to the server that is causing the stream:error to be returned from the XMPP server.

That part of the code is doing what it should as that is part of the XMPP specification. Where things break is the few lines later within the XMPPConnection.initConnection(). After the startup of the PacketWriter there is a call for PacketReader.startup(). Within this method it starts up the readerThread that listens for incoming packet data from the server. It then goes into a wait for 5 seconds to make sure that the connection is established. In the normal case when a valid session name is provided the PacketReader class would process the returned stream:stream from the server within the parsePackets() and assign the connectionID. During this it also releases the Semaphore that the PacketReader created during the startup(). When a stream:error is returned from the server the parsePackets() method throws an XMPPException but doesn’t release the Semaphore. So the startup() waits the full 5 seconds. When the wait finishes there is the check on the connectionID. With the stream:error the connectionID gets assigned an error string and not a valid connectionID. So the startup() method finishes without throwing an exception and then the XMPPConnection.initConnection() continues and assigns the connected = true.

What I see as needing to happen is that the parsePackets() needs to know if the stream:error is occuring during the initial connection. If the error does occur on the initial connection then it should release the Semaphore as well as making sure the connectionID stays null. That way the PacketReader.startup() will throw an exception that in turn causes the connected not to get assigned and the client code can catch the exception and know that there was a problem during the connection.

If this is at all unclear or you would like more information then please feel free to respond and I will assist where possible.