Code review comment: This seems to rely on very particular behavior of the embedded executor.  Can we achieve the same by delaying the acknowledgement of the job submission? That'd seem more intuitive to me.

Code under review:
void testApplicationIsStoppedWhenStoppingBootstrap() throws Exception {
        final AtomicBoolean shutdownCalled = new AtomicBoolean(false);
        final CompletableFuture<JobStatus> getJobStatusFuture = new CompletableFuture<>();
        final TestingDispatcherGateway.Builder dispatcherBuilder =
                runningJobGatewayBuilder()
                        .setRequestJobStatusFunction(ignoredJobId -> getJobStatusFuture)
                        .setClusterShutdownFunction(
                                status -> {
                                    shutdownCalled.set(true);
                                    return CompletableFuture.completedFuture(Acknowledge.get());
                                });

        
        
        final CompletableFuture<Void> errorHandlerFuture = new CompletableFuture<>();
        final ApplicationDispatcherBootstrap bootstrap =
                createApplicationDispatcherBootstrap(
                        3,
                        dispatcherBuilder.build(),
                        scheduledExecutor,
                        errorHandlerFuture::completeExceptionally);

        final CompletableFuture<Acknowledge> completionFuture =
                bootstrap.getBootstrapCompletionFuture();

        ScheduledFuture<?> applicationExecutionFuture = bootstrap.getApplicationExecutionFuture();

        bootstrap.stop();

        
        
        
        
        
        getJobStatusFuture.complete(JobStatus.RUNNING);

        
        assertThat(errorHandlerFuture.isDone()).isFalse();

        
        completionFuture.get();

        
        assertThat(shutdownCalled.get()).isFalse();

        
        assertThat(applicationExecutionFuture.isCancelled()).isTrue();
        assertThat(applicationExecutionFuture.isDone()).isTrue();
    }

Line commented on: getJobStatusFuture.complete(JobStatus.RUNNING);

Revised code:
void testApplicationIsStoppedWhenStoppingBootstrap() throws Exception {
        final AtomicBoolean shutdownCalled = new AtomicBoolean(false);
        final TestingDispatcherGateway.Builder dispatcherBuilder =
                runningJobGatewayBuilder()
                        .setClusterShutdownFunction(
                                status -> {
                                    shutdownCalled.set(true);
                                    return CompletableFuture.completedFuture(Acknowledge.get());
                                });

        final ManuallyTriggeredScheduledExecutor manuallyTriggeredExecutor =
                new ManuallyTriggeredScheduledExecutor();
        
        
        final CompletableFuture<Void> errorHandlerFuture = new CompletableFuture<>();
        final ApplicationDispatcherBootstrap bootstrap =
                createApplicationDispatcherBootstrap(
                        3,
                        dispatcherBuilder.build(),
                        manuallyTriggeredExecutor,
                        errorHandlerFuture::completeExceptionally);

        final CompletableFuture<Acknowledge> completionFuture =
                bootstrap.getBootstrapCompletionFuture();

        ScheduledFuture<?> applicationExecutionFuture = bootstrap.getApplicationExecutionFuture();

        bootstrap.stop();

        
        
        
        manuallyTriggeredExecutor.triggerNonPeriodicScheduledTask();

        
        assertThat(errorHandlerFuture.isDone()).isFalse();

        
        completionFuture.get();

        
        assertThat(shutdownCalled.get()).isFalse();

        
        assertThat(applicationExecutionFuture.isCancelled()).isTrue();
        assertThat(applicationExecutionFuture.isDone()).isTrue();
    }