use of org.eclipse.scout.rt.testing.platform.util.BlockingCountDownLatch in project scout.rt by eclipse.
the class MutualExclusionTest method testExpiredWhenReAcquiringMutex.
/**
* Tests that a job continues execution after waiting for a blocking condition to fall.
*/
@Test
public void testExpiredWhenReAcquiringMutex() throws java.lang.InterruptedException {
// synchronized because modified/read by different threads.
final List<String> protocol = Collections.synchronizedList(new ArrayList<String>());
final IBlockingCondition condition = Jobs.newBlockingCondition(true);
final BlockingCountDownLatch latch = new BlockingCountDownLatch(1);
final int expirationTime = 100;
IFuture<Void> future = ModelJobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
protocol.add("1: running");
ModelJobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
protocol.add("2: running");
condition.setBlocking(false);
latch.countDownAndBlock();
}
}, ModelJobs.newInput(ClientRunContexts.copyCurrent()).withName("job-2"));
condition.waitFor();
protocol.add("3: running");
}
}, ModelJobs.newInput(ClientRunContexts.copyCurrent()).withName("job-1").withExceptionHandling(null, false).withExpirationTime(expirationTime, TimeUnit.MILLISECONDS));
// Wait until job-1 can re-acquire the mutex
assertTrue(latch.await());
// Wait until job-1 would be expired
SleepUtil.sleepSafe(expirationTime + 1, TimeUnit.MILLISECONDS);
latch.unblock();
// Expect the job to continue running.
future.awaitDoneAndGet(5, TimeUnit.SECONDS);
List<String> expected = new ArrayList<>();
expected.add("1: running");
expected.add("2: running");
expected.add("3: running");
assertEquals(expected, protocol);
}
use of org.eclipse.scout.rt.testing.platform.util.BlockingCountDownLatch in project scout.rt by eclipse.
the class MutualExclusionTest method testBlockedJobs.
/**
* We have 5 jobs that get scheduled simultaneously. The first waits some time so that job2, job3, job4 and job5 get
* queued. Job1 then enters a blocking condition, which allows job2 to run. But job2 gets rejected by the executor,
* which allows job3 to run. After job3 completes, job1 is resumed and continues running. After job1 complete, job4
* gets scheduled. Job4 in turn gets blocked, which prevents job5 from running.
*/
@Test
public void testBlockedJobs() throws java.lang.InterruptedException {
P_JobManager jobManager = new P_JobManager();
ExecutorService executorMock = jobManager.getExecutorMock();
IBean<IJobManager> jobManagerBean = JobTestUtil.replaceCurrentJobManager(jobManager);
try {
// synchronized because modified/read by different threads.
final List<String> protocol = Collections.synchronizedList(new ArrayList<String>());
// Executor mock
doAnswer(new Answer<Future>() {
@Override
public Future answer(InvocationOnMock invocation) throws Throwable {
final Runnable runnable = (Runnable) invocation.getArguments()[0];
// Reject job-2 from being scheduled
if (runnable instanceof JobFutureTask) {
JobFutureTask<?> futureTask = (JobFutureTask<?>) runnable;
if ("job-2".equals(futureTask.getJobInput().getName())) {
futureTask.reject();
return null;
}
}
s_executor.execute(new NamedThreadRunnable(runnable));
return null;
}
}).when(executorMock).execute(any(Runnable.class));
final BlockingCountDownLatch job4RunningLatch = new BlockingCountDownLatch(1);
final IBlockingCondition condition = Jobs.newBlockingCondition(true);
// Job-1
IFuture<Void> future1 = Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
// Wait until all 5 jobs are scheduled.
JobTestUtil.waitForPermitCompetitors(m_clientSession.getModelJobSemaphore(), 5);
try {
protocol.add("running-job-1 (a)");
condition.waitFor();
protocol.add("running-job-1 (b)");
} catch (ProcessingException e) {
protocol.add("jobException");
}
if (ModelJobs.isModelThread()) {
protocol.add("running-job-1 (e) [model-thread]");
}
}
}, ModelJobs.newInput(ClientRunContexts.copyCurrent()).withName("job-1").withExecutionHint(JOB_IDENTIFIER).withExceptionHandling(null, false));
// Job-2
IFuture<Void> future2 = Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
protocol.add("running-job-2");
}
}, ModelJobs.newInput(ClientRunContexts.copyCurrent()).withName("job-2").withExecutionHint(JOB_IDENTIFIER).withExceptionHandling(null, false));
// Job-3
IFuture<Void> future3 = Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
protocol.add("running-job-3 (a)");
condition.setBlocking(false);
// Wait until job-1 tried to re-acquire the mutex.
// 4 = job1(re-acquiring), job3(owner), job4, job5
JobTestUtil.waitForPermitCompetitors(m_clientSession.getModelJobSemaphore(), 4);
protocol.add("running-job-3 (b)");
}
}, ModelJobs.newInput(ClientRunContexts.copyCurrent()).withName("job-3").withExecutionHint(JOB_IDENTIFIER).withExceptionHandling(null, false));
// Job-4
IFuture<Void> future4 = Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
protocol.add("running-job-4");
try {
job4RunningLatch.countDownAndBlock();
} catch (java.lang.InterruptedException e) {
protocol.add("job-4 [interrupted]");
}
}
}, ModelJobs.newInput(ClientRunContexts.copyCurrent()).withName("job-4").withExecutionHint(JOB_IDENTIFIER).withExceptionHandling(null, false));
// Job-5
IFuture<Void> future5 = Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
protocol.add("running-job-5");
}
}, ModelJobs.newInput(ClientRunContexts.copyCurrent()).withName("job-5").withExecutionHint(JOB_IDENTIFIER).withExceptionHandling(null, false));
assertTrue(job4RunningLatch.await());
try {
Jobs.getJobManager().awaitDone(Jobs.newFutureFilterBuilder().andMatchExecutionHint(JOB_IDENTIFIER).toFilter(), 1, TimeUnit.MILLISECONDS);
// job-4 and job-5 are pending
fail("timeout expected");
} catch (TimedOutError e) {
// NOOP
}
// job-4 and job-5 are pending
assertFalse(Jobs.getJobManager().isDone(Jobs.newFutureFilterBuilder().andMatchExecutionHint(JOB_IDENTIFIER).toFilter()));
List<String> expectedProtocol = new ArrayList<>();
expectedProtocol.add("running-job-1 (a)");
expectedProtocol.add("running-job-3 (a)");
expectedProtocol.add("running-job-3 (b)");
expectedProtocol.add("running-job-1 (b)");
expectedProtocol.add("running-job-1 (e) [model-thread]");
expectedProtocol.add("running-job-4");
assertEquals(expectedProtocol, protocol);
assertFalse(future1.isCancelled());
assertTrue(future1.isDone());
assertTrue(future2.isCancelled());
assertTrue(future2.isDone());
assertFalse(future3.isCancelled());
assertTrue(future3.isDone());
assertFalse(future4.isCancelled());
assertFalse(future4.isDone());
assertFalse(future5.isCancelled());
assertFalse(future5.isDone());
// cancel job4
future4.cancel(true);
awaitDoneElseFail(JOB_IDENTIFIER);
expectedProtocol.add("job-4 [interrupted]");
expectedProtocol.add("running-job-5");
assertEquals(expectedProtocol, protocol);
assertTrue(Jobs.getJobManager().isDone(Jobs.newFutureFilterBuilder().andMatchExecutionHint(JOB_IDENTIFIER).toFilter()));
assertTrue(future4.isCancelled());
assertTrue(future4.isDone());
assertFalse(future5.isCancelled());
assertTrue(future5.isDone());
} finally {
JobTestUtil.unregisterAndShutdownJobManager(jobManagerBean);
}
}
use of org.eclipse.scout.rt.testing.platform.util.BlockingCountDownLatch in project scout.rt by eclipse.
the class MutualExclusionTest method testBlockingCondition_InterruptedWhileReAcquiringTheMutex.
/**
* We have 3 jobs that are scheduled simultaneously. Thereby, job1 enters a blocking condition which in turn lets job2
* run. Job2 unblocks job1 so that job1 is trying to re-acquire the mutex. While waiting for the mutex to be
* available, job1 is interrupted due to a cancel-request of job2.<br/>
* This test verifies, that job1 is interrupted, competes for the mutex anew and only continues once a permit becomes
* available. Also, job3 must not start running as long as job1 did not complete.
*/
@Test
// regression
@Times(100)
public void testBlockingCondition_InterruptedWhileReAcquiringTheMutex() throws java.lang.InterruptedException {
// synchronized because modified/read by different threads.
final List<String> protocol = Collections.synchronizedList(new ArrayList<String>());
final IBlockingCondition condition = Jobs.newBlockingCondition(true);
final BlockingCountDownLatch latchJob2 = new BlockingCountDownLatch(1);
final BlockingCountDownLatch job1FinishLatch = new BlockingCountDownLatch(1);
final IFuture<Void> future1 = ModelJobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
protocol.add("running-1");
try {
protocol.add("before-blocking-1");
condition.waitFor();
} catch (ThreadInterruptedError e) {
protocol.add("interrupted-1 (a)");
} catch (RuntimeException e) {
protocol.add("jobException-1");
}
if (Thread.currentThread().isInterrupted()) {
protocol.add("interrupted-1 (b)");
}
if (ModelJobs.isModelThread()) {
protocol.add("model-thread-1");
}
protocol.add("done-1");
job1FinishLatch.countDown();
}
}, ModelJobs.newInput(ClientRunContexts.copyCurrent()).withName("job-1").withExecutionHint(JOB_IDENTIFIER).withExceptionHandling(null, false));
final IFuture<Void> future2 = ModelJobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
protocol.add("running-2a");
if (future1.getState() == JobState.WAITING_FOR_BLOCKING_CONDITION) {
protocol.add("job2: job-1-waiting-for-blocking-condition");
}
if (!future1.getExecutionSemaphore().isPermitOwner(future1)) {
protocol.add("job2: job-1-not-permit-owner");
}
protocol.add("unblocking condition");
condition.setBlocking(false);
// job-1 (interrupted acquisition task), job-2 (latch), job-3 (waiting for mutex)
JobTestUtil.waitForPermitCompetitors(m_clientSession.getModelJobSemaphore(), 3);
if (future1.getState() == JobState.WAITING_FOR_PERMIT) {
protocol.add("job2: job-1-waiting-for-mutex");
}
protocol.add("before-cancel-job1-2");
// interrupt job1 while acquiring the mutex
future1.cancel(true);
// job-1 (interrupted acquisition task), job-1 (re-acquiring a permit), job-2 (latch), job-3 (waiting for mutex)
JobTestUtil.waitForPermitCompetitors(m_clientSession.getModelJobSemaphore(), 4);
// cancelled, but still running
JobTestUtil.waitForState(future1, JobState.DONE);
protocol.add("running-2b");
latchJob2.countDownAndBlock();
protocol.add("done-2");
}
}, ModelJobs.newInput(ClientRunContexts.copyCurrent()).withName("job-2").withExecutionHint(JOB_IDENTIFIER).withExceptionHandling(null, false));
final IFuture<Void> future3 = ModelJobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
protocol.add("done-3");
}
}, ModelJobs.newInput(ClientRunContexts.copyCurrent()).withName("job-3").withExecutionHint(JOB_IDENTIFIER).withExceptionHandling(null, false));
assertTrue(latchJob2.await());
assertEquals(future1.getState(), JobState.DONE);
assertEquals(future2.getState(), JobState.RUNNING);
assertEquals(future3.getState(), JobState.WAITING_FOR_PERMIT);
latchJob2.unblock();
Jobs.getJobManager().awaitDone(Jobs.newFutureFilterBuilder().andMatchExecutionHint(JOB_IDENTIFIER).toFilter(), 5, TimeUnit.SECONDS);
List<String> expectedProtocol = new ArrayList<>();
expectedProtocol.add("running-1");
expectedProtocol.add("before-blocking-1");
expectedProtocol.add("running-2a");
expectedProtocol.add("job2: job-1-waiting-for-blocking-condition");
expectedProtocol.add("job2: job-1-not-permit-owner");
expectedProtocol.add("unblocking condition");
expectedProtocol.add("job2: job-1-waiting-for-mutex");
expectedProtocol.add("before-cancel-job1-2");
expectedProtocol.add("running-2b");
expectedProtocol.add("done-2");
expectedProtocol.add("interrupted-1 (b)");
expectedProtocol.add("model-thread-1");
expectedProtocol.add("done-1");
expectedProtocol.add("done-3");
assertEquals(expectedProtocol, protocol);
assertEquals(future1.getState(), JobState.DONE);
assertEquals(future2.getState(), JobState.DONE);
assertEquals(future3.getState(), JobState.DONE);
assertTrue(future1.isCancelled());
future1.awaitDone(1, TimeUnit.NANOSECONDS);
assertFalse(future2.isCancelled());
future2.awaitDone(1, TimeUnit.NANOSECONDS);
assertFalse(future3.isCancelled());
future3.awaitDone(1, TimeUnit.NANOSECONDS);
}
use of org.eclipse.scout.rt.testing.platform.util.BlockingCountDownLatch in project scout.rt by eclipse.
the class ClientJobCancelTest method doPingRequestAsync.
/**
* Runs a 'ping-request' which gets blocked in the service implementation.
*/
protected RequestData doPingRequestAsync(final String pingRequest) throws Exception {
final BlockingCountDownLatch serviceCallSetupLatch = new BlockingCountDownLatch(1);
final BlockingCountDownLatch serviceCallCompletedLatch = new BlockingCountDownLatch(1);
final AtomicBoolean serviceCallInterrupted = new AtomicBoolean(false);
// Mock the PingService.
class PingService implements IPingService {
@Override
public String ping(String s) {
try {
assertTrue(serviceCallSetupLatch.countDownAndBlock());
} catch (java.lang.InterruptedException e) {
serviceCallInterrupted.set(true);
} finally {
serviceCallCompletedLatch.countDown();
}
return s.toUpperCase();
}
}
// Create a separate RunContext with a separate RunMonitor, so we can wait for the service result in case of cancellation.
final ClientRunContext runContext = ClientRunContexts.copyCurrent();
final RunMonitor runMonitor = BEANS.get(RunMonitor.class);
runContext.withRunMonitor(runMonitor);
IFuture<String> pingFuture = Jobs.schedule(new Callable<String>() {
@Override
public String call() throws Exception {
return runContext.call(new Callable<String>() {
@Override
public String call() throws Exception {
IBean<?> bean = TestingUtility.registerBean(new BeanMetaData(PingService.class).withInitialInstance(new PingService()).withApplicationScoped(true));
try {
return ServiceTunnelUtility.createProxy(IPingService.class).ping(pingRequest);
} finally {
TestingUtility.unregisterBeans(Arrays.asList(bean));
}
}
});
}
}, Jobs.newInput().withExceptionHandling(null, false));
// Wait for the ping request to enter service implementation.
assertTrue(serviceCallSetupLatch.await());
return new RequestData(pingFuture, runMonitor, serviceCallSetupLatch, serviceCallCompletedLatch, serviceCallInterrupted);
}
use of org.eclipse.scout.rt.testing.platform.util.BlockingCountDownLatch in project scout.rt by eclipse.
the class ExecutionSemaphoreTest method testThreePermits.
/**
* Tests execution semaphore with 3 permits.
*/
@Test
// regression
@Times(500)
public void testThreePermits() throws InterruptedException {
IExecutionSemaphore semaphore = Jobs.newExecutionSemaphore(3);
// synchronized because modified/read by different threads.
final Set<String> protocol = Collections.synchronizedSet(new HashSet<String>());
final BlockingCountDownLatch latchGroup1 = new BlockingCountDownLatch(3);
final BlockingCountDownLatch latchGroup2 = new BlockingCountDownLatch(3);
final BlockingCountDownLatch latchGroup3 = new BlockingCountDownLatch(2);
// job-1
Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
protocol.add("job-1-running");
latchGroup1.countDownAndBlock();
}
}, Jobs.newInput().withName("job-1").withExecutionSemaphore(semaphore));
// job-2
Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
protocol.add("job-2-running");
latchGroup1.countDownAndBlock();
}
}, Jobs.newInput().withName("job-2").withExecutionSemaphore(semaphore));
// job-3
Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
protocol.add("job-3-running");
latchGroup1.countDownAndBlock();
}
}, Jobs.newInput().withName("job-3").withExecutionSemaphore(semaphore));
// job-4
Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
protocol.add("job-4-running");
latchGroup2.countDownAndBlock();
}
}, Jobs.newInput().withName("job-4").withExecutionSemaphore(semaphore));
// job-5
Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
protocol.add("job-5-running");
latchGroup2.countDownAndBlock();
}
}, Jobs.newInput().withName("job-5").withExecutionSemaphore(semaphore));
// job-6
Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
protocol.add("job-6-running");
latchGroup2.countDownAndBlock();
}
}, Jobs.newInput().withName("job-6").withExecutionSemaphore(semaphore));
// job-7
Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
protocol.add("job-7-running");
latchGroup3.countDownAndBlock();
}
}, Jobs.newInput().withName("job-7").withExecutionSemaphore(semaphore));
// job-8
Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
protocol.add("job-8-running");
latchGroup3.countDownAndBlock();
}
}, Jobs.newInput().withName("job-8").withExecutionSemaphore(semaphore));
// verify group-1
assertTrue(latchGroup1.await());
assertEquals(CollectionUtility.hashSet("job-1-running", "job-2-running", "job-3-running"), protocol);
// verify group-2
protocol.clear();
latchGroup1.unblock();
assertTrue(latchGroup2.await());
assertEquals(CollectionUtility.hashSet("job-4-running", "job-5-running", "job-6-running"), protocol);
// verify group-3
protocol.clear();
latchGroup2.unblock();
assertTrue(latchGroup3.await());
assertEquals(CollectionUtility.hashSet("job-7-running", "job-8-running"), protocol);
// job-9
Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
protocol.add("job-9-running");
}
}, Jobs.newInput().withName("job-9").withExecutionSemaphore(semaphore)).awaitDone();
assertEquals(CollectionUtility.hashSet("job-7-running", "job-8-running", "job-9-running"), protocol);
// cleanup
latchGroup3.unblock();
}
Aggregations