/** * Tests the processor using two keys and verifies the tasks are executed in parallel. */ @Test public void testAddParallelism() throws Exception { final int key1 = 1; final int key2 = 2; @Cleanup val proc = new MultiKeySequentialProcessor<Integer>(executorService()); val toRun1 = new CompletableFuture<Integer>(); val result1 = proc.add(Collections.singleton(key1), () -> toRun1); val toRun2 = new CompletableFuture<Integer>(); val result2 = proc.add(Collections.singleton(key2), () -> toRun2); Assert.assertFalse("Not expecting anything to be done yet.", result1.isDone() || result2.isDone()); // Complete second run. If it completes, we have verified that it hasn't been blocked on the first one. toRun2.complete(10); result2.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals("Unexpected result from second key run.", result2.join(), toRun2.join()); Assert.assertFalse("Not expecting first task to be done yet.", result1.isDone()); // Complete the first run. toRun1.complete(20); result1.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals("Unexpected result from first key run.", result1.join(), toRun1.join()); }
final int count = 10000; @Cleanup val proc = new MultiKeySequentialProcessor<Integer>(executorService()); val running = new AtomicBoolean(false); val previousRun = new AtomicReference<CompletableFuture<Integer>>();
/** * Tests the processor with a key filter that doesn't match any keys currently executing. */ @Test public void testAddFilterEmpty() throws Exception { final int key1 = 1; @Cleanup val proc = new MultiKeySequentialProcessor<Integer>(executorService()); val toRunFilter = new CompletableFuture<Integer>(); val resultFilter = proc.addWithFilter(key -> key == key1, () -> toRunFilter); // We setup one task to begin with. val result1 = proc.add(Collections.singleton(key1), () -> { Assert.assertTrue("Not expecting individual task to execute yet.", resultFilter.isDone()); return CompletableFuture.completedFuture(1); }); // Complete the task. Verify filter task did not complete. toRunFilter.complete(0); toRunFilter.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); result1.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals("Unexpected result from filter run.", (int) resultFilter.join(), 0); Assert.assertEquals("Unexpected result from task 1.", (int) result1.join(), 1); }
final int key3 = 3; @Cleanup val proc = new MultiKeySequentialProcessor<Integer>(executorService());
final int key3 = 3; @Cleanup val proc = new MultiKeySequentialProcessor<Integer>(executorService());
/** * Tests the ability to cancel ongoing tasks when the processor is closed. */ @Test public void testClose() { final int key = 1; @Cleanup val proc = new MultiKeySequentialProcessor<Integer>(executorService()); val toRun = new CompletableFuture<Integer>(); val result = proc.add(Collections.singleton(key), () -> toRun); proc.close(); AssertExtensions.assertThrows( "Task not cancelled.", result::join, ex -> ex instanceof ObjectClosedException); Assert.assertFalse("Not expecting inner blocker task to be done.", toRun.isDone()); } }