aboutsummaryrefslogtreecommitdiffstats
path: root/orchestrator/src/test
diff options
context:
space:
mode:
authorHåkon Hallingstad <hakon@yahoo-inc.com>2017-04-28 17:29:57 +0200
committerHåkon Hallingstad <hakon@yahoo-inc.com>2017-04-28 17:29:57 +0200
commit019a33d591366a025fa012951e9dbac21f83c1de (patch)
treefa65aa8ecf5a139eff855eabc22b8ee86eab9565 /orchestrator/src/test
parentc00a3b8a6318e7dd6c7c09b8d87042734dfdc382 (diff)
Adds classes to give the Orchestrator policy classes a simplified view of Vespa.
This should be a no-op. The only changes that actually could have an impact are the changes to getting the cluster controllers, but it should be functionally equivalent. This PR will make it easier to change the Orchestrator policy to allow suspending several nodes (NodeGroup) in an application on a single Docker host.
Diffstat (limited to 'orchestrator/src/test')
-rw-r--r--orchestrator/src/test/java/com/yahoo/vespa/orchestrator/DummyInstanceLookupService.java1
-rw-r--r--orchestrator/src/test/java/com/yahoo/vespa/orchestrator/controller/ClusterControllerClientFactoryMock.java7
-rw-r--r--orchestrator/src/test/java/com/yahoo/vespa/orchestrator/controller/SingleInstanceClusterControllerClientFactoryTest.java25
-rw-r--r--orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/ApplicationApiImplTest.java321
-rw-r--r--orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/ClusterApiImplTest.java133
-rw-r--r--orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/ModelTestUtils.java92
-rw-r--r--orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/NodeGroupTest.java33
-rw-r--r--orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/VespaModelUtilTest.java (renamed from orchestrator/src/test/java/com/yahoo/vespa/orchestrator/VespaModelUtilTest.java)12
-rw-r--r--orchestrator/src/test/java/com/yahoo/vespa/orchestrator/policy/HostedVespaPolicyTest.java12
9 files changed, 605 insertions, 31 deletions
diff --git a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/DummyInstanceLookupService.java b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/DummyInstanceLookupService.java
index d48bc1f302b..dede55f402a 100644
--- a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/DummyInstanceLookupService.java
+++ b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/DummyInstanceLookupService.java
@@ -12,6 +12,7 @@ import com.yahoo.vespa.applicationmodel.ServiceCluster;
import com.yahoo.vespa.applicationmodel.ServiceInstance;
import com.yahoo.vespa.applicationmodel.ServiceType;
import com.yahoo.vespa.applicationmodel.TenantId;
+import com.yahoo.vespa.orchestrator.model.VespaModelUtil;
import com.yahoo.vespa.service.monitor.ServiceMonitorStatus;
import java.util.HashSet;
diff --git a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/controller/ClusterControllerClientFactoryMock.java b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/controller/ClusterControllerClientFactoryMock.java
index 4fc9ad2d56d..93dcb5815c6 100644
--- a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/controller/ClusterControllerClientFactoryMock.java
+++ b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/controller/ClusterControllerClientFactoryMock.java
@@ -4,15 +4,14 @@ package com.yahoo.vespa.orchestrator.controller;
import com.yahoo.vespa.applicationmodel.ApplicationInstance;
import com.yahoo.vespa.applicationmodel.ClusterId;
import com.yahoo.vespa.applicationmodel.HostName;
-import com.yahoo.vespa.applicationmodel.ServiceInstance;
import com.yahoo.vespa.orchestrator.DummyInstanceLookupService;
-import com.yahoo.vespa.orchestrator.VespaModelUtil;
+import com.yahoo.vespa.orchestrator.model.VespaModelUtil;
import com.yahoo.vespa.service.monitor.ServiceMonitorStatus;
import java.io.IOException;
-import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -50,7 +49,7 @@ public class ClusterControllerClientFactoryMock implements ClusterControllerClie
}
@Override
- public ClusterControllerClient createClient(Collection<? extends ServiceInstance<?>> clusterControllers, String clusterName) {
+ public ClusterControllerClient createClient(List<HostName> clusterControllers, String clusterName) {
return new ClusterControllerClient() {
@Override
diff --git a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/controller/SingleInstanceClusterControllerClientFactoryTest.java b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/controller/SingleInstanceClusterControllerClientFactoryTest.java
index cc217885047..cde644e7e8b 100644
--- a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/controller/SingleInstanceClusterControllerClientFactoryTest.java
+++ b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/controller/SingleInstanceClusterControllerClientFactoryTest.java
@@ -1,17 +1,14 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.orchestrator.controller;
-import com.yahoo.vespa.jaxrs.client.JaxRsClientFactory;
-import com.yahoo.vespa.orchestrator.TestUtil;
import com.yahoo.vespa.applicationmodel.ConfigId;
import com.yahoo.vespa.applicationmodel.HostName;
-import com.yahoo.vespa.applicationmodel.ServiceInstance;
-import com.yahoo.vespa.service.monitor.ServiceMonitorStatus;
+import com.yahoo.vespa.jaxrs.client.JaxRsClientFactory;
import org.junit.Before;
import org.junit.Test;
-import java.util.Collection;
-import java.util.Collections;
+import java.util.Arrays;
+import java.util.List;
import static org.hamcrest.CoreMatchers.anyOf;
import static org.hamcrest.CoreMatchers.equalTo;
@@ -52,7 +49,7 @@ public class SingleInstanceClusterControllerClientFactoryTest {
@Test
public void testCreateClientWithNoClusterControllerInstances() throws Exception {
- final Collection<ServiceInstance<ServiceMonitorStatus>> clusterControllers = Collections.emptySet();
+ final List<HostName> clusterControllers = Arrays.asList();
try {
clientFactory.createClient(clusterControllers, "clusterName");
@@ -64,8 +61,7 @@ public class SingleInstanceClusterControllerClientFactoryTest {
@Test
public void testCreateClientWithSingleClusterControllerInstance() throws Exception {
- final Collection<ServiceInstance<ServiceMonitorStatus>> clusterControllers = Collections.singleton(
- new ServiceInstance<>(clusterControllerConfigId(1), HOST_NAME_1, ServiceMonitorStatus.UP));
+ final List<HostName> clusterControllers = Arrays.asList(HOST_NAME_1);
clientFactory.createClient(clusterControllers, "clusterName")
.setNodeState(0, ClusterControllerState.MAINTENANCE);
@@ -78,10 +74,8 @@ public class SingleInstanceClusterControllerClientFactoryTest {
}
@Test
- public void testCreateClientWithTwoNonClusterControllerInstances() throws Exception {
- final Collection<ServiceInstance<ServiceMonitorStatus>> clusterControllers = TestUtil.makeServiceInstanceSet(
- new ServiceInstance<>(new ConfigId("not-a-cluster-controller-1"), HOST_NAME_1, ServiceMonitorStatus.UP),
- new ServiceInstance<>(new ConfigId("not-a-cluster-controller-2"), HOST_NAME_2, ServiceMonitorStatus.UP));
+ public void testCreateClientWithoutClusterControllerInstances() throws Exception {
+ final List<HostName> clusterControllers = Arrays.asList();
try {
clientFactory.createClient(clusterControllers, "clusterName");
@@ -93,10 +87,7 @@ public class SingleInstanceClusterControllerClientFactoryTest {
@Test
public void testCreateClientWithThreeClusterControllerInstances() throws Exception {
- final Collection<ServiceInstance<ServiceMonitorStatus>> clusterControllers = TestUtil.makeServiceInstanceSet(
- new ServiceInstance<>(clusterControllerConfigId(1), HOST_NAME_1, ServiceMonitorStatus.UP),
- new ServiceInstance<>(clusterControllerConfigId(2), HOST_NAME_2, ServiceMonitorStatus.UP),
- new ServiceInstance<>(clusterControllerConfigId(3), HOST_NAME_3, ServiceMonitorStatus.UP));
+ final List<HostName> clusterControllers = Arrays.asList(HOST_NAME_1, HOST_NAME_2, HOST_NAME_3);
clientFactory.createClient(clusterControllers, "clusterName")
.setNodeState(0, ClusterControllerState.MAINTENANCE);
diff --git a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/ApplicationApiImplTest.java b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/ApplicationApiImplTest.java
new file mode 100644
index 00000000000..684f7e76d94
--- /dev/null
+++ b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/ApplicationApiImplTest.java
@@ -0,0 +1,321 @@
+package com.yahoo.vespa.orchestrator.model;
+
+import com.yahoo.vespa.applicationmodel.ApplicationInstance;
+import com.yahoo.vespa.applicationmodel.HostName;
+import com.yahoo.vespa.applicationmodel.ServiceType;
+import com.yahoo.vespa.orchestrator.status.HostStatus;
+import com.yahoo.vespa.service.monitor.ServiceMonitorStatus;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.junit.Assert.assertEquals;
+
+public class ApplicationApiImplTest {
+ final ModelTestUtils modelUtils = new ModelTestUtils();
+
+ @Test
+ public void testApplicationInfo() {
+ ApplicationApiImpl applicationApi =
+ modelUtils.createApplicationApiImpl(modelUtils.createApplicationInstance(new ArrayList<>()));
+ assertEquals("tenant:application-name:foo:bar:default", applicationApi.applicationInfo());
+ }
+
+ @Test
+ public void testGetClustersThatAreOnAtLeastOneNodeInGroup() {
+ HostName hostName1 = new HostName("host1");
+ HostName hostName2 = new HostName("host2");
+ HostName hostName3 = new HostName("host3");
+ HostName hostName4 = new HostName("host4");
+
+ ApplicationInstance<ServiceMonitorStatus> applicationInstance =
+ modelUtils.createApplicationInstance(Arrays.asList(
+ modelUtils.createServiceCluster(
+ "cluster-3",
+ new ServiceType("service-type-3"),
+ Arrays.asList(
+ modelUtils.createServiceInstance("config-id-1", hostName1, ServiceMonitorStatus.UP),
+ modelUtils.createServiceInstance("config-id-2", hostName2, ServiceMonitorStatus.UP)
+ )
+ ),
+ modelUtils.createServiceCluster(
+ "cluster-1",
+ new ServiceType("service-type-1"),
+ Arrays.asList(
+ modelUtils.createServiceInstance("config-id-3", hostName1, ServiceMonitorStatus.UP),
+ modelUtils.createServiceInstance("config-id-4", hostName3, ServiceMonitorStatus.UP)
+ )
+ ),
+ modelUtils.createServiceCluster(
+ "cluster-2",
+ new ServiceType("service-type-2"),
+ Arrays.asList(
+ modelUtils.createServiceInstance("config-id-5", hostName1, ServiceMonitorStatus.UP),
+ modelUtils.createServiceInstance("config-id-6", hostName2, ServiceMonitorStatus.UP)
+ )
+ )
+ ));
+
+ verifyClustersInOrder(modelUtils.createApplicationApiImpl(applicationInstance, hostName1), 1, 2, 3);
+ verifyClustersInOrder(modelUtils.createApplicationApiImpl(applicationInstance, hostName2), 2, 3);
+ verifyClustersInOrder(modelUtils.createApplicationApiImpl(applicationInstance, hostName3), 1);
+ verifyClustersInOrder(modelUtils.createApplicationApiImpl(applicationInstance, hostName4));
+ }
+
+ private void verifyClustersInOrder(ApplicationApi applicationApi,
+ Integer... expectedClusterNumbers) {
+ // Note: we require the clusters to be in order.
+ List<ClusterApi> clusterApis = applicationApi.getClusters();
+ String clusterInfos = clusterApis.stream().map(clusterApi -> clusterApi.clusterInfo()).collect(Collectors.joining(","));
+
+ String expectedClusterInfos = Arrays.stream(expectedClusterNumbers)
+ .map(number -> "{ clusterId=cluster-" + number + ", serviceType=service-type-" + number + " }")
+ .collect(Collectors.joining(","));
+
+ assertEquals(expectedClusterInfos, clusterInfos);
+ }
+
+ @Test
+ public void testGetUpStorageNodesInGroupInClusterOrder() {
+ HostName hostName1 = new HostName("host1");
+ HostName hostName2 = new HostName("host2");
+ HostName hostName3 = new HostName("host3");
+ HostName hostName4 = new HostName("host4");
+ HostName hostName5 = new HostName("host5");
+ HostName hostName6 = new HostName("host6");
+ HostName hostName7 = new HostName("host7");
+
+ ApplicationInstance<ServiceMonitorStatus> applicationInstance =
+ modelUtils.createApplicationInstance(Arrays.asList(
+ modelUtils.createServiceCluster(
+ "cluster-3",
+ VespaModelUtil.STORAGENODE_SERVICE_TYPE,
+ Arrays.asList(
+ modelUtils.createServiceInstance("config-id-30", hostName1, ServiceMonitorStatus.UP),
+ modelUtils.createServiceInstance("config-id-31", hostName2, ServiceMonitorStatus.UP)
+ )
+ ),
+ modelUtils.createServiceCluster(
+ "cluster-1",
+ VespaModelUtil.STORAGENODE_SERVICE_TYPE,
+ Arrays.asList(
+ modelUtils.createServiceInstance("config-id-10", hostName3, ServiceMonitorStatus.DOWN),
+ modelUtils.createServiceInstance("config-id-11", hostName4, ServiceMonitorStatus.UP)
+ )
+ ),
+ modelUtils.createServiceCluster(
+ "cluster-4",
+ new ServiceType("service-type-4"),
+ Arrays.asList(
+ modelUtils.createServiceInstance("config-id-40", hostName1, ServiceMonitorStatus.UP),
+ modelUtils.createServiceInstance("config-id-41", hostName2, ServiceMonitorStatus.UP),
+ modelUtils.createServiceInstance("config-id-42", hostName3, ServiceMonitorStatus.UP),
+ modelUtils.createServiceInstance("config-id-43", hostName5, ServiceMonitorStatus.UP)
+ )
+ ),
+ modelUtils.createServiceCluster(
+ "cluster-2",
+ VespaModelUtil.STORAGENODE_SERVICE_TYPE,
+ Arrays.asList(
+ modelUtils.createServiceInstance("config-id-20", hostName6, ServiceMonitorStatus.DOWN),
+ modelUtils.createServiceInstance("config-id-21", hostName7, ServiceMonitorStatus.UP)
+ )
+ )
+ ));
+
+ verifyUpStorageNodesInOrder(modelUtils.createApplicationApiImpl(applicationInstance, hostName1), hostName1);
+ verifyUpStorageNodesInOrder(modelUtils.createApplicationApiImpl(applicationInstance, hostName2), hostName2);
+ verifyUpStorageNodesInOrder(modelUtils.createApplicationApiImpl(applicationInstance, hostName3)); // host3 is DOWN
+ verifyUpStorageNodesInOrder(modelUtils.createApplicationApiImpl(applicationInstance, hostName4), hostName4);
+ verifyUpStorageNodesInOrder(modelUtils.createApplicationApiImpl(applicationInstance, hostName5)); // not a storage cluster
+
+ verifyUpStorageNodesInOrder(modelUtils.createApplicationApiImpl(applicationInstance, hostName1, hostName3), hostName1);
+
+ // For the node group (host1, host4), they both have an up storage node (service instance)
+ // with clusters (cluster-3, cluster-1) respectively, and so the order of the hosts are reversed
+ // (host4, host1) when sorted by the clusters.
+ verifyUpStorageNodesInOrder(modelUtils.createApplicationApiImpl(applicationInstance, hostName1, hostName4), hostName4, hostName1);
+
+ verifyUpStorageNodesInOrder(modelUtils.createApplicationApiImpl(
+ applicationInstance, hostName1, hostName4, hostName5), hostName4, hostName1);
+ verifyUpStorageNodesInOrder(modelUtils.createApplicationApiImpl(
+ applicationInstance, hostName1, hostName4, hostName5, hostName6), hostName4, hostName1);
+ verifyUpStorageNodesInOrder(modelUtils.createApplicationApiImpl(
+ applicationInstance, hostName1, hostName4, hostName5, hostName7), hostName4, hostName7, hostName1);
+ }
+
+ private void verifyUpStorageNodesInOrder(ApplicationApi applicationApi,
+ HostName... expectedHostNames) {
+ List<HostName> upStorageNodes = applicationApi.getUpStorageNodesInGroupInClusterOrder().stream()
+ .map(storageNode -> storageNode.hostName())
+ .collect(Collectors.toList());
+ assertEquals(Arrays.asList(expectedHostNames), upStorageNodes);
+ }
+
+ @Test
+ public void testUpConditionOfStorageNode() {
+ verifyUpConditionWith(HostStatus.NO_REMARKS, ServiceMonitorStatus.UP, true);
+ verifyUpConditionWith(HostStatus.NO_REMARKS, ServiceMonitorStatus.NOT_CHECKED, true);
+ verifyUpConditionWith(HostStatus.NO_REMARKS, ServiceMonitorStatus.DOWN, false);
+ verifyUpConditionWith(HostStatus.ALLOWED_TO_BE_DOWN, ServiceMonitorStatus.UP, false);
+ verifyUpConditionWith(HostStatus.ALLOWED_TO_BE_DOWN, ServiceMonitorStatus.NOT_CHECKED, false);
+ verifyUpConditionWith(HostStatus.ALLOWED_TO_BE_DOWN, ServiceMonitorStatus.DOWN, false);
+ }
+
+ private void verifyUpConditionWith(HostStatus hostStatus, ServiceMonitorStatus serviceStatus, boolean expectUp) {
+ HostName hostName1 = modelUtils.createNode("host1", hostStatus);
+
+ ApplicationInstance<ServiceMonitorStatus> applicationInstance =
+ modelUtils.createApplicationInstance(Arrays.asList(
+ modelUtils.createServiceCluster(
+ "cluster-1",
+ VespaModelUtil.STORAGENODE_SERVICE_TYPE,
+ Arrays.asList(modelUtils.createServiceInstance("config-id-1", hostName1, serviceStatus))
+ )
+ ));
+
+ ApplicationApiImpl applicationApi = modelUtils.createApplicationApiImpl(applicationInstance, hostName1);
+ List<HostName> upStorageNodes = expectUp ? Arrays.asList(hostName1) : new ArrayList<>();
+
+ List<HostName> actualStorageNodes = applicationApi.getUpStorageNodesInGroupInClusterOrder().stream()
+ .map(storageNode -> storageNode.hostName())
+ .collect(Collectors.toList());
+ assertEquals(upStorageNodes, actualStorageNodes);
+ }
+
+ @Test
+ public void testGetNodesInGroupWithStatus() {
+ HostName hostName1 = modelUtils.createNode("host1", HostStatus.NO_REMARKS);
+ HostName hostName2 = modelUtils.createNode("host2", HostStatus.NO_REMARKS);
+ HostName hostName3 = modelUtils.createNode("host3", HostStatus.ALLOWED_TO_BE_DOWN);
+
+ ApplicationInstance<ServiceMonitorStatus> applicationInstance =
+ modelUtils.createApplicationInstance(Arrays.asList(
+ modelUtils.createServiceCluster(
+ "cluster-1",
+ new ServiceType("service-type-1"),
+ Arrays.asList(
+ modelUtils.createServiceInstance("config-id-10", hostName1, ServiceMonitorStatus.UP),
+ modelUtils.createServiceInstance("config-id-11", hostName2, ServiceMonitorStatus.UP)
+ )
+ ),
+ modelUtils.createServiceCluster(
+ "cluster-2",
+ new ServiceType("service-type-2"),
+ Arrays.asList(
+ modelUtils.createServiceInstance("config-id-20", hostName1, ServiceMonitorStatus.UP),
+ modelUtils.createServiceInstance("config-id-21", hostName3, ServiceMonitorStatus.UP)
+ )
+ )
+ ));
+
+ verifyNodesInGroupWithoutRemarks(
+ modelUtils.createApplicationApiImpl(applicationInstance, hostName1),
+ Arrays.asList(hostName1),
+ Arrays.asList());
+ verifyNodesInGroupWithoutRemarks(
+ modelUtils.createApplicationApiImpl(applicationInstance, hostName1, hostName2),
+ Arrays.asList(hostName1, hostName2),
+ Arrays.asList());
+ verifyNodesInGroupWithoutRemarks(
+ modelUtils.createApplicationApiImpl(applicationInstance, hostName1, hostName2, hostName3),
+ Arrays.asList(hostName1, hostName2),
+ Arrays.asList(hostName3));
+ verifyNodesInGroupWithoutRemarks(
+ modelUtils.createApplicationApiImpl(applicationInstance, hostName3),
+ Arrays.asList(),
+ Arrays.asList(hostName3));
+ }
+
+ private void verifyNodesInGroupWithoutRemarks(ApplicationApi applicationApi,
+ List<HostName> noRemarksHostNames,
+ List<HostName> allowedToBeDownHostNames) {
+ List<HostName> actualNoRemarksHosts = applicationApi.getNodesInGroupWithStatus(HostStatus.NO_REMARKS);
+ assertEquals(noRemarksHostNames, actualNoRemarksHosts);
+ List<HostName> actualAllowedToBeDownHosts = applicationApi.getNodesInGroupWithStatus(HostStatus.ALLOWED_TO_BE_DOWN);
+ assertEquals(allowedToBeDownHostNames, actualAllowedToBeDownHosts);
+ }
+
+ @Test
+ public void testGetStorageNodesAllowedToBeDownInGroupInReverseClusterOrder() {
+ HostName allowedToBeDownHost1 = modelUtils.createNode("host1", HostStatus.ALLOWED_TO_BE_DOWN);
+ HostName noRemarksHost2 = modelUtils.createNode("host2", HostStatus.NO_REMARKS);
+ HostName allowedToBeDownHost3 = modelUtils.createNode("host3", HostStatus.ALLOWED_TO_BE_DOWN);
+ HostName allowedToBeDownHost4 = modelUtils.createNode("host4", HostStatus.ALLOWED_TO_BE_DOWN);
+ HostName noRemarksHost5 = modelUtils.createNode("host5", HostStatus.ALLOWED_TO_BE_DOWN);
+ HostName noRemarksHost6 = modelUtils.createNode("host6", HostStatus.NO_REMARKS);
+ HostName allowedToBeDownHost7 = modelUtils.createNode("host7", HostStatus.ALLOWED_TO_BE_DOWN);
+
+ ApplicationInstance<ServiceMonitorStatus> applicationInstance =
+ modelUtils.createApplicationInstance(Arrays.asList(
+ modelUtils.createServiceCluster(
+ "cluster-4",
+ VespaModelUtil.STORAGENODE_SERVICE_TYPE,
+ Arrays.asList(
+ modelUtils.createServiceInstance("config-id-40", allowedToBeDownHost1, ServiceMonitorStatus.UP),
+ modelUtils.createServiceInstance("config-id-41", noRemarksHost2, ServiceMonitorStatus.DOWN)
+ )
+ ),
+ modelUtils.createServiceCluster(
+ "cluster-1",
+ new ServiceType("service-type-1"),
+ Arrays.asList(
+ modelUtils.createServiceInstance("config-id-10", allowedToBeDownHost1, ServiceMonitorStatus.UP),
+ modelUtils.createServiceInstance("config-id-11", allowedToBeDownHost3, ServiceMonitorStatus.UP)
+ )
+ ),
+ modelUtils.createServiceCluster(
+ "cluster-3",
+ VespaModelUtil.STORAGENODE_SERVICE_TYPE,
+ Arrays.asList(
+ modelUtils.createServiceInstance("config-id-30", allowedToBeDownHost4, ServiceMonitorStatus.UP),
+ modelUtils.createServiceInstance("config-id-31", noRemarksHost5, ServiceMonitorStatus.UP)
+ )
+ ),
+ modelUtils.createServiceCluster(
+ "cluster-2",
+ VespaModelUtil.STORAGENODE_SERVICE_TYPE,
+ Arrays.asList(
+ modelUtils.createServiceInstance("config-id-20", noRemarksHost6, ServiceMonitorStatus.UP),
+ modelUtils.createServiceInstance("config-id-21", allowedToBeDownHost7, ServiceMonitorStatus.UP)
+ )
+ )
+ ));
+
+ verifyStorageNodesAllowedToBeDown(
+ modelUtils.createApplicationApiImpl(applicationInstance, allowedToBeDownHost1), allowedToBeDownHost1);
+ verifyStorageNodesAllowedToBeDown(
+ modelUtils.createApplicationApiImpl(applicationInstance, noRemarksHost2));
+ verifyStorageNodesAllowedToBeDown(
+ modelUtils.createApplicationApiImpl(applicationInstance, allowedToBeDownHost3));
+
+ verifyStorageNodesAllowedToBeDown(
+ modelUtils.createApplicationApiImpl(applicationInstance, allowedToBeDownHost1, noRemarksHost6), allowedToBeDownHost1);
+
+ // allowedToBeDownHost4 is in cluster-3, while allowedToBeDownHost1 is in cluster-4, so allowedToBeDownHost4 should be ordered
+ // before allowedToBeDownHost1.
+ verifyStorageNodesAllowedToBeDown(
+ modelUtils.createApplicationApiImpl(applicationInstance, allowedToBeDownHost1, noRemarksHost6, allowedToBeDownHost4),
+ allowedToBeDownHost4, allowedToBeDownHost1);
+
+ verifyStorageNodesAllowedToBeDown(
+ modelUtils.createApplicationApiImpl(applicationInstance, allowedToBeDownHost1, allowedToBeDownHost4, allowedToBeDownHost7),
+ allowedToBeDownHost7, allowedToBeDownHost4, allowedToBeDownHost1);
+
+ verifyStorageNodesAllowedToBeDown(
+ modelUtils.createApplicationApiImpl(applicationInstance, allowedToBeDownHost4, allowedToBeDownHost1, allowedToBeDownHost7),
+ allowedToBeDownHost7, allowedToBeDownHost4, allowedToBeDownHost1);
+ }
+
+ private void verifyStorageNodesAllowedToBeDown(
+ ApplicationApi applicationApi, HostName... hostNames) {
+ List<HostName> actualStorageNodes =
+ applicationApi.getStorageNodesAllowedToBeDownInGroupInReverseClusterOrder().stream()
+ .map(storageNode -> storageNode.hostName())
+ .collect(Collectors.toList());
+ assertEquals(Arrays.asList(hostNames), actualStorageNodes);
+ }
+}
diff --git a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/ClusterApiImplTest.java b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/ClusterApiImplTest.java
new file mode 100644
index 00000000000..082002b7cf2
--- /dev/null
+++ b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/ClusterApiImplTest.java
@@ -0,0 +1,133 @@
+package com.yahoo.vespa.orchestrator.model;
+
+import com.yahoo.vespa.applicationmodel.HostName;
+import com.yahoo.vespa.applicationmodel.ServiceCluster;
+import com.yahoo.vespa.applicationmodel.ServiceType;
+import com.yahoo.vespa.orchestrator.status.HostStatus;
+import com.yahoo.vespa.service.monitor.ServiceMonitorStatus;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Optional;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class ClusterApiImplTest {
+ final ModelTestUtils modelUtils = new ModelTestUtils();
+
+ @Test
+ public void testServicesDownAndNotInGroup() {
+ HostName hostName1 = modelUtils.createNode("host1", HostStatus.NO_REMARKS);
+ HostName hostName2 = modelUtils.createNode("host2", HostStatus.NO_REMARKS);
+ HostName hostName3 = modelUtils.createNode("host3", HostStatus.ALLOWED_TO_BE_DOWN);
+ HostName hostName4 = modelUtils.createNode("host4", HostStatus.ALLOWED_TO_BE_DOWN);
+ HostName hostName5 = modelUtils.createNode("host5", HostStatus.NO_REMARKS);
+
+
+ ServiceCluster<ServiceMonitorStatus> serviceCluster = modelUtils.createServiceCluster(
+ "cluster",
+ new ServiceType("service-type"),
+ Arrays.asList(
+ modelUtils.createServiceInstance("service-1", hostName1, ServiceMonitorStatus.UP),
+ modelUtils.createServiceInstance("service-2", hostName2, ServiceMonitorStatus.DOWN),
+ modelUtils.createServiceInstance("service-3", hostName3, ServiceMonitorStatus.UP),
+ modelUtils.createServiceInstance("service-4", hostName4, ServiceMonitorStatus.DOWN),
+ modelUtils.createServiceInstance("service-5", hostName5, ServiceMonitorStatus.UP)
+ )
+ );
+
+ ClusterApiImpl clusterApi = new ClusterApiImpl(
+ serviceCluster,
+ new NodeGroup(modelUtils.createApplicationInstance(new ArrayList<>()), hostName5),
+ modelUtils.getHostStatusMap(),
+ modelUtils.getClusterControllerClientFactory());
+
+ assertEquals("{ clusterId=cluster, serviceType=service-type }", clusterApi.clusterInfo());
+ assertFalse(clusterApi.isStorageCluster());
+ assertEquals("[ServiceInstance{configId=service-2, hostName=host2, serviceStatus=DOWN}, "
+ + "ServiceInstance{configId=service-3, hostName=host3, serviceStatus=UP}, "
+ + "ServiceInstance{configId=service-4, hostName=host4, serviceStatus=DOWN}]",
+ clusterApi.servicesDownAndNotInGroupDescription());
+ assertEquals("[host3, host4]",
+ clusterApi.nodesAllowedToBeDownNotInGroupDescription());
+ assertEquals(60, clusterApi.percentageOfServicesDown());
+ assertEquals(80, clusterApi.percentageOfServicesDownIfGroupIsAllowedToBeDown());
+ }
+
+ @Test
+ public void testNoServices() {
+ HostName hostName1 = modelUtils.createNode("host1", HostStatus.NO_REMARKS);
+ HostName hostName2 = modelUtils.createNode("host2", HostStatus.NO_REMARKS);
+ HostName hostName3 = modelUtils.createNode("host3", HostStatus.ALLOWED_TO_BE_DOWN);
+ HostName hostName4 = modelUtils.createNode("host4", HostStatus.ALLOWED_TO_BE_DOWN);
+ HostName hostName5 = modelUtils.createNode("host5", HostStatus.NO_REMARKS);
+
+
+ ServiceCluster<ServiceMonitorStatus> serviceCluster = modelUtils.createServiceCluster(
+ "cluster",
+ new ServiceType("service-type"),
+ Arrays.asList(
+ modelUtils.createServiceInstance("service-1", hostName1, ServiceMonitorStatus.UP),
+ modelUtils.createServiceInstance("service-2", hostName2, ServiceMonitorStatus.DOWN),
+ modelUtils.createServiceInstance("service-3", hostName3, ServiceMonitorStatus.UP),
+ modelUtils.createServiceInstance("service-4", hostName4, ServiceMonitorStatus.DOWN),
+ modelUtils.createServiceInstance("service-5", hostName5, ServiceMonitorStatus.UP)
+ )
+ );
+
+ verifyNoServices(serviceCluster, false, false, hostName1);
+ verifyNoServices(serviceCluster, true, false, hostName2);
+ verifyNoServices(serviceCluster, true, false, hostName3);
+ verifyNoServices(serviceCluster, true, false, hostName4);
+ verifyNoServices(serviceCluster, false, false, hostName5);
+
+ verifyNoServices(serviceCluster, false, false, hostName1, hostName2);
+ verifyNoServices(serviceCluster, true, false, hostName2, hostName3);
+ verifyNoServices(serviceCluster, true, true, hostName2, hostName3, hostName4);
+ verifyNoServices(serviceCluster, false, true, hostName1, hostName2, hostName3, hostName4);
+ }
+
+ private void verifyNoServices(ServiceCluster<ServiceMonitorStatus> serviceCluster,
+ boolean expectedNoServicesInGroupIsUp,
+ boolean expectedNoServicesOutsideGroupIsDown,
+ HostName... groupNodes) {
+ ClusterApiImpl clusterApi = new ClusterApiImpl(
+ serviceCluster,
+ new NodeGroup(modelUtils.createApplicationInstance(new ArrayList<>()), groupNodes),
+ modelUtils.getHostStatusMap(),
+ modelUtils.getClusterControllerClientFactory());
+
+ assertEquals(expectedNoServicesInGroupIsUp, clusterApi.noServicesInGroupIsUp());
+ assertEquals(expectedNoServicesOutsideGroupIsDown, clusterApi.noServicesOutsideGroupIsDown());
+ }
+
+ @Test
+ public void testStorageCluster() {
+ HostName hostName1 = new HostName("host1");
+ HostName hostName2 = new HostName("host2");
+ HostName hostName3 = new HostName("host3");
+
+ ServiceCluster<ServiceMonitorStatus> serviceCluster = modelUtils.createServiceCluster(
+ "cluster",
+ VespaModelUtil.STORAGENODE_SERVICE_TYPE,
+ Arrays.asList(
+ modelUtils.createServiceInstance("storage-1", hostName1, ServiceMonitorStatus.UP),
+ modelUtils.createServiceInstance("storage-2", hostName2, ServiceMonitorStatus.DOWN)
+ )
+ );
+
+ ClusterApiImpl clusterApi = new ClusterApiImpl(
+ serviceCluster,
+ new NodeGroup(modelUtils.createApplicationInstance(new ArrayList<>()), hostName1, hostName3),
+ new HashMap<>(),
+ modelUtils.getClusterControllerClientFactory());
+
+ assertTrue(clusterApi.isStorageCluster());
+ assertEquals(Optional.of(hostName1), clusterApi.storageNodeInGroup().map(storageNode -> storageNode.hostName()));
+ assertEquals(Optional.of(hostName1), clusterApi.upStorageNodeInGroup().map(storageNode -> storageNode.hostName()));
+ }
+} \ No newline at end of file
diff --git a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/ModelTestUtils.java b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/ModelTestUtils.java
new file mode 100644
index 00000000000..03eb0184a88
--- /dev/null
+++ b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/ModelTestUtils.java
@@ -0,0 +1,92 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.orchestrator.model;
+
+import com.yahoo.vespa.applicationmodel.ApplicationInstance;
+import com.yahoo.vespa.applicationmodel.ApplicationInstanceId;
+import com.yahoo.vespa.applicationmodel.ClusterId;
+import com.yahoo.vespa.applicationmodel.ConfigId;
+import com.yahoo.vespa.applicationmodel.HostName;
+import com.yahoo.vespa.applicationmodel.ServiceCluster;
+import com.yahoo.vespa.applicationmodel.ServiceInstance;
+import com.yahoo.vespa.applicationmodel.ServiceType;
+import com.yahoo.vespa.applicationmodel.TenantId;
+import com.yahoo.vespa.orchestrator.controller.ClusterControllerClientFactory;
+import com.yahoo.vespa.orchestrator.status.HostStatus;
+import com.yahoo.vespa.orchestrator.status.MutableStatusRegistry;
+import com.yahoo.vespa.service.monitor.ServiceMonitorStatus;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ModelTestUtils {
+ private final MutableStatusRegistry statusRegistry = mock(MutableStatusRegistry.class);
+ private final ClusterControllerClientFactory clusterControllerClientFactory = mock(ClusterControllerClientFactory.class);
+ private final Map<HostName, HostStatus> hostStatusMap = new HashMap<>();
+
+ ModelTestUtils() {
+ when(statusRegistry.getHostStatus(any())).thenReturn(HostStatus.NO_REMARKS);
+ }
+
+ Map<HostName, HostStatus> getHostStatusMap() {
+ return hostStatusMap;
+ }
+
+ HostName createNode(String name, HostStatus hostStatus) {
+ HostName hostName = new HostName(name);
+ hostStatusMap.put(hostName, hostStatus);
+ when(statusRegistry.getHostStatus(hostName)).thenReturn(hostStatus);
+ return hostName;
+ }
+
+ ApplicationApiImpl createApplicationApiImpl(
+ ApplicationInstance<ServiceMonitorStatus> applicationInstance,
+ HostName... hostnames) {
+ NodeGroup nodeGroup = new NodeGroup(applicationInstance, hostnames);
+ return new ApplicationApiImpl(nodeGroup, statusRegistry, clusterControllerClientFactory);
+ }
+
+ ApplicationInstance<ServiceMonitorStatus> createApplicationInstance(
+ List<ServiceCluster<ServiceMonitorStatus>> serviceClusters) {
+ Set<ServiceCluster<ServiceMonitorStatus>> serviceClusterSet = serviceClusters.stream()
+ .collect(Collectors.toSet());
+
+ return new ApplicationInstance<>(
+ new TenantId("tenant"),
+ new ApplicationInstanceId("application-name:foo:bar:default"),
+ serviceClusterSet);
+ }
+
+ ServiceCluster<ServiceMonitorStatus> createServiceCluster(
+ String clusterId,
+ ServiceType serviceType,
+ List<ServiceInstance<ServiceMonitorStatus>> serviceInstances) {
+ Set<ServiceInstance<ServiceMonitorStatus>> serviceInstanceSet = serviceInstances.stream()
+ .collect(Collectors.toSet());
+
+ return new ServiceCluster<>(
+ new ClusterId(clusterId),
+ serviceType,
+ serviceInstanceSet);
+ }
+
+ ServiceInstance<ServiceMonitorStatus> createServiceInstance(
+ String configId,
+ HostName hostName,
+ ServiceMonitorStatus status) {
+ return new ServiceInstance<>(
+ new ConfigId(configId),
+ hostName,
+ status);
+ }
+
+ public ClusterControllerClientFactory getClusterControllerClientFactory() {
+ return clusterControllerClientFactory;
+ }
+}
diff --git a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/NodeGroupTest.java b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/NodeGroupTest.java
new file mode 100644
index 00000000000..56a9e6bf147
--- /dev/null
+++ b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/NodeGroupTest.java
@@ -0,0 +1,33 @@
+package com.yahoo.vespa.orchestrator.model;
+
+import com.yahoo.vespa.applicationmodel.ApplicationInstance;
+import com.yahoo.vespa.applicationmodel.ApplicationInstanceId;
+import com.yahoo.vespa.applicationmodel.HostName;
+import com.yahoo.vespa.applicationmodel.TenantId;
+import com.yahoo.vespa.service.monitor.ServiceMonitorStatus;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.HashSet;
+
+import static org.junit.Assert.assertEquals;
+
+public class NodeGroupTest {
+ @Test
+ public void testBasics() {
+ ApplicationInstance<ServiceMonitorStatus> applicationInstance = new ApplicationInstance<>(
+ new TenantId("tenant"),
+ new ApplicationInstanceId("application-instance"),
+ new HashSet<>());
+
+ HostName hostName1 = new HostName("host1");
+ HostName hostName2 = new HostName("host2");
+ HostName hostName3 = new HostName("host3");
+ NodeGroup nodeGroup = new NodeGroup(applicationInstance, hostName1, hostName3);
+ nodeGroup.addNode(hostName2);
+
+ // hostnames are sorted (for no good reason other than testability due to stability, readability)
+ assertEquals(Arrays.asList(hostName1, hostName2, hostName3), nodeGroup.getHostNames());
+ assertEquals("host1,host2,host3", nodeGroup.toCommaSeparatedString());
+ }
+} \ No newline at end of file
diff --git a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/VespaModelUtilTest.java b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/VespaModelUtilTest.java
index c39410e9ca6..f2c17299d39 100644
--- a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/VespaModelUtilTest.java
+++ b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/VespaModelUtilTest.java
@@ -1,5 +1,5 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.orchestrator;
+package com.yahoo.vespa.orchestrator.model;
import com.yahoo.vespa.applicationmodel.ApplicationInstance;
import com.yahoo.vespa.applicationmodel.ApplicationInstanceId;
@@ -10,14 +10,15 @@ import com.yahoo.vespa.applicationmodel.ServiceCluster;
import com.yahoo.vespa.applicationmodel.ServiceInstance;
import com.yahoo.vespa.applicationmodel.ServiceType;
import com.yahoo.vespa.applicationmodel.TenantId;
+import com.yahoo.vespa.orchestrator.TestUtil;
import com.yahoo.vespa.service.monitor.ServiceMonitorStatus;
import org.junit.Test;
+import java.util.Arrays;
import java.util.HashSet;
+import java.util.List;
import java.util.Optional;
-import java.util.Set;
-import com.google.common.collect.ImmutableSet;
import static com.yahoo.vespa.orchestrator.TestUtil.makeServiceClusterSet;
import static com.yahoo.vespa.orchestrator.TestUtil.makeServiceInstanceSet;
import static junit.framework.TestCase.assertFalse;
@@ -169,9 +170,8 @@ public class VespaModelUtilTest {
@Test
public void testGettingClusterControllerInstances() {
- Set<ServiceInstance<?>> controllers =
- new HashSet<>(VespaModelUtil.getClusterControllerInstances(application, CONTENT_CLUSTER_ID));
- Set<ServiceInstance<ServiceMonitorStatus>> expectedControllers = ImmutableSet.of(controller0, controller1);
+ List<HostName> controllers = VespaModelUtil.getClusterControllerInstancesInOrder(application, CONTENT_CLUSTER_ID);
+ List<HostName> expectedControllers = Arrays.asList(controller0.hostName(), controller1.hostName());
assertThat(controllers).isEqualTo(expectedControllers);
}
diff --git a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/policy/HostedVespaPolicyTest.java b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/policy/HostedVespaPolicyTest.java
index 45d605b6d8a..09471f9d6ae 100644
--- a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/policy/HostedVespaPolicyTest.java
+++ b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/policy/HostedVespaPolicyTest.java
@@ -12,19 +12,21 @@ import com.yahoo.vespa.applicationmodel.ServiceInstance;
import com.yahoo.vespa.applicationmodel.ServiceType;
import com.yahoo.vespa.applicationmodel.TenantId;
import com.yahoo.vespa.orchestrator.TestUtil;
-import com.yahoo.vespa.orchestrator.VespaModelUtil;
import com.yahoo.vespa.orchestrator.controller.ClusterControllerClient;
import com.yahoo.vespa.orchestrator.controller.ClusterControllerClientFactory;
import com.yahoo.vespa.orchestrator.controller.ClusterControllerState;
import com.yahoo.vespa.orchestrator.controller.ClusterControllerStateResponse;
+import com.yahoo.vespa.orchestrator.model.VespaModelUtil;
import com.yahoo.vespa.orchestrator.status.HostStatus;
import com.yahoo.vespa.orchestrator.status.MutableStatusRegistry;
import com.yahoo.vespa.service.monitor.ServiceMonitorStatus;
import org.junit.Test;
import java.util.HashSet;
+import java.util.List;
import java.util.Optional;
import java.util.Set;
+import java.util.stream.Collectors;
import static com.yahoo.vespa.orchestrator.TestUtil.makeServiceClusterSet;
import static com.yahoo.vespa.orchestrator.TestUtil.makeServiceInstanceSet;
@@ -417,10 +419,12 @@ public class HostedVespaPolicyTest {
// Verification phase.
if (expectedNodeStateSentToClusterController.isPresent()) {
+ List<HostName> clusterControllers = CLUSTER_CONTROLLER_SERVICE_CLUSTER.serviceInstances().stream()
+ .map(service -> service.hostName())
+ .collect(Collectors.toList());
+
verify(clusterControllerClientFactory, times(1))
- .createClient(
- CLUSTER_CONTROLLER_SERVICE_CLUSTER.serviceInstances(),
- CONTENT_CLUSTER_NAME);
+ .createClient(clusterControllers, CONTENT_CLUSTER_NAME);
verify(client, times(1))
.setNodeState(
STORAGE_NODE_INDEX,