@SuppressWarnings("removal") // TODO: Remove on Vespa 9
    private String createVisitorToString(CreateVisitorMessage msg) {
        StringBuilder sb = new StringBuilder();
        sb.append("CreateVisitorMessage(buckets=[\n");
        for (BucketId id : msg.getBuckets()) {
            sb.append(id).append("\n");
        }
        sb.append("]\n");
        if (!"".equals(msg.getDocumentSelection())) {
            sb.append("selection='").append(msg.getDocumentSelection()).append("'\n");
        }
        if (msg.getTimeRemaining() != 5 * 60 * 1000) {
            sb.append("time remaining=").append(msg.getTimeRemaining()).append("\n");
        }
        if (msg.getFromTimestamp() != 0) {
            sb.append("from timestamp=").append(msg.getFromTimestamp()).append("\n");
        }
        if (msg.getToTimestamp() != 0) {
            sb.append("to timestamp=").append(msg.getToTimestamp()).append("\n");
        }
        if (msg.getMaxPendingReplyCount() != 32) {
            sb.append("max pending=").append(msg.getMaxPendingReplyCount()).append("\n");
        }
        if (!DocumentOnly.NAME.equals(msg.getFieldSet())) {
            sb.append("fieldset=").append(msg.getFieldSet()).append("\n");
        }
        if (msg.getVisitInconsistentBuckets()) {
            sb.append("visit inconsistent=").append(msg.getVisitInconsistentBuckets()).append("\n");
        }
        if (msg.getVisitRemoves()) {
            sb.append("visit removes=").append(msg.getVisitRemoves()).append("\n");
        }
        if (!msg.getParameters().isEmpty()) {
            sb.append("parameters=[\n");
            for (Map.Entry<String, byte[]> kv : msg.getParameters().entrySet()) {
                sb.append(kv.getKey()).append(" -> ");
                sb.append(new String(kv.getValue(), Charset.defaultCharset()));
                sb.append("\n");
            }
            sb.append("]\n");
        }
        if (msg.getRoute() != null && !"storage".equals(msg.getRoute().toString())) {
            sb.append("route=").append(msg.getRoute()).append("\n");
        }
        if (msg.getMaxBucketsPerVisitor() != 1) {
            sb.append("max buckets per visitor=").append(msg.getMaxBucketsPerVisitor()).append("\n");
        }
        if (msg.getPriority() != DocumentProtocol.Priority.NORMAL_3) { // TODO: remove on Vespa 9
            sb.append("priority=").append(msg.getPriority()).append("\n");
        }
        if (!"DumpVisitor".equals(msg.getLibraryName())) {
            sb.append("visitor library=").append(msg.getLibraryName()).append("\n");
        }
        if (msg.getTrace().getLevel() != 0) {
            sb.append("trace level=").append(msg.getTrace().getLevel()).append("\n");
        }
        sb.append(")");
        return sb.toString();
    }
Mock the executor to keep things nicely single threaded for the testing.
No need to synchronize things here since we don't use multiple threads.
documentapi/src/test/java/com/yahoo/documentapi/messagebus/MessageBusVisitorSessionTestCase.java