package org.marketcetera.module;
import org.marketcetera.util.misc.ClassVersion;
import org.marketcetera.util.log.SLF4JLoggerProxy;
import org.junit.BeforeClass;
import org.junit.AfterClass;
import org.junit.Test;
import org.junit.After;
import static org.junit.Assert.*;
import java.util.*;
import java.util.concurrent.Future;
/* $License$ */
/**
* Tests data flows
*
* @author anshul@marketcetera.com
*/
@ClassVersion("$Id: DataFlowTest.java 16154 2012-07-14 16:34:05Z colin $")
public class DataFlowTest extends ModuleTestBase {
@BeforeClass
public static void setup() throws Exception {
try {
sManager = new ModuleManager();
sManager.init();
sManager.addSinkListener(sSink);
} catch (Exception e) {
SLF4JLoggerProxy.error(e,e);
throw e;
}
}
@AfterClass
public static void cleanup() throws Exception {
sManager.stop();
}
@After
public void clearUp() throws Exception {
//clear the sink
sSink.clear();
//clear the emitter
((EmitterModule) ModuleBase.getInstance(
EmitterModuleFactory.INSTANCE_URN)).clear();
//prune all history records
sManager.setMaxFlowHistory(0);
sManager.setMaxFlowHistory(ModuleManager.DEFAULT_MAX_FLOW_HISTORY);
assertEquals(ModuleManager.DEFAULT_MAX_FLOW_HISTORY,
sManager.getMaxFlowHistory());
}
/**
* Verify failures when fetching data flow info specifying
* an invalid ID.
*
* @throws Exception if there were unexpected failures during
* testing
*/
@Test
public void getDataFlowInvalidID() throws Exception {
final DataFlowID id = new DataFlowID("blah");
new ExpectedFailure<DataFlowNotFoundException>(
Messages.DATA_FLOW_NOT_FOUND, id.getValue()){
protected void run() throws Exception {
sManager.getDataFlowInfo(id);
}
};
}
/**
* Verify failures when canceling a data flow specifying
* an invalid ID.
*
* @throws Exception if there were unexpected failures during
* testing
*/
@Test
public void cancelDataFlowInvalidID() throws Exception {
final DataFlowID flowID = new DataFlowID("blah");
new ExpectedFailure<DataFlowNotFoundException>(
Messages.DATA_FLOW_NOT_FOUND,flowID.getValue()){
protected void run() throws Exception {
sManager.cancel(flowID);
}
};
}
/**
* Tests creation & cancellation of simple data flows through the module
* manager API.
*
* @throws Exception if there's an unexpected error.
*/
@Test
public void createFlowManager() throws Exception {
//verify that there are no data flows
assertTrue(sManager.getDataFlows(true).isEmpty());
//Start emitter module, if not already started
startEmitter();
ModuleURN procURN = new ModuleURN(ProcessorModuleFactory.PROVIDER_URN,
"proc");
//verify that this module does not exist, so that we can verify
//it gets auto-instantiated.
List<ModuleURN> urns = sManager.getModuleInstances(
ProcessorModuleFactory.PROVIDER_URN);
assertFalse(urns.toString(), urns.contains(procURN));
//data flow with sink module auto-appended
checkDataFlowManager(true, false, true, new DataRequest(procURN,
String.class.getName()));
//data flow with sink explicitly requested to be auto-appended
checkDataFlowManager(false, true, true, new DataRequest(procURN,
String.class.getName()));
//data flow with sink explicitly added
checkDataFlowManager(false, true, true,
new DataRequest(procURN, String.class.getName()),
new DataRequest(SinkModuleFactory.INSTANCE_URN));
//manually create the processor module as the auto-created one
//gets deleted as soon as the data flow is over.
sManager.createModule(procURN.parent(), procURN);
//test module search functionality when setting up data flows
checkDataFlowManager(false, true, false,
new DataRequest(new ModuleURN("metc:::proc"),
String.class.getName()),
new DataRequest(SinkModuleFactory.INSTANCE_URN.parent()));
checkDataFlowManager(false, true, false,
new DataRequest(new ModuleURN("metc:::proc"),
String.class.getName()),
new DataRequest(SinkModuleFactory.INSTANCE_URN.parent().parent()));
}
/**
* Verifies that attempts to emit data fail when
* the data flow has ended.
*
* @throws Exception if there are unexpected errors
*/
@Test(timeout = 10000)
public void emitFailStoppedFlow() throws Exception {
assertTrue(sManager.getDataFlowHistory().isEmpty());
startEmitter();
DataFlowID flowID = sManager.createDataFlow(new DataRequest[]{
new DataRequest(EmitterModuleFactory.INSTANCE_URN,"send this data")
});
//Wait until sink receives this data
while(sSink.getData().length < 1) {
Thread.sleep(500);
}
sManager.cancel(flowID);
EmitterModule module = (EmitterModule) ModuleBase.getInstance(
EmitterModuleFactory.INSTANCE_URN);
DataEmitterSupport support = module.getLastTask().getSupport();
assertNotNull(support);
int numData = sSink.getData().length;
support.send(new Object());
//verify that the sink doesn't get it.
assertEquals(numData, sSink.getData().length);
//verify nothing happens if you try to emit error, its silently ignored
support.dataEmitError(TestMessages.BAD_DATA, true);
module.clear();
}
/**
* Tests creation & cancellation of simple data flows through the
* data flow support interface.
*
* @throws Exception if there's an unexpected error.
*/
@Test
public void createFlowModule() throws Exception {
//verify that there are no data flows
assertTrue(sManager.getDataFlows(true).isEmpty());
//Start emitter module, if not already started
startEmitter();
//create the flow requester module.
//Have the instance name similar to that of emitter so that we can
//test expansion of 'this' in the URN
ModuleURN procURN = new ModuleURN(FlowRequesterModuleFactory.PROVIDER_URN,
EmitterModuleFactory.INSTANCE_URN.instanceName());
sManager.createModule(FlowRequesterModuleFactory.PROVIDER_URN, procURN);
ModuleTestBase.assertModuleInfo(sManager.getModuleInfo(procURN),
procURN, ModuleState.CREATED, null, null, false, false,
true, true, true);
final FlowRequesterModule module = (FlowRequesterModule) ModuleBase.getInstance(procURN);
assertNotNull(module);
//verify data flows
//data flow with sink module auto-appended
checkDataFlowModule(module, null, true, false, new DataRequest(procURN,
String.class.getName()));
//data flow with sink explicitly requested to be auto-appended
checkDataFlowModule(module, null, false, true, new DataRequest(procURN,
String.class.getName()));
//data flow with sink explicitly added
checkDataFlowModule(module, null, false, true,
new DataRequest(procURN, String.class.getName()),
new DataRequest(SinkModuleFactory.INSTANCE_URN));
//verify expansion of 'this' keyword
checkDataFlowModule(module, null, false, true,
new DataRequest(new ModuleURN("metc:this:this:this"),
String.class.getName()),
new DataRequest(SinkModuleFactory.INSTANCE_URN.parent()));
//verify module search works
checkDataFlowModule(module, null, false, true,
new DataRequest(new ModuleURN("metc:flow::default"),
String.class.getName()),
new DataRequest(SinkModuleFactory.INSTANCE_URN.parent().parent()));
//verify expansion of this in emitter URN
checkDataFlowModule(module, new ModuleURN("metc:emit:this:this"),
false, true, new DataRequest(
new ModuleURN("metc:flow::default"), String.class.getName()),
new DataRequest(SinkModuleFactory.INSTANCE_URN.parent().parent()));
//verify that the initiated data flows are canceled by the system
//if the module doesn't stop them in prestop
module.setSkipCancel(true);
checkDataFlowModule(module, new ModuleURN("metc:emit:this:this"),
false, true, new DataRequest(
new ModuleURN("metc:flow::default"), String.class.getName()),
new DataRequest(SinkModuleFactory.INSTANCE_URN.parent().parent()));
//verify that requests cannot be made when the module is not started.
module.setInvokeDefault(true);
module.setRequests(new DataRequest[]{
new DataRequest(EmitterModuleFactory.INSTANCE_URN),
new DataRequest(module.getURN(), String.class.getName())
});
new ExpectedFailure<ModuleStateException>(
Messages.DATAFLOW_FAILED_REQ_MODULE_STATE_INCORRECT, procURN.toString(),
ModuleState.STOPPED, ModuleState.REQUEST_FLOW_STATES.toString()){
protected void run() throws Exception {
module.createFlow();
}
};
// verify requests cannot be canceled when the module
// is not started
final DataFlowID flowID = new DataFlowID("doesntmatter");
module.setFlowID(flowID);
new ExpectedFailure<ModuleStateException>(
Messages.CANCEL_FAILED_MODULE_STATE_INCORRECT, flowID.getValue(),
module.getURN().toString(), ModuleState.STOPPED,
ModuleState.CANCEL_FLOW_STATES.toString()){
protected void run() throws Exception {
module.cancelFlow();
}
};
}
/**
* Verifies that attempts to invoke data flow setup/cancel APIs, in
* {@link DataFlowSupport}, from within
* {@link DataEmitter#requestData(DataRequest, DataEmitterSupport)} &
* {@link DataEmitter#cancel(DataFlowID, RequestID)} fails.
*
* @throws Exception if there were errors.
*/
@Test
public void checkNestedFlowRequestFailures() throws Exception {
//create the flow requester module.
//Have the instance name similar to that of emitter so that we can
//test expansion of 'this' in the URN
final ModuleURN procURN = new ModuleURN(FlowRequesterModuleFactory.PROVIDER_URN,
"flow");
sManager.createModule(FlowRequesterModuleFactory.PROVIDER_URN, procURN);
ModuleTestBase.assertModuleInfo(sManager.getModuleInfo(procURN),
procURN, ModuleState.CREATED, null, null, false, false,
true, true, true);
final FlowRequesterModule module = (FlowRequesterModule) ModuleBase.getInstance(procURN);
assertNotNull(module);
//Start the module
sManager.start(procURN);
//Carry out nested flow requests from request data
module.setNestDataFlowInRequest(true);
module.setNestedCreateDataFlow(true);
module.setInvokeDefault(true);
//invoking default createDataflow
runNestedFlowRequestFailureInRequestData(procURN);
module.setInvokeDefault(false);
//invoking createDataFlow with explicit sink module append
runNestedFlowRequestFailureInRequestData(procURN);
module.setNestedCreateDataFlow(false);
module.setNestedCancelDataFlow(true);
//invoking cancel flow
runNestedFlowRequestFailureInRequestData(procURN);
//Carry out nested flow requests from cancel request
DataFlowID flowID = createFlowForNestedFlowTesting(module);
module.setNestDataFlowInCancel(true);
module.setNestedCancelDataFlow(false);
module.setNestedCreateDataFlow(true);
module.setInvokeDefault(true);
//invoking default create data flow
runNestedFlowRequestFailureInCancel(module, flowID);
//invoking create data flow with explicit sink module append
flowID = createFlowForNestedFlowTesting(module);
module.setNestDataFlowInCancel(true);
module.setInvokeDefault(false);
runNestedFlowRequestFailureInCancel(module, flowID);
//invoking cancel flow
flowID = createFlowForNestedFlowTesting(module);
module.setNestDataFlowInCancel(true);
module.setNestedCreateDataFlow(false);
module.setNestedCancelDataFlow(true);
runNestedFlowRequestFailureInCancel(module, flowID);
}
private void runNestedFlowRequestFailureInCancel(
FlowRequesterModule inModule,
DataFlowID inFlowID) throws ModuleException {
//make sure there's no failure
inModule.resetNestedCancelFailure();
assertNull(inModule.getNestedCancelFailure());
sManager.cancel(inFlowID);
//verify we get a failure
assertNotNull(inModule.getNestedCancelFailure());
assertEquals(ModuleException.class,
ExpectedFailure.assertI18NException(
inModule.getNestedCancelFailure(),
Messages.INCORRECT_NESTED_FLOW_REQUEST).getClass());
}
private DataFlowID createFlowForNestedFlowTesting(
FlowRequesterModule inModule) throws ModuleException {
inModule.setNestDataFlowInRequest(false);
inModule.setNestDataFlowInCancel(false);
//Create a data flow so that we can cancel it
DataFlowID flowID = sManager.createDataFlow(new DataRequest[]{
new DataRequest(inModule.getURN(),String.class.getName())
});
//verify flow is active
sManager.getDataFlowInfo(flowID);
return flowID;
}
private void runNestedFlowRequestFailureInRequestData(
final ModuleURN inProcURN) throws Exception {
assertEquals(ModuleException.class, ExpectedFailure.assertI18NException(
new ExpectedFailure<RequestDataException>(){
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(inProcURN)
});
}
}.getException().getCause(),
Messages.INCORRECT_NESTED_FLOW_REQUEST).getClass());
}
/**
* Test create data flow errors due to system reported failures.
*
* @throws Exception if there's an unexpected failure.
*/
@Test
public void createFlowSystemFailures() throws Exception {
assertTrue(sManager.getDataFlows(true).isEmpty());
//null request
new ExpectedFailure<DataFlowException>(
Messages.DATA_REQUEST_TOO_SHORT,0){
protected void run() throws Exception {
sManager.createDataFlow(null);
}
};
//empty request
new ExpectedFailure<DataFlowException>(
Messages.DATA_REQUEST_TOO_SHORT,0){
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[0]);
}
};
//short request without sink auto-appended
new ExpectedFailure<DataFlowException>(
Messages.DATA_REQUEST_TOO_SHORT, 1){
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{new DataRequest(
new ModuleURN("metc:dontmatter"))},false);
}
};
//invalid module URN for first module
final ModuleURN urn1 = new ModuleURN("invalidURN");
new ExpectedFailure<InvalidURNException>(Messages.INVALID_URN_SCHEME,
urn1.scheme(), urn1.toString(), ModuleURN.SCHEME){
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(urn1),
new DataRequest(SingleModuleFactory.INSTANCE_URN)
});
}
};
//invalid module URN for the second module
new ExpectedFailure<InvalidURNException>(Messages.INVALID_URN_SCHEME,
urn1.scheme(), urn1.toString(), ModuleURN.SCHEME){
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(SingleModuleFactory.INSTANCE_URN),
new DataRequest(urn1),
});
}
};
// A provider urn with a provider that doesn't exist
final ModuleURN urn2 = new ModuleURN("metc:not:exist");
//non-existent first module
new ExpectedFailure<ModuleNotFoundException>(Messages.MODULE_NOT_FOUND,
urn2.toString()){
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(urn2),
new DataRequest(SingleModuleFactory.INSTANCE_URN)
});
}
};
//non-existent second module
new ExpectedFailure<ModuleNotFoundException>(Messages.MODULE_NOT_FOUND,
urn2.toString()){
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(SingleModuleFactory.INSTANCE_URN),
new DataRequest(urn2)
});
}
};
// An instance urn for a module that does exist
final ModuleURN urn3 = new ModuleURN(
ComplexModuleFactory.PROVIDER_URN,"notexist");
//non-existent first module
new ExpectedFailure<ModuleNotFoundException>(Messages.MODULE_NOT_FOUND,
urn3.toString()){
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(urn3),
new DataRequest(SingleModuleFactory.INSTANCE_URN)
});
}
};
//non-existent second module
new ExpectedFailure<ModuleNotFoundException>(Messages.MODULE_NOT_FOUND,
urn3.toString()){
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(SingleModuleFactory.INSTANCE_URN),
new DataRequest(urn3)
});
}
};
//An instance urn for a module whose provider does not exist
final ModuleURN urn4 = new ModuleURN("metc:not:exist:no");
//non-existent first module
new ExpectedFailure<ModuleNotFoundException>(Messages.MODULE_NOT_FOUND,
urn4.toString()){
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(urn4),
new DataRequest(SingleModuleFactory.INSTANCE_URN)
});
}
}.getException().printStackTrace();
//non-existent second module
new ExpectedFailure<ModuleNotFoundException>(Messages.MODULE_NOT_FOUND,
urn4.toString()){
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(SingleModuleFactory.INSTANCE_URN),
new DataRequest(urn4)
});
}
};
//non-emitting first module
new ExpectedFailure<DataFlowException>(Messages.MODULE_NOT_EMITTER,
SingleModuleFactory.INSTANCE_URN.toString()) {
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(SingleModuleFactory.INSTANCE_URN),
new DataRequest(EmitterModuleFactory.INSTANCE_URN)
});
}
};
//start the emitter module so as to not get module not started errors.
startEmitter();
//non-emitting second module
new ExpectedFailure<DataFlowException>(Messages.MODULE_NOT_EMITTER,
SingleModuleFactory.INSTANCE_URN.toString()) {
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(EmitterModuleFactory.INSTANCE_URN),
new DataRequest(SingleModuleFactory.INSTANCE_URN),
new DataRequest(SinkModuleFactory.INSTANCE_URN)
},false);
}
};
//non-receiving second module
new ExpectedFailure<DataFlowException>(Messages.MODULE_NOT_RECEIVER,
SingleModuleFactory.INSTANCE_URN.toString()) {
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(EmitterModuleFactory.INSTANCE_URN),
new DataRequest(SingleModuleFactory.INSTANCE_URN)
});
}
};
//create a receiver module, its autostarted
final ModuleURN receiverURN = new ModuleURN(
ProcessorModuleFactory.PROVIDER_URN,"myreceiver");
sManager.createModule(ProcessorModuleFactory.PROVIDER_URN,receiverURN);
//non-receiving third module
new ExpectedFailure<DataFlowException>(Messages.MODULE_NOT_RECEIVER,
SingleModuleFactory.INSTANCE_URN.toString()) {
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(EmitterModuleFactory.INSTANCE_URN),
new DataRequest(receiverURN),
new DataRequest(SingleModuleFactory.INSTANCE_URN)
});
}
};
//create another receiver module.
final ModuleURN receiver2URN = new ModuleURN(
ProcessorModuleFactory.PROVIDER_URN,"mysecondreceiver");
sManager.createModule(ProcessorModuleFactory.PROVIDER_URN,receiver2URN);
//try creating a data flow such that the specified URN matches multiple
//modules, verify it fails.
final ModuleURN multiMatchURN = receiver2URN.parent();
HashSet actualParams = new HashSet<Object>(Arrays.asList(
new ExpectedFailure<ModuleNotFoundException>(
Messages.MULTIPLE_MODULES_MATCH_URN){
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(EmitterModuleFactory.INSTANCE_URN),
new DataRequest(multiMatchURN)
});
}
}.getException().getI18NBoundMessage().getParams()));
HashSet expectedParams = new HashSet<Object>(Arrays.asList(
multiMatchURN.getValue(), receiverURN.getValue(),
receiver2URN.getValue()));
//verify the message parameters
assertEquals(expectedParams, actualParams);
//verify this keyword expansion doesn't work
final ModuleURN requestURN = new ModuleURN(
ProcessorModuleFactory.PROVIDER_URN, "this");
new ExpectedFailure<InvalidURNException>(
Messages.INVALID_INSTANCE_URN,
requestURN.toString(),
requestURN.instanceName()){
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(EmitterModuleFactory.INSTANCE_URN),
new DataRequest(requestURN)
});
}
};
//Stop the receiver
sManager.stop(receiverURN);
//verify module stopped related failures
//last module stopped
new ExpectedFailure<ModuleStateException>(
Messages.DATAFLOW_FAILED_PCPT_MODULE_STATE_INCORRECT,
receiverURN.toString(), ModuleState.STOPPED,
ModuleState.PARTICIPATE_FLOW_STATES.toString()) {
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(EmitterModuleFactory.INSTANCE_URN),
new DataRequest(receiverURN),
},false);
}
};
//second module stopped
new ExpectedFailure<ModuleStateException>(
Messages.DATAFLOW_FAILED_PCPT_MODULE_STATE_INCORRECT,
receiverURN.toString(), ModuleState.STOPPED,
ModuleState.PARTICIPATE_FLOW_STATES.toString()) {
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(EmitterModuleFactory.INSTANCE_URN),
new DataRequest(receiverURN)});
}
};
//first module stopped
sManager.stop(EmitterModuleFactory.INSTANCE_URN);
new ExpectedFailure<ModuleStateException>(
Messages.DATAFLOW_FAILED_PCPT_MODULE_STATE_INCORRECT,
EmitterModuleFactory.INSTANCE_URN.toString(),
ModuleState.STOPPED,
ModuleState.PARTICIPATE_FLOW_STATES.toString()) {
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(EmitterModuleFactory.INSTANCE_URN),
new DataRequest(receiverURN)});
}
};
assertTrue(sManager.getDataFlows(true).isEmpty());
}
/**
* Tests module's auto-creation and deletion as it participates
* in data flows.
*
* @throws Exception if there were unexpected errors
*/
@Test
public void moduleAutoDelete() throws Exception {
//Start emitter module, if not already started
startEmitter();
final ModuleURN procURN = new ModuleURN(
ProcessorModuleFactory.PROVIDER_URN, "autod");
//verify that this module does not exist, so that we can verify
//it gets auto-instantiated.
List<ModuleURN> urns = sManager.getModuleInstances(
ProcessorModuleFactory.PROVIDER_URN);
assertFalse(urns.toString(), urns.contains(procURN));
//Create the first data flow
DataFlowID flowID1 = sManager.createDataFlow(new DataRequest[]{
new DataRequest(EmitterModuleFactory.INSTANCE_URN, "no"),
new DataRequest(procURN, String.class.getName())
});
//verify that the module has been created.
urns = sManager.getModuleInstances(
ProcessorModuleFactory.PROVIDER_URN);
assertTrue(urns.toString(), urns.contains(procURN));
assertFlowInfo(sManager.getDataFlowInfo(flowID1), flowID1, 3, true,
false, null, null);
assertModuleInfo(sManager, procURN, ModuleState.STARTED,
null, new DataFlowID[]{flowID1}, true, true, true, true, false);
//create another one
DataFlowID flowID2 = sManager.createDataFlow(new DataRequest[]{
new DataRequest(EmitterModuleFactory.INSTANCE_URN, "so"),
new DataRequest(procURN, String.class.getName())
});
assertFlowInfo(sManager.getDataFlowInfo(flowID2), flowID2, 3, true,
false, null, null);
assertModuleInfo(sManager, procURN, ModuleState.STARTED,
null, new DataFlowID[]{flowID1, flowID2}, true, true,
true, true, false);
//Stop the first flow.
sManager.cancel(flowID1);
//verify that the module is still there.
assertModuleInfo(sManager, procURN, ModuleState.STARTED,
null, new DataFlowID[]{flowID2}, true, true,
true, true, false);
//Stop the second flow
sManager.cancel(flowID2);
//verify that the module has been deleted.
urns = sManager.getModuleInstances(
ProcessorModuleFactory.PROVIDER_URN);
assertFalse(urns.toString(), urns.contains(procURN));
//verify that the auto-created module is not orphaned
//if the attempt to create a data flow fails
//Create a data flow that fails to setup
new ExpectedFailure<IllegalRequestParameterValue>(){
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(EmitterModuleFactory.INSTANCE_URN, null),
new DataRequest(procURN, String.class.getName())
});
}
};
//verify that the module does not exist
urns = sManager.getModuleInstances(
ProcessorModuleFactory.PROVIDER_URN);
assertFalse(urns.toString(), urns.contains(procURN));
}
/**
* Verify create data flow request errors due to errors raised by modules
*
* @throws Exception if there's an error
*/
@Test
public void createFlowModuleFailures() throws Exception {
//verify that there are no data flows
assertTrue(sManager.getDataFlows(true).isEmpty());
//Start emitter module, if not already started
startEmitter();
final ModuleURN procURN = new ModuleURN(
ProcessorModuleFactory.PROVIDER_URN, "failures");
//verify that this module does not exist, so that we can verify
//it gets auto-instantiated.
List<ModuleURN> urns = sManager.getModuleInstances(
ProcessorModuleFactory.PROVIDER_URN);
assertFalse(urns.toString(), urns.contains(procURN));
//test various emitter module failures: parm value
new ExpectedFailure<IllegalRequestParameterValue>(
Messages.ILLEGAL_REQ_PARM_VALUE,
EmitterModuleFactory.INSTANCE_URN.getValue(),
null) {
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(EmitterModuleFactory.INSTANCE_URN),
new DataRequest(procURN,String.class.getName())});
}
};
//verify that when a request to initate data flow fails any module
//that had sucessfully initiated requests have their requests
//canceled. In this case the processor module should have its
//request canceled.
ProcessorModule proc = (ProcessorModule) ModuleBase.getInstance(procURN);
assertEquals(0, proc.getNumRequests());
//test various emitter module failures: parm type
new ExpectedFailure<UnsupportedRequestParameterType>(
Messages.UNSUPPORTED_REQ_PARM_TYPE,
EmitterModuleFactory.INSTANCE_URN.getValue(),
Boolean.class.getName()) {
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(EmitterModuleFactory.INSTANCE_URN,
true),
new DataRequest(procURN, String.class.getName())});
}
};
//test processor module failures
new ExpectedFailure<IllegalRequestParameterValue>(
Messages.ILLEGAL_REQ_PARM_VALUE,
procURN.getValue(),
null) {
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(EmitterModuleFactory.INSTANCE_URN,
"send data"),
new DataRequest(procURN)});
}
};
new ExpectedFailure<UnsupportedRequestParameterType>(
Messages.UNSUPPORTED_REQ_PARM_TYPE,
procURN.getValue(),
Boolean.class.getName()) {
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(EmitterModuleFactory.INSTANCE_URN,
"send data"),
new DataRequest(procURN, true)});
}
};
new ExpectedFailure<IllegalRequestParameterValue>(
Messages.ILLEGAL_REQ_PARM_VALUE,
procURN.getValue(),
"blah") {
protected void run() throws Exception {
sManager.createDataFlow(new DataRequest[]{
new DataRequest(EmitterModuleFactory.INSTANCE_URN,
"send data"),
new DataRequest(procURN, "blah")});
}
};
}
/**
* Verify that if the module fails to start, any flows it created
* within its preStart() method are canceled.
*
* @throws Exception if there was an unexpected failure.
*/
@Test
public void preStartFlowsCleanup() throws Exception {
startEmitter();
//create a flow requester
final ModuleURN procURN = new ModuleURN(
FlowRequesterModuleFactory.PROVIDER_URN,
"prestart");
sManager.createModule(FlowRequesterModuleFactory.PROVIDER_URN, procURN);
//construct data request for it to issue.
DataRequest[] req = new DataRequest[]{
new DataRequest(EmitterModuleFactory.INSTANCE_URN,"somestring"),
new DataRequest(procURN, String.class.getName())
};
final FlowRequesterModule module = (FlowRequesterModule) ModuleBase.
getInstance(procURN);
assertNotNull(module);
module.setRequests(req);
module.setInvokeDefault(true);
module.setFailPreStart(true);
new ExpectedFailure<ModuleException>(
TestMessages.TEST_START_STOP_FAILURE){
protected void run() throws Exception {
sManager.start(procURN);
}
};
//verify module state
assertModuleInfo(sManager, procURN, ModuleState.START_FAILED, null,
null, false, false, true, true, true);
assertNotNull(module.getFlowID());
//verify that that the data flow is not running.
new ExpectedFailure<DataFlowNotFoundException>(
Messages.DATA_FLOW_NOT_FOUND,
module.getFlowID().getValue()){
protected void run() throws Exception {
sManager.getDataFlowInfo(module.getFlowID());
}
};
//verify the data flow in history.
DataFlowInfo flowInfo = sManager.getDataFlowHistory().get(0);
assertFlowInfo(flowInfo, module.getFlowID(), 3, true, true,
procURN, null);
}
/**
* Test data flow stop requested by an emitter.
*
* @throws Exception if there are unexpected errors
*/
@Test(timeout = 60000)
public void dataFlowStopEmitter() throws Exception {
assertTrue(sManager.getDataFlowHistory().isEmpty());
Map<String,Object> param = new HashMap<String, Object>();
final String emitData = "my data";
param.put("value", emitData);
param.put("error", TestMessages.EMIT_DATA_ERROR);
param.put("times", NUM_TIMES);
param.put("requestStop", Boolean.TRUE);
startEmitter();
ModuleURN procURN = new ModuleURN(ProcessorModuleFactory.PROVIDER_URN,
"emitFail");
DataFlowID flowID = sManager.createDataFlow(new DataRequest[]{
new DataRequest(EmitterModuleFactory.INSTANCE_URN, param),
new DataRequest(procURN, String.class.getName())
});
sSink.waitUntilTerminator();
List<DataFlowID> flows = sManager.getDataFlows(true);
assertEquals(1,flows.size());
assertEquals(flowID, flows.get(0));
EmitterModule.readyToProceed();
//wait for the flow to stop
while(!sManager.getDataFlows(true).isEmpty()) {
Thread.sleep(1000);
}
assertEquals(1, sManager.getDataFlowHistory().size());
assertFlowInfo(sManager.getDataFlowHistory().get(0),flowID,
3, true, true, null, EmitterModuleFactory.INSTANCE_URN);
verifyFlowSteps(param, EmitterModuleFactory.INSTANCE_URN,
procURN, sManager.getDataFlowHistory().get(0), true, false);
//verify emitter has the task stopped.
EmitterModule emitter = (EmitterModule) ModuleBase.getInstance(
EmitterModuleFactory.INSTANCE_URN);
final Set<RequestID> requestIDs = emitter.getRequests();
assertEquals(1, requestIDs.size());
Future<Integer> task = emitter.getTask(requestIDs.iterator().next());
assertTrue(task.isCancelled());
//reset the counter for test.
emitter.clear();
}
/**
* Tests data flow stop requested by a data receiver.
*
* @throws Exception if there were unexpected errors.
*/
@Test(timeout = 60000)
public void dataFlowStopReceiver() throws Exception {
assertTrue(sManager.getDataFlowHistory().isEmpty());
Map<String,Object> param = new HashMap<String, Object>();
final String emitData = "my data";
param.put("value", emitData);
param.put("error", TestMessages.EMIT_DATA_ERROR);
param.put("times", NUM_TIMES);
param.put("emitNull", null);
startEmitter();
ModuleURN procURN = new ModuleURN(ProcessorModuleFactory.PROVIDER_URN,
"receiveFail");
DataFlowID flowID = sManager.createDataFlow(new DataRequest[]{
new DataRequest(EmitterModuleFactory.INSTANCE_URN, param),
new DataRequest(procURN, String.class.getName())
});
List<DataFlowID> flows = sManager.getDataFlows(true);
assertEquals(1,flows.size());
assertEquals(flowID, flows.get(0));
sSink.waitUntilTerminator();
//Now let the emitter emit null
EmitterModule.readyToProceed();
//wait for the flow to stop
while(!sManager.getDataFlows(true).isEmpty()) {
Thread.sleep(1000);
}
assertEquals(1, sManager.getDataFlowHistory().size());
assertFlowInfo(sManager.getDataFlowHistory().get(0),flowID,
3, true, true, null, procURN);
verifyFlowSteps(param, EmitterModuleFactory.INSTANCE_URN, procURN,
sManager.getDataFlowHistory().get(0), false, true);
//verify emitter has the task stopped.
EmitterModule emitter = (EmitterModule) ModuleBase.getInstance(
EmitterModuleFactory.INSTANCE_URN);
final Set<RequestID> requestIDs = emitter.getRequests();
assertEquals(1, requestIDs.size());
Future<Integer> task = emitter.getTask(requestIDs.iterator().next());
assertTrue(task.isCancelled());
//reset the counter for test.
emitter.clear();
}
/**
* Verifies that any exceptions thrown by a module when canceling
* a request is ignored and doesn't prevent the rest of the modules
* in a data flow from getting their own request cancellations.
*
* @throws Exception if there were unexpected errors.
*/
@Test
public void requestCancelExceptionIgnored() throws Exception {
//Create a data flow, setup the emitter to throw an
//exception when its requested to cancel the data flow
//and verify that the data flow is canceled and that
//the processor got its request canceled.
ModuleURN procURN = new ModuleURN(ProcessorModuleFactory.PROVIDER_URN,
"cancelFail");
startEmitter();
DataFlowID flowID = sManager.createDataFlow(new DataRequest[]{
new DataRequest(EmitterModuleFactory.INSTANCE_URN, "something"),
new DataRequest(procURN, String.class.getName())
});
//Get a reference to the emitter
EmitterModule em = (EmitterModule) ModuleBase.getInstance(
EmitterModuleFactory.INSTANCE_URN);
assertEquals(1, em.getRequests().size());
//Get a reference to the processor
ProcessorModule pm = (ProcessorModule) ModuleBase.getInstance(procURN);
assertEquals(1, pm.getNumRequests());
//Setup emitter to throw exception on cancel
em.setThrowExceptionOnCancel(true);
//verify the flow
assertFlowInfo(sManager.getDataFlowInfo(flowID), flowID, 3,
true, false, null, null);
//cancel the flow
sManager.cancel(flowID);
//verify that the flows are no longer running
assertTrue(sManager.getDataFlows(true).isEmpty());
//verify both emitter and processor had their requests canceled.
assertEquals(0,pm.getNumRequests());
assertEquals(1,em.getRequests().size());
assertTrue(em.getTask(em.getRequests().iterator().next()).isCancelled());
}
/**
* Starts the emitter if its not already running.
*
* @throws ModuleException if there were errors.
*/
private static void startEmitter() throws ModuleException {
ModuleInfo info = sManager.getModuleInfo(EmitterModuleFactory.INSTANCE_URN);
if(!info.getState().isStarted()) {
sManager.start(EmitterModuleFactory.INSTANCE_URN);
}
}
/**
* Checks simple data flow of 3 modules, emitter, processor and sink.
*
* @param inInvokeDefault if the API that defaults append sink flag
* should be invoked.
* @param inAppendSink the value of append sink flag, if inInvokeDefault
* is false.
* @param inProcAutoCreated if the processor module was auto-created.
* @param inDataRequests the data requests, emitter module is
* automatically prepended to it.
*
* @throws Exception if there are errors
*/
private void checkDataFlowManager(boolean inInvokeDefault,
boolean inAppendSink,
boolean inProcAutoCreated,
DataRequest... inDataRequests)
throws Exception {
int numFlowHistory = sManager.getDataFlowHistory().size();
List<DataFlowID> flows;
//Initialize the request parameter for emitter.
Map<String,Object> param = new HashMap<String, Object>();
final String emitData = "my data";
param.put("value", emitData);
param.put("error", TestMessages.EMIT_DATA_ERROR);
param.put("times", NUM_TIMES);
//Prepend emitter to the supplied request.
final DataRequest[] requests = new DataRequest[inDataRequests.length + 1];
requests[0] = new DataRequest(EmitterModuleFactory.INSTANCE_URN, param);
System.arraycopy(inDataRequests,0,requests,1, inDataRequests.length);
//The processor module is always the second one, get its URL
ModuleURN procModuleURN = requests[1].getRequestURN();
DataFlowID flowID;
//Create the data flow
if (inInvokeDefault) {
flowID = sManager.createDataFlow(requests);
} else {
flowID = sManager.createDataFlow(requests,inAppendSink);
}
assertNotNull(flowID);
//verify that the flow ID is reported
flows = sManager.getDataFlows(true);
assertEquals(1, flows.size());
assertEquals(flowID, flows.get(0));
assertEquals(flows,sManager.getDataFlows(false));
// verify that we cannot stop a module when its participating
// in data flows
HashSet<DataFlowID> set = new HashSet<DataFlowID>();
set.add(flowID);
new ExpectedFailure<DataFlowException>(
Messages.CANNOT_STOP_MODULE_DATAFLOWS,
EmitterModuleFactory.INSTANCE_URN.toString(),
set.toString()){
protected void run() throws Exception {
sManager.stop(EmitterModuleFactory.INSTANCE_URN);
}
};
//wait until we get all the data through the sink
sSink.waitUntilTerminator();
//get data flow info for verification
DataFlowInfo flowInfo = sManager.getDataFlowInfo(flowID);
//now verify the flow info
assertFlowInfo(flowInfo,flowID, 3, true, false, null, null);
final ModuleURN actualProcURN = verifyFlowSteps(param,
EmitterModuleFactory.INSTANCE_URN, procModuleURN, flowInfo, false, false);
//verify module infos
assertModuleInfo(sManager.getModuleInfo(
EmitterModuleFactory.INSTANCE_URN),
EmitterModuleFactory.INSTANCE_URN,ModuleState.STARTED, null,
new DataFlowID[]{flowID},false, false, false, true, false);
assertModuleInfo(sManager.getModuleInfo(actualProcURN),
actualProcURN,ModuleState.STARTED, null,
new DataFlowID[]{flowID},inProcAutoCreated, true, true,
true, false);
assertModuleInfo(sManager.getModuleInfo(
SinkModuleFactory.INSTANCE_URN),
SinkModuleFactory.INSTANCE_URN,ModuleState.STARTED, null,
new DataFlowID[]{flowID},false, true, true, false, false);
//Verify that the emitter has the data flow ID
EmitterModule emitter = (EmitterModule) ModuleBase.getInstance(
EmitterModuleFactory.INSTANCE_URN);
assertTrue(emitter.getFlows().contains(flowID));
assertEquals(1, emitter.getFlows().size());
//verify processor was invoked with correct parameters
ProcessorModule proc = (ProcessorModule) ModuleBase.getInstance(actualProcURN);
assertEquals(1, proc.getNumRequests());
assertTrue(proc.isStartInvoked());
assertEquals(1, proc.getFlows().length);
assertEquals(flowID, proc.getFlows()[0]);
//cancel the data flow as soon as we get all the data
sManager.cancel(flowID);
//verify the received data
FlowData[] data = sSink.getData();
assertEquals(NUM_TIMES / 2, data.length);
for(FlowData d:data) {
assertEquals(flowID, d.getFirstMember());
assertEquals(emitData, d.getSecondMember());
}
//clear the sink
sSink.clear();
//verify that the modules have been stopped
//emitter
final Set<RequestID> requestIDs = emitter.getRequests();
assertEquals(1, requestIDs.size());
Future<Integer> task = emitter.getTask(requestIDs.iterator().next());
assertTrue(task.isCancelled());
//verify that the flow got canceled
assertTrue(emitter.getFlows().isEmpty());
//reset the counter for test.
emitter.clear();
//verify no flows running.
assertTrue(sManager.getDataFlows(true).isEmpty());
//verify processor was able to clear its state.
proc = (ProcessorModule) ModuleBase.getInstance(actualProcURN);
assertEquals(0, proc.getNumRequests());
assertEquals(0, proc.getFlows().length);
//verify flow history record
List<DataFlowInfo> history = sManager.getDataFlowHistory();
//should have one more record
assertEquals(numFlowHistory + 1, history.size());
//The record corresponding to this flow must be the first one.
//verify the record and the steps
assertFlowInfo(history.get(0), flowID, 3, true, true, null, null);
verifyFlowSteps(param, EmitterModuleFactory.INSTANCE_URN,
procModuleURN, history.get(0), false, false);
//if the processor module was auto-created, verify that it
//got deleted.
if(inProcAutoCreated) {
new ExpectedFailure<ModuleNotFoundException>(
Messages.MODULE_NOT_FOUND, actualProcURN.toString()) {
protected void run() throws Exception {
sManager.getModuleInfo(actualProcURN);
}
};
}
}
/**
* Checks simple data flow of 3 modules, emitter, processor and sink.
*
* @param inModule The flow requester module instance
* @param inEmitterURN the Emitter URN, if null the default value is used
* @param inInvokeDefault if the API that defaults append sink flag
* should be invoked.
* @param inAppendSink the value of append sink flag, if inInvokeDefault
* is false.
* @param inDataRequests the data requests, emitter module is
* automatically prepended to it. @throws Exception if there are errors
*
* @throws Exception if there's a failure
*/
private void checkDataFlowModule(FlowRequesterModule inModule,
ModuleURN inEmitterURN,
boolean inInvokeDefault,
boolean inAppendSink,
DataRequest... inDataRequests)
throws Exception {
int numFlowHistory = sManager.getDataFlowHistory().size();
List<DataFlowID> flows;
//Initialize the request parameter for emitter.
Map<String,Object> param = new HashMap<String, Object>();
final String emitData = "my data";
param.put("value", emitData);
param.put("error", TestMessages.EMIT_DATA_ERROR);
param.put("times", NUM_TIMES);
//Prepend emitter to the supplied request.
final DataRequest[] requests = new DataRequest[inDataRequests.length + 1];
if(inEmitterURN == null) {
inEmitterURN = EmitterModuleFactory.INSTANCE_URN;
}
requests[0] = new DataRequest(inEmitterURN, param);
System.arraycopy(inDataRequests,0,requests,1, inDataRequests.length);
//The processor module is always the second one, get its URL
ModuleURN procModuleURN = requests[1].getRequestURN();
DataFlowID flowID;
//Supply the data flow request parameters to the module
inModule.setRequests(requests);
inModule.setInvokeDefault(inInvokeDefault);
inModule.setAppendSink(inAppendSink);
//Start the module which should initiate the data flow.
sManager.start(inModule.getURN());
flowID = inModule.getFlowID();
assertNotNull(flowID);
//verify that the flow ID is reported
flows = sManager.getDataFlows(true);
assertEquals(1, flows.size());
assertEquals(flowID, flows.get(0));
//verify that this flow gets filtered out as its module initiated.
assertTrue(sManager.getDataFlows(false).isEmpty());
//wait until we get all the data through the sink
sSink.waitUntilTerminator();
//get data flow info for verification
DataFlowInfo flowInfo = sManager.getDataFlowInfo(flowID);
//now verify the flow info
assertFlowInfo(flowInfo,flowID, 3, true, false, inModule.getURN(), null);
ModuleURN actualProcURN = verifyFlowSteps(param, inEmitterURN,
procModuleURN, flowInfo, false, false);
//verify module infos
ModuleTestBase.assertModuleInfo(sManager.getModuleInfo(
EmitterModuleFactory.INSTANCE_URN),
EmitterModuleFactory.INSTANCE_URN,ModuleState.STARTED, null,
new DataFlowID[]{flowID},false, false, false, true, false);
ModuleTestBase.assertModuleInfo(sManager.getModuleInfo(actualProcURN),
actualProcURN,ModuleState.STARTED, new DataFlowID[]{flowID},
new DataFlowID[]{flowID},false, false, true, true, true);
ModuleTestBase.assertModuleInfo(sManager.getModuleInfo(
SinkModuleFactory.INSTANCE_URN),
SinkModuleFactory.INSTANCE_URN,ModuleState.STARTED, null,
new DataFlowID[]{flowID},false, true, true, false, false);
//Verify that the emitter has the data flow ID
EmitterModule emitter = (EmitterModule) ModuleBase.getInstance(
EmitterModuleFactory.INSTANCE_URN);
assertTrue(emitter.getFlows().contains(flowID));
assertEquals(1, emitter.getFlows().size());
//verify processor was invoked with correct parameters
ProcessorModule proc = (ProcessorModule) ModuleBase.getInstance(actualProcURN);
assertEquals(1, proc.getNumRequests());
assertTrue(proc.isStartInvoked());
assertEquals(1, proc.getFlows().length);
assertEquals(flowID, proc.getFlows()[0]);
//cancel the data flow as soon as we get all the data by stopping the module
sManager.stop(inModule.getURN());
//verify the received data
FlowData[] data = sSink.getData();
assertEquals(NUM_TIMES / 2, data.length);
for(FlowData d:data) {
assertEquals(flowID, d.getFirstMember());
assertEquals(emitData, d.getSecondMember());
}
//clear the sink
sSink.clear();
//verify that the modules have been stopped
//emitter
final Set<RequestID> requestIDs = emitter.getRequests();
assertEquals(1, requestIDs.size());
Future<Integer> task = emitter.getTask(requestIDs.iterator().next());
assertTrue(task.isCancelled());
//verify that the flow got canceled
assertTrue(emitter.getFlows().isEmpty());
//reset the counter for test.
emitter.clear();
//verify processor was started.
proc = (ProcessorModule) ModuleBase.getInstance(actualProcURN);
assertEquals(0, proc.getNumRequests());
assertTrue(proc.isStartInvoked());
assertTrue(proc.isStopInvoked());
//verify no flows running.
assertTrue(sManager.getDataFlows(true).isEmpty());
//verify flow history record
List<DataFlowInfo> history = sManager.getDataFlowHistory();
//should have one more record
assertEquals(numFlowHistory + 1, history.size());
//The record corresponding to this flow must be the first one.
//verify the record and the steps
assertFlowInfo(history.get(0), flowID, 3, true, true, inModule.getURN(),
inModule.isSkipCancel()
? null
: inModule.getURN());
verifyFlowSteps(param, inEmitterURN, procModuleURN,
history.get(0), false, false);
}
private ModuleURN verifyFlowSteps(Map<String, Object> inParam,
ModuleURN inEmitterURN,
ModuleURN inProcModuleURN,
DataFlowInfo inFlowInfo,
boolean inEmitStop,
boolean inReceiveStop) {
assertFlowStep(inFlowInfo.getFlowSteps()[0],
EmitterModuleFactory.INSTANCE_URN,
true,
NUM_TIMES + 1 + (inReceiveStop? 1:0),
NUM_TIMES + (inEmitStop? 1:0),
inEmitStop
? TestMessages.STOP_DATA_FLOW.getText()
: TestMessages.EMIT_DATA_ERROR.getText(),
false,
0,
0,
null,
inEmitterURN,
inParam.toString());
assertFlowStep(inFlowInfo.getFlowSteps()[1],
// The actual URN may be different from the
// supplied one, if the supplied one was
// abbreviated, do not check
null,
true,
NUM_TIMES / 2 + 1,
0,
null,
true,
NUM_TIMES + 1 + (inReceiveStop? 1: 0),
NUM_TIMES / 2 + (inReceiveStop? 1: 0),
inReceiveStop
? TestMessages.STOP_DATA_FLOW.getText()
: TestMessages.BAD_DATA.getText(),
inProcModuleURN,
String.class.getName());
ModuleURN actualProcURN = inFlowInfo.getFlowSteps()[1].getModuleURN();
assertFlowStep(inFlowInfo.getFlowSteps()[2],
SinkModuleFactory.INSTANCE_URN,
false,
0,
0,
null,
true,
NUM_TIMES / 2 + 1,
0,
null,
//Requested URN may be an abbreviated one
//skip the check
null,
null);
return actualProcURN;
}
private static ModuleManager sManager;
private static final int NUM_TIMES = 6;
private static Sink sSink = new Sink();
}