package org.marketcetera.saclient; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import java.util.Arrays; import org.hamcrest.Matchers; import org.junit.*; import org.marketcetera.core.LoggerConfiguration; import org.marketcetera.core.Util; import org.marketcetera.core.VersionInfo; import org.marketcetera.module.ExpectedFailure; import org.marketcetera.util.misc.ClassVersion; /* $License$ */ /** * Tests aspects of {@link SAClient} related to it's ability to connect * with the remote strategy agent. * * @author anshul@marketcetera.com * @version $Id: SAClientConnectionTest.java 16881 2014-04-15 23:39:25Z colin $ * @since 2.0.0 */ @ClassVersion("$Id: SAClientConnectionTest.java 16881 2014-04-15 23:39:25Z colin $") public class SAClientConnectionTest { /** * verifies behavior of Web services after the connection to the client * has been closed. * * @throws Exception if there were unexpected failures. */ @Test public void closedFailures() throws Exception { final SAClient saclient = MockStrategyAgent.connectTo(); //Close the connection saclient.close(); //verify that the saclient fails all API invocations new DisconnectedFailure() { @Override protected void run() throws Exception { saclient.createStrategy(null); } }; new DisconnectedFailure() { @Override protected void run() throws Exception { saclient.delete(null); } }; new DisconnectedFailure() { @Override protected void run() throws Exception { saclient.getInstances(null); } }; new DisconnectedFailure() { @Override protected void run() throws Exception { saclient.getModuleInfo(null); } }; new DisconnectedFailure() { @Override protected void run() throws Exception { saclient.getProperties(null); } }; new DisconnectedFailure() { @Override protected void run() throws Exception { saclient.getProviders(); } }; new DisconnectedFailure() { @Override protected void run() throws Exception { saclient.getStrategyCreateParms(null); } }; new DisconnectedFailure() { @Override protected void run() throws Exception { saclient.setProperties(null, null); } }; new DisconnectedFailure() { @Override protected void run() throws Exception { saclient.start(null); } }; new DisconnectedFailure() { @Override protected void run() throws Exception { saclient.stop(null); } }; //These methods can be invoked even when the client is not connected. SAClientTestBase.MyConnectionStatusListener listener = new SAClientTestBase.MyConnectionStatusListener(); saclient.addConnectionStatusListener(listener); saclient.removeConnectionStatusListener(listener); SAClientTestBase.MyDataReceiver receiver = new SAClientTestBase.MyDataReceiver(); saclient.addDataReceiver(receiver); saclient.removeDataReciever(receiver); verifyParameters(MockStrategyAgent.DEFAULT_PARAMETERS, saclient.getParameters()); //We can close it again if we want saclient.close(); } /** * Verifies the behavior of services after the client gets disconnected. * * @throws Exception if there unexpected errors. */ @Test public void disconnectedFailures() throws Exception { final SAClient saclient = MockStrategyAgent.connectTo(); SAClientTestBase.MyConnectionStatusListener listener = new SAClientTestBase.MyConnectionStatusListener(); saclient.addConnectionStatusListener(listener); listener.reset(); //stop the agent to force disconnection stopAgent(); //wait until the notification has been processed assertFalse(listener.getNext()); //verify that the saclient fails all API invocations new DisconnectedFailure() { @Override protected void run() throws Exception { saclient.createStrategy(null); } }; new DisconnectedFailure() { @Override protected void run() throws Exception { saclient.delete(null); } }; new DisconnectedFailure() { @Override protected void run() throws Exception { saclient.getInstances(null); } }; new DisconnectedFailure() { @Override protected void run() throws Exception { saclient.getModuleInfo(null); } }; new DisconnectedFailure() { @Override protected void run() throws Exception { saclient.getProperties(null); } }; new DisconnectedFailure() { @Override protected void run() throws Exception { saclient.getProviders(); } }; new DisconnectedFailure() { @Override protected void run() throws Exception { saclient.getStrategyCreateParms(null); } }; new DisconnectedFailure() { @Override protected void run() throws Exception { saclient.setProperties(null, null); } }; new DisconnectedFailure() { @Override protected void run() throws Exception { saclient.start(null); } }; new DisconnectedFailure() { @Override protected void run() throws Exception { saclient.stop(null); } }; //These methods can be invoked even when the client is not connected. saclient.addConnectionStatusListener(listener); saclient.removeConnectionStatusListener(listener); SAClientTestBase.MyDataReceiver receiver = new SAClientTestBase.MyDataReceiver(); saclient.addDataReceiver(receiver); saclient.removeDataReciever(receiver); verifyParameters(MockStrategyAgent.DEFAULT_PARAMETERS, saclient.getParameters()); //We can close it again if we want saclient.close(); } /** * Tests the behavior when null listeners are added / removed. * * @throws Exception if there were unexpected exceptions. */ @Test public void nullListeners() throws Exception { final SAClient saclient = MockStrategyAgent.connectTo(); new ExpectedFailure<NullPointerException>(){ @Override protected void run() throws Exception { saclient.addConnectionStatusListener(null); } }; new ExpectedFailure<NullPointerException>(){ @Override protected void run() throws Exception { saclient.removeConnectionStatusListener(null); } }; saclient.close(); } /** * Verifies that connection notifications are delivered when * the connection fails or is closed. * * @throws Exception if there were unexpected errors. */ @Test(timeout = 100000) public void connectionNotifications() throws Exception { SAClient client = MockStrategyAgent.connectTo(); SAClientTestBase.MyConnectionStatusListener listener = new SAClientTestBase.MyConnectionStatusListener(); client.addConnectionStatusListener(listener); listener.reset(); assertFalse(listener.hasData()); //close the connection client.close(); //See if we get a notification assertFalse(listener.getNext()); //Wait a little more Thread.sleep(1000); //There should be nothing more assertFalse(listener.hasData()); //Connect again client = MockStrategyAgent.connectTo(); client.addConnectionStatusListener(listener); listener.reset(); //but this time kill the server stopAgent(); //See if we get a notification assertFalse(listener.getNext()); //verify that all the WS invocations fail //Wait a little more Thread.sleep(1000); //There should be nothing more assertFalse(listener.hasData()); //Close the client client.close(); } /** * Verify that if a listener throws an exception, it doesn't impact * delivery of notifications to other registered listeners. * * @throws Exception if there were unexpected failures. */ @Test(timeout = 100000) public void connectionListenerFailure() throws Exception { SAClient client = MockStrategyAgent.connectTo(); final SAClientTestBase.MyConnectionStatusListener listener1 = new SAClientTestBase.MyConnectionStatusListener(); SAClientTestBase.MyConnectionStatusListener listener2 = new SAClientTestBase.MyConnectionStatusListener(); //configure both listeners to fail client.addConnectionStatusListener(listener1); client.addConnectionStatusListener(listener2); listener1.reset(); listener2.reset(); listener1.setFail(true); listener2.setFail(true); assertFalse(listener1.hasData()); assertFalse(listener2.hasData()); //close the connection client.close(); //See if we get a notification assertFalse(listener1.getNext()); assertFalse(listener2.getNext()); //verify that listener throws exception when set to fail new ExpectedFailure<IllegalStateException>(){ @Override protected void run() throws Exception { listener1.receiveConnectionStatus(false); } }; } /** * Tests notifications when connection listener is added twice. * * @throws Exception if there were unexpected errors. */ @Test(timeout = 100000) public void listenerDuplicates() throws Exception { SAClient client = MockStrategyAgent.connectTo(); final SAClientTestBase.MyConnectionStatusListener listener = new SAClientTestBase.MyConnectionStatusListener(); client.addConnectionStatusListener(listener); //Add listener twice client.addConnectionStatusListener(listener); listener.reset(); assertFalse(listener.hasData()); //close the connection client.close(); //See if we get a notification assertFalse(listener.getNext()); //And that listener got notified twice assertFalse(listener.getNext()); } /** * Tests that multiple listeners are notified in the reverse order * of their addition. * * @throws Exception if there were unexpected errors. */ @Test(timeout = 100000) public void listenerOrder() throws Exception { SAClient client = MockStrategyAgent.connectTo(); final SAClientTestBase.MyConnectionStatusListener listener1 = new SAClientTestBase.MyConnectionStatusListener(); SAClientTestBase.MyConnectionStatusListener listener2 = new SAClientTestBase.MyConnectionStatusListener(); client.addConnectionStatusListener(listener1); client.addConnectionStatusListener(listener2); listener1.reset(); listener2.reset(); assertFalse(listener1.hasData()); assertFalse(listener2.hasData()); //close the connection client.close(); //See if we get notifications assertFalse(listener1.getNext()); assertFalse(listener2.getNext()); //And that listener2 is notified before listener1 assertThat(listener1.getLastAddTime(), Matchers.greaterThan(listener2.getLastAddTime())); } /** * Verifies that removed listeners do not receive notifications. * * @throws Exception if there were unexpected errors. */ @Test(timeout = 100000) public void listenerRemove() throws Exception { SAClient client = MockStrategyAgent.connectTo(); final SAClientTestBase.MyConnectionStatusListener listener1 = new SAClientTestBase.MyConnectionStatusListener(); SAClientTestBase.MyConnectionStatusListener listener2 = new SAClientTestBase.MyConnectionStatusListener(); client.addConnectionStatusListener(listener1); client.addConnectionStatusListener(listener2); listener1.reset(); listener2.reset(); assertFalse(listener1.hasData()); assertFalse(listener2.hasData()); //Remove listener2 client.removeConnectionStatusListener(listener2); //remove a listener that is not added for kicks client.removeConnectionStatusListener(new SAClientTestBase.MyConnectionStatusListener()); //close the connection client.close(); //Verify listener1 gets notifications assertFalse(listener1.getNext()); //And that listener2 doesn't. We can be sure about the timing because //it was added after listener1 it would have been notified before //listener1. assertFalse(listener2.hasData()); assertNull(listener2.getLastAddTime()); } /** * Tests that when a listener is added more than once, the most * recently added instance is removed first. * * @throws Exception if there were unexpected errors. */ @Test(timeout = 100000) public void duplicateListenerRemoveOrder() throws Exception { SAClient client = MockStrategyAgent.connectTo(); final SAClientTestBase.MyConnectionStatusListener listener0 = new SAClientTestBase.MyConnectionStatusListener(); final SAClientTestBase.MyConnectionStatusListener listener1 = new SAClientTestBase.MyConnectionStatusListener(); SAClientTestBase.MyConnectionStatusListener listener2 = new SAClientTestBase.MyConnectionStatusListener(); client.addConnectionStatusListener(listener0); client.addConnectionStatusListener(listener1); client.addConnectionStatusListener(listener2); //add listener1 twice client.addConnectionStatusListener(listener1); listener0.reset(); listener1.reset(); listener2.reset(); assertFalse(listener0.hasData()); assertFalse(listener1.hasData()); assertFalse(listener2.hasData()); //Remove listener1 client.removeConnectionStatusListener(listener1); //close the connection client.close(); //Verify each listener gets a notifications assertFalse(listener0.getNext()); assertFalse(listener1.getNext()); assertFalse(listener2.getNext()); //Since listener0 has been notified that listener1 should have //received all its notifications. Verify that it has no more //notifications. assertFalse(listener1.hasData()); //And that listener1 gets it after listener2, which proves that //the most recently added instance was removed. if the other instance //was removed this assert will fail. assertThat(listener1.getLastAddTime(), Matchers.greaterThan(listener2.getLastAddTime())); //And that listener0 was notified in the end assertThat(listener0.getLastAddTime(), Matchers.greaterThan(listener1.getLastAddTime())); } /** * Verifies that the client appID has the correct version. */ @Test public void versionTest() { assertEquals(SAClientVersion.APP_ID_VERSION, new VersionInfo(Util.getVersion(SAClientVersion.APP_ID))); } @Before public void startAgent() throws Exception { mAgent = new MockStrategyAgent(); } @After public void stopAgent() throws Exception { if (mAgent != null) { mAgent.close(); mAgent = null; } } @BeforeClass public static void setup() throws Exception { LoggerConfiguration.logSetup(); MockStrategyAgent.startServerAndClient(); } @AfterClass public static void teardown() throws Exception { MockStrategyAgent.closeServerAndClient(); } private void verifyParameters(SAClientParameters inExpected, SAClientParameters inActual) { assertEquals(inExpected.getURL(), inActual.getURL()); assertEquals(inExpected.getHostname(), inActual.getHostname()); assertEquals(inExpected.getPort(), inActual.getPort()); assertEquals(inExpected.getUsername(), inActual.getUsername()); //password should be smudged! assertFalse(String.valueOf(inActual.getPassword()), Arrays.equals(inExpected.getPassword(), inActual.getPassword())); } /** * Closure for testing saclient failures after it has been * disconnected. */ private static abstract class DisconnectedFailure extends ExpectedFailure<ConnectionException> { protected DisconnectedFailure() throws Exception { super(Messages.CLIENT_DISCONNECTED); } } private volatile MockStrategyAgent mAgent; }