package org.marketcetera.module;
import org.marketcetera.marketdata.MockMarketDataFeedModuleFactory;
import org.marketcetera.util.misc.ClassVersion;
import org.marketcetera.util.test.CollectionAssert;
import org.marketcetera.core.Pair;
import org.marketcetera.core.LoggerConfiguration;
import static org.junit.Assert.*;
import org.junit.BeforeClass;
import javax.management.*;
import javax.management.openmbean.SimpleType;
import java.util.List;
import java.util.HashSet;
import java.util.Arrays;
import java.util.LinkedList;
import java.lang.management.ManagementFactory;
/* $License$ */
/**
* A base class with colletion of all utility methods for testing modules
*
* @author anshul@marketcetera.com
*/
@ClassVersion("$Id: ModuleTestBase.java 16154 2012-07-14 16:34:05Z colin $")
public class ModuleTestBase {
/**
* Setup logging for unit tests.
*/
@BeforeClass
public static void logSetup() {
LoggerConfiguration.logSetup();
}
/**
* Verifies all the providers that are expected to be available
* in the unit testing environment.
*
* @param inProviders the actual set of provider URNs found.
*/
protected static void checkAllProviders(List<ModuleURN> inProviders) {
assertEquals(14, inProviders.size());
CollectionAssert.assertArrayPermutation(new ModuleURN[]{
SinkModuleFactory.PROVIDER_URN,
SingleModuleFactory.PROVIDER_URN,
MultipleModuleFactory.PROVIDER_URN,
ComplexModuleFactory.PROVIDER_URN,
JMXTestModuleFactory.PROVIDER_URN,
ConfigurationProviderTestFactory.PROVIDER_URN,
EmitterModuleFactory.PROVIDER_URN,
ProcessorModuleFactory.PROVIDER_URN,
FlowRequesterModuleFactory.PROVIDER_URN,
SingleParmModuleFactory.PROVIDER_URN,
CopierModuleFactory.PROVIDER_URN,
ConcurrentTestFactory.PROVIDER_URN,
DynamicBeanModuleFactory.PROVIDER_URN,
MockMarketDataFeedModuleFactory.PROVIDER_URN
}, inProviders.toArray(new ModuleURN[inProviders.size()]));
}
/**
* Verifies the ProviderInfo field values.
*
* @param inInfo the provider info to verify.
* @param inURN the expected provider URN.
* @param parameterTypeNames the expected parameter type names.
* @param parameterTypes the expected parameter types
* @param description the expected provider description
* @param autoInstantiate if the provider supports
* auto-instantiated modules.
* @param multipleInstances if the provider supports multiple
* instances of the modules
* @throws ClassNotFoundException if there was an error.
*/
protected static void assertProviderInfo(ProviderInfo inInfo,
ModuleURN inURN,
String[] parameterTypeNames,
Class<?>[] parameterTypes,
String description,
boolean autoInstantiate,
boolean multipleInstances)
throws ClassNotFoundException {
assertEquals(inURN, inInfo.getURN());
List<String> list = inInfo.getParameterTypeNames();
CollectionAssert.assertArrayPermutation(parameterTypeNames,
list.toArray(new String[list.size()]));
assertArrayEquals(parameterTypes, inInfo.parameterTypes());
assertEquals(description, inInfo.getDescription());
assertEquals(autoInstantiate, inInfo.isAutoInstantiate());
assertEquals(multipleInstances, inInfo.isMultipleInstances());
}
/**
* Verifies the module info fields.
*
* @param inInfo the module info to verify.
* @param inURN the expected module URN
* @param inState the expected module state
* @param inInitDataFlows the set of data flows initiated
* @param inParticipateDataFlows the set of data flows participating in
* @param inAutocreated if the module is autocreated.
* @param inAutostart if the module is autostarted
* @param inReceiver if the module is a receiver
* @param inEmitter if the module is an emitter
* @param inFlowRequester if the module is a flow requester
* @return the supplied module info
*/
public static ModuleInfo assertModuleInfo(ModuleInfo inInfo,
ModuleURN inURN,
ModuleState inState,
DataFlowID[] inInitDataFlows,
DataFlowID[] inParticipateDataFlows,
boolean inAutocreated,
boolean inAutostart,
boolean inReceiver,
boolean inEmitter,
boolean inFlowRequester) {
assertEquals(inURN, inInfo.getURN());
assertEquals(inState, inInfo.getState());
CollectionAssert.assertArrayPermutation(inInitDataFlows,
inInfo.getInitiatedDataFlows());
CollectionAssert.assertArrayPermutation(inParticipateDataFlows,
inInfo.getParticipatingDataFlows());
assertEquals(inAutocreated, inInfo.isAutocreated());
assertEquals(inAutostart, inInfo.isAutostart());
assertEquals(inReceiver, inInfo.isReceiver());
assertEquals(inEmitter, inInfo.isEmitter());
assertEquals(inFlowRequester, inInfo.isFlowRequester());
assertNotNull(inInfo.getCreated());
if(inInfo.getState().isStarted()) {
//verify started time stamp
assertNotNull(inInfo.getStarted());
}
if(ModuleState.STOPPED == inInfo.getState()) {
//verify stopped time stamp
assertNotNull(inInfo.getStopped());
}
return inInfo;
}
/**
* Verify the state of ModuleBase instance.
*
* @param inURN the module instance URN
* @param inStartInvoked if module start has been invoked
* @param inStopInvoked if the module stop has been invoked
* @param inAutoStart if the module is auto-start
* @param inAutoCreated if the module is auto-created.
* @return the module instance
*/
protected static ModuleBase assertModuleBase(ModuleURN inURN,
boolean inStartInvoked,
boolean inStopInvoked,
boolean inAutoStart,
boolean inAutoCreated) {
ModuleBase module = ModuleBase.getInstance(inURN);
assertModuleBase(module, inURN, inStartInvoked, inStopInvoked,
inAutoStart, inAutoCreated);
return module;
}
/**
* Verify the state of a ModuleBase instance.
*
* @param inModule the module base instance.
* @param inURN the module instance URN.
* @param inStartInvoked if the module start has been invoked
* @param inStopInvoked if the module stop has been invoked
* @param inAutoStart if the module is auto-start
* @param inAutoCreated if the module is auto-created.
*/
protected static void assertModuleBase(ModuleBase inModule,
ModuleURN inURN,
boolean inStartInvoked,
boolean inStopInvoked,
boolean inAutoStart,
boolean inAutoCreated) {
assertNotNull(inModule);
assertEquals(inURN, inModule.getURN());
assertEquals(inStartInvoked, inModule.isStartInvoked());
assertEquals(inStopInvoked, inModule.isStopInvoked());
assertEquals(inAutoStart, inModule.isAutoStart());
assertEquals(inAutoCreated, inModule.isAutoCreated());
}
/**
* Verify the provider info, after querying it from the module
* manager.
*
* @param inManager the module manager
* @param inURN the provider URN.
* @param parameterTypeNames the provider parameter type names
* @param parameterTypes the provider parameter types
* @param description the provider description
* @param autoInstantiate if the provider supports auto-instantiated instances
* @param multipleInstances if the provider supports multiple instances
*
* @throws Exception if there was an unexpected failure
*/
protected static void assertProviderInfo(ModuleManager inManager,
ModuleURN inURN,
String[] parameterTypeNames,
Class<?>[] parameterTypes,
String description,
boolean autoInstantiate,
boolean multipleInstances)
throws Exception {
ProviderInfo info = inManager.getProviderInfo(inURN);
assertProviderInfo(info, inURN, parameterTypeNames, parameterTypes,
description, autoInstantiate, multipleInstances);
}
/**
* Verifies the module info queried from the module manager
*
* @param inManager the module manager instance
* @param inURN the module URN
* @param inState the module state
* @param inInitDataFlows the data flows initiated by the module
* @param inParticipateDataFlows the data flows that module is
* participating in
* @param inAutocreated if the module is auto-created
* @param inAutostart if the module is auto-started
* @param inReceiver if the module is a receiver
* @param inEmitter if the module is an emitter
* @param inFlowRequester if the module is a data flow creator
*
* @return the module info for the module
*
* @throws Exception if there was an unexpected error
*/
protected static ModuleInfo assertModuleInfo(ModuleManager inManager,
ModuleURN inURN,
ModuleState inState,
DataFlowID[] inInitDataFlows,
DataFlowID[] inParticipateDataFlows,
boolean inAutocreated,
boolean inAutostart,
boolean inReceiver,
boolean inEmitter,
boolean inFlowRequester)
throws Exception {
ModuleInfo info = inManager.getModuleInfo(inURN);
return assertModuleInfo(info, inURN, inState,
inInitDataFlows, inParticipateDataFlows,
inAutocreated, inAutostart, inReceiver,
inEmitter, inFlowRequester);
}
/**
* Verify if all the URNs specified in the <code>inContents</code>
* are present in the <code>inContainer</code> as well.
*
* @param inContainer if the container of URNs
* @param inContents the set of URNs that should be present
* in the container
*/
protected static void assertContains(List<ModuleURN> inContainer,
ModuleURN [] inContents) {
HashSet<ModuleURN> container =
new HashSet<ModuleURN>(inContainer);
List<ModuleURN> urnList = Arrays.asList(inContents);
HashSet<ModuleURN> contents = new HashSet<ModuleURN>(urnList);
contents.removeAll(container);
assertTrue(contents.toString(), container.containsAll(urnList));
}
/**
* Verifies the contents of the supplied data flow info.
*
* @param inInfo the data flow info
* @param inFlowID the expected data flow ID
* @param inNumSteps the expected number of data flow steps
* @param hasCreated if the data flow has a created time stamp
* @param hasStopped if the data flow has a stopped time stamp
* @param inRequesterURN the data flow requester URN
* @param inStopperURN the data flow stopper URN
*/
protected static void assertFlowInfo(DataFlowInfo inInfo,
DataFlowID inFlowID,
int inNumSteps,
boolean hasCreated,
boolean hasStopped,
ModuleURN inRequesterURN,
ModuleURN inStopperURN) {
assertEquals(inFlowID, inInfo.getFlowID());
assertEquals(inNumSteps, inInfo.getFlowSteps().length);
assertEquals(hasCreated, inInfo.getCreated() != null);
assertEquals(hasStopped, inInfo.getStopped() != null);
assertEquals(inRequesterURN, inInfo.getRequesterURN());
assertEquals(inStopperURN, inInfo.getStopperURN());
}
/**
* Verifies contents of a data flow step
*
* @param inStep the data flow step
* @param inURN the URN of the module in this step
* @param inEmitter if the module is an emitter
* @param inNumEmitted number of data instances emitted
* @param inNumEmitErrors numbers of emit errors encountered
* @param inLastEmitError the last emit error encountered
* @param inReceiver if the module is a receiver
* @param inNumReceived number of data instances received
* @param inNumReceiveErrors number of receive errors encountered
* @param inLastReceiveError the last receive error encountered
* @param inRequestURN the module URN specified in the data request
* @param inRequestParam the request parameter specified in the
* data request
*/
protected static void assertFlowStep(DataFlowStep inStep,
ModuleURN inURN,
boolean inEmitter,
int inNumEmitted,
int inNumEmitErrors,
String inLastEmitError,
boolean inReceiver,
int inNumReceived,
int inNumReceiveErrors,
String inLastReceiveError,
ModuleURN inRequestURN,
Object inRequestParam) {
if (inURN != null) {
assertEquals(inURN, inStep.getModuleURN());
}
assertEquals(inEmitter,inStep.isEmitter());
assertEquals(inNumEmitted,inStep.getNumEmitted());
assertEquals(inNumEmitErrors,inStep.getNumEmitErrors());
if (inLastEmitError != null) {
assertNotNull(inStep.getLastEmitError());
assertTrue(inStep.getLastEmitError().startsWith(inLastEmitError));
} else {
assertNull(inStep.getLastEmitError());
}
assertEquals(inReceiver,inStep.isReceiver());
assertEquals(inNumReceived,inStep.getNumReceived());
assertEquals(inNumReceiveErrors,inStep.getNumReceiveErrors());
if (inLastReceiveError != null) {
assertNotNull(inStep.getLastReceiveError());
assertTrue(inStep.getLastReceiveError(),
inStep.getLastReceiveError().startsWith(inLastReceiveError));
} else {
assertNull(inStep.getLastReceiveError(),inStep.getLastReceiveError());
}
if (inRequestURN != null) {
assertEquals(inRequestURN,inStep.getRequest().getRequestURN());
}
assertEquals(inRequestParam,inStep.getRequest().getData());
//Only sync data coupling is supported for now.
assertEquals(DataCoupling.SYNC, inStep.getRequest().getCoupling());
}
/**
* Gets the MBean server to use for all the tests.
*
* @return the mbean server to use for all tests.
*/
protected static MBeanServer getMBeanServer() {
return ManagementFactory.getPlatformMBeanServer();
}
/**
* Verifies that the bean, attribute, operation and parameter info
* all have the descriptor name, {@link org.marketcetera.module.DisplayName} specified.
*
* Also verifies that all the parameter types are simple types.
*
* @param inInfo the bean info to verify.
*/
public static void verifyBeanInfo(MBeanInfo inInfo) {
//verify that every info has the display name descriptor
assertDescriptor(inInfo.getDescriptor(), false);
for (MBeanAttributeInfo attrib : inInfo.getAttributes()) {
assertDescriptor(attrib.getDescriptor(), false);
}
for (MBeanOperationInfo opInfo : inInfo.getOperations()) {
assertDescriptor(opInfo.getDescriptor(), false);
for (MBeanParameterInfo parameterInfo : opInfo.getSignature()) {
assertDescriptor(parameterInfo.getDescriptor(), true);
}
}
}
/**
* Verifies the descriptor value.
*
* @param inDescriptor the descriptor.
* @param inSimpleType if the descriptor should be validated to describe
* a simple type.
*/
public static void assertDescriptor(Descriptor inDescriptor, boolean inSimpleType) {
if (inSimpleType) {
Object value = inDescriptor.getFieldValue("openType");
assertNotNull(value);
assertTrue(value.getClass().toString(), value instanceof SimpleType<?>);
}
assertNotNull(inDescriptor.getFieldValue("name"));
}
/**
* A class that contains data collected by {@link Sink}
*/
protected static class FlowData extends Pair<DataFlowID,Object> {
/**
* Creates an instance.
*
* @param inFlowID the data flow ID
* @param inObject the data object received
*/
FlowData(DataFlowID inFlowID, Object inObject) {
super(inFlowID, inObject);
}
}
/**
* A sink data listener to help with testing.
* <p>
* This listener has a special behavior for boolean false values
* received. Whenever it receives a false value, it notifies
* all the threads that are waiting in {@link #waitUntilTerminator()}
* method. The boolean false value is never added to the set of
* data received.
* <p>
* The waiting threads are notified only once. Any boolean
* false values received after the first one are ignored
* until {@link #clear()} is invoked.
*/
protected static class Sink implements SinkDataListener {
/**
* Adds the received data to the set of objects received.
*
* if a boolean false value is received the received
* terminator flag is cleared and any threads waiting
* in {@link #waitUntilTerminator()} are notified.
*
* @param inFlowID the data flow ID.
* @param inData the data.
*/
public synchronized void receivedData(DataFlowID inFlowID,
Object inData) {
if (inData instanceof Boolean && !(Boolean) inData) {
// a boolean false value is a terminator
mReceivedTerminator = true;
notifyAll();
} else {
mData.add(new FlowData(inFlowID, inData));
}
if(mThrowException) {
throw new IllegalArgumentException();
}
}
/**
* Gets the list of data received by this listener in
* the order it was received.
*
* @return the flow data received until now.
*/
public synchronized FlowData[] getData() {
return mData.toArray(new FlowData[mData.size()]);
}
/**
* Clears all the data in the sink and the
* terminator received flag. any invocation
* of {@link #waitUntilTerminator()} will block
* until a boolean false value is received by the sink.
*/
public synchronized void clear() {
mData.clear();
mReceivedTerminator = false;
}
/**
* The {@link #receivedData(DataFlowID, Object)} throws an exception
* if this attribute is set to true.
*
* @param inThrowException if an exception should be thrown
* when receiving data.
*/
public void setThrowException(boolean inThrowException) {
mThrowException = inThrowException;
}
/**
* Waits until we receive the boolean: false data flow
* terminator.
*
* @throws InterruptedException if the wait was interrupted
*/
public synchronized void waitUntilTerminator()
throws InterruptedException {
while(!mReceivedTerminator) {
wait();
}
}
private boolean mReceivedTerminator = false;
private LinkedList<FlowData> mData =
new LinkedList<FlowData>();
private boolean mThrowException;
}
}