Search in sources :

Example 1 with BlockingCountDownLatch

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());
}
Also used : BlockingCountDownLatch(org.eclipse.scout.rt.testing.platform.util.BlockingCountDownLatch) IRunnable(org.eclipse.scout.rt.platform.util.concurrent.IRunnable) JobEvent(org.eclipse.scout.rt.platform.job.listener.JobEvent) Test(org.junit.Test) Times(org.eclipse.scout.rt.testing.platform.runner.Times)

Example 2 with BlockingCountDownLatch

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);
}
Also used : BlockingCountDownLatch(org.eclipse.scout.rt.testing.platform.util.BlockingCountDownLatch) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ArrayList(java.util.ArrayList) IRunnable(org.eclipse.scout.rt.platform.util.concurrent.IRunnable) TimedOutError(org.eclipse.scout.rt.platform.util.concurrent.TimedOutError)

Example 3 with BlockingCountDownLatch

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());
}
Also used : BlockingCountDownLatch(org.eclipse.scout.rt.testing.platform.util.BlockingCountDownLatch) ThreadInterruptedError(org.eclipse.scout.rt.platform.util.concurrent.ThreadInterruptedError) IRunnable(org.eclipse.scout.rt.platform.util.concurrent.IRunnable) Test(org.junit.Test)

Example 4 with BlockingCountDownLatch

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);
}
Also used : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) BlockingCountDownLatch(org.eclipse.scout.rt.testing.platform.util.BlockingCountDownLatch) RunMonitor(org.eclipse.scout.rt.platform.context.RunMonitor) Test(org.junit.Test)

Example 5 with BlockingCountDownLatch

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);
}
Also used : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) BlockingCountDownLatch(org.eclipse.scout.rt.testing.platform.util.BlockingCountDownLatch) RunMonitor(org.eclipse.scout.rt.platform.context.RunMonitor) Test(org.junit.Test)

Aggregations

BlockingCountDownLatch (org.eclipse.scout.rt.testing.platform.util.BlockingCountDownLatch)93 Test (org.junit.Test)89 IRunnable (org.eclipse.scout.rt.platform.util.concurrent.IRunnable)66 AssertionException (org.eclipse.scout.rt.platform.util.Assertions.AssertionException)30 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)16 ProcessingException (org.eclipse.scout.rt.platform.exception.ProcessingException)14 ThreadInterruptedError (org.eclipse.scout.rt.platform.util.concurrent.ThreadInterruptedError)12 ArrayList (java.util.ArrayList)10 TimedOutError (org.eclipse.scout.rt.platform.util.concurrent.TimedOutError)10 IBlockingCondition (org.eclipse.scout.rt.platform.job.IBlockingCondition)9 IExecutionSemaphore (org.eclipse.scout.rt.platform.job.IExecutionSemaphore)9 RunMonitor (org.eclipse.scout.rt.platform.context.RunMonitor)7 JobEvent (org.eclipse.scout.rt.platform.job.listener.JobEvent)7 Times (org.eclipse.scout.rt.testing.platform.runner.Times)7 Holder (org.eclipse.scout.rt.platform.holders.Holder)6 AtomicReference (java.util.concurrent.atomic.AtomicReference)4 IMessage (org.eclipse.scout.rt.mom.api.IMessage)4 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)3 IMessageListener (org.eclipse.scout.rt.mom.api.IMessageListener)3 FutureCancelledError (org.eclipse.scout.rt.platform.util.concurrent.FutureCancelledError)3