summaryrefslogtreecommitdiffstats
path: root/controller-server/src/test/java
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2018-01-18 10:42:25 +0100
committerMartin Polden <mpolden@mpolden.no>2018-01-25 11:06:04 +0100
commitb87cbc288ed5eb12d9a9c368c2f501523e4344ab (patch)
treea03b5b661de6152af3d497f3f629d4d01abd9143 /controller-server/src/test/java
parente0d9ae612ee405eb3e83ca2997b3cc8f155b80df (diff)
Introduce application version number
Diffstat (limited to 'controller-server/src/test/java')
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ArtifactRepositoryMock.java39
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java157
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java28
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ZoneRegistryMock.java13
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java7
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java46
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java6
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentExpirerTest.java5
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployerTest.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java38
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerControllerTester.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java1
12 files changed, 282 insertions, 62 deletions
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ArtifactRepositoryMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ArtifactRepositoryMock.java
new file mode 100644
index 00000000000..efbc10e8deb
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ArtifactRepositoryMock.java
@@ -0,0 +1,39 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.controller;
+
+import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.ArtifactRepository;
+import com.yahoo.vespa.hosted.controller.application.ApplicationPackage;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * @author mpolden
+ */
+public class ArtifactRepositoryMock implements ArtifactRepository {
+
+ private final Map<Integer, byte[]> repository = new HashMap<>();
+
+ public ArtifactRepositoryMock put(ApplicationId applicationId, ApplicationPackage applicationPackage,
+ String applicationVersion) {
+ repository.put(artifactHash(applicationId, applicationVersion), applicationPackage.zippedContent());
+ return this;
+ }
+
+ @Override
+ public byte[] getApplicationPackage(ApplicationId applicationId, String applicationVersion) {
+ int artifactHash = artifactHash(applicationId, applicationVersion);
+ if (!repository.containsKey(artifactHash)) {
+ throw new IllegalArgumentException("No application package found for " + applicationId + " with version "
+ + applicationVersion);
+ }
+ return repository.get(artifactHash);
+ }
+
+ private static int artifactHash(ApplicationId applicationId, String applicationVersion) {
+ return Objects.hash(applicationId, applicationVersion);
+ }
+
+}
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 ceed52d2dad..1127e739689 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
@@ -10,11 +10,11 @@ import com.yahoo.config.provision.InstanceName;
import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.TenantName;
+import com.yahoo.vespa.athenz.api.AthenzDomain;
import com.yahoo.vespa.config.SlimeUtils;
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;
-import com.yahoo.vespa.athenz.api.AthenzDomain;
import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
import com.yahoo.vespa.hosted.controller.api.identifiers.Property;
import com.yahoo.vespa.hosted.controller.api.identifiers.PropertyId;
@@ -26,12 +26,13 @@ import com.yahoo.vespa.hosted.controller.api.integration.dns.Record;
import com.yahoo.vespa.hosted.controller.api.integration.dns.RecordName;
import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.application.ApplicationPackage;
-import com.yahoo.vespa.hosted.controller.application.ApplicationRevision;
+import com.yahoo.vespa.hosted.controller.application.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.application.Change;
import com.yahoo.vespa.hosted.controller.application.DeploymentJobs;
import com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobError;
import com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobType;
import com.yahoo.vespa.hosted.controller.application.JobStatus;
+import com.yahoo.vespa.hosted.controller.application.SourceRevision;
import com.yahoo.vespa.hosted.controller.athenz.mock.AthenzDbMock;
import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder;
import com.yahoo.vespa.hosted.controller.deployment.BuildSystem;
@@ -100,21 +101,21 @@ public class ControllerTest {
Version version1 = Version.fromString("6.1"); // Set in config server mock
Application app1 = tester.createApplication("app1", "tenant1", 1, 11L);
tester.notifyJobCompletion(component, app1, true);
- assertFalse("Revision is currently not known",
- ((Change.ApplicationChange)tester.controller().applications().require(app1.id()).deploying().get()).revision().isPresent());
+ assertFalse("Application version is currently not known",
+ ((Change.ApplicationChange)tester.controller().applications().require(app1.id()).deploying().get()).version().isPresent());
tester.deployAndNotify(app1, applicationPackage, true, systemTest);
tester.deployAndNotify(app1, applicationPackage, true, stagingTest);
assertEquals(4, applications.require(app1.id()).deploymentJobs().jobStatus().size());
- Optional<ApplicationRevision> revision = ((Change.ApplicationChange)tester.controller().applications().require(app1.id()).deploying().get()).revision();
- assertTrue("Revision has been set during deployment", revision.isPresent());
+ Optional<ApplicationVersion> applicationVersion = ((Change.ApplicationChange)tester.controller().applications().require(app1.id()).deploying().get()).version();
+ assertTrue("Application version has been set during deployment", applicationVersion.isPresent());
assertStatus(JobStatus.initial(stagingTest)
- .withTriggering(version1, revision, false, "", tester.clock().instant().minus(Duration.ofMillis(1)))
+ .withTriggering(version1, applicationVersion, false, "", tester.clock().instant().minus(Duration.ofMillis(1)))
.withCompletion(42, Optional.empty(), tester.clock().instant(), tester.controller()), app1.id(), tester.controller());
// Causes first deployment job to be triggered
assertStatus(JobStatus.initial(productionCorpUsEast1)
- .withTriggering(version1, revision, false, "", tester.clock().instant()), app1.id(), tester.controller());
+ .withTriggering(version1, applicationVersion, false, "", tester.clock().instant()), app1.id(), tester.controller());
tester.clock().advance(Duration.ofSeconds(1));
// production job (failing)
@@ -122,9 +123,9 @@ public class ControllerTest {
assertEquals(4, applications.require(app1.id()).deploymentJobs().jobStatus().size());
JobStatus expectedJobStatus = JobStatus.initial(productionCorpUsEast1)
- .withTriggering(version1, revision, false, "", tester.clock().instant()) // Triggered first without revision info
+ .withTriggering(version1, applicationVersion, false, "", tester.clock().instant()) // Triggered first without application version info
.withCompletion(42, Optional.of(JobError.unknown), tester.clock().instant(), tester.controller())
- .withTriggering(version1, revision, false, "", tester.clock().instant()); // Re-triggering (due to failure) has revision info
+ .withTriggering(version1, applicationVersion, false, "", tester.clock().instant()); // Re-triggering (due to failure) has application version info
assertStatus(expectedJobStatus, app1.id(), tester.controller());
@@ -147,20 +148,20 @@ public class ControllerTest {
tester.notifyJobCompletion(component, app1, true);
tester.deployAndNotify(app1, applicationPackage, true, false, systemTest);
assertStatus(JobStatus.initial(systemTest)
- .withTriggering(version1, revision, false, "", tester.clock().instant().minus(Duration.ofMillis(1)))
+ .withTriggering(version1, applicationVersion, false, "", tester.clock().instant().minus(Duration.ofMillis(1)))
.withCompletion(42, Optional.empty(), tester.clock().instant(), tester.controller()), app1.id(), tester.controller());
tester.deployAndNotify(app1, applicationPackage, true, stagingTest);
// production job succeeding now
tester.deployAndNotify(app1, applicationPackage, true, productionCorpUsEast1);
expectedJobStatus = expectedJobStatus
- .withTriggering(version1, revision, false, "", tester.clock().instant().minus(Duration.ofMillis(1)))
+ .withTriggering(version1, applicationVersion, false, "", tester.clock().instant().minus(Duration.ofMillis(1)))
.withCompletion(42, Optional.empty(), tester.clock().instant(), tester.controller());
assertStatus(expectedJobStatus, app1.id(), tester.controller());
// causes triggering of next production job
assertStatus(JobStatus.initial(productionUsEast3)
- .withTriggering(version1, revision, false, "", tester.clock().instant()),
+ .withTriggering(version1, applicationVersion, false, "", tester.clock().instant()),
app1.id(), tester.controller());
tester.deployAndNotify(app1, applicationPackage, true, productionUsEast3);
@@ -198,6 +199,132 @@ public class ControllerTest {
applications.require(app1.id()).deployments().get(productionCorpUsEast1.zone(SystemName.main).get()));
assertNull("Deployment job was removed", applications.require(app1.id()).deploymentJobs().jobStatus().get(productionCorpUsEast1));
}
+
+ // TODO: Replace above test with this one after introducing new application version number
+ @Test
+ public void testDeploymentWithApplicationVersion() {
+ // Setup system
+ DeploymentTester tester = new DeploymentTester();
+ ApplicationController applications = tester.controller().applications();
+ Version version1 = Version.fromString("6.1"); // Set in config server mock
+ Application app1 = tester.createApplication("app1", "tenant1", 1, 11L);
+
+ // Component runs, uploads artifact and notifies completion
+ ApplicationPackage applicationPackage = new ApplicationPackageBuilder()
+ .environment(Environment.prod)
+ .region("corp-us-east-1")
+ .region("us-east-3")
+ .build();
+ SourceRevision source = new SourceRevision("repo", "branch", "deadbeef");
+ String expectedVersionString = "1.0.37-deadbeef";
+ tester.artifactRepository().put(app1.id(), applicationPackage, expectedVersionString);
+ tester.notifyJobCompletion(component, app1, Optional.empty(), Optional.of(source), 37);
+ ApplicationVersion expectedVersion = ApplicationVersion.from(source, 37);
+ assertEquals(expectedVersionString, ((Change.ApplicationChange) tester.controller().applications()
+ .require(app1.id())
+ .deploying()
+ .get()).version().get().id());
+
+ // Deploy without application package
+ tester.deployAndNotify(app1, true, systemTest);
+ tester.deployAndNotify(app1, true, stagingTest);
+ assertEquals(4, applications.require(app1.id()).deploymentJobs().jobStatus().size());
+ assertStatus(JobStatus.initial(stagingTest)
+ .withTriggering(version1, Optional.of(expectedVersion), false, "", tester.clock().instant().minus(Duration.ofMillis(1)))
+ .withCompletion(42, Optional.empty(), tester.clock().instant(), tester.controller()), app1.id(), tester.controller());
+
+ // Causes first deployment job to be triggered
+ assertStatus(JobStatus.initial(productionCorpUsEast1)
+ .withTriggering(version1, Optional.of(expectedVersion), false, "", tester.clock().instant()), app1.id(), tester.controller());
+ tester.clock().advance(Duration.ofSeconds(1));
+
+ // production job (failing)
+ tester.deployAndNotify(app1, false, productionCorpUsEast1);
+ assertEquals(4, applications.require(app1.id()).deploymentJobs().jobStatus().size());
+
+ JobStatus expectedJobStatus = JobStatus.initial(productionCorpUsEast1)
+ .withTriggering(version1, Optional.of(expectedVersion), false, "", tester.clock().instant())
+ .withCompletion(42, Optional.of(JobError.unknown), tester.clock().instant(), tester.controller());
+
+ assertStatus(expectedJobStatus, app1.id(), tester.controller());
+
+ // Simulate restart
+ tester.restartController();
+ applications = tester.controller().applications();
+
+ assertNotNull(tester.controller().tenants().tenant(new TenantId("tenant1")));
+ assertNotNull(applications.get(ApplicationId.from(TenantName.from("tenant1"),
+ ApplicationName.from("application1"),
+ InstanceName.from("default"))));
+ assertEquals(4, applications.require(app1.id()).deploymentJobs().jobStatus().size());
+
+
+ tester.clock().advance(Duration.ofHours(1));
+
+ tester.notifyJobCompletion(productionCorpUsEast1, app1, false); // Need to complete the job, or new jobs won't start.
+
+ // Component is triggered again
+ tester.artifactRepository().put(app1.id(), applicationPackage, "1.0.38-deadbeef");
+ tester.notifyJobCompletion(component, app1, Optional.empty(), Optional.of(source), 38);
+ tester.deployAndNotify(app1, Optional.empty(), true, false, systemTest);
+ expectedVersion = ApplicationVersion.from(source, 38);
+ assertStatus(JobStatus.initial(systemTest)
+ .withTriggering(version1, Optional.of(expectedVersion), false, "", tester.clock().instant().minus(Duration.ofMillis(1)))
+ .withCompletion(42, Optional.empty(), tester.clock().instant(), tester.controller()), app1.id(), tester.controller());
+ tester.deployAndNotify(app1, Optional.empty(), true, true, stagingTest);
+
+ // production job succeeding now
+ tester.deployAndNotify(app1, Optional.empty(), true, true, productionCorpUsEast1);
+ expectedJobStatus = expectedJobStatus
+ .withTriggering(version1, Optional.of(expectedVersion), false, "", tester.clock().instant().minus(Duration.ofMillis(1)))
+ .withCompletion(42, Optional.empty(), tester.clock().instant(), tester.controller());
+ assertStatus(expectedJobStatus, app1.id(), tester.controller());
+
+ // causes triggering of next production job
+ assertStatus(JobStatus.initial(productionUsEast3)
+ .withTriggering(version1, Optional.of(expectedVersion), false, "", tester.clock().instant()),
+ app1.id(), tester.controller());
+ tester.deployAndNotify(app1, Optional.empty(), true, true, productionUsEast3);
+
+ assertEquals(5, applications.get(app1.id()).get().deploymentJobs().jobStatus().size());
+
+ // prod zone removal is not allowed
+ applicationPackage = new ApplicationPackageBuilder()
+ .environment(Environment.prod)
+ .region("us-east-3")
+ .build();
+ tester.artifactRepository().put(app1.id(), applicationPackage, "1.0.56-cafed00d");
+ source = new SourceRevision("repo", "branch", "cafed00d");
+ tester.notifyJobCompletion(component, app1, Optional.empty(), Optional.of(source), 56);
+ try {
+ tester.deploy(systemTest, app1, Optional.empty(), false);
+ fail("Expected exception due to unallowed production deployment removal");
+ }
+ catch (IllegalArgumentException e) {
+ assertEquals("deployment-removal: application 'tenant1.app1' is deployed in corp-us-east-1, but does not include this zone in deployment.xml", e.getMessage());
+ }
+ assertNotNull("Zone was not removed",
+ applications.require(app1.id()).deployments().get(productionCorpUsEast1.zone(SystemName.main).get()));
+ JobStatus jobStatus = applications.require(app1.id()).deploymentJobs().jobStatus().get(productionCorpUsEast1);
+ assertNotNull("Deployment job was not removed", jobStatus);
+ assertEquals(42, jobStatus.lastCompleted().get().id());
+ assertEquals("staging-test completed", jobStatus.lastCompleted().get().reason());
+
+ // prod zone removal is allowed with override
+ applicationPackage = new ApplicationPackageBuilder()
+ .allow(ValidationId.deploymentRemoval)
+ .upgradePolicy("default")
+ .environment(Environment.prod)
+ .region("us-east-3")
+ .build();
+ tester.artifactRepository().put(app1.id(), applicationPackage, "1.0.103-c00ffefe");
+ source = new SourceRevision("repo", "branch", "c00ffefe");
+ tester.notifyJobCompletion(component, app1, Optional.empty(), Optional.of(source), 103);
+ tester.deployAndNotify(app1, Optional.empty(), true, true, systemTest);
+ assertNull("Zone was removed",
+ applications.require(app1.id()).deployments().get(productionCorpUsEast1.zone(SystemName.main).get()));
+ assertNull("Deployment job was removed", applications.require(app1.id()).deploymentJobs().jobStatus().get(productionCorpUsEast1));
+ }
@Test
public void testDeployVersion() {
@@ -557,6 +684,7 @@ public class ControllerTest {
public void testCleanupOfStaleDeploymentData() throws IOException {
DeploymentTester tester = new DeploymentTester();
tester.controllerTester().zoneRegistry().setSystem(SystemName.cd);
+ tester.controllerTester().zoneRegistry().setZones(ZoneId.from("prod", "cd-us-central-1"));
Supplier<Map<JobType, JobStatus>> statuses = () ->
tester.application(ApplicationId.from("vespa", "canary", "default")).deploymentJobs().jobStatus();
@@ -764,6 +892,7 @@ public class ControllerTest {
public void testDeployWithoutProjectId() {
DeploymentTester tester = new DeploymentTester();
tester.controllerTester().zoneRegistry().setSystem(SystemName.cd);
+ tester.controllerTester().zoneRegistry().setZones(ZoneId.from("prod", "cd-us-central-1"));
ApplicationPackage applicationPackage = new ApplicationPackageBuilder()
.environment(Environment.prod)
.region("cd-us-central-1")
@@ -777,7 +906,7 @@ public class ControllerTest {
// Same options as used in our integration tests
DeployOptions options = new DeployOptions(Optional.empty(), Optional.empty(), false,
false);
- tester.controller().applications().deployApplication(app.id(), zone, applicationPackage, options);
+ tester.controller().applications().deployApplication(app.id(), zone, Optional.of(applicationPackage), options);
assertTrue("Application deployed and activated",
tester.controllerTester().configServer().activated().getOrDefault(app.id(), false));
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 b1486c8ec00..3b574ac606b 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
@@ -7,6 +7,7 @@ import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.InstanceName;
import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.TenantName;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.ArtifactRepository;
import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
import com.yahoo.slime.Slime;
import com.yahoo.test.ManualClock;
@@ -64,30 +65,32 @@ public final class ControllerTester {
private final CuratorDb curator;
private final MemoryNameService nameService;
private final RotationsConfig rotationsConfig;
+ private final ArtifactRepositoryMock artifactRepository;
private Controller controller;
public ControllerTester() {
this(new MemoryControllerDb(), new AthenzDbMock(), new ManualClock(), new ConfigServerClientMock(),
new ZoneRegistryMock(), new GitHubMock(), new MockCuratorDb(), defaultRotationsConfig(),
- new MemoryNameService());
+ new MemoryNameService(), new ArtifactRepositoryMock());
}
public ControllerTester(ManualClock clock) {
this(new MemoryControllerDb(), new AthenzDbMock(), clock, new ConfigServerClientMock(),
new ZoneRegistryMock(), new GitHubMock(), new MockCuratorDb(), defaultRotationsConfig(),
- new MemoryNameService());
+ new MemoryNameService(), new ArtifactRepositoryMock());
}
public ControllerTester(RotationsConfig rotationsConfig) {
this(new MemoryControllerDb(), new AthenzDbMock(), new ManualClock(), new ConfigServerClientMock(),
- new ZoneRegistryMock(), new GitHubMock(), new MockCuratorDb(), rotationsConfig, new MemoryNameService());
+ new ZoneRegistryMock(), new GitHubMock(), new MockCuratorDb(), rotationsConfig, new MemoryNameService(),
+ new ArtifactRepositoryMock());
}
private ControllerTester(ControllerDb db, AthenzDbMock athenzDb, ManualClock clock,
ConfigServerClientMock configServer, ZoneRegistryMock zoneRegistry,
GitHubMock gitHub, CuratorDb curator, RotationsConfig rotationsConfig,
- MemoryNameService nameService) {
+ MemoryNameService nameService, ArtifactRepositoryMock artifactRepository) {
this.db = db;
this.athenzDb = athenzDb;
this.clock = clock;
@@ -97,8 +100,9 @@ public final class ControllerTester {
this.curator = curator;
this.nameService = nameService;
this.rotationsConfig = rotationsConfig;
+ this.artifactRepository = artifactRepository;
this.controller = createController(db, curator, rotationsConfig, configServer, clock, gitHub, zoneRegistry,
- athenzDb, nameService);
+ athenzDb, nameService, artifactRepository);
}
public Controller controller() { return controller; }
@@ -117,10 +121,12 @@ public final class ControllerTester {
public GitHubMock gitHub() { return gitHub; }
+ public ArtifactRepositoryMock artifactRepository() { return artifactRepository; }
+
/** Create a new controller instance. Useful to verify that controller state is rebuilt from persistence */
public final void createNewController() {
controller = createController(db, curator, rotationsConfig, configServer, clock, gitHub, zoneRegistry, athenzDb,
- nameService);
+ nameService, artifactRepository);
}
/** Creates the given tenant and application and deploys it */
@@ -209,6 +215,10 @@ public final class ControllerTester {
}
public void deploy(Application application, ZoneId zone, ApplicationPackage applicationPackage, boolean deployCurrentVersion) {
+ deploy(application, zone, Optional.of(applicationPackage), deployCurrentVersion);
+ }
+
+ public void deploy(Application application, ZoneId zone, Optional<ApplicationPackage> applicationPackage, boolean deployCurrentVersion) {
ScrewdriverId app1ScrewdriverId = new ScrewdriverId(String.valueOf(application.deploymentJobs().projectId().get()));
GitRevision app1RevisionId = new GitRevision(new GitRepository("repo"), new GitBranch("master"), new GitCommit("commit1"));
controller().applications().deployApplication(application.id(),
@@ -231,7 +241,8 @@ public final class ControllerTester {
private static Controller createController(ControllerDb db, CuratorDb curator, RotationsConfig rotationsConfig,
ConfigServerClientMock configServerClientMock, ManualClock clock,
GitHubMock gitHubClientMock, ZoneRegistryMock zoneRegistryMock,
- AthenzDbMock athensDb, MemoryNameService nameService) {
+ AthenzDbMock athensDb, MemoryNameService nameService,
+ ArtifactRepository artifactRepository) {
Controller controller = new Controller(db,
curator,
rotationsConfig,
@@ -247,7 +258,8 @@ public final class ControllerTester {
new MockRoutingGenerator(),
new ChefMock(),
clock,
- new AthenzClientFactoryMock(athensDb));
+ new AthenzClientFactoryMock(athensDb),
+ artifactRepository);
controller.updateVersionStatus(VersionStatus.compute(controller));
return controller;
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ZoneRegistryMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ZoneRegistryMock.java
index c205357c7ef..63751cfaa98 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ZoneRegistryMock.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ZoneRegistryMock.java
@@ -16,6 +16,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneFilterMock;
import java.net.URI;
import java.time.Duration;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -34,9 +35,11 @@ public class ZoneRegistryMock extends AbstractComponent implements ZoneRegistry
@Inject
public ZoneRegistryMock() {
- this.zones.add(ZoneId.from("prod", "corp-us-east-1"));
- this.zones.add(ZoneId.from("prod", "us-east-3"));
- this.zones.add(ZoneId.from("prod", "us-west-1"));
+ zones.add(ZoneId.from("prod", "corp-us-east-1"));
+ zones.add(ZoneId.from("prod", "us-east-3"));
+ zones.add(ZoneId.from("prod", "us-west-1"));
+ zones.add(ZoneId.from("prod", "us-central-1"));
+ zones.add(ZoneId.from("prod", "eu-west-1"));
}
public ZoneRegistryMock setDeploymentTimeToLive(ZoneId zone, Duration duration) {
@@ -54,6 +57,10 @@ public class ZoneRegistryMock extends AbstractComponent implements ZoneRegistry
return this;
}
+ public ZoneRegistryMock setZones(ZoneId... zone) {
+ return setZones(Arrays.asList(zone));
+ }
+
public ZoneRegistryMock setSystem(SystemName system) {
this.system = system;
return this;
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 3311cffa078..9d5fcb31288 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
@@ -71,8 +71,8 @@ public class ApplicationPackageBuilder {
return this;
}
- public ApplicationPackageBuilder blockChange(boolean revision, boolean version,
- String daySpec, String hourSpec, String zoneSpec) {
+ public ApplicationPackageBuilder blockChange(boolean revision, boolean version, String daySpec, String hourSpec,
+ String zoneSpec) {
blockChange.append(" <block-change");
blockChange.append(" revision='").append(revision).append("'");
blockChange.append(" version='").append(version).append("'");
@@ -93,7 +93,8 @@ public class ApplicationPackageBuilder {
}
public ApplicationPackageBuilder athenzIdentity(AthenzDomain domain, AthenzService service) {
- this.athenzIdentityAttributes = String.format("athenz-domain='%s' athenz-service='%s'", domain.value(), service.value());
+ this.athenzIdentityAttributes = String.format("athenz-domain='%s' athenz-service='%s'", domain.value(),
+ service.value());
return this;
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java
index c9f0c6cba1d..8de32b4b531 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java
@@ -7,6 +7,7 @@ import com.yahoo.config.provision.Environment;
import com.yahoo.test.ManualClock;
import com.yahoo.vespa.hosted.controller.Application;
import com.yahoo.vespa.hosted.controller.ApplicationController;
+import com.yahoo.vespa.hosted.controller.ArtifactRepositoryMock;
import com.yahoo.vespa.hosted.controller.ConfigServerClientMock;
import com.yahoo.vespa.hosted.controller.Controller;
import com.yahoo.vespa.hosted.controller.ControllerTester;
@@ -16,6 +17,7 @@ import com.yahoo.vespa.hosted.controller.application.ApplicationPackage;
import com.yahoo.vespa.hosted.controller.application.Change;
import com.yahoo.vespa.hosted.controller.application.DeploymentJobs;
import com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobType;
+import com.yahoo.vespa.hosted.controller.application.SourceRevision;
import com.yahoo.vespa.hosted.controller.maintenance.ReadyJobsTrigger;
import com.yahoo.vespa.hosted.controller.maintenance.JobControl;
import com.yahoo.vespa.hosted.controller.maintenance.Upgrader;
@@ -43,6 +45,7 @@ public class DeploymentTester {
// Set a long interval so that maintainers never do scheduled runs during tests
private static final Duration maintenanceInterval = Duration.ofDays(1);
+ private static final int defaultBuildNumber = 42;
private final ControllerTester tester;
private final Upgrader upgrader;
@@ -81,6 +84,8 @@ public class DeploymentTester {
public ConfigServerClientMock configServer() { return tester.configServer(); }
+ public ArtifactRepositoryMock artifactRepository() { return tester.artifactRepository(); }
+
public Application application(String name) {
return application(ApplicationId.from("tenant1", name, "default"));
}
@@ -154,16 +159,18 @@ public class DeploymentTester {
}
public static DeploymentJobs.JobReport jobReport(Application application, JobType jobType, boolean success) {
- return jobReport(application, jobType, Optional.ofNullable(success ? null : unknown));
+ return jobReport(application, jobType, Optional.ofNullable(success ? null : unknown), Optional.empty(), defaultBuildNumber);
}
- public static DeploymentJobs.JobReport jobReport(Application application, JobType jobType, Optional<DeploymentJobs.JobError> jobError) {
+ public static DeploymentJobs.JobReport jobReport(Application application, JobType jobType,
+ Optional<DeploymentJobs.JobError> jobError,
+ Optional<SourceRevision> sourceRevision, long buildNumber) {
return new DeploymentJobs.JobReport(
application.id(),
jobType,
application.deploymentJobs().projectId().get(),
- 42,
- Optional.empty(),
+ buildNumber,
+ sourceRevision,
jobError
);
}
@@ -204,8 +211,13 @@ public class DeploymentTester {
}
public void notifyJobCompletion(JobType jobType, Application application, Optional<DeploymentJobs.JobError> jobError) {
+ notifyJobCompletion(jobType, application, jobError, Optional.empty(), defaultBuildNumber);
+ }
+
+ public void notifyJobCompletion(JobType jobType, Application application, Optional<DeploymentJobs.JobError> jobError,
+ Optional<SourceRevision> source, long buildNumber) {
clock().advance(Duration.ofMillis(1));
- applications().notifyJobCompletion(jobReport(application, jobType, jobError));
+ applications().notifyJobCompletion(jobReport(application, jobType, jobError, source, buildNumber));
}
public void completeUpgrade(Application application, Version version, String upgradePolicy) {
@@ -233,11 +245,22 @@ public class DeploymentTester {
}
public void deploy(JobType job, Application application, ApplicationPackage applicationPackage) {
- deploy(job, application, applicationPackage, false);
+ deploy(job, application, Optional.of(applicationPackage), false);
+ }
+
+ public void deploy(JobType job, Application application, ApplicationPackage applicationPackage,
+ boolean deployCurrentVersion) {
+ deploy(job, application, Optional.of(applicationPackage), deployCurrentVersion);
}
- public void deploy(JobType job, Application application, ApplicationPackage applicationPackage, boolean deployCurrentVersion) {
- job.zone(controller().system()).ifPresent(zone -> tester.deploy(application, zone, applicationPackage, deployCurrentVersion));
+ public void deploy(JobType job, Application application, Optional<ApplicationPackage> applicationPackage,
+ boolean deployCurrentVersion) {
+ job.zone(controller().system()).ifPresent(zone -> tester.deploy(application, zone, applicationPackage,
+ deployCurrentVersion));
+ }
+
+ public void deployAndNotify(Application application, boolean success, JobType... job) {
+ deployAndNotify(application, Optional.empty(), success, true, job);
}
public void deployAndNotify(Application application, String upgradePolicy, boolean success, JobType... jobs) {
@@ -251,10 +274,15 @@ public class DeploymentTester {
public void deployAndNotify(Application application, ApplicationPackage applicationPackage, boolean success,
boolean expectOnlyTheseJobs, JobType... jobs) {
+ deployAndNotify(application, Optional.of(applicationPackage), success, expectOnlyTheseJobs, jobs);
+ }
+
+ public void deployAndNotify(Application application, Optional<ApplicationPackage> applicationPackage,
+ boolean success, boolean expectOnlyTheseJobs, JobType... jobs) {
consumeJobs(application, expectOnlyTheseJobs, jobs);
for (JobType job : jobs) {
if (success) {
- deploy(job, application, applicationPackage);
+ deploy(job, application, applicationPackage, false);
}
notifyJobCompletion(job, application, success);
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java
index b71a9090c79..74d03240ec3 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java
@@ -247,7 +247,7 @@ public class DeploymentTriggerTest {
.region("corp-us-east-1")
.region("us-central-1")
.region("us-west-1")
- .region("ap-northeast-1")
+ .region("eu-west-1")
.build();
// Component job finishes
@@ -260,7 +260,7 @@ public class DeploymentTriggerTest {
tester.deployAndNotify(application, newApplicationPackage, true, JobType.productionCorpUsEast1);
tester.deployAndNotify(application, newApplicationPackage, true, JobType.productionUsCentral1);
tester.deployAndNotify(application, newApplicationPackage, true, JobType.productionUsWest1);
- tester.deployAndNotify(application, newApplicationPackage, true, JobType.productionApNortheast1);
+ tester.deployAndNotify(application, newApplicationPackage, true, JobType.productionEuWest1);
assertTrue("All jobs consumed", buildSystem.jobs().isEmpty());
}
@@ -277,7 +277,7 @@ public class DeploymentTriggerTest {
ApplicationPackageBuilder applicationPackageBuilder = new ApplicationPackageBuilder()
.upgradePolicy("canary")
- // Block revision changes on tuesday in hours 18 and 19
+ // Block application version changes on tuesday in hours 18 and 19
.blockChange(true, false, "tue", "18-19", "UTC")
.region("us-west-1")
.region("us-central-1")
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentExpirerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentExpirerTest.java
index d48f7b84ee6..513e5520d85 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentExpirerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentExpirerTest.java
@@ -3,8 +3,8 @@ package com.yahoo.vespa.hosted.controller.maintenance;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.RegionName;
-import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.Application;
+import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.application.ApplicationPackage;
import com.yahoo.vespa.hosted.controller.application.Deployment;
import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder;
@@ -13,7 +13,6 @@ import com.yahoo.vespa.hosted.controller.persistence.MockCuratorDb;
import org.junit.Before;
import org.junit.Test;
-import java.io.IOException;
import java.time.Duration;
import java.util.List;
import java.util.stream.Collectors;
@@ -33,7 +32,7 @@ public class DeploymentExpirerTest {
}
@Test
- public void testDeploymentExpiry() throws IOException, InterruptedException {
+ public void testDeploymentExpiry() {
tester.controllerTester().zoneRegistry().setDeploymentTimeToLive(
ZoneId.from(Environment.dev, RegionName.from("us-east-1")),
Duration.ofDays(14)
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployerTest.java
index 62e6d379c60..b200e2d7e18 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployerTest.java
@@ -7,6 +7,7 @@ import com.yahoo.config.provision.SystemName;
import com.yahoo.slime.Slime;
import com.yahoo.vespa.config.SlimeUtils;
import com.yahoo.vespa.hosted.controller.Application;
+import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.application.ApplicationPackage;
import com.yahoo.vespa.hosted.controller.application.DeploymentJobs;
import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder;
@@ -178,6 +179,7 @@ public class FailureRedeployerTest {
public void retryIgnoresStaleJobData() throws Exception {
DeploymentTester tester = new DeploymentTester();
tester.controllerTester().zoneRegistry().setSystem(SystemName.cd);
+ tester.controllerTester().zoneRegistry().setZones(ZoneId.from("prod", "cd-us-central-1"));
// Current system version, matches version in test data
Version version = Version.fromString("6.141.117");
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 d7389ca94cd..f42a4c1deb3 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
@@ -6,14 +6,14 @@ import com.yahoo.config.application.api.DeploymentSpec;
import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.ClusterSpec;
-import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
import com.yahoo.slime.Slime;
import com.yahoo.vespa.config.SlimeUtils;
import com.yahoo.vespa.hosted.controller.Application;
import com.yahoo.vespa.hosted.controller.ControllerTester;
import com.yahoo.vespa.hosted.controller.api.integration.MetricsService;
import com.yahoo.vespa.hosted.controller.api.integration.organization.IssueId;
-import com.yahoo.vespa.hosted.controller.application.ApplicationRevision;
+import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
+import com.yahoo.vespa.hosted.controller.application.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.application.Change;
import com.yahoo.vespa.hosted.controller.application.ClusterInfo;
import com.yahoo.vespa.hosted.controller.application.ClusterUtilization;
@@ -26,7 +26,6 @@ import com.yahoo.vespa.hosted.controller.application.SourceRevision;
import com.yahoo.vespa.hosted.controller.rotation.RotationId;
import org.junit.Test;
-import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.ArrayList;
@@ -60,10 +59,11 @@ public class ApplicationSerializerTest {
"</validation-overrides>");
List<Deployment> deployments = new ArrayList<>();
- ApplicationRevision revision1 = ApplicationRevision.from("appHash1");
- ApplicationRevision revision2 = ApplicationRevision.from("appHash2", new SourceRevision("repo1", "branch1", "commit1"));
- deployments.add(new Deployment(zone1, revision1, Version.fromString("1.2.3"), Instant.ofEpochMilli(3))); // One deployment without cluster info and utils
- deployments.add(new Deployment(zone2, revision2, Version.fromString("1.2.3"), Instant.ofEpochMilli(5),
+ ApplicationVersion applicationVersion1 = ApplicationVersion.from("appHash1");
+ ApplicationVersion applicationVersion2 = ApplicationVersion
+ .from("appHash2", new SourceRevision("repo1", "branch1", "commit1"));
+ deployments.add(new Deployment(zone1, applicationVersion1, Version.fromString("1.2.3"), Instant.ofEpochMilli(3))); // One deployment without cluster info and utils
+ deployments.add(new Deployment(zone2, applicationVersion2, Version.fromString("1.2.3"), Instant.ofEpochMilli(5),
createClusterUtils(3, 0.2), createClusterInfo(3, 4),new DeploymentMetrics(2,3,4,5,6)));
Optional<Long> projectId = Optional.of(123L);
@@ -96,8 +96,8 @@ public class ApplicationSerializerTest {
assertEquals(original.validationOverrides().xmlForm(), serialized.validationOverrides().xmlForm());
assertEquals(2, serialized.deployments().size());
- assertEquals(original.deployments().get(zone1).revision(), serialized.deployments().get(zone1).revision());
- assertEquals(original.deployments().get(zone2).revision(), serialized.deployments().get(zone2).revision());
+ assertEquals(original.deployments().get(zone1).applicationVersion(), serialized.deployments().get(zone1).applicationVersion());
+ assertEquals(original.deployments().get(zone2).applicationVersion(), serialized.deployments().get(zone2).applicationVersion());
assertEquals(original.deployments().get(zone1).version(), serialized.deployments().get(zone1).version());
assertEquals(original.deployments().get(zone2).version(), serialized.deployments().get(zone2).version());
assertEquals(original.deployments().get(zone1).at(), serialized.deployments().get(zone1).at());
@@ -145,18 +145,20 @@ public class ApplicationSerializerTest {
assertEquals(6, serialized.deployments().get(zone2).metrics().writeLatencyMillis(), Double.MIN_VALUE);
{ // test more deployment serialization cases
- Application original2 = writable(original).withDeploying(Optional.of(Change.ApplicationChange.of(ApplicationRevision.from("hash1"))));
+ Application original2 = writable(original).withDeploying(Optional.of(Change.ApplicationChange.of(ApplicationVersion
+ .from("hash1"))));
Application serialized2 = applicationSerializer.fromSlime(applicationSerializer.toSlime(original2));
assertEquals(original2.deploying(), serialized2.deploying());
- assertEquals(((Change.ApplicationChange)serialized2.deploying().get()).revision().get().source(),
- ((Change.ApplicationChange)original2.deploying().get()).revision().get().source());
+ assertEquals(((Change.ApplicationChange)serialized2.deploying().get()).version().get().source(),
+ ((Change.ApplicationChange)original2.deploying().get()).version().get().source());
- Application original3 = writable(original).withDeploying(Optional.of(Change.ApplicationChange.of(ApplicationRevision.from("hash1",
- new SourceRevision("a", "b", "c")))));
+ Application original3 = writable(original).withDeploying(Optional.of(Change.ApplicationChange.of(ApplicationVersion
+ .from("hash1",
+ new SourceRevision("a", "b", "c")))));
Application serialized3 = applicationSerializer.fromSlime(applicationSerializer.toSlime(original3));
assertEquals(original3.deploying(), serialized2.deploying());
- assertEquals(((Change.ApplicationChange)serialized3.deploying().get()).revision().get().source(),
- ((Change.ApplicationChange)original3.deploying().get()).revision().get().source());
+ assertEquals(((Change.ApplicationChange)serialized3.deploying().get()).version().get().source(),
+ ((Change.ApplicationChange)original3.deploying().get()).version().get().source());
Application original4 = writable(original).withDeploying(Optional.empty());
Application serialized4 = applicationSerializer.fromSlime(applicationSerializer.toSlime(original4));
@@ -195,7 +197,7 @@ public class ApplicationSerializerTest {
}
@Test
- public void testLegacySerialization() throws IOException {
+ public void testLegacySerialization() {
Application applicationWithSuccessfulJob = applicationSerializer.fromSlime(applicationSlime(false));
assertFalse("No job error for successful job", applicationWithSuccessfulJob.deploymentJobs().jobStatus().get(DeploymentJobs.JobType.systemTest).jobError().isPresent());
@@ -211,7 +213,7 @@ public class ApplicationSerializerTest {
@Test
public void testCompleteApplicationDeserialization() {
- Application application = applicationSerializer.fromSlime(SlimeUtils.jsonToSlime(longApplicationJson.getBytes(StandardCharsets.UTF_8)));
+ applicationSerializer.fromSlime(SlimeUtils.jsonToSlime(longApplicationJson.getBytes(StandardCharsets.UTF_8)));
// ok if no error
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerControllerTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerControllerTester.java
index fc0147dacef..5b806d580e2 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerControllerTester.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerControllerTester.java
@@ -81,7 +81,7 @@ public class ContainerControllerTester {
GitRevision app1RevisionId = new GitRevision(new GitRepository("repo"), new GitBranch("master"), new GitCommit("commit1"));
controller().applications().deployApplication(application.id(),
zone,
- applicationPackage,
+ Optional.of(applicationPackage),
new DeployOptions(Optional.of(new ScrewdriverBuildJob(app1ScrewdriverId, app1RevisionId)), Optional.empty(), false, false));
return application;
}
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 028992e8f7d..abc5f9f8aa1 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
@@ -67,6 +67,7 @@ public class ControllerContainerTest {
" <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" +
+ " <component id='com.yahoo.vespa.hosted.controller.ArtifactRepositoryMock'/>\n" +
" <handler id='com.yahoo.vespa.hosted.controller.restapi.application.ApplicationApiHandler'>\n" +
" <binding>http://*/application/v4/*</binding>\n" +
" </handler>\n" +