CallbackCountDownLatch extends CountDownLatch { @Override public void countDown() { super.countDown(); if (getCount() <= 0) { future.complete(null); } } CallbackCountDownLatch(int size, Runnable callback);  CallbackCountDownLatch(int size, Runnable callback, Executor executor); @Override void countDown();  }
@Test public void zeroCountDownTriggersCallback() { final AtomicInteger timesCalled = new AtomicInteger(0); final CallbackCountDownLatch latch = new CallbackCountDownLatch(2, timesCalled::getAndIncrement); assertThat(timesCalled).hasValue(0); latch.countDown(); assertThat(timesCalled).hasValue(0); latch.countDown(); assertThat(timesCalled).hasValue(1); latch.countDown(); assertThat(timesCalled).hasValue(1); }
@Test public void asyncCallback() { final Executor mockExecutor = mock(Executor.class); final Runnable noop = () -> { }; final CallbackCountDownLatch latch = new CallbackCountDownLatch(2, noop, mockExecutor); verify(mockExecutor, never()).execute(any()); latch.countDown(); verify(mockExecutor, never()).execute(any()); latch.countDown(); verify(mockExecutor).execute(any()); latch.countDown(); verify(mockExecutor).execute(any()); }