@Test
    public void retire_multiple_proxy_simultaneously() {
        MockDeployer deployer = new MockDeployer(tester.provisioner(),
                                                 tester.clock(),
                                                 List.of(new MockDeployer.ApplicationContext(proxyApp, Version.fromString("6.42"))));
        RetiredExpirer retiredExpirer =  new RetiredExpirer(tester.nodeRepository(),
                                                            deployer,
                                                            new TestMetric(),
                                                            Duration.ofDays(30),
                                                            Duration.ofMinutes(10));
        final int numNodesToRetire = 5;

        { // Deploy
            tester.prepareAndActivateInfraApplication(proxyApp);
            NodeList nodes = tester.nodeRepository().nodes().list(Node.State.active).nodeType(NodeType.proxy);
            assertEquals("Activated all proxies", 11, nodes.size());
        }

        List<Node> nodesToRetire = tester.nodeRepository().nodes().list(Node.State.active).nodeType(NodeType.proxy).asList()
                .subList(3, 3 + numNodesToRetire);
        {
            nodesToRetire.forEach(nodeToRetire ->
                    tester.nodeRepository().nodes().write(nodeToRetire.withWantToRetire(true, Agent.system, tester.clock().instant()), () -> {}));

            tester.prepareAndActivateInfraApplication(proxyApp);
            NodeList nodes = tester.nodeRepository().nodes().list(Node.State.active).nodeType(NodeType.proxy);
            assertEquals(11, nodes.size());

            // Verify that wantToRetire has been propagated
            List<Node> nodesCurrentlyRetiring = nodes.stream()
                    .filter(node -> node.allocation().get().membership().retired())
                    .toList();
            assertEquals(5, nodesCurrentlyRetiring.size());

            // The retiring nodes should be the nodes we marked for retirement
            assertTrue(Set.copyOf(nodesToRetire).containsAll(nodesCurrentlyRetiring));
        }

        { // Redeploying while the nodes are still retiring has no effect
            tester.prepareAndActivateInfraApplication(proxyApp);
            NodeList nodes = tester.nodeRepository().nodes().list(Node.State.active).nodeType(NodeType.proxy);
            assertEquals(11, nodes.size());

            // Verify that wantToRetire has been propagated
            List<Node> nodesCurrentlyRetiring = nodes.stream()
                    .filter(node -> node.allocation().get().membership().retired())
                    .toList();
            assertEquals(5, nodesCurrentlyRetiring.size());
        }

        {
            // Let all retired nodes expire
            tester.advanceTime(Duration.ofMinutes(11));
            retiredExpirer.run();

            tester.prepareAndActivateInfraApplication(proxyApp);

            // All currently active proxy nodes are not marked with wantToRetire or as retired
            long numRetiredActiveProxyNodes = tester.nodeRepository().nodes().list(Node.State.active).nodeType(NodeType.proxy).stream()
                    .filter(node -> !node.status().wantToRetire())
                    .filter(node -> !node.allocation().get().membership().retired())
                    .count();
            assertEquals(6, numRetiredActiveProxyNodes);

            // All the nodes that were marked with wantToRetire earlier are now dirty
            assertEquals(nodesToRetire.stream().map(Node::hostname).collect(Collectors.toSet()),
                    tester.nodeRepository().nodes().list(Node.State.dirty).stream().map(Node::hostname).collect(Collectors.toSet()));
        }
    }
Tests provisioning by node type instead of by count and flavor

@author bratseth
node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/NodeTypeProvisioningTest.java