// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.clustercontroller.core; import com.yahoo.vdslib.distribution.ConfiguredNode; import com.yahoo.vdslib.distribution.Distribution; import com.yahoo.vdslib.state.ClusterState; import com.yahoo.vdslib.state.Node; import com.yahoo.vdslib.state.NodeState; import com.yahoo.vdslib.state.NodeType; import com.yahoo.vdslib.state.State; import com.yahoo.vespa.clustercontroller.core.hostinfo.HostInfo; import com.yahoo.vespa.clustercontroller.core.listeners.NodeListener; import com.yahoo.vespa.clustercontroller.core.mocks.TestEventLog; import com.yahoo.vespa.clustercontroller.core.testutils.LogFormatter; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.util.LinkedList; import java.util.Set; import java.util.TreeSet; import java.util.logging.Logger; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; public class StateChangeHandlerTest { private static final Logger log = Logger.getLogger(StateChangeHandlerTest.class.getName()); private static class Config { int nodeCount = 3; int stableStateTime = 1000 * 60000; int maxSlobrokDisconnectPeriod = 60000; int maxPrematureCrashes = 3; } private static class TestNodeListener implements NodeListener { LinkedList events = new LinkedList<>(); @Override public void handleNewNodeState(NodeInfo node, NodeState newState) { events.add(node + " - " + newState); } @Override public void handleNewWantedNodeState(NodeInfo node, NodeState newState) { events.add(node + " - " + newState); } @Override public void handleRemovedNode(Node node) { events.add("removed: " + node); } @Override public void handleUpdatedHostInfo(NodeInfo node, HostInfo newHostInfo) { events.add(node + " - " + newHostInfo); } public String toString() { StringBuilder sb = new StringBuilder(); sb.append("NodeChanges("); for (String change : events) sb.append('\n').append(change); sb.append(")"); return sb.toString(); } } private final FakeTimer clock = new FakeTimer(); private final TestEventLog eventLog = new TestEventLog(); private final Set configuredNodes = new TreeSet<>(); private Config config; private ContentCluster cluster; private StateChangeHandler nodeStateChangeHandler; private TestNodeListener nodeStateUpdateListener; private final ClusterStateGenerator.Params params = new ClusterStateGenerator.Params(); @BeforeEach public void setUp() { LogFormatter.initializeLogging(); } private void initialize(Config config) { Distribution distribution = new Distribution(Distribution.getDefaultDistributionConfig(2, 100)); this.config = config; for (int i=0; i