@Test
    void testGetNodeStateWithConfigurationChangeToRetiredWhileNodeDown() throws Exception {
        { // Configuration: 5 nodes, all normal
            List<ConfiguredNode> configuredNodes = new ArrayList<>();
            for (int i = 0; i < 5; i++)
                configuredNodes.add(new ConfiguredNode(i, false));
            FleetControllerOptions.Builder builder = defaultOptions(configuredNodes)
                    .setMaxInitProgressTime(30000)
                    .setStableStateTimePeriod(60000);
            setUpFleetController(timer, builder);
            setUpVdsNodes(timer, false, configuredNodes);
            waitForState("version:\\d+ distributor:5 storage:5");
        }

        { // 2 first storage nodes go down (0 and 2 are the corresponding distributors)
            waitForCompleteCycle();
            timer.advanceTime(1000000);
            waitForCompleteCycle(); // Make fleet controller notice that time has changed before any disconnects
            nodes.get(1).disconnectImmediately();
            nodes.get(3).disconnectImmediately();
            waitForState("version:\\d+ distributor:5 storage:5 .0.s:m .1.s:m");
        }

        { // Configuration change: Add 2 new nodes and retire the 5 existing ones
            setUpVdsNodes(timer, false, 2);
            Set<ConfiguredNode> configuredNodes = new TreeSet<>();
            for (int i = 0; i < 5; i++)
                configuredNodes.add(new ConfiguredNode(i, true));
            configuredNodes.add(new ConfiguredNode(5, false));
            configuredNodes.add(new ConfiguredNode(6, false));
            var builder = FleetControllerOptions.Builder.copy(fleetController().getOptions())
                    .setNodes(configuredNodes);
            fleetController().updateOptions(builder.build());
            waitForState("version:\\d+ distributor:7 storage:7 .0.s:m .1.s:m .2.s:r .3.s:r .4.s:r");
        }

        { // 2 storage nodes down come up, should go to state retired
            waitForCompleteCycle();
            timer.advanceTime(1000000);
            waitForCompleteCycle(); // Make fleet controller notice that time has changed before any disconnects
            nodes.get(1).connect();
            nodes.get(3).connect();
            waitForState("version:\\d+ distributor:7 storage:7 .0.s:r .1.s:r .2.s:r .3.s:r .4.s:r");
        }

        { // 2 first storage nodes go down again
            waitForCompleteCycle();
            timer.advanceTime(1000000);
            waitForCompleteCycle(); // Make fleet controller notice that time has changed before any disconnects
            nodes.get(1).disconnectImmediately();
            nodes.get(3).disconnectImmediately();
            waitForState("version:\\d+ distributor:7 storage:7 .0.s:m .1.s:m .2.s:r .3.s:r .4.s:r");
        }

        { // Configuration change: Unretire the nodes
            Set<ConfiguredNode> configuredNodes = new TreeSet<>();
            for (int i = 0; i < 7; i++)
                configuredNodes.add(new ConfiguredNode(i, false));
            var builder = FleetControllerOptions.Builder.copy(fleetController().getOptions())
                    .setNodes(configuredNodes);
            fleetController().updateOptions(builder.build());
            waitForState("version:\\d+ distributor:7 storage:7 .0.s:m .1.s:m");
        }

        { // 2 storage nodes down come up, should go to state up
            waitForCompleteCycle();
            timer.advanceTime(1000000);
            waitForCompleteCycle(); // Make fleet controller notice that time has changed before any disconnects
            nodes.get(1).connect();
            nodes.get(3).connect();
            waitForState("version:\\d+ distributor:7 storage:7");
        }

    }
Note: RpcServer is only used in unit tests

@author humbe
clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/RpcServerTest.java