Server implements ListenableAsyncCloseable { public void blockUntilShutdown() throws InterruptedException { try { whenClosed().get(); } catch (ExecutionException e) { throw new CompletionException(e.toString(), Exceptions.peel(e)); } } Server(ServerConfig config, @Nullable Mapping<String, SslContext> sslContexts); static ServerBuilder builder(); ServerConfig config(); List<ServiceConfig> serviceConfigs(); String defaultHostname(); Map<InetSocketAddress, ServerPort> activePorts(); @Nullable ServerPort activePort(); @Nullable ServerPort activePort(SessionProtocol protocol); int activeLocalPort(); int activeLocalPort(SessionProtocol protocol); MeterRegistry meterRegistry(); void addListener(ServerListener listener); boolean removeListener(ServerListener listener); CompletableFuture<Void> start(); CompletableFuture<Void> stop(); EventLoop nextEventLoop(); @Override boolean isClosing(); @Override boolean isClosed(); @Override CompletableFuture<?> whenClosed(); @Override CompletableFuture<?> closeAsync(); @Override void close(); int numConnections(); void blockUntilShutdown(); @Override String toString();  }
@Test void blockUntilShutdown() throws Exception { final AtomicBoolean stopped = new AtomicBoolean(); final Server server = Server.builder() .service("/", (ctx, req) -> HttpResponse.of(HttpStatus.OK)) .serverListener(new ServerListenerAdapter() { @Override public void serverStopping(Server server) throws Exception { stopped.set(true); } }) .build(); server.start().join(); CommonPools.blockingTaskExecutor().schedule(server::close, 1, TimeUnit.SECONDS); server.blockUntilShutdown(); assertThat(stopped).isTrue(); }