package org.marketcetera.saclient;
import java.util.Date;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.marketcetera.core.LoggerConfiguration;
import org.marketcetera.module.ModuleManager;
import org.marketcetera.util.misc.ClassVersion;
import org.marketcetera.util.ws.ContextClassProvider;
/* $License$ */
/**
* Base class for testing SA Client functions.
*
* @author anshul@marketcetera.com
* @version $Id: SAClientTestBase.java 16881 2014-04-15 23:39:25Z colin $
* @since 2.0.0
*/
@ClassVersion("$Id: SAClientTestBase.java 16881 2014-04-15 23:39:25Z colin $")
public class SAClientTestBase {
@BeforeClass
public static void setup() throws Exception {
LoggerConfiguration.logSetup();
}
/**
* Run before each test.
*
* @throws Exception if an unexpected error occurs
*/
@Before
public void before()
throws Exception
{
MockStrategyAgent.setContextClassProvider(getContextClassProvider());
MockStrategyAgent.startServerAndClient();
startAgent();
SAClientParameters defaultParams = MockStrategyAgent.DEFAULT_PARAMETERS;
SAClientParameters modifiedParams = new SAClientParameters(defaultParams.getUsername(),
defaultParams.getPassword(),
defaultParams.getURL(),
defaultParams.getHostname(),
defaultParams.getPort(),
getContextClassProvider());
sClient = MockStrategyAgent.connectTo(modifiedParams);
}
/**
* Run after each test.
*
* @throws Exception if an unexpected error occurs
*/
@After
public void teardown()
throws Exception
{
if (sClient != null) {
sClient.close();
sClient = null;
}
stopAgent();
MockStrategyAgent.closeServerAndClient();
}
/**
* Adds additional context classes to the SA client/server context.
*
* <p>Subclasses may override this method to provide additional context classes. The default
* behavior is to return no additional context classes.
*
* @return a <code>ContextClassProvider</code> value
*/
protected ContextClassProvider getContextClassProvider()
{
return null;
}
/**
* Starts the mock strategy agent.
*
* @throws Exception if there were unexpected errors.
*/
protected static void startAgent() throws Exception {
sMockSA = new MockStrategyAgent();
}
/**
* Stops the mock strategy agent if it's not running.
*
* @throws Exception if there were unexpected errors.
*/
protected static void stopAgent() throws Exception {
if (sMockSA != null) {
sMockSA.close();
sMockSA = null;
}
}
/**
* Resets the mock service parameters.
*/
protected static void resetServiceParameters() {
getMockSAService().reset();
}
/**
* The SA client.
*
* @return the SA client.
*/
protected static SAClient getClient() {
return sClient;
}
/**
* The module manager instance within the mock strategy agent.
*
* @return the module manager instance in strategy agent.
*/
protected static ModuleManager getMM() {
return sMockSA.getManager();
}
/**
* The mock service instance.
*
* @return the mock service instance.
*/
protected static MockSAServiceImpl getMockSAService() {
return sMockSA.getService();
}
/**
* A mock receiver to test data receivers.
*/
protected static class MyDataReceiver extends ObjectQueue<Object>
implements DataReceiver {
@Override
public void receiveData(Object inObject) {
add(inObject);
}
}
/**
* A mock Connection status listener to test connection status
* listeners.
*/
protected static class MyConnectionStatusListener
extends ObjectQueue<Boolean>
implements ConnectionStatusListener
{
@Override
public void receiveConnectionStatus(boolean inStatus)
{
add(inStatus);
}
}
protected volatile static MockStrategyAgent sMockSA;
protected volatile static SAClient sClient;
/**
* A base class for testing listeners.
*
* @param <T> the type of data received by the listeners.
*/
private static class ObjectQueue<T> {
/**
* Adds the received data/notification.
*
* @param inValue the received data.
*/
protected void add(T inValue) {
mLastAdd = new Date();
//Slow it down so that we get different mLastAdd values
//for multiple invocations.
try {
Thread.sleep(100);
} catch (InterruptedException ignored) {
}
mData.add(inValue);
if(isFail()) {
throw new IllegalStateException();
}
}
/**
* Returns the earliest added data that hasn't been fetched yet.
* Waits until the data is added, if no data is available already.
*
* @return the data added via {@link #add(Object)}.
*
* @throws InterruptedException if the wait for data is interrupted.
*/
public T getNext() throws InterruptedException {
return mData.take();
}
/**
* If data has been added but hasn't been retrieved.
*
* @return true if data is available to be fetched.
*/
public boolean hasData() {
return !mData.isEmpty();
}
/**
* If addition of data should throw an exception.
*
* @return if addition of data should throw an exception.
*/
public boolean isFail() {
return mFail;
}
/**
* Set if addition of data should throw an exception.
*
* @param inFail if addition of should throw an exception.
*/
public void setFail(boolean inFail) {
mFail = inFail;
}
/**
* Gets the timestamp of the last {@link #add(Object)} invocation.
*
* @return the timestamp of the last add() invocation.
*/
public Date getLastAddTime() {
return mLastAdd;
}
/**
* Resets the object back to its initial state.
*/
public void reset() {
setFail(false);
mData.clear();
mLastAdd = null;
}
private volatile boolean mFail;
private volatile Date mLastAdd;
private final BlockingQueue<T> mData = new LinkedBlockingQueue<T>();
}
}