public void waitForNodesHavingSystemStateVersionEqualToOrAbove(int version, int nodeCount, Duration timeout) throws InterruptedException {
        Instant endTime = Instant.now().plus(timeout);
        synchronized (monitor) {
            while (true) {
                int ackedNodes = 0;
                for (NodeInfo node : cluster.getNodeInfos()) {
                    if (node.getClusterStateVersionBundleAcknowledged() >= version) {
                        ++ackedNodes;
                    }
                }
                if (ackedNodes >= nodeCount) {
                    context.log(logger, Level.INFO, ackedNodes + " nodes now have acked system state " + version + " or higher.");
                    return;
                }
                if (Instant.now().isAfter(endTime)) {
                    throw new IllegalStateException("Did not get " + nodeCount + " nodes to system state " + version + " within timeout of " + timeout);
                }
                monitor.wait(10);
            }
        }
    }
This function might not be 100% threadsafe, as in theory cluster can be changing while accessed.
But it is only used in unit tests that should not trigger any thread issues. Don't want to add locks that reduce
live performance to remove a non-problem.
clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/FleetController.java