@Override
    protected double maintain() {
        // Reboot candidates: Nodes in long-term states, where we know we can safely orchestrate a reboot
        List<Node> nodesToReboot = nodeRepository().nodes().list(Node.State.active, Node.State.ready).stream()
                .filter(node -> node.type().isHost())
                .filter(this::shouldReboot)
                .toList();

        if (!nodesToReboot.isEmpty())
            nodeRepository().nodes().reboot(NodeListFilter.from(nodesToReboot));
        return 1.0;
    }
@Test(timeout = 30_000) // Avoid looping forever if assertions don't hold
    public void testRebootScheduledEvenWithSmallProbability() {
        Duration rebootInterval = Duration.ofDays(30);
        InMemoryFlagSource flagSource = new InMemoryFlagSource();
        ProvisioningTester tester = createTester(rebootInterval, flagSource);

        makeReadyHosts(2, tester);
        NodeRepository nodeRepository = tester.nodeRepository();
        NodeRebooter rebooter = new NodeRebooter(nodeRepository, flagSource, new TestMetric());

        assertReadyHosts(2, nodeRepository, 0L);

        // No reboots within 0x-1x reboot interval
        tester.clock().advance(rebootInterval);
        rebooter.maintain();
        simulateReboot(nodeRepository);
        assertReadyHosts(2, nodeRepository, 0L);

        // Advancing just a little bit into the 1x-2x interval, there is a >0 probability of
        // rebooting a host. Run until all have been scheduled.
        tester.clock().advance(Duration.ofMinutes(25));
        while (true) {
            rebooter.maintain();
            simulateReboot(nodeRepository);
            NodeList nodes = nodeRepository.nodes().list(Node.State.ready).nodeType(NodeType.host);
            int count = withCurrentRebootGeneration(1L, nodes.asList()).size();
            if (count == 2) {
                break;
            }
        }
    }