@Test
    public void testDestroyAbortsSessionIfNotDone() throws Exception {
        MockComponents mc = createDefaultMock("id.user==1234");
        mc.visitorSession.start();
        mc.executor.expectAndProcessTasks(1);
        mc.controlHandler.setSynchronousWaitUntilDone(true);
        mc.controlHandler.resetMock();
        final MessageBusVisitorSession session = mc.visitorSession;
        final SharedValue<Exception> exceptionPropagator = new SharedValue<Exception>();
        final CyclicBarrier barrier = new CyclicBarrier(2);

        // Have to do this multi-threaded for once since destroy is
        // synchronous and any code logic bug could otherwise cause the
        // test (and thus the build) to hang indefinitely.
        // NOTE: even though the MockControlHandler itself is not thread safe,
        // the control flow of the test should guarantee there is no concurrent
        // access to it.
        Thread t = new Thread(() -> {
            try {
                session.destroy();
                if (!session.isDone()) {
                    throw new IllegalStateException("Session is not marked as done after destroy()");
                }
                barrier.await(20000, TimeUnit.MILLISECONDS);
            } catch (Exception e) {
                exceptionPropagator.setValue(e);
            }
        });
        t.start();

        try {
            waitUntilTrue(20000, () -> session.isDestroying());

            // Reply to visitor. Normally, the visitor would be resent, but
            // since destroy aborts the session, this won't happen and the
            // session will be marked as completed instead.
            replyErrorToCreateVisitor(mc.sender, new Error(DocumentProtocol.ERROR_BUCKET_DELETED, "goner"));
            mc.executor.expectAndProcessTasks(1); // reply
            mc.executor.expectNoTasks();

            barrier.await(20000, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            t.interrupt();
            throw e;
        } finally {
            t.join();
        }

        if (exceptionPropagator.getValue() != null) {
            throw new IllegalStateException(
                    "Exception thrown in destruction thread",
                    exceptionPropagator.getValue());
        }

        assertTrue(mc.sender.isDestroyed());
        assertTrue(mc.receiver.isDestroyed());

        assertEquals(
                "onDone : ABORTED - 'Session explicitly destroyed before completion'\n",
                mc.controlHandler.toString());
    }
Test that calling waitUntilDone waits until session has completed.
Test that destroy() destroys the communication interfaces it uses.
@throws Exception
documentapi/src/test/java/com/yahoo/documentapi/messagebus/MessageBusVisitorSessionTestCase.java