@Test
    public void testSynchronousWaitUntilDoneAndDestroy() throws Exception {
        MockComponents mc = createDefaultMock("id.user==1234");
        mc.visitorSession.start();
        mc.executor.expectAndProcessTasks(1);
        mc.controlHandler.setSynchronousWaitUntilDone(true);
        mc.controlHandler.resetMock();
        final MockControlHandler controlHandler = mc.controlHandler;
        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 waitUntilDone/destroy
        // are both synchronous and will not return before session is complete,
        // either through success or failure.
        Thread t = new Thread(() -> {
            try {
                boolean ok = session.waitUntilDone(20000);
                if (!session.isDone()) {
                    throw new IllegalStateException("waitUntilDone returned, but session is not marked as done");
                }
                assertTrue(ok);
                session.destroy();
                barrier.await(20000, TimeUnit.MILLISECONDS);
            } catch (Exception e) {
                exceptionPropagator.setValue(e);
            }
        });
        t.start();

        try {
            waitUntilTrue(20000, () -> controlHandler.isWaiting());

            // Reply to visitor, causing session to complete
            assertEquals("CreateVisitorMessage(buckets=[\n" +
                    "BucketId(0x80000000000004d2)\n" +
                    "BucketId(0x0000000000000000)\n" +
                    "]\n" +
                    "selection='id.user==1234'\n)",
                    replyToCreateVisitor(mc.sender, ProgressToken.FINISHED_BUCKET));
            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(
                "waitUntilDone : 20000\n" +
                "onProgress : 0 active, 0 pending, 1 finished, 1 total\n" +
                "onVisitorStatistics : 0 buckets visited, 0 docs returned\n" +
                "onDone : SUCCESS - ''\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