public void testExecuteAsyncSupplierReturnsNull() throws Exception { eventuallyEquals(0, executor::getActiveCount); LimitedExecutor limitedExecutor = new LimitedExecutor(NAME, executor, 1); limitedExecutor.executeAsync(() -> null); CompletableFuture<String> cf1 = new CompletableFuture<>(); limitedExecutor.execute(() -> cf1.complete("a")); cf1.get(10, TimeUnit.SECONDS); }
/** * Test that an async task ({@code executeAsync()}) will block another task from running * until its {@code CompletableFuture} is completed. */ public void testConcurrencyLimitExecuteAsync() throws Exception { eventuallyEquals(0, executor::getActiveCount); LimitedExecutor limitedExecutor = new LimitedExecutor(NAME, executor, 1); CompletableFuture<String> blocker1 = new CompletableFuture<>(); CompletableFuture<String> cf1 = new CompletableFuture<>(); limitedExecutor.executeAsync(() -> blocker1.thenAccept(cf1::complete)); verifyTaskIsBlocked(limitedExecutor, blocker1, cf1); }
/** * Test that no more than 1 task runs at a time. */ public void testConcurrencyLimit() throws Exception { eventuallyEquals(0, executor::getActiveCount); LimitedExecutor limitedExecutor = new LimitedExecutor(NAME, executor, 1); CompletableFuture<String> blocker1 = new CompletableFuture<>(); CompletableFuture<String> cf1 = new CompletableFuture<>(); limitedExecutor.execute(() -> { try { cf1.complete(blocker1.get(10, SECONDS)); } catch (Exception e) { cf1.completeExceptionally(e); } }); verifyTaskIsBlocked(limitedExecutor, blocker1, cf1); }
private void verifyTaskIsBlocked(LimitedExecutor limitedExecutor, CompletableFuture<String> blocker1, CompletableFuture<String> cf1) throws Exception { CompletableFuture<String> blocker2 = new CompletableFuture<>(); CompletableFuture<String> cf2 = new CompletableFuture<>(); // execute() may block Future<?> fork2 = fork(() -> { limitedExecutor.execute(() -> { try { cf2.complete(cf1.getNow("task 2 ran too early") + " " + blocker2.get(10, SECONDS)); } catch (Exception e) { cf2.completeExceptionally(e); } }); }); assertFalse(cf1.isDone()); assertFalse(cf2.isDone()); blocker1.complete("value1"); assertEquals("value1", cf1.get(10, SECONDS)); assertFalse(cf2.isDone()); blocker2.complete("value2"); assertEquals("value1 value2", cf2.get(10, SECONDS)); fork2.get(10, SECONDS); eventuallyEquals(0, executor::getActiveCount); } }
public void testBasicWithinThread() throws Exception { LimitedExecutor limitedExecutor = new LimitedExecutor(NAME, new WithinThreadExecutor(), 1); CompletableFuture<String> cf = new CompletableFuture<>(); limitedExecutor.execute(() -> cf.complete("value")); assertEquals("value", cf.getNow("task did not run synchronously")); }
/** * Test that an async task ({@code executeAsync()}) will block another task from running * until its {@code CompletableFuture} is completed, when using a {@link WithinThreadExecutor}. */ public void testConcurrencyLimitExecuteAsyncWithinThread() throws Exception { LimitedExecutor limitedExecutor = new LimitedExecutor(NAME, new WithinThreadExecutor(), 1); CompletableFuture<String> blocker1 = new CompletableFuture<>(); CompletableFuture<String> cf1 = new CompletableFuture<>(); // executeAsync() will not block limitedExecutor.executeAsync(() -> blocker1.thenAccept(cf1::complete)); verifyTaskIsBlocked(limitedExecutor, blocker1, cf1); }
/** * Test that no more than 1 task runs at a time when using a {@link WithinThreadExecutor}. */ public void testConcurrencyLimitWithinThread() throws Exception { LimitedExecutor limitedExecutor = new LimitedExecutor(NAME, new WithinThreadExecutor(), 1); CompletableFuture<String> blocker1 = new CompletableFuture<>(); CompletableFuture<String> blocker2 = new CompletableFuture<>(); CompletableFuture<String> cf1 = new CompletableFuture<>(); // execute() will block Future<?> fork1 = fork(() -> { limitedExecutor.execute(() -> { blocker2.complete("blocking"); try { cf1.complete(blocker1.get(10, SECONDS)); } catch (Exception e) { cf1.completeExceptionally(e); } }); }); assertEquals("blocking", blocker2.get(10, SECONDS)); verifyTaskIsBlocked(limitedExecutor, blocker1, cf1); fork1.get(10, SECONDS); }