StartStopSupport implements ListenableAsyncCloseable { @Override public final void close() { try { closeable.close(); } catch (Throwable e) { closeFailed(Exceptions.peel(e)); } } 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 close() { final StartStop startStop = new StartStop(arg -> "foo", arg -> null); startStop.close(); assertThat(startStop.isClosing()).isTrue(); assertThat(startStop.isClosed()).isTrue(); }
@Test public void closeWhileStopped() throws Throwable { final StartTask startTask = SpiedStartTask.of("bar"); final StopTask stopTask = mock(StopTask.class); final StartStop startStop = new StartStop(startTask, stopTask); for (int i = 0; i < 2; i++) { startStop.close(); verify(startTask, never()).run(any()); verify(stopTask, never()).run(any()); } }