use of org.eclipse.scout.rt.testing.platform.util.BlockingCountDownLatch in project scout.rt by eclipse.
the class JobStateTest method testWaitingForMutexAndBlockingCondition.
@Test
// regression
@Times(100)
public void testWaitingForMutexAndBlockingCondition() throws ThreadInterruptedError, java.lang.InterruptedException {
JobEventCaptureListener captureListener = new JobEventCaptureListener();
Jobs.getJobManager().addListener(captureListener);
final BlockingCountDownLatch job1RunningLatch = new BlockingCountDownLatch(1);
final BlockingCountDownLatch job2RunningLatch = new BlockingCountDownLatch(1);
final BlockingCountDownLatch job2UnblockedLatch = new BlockingCountDownLatch(1);
final BlockingCountDownLatch job3RunningLatch = new BlockingCountDownLatch(1);
final IBlockingCondition condition = Jobs.newBlockingCondition(true);
final IExecutionSemaphore mutex = Jobs.newExecutionSemaphore(1);
// Schedule job-1
IFuture<Void> future1 = Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
job1RunningLatch.countDownAndBlock();
}
}, Jobs.newInput().withName("job-1").withExecutionSemaphore(mutex));
// wait until running (for idempotent event assertion)
assertTrue(job1RunningLatch.await());
// Schedule job-2
IFuture<Void> future2 = Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
job2RunningLatch.countDownAndBlock();
condition.waitFor();
job2UnblockedLatch.countDownAndBlock();
}
}, Jobs.newInput().withName("job-2").withExecutionSemaphore(mutex));
// Wait until competing for a permit.
// That is for idempotent event assertion, because permit is acquired asynchronously in another thread.
// However, permit acquisition is guaranteed to be in the 'as-scheduled' order. Nevertheless, the SCHEDULING and PENDING event of the next job would possibly interfere.
JobTestUtil.waitForPermitCompetitors(mutex, 2);
// Schedule job-3
IFuture<Void> future3 = Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
job3RunningLatch.countDownAndBlock();
JobTestUtil.waitForPermitCompetitors(mutex, 2);
}
}, Jobs.newInput().withName("job-3").withExecutionSemaphore(mutex));
// Wait until competing for a permit.
// That is for idempotent event assertion, because permit is acquired asynchronously in another thread.
// However, permit acquisition is guaranteed to be in the 'as-scheduled' order. Nevertheless, the SCHEDULING and PENDING event of the next job would possibly interfere.
JobTestUtil.waitForPermitCompetitors(mutex, 3);
assertEquals(JobState.RUNNING, future1.getState());
assertEquals(JobState.WAITING_FOR_PERMIT, future2.getState());
assertEquals(JobState.WAITING_FOR_PERMIT, future3.getState());
job1RunningLatch.unblock();
job2RunningLatch.await();
assertEquals(JobState.DONE, future1.getState());
assertEquals(JobState.RUNNING, future2.getState());
assertEquals(JobState.WAITING_FOR_PERMIT, future3.getState());
job2RunningLatch.unblock();
job3RunningLatch.await();
assertEquals(JobState.DONE, future1.getState());
assertEquals(JobState.WAITING_FOR_BLOCKING_CONDITION, future2.getState());
assertEquals(JobState.RUNNING, future3.getState());
condition.setBlocking(false);
// job-2 and job-3
JobTestUtil.waitForPermitCompetitors(mutex, 2);
assertEquals(JobState.DONE, future1.getState());
assertEquals(JobState.WAITING_FOR_PERMIT, future2.getState());
assertEquals(JobState.RUNNING, future3.getState());
job3RunningLatch.unblock();
job2UnblockedLatch.await();
assertEquals(JobState.DONE, future1.getState());
assertEquals(JobState.RUNNING, future2.getState());
assertEquals(JobState.DONE, future3.getState());
job2UnblockedLatch.unblock();
future2.awaitDoneAndGet(5, TimeUnit.SECONDS);
future3.awaitDoneAndGet(5, TimeUnit.SECONDS);
assertEquals(JobState.DONE, future1.getState());
assertEquals(JobState.DONE, future2.getState());
assertEquals(JobState.DONE, future3.getState());
// verify events
int i = -1;
List<JobEvent> capturedEvents = captureListener.getCapturedEvents();
List<JobState> capturedFutureStates = captureListener.getCapturedFutureStates();
i++;
assertStateChangedEvent(future1, JobState.SCHEDULED, capturedEvents.get(i));
assertEquals(JobState.SCHEDULED, capturedFutureStates.get(i));
i++;
assertStateChangedEvent(future1, JobState.WAITING_FOR_PERMIT, capturedEvents.get(i));
assertEquals(JobState.WAITING_FOR_PERMIT, capturedFutureStates.get(i));
i++;
assertStateChangedEvent(future1, JobState.RUNNING, capturedEvents.get(i));
assertEquals(JobState.RUNNING, capturedFutureStates.get(i));
i++;
assertStateChangedEvent(future2, JobState.SCHEDULED, capturedEvents.get(i));
assertEquals(JobState.SCHEDULED, capturedFutureStates.get(i));
i++;
assertStateChangedEvent(future2, JobState.WAITING_FOR_PERMIT, capturedEvents.get(i));
assertEquals(JobState.WAITING_FOR_PERMIT, capturedFutureStates.get(i));
i++;
assertStateChangedEvent(future3, JobState.SCHEDULED, capturedEvents.get(i));
assertEquals(JobState.SCHEDULED, capturedFutureStates.get(i));
i++;
assertStateChangedEvent(future3, JobState.WAITING_FOR_PERMIT, capturedEvents.get(i));
assertEquals(JobState.WAITING_FOR_PERMIT, capturedFutureStates.get(i));
i++;
assertStateChangedEvent(future1, JobState.DONE, capturedEvents.get(i));
assertEquals(JobState.DONE, capturedFutureStates.get(i));
i++;
assertStateChangedEvent(future2, JobState.RUNNING, capturedEvents.get(i));
assertEquals(JobState.RUNNING, capturedFutureStates.get(i));
i++;
assertBlockedStateEvent(future2, condition, capturedEvents.get(i));
assertEquals(JobState.WAITING_FOR_BLOCKING_CONDITION, capturedFutureStates.get(i));
i++;
assertStateChangedEvent(future3, JobState.RUNNING, capturedEvents.get(i));
assertEquals(JobState.RUNNING, capturedFutureStates.get(i));
i++;
assertStateChangedEvent(future2, JobState.WAITING_FOR_PERMIT, capturedEvents.get(i));
assertEquals(JobState.WAITING_FOR_PERMIT, capturedFutureStates.get(i));
i++;
assertStateChangedEvent(future3, JobState.DONE, capturedEvents.get(i));
assertEquals(JobState.DONE, capturedFutureStates.get(i));
i++;
assertStateChangedEvent(future2, JobState.RUNNING, capturedEvents.get(i));
assertEquals(JobState.RUNNING, capturedFutureStates.get(i));
i++;
assertStateChangedEvent(future2, JobState.DONE, capturedEvents.get(i));
assertEquals(JobState.DONE, capturedFutureStates.get(i));
assertEquals(i + 1, capturedEvents.size());
}
use of org.eclipse.scout.rt.testing.platform.util.BlockingCountDownLatch in project scout.rt by eclipse.
the class PeriodicJobMutexTest method testInternal.
/**
* This test schedules a job according to the given input.
* <p>
* After 2 iterations, the periodic job is cancelled. While running, this job is checked to be the mutex owner. Then,
* another job with the same mutex is scheduled and awaited for (timeout expected because mutual exclusion). And
* finally, another job with the same mutex is scheduled, which is expected to be run after the timed out job. Both
* that jobs are expected to be run right after one iterations completes.
*/
private void testInternal(final ScheduleBuilder<? extends Trigger> periodicScheduleBuilder, final IExecutionSemaphore executionSemaphore) {
// synchronized because modified/read by different threads.
final List<String> protocol = Collections.synchronizedList(new ArrayList<String>());
final AtomicInteger rounds = new AtomicInteger(0);
final BlockingCountDownLatch latch = new BlockingCountDownLatch(2);
// Schedule other job
Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
protocol.add("other job");
latch.countDown();
}
}, Jobs.newInput().withExecutionSemaphore(executionSemaphore));
Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
latch.await();
// cancel after 2 iterations
if (rounds.getAndIncrement() == 2) {
IFuture.CURRENT.get().cancel(false);
return;
}
protocol.add("begin");
// This task should be mutex-owner
IFuture<?> currentFuture = IFuture.CURRENT.get();
IExecutionSemaphore mutex = currentFuture.getExecutionSemaphore();
if (mutex != null && mutex.isPermitOwner(currentFuture)) {
protocol.add("mutex-owner");
}
// Schedule other job with same mutex, and wait for it to complete.
// expected: that job must not commence execution until the periodic job completes this iteration
// However, to circumvent deadlock-detection, schedule this job within another job, that is not mutex owner
Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
try {
Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
protocol.add("running-2");
}
}, Jobs.newInput().withExecutionSemaphore(executionSemaphore).withExecutionHint(JOB_IDENTIFIER)).awaitDone(200, TimeUnit.MILLISECONDS);
} catch (TimedOutError e) {
protocol.add("timeout-because-mutex-owner");
}
}
}, Jobs.newInput().withExecutionHint(JOB_IDENTIFIER)).awaitDone();
// Schedule other job with same mutex
// expected: must only commence execution once this iteration completes.
Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
protocol.add("running-3");
}
}, Jobs.newInput().withExecutionSemaphore(executionSemaphore).withExecutionHint(JOB_IDENTIFIER));
protocol.add("end");
}
}, Jobs.newInput().withExecutionHint(JOB_IDENTIFIER).withExecutionSemaphore(executionSemaphore).withExecutionTrigger(Jobs.newExecutionTrigger().withStartIn(200, // execute with a delay
TimeUnit.MILLISECONDS).withSchedule(// periodic schedule plan
periodicScheduleBuilder)));
latch.countDown();
// Wait for the job to complete
Jobs.getJobManager().awaitDone(Jobs.newFutureFilterBuilder().andMatchExecutionHint(JOB_IDENTIFIER).toFilter(), 10, TimeUnit.SECONDS);
List<String> expected = new ArrayList<String>();
expected.add("other job");
expected.add("begin");
expected.add("mutex-owner");
expected.add("timeout-because-mutex-owner");
expected.add("end");
expected.add("running-2");
expected.add("running-3");
expected.add("begin");
expected.add("mutex-owner");
expected.add("timeout-because-mutex-owner");
expected.add("end");
expected.add("running-2");
expected.add("running-3");
assertEquals(expected, protocol);
}
use of org.eclipse.scout.rt.testing.platform.util.BlockingCountDownLatch in project scout.rt by eclipse.
the class WhenDoneScheduleTest method testFunctionFutureState.
@Test
public void testFunctionFutureState() throws InterruptedException {
final BlockingCountDownLatch jobRunningLatch = new BlockingCountDownLatch(1);
final BlockingCountDownLatch functionJobRunningLatch = new BlockingCountDownLatch(1);
// Schedule future
IFuture<Void> future = Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
jobRunningLatch.countDownAndBlock();
}
}, Jobs.newInput().withExecutionHint(JOB_MARKER));
// Schedule function
IFuture<Void> functionFuture = future.whenDoneSchedule(new IBiConsumer<Void, Throwable>() {
@Override
public void accept(Void result, Throwable u) {
try {
functionJobRunningLatch.countDownAndBlock();
} catch (InterruptedException e) {
throw new ThreadInterruptedError("interrupted", e);
}
}
}, Jobs.newInput().withExecutionHint(JOB_MARKER));
assertTrue(jobRunningLatch.await());
assertEquals(JobState.RUNNING, future.getState());
assertEquals(JobState.NEW, functionFuture.getState());
jobRunningLatch.unblock();
assertTrue(functionJobRunningLatch.await());
assertEquals(JobState.DONE, future.getState());
assertEquals(JobState.RUNNING, functionFuture.getState());
functionJobRunningLatch.unblock();
// Wait until the job jobs are done
Jobs.getJobManager().awaitDone(Jobs.newFutureFilterBuilder().andMatchExecutionHint(JOB_MARKER).toFilter(), 5, TimeUnit.SECONDS);
assertEquals(JobState.DONE, functionFuture.getState());
assertEquals(JobState.DONE, future.getState());
}
use of org.eclipse.scout.rt.testing.platform.util.BlockingCountDownLatch in project scout.rt by eclipse.
the class WhenDoneScheduleTest method testCancellationOfSharedRunMonitor.
@Test
public void testCancellationOfSharedRunMonitor() throws InterruptedException {
final BlockingCountDownLatch setupLatch = new BlockingCountDownLatch(1);
RunMonitor sharedRunMonitor = BEANS.get(RunMonitor.class);
// Schedule future
IFuture<String> future = Jobs.schedule(new Callable<String>() {
@Override
public String call() throws Exception {
setupLatch.countDownAndBlock();
return "abc";
}
}, Jobs.newInput().withExceptionHandling(null, // to not work with JUnitExceptionHandler
true).withRunContext(RunContexts.empty().withRunMonitor(sharedRunMonitor)).withExecutionHint(JOB_MARKER));
// Schedule function
final AtomicBoolean functionExecuted = new AtomicBoolean(false);
IFuture<Void> functionFuture = future.whenDoneSchedule(new IBiFunction<String, Throwable, Void>() {
@Override
public Void apply(String result, Throwable error) {
functionExecuted.set(true);
return null;
}
}, Jobs.newInput().withRunContext(RunContexts.empty().withRunMonitor(sharedRunMonitor)).withExecutionHint(JOB_MARKER));
assertTrue(setupLatch.await());
sharedRunMonitor.cancel(true);
// Wait until the job jobs are done
Jobs.getJobManager().awaitDone(Jobs.newFutureFilterBuilder().andMatchExecutionHint(JOB_MARKER).toFilter(), 5, TimeUnit.SECONDS);
// Verify that the function is not executed
assertFalse(functionExecuted.get());
// Verify that both futures are cancelled
assertFutureCancelled(future);
assertFutureCancelled(functionFuture);
}
use of org.eclipse.scout.rt.testing.platform.util.BlockingCountDownLatch in project scout.rt by eclipse.
the class WhenDoneScheduleTest method testCancellationOfFutureRunMonitor.
@Test
public void testCancellationOfFutureRunMonitor() throws InterruptedException {
final BlockingCountDownLatch setupLatch = new BlockingCountDownLatch(1);
RunMonitor runMonitor = BEANS.get(RunMonitor.class);
// Schedule future
IFuture<String> future = Jobs.schedule(new Callable<String>() {
@Override
public String call() throws Exception {
setupLatch.countDownAndBlock();
return "abc";
}
}, Jobs.newInput().withExceptionHandling(null, // to not work with JUnitExceptionHandler
true).withRunContext(RunContexts.empty().withRunMonitor(runMonitor)).withExecutionHint(JOB_MARKER));
// Schedule function
final AtomicBoolean functionExecuted = new AtomicBoolean(false);
IFuture<Void> functionFuture = future.whenDoneSchedule(new IBiFunction<String, Throwable, Void>() {
@Override
public Void apply(String result, Throwable error) {
functionExecuted.set(true);
return null;
}
}, Jobs.newInput().withExecutionHint(JOB_MARKER));
assertTrue(setupLatch.await());
runMonitor.cancel(true);
// Wait until the job jobs are done
Jobs.getJobManager().awaitDone(Jobs.newFutureFilterBuilder().andMatchExecutionHint(JOB_MARKER).toFilter(), 5, TimeUnit.SECONDS);
// Verify that the function is not executed
assertFalse(functionExecuted.get());
// Verify that both futures are cancelled
assertFutureCancelled(future);
assertFutureCancelled(functionFuture);
}
Aggregations