@Override
    protected double maintain() {
        expireReserved();
        return (deprovisionRemovable() + pruneReals()) / 2;
    }
@Test
    public void expire_inactive() {
        LoadBalancerExpirer expirer = new LoadBalancerExpirer(tester.nodeRepository(),
                                                              Duration.ofDays(1),
                                                              tester.loadBalancerService(),
                                                              new TestMetric());
        Supplier<Map<LoadBalancerId, LoadBalancer>> loadBalancers = () -> tester.nodeRepository().database().readLoadBalancers((ignored) -> true);

        // Deploy two applications with a total of three load balancers
        ClusterSpec.Id cluster1 = ClusterSpec.Id.from("qrs");
        ClusterSpec.Id cluster2 = ClusterSpec.Id.from("qrs2");
        ApplicationId app1 = ProvisioningTester.applicationId();
        ApplicationId app2 = ProvisioningTester.applicationId();
        LoadBalancerId lb1 = new LoadBalancerId(app1, cluster1);
        LoadBalancerId lb2 = new LoadBalancerId(app2, cluster1);
        LoadBalancerId lb3 = new LoadBalancerId(app2, cluster2);
        deployApplication(app1, cluster1);
        deployApplication(app2, cluster1, cluster2);
        assertEquals(3, loadBalancers.get().size());

        // Remove one application deactivates load balancers for that application
        tester.remove(app1);
        assertSame(LoadBalancer.State.inactive, loadBalancers.get().get(lb1).state());
        assertNotSame(LoadBalancer.State.inactive, loadBalancers.get().get(lb2).state());

        // Expirer defers removal while nodes are still allocated to application
        tester.move(Node.State.ready, tester.nodeRepository().nodes().list(Node.State.dirty).asList());
        expirer.maintain();
        assertEquals(Set.of(), tester.loadBalancerService().instances().get(lb1).reals());
        assertEquals(Set.of(), loadBalancers.get().get(lb1).instance().get().reals());

        // Expirer defers removal of load balancer until expiration time passes
        expirer.maintain();
        assertSame(LoadBalancer.State.inactive, loadBalancers.get().get(lb1).state());
        assertTrue("Inactive load balancer not removed", tester.loadBalancerService().instances().containsKey(lb1));

        // Expirer removes load balancers once expiration time passes
        tester.clock().advance(Duration.ofHours(1).plus(Duration.ofSeconds(1)));
        expirer.maintain();
        assertFalse("Inactive load balancer removed", tester.loadBalancerService().instances().containsKey(lb1));

        // Active load balancer is left alone
        assertSame(LoadBalancer.State.active, loadBalancers.get().get(lb2).state());
        assertTrue("Active load balancer is not removed", tester.loadBalancerService().instances().containsKey(lb2));

        // A single cluster is removed
        deployApplication(app2, cluster1);
        expirer.maintain();
        assertSame(LoadBalancer.State.inactive, loadBalancers.get().get(lb3).state());

        // Expirer defers removal while nodes are still allocated to cluster
        expirer.maintain();
        assertEquals(2, tester.loadBalancerService().instances().size());
        removeNodesOf(app2, cluster2);

        // Expirer removes load balancer for removed cluster
        tester.clock().advance(Duration.ofHours(1).plus(Duration.ofSeconds(1)));
        expirer.maintain();
        assertFalse("Inactive load balancer removed", tester.loadBalancerService().instances().containsKey(lb3));
    }