private static void tlsCustomization(Consumer<ServerBuilder> defaultKeySetter,
                                         Consumer<VirtualHostBuilder> virtualHostKeySetter) {
        final AtomicReference<SslContextBuilder> defaultSslCtxBuilder = new AtomicReference<>();
        final AtomicReference<SslContextBuilder> virtualHostSslCtxBuilder = new AtomicReference<>();
        final AtomicInteger firstDefaultCustomizerInvoked = new AtomicInteger();
        final AtomicInteger secondDefaultCustomizerInvoked = new AtomicInteger();
        final AtomicInteger firstVirtualHostCustomizerInvoked = new AtomicInteger();
        final AtomicInteger secondVirtualHostCustomizerInvoked = new AtomicInteger();

        final ServerBuilder sb = Server.builder().service("/", (ctx, req) -> HttpResponse.of(200));
        defaultKeySetter.accept(sb);
        sb.tlsCustomizer(b -> {
            firstDefaultCustomizerInvoked.incrementAndGet();
            defaultSslCtxBuilder.set(b);
        });
        sb.tlsCustomizer(b -> {
            secondDefaultCustomizerInvoked.incrementAndGet();
            assertThat(b).isSameAs(defaultSslCtxBuilder.get());
        });

        // A virtual host must have its own self-signed certificate and customizers.
        // i.e. first and second customizer should not be invoked.
        final VirtualHostBuilder vhb = sb.virtualHost("example.com");
        virtualHostKeySetter.accept(vhb);
        vhb.tlsCustomizer(b -> {
            firstVirtualHostCustomizerInvoked.incrementAndGet();
            virtualHostSslCtxBuilder.set(b);
        });
        vhb.tlsCustomizer(b -> {
            secondVirtualHostCustomizerInvoked.incrementAndGet();
            assertThat(b).isSameAs(virtualHostSslCtxBuilder.get());
        });

        // No interaction should occur until `ServerBuilder.build()`.
        assertThat(firstDefaultCustomizerInvoked).hasValue(0);
        assertThat(secondDefaultCustomizerInvoked).hasValue(0);
        assertThat(firstVirtualHostCustomizerInvoked).hasValue(0);
        assertThat(secondVirtualHostCustomizerInvoked).hasValue(0);

        // Try to build twice, to make sure `build()` does not have any side effects.
        for (int i = 0; i < 2; i++) {
            sb.build();

            assertThat(firstDefaultCustomizerInvoked).hasValue(1);
            assertThat(secondDefaultCustomizerInvoked).hasValue(1);
            assertThat(firstVirtualHostCustomizerInvoked).hasValue(1);
            assertThat(secondVirtualHostCustomizerInvoked).hasValue(1);

            assertThat(defaultSslCtxBuilder.get()).isNotSameAs(virtualHostSslCtxBuilder.get());

            firstDefaultCustomizerInvoked.set(0);
            secondDefaultCustomizerInvoked.set(0);
            firstVirtualHostCustomizerInvoked.set(0);
            secondVirtualHostCustomizerInvoked.set(0);
        }
    }
Makes sure that {@link ServerBuilder#decorator(DecoratingHttpServiceFunction)} works at every service and
virtual hosts and {@link VirtualHostBuilder#decorator(DecoratingHttpServiceFunction)} works only at
its own services.
core/src/test/java/com/linecorp/armeria/server/ServerBuilderTest.java