/** * Tests if a {@link Component}'s execution is not considered if the {@link ComponentExecutor} got * cancelled before the actual run was performed. * * @throws ComponentExecutionException on unexpected error * @throws ComponentException on unexpected error * @throws InterruptedException on unexpected interruption * @throws ExecutionException on unexpected interruption */ @Test(timeout = TEST_TIMEOUT_500_MSEC) public void testOnCancelledBeforeExecuteByConsLimWasCalled() throws ComponentException, ComponentExecutionException, InterruptedException, ExecutionException { final ComponentExecutionRelatedInstances compExeRelatedInstancesStub = createComponentExecutionRelatedInstancesStub(); final ComponentExecutor compExecutor = new ComponentExecutor(compExeRelatedInstancesStub, ComponentExecutionType.ProcessInputs); Future<Boolean> cancelTask = ConcurrencyUtils.getAsyncTaskService() .submit( new Callable<Boolean>() { @Override public Boolean call() throws Exception { compExecutor.onCancelled(); boolean isComponentKnownCanceled = compExeRelatedInstancesStub.compExeRelatedStates.isComponentCancelled.get(); return isComponentKnownCanceled; } }); assertFalse(cancelTask.get()); compExecutor.executeByConsideringLimitations(); assertTrue(compExeRelatedInstancesStub.compExeRelatedStates.isComponentCancelled.get()); }
/** OSGi-DS lifecycle method. Starts background logging of accumulated log lines. */ public void activate() { enabled = (System.getProperty(SYSTEM_PROPERTY_FOR_ACTIVATION) != null); if (!enabled) { log.debug("Combined workflow console log is disabled"); return; } // TODO improve filename, locking/uniqueness etc. String logFileName = StringUtils.format("console.combined.%d.log", System.currentTimeMillis()); File outputDir = configurationService.getConfigurablePath(ConfigurablePathId.PROFILE_OUTPUT); logFile = new File(outputDir, logFileName); try { fileWriter = new BufferedWriter(new FileWriter(logFile)); // TODO use the thread pool instead? backgroundWriterTask = new BackgroundLogWriterTask(fileWriter, Thread.MIN_PRIORITY); backgroundTaskFuture = ConcurrencyUtils.getAsyncTaskService() .submit(backgroundWriterTask, "Common ConsoleRow log " + logFile.getAbsolutePath()); log.debug( "Logging combined workflow console output to " + logFileName + " (NOTE: may not capture all output yet)"); // TODO 5.0 } catch (IOException e) { log.error("Failed to set up background console logging to " + logFileName, e); } }
/** * Tests if waiting for execution permission is interrupted if component is cancelled. * * @throws ComponentExecutionException on unexpected error * @throws ComponentException on unexpected error * @throws InterruptedException on unexpected interruption * @throws ExecutionException on unexpected interruption */ @Test(timeout = TEST_TIMEOUT_500_MSEC) public void testWaitingForExecutionPermissionOnCancelled() throws ComponentException, ComponentExecutionException, InterruptedException, ExecutionException { ComponentExecutionPermitsService compExePermitsService = createComponentExecutionPermitServiceMock(false); final ComponentExecutionRelatedInstances compExeRelatedInstancesStub = createComponentExecutionRelatedInstancesStub(); final ComponentExecutor compExecutor = new ComponentExecutor(compExeRelatedInstancesStub, ComponentExecutionType.ProcessInputs); compExecutor.bindComponentExecutionPermitsService(compExePermitsService); final int delayMsec = 100; ConcurrencyUtils.getAsyncTaskService() .scheduleAfterDelay( new Runnable() { @TaskDescription("Delayed cancel call") @Override public void run() { compExecutor.onCancelled(); } }, delayMsec); compExecutor.acquireExecutionPermission(); EasyMock.verify(compExePermitsService); assertTrue(compExeRelatedInstancesStub.compExeRelatedStates.isComponentCancelled.get()); }
/** * Tests if a {@link Component}'s execution is not considered if the {@link ComponentExecutor} got * cancelled before the actual run was performed. * * @throws ComponentExecutionException on unexpected error * @throws ComponentException on unexpected error * @throws InterruptedException on unexpected interruption * @throws ExecutionException on unexpected interruption */ @Test(timeout = TEST_TIMEOUT_500_MSEC) public void testOnCancelledDuringExecuteByConsLimWasCalled() throws ComponentException, ComponentExecutionException, InterruptedException, ExecutionException { ComponentExecutionPermitsService compExePermitsService = createComponentExecutionPermitServiceMock(); final ComponentExecutionRelatedInstances compExeRelatedInstancesStub = createComponentExecutionRelatedInstancesStub(); final ComponentExecutor compExecutor = new ComponentExecutor(compExeRelatedInstancesStub, ComponentExecutionType.ProcessInputs); compExecutor.bindComponentExecutionPermitsService(compExePermitsService); compExecutor.acquireExecutionPermission(); Future<Boolean> cancelTask = ConcurrencyUtils.getAsyncTaskService() .submit( new Callable<Boolean>() { @Override public Boolean call() throws Exception { compExecutor.onCancelled(); return compExeRelatedInstancesStub.compExeRelatedStates.isComponentCancelled .get(); } }); assertFalse(cancelTask.get()); compExecutor.performExecutionAndReleasePermission(); EasyMock.verify(compExePermitsService); assertTrue(compExeRelatedInstancesStub.compExeRelatedStates.isComponentCancelled.get()); }
/** * Tests canceling of {@link Component#processInputs()} in failure case, that means {@link * Component#processInputs()} doesn't return within expected amount of time. * * @throws ComponentExecutionException on unexpected error * @throws ComponentException on unexpected error * @throws InterruptedException on unexpected error * @throws ExecutionException on unexpected error */ @Test(timeout = TEST_TIMEOUT_500_MSEC) public void testCancelProcessingInputsFailure() throws ComponentExecutionException, ComponentException, InterruptedException, ExecutionException { ComponentExecutionRelatedInstances compExeRelatedInstancesStub = createComponentExecutionRelatedInstancesStub(); final CountDownLatch processInputsCalledLatch = new CountDownLatch(1); Component compStub = new ComponentDefaultStub.Default() { private int processInputsCount = 0; private int onProcessInputsInterruptedCount = 0; @Override public void processInputs() throws ComponentException { if (processInputsCount > 0) { fail("'processInputs' is expected to be called only once"); } processInputsCalledLatch.countDown(); final CountDownLatch dummyLatch = new CountDownLatch(1); while (true) { try { dummyLatch.await(); } catch (InterruptedException e) { // ignore for test purposes e = null; } } } @Override public void onProcessInputsInterrupted(ThreadHandler executingThreadHandler) { if (onProcessInputsInterruptedCount > 0) { fail("'onProcessInputsInterrupted' is expected to be called only once"); } } }; compExeRelatedInstancesStub.component.set(compStub); ComponentStateMachine compStateMachineMock = EasyMock.createStrictMock(ComponentStateMachine.class); Capture<ComponentStateMachineEvent> compStateMachineEventCapture = new Capture<>(); compStateMachineMock.postEvent(EasyMock.capture(compStateMachineEventCapture)); EasyMock.expectLastCall(); EasyMock.replay(compStateMachineMock); compExeRelatedInstancesStub.compStateMachine = compStateMachineMock; ComponentExecutionStorageBridge compExeStorageBridgeMock = createComponentExecutionStorageBridgeRunFailure(compExeRelatedInstancesStub); compExeRelatedInstancesStub.compExeStorageBridge = compExeStorageBridgeMock; ComponentContextBridge compCtxBridgeMock = EasyMock.createStrictMock(ComponentContextBridge.class); EasyMock.expect(compCtxBridgeMock.getEndpointDatumsForExecution()) .andStubReturn(new HashMap<String, EndpointDatum>()); EasyMock.replay(compCtxBridgeMock); compExeRelatedInstancesStub.compCtxBridge = compCtxBridgeMock; compExeRelatedInstancesStub.compExeScheduler = createComponentExecutionSchedulerMock(false); Capture<ConsoleRow.Type> consoleRowTypeCapture = new Capture<>(); Capture<String> logMessageCapture = new Capture<>(); ConsoleRowsSender consoleRowsSenderMock = createConsoleRowsSenderMock(consoleRowTypeCapture, logMessageCapture); compExeRelatedInstancesStub.consoleRowsSender = consoleRowsSenderMock; ComponentExecutionStatsService compExeStatsServiceMock = createComponentExecutionStatsServiceMock(compExeRelatedInstancesStub); final ComponentExecutor compExecutor = new ComponentExecutor(compExeRelatedInstancesStub, ComponentExecutionType.ProcessInputs); compExecutor.bindComponentExecutionPermitsService(createComponentExecutionPermitServiceMock()); compExecutor.bindComponentExecutionStatsService(compExeStatsServiceMock); ComponentExecutor.waitIntervalAfterCacelledCalledMSec = WAIT_INTERVAL_100_MSEC; final AtomicReference<Exception> expectedExceptionRef = new AtomicReference<Exception>(null); final CountDownLatch executedLatch = new CountDownLatch(1); final Future<?> executeTask = ConcurrencyUtils.getAsyncTaskService() .submit( new Runnable() { @Override public void run() { try { compExecutor.executeByConsideringLimitations(); } catch (ComponentException | ComponentExecutionException e) { expectedExceptionRef.set(e); } executedLatch.countDown(); } }); processInputsCalledLatch.await(); compExecutor.onCancelled(); executeTask.cancel(true); executedLatch.await(); assertNotNull(expectedExceptionRef.get()); assertTrue(expectedExceptionRef.get() instanceof ComponentException); assertFailureHandling( consoleRowTypeCapture, logMessageCapture, (ComponentException) expectedExceptionRef.get(), "didn't terminate in time"); assertTrue(compExeRelatedInstancesStub.compExeRelatedStates.isComponentCancelled.get()); EasyMock.verify(compStateMachineMock); assertEquals( ComponentStateMachineEventType.RUNNING, compStateMachineEventCapture.getValue().getType()); assertEquals( ComponentState.PROCESSING_INPUTS, compStateMachineEventCapture.getValue().getNewComponentState()); EasyMock.verify(compExeStorageBridgeMock); EasyMock.verify(consoleRowsSenderMock); }
/** * Tests canceling of {@link Component#processInputs()} in success case, that means {@link * Component#processInputs()} returns within expected amount of time. * * @throws ComponentExecutionException on unexpected error * @throws ComponentException on unexpected error * @throws InterruptedException on unexpected error * @throws ExecutionException on unexpected error */ @Test(timeout = TEST_TIMEOUT_500_MSEC) public void testCancelProcessingInputsSuccess() throws ComponentExecutionException, ComponentException, InterruptedException, ExecutionException { ComponentExecutionRelatedInstances compExeRelatedInstancesStub = createComponentExecutionRelatedInstancesStub(); final AtomicReference<CountDownLatch> countDownLatchRef = new AtomicReference<CountDownLatch>(new CountDownLatch(1)); Component compStub = new ComponentDefaultStub.Default() { private int processInputsCount = 0; private int onProcessInputsInterruptedCount = 0; @Override public void processInputs() throws ComponentException { if (processInputsCount > 0) { fail("'processInputs' is expected to be called only once"); } try { countDownLatchRef.get().await(); } catch (InterruptedException e) { fail("unexpected InterruptedException"); } } @Override public void onProcessInputsInterrupted(ThreadHandler executingThreadHandler) { if (onProcessInputsInterruptedCount > 0) { fail("'onProcessInputsInterrupted' is expected to be called only once"); } countDownLatchRef.get().countDown(); } }; compExeRelatedInstancesStub.component.set(compStub); Capture<ComponentStateMachineEvent> compStateMachineEventCapture = new Capture<>(); ComponentStateMachine compStateMachineMock = createComponentStateMachineEventForRuns(compStateMachineEventCapture); compExeRelatedInstancesStub.compStateMachine = compStateMachineMock; ComponentExecutionStorageBridge compExeStorageBridgeMock = createComponentExecutionStorageBridgeRunSuccess(compExeRelatedInstancesStub); compExeRelatedInstancesStub.compExeStorageBridge = compExeStorageBridgeMock; ComponentContextBridge compCtxBridgeMock = EasyMock.createStrictMock(ComponentContextBridge.class); EasyMock.expect(compCtxBridgeMock.getEndpointDatumsForExecution()) .andStubReturn(new HashMap<String, EndpointDatum>()); EasyMock.replay(compCtxBridgeMock); compExeRelatedInstancesStub.compCtxBridge = compCtxBridgeMock; compExeRelatedInstancesStub.compExeScheduler = createComponentExecutionSchedulerMock(false); ConsoleRowsSender consoleRowsSenderMock = createConsoleRowsSenderMock(null, null); compExeRelatedInstancesStub.consoleRowsSender = consoleRowsSenderMock; ComponentExecutionStatsService compExeStatsServiceMock = createComponentExecutionStatsServiceMock(compExeRelatedInstancesStub); final ComponentExecutor compExecutor = new ComponentExecutor(compExeRelatedInstancesStub, ComponentExecutionType.ProcessInputs); compExecutor.bindComponentExecutionPermitsService(createComponentExecutionPermitServiceMock()); compExecutor.bindComponentExecutionStatsService(compExeStatsServiceMock); final int delayMsec = 100; ConcurrencyUtils.getAsyncTaskService() .scheduleAfterDelay( new Runnable() { @TaskDescription("Delayed cancel call") @Override public void run() { compExecutor.onCancelled(); } }, delayMsec); compExecutor.executeByConsideringLimitations(); assertTrue(compExeRelatedInstancesStub.compExeRelatedStates.isComponentCancelled.get()); EasyMock.verify(compStateMachineMock); assertEquals( ComponentStateMachineEventType.RUNNING, compStateMachineEventCapture.getValue().getType()); assertEquals( ComponentState.PROCESSING_INPUTS, compStateMachineEventCapture.getValue().getNewComponentState()); EasyMock.verify(compExeStorageBridgeMock); EasyMock.verify(consoleRowsSenderMock); }
public AbstractStateMachine(S initialState) { this.currentState = initialState; this.eventQueue = ConcurrencyUtils.getFactory() .createAsyncOrderedExecutionQueue(AsyncCallbackExceptionPolicy.LOG_AND_PROCEED); }