diff options
author | Martin Polden <mpolden@mpolden.no> | 2017-11-29 14:00:12 +0100 |
---|---|---|
committer | Martin Polden <mpolden@mpolden.no> | 2017-11-29 15:31:25 +0100 |
commit | 5c0c4397759b944b5dcd2b8c645ba898f4567746 (patch) | |
tree | db52ce2090d5676bec6a90bfe775458acb06ace4 /controller-server/src/test | |
parent | 3d3c9227385b428cb3d2041103b5ec11dd615bd0 (diff) |
Move rotation to application
Diffstat (limited to 'controller-server/src/test')
11 files changed, 291 insertions, 283 deletions
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java index d0c1fd95427..b0fb820ca4c 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java @@ -11,9 +11,7 @@ import com.yahoo.config.provision.RegionName; import com.yahoo.config.provision.SystemName; import com.yahoo.config.provision.TenantName; import com.yahoo.config.provision.Zone; -import com.yahoo.slime.Slime; import com.yahoo.vespa.config.SlimeUtils; -import com.yahoo.vespa.curator.Lock; import com.yahoo.vespa.hosted.controller.api.Tenant; import com.yahoo.vespa.hosted.controller.api.application.v4.model.DeployOptions; import com.yahoo.vespa.hosted.controller.api.application.v4.model.EndpointStatus; @@ -601,6 +599,7 @@ public class ControllerTest { ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) + .globalServiceId("foo") .region("us-west-1") .region("us-central-1") // Two deployments should result in DNS alias being registered once .build(); @@ -610,7 +609,7 @@ public class ControllerTest { Optional<Record> record = tester.controllerTester().nameService().findRecord(Record.Type.CNAME, "app1.tenant1.global.vespa.yahooapis.com"); assertTrue(record.isPresent()); assertEquals("app1.tenant1.global.vespa.yahooapis.com", record.get().name()); - assertEquals("fake-global-rotation-tenant1.app1", record.get().value()); + assertEquals("rotation-fqdn-01", record.get().value()); } @Test diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java index 8f9c22f8b81..f202deafa8a 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java @@ -41,7 +41,7 @@ import com.yahoo.vespa.hosted.controller.persistence.MemoryControllerDb; import com.yahoo.vespa.hosted.controller.persistence.MockCuratorDb; import com.yahoo.vespa.hosted.controller.routing.MockRoutingGenerator; import com.yahoo.vespa.hosted.controller.versions.VersionStatus; -import com.yahoo.vespa.hosted.rotation.MemoryRotationRepository; +import com.yahoo.vespa.hosted.rotation.config.RotationsConfig; import java.util.Optional; @@ -63,22 +63,31 @@ public final class ControllerTester { private final GitHubMock gitHub; private final CuratorDb curator; private final MemoryNameService nameService; + private final RotationsConfig rotationsConfig; private Controller controller; public ControllerTester() { this(new MemoryControllerDb(), new AthenzDbMock(), new ManualClock(), new ConfigServerClientMock(), - new ZoneRegistryMock(), new GitHubMock(), new MockCuratorDb(), new MemoryNameService()); + new ZoneRegistryMock(), new GitHubMock(), new MockCuratorDb(), defaultRotationsConfig(), + new MemoryNameService()); } public ControllerTester(ManualClock clock) { this(new MemoryControllerDb(), new AthenzDbMock(), clock, new ConfigServerClientMock(), - new ZoneRegistryMock(), new GitHubMock(), new MockCuratorDb(), new MemoryNameService()); + new ZoneRegistryMock(), new GitHubMock(), new MockCuratorDb(), defaultRotationsConfig(), + new MemoryNameService()); + } + + public ControllerTester(RotationsConfig rotationsConfig) { + this(new MemoryControllerDb(), new AthenzDbMock(), new ManualClock(), new ConfigServerClientMock(), + new ZoneRegistryMock(), new GitHubMock(), new MockCuratorDb(), rotationsConfig, new MemoryNameService()); } private ControllerTester(ControllerDb db, AthenzDbMock athenzDb, ManualClock clock, ConfigServerClientMock configServer, ZoneRegistryMock zoneRegistry, - GitHubMock gitHub, CuratorDb curator, MemoryNameService nameService) { + GitHubMock gitHub, CuratorDb curator, RotationsConfig rotationsConfig, + MemoryNameService nameService) { this.db = db; this.athenzDb = athenzDb; this.clock = clock; @@ -87,7 +96,8 @@ public final class ControllerTester { this.gitHub = gitHub; this.curator = curator; this.nameService = nameService; - this.controller = createController(db, curator, configServer, clock, gitHub, zoneRegistry, + this.rotationsConfig = rotationsConfig; + this.controller = createController(db, curator, rotationsConfig, configServer, clock, gitHub, zoneRegistry, athenzDb, nameService); } @@ -109,7 +119,8 @@ public final class ControllerTester { /** Create a new controller instance. Useful to verify that controller state is rebuilt from persistence */ public final void createNewController() { - controller = createController(db, curator, configServer, clock, gitHub, zoneRegistry, athenzDb, nameService); + controller = createController(db, curator, rotationsConfig, configServer, clock, gitHub, zoneRegistry, athenzDb, + nameService); } /** Creates the given tenant and application and deploys it */ @@ -214,13 +225,13 @@ public final class ControllerTester { return new LockedApplication(application, new Lock("/test", new MockCurator())); } - private static Controller createController(ControllerDb db, CuratorDb curator, + private static Controller createController(ControllerDb db, CuratorDb curator, RotationsConfig rotationsConfig, ConfigServerClientMock configServerClientMock, ManualClock clock, GitHubMock gitHubClientMock, ZoneRegistryMock zoneRegistryMock, AthenzDbMock athensDb, MemoryNameService nameService) { Controller controller = new Controller(db, curator, - new MemoryRotationRepository(), + rotationsConfig, gitHubClientMock, new MemoryEntityService(), new MockOrganization(clock), @@ -237,4 +248,13 @@ public final class ControllerTester { return controller; } + private static RotationsConfig defaultRotationsConfig() { + RotationsConfig.Builder builder = new RotationsConfig.Builder(); + for (int i = 1; i <= 10; i++) { + String id = String.format("%02d", i); + builder = builder.rotations("rotation-id-" + id, "rotation-fqdn-" + id); + } + return new RotationsConfig(builder); + } + } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java index 72bfa238094..96b096ccdd8 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java @@ -26,6 +26,7 @@ public class ApplicationPackageBuilder { private String upgradePolicy = null; private Environment environment = Environment.prod; + private String globalServiceId = null; private final StringBuilder environmentBody = new StringBuilder(); private final StringBuilder validationOverridesBody = new StringBuilder(); private final StringBuilder blockChange = new StringBuilder(); @@ -41,6 +42,11 @@ public class ApplicationPackageBuilder { return this; } + public ApplicationPackageBuilder globalServiceId(String globalServiceId) { + this.globalServiceId = globalServiceId; + return this; + } + public ApplicationPackageBuilder region(String regionName) { environmentBody.append(" <region active='true'>"); environmentBody.append(regionName); @@ -99,6 +105,11 @@ public class ApplicationPackageBuilder { xml.append(blockChange); xml.append(" <"); xml.append(environment.value()); + if (globalServiceId != null) { + xml.append(" global-service-id='"); + xml.append(globalServiceId); + xml.append("'"); + } xml.append(">\n"); xml.append(environmentBody); xml.append(" </"); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java index 2c1471b29b6..bf869230e8d 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java @@ -25,6 +25,7 @@ import com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobError; import com.yahoo.vespa.hosted.controller.application.DeploymentMetrics; import com.yahoo.vespa.hosted.controller.application.JobStatus; import com.yahoo.vespa.hosted.controller.application.SourceRevision; +import com.yahoo.vespa.hosted.controller.rotation.RotationId; import org.junit.Test; import java.io.IOException; @@ -86,7 +87,8 @@ public class ApplicationSerializerTest { Optional.of(new Change.VersionChange(Version.fromString("6.7"))), true, Optional.of(IssueId.from("1234")), - new MetricsService.ApplicationMetrics(0.5, 0.9)); + new MetricsService.ApplicationMetrics(0.5, 0.9), + Optional.of(new RotationId("my-rotation"))); Application serialized = applicationSerializer.fromSlime(applicationSerializer.toSlime(original)); @@ -115,6 +117,7 @@ public class ApplicationSerializerTest { assertEquals(original.ownershipIssueId(), serialized.ownershipIssueId()); assertEquals(original.deploying(), serialized.deploying()); + assertEquals(original.rotation().get().id(), serialized.rotation().get().id()); // Test cluster utilization assertEquals(0, serialized.deployments().get(zone1).clusterUtils().size()); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java index 044c5d75d12..631ceab98a5 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java @@ -25,60 +25,70 @@ import static org.junit.Assert.assertEquals; public class ControllerContainerTest { protected JDisc container; + @Before public void startContainer() { container = JDisc.fromServicesXml(controllerServicesXml, Networking.disable); } + @After public void stopContainer() { container.close(); } private final String controllerServicesXml = - "<jdisc version='1.0'>" + - " <config name='vespa.hosted.zone.config.zone'>" + - " <system>main</system>" + - " </config>" + - " <component id='com.yahoo.vespa.hosted.controller.persistence.MockCuratorDb'/>" + - " <component id='com.yahoo.vespa.hosted.controller.athenz.mock.AthenzClientFactoryMock'/>" + - " <component id='com.yahoo.vespa.hosted.controller.api.integration.chef.ChefMock'/>" + - " <component id='com.yahoo.vespa.hosted.controller.api.integration.dns.MemoryNameService'/>" + - " <component id='com.yahoo.vespa.hosted.controller.api.integration.entity.MemoryEntityService'/>" + - " <component id='com.yahoo.vespa.hosted.controller.api.integration.github.GitHubMock'/>" + - " <component id='com.yahoo.vespa.hosted.controller.api.integration.routing.MemoryGlobalRoutingService'/>" + - " <component id='com.yahoo.vespa.hosted.controller.api.integration.stubs.LoggingDeploymentIssues'/>" + - " <component id='com.yahoo.vespa.hosted.controller.api.integration.stubs.DummyOwnershipIssues'/>" + - " <component id='com.yahoo.vespa.hosted.controller.api.integration.organization.MockOrganization'/>" + - " <component id='com.yahoo.vespa.hosted.controller.ConfigServerClientMock'/>" + - " <component id='com.yahoo.vespa.hosted.controller.ZoneRegistryMock'/>" + - " <component id='com.yahoo.vespa.hosted.controller.Controller'/>" + - " <component id='com.yahoo.vespa.hosted.controller.ConfigServerProxyMock'/>" + - " <component id='com.yahoo.vespa.hosted.controller.integration.MockMetricsService'/>" + - " <component id='com.yahoo.vespa.hosted.controller.maintenance.ControllerMaintenance'/>" + - " <component id='com.yahoo.vespa.hosted.controller.maintenance.JobControl'/>" + - " <component id='com.yahoo.vespa.hosted.controller.persistence.MemoryControllerDb'/>" + - " <component id='com.yahoo.vespa.hosted.controller.restapi.application.MockAuthorizer'/>" + - " <component id='com.yahoo.vespa.hosted.controller.routing.MockRoutingGenerator'/>" + - " <component id='com.yahoo.vespa.hosted.rotation.MemoryRotationRepository'/>" + - " <handler id='com.yahoo.vespa.hosted.controller.restapi.RootHandler'>" + - " <binding>http://*/</binding>" + - " </handler>" + - " <handler id='com.yahoo.vespa.hosted.controller.restapi.application.ApplicationApiHandler'>" + - " <binding>http://*/application/v4/*</binding>" + - " </handler>" + - " <handler id='com.yahoo.vespa.hosted.controller.restapi.deployment.DeploymentApiHandler'>" + - " <binding>http://*/deployment/v1/*</binding>" + - " </handler>" + - " <handler id='com.yahoo.vespa.hosted.controller.restapi.controller.ControllerApiHandler'>" + - " <binding>http://*/controller/v1/*</binding>" + - " </handler>" + - " <handler id='com.yahoo.vespa.hosted.controller.restapi.screwdriver.ScrewdriverApiHandler'>" + - " <binding>http://*/screwdriver/v1/*</binding>" + - " </handler>" + - " <handler id='com.yahoo.vespa.hosted.controller.restapi.zone.v1.ZoneApiHandler'>" + - " <binding>http://*/zone/v1</binding>" + - " <binding>http://*/zone/v1/*</binding>" + - " </handler>" + - " <handler id='com.yahoo.vespa.hosted.controller.restapi.zone.v2.ZoneApiHandler'>" + - " <binding>http://*/zone/v2</binding>" + - " <binding>http://*/zone/v2/*</binding>" + - " </handler>" + + "<jdisc version='1.0'>\n" + + " <config name='vespa.hosted.zone.config.zone'>\n" + + " <system>main</system>\n" + + " </config>\n" + + " <config name=\"vespa.hosted.rotation.config.rotations\">\n" + + " <rotations>\n" + + " <item key=\"rotation-id-1\">rotation-fqdn-1</item>\n" + + " <item key=\"rotation-id-2\">rotation-fqdn-2</item>\n" + + " <item key=\"rotation-id-3\">rotation-fqdn-3</item>\n" + + " <item key=\"rotation-id-4\">rotation-fqdn-4</item>\n" + + " <item key=\"rotation-id-5\">rotation-fqdn-5</item>\n" + + " </rotations>\n" + + " </config>\n" + + " <component id='com.yahoo.vespa.hosted.controller.persistence.MockCuratorDb'/>\n" + + " <component id='com.yahoo.vespa.hosted.controller.athenz.mock.AthenzClientFactoryMock'/>\n" + + " <component id='com.yahoo.vespa.hosted.controller.api.integration.chef.ChefMock'/>\n" + + " <component id='com.yahoo.vespa.hosted.controller.api.integration.dns.MemoryNameService'/>\n" + + " <component id='com.yahoo.vespa.hosted.controller.api.integration.entity.MemoryEntityService'/>\n" + + " <component id='com.yahoo.vespa.hosted.controller.api.integration.github.GitHubMock'/>\n" + + " <component id='com.yahoo.vespa.hosted.controller.api.integration.routing.MemoryGlobalRoutingService'/>\n" + + " <component id='com.yahoo.vespa.hosted.controller.api.integration.stubs.LoggingDeploymentIssues'/>\n" + + " <component id='com.yahoo.vespa.hosted.controller.api.integration.stubs.DummyOwnershipIssues'/>\n" + + " <component id='com.yahoo.vespa.hosted.controller.api.integration.organization.MockOrganization'/>\n" + + " <component id='com.yahoo.vespa.hosted.controller.ConfigServerClientMock'/>\n" + + " <component id='com.yahoo.vespa.hosted.controller.ZoneRegistryMock'/>\n" + + " <component id='com.yahoo.vespa.hosted.controller.Controller'/>\n" + + " <component id='com.yahoo.vespa.hosted.controller.ConfigServerProxyMock'/>\n" + + " <component id='com.yahoo.vespa.hosted.controller.integration.MockMetricsService'/>\n" + + " <component id='com.yahoo.vespa.hosted.controller.maintenance.ControllerMaintenance'/>\n" + + " <component id='com.yahoo.vespa.hosted.controller.maintenance.JobControl'/>\n" + + " <component id='com.yahoo.vespa.hosted.controller.persistence.MemoryControllerDb'/>\n" + + " <component id='com.yahoo.vespa.hosted.controller.restapi.application.MockAuthorizer'/>\n" + + " <component id='com.yahoo.vespa.hosted.controller.routing.MockRoutingGenerator'/>\n" + + " <handler id='com.yahoo.vespa.hosted.controller.restapi.RootHandler'>\n" + + " <binding>http://*/</binding>\n" + + " </handler>\n" + + " <handler id='com.yahoo.vespa.hosted.controller.restapi.application.ApplicationApiHandler'>\n" + + " <binding>http://*/application/v4/*</binding>\n" + + " </handler>\n" + + " <handler id='com.yahoo.vespa.hosted.controller.restapi.deployment.DeploymentApiHandler'>\n" + + " <binding>http://*/deployment/v1/*</binding>\n" + + " </handler>\n" + + " <handler id='com.yahoo.vespa.hosted.controller.restapi.controller.ControllerApiHandler'>\n" + + " <binding>http://*/controller/v1/*</binding>\n" + + " </handler>\n" + + " <handler id='com.yahoo.vespa.hosted.controller.restapi.screwdriver.ScrewdriverApiHandler'>\n" + + " <binding>http://*/screwdriver/v1/*</binding>\n" + + " </handler>\n" + + " <handler id='com.yahoo.vespa.hosted.controller.restapi.zone.v1.ZoneApiHandler'>\n" + + " <binding>http://*/zone/v1</binding>\n" + + " <binding>http://*/zone/v1/*</binding>\n" + + " </handler>\n" + + " <handler id='com.yahoo.vespa.hosted.controller.restapi.zone.v2.ZoneApiHandler'>\n" + + " <binding>http://*/zone/v2</binding>\n" + + " <binding>http://*/zone/v2/*</binding>\n" + + " </handler>\n" + "</jdisc>"; protected void assertResponse(Request request, int responseStatus, String responseMessage) throws IOException { diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java index bf4586f9fd0..3d73b5b110d 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java @@ -61,13 +61,18 @@ import static com.yahoo.application.container.handler.Request.Method.PUT; public class ApplicationApiTest extends ControllerContainerTest { private static final String responseFiles = "src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/"; + private static final ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) + .globalServiceId("foo") .region("corp-us-east-1") + .region("us-east-3") + .region("us-west-1") .build(); + private static final String athenzUserDomain = "domain1"; - private static final String athenzScrewdriverDomain = AthenzUtils.SCREWDRIVER_DOMAIN.id(); + private static final String athenzScrewdriverDomain = AthenzUtils.SCREWDRIVER_DOMAIN.id(); @Test public void testApplicationApi() throws Exception { @@ -260,13 +265,6 @@ public class ApplicationApiTest extends ControllerContainerTest { tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/prod/region/corp-us-east-1/instance/default", DELETE), "Deactivated tenant/tenant1/application/application1/environment/prod/region/corp-us-east-1/instance/default"); - // DELETE an application - tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1", DELETE), - ""); - // DELETE a tenant - tester.assertResponse(request("/application/v4/tenant/tenant1", DELETE), - new File("tenant-without-applications.json")); - // PUT (create) the authenticated user byte[] data = new byte[0]; tester.assertResponse(request("/application/v4/user?user=newuser&domain=by", PUT) @@ -300,6 +298,13 @@ public class ApplicationApiTest extends ControllerContainerTest { tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-west-1/instance/default/promote", POST), "{\"message\":\"Successfully copied environment hosted-instance_tenant1_application1_placeholder_component_default to hosted-instance_tenant1_application1_us-west-1_prod_default\"}"); + // DELETE an application + tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1", DELETE), + ""); + // DELETE a tenant + tester.assertResponse(request("/application/v4/tenant/tenant1", DELETE), + new File("tenant-without-applications.json")); + controllerTester.controller().deconstruct(); } @@ -373,6 +378,7 @@ public class ApplicationApiTest extends ControllerContainerTest { // New zone is added before us-east-3 applicationPackage = new ApplicationPackageBuilder() + .globalServiceId("foo") // These decides the ordering of deploymentJobs and instances in the response .region("us-west-1") .region("us-east-3") diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-without-change-multiple-deployments.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-without-change-multiple-deployments.json index 6442ddf5c02..961e005bfbd 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-without-change-multiple-deployments.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-without-change-multiple-deployments.json @@ -205,7 +205,7 @@ ], "compileVersion": "(ignore)", "globalRotations": [ - "http://fake-global-rotation-tenant1.application1" + "http://application1.tenant1.global.vespa.yahooapis.com:4080/" ], "instances": [ { diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application.json index fdd3dcc4d5c..3924cf51ca9 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application.json @@ -146,7 +146,7 @@ ], "compileVersion": "(ignore)", "globalRotations": [ - "http://fake-global-rotation-tenant1.application1" + "http://application1.tenant1.global.vespa.yahooapis.com:4080/" ], "instances": [ { diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application1-recursive.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application1-recursive.json index 41556c04209..5030fc7d0a6 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application1-recursive.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application1-recursive.json @@ -146,7 +146,7 @@ ], "compileVersion": "6.1.0", "globalRotations": [ - "http://fake-global-rotation-tenant1.application1" + "http://application1.tenant1.global.vespa.yahooapis.com:4080/" ], "instances": [ @include(dev-us-west-1.json), diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/rotation/RotationTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/rotation/RotationTest.java new file mode 100644 index 00000000000..8fc41b8daa6 --- /dev/null +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/rotation/RotationTest.java @@ -0,0 +1,171 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.rotation; + +import com.yahoo.vespa.hosted.controller.Application; +import com.yahoo.vespa.hosted.controller.ControllerTester; +import com.yahoo.vespa.hosted.controller.application.ApplicationRotation; +import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; +import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder; +import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; +import com.yahoo.vespa.hosted.rotation.config.RotationsConfig; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.net.URI; +import java.util.Optional; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +/** + * @author Oyvind Gronnesby + * @author mpolden + */ +public class RotationTest { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private final RotationsConfig rotationsConfig = new RotationsConfig( + new RotationsConfig.Builder() + .rotations("foo-1", "foo-1.com") + .rotations("foo-2", "foo-2.com") + ); + + private final RotationsConfig rotationsConfigWhitespaces = new RotationsConfig( + new RotationsConfig.Builder() + .rotations("foo-1", "\n foo-1.com \n") + .rotations("foo-2", "foo-2.com") + ); + + private final ApplicationPackage applicationPackage = new ApplicationPackageBuilder() + .globalServiceId("foo") + .region("us-east-3") + .region("us-west-1") + .build(); + + private DeploymentTester tester; + private RotationRepository repository; + private Application application; + + @Before + public void before() { + tester = new DeploymentTester(new ControllerTester(rotationsConfig)); + repository = tester.controller().applications().rotationRepository(); + application = tester.createApplication("app1", "tenant1", 11L,1L); + } + + @Test + public void assigns_and_reuses_rotation() { + // Deploying assigns a rotation + tester.deployCompletely(application, applicationPackage); + Rotation expected = new Rotation(new RotationId("foo-1"), "foo-1.com"); + + application = tester.applications().require(application.id()); + assertEquals(expected.id(), application.rotation().get().id()); + assertEquals(URI.create("http://app1.tenant1.global.vespa.yahooapis.com:4080/"), + application.rotation().get().url()); + Rotation rotation = repository.getRotation(tester.applications().require(application.id())); + assertEquals(expected, rotation); + + // Deploying once more assigns same rotation + ApplicationPackage applicationPackage = new ApplicationPackageBuilder() + .globalServiceId("foo") + .region("us-east-3") + .region("us-west-1") + .searchDefinition("search foo { }") // Update application package so there is something to deploy + .build(); + tester.deployCompletely(application, applicationPackage); + assertEquals(expected.id(), tester.applications().require(application.id()).rotation().get().id()); + } + + @Test + public void strips_whitespace_in_rotation_fqdn() { + DeploymentTester tester = new DeploymentTester(new ControllerTester(rotationsConfigWhitespaces)); + RotationRepository repository = tester.controller().applications().rotationRepository(); + Application application = tester.createApplication("app2", "tenant2", 22L, + 2L); + tester.deployCompletely(application, applicationPackage); + application = tester.applications().require(application.id()); + + Rotation rotation = repository.getRotation(application); + Rotation assignedRotation = new Rotation(new RotationId("foo-1"), "foo-1.com"); + assertEquals(assignedRotation, rotation); + } + + + @Test + public void out_of_rotations() { + // Assigns 1 rotation + tester.deployCompletely(application, applicationPackage); + + // Assigns 1 more + Application application2 = tester.createApplication("app2", "tenant2", 22L, + 2L); + tester.deployCompletely(application2, applicationPackage); + + // We're now out of rotations + thrown.expect(IllegalStateException.class); + thrown.expectMessage("no rotations available"); + Application application3 = tester.createApplication("app3", "tenant3", 33L, + 3L); + tester.deployCompletely(application3, applicationPackage); + } + + @Test + public void too_few_zones() { + ApplicationPackage applicationPackage = new ApplicationPackageBuilder() + .globalServiceId("foo") + .region("us-east-3") + .build(); + Application application = tester.createApplication("app2", "tenant2", 22L, + 2L); + thrown.expect(RuntimeException.class); + thrown.expectMessage("less than 2 prod zones are defined"); + tester.deployCompletely(application, applicationPackage); + } + + @Test + public void no_rotation_assigned_for_application_without_service_id() { + ApplicationPackage applicationPackage = new ApplicationPackageBuilder() + .region("us-east-3") + .region("us-west-1") + .build(); + tester.deployCompletely(application, applicationPackage); + Application app = tester.applications().require(application.id()); + Optional<ApplicationRotation> rotation = app.rotation(); + assertFalse(rotation.isPresent()); + } + + @Test + public void application_with_only_one_non_corp_region() { + ApplicationPackage applicationPackage = new ApplicationPackageBuilder() + .globalServiceId("foo") + .region("us-east-3") + .region("corp-us-east-1") + .build(); + Application application = tester.createApplication("app2", "tenant2", 22L, + 2L); + thrown.expect(RuntimeException.class); + thrown.expectMessage("less than 2 prod zones are defined"); + tester.deployCompletely(application, applicationPackage); + } + + @Test + public void application_with_corp_region_and_two_non_corp_region() { + ApplicationPackage applicationPackage = new ApplicationPackageBuilder() + .globalServiceId("foo") + .region("us-east-3") + .region("corp-us-east-1") + .region("us-west-1") + .build(); + Application application = tester.createApplication("app2", "tenant2", 22L, + 2L); + tester.deployCompletely(application, applicationPackage); + assertEquals(new RotationId("foo-1"), tester.applications().require(application.id()) + .rotation().get().id()); + } + +} diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/rotation/ControllerRotationRepositoryTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/rotation/ControllerRotationRepositoryTest.java deleted file mode 100644 index b4074fc1944..00000000000 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/rotation/ControllerRotationRepositoryTest.java +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.hosted.rotation; - -import com.yahoo.config.application.api.DeploymentSpec; -import com.yahoo.config.provision.ApplicationId; -import com.yahoo.jdisc.Metric; -import com.yahoo.vespa.hosted.controller.api.identifiers.RotationId; -import com.yahoo.vespa.hosted.controller.api.rotation.Rotation; -import com.yahoo.vespa.hosted.controller.persistence.ControllerDb; -import com.yahoo.vespa.hosted.controller.persistence.MemoryControllerDb; -import com.yahoo.vespa.hosted.rotation.config.RotationsConfig; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import java.io.StringReader; -import java.net.URI; -import java.util.Collection; -import java.util.Collections; -import java.util.Set; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -/** - * @author Oyvind Gronnesby - */ -public class ControllerRotationRepositoryTest { - - private final RotationsConfig rotationsConfig = new RotationsConfig( - new RotationsConfig.Builder() - .rotations("foo-1", "foo-1.com") - .rotations("foo-2", "foo-2.com") - ); - private final RotationsConfig rotationsConfigWhitespaces = new RotationsConfig( - new RotationsConfig.Builder() - .rotations("foo-1", "\n foo-1.com \n") - .rotations("foo-2", "foo-2.com") - ); - private final ControllerDb controllerDb = new MemoryControllerDb(); - private final ApplicationId applicationId = ApplicationId.from("msbe", "tumblr-search", "default"); - - @Rule public ExpectedException thrown = ExpectedException.none(); - - private final DeploymentSpec deploymentSpec = DeploymentSpec.fromXml( - new StringReader( - "<deployment>" + - " <prod global-service-id='foo'>" + - " <region active='true'>us-east</region>" + - " <region active='true'>us-west</region>" + - " </prod>" + - "</deployment>" - ) - ); - - private final DeploymentSpec deploymentSpecOneRegion = DeploymentSpec.fromXml( - new StringReader( - "<deployment>" + - " <prod global-service-id='nalle'>" + - " <region active='true'>us-east</region>" + - " </prod>" + - "</deployment>" - ) - ); - - private final DeploymentSpec deploymentSpecNoServiceId = DeploymentSpec.fromXml( - new StringReader( - "<deployment>" + - " <prod>" + - " <region active='true'>us-east</region>" + - " <region active='true'>us-west</region>" + - " </prod>" + - "</deployment>" - ) - ); - - private final DeploymentSpec deploymentSpecOnlyOneNonCorpRegion = DeploymentSpec.fromXml( - new StringReader( - "<deployment>" + - " <prod global-service-id='nalle'>" + - " <region active='true'>us-east</region>" + - " <region active='true'>corp-us-west</region>" + - " </prod>" + - "</deployment>" - ) - ); - - private final DeploymentSpec deploymentSpecWithAdditionalCorpZone = DeploymentSpec.fromXml( - new StringReader( - "<deployment>" + - " <prod global-service-id='nalle'>" + - " <region active='true'>us-east</region>" + - " <region active='true'>corp-us-west</region>" + - " <region active='true'>us-west</region>" + - " </prod>" + - "</deployment>" - ) - ); - - private ControllerRotationRepository repository; - private ControllerRotationRepository repositoryWhitespaces; - private Metric metric; - - @Before - public void setup_repository() { - metric = mock(Metric.class); - repository = new ControllerRotationRepository(rotationsConfig, controllerDb, metric); - repositoryWhitespaces = new ControllerRotationRepository(rotationsConfigWhitespaces, controllerDb, metric); - controllerDb.assignRotation(new RotationId("foo-1"), applicationId); - } - - @Test - public void application_with_rotation_reused() { - Set<Rotation> rotations = repository.getOrAssignRotation(applicationId, deploymentSpec); - Rotation assignedRotation = new Rotation(new RotationId("foo-1"), "foo-1.com"); - assertContainsOnly(assignedRotation, rotations); - } - - @Test - public void names_stripped() { - Set<Rotation> rotations = repositoryWhitespaces.getOrAssignRotation(applicationId, deploymentSpec); - Rotation assignedRotation = new Rotation(new RotationId("foo-1"), "foo-1.com"); - assertContainsOnly(assignedRotation, rotations); - } - - @Test - public void application_without_rotation() { - ApplicationId other = ApplicationId.from("othertenant", "otherapplication", "default"); - Set<Rotation> rotations = repository.getOrAssignRotation(other, deploymentSpec); - Rotation assignedRotation = new Rotation(new RotationId("foo-2"), "foo-2.com"); - assertContainsOnly(assignedRotation, rotations); - verify(metric).set(eq(ControllerRotationRepository.REMAINING_ROTATIONS_METRIC_NAME), eq(1), any()); - } - - @Test - public void application_without_rotation_but_none_left() { - application_without_rotation(); // run this test to assign last rotation - ApplicationId third = ApplicationId.from("thirdtenant", "thirdapplication", "default"); - - thrown.expect(RuntimeException.class); - thrown.expectMessage("no rotations available"); - - repository.getOrAssignRotation(third, deploymentSpec); - verify(metric).set(eq(ControllerRotationRepository.REMAINING_ROTATIONS_METRIC_NAME), eq(0), any()); - } - - @Test - public void application_without_rotation_but_does_not_qualify() { - ApplicationId other = ApplicationId.from("othertenant", "otherapplication", "default"); - - thrown.expect(RuntimeException.class); - thrown.expectMessage("less than 2 prod zones are defined"); - - repository.getOrAssignRotation(other, deploymentSpecOneRegion); - } - - @Test - public void application_with_rotation_but_does_not_qualify() { - Set<Rotation> rotations = repository.getOrAssignRotation(applicationId, deploymentSpecOneRegion); - Rotation assignedRotation = new Rotation(new RotationId("foo-1"), "foo-1.com"); - assertContainsOnly(assignedRotation, rotations); - } - - @Test - public void application_with_rotation_is_listed() { - repository.getOrAssignRotation(applicationId, deploymentSpec); - Set<URI> uris = repository.getRotationUris(applicationId); - assertEquals(Collections.singleton(URI.create("http://tumblr-search.msbe.global.vespa.yahooapis.com:4080/")), uris); - } - - @Test - public void application_without_rotation_is_empty() { - ApplicationId other = ApplicationId.from("othertenant", "otherapplication", "default"); - Set<URI> uris = repository.getRotationUris(other); - assertTrue(uris.isEmpty()); - } - - @Test - public void application_without_serviceid_and_two_regions() { - ApplicationId other = ApplicationId.from("othertenant", "otherapplication", "default"); - Set<Rotation> rotations = repository.getOrAssignRotation(other, deploymentSpecNoServiceId); - assertTrue(rotations.isEmpty()); - } - - @Test - public void application_with_only_one_non_corp_region() { - ApplicationId other = ApplicationId.from("othertenant", "otherapplication", "default"); - - thrown.expect(RuntimeException.class); - thrown.expectMessage("less than 2 prod zones are defined"); - - repository.getOrAssignRotation(other, deploymentSpecOnlyOneNonCorpRegion); - } - - @Test - public void application_with_corp_region_and_two_non_corp_region() { - ApplicationId other = ApplicationId.from("othertenant", "otherapplication", "default"); - Set<Rotation> rotations = repository.getOrAssignRotation(other, deploymentSpecWithAdditionalCorpZone); - assertContainsOnly(new Rotation(new RotationId("foo-2"), "foo-2.com"), rotations); - } - - private static <T> void assertContainsOnly(T item, Collection<T> items) { - assertTrue("Collection contains only " + item.toString(), - items.size() == 1 && items.contains(item)); - } - -} |