package org.marketcetera.saclient;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.math.BigDecimal;
import java.math.BigInteger;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Test;
import org.marketcetera.client.ClientTest;
import org.marketcetera.event.EventTestBase;
import org.marketcetera.module.CopierModuleFactory;
import org.marketcetera.module.DataFlowID;
import org.marketcetera.module.DataRequest;
import org.marketcetera.module.ExpectedFailure;
import org.marketcetera.modules.remote.receiver.ReceiverFactory;
import org.marketcetera.trade.Equity;
import org.marketcetera.trade.ExecutionReport;
import org.marketcetera.trade.FIXOrder;
import org.marketcetera.trade.OrderCancel;
import org.marketcetera.trade.OrderCancelReject;
import org.marketcetera.trade.OrderReplace;
import org.marketcetera.trade.OrderSingle;
import org.marketcetera.trade.TypesTestBase;
import org.marketcetera.util.misc.ClassVersion;
/* $License$ */
/**
* Tests {@link SAClient} JMS functions.
*
* @author anshul@marketcetera.com
* @version $Id: SAClientJMSTest.java 16154 2012-07-14 16:34:05Z colin $
* @since 2.0.0
*/
@ClassVersion("$Id: SAClientJMSTest.java 16154 2012-07-14 16:34:05Z colin $")
public class SAClientJMSTest extends SAClientTestBase {
/**
* Tests the behavior when a null receiver is added / removed.
*
* @throws Exception if there were unexpected failures.
*/
@Test
public void nullReceiver() throws Exception {
new ExpectedFailure<NullPointerException>(){
@Override
protected void run() throws Exception {
getClient().addDataReceiver(null);
}
};
new ExpectedFailure<NullPointerException>(){
@Override
protected void run() throws Exception {
getClient().removeDataReciever(null);
}
};
}
/**
* Tests simple reception of data by a single receiver.
*
* @throws Exception if there were unexpected errors.
*/
@Test(timeout = 1000000)
public void simpleReceive() throws Exception {
getClient().addDataReceiver(mReceiver1);
runTest(new TestVerifier() {
@Override
public void verifyExpected(Object inExpected) throws Exception {
verifyEquals(inExpected, mReceiver1.getNext());
}
});
}
/**
* Tests reception of data by two receivers and verifies that the
* order of data delivery to the two receivers.
*
* @throws Exception if there were unexpected errors.
*/
@Test(timeout = 10000)
public void dualReceivers() throws Exception {
getClient().addDataReceiver(mReceiver1);
getClient().addDataReceiver(mReceiver2);
runTest(new TestVerifier() {
@Override
public void verifyExpected(Object inExpected) throws Exception {
verifyEquals(inExpected, mReceiver1.getNext());
//since receiver2 receives data before receiver1, receiver2
//should have data by now.
assertTrue(mReceiver2.hasData());
verifyEquals(inExpected, mReceiver2.getNext());
}
});
//verify that receiver1 indeed received data after receiver2
assertThat(mReceiver1.getLastAddTime(),
Matchers.greaterThan(mReceiver2.getLastAddTime()));
}
/**
* Verifies that failure of a receiver to receive data does not
* impact the delivery of data to other receivers.
*
* @throws Exception if there were unexpected errors.
*/
@Test(timeout = 10000)
public void receiverFailure() throws Exception {
//Configure both the receivers to fail
mReceiver1.setFail(true);
mReceiver2.setFail(true);
getClient().addDataReceiver(mReceiver1);
getClient().addDataReceiver(mReceiver2);
runTest(new TestVerifier() {
@Override
public void verifyExpected(Object inExpected) throws Exception {
verifyEquals(inExpected, mReceiver1.getNext());
//since receiver2 receives data before receiver1, receiver2
//should have data by now.
assertTrue(mReceiver2.hasData());
verifyEquals(inExpected, mReceiver2.getNext());
}
});
//As a double check verify that receivers fail when setFail is set
new ExpectedFailure<IllegalStateException>() {
@Override
protected void run() throws Exception {
mReceiver1.receiveData(new Object());
}
};
}
/**
* Verifies that a receiver does not receive any data after it has been
* removed.
*
* @throws Exception if there were unexpected errors.
*/
@Test(timeout = 10000)
public void noReceiveOnRemove() throws Exception {
getClient().addDataReceiver(mReceiver1);
getClient().addDataReceiver(mReceiver2);
getClient().removeDataReciever(mReceiver1);
runTest(new TestVerifier() {
@Override
public void verifyExpected(Object inExpected) throws Exception {
verifyEquals(inExpected, mReceiver2.getNext());
}
});
}
/**
* Verfies that lack of any data receivers does not impact data flows.
*
* @throws Exception if there were unexpected errors.
*/
@Test(timeout = 10000)
public void noReceivers() throws Exception {
runTest(new TestVerifier() {
@Override
public void verifyExpected(Object inExpected) throws Exception {
//Slow it down to allow for data to be received if it can be.
Thread.sleep(300);
}
});
}
/**
* Verifies that when all receivers are removed, no data is received.
*
* @throws Exception if there were unexpected errors.
*/
@Test(timeout = 10000)
public void allReceiversRemoved() throws Exception {
getClient().addDataReceiver(mReceiver1);
getClient().addDataReceiver(mReceiver2);
getClient().removeDataReciever(mReceiver1);
getClient().removeDataReciever(mReceiver2);
//Remove a receiver that was never added for kicks.
getClient().removeDataReciever(new MyDataReceiver());
runTest(new TestVerifier() {
@Override
public void verifyExpected(Object inExpected) throws Exception {
//Slow it down to allow for data to be received if it can be.
Thread.sleep(300);
}
});
}
/**
* Verifies that a receiver receives data twice if it's added twice.
*
* @throws Exception if there were unexpected errors.
*/
@Test(timeout = 10000)
public void receiverAddedTwice() throws Exception {
getClient().addDataReceiver(mReceiver1);
getClient().addDataReceiver(mReceiver1);
runTest(new TestVerifier() {
@Override
public void verifyExpected(Object inExpected) throws Exception {
verifyEquals(inExpected, mReceiver1.getNext());
verifyEquals(inExpected, mReceiver1.getNext());
}
});
}
/**
* Verifies that when duplicate receivers are added, its remove removes
* the most recently added instance.
*
* @throws Exception if there were unexpected errors.
*/
@Test(timeout = 10000)
public void duplicateReceiverRemove() throws Exception {
getClient().addDataReceiver(mReceiver1);
getClient().addDataReceiver(mReceiver2);
//Add receiver1 twice.
getClient().addDataReceiver(mReceiver1);
//And then remove it
getClient().removeDataReciever(mReceiver1);
runTest(new TestVerifier() {
@Override
public void verifyExpected(Object inExpected) throws Exception {
verifyEquals(inExpected, mReceiver1.getNext());
//since receiver2 receives data before receiver1, receiver2
//should have data by now.
assertTrue(mReceiver2.hasData());
verifyEquals(inExpected, mReceiver2.getNext());
}
});
//verify that receiver1 indeed received data after receiver2
//which verifies that most recently added instance was removed.
//if the other instance was removed this assertion would fail.
assertThat(mReceiver1.getLastAddTime(),
Matchers.greaterThan(mReceiver2.getLastAddTime()));
}
/**
* Removes the receivers and resets their state.
*/
@After
public void resetReceivers() {
getClient().removeDataReciever(mReceiver1);
getClient().removeDataReciever(mReceiver2);
mReceiver1.reset();
mReceiver2.reset();
}
/**
* Runs a test data flow that results in the client receiving the result
* of that data flow.
*
* @param inVerifier the verifier that performs the verification of
* actual data received during the data flow.
*
* @throws Exception if there were unexpected errors.
*/
private void runTest(TestVerifier inVerifier) throws Exception {
Object[] data = createTestObjects();
assertReceiversHaveNoData();
//Create a flow to send data to the receiver module
DataFlowID flowID = emitData(data);
try {
//verify that we receive all the data
for (Object expected : data) {
//Verify only if expected is non-null
//null values are not transmitted
if (expected != null) {
inVerifier.verifyExpected(expected);
}
}
} finally {
if (flowID != null) {
getMM().cancel(flowID);
}
}
assertReceiversHaveNoData();
}
/**
* An interface to help with testing.
*/
private static interface TestVerifier {
/**
* Verifies the actual data received is the same as the supplied
* expected object.
*
* @param inExpected the expected object.
*
* @throws Exception if there were unexpected errors.
*/
public void verifyExpected(Object inExpected) throws Exception;
}
/**
* Verifies that both the receivers have no data.
*/
private void assertReceiversHaveNoData() {
assertFalse(mReceiver1.hasData());
assertFalse(mReceiver2.hasData());
}
/**
* Verifies the equality of the supplied objects. The equality check
* is adapted based on the type of object.
*
* @param inExpected the expected object.
* @param inActual the actual object.
*/
private void verifyEquals(Object inExpected, Object inActual) {
if (inExpected instanceof OrderSingle) {
TypesTestBase.assertOrderSingleEquals((OrderSingle) inExpected,
(OrderSingle) inActual);
} else if (inExpected instanceof OrderReplace) {
TypesTestBase.assertOrderReplaceEquals((OrderReplace) inExpected,
(OrderReplace) inActual);
} else if (inExpected instanceof OrderCancel) {
TypesTestBase.assertOrderCancelEquals((OrderCancel) inExpected,
(OrderCancel) inActual);
} else if (inExpected instanceof FIXOrder) {
TypesTestBase.assertOrderFIXEquals((FIXOrder) inExpected,
(FIXOrder) inActual);
} else if (inExpected instanceof OrderCancelReject) {
TypesTestBase.assertCancelRejectEquals((OrderCancelReject) inExpected,
(OrderCancelReject) inActual);
} else if (inExpected instanceof ExecutionReport) {
TypesTestBase.assertExecReportEquals((ExecutionReport) inExpected,
(ExecutionReport) inActual);
} else if (inExpected instanceof org.marketcetera.core.notifications.Notification) {
assertEquals(inExpected.toString(), inActual.toString());
} else {
assertEquals(inExpected, inActual);
}
}
/**
* Creates test objects that will be streamed in the data flow for testing.
*
* @return the array of created objects.
*
* @throws Exception if there were unexpected errors.
*/
private Object[] createTestObjects() throws Exception {
return new Object[]{
EventTestBase.generateEquityAskEvent(1, 2, new Equity("asym"), "ex", BigDecimal.ONE, BigDecimal.TEN),
EventTestBase.generateEquityBidEvent(3, 4, new Equity("bsym"), "ex", BigDecimal.ONE, BigDecimal.TEN),
EventTestBase.generateEquityTradeEvent(5, 6, new Equity("csym"), "ex", BigDecimal.ONE, BigDecimal.TEN),
ClientTest.createOrderSingle(),
ClientTest.createOrderReplace(),
ClientTest.createOrderCancel(),
ClientTest.createOrderFIX(),
ClientTest.createCancelReject(),
ClientTest.createExecutionReport(),
org.marketcetera.core.notifications.Notification.high(
"Subject", "body", "test.notification"),
BigInteger.ONE,
null,
"Test String"
};
}
/**
* Emits data into the receiver. So that it can be received by the client
*
* @param inData the data that needs to be emitted by the data flow.
* @return the data flowID.
* @throws Exception if there were unexpected errors.
*/
private static DataFlowID emitData(Object... inData) throws Exception {
return getMM().createDataFlow(new DataRequest[]{
new DataRequest(CopierModuleFactory.INSTANCE_URN, inData),
new DataRequest(ReceiverFactory.INSTANCE_URN)
}, false);
}
private final MyDataReceiver mReceiver1 = new MyDataReceiver();
private final MyDataReceiver mReceiver2 = new MyDataReceiver();
}