StartStopSupport implements ListenableAsyncCloseable { public final CompletableFuture<V> start(boolean failIfStarted) { return start(null, null, failIfStarted); } protected  StartStopSupport(Executor executor); final void addListener(L listener); final boolean removeListener(L listener); final CompletableFuture<V> start(boolean failIfStarted); final CompletableFuture<V> start(@Nullable T arg, boolean failIfStarted); final CompletableFuture<V> start(@Nullable T arg, @Nullable U rollbackArg, boolean failIfStarted); final CompletableFuture<Void> stop(); final CompletableFuture<Void> stop(@Nullable U arg); @Override final boolean isClosing(); @Override final boolean isClosed(); @Override final CompletableFuture<?> whenClosed(); @Override final CompletableFuture<?> closeAsync(); @Override final void close(); @Override String toString();  }
@Test public void startingWhileStarted() { final StartStop startStop = new StartStop(arg -> "foo", arg -> null); final CompletableFuture<String> startFuture = startStop.start(true); assertThat(startFuture.join()).isEqualTo("foo"); assertThatThrownBy(() -> startStop.start(true).join()) .isInstanceOf(CompletionException.class) .hasCauseInstanceOf(IllegalStateException.class); assertThat(startStop.start(false)).isSameAs(startFuture); }
@Test public void rollback() throws Throwable { final StopTask stopTask = mock(StopTask.class); final Exception exception = new AnticipatedException(); final StartStop startStop = new StartStop(arg -> { throw exception; }, stopTask); assertThatThrownBy(() -> startStop.start(null, 1L, true).join()) .isInstanceOf(CompletionException.class) .hasCause(exception); verify(stopTask, times(1)).run(1L); }
@Test public void rollbackFailure() throws Throwable { final Exception startException = new AnticipatedException(); final Exception stopException = new AnticipatedException(); final List<Throwable> rollbackFailed = new ArrayList<>(); final StartStop startStop = new StartStop(arg -> { throw startException; }, arg -> { throw stopException; }) { @Override protected void rollbackFailed(Throwable cause) { rollbackFailed.add(cause); } }; assertThatThrownBy(() -> startStop.start(true).join()) .isInstanceOf(CompletionException.class) .hasCause(startException); assertThat(rollbackFailed).containsExactly(stopException); }
@Test public void doStartReturnsNull() throws Exception { final StartStopSupport<Void, Void, Void, Void> startStop = new StartStopSupport<Void, Void, Void, Void>(rule.get()) { @Override protected CompletionStage<Void> doStart(@Nullable Void arg) throws Exception { return null; } @Override protected CompletionStage<Void> doStop(@Nullable Void arg) throws Exception { return CompletableFuture.completedFuture(null); } }; assertThatThrownBy(() -> startStop.start(true).join()) .isInstanceOf(CompletionException.class) .hasCauseInstanceOf(IllegalStateException.class) .satisfies(cause -> { assertThat(cause.getCause().getMessage()).contains("doStart() returned null"); }); }