diff options
Diffstat (limited to 'controller-server')
26 files changed, 374 insertions, 794 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java index 0eca30ddeec..7c718518129 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java @@ -10,6 +10,7 @@ import com.yahoo.config.application.api.ValidationId; import com.yahoo.config.application.api.ValidationOverrides; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ClusterSpec; +import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.InstanceName; import com.yahoo.config.provision.TenantName; import com.yahoo.config.provision.zone.ZoneId; @@ -403,9 +404,6 @@ public class ApplicationController { application = storeWithUpdatedConfig(application, applicationPackage); } - if (zone.environment().isProduction()) // Assign and register endpoints - application = withRotation(applicationPackage.deploymentSpec(), application, instance); - endpoints = registerEndpointsInDns(applicationPackage.deploymentSpec(), application.get().require(instanceId.instance()), zone); } // Release application lock while doing the deployment, which is a lengthy task. @@ -481,6 +479,11 @@ public class ApplicationController { application = application.with(name, instance -> withoutUnreferencedDeploymentJobs(deploymentSpec, instance)); } } + + for (InstanceName instance : declaredInstances) + if (applicationPackage.deploymentSpec().requireInstance(instance).deploysTo(Environment.prod)) + application = withRotation(applicationPackage.deploymentSpec(), application, instance); + store(application); return application; } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java index 246dd236b5a..dcadd992b32 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java @@ -84,14 +84,13 @@ public class Controller extends AbstractComponent implements ApplicationIdSource MavenRepository mavenRepository, ServiceRegistry serviceRegistry) { this(curator, rotationsConfig, zoneRegistry, - Clock.systemUTC(), accessControl, + accessControl, com.yahoo.net.HostName::getLocalhost, flagSource, mavenRepository, serviceRegistry); } public Controller(CuratorDb curator, RotationsConfig rotationsConfig, ZoneRegistry zoneRegistry, - Clock clock, AccessControl accessControl, Supplier<String> hostnameSupplier, FlagSource flagSource, MavenRepository mavenRepository, @@ -101,7 +100,7 @@ public class Controller extends AbstractComponent implements ApplicationIdSource this.curator = Objects.requireNonNull(curator, "Curator cannot be null"); this.zoneRegistry = Objects.requireNonNull(zoneRegistry, "ZoneRegistry cannot be null"); this.serviceRegistry = Objects.requireNonNull(serviceRegistry, "ServiceRegistry cannot be null"); - this.clock = Objects.requireNonNull(clock, "Clock cannot be null"); + this.clock = Objects.requireNonNull(serviceRegistry.clock(), "Clock cannot be null"); this.flagSource = Objects.requireNonNull(flagSource, "FlagSource cannot be null"); this.mavenRepository = Objects.requireNonNull(mavenRepository, "MavenRepository cannot be null"); 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 efce8642294..c374787aaa4 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 @@ -31,7 +31,8 @@ import com.yahoo.vespa.hosted.controller.application.DeploymentMetrics; import com.yahoo.vespa.hosted.controller.application.JobStatus; import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder; import com.yahoo.vespa.hosted.controller.deployment.BuildJob; -import com.yahoo.vespa.hosted.controller.deployment.InternalDeploymentTester; +import com.yahoo.vespa.hosted.controller.deployment.DeploymentContext; +import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; import com.yahoo.vespa.hosted.controller.integration.ZoneApiMock; import com.yahoo.vespa.hosted.controller.rotation.RotationId; import com.yahoo.vespa.hosted.controller.rotation.RotationLock; @@ -67,7 +68,7 @@ import static org.junit.Assert.fail; */ public class ControllerTest { - private final InternalDeploymentTester tester = new InternalDeploymentTester(); + private final DeploymentTester tester = new DeploymentTester(); @Test public void testDeployment() { @@ -83,7 +84,7 @@ public class ControllerTest { var context = tester.deploymentContext(); context.submit(applicationPackage); assertEquals("Application version is known from completion of initial job", - ApplicationVersion.from(BuildJob.defaultSourceRevision, 1, "a@b", new Version("6.1"), Instant.ofEpochSecond(1)), + ApplicationVersion.from(DeploymentContext.defaultSourceRevision, 1, "a@b", new Version("6.1"), Instant.ofEpochSecond(1)), context.application().change().application().get()); context.runJob(systemTest); context.runJob(stagingTest); 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 e4d57075d24..351b139f747 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 @@ -86,42 +86,37 @@ public final class ControllerTester { private Controller controller; - public ControllerTester(ManualClock clock, RotationsConfig rotationsConfig, MockCuratorDb curatorDb) { + public ControllerTester(RotationsConfig rotationsConfig, MockCuratorDb curatorDb) { this(new AthenzDbMock(), - clock, new ZoneRegistryMock(), curatorDb, rotationsConfig, new ServiceRegistryMock()); } - public ControllerTester(ManualClock clock) { - this(clock, defaultRotationsConfig(), new MockCuratorDb()); - } - public ControllerTester(RotationsConfig rotationsConfig) { - this(new ManualClock(), rotationsConfig, new MockCuratorDb()); + this(rotationsConfig, new MockCuratorDb()); } public ControllerTester(MockCuratorDb curatorDb) { - this(new ManualClock(), defaultRotationsConfig(), curatorDb); + this(defaultRotationsConfig(), curatorDb); } public ControllerTester() { - this(new ManualClock()); + this(defaultRotationsConfig(), new MockCuratorDb()); } - private ControllerTester(AthenzDbMock athenzDb, ManualClock clock, + private ControllerTester(AthenzDbMock athenzDb, ZoneRegistryMock zoneRegistry, CuratorDb curator, RotationsConfig rotationsConfig, - ServiceRegistryMock serviceRegistry) { + ServiceRegistryMock serviceRegistry, Controller controller) { this.athenzDb = athenzDb; - this.clock = clock; + this.clock = serviceRegistry.clock(); this.zoneRegistry = zoneRegistry; this.serviceRegistry = serviceRegistry; this.curator = curator; this.rotationsConfig = rotationsConfig; - this.controller = createController(curator, rotationsConfig, clock, zoneRegistry, athenzDb, serviceRegistry); + this.controller = controller; // Make root logger use time from manual clock configureDefaultLogHandler(handler -> handler.setFilter( @@ -131,6 +126,14 @@ public final class ControllerTester { })); } + private ControllerTester(AthenzDbMock athenzDb, + ZoneRegistryMock zoneRegistry, + CuratorDb curator, RotationsConfig rotationsConfig, + ServiceRegistryMock serviceRegistry) { + this(athenzDb, zoneRegistry, curator, rotationsConfig, serviceRegistry, + createController(curator, rotationsConfig, zoneRegistry, athenzDb, serviceRegistry)); + } + public void configureDefaultLogHandler(Consumer<Handler> configureFunc) { Arrays.stream(Logger.getLogger("").getHandlers()) // Do not mess with log configuration if a custom one has been set @@ -176,8 +179,7 @@ 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(curator, rotationsConfig, clock, zoneRegistry, athenzDb, - serviceRegistry); + controller = createController(curator, rotationsConfig, zoneRegistry, athenzDb, serviceRegistry); } /** Creates the given tenant and application and deploys it */ @@ -351,14 +353,12 @@ public final class ControllerTester { } private static Controller createController(CuratorDb curator, RotationsConfig rotationsConfig, - ManualClock clock, ZoneRegistryMock zoneRegistryMock, AthenzDbMock athensDb, ServiceRegistryMock serviceRegistry) { Controller controller = new Controller(curator, rotationsConfig, zoneRegistryMock, - clock, new AthenzFacade(new AthenzClientFactoryMock(athensDb)), () -> "test-controller", new InMemoryFlagSource(), diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/BuildJob.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/BuildJob.java index ce733d60a77..63d84926144 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/BuildJob.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/BuildJob.java @@ -17,22 +17,14 @@ import java.util.function.Consumer; import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.component; -/** - * Create a build job for testing purposes. In most cases this should be constructed by calling - * {@link DeploymentTester#jobCompletion(JobType)} or {@link ContainerControllerTester#jobCompletion(JobType)}. - * - * @author mpolden - */ public class BuildJob { - public static final SourceRevision defaultSourceRevision = new SourceRevision("repository1", - "master", "commit1"); public static final long defaultBuildNumber = 42; private JobType job; private ApplicationId applicationId; private Optional<DeploymentJobs.JobError> jobError = Optional.empty(); - private Optional<SourceRevision> sourceRevision = Optional.of(defaultSourceRevision); + private Optional<SourceRevision> sourceRevision = Optional.of(DeploymentContext.defaultSourceRevision); private long projectId; private long buildNumber = defaultBuildNumber; diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java index a8e7d96710f..a5840cea3bd 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java @@ -57,10 +57,10 @@ import static org.junit.Assert.assertTrue; * A deployment context for an application. This allows fine-grained control of the deployment of an application's * instances. * - * References to this should be acquired through {@link InternalDeploymentTester#deploymentContext}. + * References to this should be acquired through {@link DeploymentTester#deploymentContext}. * * Tester code that is not specific to deployments should be added to either {@link ControllerTester} or - * {@link InternalDeploymentTester} instead of this class. + * {@link DeploymentTester} instead of this class. * * @author mpolden */ @@ -83,6 +83,7 @@ public class DeploymentContext { .emailAddress("b@a") .trust(generateCertificate()) .build(); + public static final SourceRevision defaultSourceRevision = new SourceRevision("repository1", "master", "commit1"); private final TenantAndApplicationId applicationId; private final ApplicationId instanceId; @@ -98,7 +99,7 @@ public class DeploymentContext { private ApplicationVersion lastSubmission = null; private boolean deferDnsUpdates = false; - public DeploymentContext(ApplicationId instanceId, InternalDeploymentTester tester) { + public DeploymentContext(ApplicationId instanceId, DeploymentTester tester) { this.applicationId = TenantAndApplicationId.from(instanceId); this.instanceId = instanceId; @@ -196,7 +197,7 @@ public class DeploymentContext { /** Submit given application package for deployment */ public DeploymentContext submit(ApplicationPackage applicationPackage) { - return submit(applicationPackage, BuildJob.defaultSourceRevision); + return submit(applicationPackage, defaultSourceRevision); } /** Submit given application package for deployment */ @@ -274,10 +275,15 @@ public class DeploymentContext { return this; } + /** Runs a deployment of the given package to the given dev/perf job, on the given version. */ + public DeploymentContext runJob(JobType type, ApplicationPackage applicationPackage, Version vespaVersion) { + jobs.deploy(instanceId, type, Optional.ofNullable(vespaVersion), applicationPackage); + return runJob(type); + } + /** Runs a deployment of the given package to the given dev/perf job. */ public DeploymentContext runJob(JobType type, ApplicationPackage applicationPackage) { - jobs.deploy(instanceId, type, Optional.empty(), applicationPackage); - return runJob(type); + return runJob(type, applicationPackage, null); } /** Pulls the ready job trigger, and then runs the whole of the given job, successfully. */ 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 582333154a2..0ca035b85b2 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 @@ -1,27 +1,31 @@ -// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// 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.deployment; import com.yahoo.component.Version; import com.yahoo.config.provision.ApplicationId; -import com.yahoo.config.provision.Environment; -import com.yahoo.config.provision.InstanceName; -import com.yahoo.config.provision.TenantName; +import com.yahoo.config.provision.zone.ZoneId; +import com.yahoo.log.LogLevel; 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.Controller; import com.yahoo.vespa.hosted.controller.ControllerTester; import com.yahoo.vespa.hosted.controller.Instance; +import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId; +import com.yahoo.vespa.hosted.controller.api.integration.athenz.AthenzDbMock; +import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion; import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; -import com.yahoo.vespa.hosted.controller.api.integration.stubs.MockBuildService; +import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId; +import com.yahoo.vespa.hosted.controller.api.integration.deployment.SourceRevision; +import com.yahoo.vespa.hosted.controller.api.integration.deployment.TesterId; +import com.yahoo.vespa.hosted.controller.api.integration.routing.RoutingGeneratorMock; +import com.yahoo.vespa.hosted.controller.api.integration.stubs.MockTesterCloud; 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.JobStatus; -import com.yahoo.vespa.hosted.controller.application.SystemApplication; import com.yahoo.vespa.hosted.controller.application.TenantAndApplicationId; import com.yahoo.vespa.hosted.controller.integration.ConfigServerMock; import com.yahoo.vespa.hosted.controller.maintenance.JobControl; +import com.yahoo.vespa.hosted.controller.maintenance.JobRunner; +import com.yahoo.vespa.hosted.controller.maintenance.JobRunnerTest; import com.yahoo.vespa.hosted.controller.maintenance.NameServiceDispatcher; import com.yahoo.vespa.hosted.controller.maintenance.OutstandingChangeDeployer; import com.yahoo.vespa.hosted.controller.maintenance.ReadyJobsTrigger; @@ -31,54 +35,96 @@ import java.time.Duration; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; -import java.util.List; +import java.util.Collections; import java.util.Optional; -import java.util.UUID; +import java.util.logging.Logger; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; /** - * This class provides convenience methods for testing deployments - * - * @author bratseth - * @author mpolden + * @author jonmv */ 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 String ATHENZ_DOMAIN = "domain"; + private static final String ATHENZ_SERVICE = "service"; + + public static final TenantAndApplicationId appId = TenantAndApplicationId.from("tenant", "application"); + public static final ApplicationId instanceId = appId.defaultInstance(); + public static final TesterId testerId = TesterId.of(instanceId); + + private final DeploymentContext defaultContext; private final ControllerTester tester; + private final JobController jobs; + private final RoutingGeneratorMock routing; + private final MockTesterCloud cloud; + private final JobRunner runner; private final Upgrader upgrader; + private final ReadyJobsTrigger readyJobsTrigger; private final OutstandingChangeDeployer outstandingChangeDeployer; - private final ReadyJobsTrigger readyJobTrigger; private final NameServiceDispatcher nameServiceDispatcher; - private final boolean updateDnsAutomatically; + + public JobController jobs() { return jobs; } + public RoutingGeneratorMock routing() { return routing; } + public MockTesterCloud cloud() { return cloud; } + public JobRunner runner() { return runner; } + public ConfigServerMock configServer() { return tester.configServer(); } + public Controller controller() { return tester.controller(); } + public DeploymentTrigger deploymentTrigger() { return applications().deploymentTrigger(); } + public ControllerTester controllerTester() { return tester; } + public Upgrader upgrader() { return upgrader; } + public ApplicationController applications() { return tester.controller().applications(); } + public ManualClock clock() { return tester.clock(); } + public Application application() { return application(appId); } + public Application application(TenantAndApplicationId id ) { return applications().requireApplication(id); } + public Instance instance() { return instance(instanceId); } + public Instance instance(ApplicationId id) { return applications().requireInstance(id); } public DeploymentTester() { this(new ControllerTester()); } - public DeploymentTester(ControllerTester tester) { - this(tester, true); + public DeploymentTester(ControllerTester controllerTester) { + tester = controllerTester; + jobs = tester.controller().jobController(); + routing = tester.serviceRegistry().routingGeneratorMock(); + cloud = (MockTesterCloud) tester.controller().jobController().cloud(); + var jobControl = new JobControl(tester.controller().curator()); + runner = new JobRunner(tester.controller(), Duration.ofDays(1), jobControl, + JobRunnerTest.inThreadExecutor(), new InternalStepRunner(tester.controller())); + upgrader = new Upgrader(tester.controller(), maintenanceInterval, jobControl, tester.curator()); + upgrader.setUpgradesPerMinute(1); // Anything that makes it at least one for any maintenance period is fine. + readyJobsTrigger = new ReadyJobsTrigger(tester.controller(), maintenanceInterval, jobControl); + outstandingChangeDeployer = new OutstandingChangeDeployer(tester.controller(), maintenanceInterval, jobControl); + nameServiceDispatcher = new NameServiceDispatcher(tester.controller(), maintenanceInterval, jobControl, + Integer.MAX_VALUE); + defaultContext = newDeploymentContext(instanceId); + routing.putEndpoints(new DeploymentId(null, null), Collections.emptyList()); // Turn off default behaviour for the mock. + + // Get deployment job logs to stderr. + Logger.getLogger("").setLevel(LogLevel.DEBUG); + Logger.getLogger(InternalStepRunner.class.getName()).setLevel(LogLevel.DEBUG); + tester.configureDefaultLogHandler(handler -> handler.setLevel(LogLevel.DEBUG)); + + // Mock Athenz domain to allow launch of service + AthenzDbMock.Domain domain = tester.athenzDb().getOrCreateDomain(new com.yahoo.vespa.athenz.api.AthenzDomain(ATHENZ_DOMAIN)); + domain.services.put(ATHENZ_SERVICE, new AthenzDbMock.Service(true)); + } + + public ReadyJobsTrigger readyJobsTrigger() { + return readyJobsTrigger; } - public DeploymentTester(ControllerTester tester, boolean updateDnsAutomatically) { - this.tester = tester; - this.updateDnsAutomatically = updateDnsAutomatically; - tester.curator().writeUpgradesPerMinute(100); + public OutstandingChangeDeployer outstandingChangeDeployer() { return outstandingChangeDeployer; } - JobControl jobControl = new JobControl(tester.curator()); - this.upgrader = new Upgrader(tester.controller(), maintenanceInterval, jobControl, tester.curator()); - this.upgrader.setUpgradesPerMinute(1); // Anything that makes it at least one for any maintenance period is fine. - this.outstandingChangeDeployer = new OutstandingChangeDeployer(tester.controller(), maintenanceInterval, jobControl); - this.readyJobTrigger = new ReadyJobsTrigger(tester.controller(), maintenanceInterval, jobControl); - this.nameServiceDispatcher = new NameServiceDispatcher(tester.controller(), Duration.ofHours(12), - new JobControl(tester.controller().curator()), - Integer.MAX_VALUE); - atHourOfDay(5); // Set hour of day which always allows confidence to change + public NameServiceDispatcher nameServiceDispatcher() { + return nameServiceDispatcher; } public DeploymentTester atHourOfDay(int hour) { @@ -93,269 +139,158 @@ public class DeploymentTester { return this; } - public Upgrader upgrader() { return upgrader; } - - public OutstandingChangeDeployer outstandingChangeDeployer() { return outstandingChangeDeployer; } - - public ReadyJobsTrigger readyJobTrigger() { return readyJobTrigger; } - - public Controller controller() { return tester.controller(); } - - public ApplicationController applications() { return tester.controller().applications(); } - - public MockBuildService buildService() { return tester.serviceRegistry().buildServiceMock(); } - - public DeploymentTrigger deploymentTrigger() { return tester.controller().applications().deploymentTrigger(); } - - public ManualClock clock() { return tester.clock(); } - - public ControllerTester controllerTester() { return tester; } - - public ConfigServerMock configServer() { return tester.serviceRegistry().configServerMock(); } - - public Application application(TenantAndApplicationId id) { - return controller().applications().requireApplication(id); - } - - public Instance defaultInstance(String name) { - return instance(ApplicationId.from("tenant1", name, "default")); - } - - public Instance defaultInstance(TenantAndApplicationId application) { - return controller().applications().requireApplication(application).require(InstanceName.defaultName()); - } - - public Instance instance(ApplicationId application) { - return controller().applications().requireInstance(application); + /** Returns the default deployment context owned by this */ + public DeploymentContext deploymentContext() { + return defaultContext; } - // TODO(mpolden): Change callers to use ControllerTester#computeVersionStatus and remove this - public void computeVersionStatus() { - tester.computeVersionStatus(); + /** Create a new deployment context for given application */ + public DeploymentContext newDeploymentContext(String tenantName, String applicationName, String instanceName) { + return newDeploymentContext(ApplicationId.from(tenantName, applicationName, instanceName)); } - // TODO(mpolden): Change callers to use ControllerTester#upgradeController and remove this - public void upgradeController(Version version) { - tester.upgradeController(version); + /** Create a new deployment context for given application */ + public DeploymentContext newDeploymentContext(ApplicationId instance) { + return new DeploymentContext(instance, this); } - // TODO(mpolden): Change callers to use ControllerTester#upgradeController and remove this - public void upgradeController(Version version, String commitSha, Instant commitDate) { - tester.upgradeController(version, commitSha, commitDate); + /** Create a new application with given tenant and application name */ + public Application createApplication(String tenantName, String applicationName, String instanceName) { + return newDeploymentContext(tenantName, applicationName, instanceName).application(); } - // TODO(mpolden): Change callers to use ControllerTester#upgradeSystemApplications and remove this - public void upgradeSystemApplications(Version version) { - tester.upgradeSystemApplications(version); + /** Submits a new application, and returns the version of the new submission. */ + public ApplicationVersion newSubmission(TenantAndApplicationId id, ApplicationPackage applicationPackage, SourceRevision sourceRevision) { + return newDeploymentContext(id.defaultInstance()).submit(applicationPackage, sourceRevision).lastSubmission().get(); } - // TODO(mpolden): Change callers to use ControllerTester#upgradeSystemApplications and remove this - public void upgradeSystemApplications(Version version, List<SystemApplication> systemApplications) { - tester.upgradeSystemApplications(version, systemApplications); + public ApplicationVersion newSubmission(TenantAndApplicationId id, ApplicationPackage applicationPackage) { + return newSubmission(id, applicationPackage, DeploymentContext.defaultSourceRevision); } - // TODO(mpolden): Change callers to use ControllerTester#upgradeSystem and remove this - public void upgradeSystem(Version version) { - tester.upgradeSystem(version); - upgrader().maintain(); - readyJobTrigger().maintain(); + /** + * Submits a new application package, and returns the version of the new submission. + */ + public ApplicationVersion newSubmission(ApplicationPackage applicationPackage) { + return newSubmission(appId, applicationPackage); } - // TODO(mpolden): Change callers to use InternalDeploymentTester#flushDnsRequests and remove this - public void flushDnsRequests() { - nameServiceDispatcher.run(); - assertTrue("All name service requests dispatched", - controller().curator().readNameServiceQueue().requests().isEmpty()); + /** + * Submits a new application, and returns the version of the new submission. + */ + public ApplicationVersion newSubmission() { + return defaultContext.submit().lastSubmission().get(); } - /** Triggers jobs until nothing more triggers, and returns the number of triggered jobs. */ - public int triggerUntilQuiescence() { - int triggered = 0; - while (triggered != (triggered += deploymentTrigger().triggerReadyJobs())); - return triggered; - } - - public Application createApplication(String applicationName, String tenantName, long projectId, long propertyId) { - return createApplication("default", applicationName, tenantName, projectId, propertyId); - } - - public Application createApplication(String instanceName, String applicationName, String tenantName, long projectId, long propertyId) { - TenantName tenant = tester.createTenant(tenantName, UUID.randomUUID().toString(), propertyId); - return tester.createApplication(tenant, applicationName, instanceName, projectId); - } - - public void restartController() { tester.createNewController(); } - - /** Notify the controller about a job completing */ - public BuildJob jobCompletion(JobType job) { - return new BuildJob(this::notifyJobCompletion, tester.serviceRegistry().artifactRepositoryMock()).type(job); + /** + * Sets a single endpoint in the routing mock; this matches that required for the tester. + */ + public void setEndpoints(ApplicationId id, ZoneId zone) { + newDeploymentContext(id).setEndpoints(zone); } - /** Simulate the full lifecycle of an application deployment as declared in given application package */ - public Application createAndDeploy(String applicationName, int projectId, ApplicationPackage applicationPackage) { - TenantName tenant = tester.createTenant("tenant1", "domain1", 1L); - return createAndDeploy(tenant, applicationName, projectId, applicationPackage); + /** Completely deploys the given application version, assuming it is the last to be submitted. */ + public void deployNewSubmission(ApplicationVersion version) { + deployNewSubmission(appId, version); } - /** Simulate the full lifecycle of an application deployment as declared in given application package */ - public Application createAndDeploy(TenantName tenant, String applicationName, int projectId, ApplicationPackage applicationPackage) { - Application application = tester.createApplication(tenant, applicationName, "default", projectId); - deployCompletely(application, applicationPackage); - return applications().requireApplication(application.id()); + /** Completely deploys the given application version, assuming it is the last to be submitted. */ + public void deployNewSubmission(TenantAndApplicationId id, ApplicationVersion version) { + var context = newDeploymentContext(id.defaultInstance()); + var application = context.application(); + assertFalse(application.instances().values().stream() + .anyMatch(instance -> instance.deployments().values().stream() + .anyMatch(deployment -> deployment.applicationVersion().equals(version)))); + assertEquals(version, application.change().application().get()); + assertFalse(application.change().platform().isPresent()); + context.completeRollout(); + assertFalse(context.application().change().hasTargets()); } - /** Simulate the full lifecycle of an application deployment to prod.us-west-1 with the given upgrade policy */ - public Application createAndDeploy(String applicationName, int projectId, String upgradePolicy) { - return createAndDeploy(applicationName, projectId, applicationPackage(upgradePolicy)); + /** Completely deploys the given, new platform. */ + public void deployNewPlatform(Version version) { + deployNewPlatform(appId, version); } - /** Simulate the full lifecycle of an application deployment to prod.us-west-1 with the given upgrade policy */ - public void createAndDeploy(TenantName tenant, String applicationName, int projectId, String upgradePolicy) { - createAndDeploy(tenant, applicationName, projectId, applicationPackage(upgradePolicy)); + /** Completely deploys the given, new platform. */ + public void deployNewPlatform(TenantAndApplicationId id, Version version) { + newDeploymentContext(id.defaultInstance()).deployPlatform(version); } - /** Deploy application completely using the given application package */ - public void deployCompletely(Application application, ApplicationPackage applicationPackage) { - deployCompletely(application, applicationPackage, BuildJob.defaultBuildNumber); - } - - public void completeDeploymentWithError(Application application, ApplicationPackage applicationPackage, long buildNumber, JobType failOnJob) { - jobCompletion(JobType.component).application(application) - .buildNumber(buildNumber) - .uploadArtifact(applicationPackage) - .submit(); - completeDeployment(application, applicationPackage, Optional.ofNullable(failOnJob)); - } - - public void deployCompletely(Application application, ApplicationPackage applicationPackage, long buildNumber) { - completeDeploymentWithError(application, applicationPackage, buildNumber, null); - } - - private void completeDeployment(Application application, ApplicationPackage applicationPackage, Optional<JobType> failOnJob) { - assertTrue(application.id() + " has pending changes to deploy", applications().requireApplication(application.id()).change().hasTargets()); - DeploymentSteps steps = controller().applications().deploymentTrigger().steps(applicationPackage.deploymentSpec()); - List<JobType> jobs = steps.jobs(); - // TODO jonmv: Change to list instances here. - for (JobType job : jobs) { - boolean failJob = failOnJob.map(j -> j.equals(job)).orElse(false); - deployAndNotify(application.id().defaultInstance(), applicationPackage, ! failJob, job); - if (failJob) { - break; - } - } - if (failOnJob.isPresent()) { - assertTrue(applications().requireApplication(application.id()).change().hasTargets()); - assertTrue(defaultInstance(application.id()).deploymentJobs().hasFailures()); - } else { - assertFalse(applications().requireApplication(application.id()).change().hasTargets()); + /** Aborts and finishes all running jobs. */ + public void abortAll() { + triggerJobs(); + for (Run run : jobs.active()) { + jobs.abort(run.id()); + runner.advance(jobs.run(run.id()).get()); + assertTrue(jobs.run(run.id()).get().hasEnded()); } - if (updateDnsAutomatically) { - flushDnsRequests(); - } - } - - public void completeUpgrade(Application application, Version version, String upgradePolicy) { - completeUpgrade(application, version, applicationPackage(upgradePolicy)); - } - - public void completeUpgrade(Application application, Version version, ApplicationPackage applicationPackage) { - assertTrue(application + " has a change", applications().requireApplication(application.id()).change().hasTargets()); - assertEquals(Change.of(version), applications().requireApplication(application.id()).change()); - completeDeployment(application, applicationPackage, Optional.empty()); - } - - public void completeUpgradeWithError(Application application, Version version, String upgradePolicy, JobType failOnJob) { - completeUpgradeWithError(application, version, applicationPackage(upgradePolicy), Optional.of(failOnJob)); - } - - public void completeUpgradeWithError(Application application, Version version, ApplicationPackage applicationPackage, JobType failOnJob) { - completeUpgradeWithError(application, version, applicationPackage, Optional.of(failOnJob)); } - private void completeUpgradeWithError(Application application, Version version, ApplicationPackage applicationPackage, Optional<JobType> failOnJob) { - assertTrue(applications().requireApplication(application.id()).change().hasTargets()); - assertEquals(Change.of(version), applications().requireApplication(application.id()).change()); - completeDeployment(application, applicationPackage, failOnJob); + /** Triggers jobs until nothing more triggers, and returns the number of triggered jobs. */ + public int triggerJobs() { + int triggered = 0; + while (triggered != (triggered += deploymentTrigger().triggerReadyJobs())); + return triggered; } - public void deploy(JobType job, ApplicationId id, ApplicationPackage applicationPackage) { - deploy(job, id, Optional.of(applicationPackage), false); + /** Starts a manual deployment of the given package, and then runs the whole of the given job, successfully. */ + public void runJob(ApplicationId instanceId, JobType type, ApplicationPackage applicationPackage) { + jobs.deploy(instanceId, type, Optional.empty(), applicationPackage); + newDeploymentContext(instanceId).runJob(type); } - public void deploy(JobType job, ApplicationId id, ApplicationPackage applicationPackage, - boolean deployCurrentVersion) { - deploy(job, id, Optional.of(applicationPackage), deployCurrentVersion); + /** Pulls the ready job trigger, and then runs the whole of the given job, successfully. */ + public void runJob(JobType type) { + defaultContext.runJob(type); } - public void deploy(JobType job, ApplicationId id, Optional<ApplicationPackage> applicationPackage, - boolean deployCurrentVersion) { - tester.deploy(id, job.zone(controller().system()), applicationPackage, deployCurrentVersion); + /** Pulls the ready job trigger, and then runs the whole of the given job, successfully. */ + public void runJob(ApplicationId instanceId, JobType type) { + if (type.environment().isManuallyDeployed()) + throw new IllegalArgumentException("Use overload with application package for dev/perf jobs"); + newDeploymentContext(instanceId).runJob(type); } - public void deployAndNotify(Instance i, String upgradePolicy, boolean success, JobType job) { - deployAndNotify(i.id(), applicationPackage(upgradePolicy), success, job); + public void failDeployment(JobType type) { + defaultContext.failDeployment(type); } - public void deployAndNotify(ApplicationId id, ApplicationPackage applicationPackage, boolean success, JobType job) { - deployAndNotify(id, Optional.of(applicationPackage), success, job); + public void failDeployment(ApplicationId instanceId, JobType type) { + newDeploymentContext(instanceId).failDeployment(type); } - public void deployAndNotify(Instance i, boolean success, JobType job) { - deployAndNotify(i.id(), Optional.empty(), success, job); - } - public void deployAndNotify(ApplicationId id, boolean success, JobType job) { - deployAndNotify(id, Optional.empty(), success, job); + public void timeOutUpgrade(JobType type) { + defaultContext.timeOutUpgrade(type); } - public void deployAndNotify(ApplicationId id, Optional<ApplicationPackage> applicationPackage, boolean success, JobType job) { - if (success) { - // Staging deploys twice, once with current version and once with new version - if (job == JobType.stagingTest) { - deploy(job, id, applicationPackage, true); - } - deploy(job, id, applicationPackage, false); - } - // Deactivate test deployments after deploy. This replicates the behaviour of the tenant pipeline - if (job.isTest()) { - controller().applications().deactivate(id, job.zone(controller().system())); - } - jobCompletion(job).application(id).success(success).submit(); + public void timeOutUpgrade(ApplicationId instanceId, JobType type) { + newDeploymentContext(instanceId).timeOutConvergence(type); } - public Optional<JobStatus.JobRun> firstFailing(Instance instance, JobType job) { - return tester.controller().applications().requireInstance(instance.id()) - .deploymentJobs().jobStatus().get(job).firstFailing(); + public void timeOutConvergence(JobType type) { + defaultContext.timeOutConvergence(type); } - private void notifyJobCompletion(DeploymentJobs.JobReport report) { - if (report.jobType() != JobType.component && ! buildService().remove(report.buildJob())) - throw new IllegalArgumentException(report.jobType() + " is not running for " + report.applicationId()); - assertFalse("Unexpected entry '" + report.jobType() + "@" + report.projectId() + " in: " + buildService().jobs(), - buildService().remove(report.buildJob())); - - applications().deploymentTrigger().notifyOfCompletion(report); - applications().deploymentTrigger().triggerReadyJobs(); + public void timeOutConvergence(ApplicationId instanceId, JobType type) { + newDeploymentContext(instanceId).timeOutConvergence(type); } - public static ApplicationPackage applicationPackage(String upgradePolicy) { - return new ApplicationPackageBuilder() - .upgradePolicy(upgradePolicy) - .environment(Environment.prod) - .region("us-west-1") - .region("us-east-3") - .build(); + public RunId startSystemTestTests() { + return defaultContext.startSystemTestTests(); } - public void assertRunning(JobType job, ApplicationId application) { - assertTrue(String.format("Job %s for %s is running", job, application), isRunning(job, application)); + /** Creates and submits a new application, and then starts the job of the given type. Use only once per test. */ + public RunId newRun(JobType type) { + return defaultContext.newRun(type); } - public void assertNotRunning(JobType job, ApplicationId application) { - assertFalse(String.format("Job %s for %s is not running", job, application), isRunning(job, application)); + public void assertRunning(JobType type) { + assertRunning(instanceId, type); } - private boolean isRunning(JobType job, ApplicationId application) { - return buildService().jobs().contains(ControllerTester.buildJob(instance(application).id(), job)); + public void assertRunning(ApplicationId id, JobType type) { + assertTrue(jobs.active().stream().anyMatch(run -> run.id().application().equals(id) && run.id().type() == type)); } } 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 09d93a5f857..07cddbe2c7e 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 @@ -3,28 +3,20 @@ package com.yahoo.vespa.hosted.controller.deployment; import com.yahoo.component.Version; import com.yahoo.config.provision.Environment; -import com.yahoo.config.provision.InstanceName; import com.yahoo.config.provision.zone.ZoneId; -import com.yahoo.vespa.hosted.controller.Application; -import com.yahoo.vespa.hosted.controller.Instance; import com.yahoo.vespa.hosted.controller.api.application.v4.model.DeployOptions; -import com.yahoo.vespa.hosted.controller.api.integration.BuildService; import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion; import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId; -import com.yahoo.vespa.hosted.controller.api.integration.stubs.MockBuildService; 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.versions.VespaVersion; import org.junit.Ignore; import org.junit.Test; import java.time.Duration; import java.time.Instant; -import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Optional; @@ -32,8 +24,6 @@ import java.util.OptionalLong; import java.util.stream.Collectors; import static com.yahoo.config.provision.SystemName.main; -import static com.yahoo.vespa.hosted.controller.ControllerTester.buildJob; -import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.component; import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.productionEuWest1; import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.productionUsCentral1; import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.productionUsEast3; @@ -42,7 +32,6 @@ import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobTy import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.systemTest; import static com.yahoo.vespa.hosted.controller.deployment.DeploymentTrigger.ChangesToCancel.ALL; import static com.yahoo.vespa.hosted.controller.deployment.DeploymentTrigger.ChangesToCancel.PLATFORM; -import static com.yahoo.vespa.hosted.controller.deployment.InternalDeploymentTester.appId; import static java.time.temporal.ChronoUnit.MILLIS; import static java.util.Collections.emptyList; import static org.junit.Assert.assertEquals; @@ -59,7 +48,7 @@ import static org.junit.Assert.assertTrue; */ public class DeploymentTriggerTest { - private final InternalDeploymentTester tester = new InternalDeploymentTester(); + private final DeploymentTester tester = new DeploymentTester(); @Test public void testTriggerFailing() { @@ -104,12 +93,13 @@ public class DeploymentTriggerTest { assertEquals("Job is not triggered when no projectId is present", 0, tester.jobs().active().size()); } + /* @Test @Ignore // TODO jonmv: Re-enable, but changed, when instances are orchestrated. public void testIndependentInstances() { - Application app1 = tester.tester().createApplication("instance1", "app", "tenant", 1, 1L); - Application app2 = tester.tester().createApplication("instance2", "app", "tenant", 2, 1L); + var app1 = tester.tester().createApplication("instance1", "app", "tenant", 1, 1L); + var app2 = tester.tester().createApplication("instance2", "app", "tenant", 2, 1L); Instance instance1 = tester.tester().instance(app1.id().instance(InstanceName.from("instance1"))); Instance instance2 = tester.tester().instance(app2.id().instance(InstanceName.from("instance2"))); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() @@ -147,6 +137,7 @@ public class DeploymentTriggerTest { assertEquals(newVersion, instance1Version); assertEquals(version, instance2Version); } + */ @Test public void abortsJobsOnNewApplicationChange() { @@ -201,11 +192,11 @@ public class DeploymentTriggerTest { // Test jobs pass app.runJob(systemTest).runJob(stagingTest); - tester.tester().deploymentTrigger().triggerReadyJobs(); + tester.triggerJobs(); // No jobs have started yet, as 30 seconds have not yet passed. assertEquals(0, tester.jobs().active().size()); - tester.tester().clock().advance(Duration.ofSeconds(30)); + tester.clock().advance(Duration.ofSeconds(30)); tester.triggerJobs(); // 30 seconds later, the first jobs may trigger. @@ -213,7 +204,7 @@ public class DeploymentTriggerTest { app.assertRunning(productionUsWest1); // 3 minutes pass, delayed trigger does nothing as us-west-1 is still in progress - tester.tester().clock().advance(Duration.ofMinutes(3)); + tester.clock().advance(Duration.ofMinutes(3)); tester.triggerJobs(); assertEquals(1, tester.jobs().active().size()); app.assertRunning(productionUsWest1); @@ -226,18 +217,18 @@ public class DeploymentTriggerTest { assertTrue("No more jobs triggered at this time", tester.jobs().active().isEmpty()); // 3 minutes pass, us-central-1 is still not triggered - tester.tester().clock().advance(Duration.ofMinutes(3)); + tester.clock().advance(Duration.ofMinutes(3)); tester.triggerJobs(); assertTrue("No more jobs triggered at this time", tester.jobs().active().isEmpty()); // 4 minutes pass, us-central-1 is triggered - tester.tester().clock().advance(Duration.ofMinutes(1)); + tester.clock().advance(Duration.ofMinutes(1)); tester.triggerJobs(); app.runJob(productionUsCentral1); assertTrue("All jobs consumed", tester.jobs().active().isEmpty()); // Delayed trigger job runs again, with nothing to trigger - tester.tester().clock().advance(Duration.ofMinutes(10)); + tester.clock().advance(Duration.ofMinutes(10)); tester.triggerJobs(); assertTrue("All jobs consumed", tester.jobs().active().isEmpty()); } @@ -423,15 +414,15 @@ public class DeploymentTriggerTest { app.assertNotRunning(productionUsWest1); // us-west-1 triggers when no longer paused, but does not retry when paused again. - tester.tester().clock().advance(Duration.ofMillis(1500)); + tester.clock().advance(Duration.ofMillis(1500)); tester.triggerJobs(); app.assertRunning(productionUsWest1); - tester.deploymentTrigger().pauseJob(app.instanceId(), productionUsWest1, tester.tester().clock().instant().plus(Duration.ofSeconds(1))); + tester.deploymentTrigger().pauseJob(app.instanceId(), productionUsWest1, tester.clock().instant().plus(Duration.ofSeconds(1))); app.failDeployment(productionUsWest1); tester.triggerJobs(); app.assertNotRunning(productionUsWest1); - tester.tester().clock().advance(Duration.ofMillis(1000)); + tester.clock().advance(Duration.ofMillis(1000)); tester.triggerJobs(); app.runJob(productionUsWest1); @@ -466,7 +457,7 @@ public class DeploymentTriggerTest { assertEquals(Change.of(appVersion1), app.application().change()); // Now cancel the change as is done through the web API. - tester.tester().deploymentTrigger().cancelChange(app.application().id(), ALL); + tester.deploymentTrigger().cancelChange(app.application().id(), ALL); assertEquals(Change.empty(), app.application().change()); // A new version is released, which should now deploy the currently deployed application version to avoid downgrades. @@ -681,13 +672,13 @@ public class DeploymentTriggerTest { initialFailure, app.instance().deploymentJobs().jobStatus().get(systemTest).firstFailing().get().at()); // Failure again -- failingSince should remain the same - tester.tester().clock().advance(Duration.ofMillis(1000)); + tester.clock().advance(Duration.ofMillis(1000)); app.failDeployment(systemTest); assertEquals("Failure age is right at second consecutive failure", initialFailure, app.instance().deploymentJobs().jobStatus().get(systemTest).firstFailing().get().at()); // Success resets failingSince - tester.tester().clock().advance(Duration.ofMillis(1000)); + tester.clock().advance(Duration.ofMillis(1000)); app.runJob(systemTest); assertFalse(app.instance().deploymentJobs().jobStatus().get(systemTest).firstFailing().isPresent()); @@ -696,8 +687,8 @@ public class DeploymentTriggerTest { // Two repeated failures again. // Initial failure - tester.tester().clock().advance(Duration.ofMillis(1000)); - initialFailure = tester.tester().clock().instant().truncatedTo(MILLIS); + tester.clock().advance(Duration.ofMillis(1000)); + initialFailure = tester.clock().instant().truncatedTo(MILLIS); app.submit(applicationPackage); app.failDeployment(systemTest); @@ -705,7 +696,7 @@ public class DeploymentTriggerTest { initialFailure, app.instance().deploymentJobs().jobStatus().get(systemTest).firstFailing().get().at()); // Failure again -- failingSince should remain the same - tester.tester().clock().advance(Duration.ofMillis(1000)); + tester.clock().advance(Duration.ofMillis(1000)); app.failDeployment(systemTest); assertEquals("Failure age is right at second consecutive failure", initialFailure, app.instance().deploymentJobs().jobStatus().get(systemTest).firstFailing().get().at()); @@ -767,10 +758,10 @@ public class DeploymentTriggerTest { // all applications: system-test completes successfully with some time in between, to determine trigger order. app2.runJob(systemTest); - tester.tester().clock().advance(Duration.ofMinutes(1)); + tester.clock().advance(Duration.ofMinutes(1)); app1.runJob(systemTest); - tester.tester().clock().advance(Duration.ofMinutes(1)); + tester.clock().advance(Duration.ofMinutes(1)); app3.runJob(systemTest); @@ -879,8 +870,8 @@ public class DeploymentTriggerTest { .build(); var app = tester.deploymentContext().submit(applicationPackage); // TODO jonmv: support instances in deployment context> app.deploy(); - assertEquals(2, tester.tester().application(appId).instances().size()); - assertEquals(2, tester.tester().application(appId).productionDeployments().values().stream() + assertEquals(2, app.application().instances().size()); + assertEquals(2, app.application().productionDeployments().values().stream() .mapToInt(Collection::size) .sum()); } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalDeploymentTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalDeploymentTester.java deleted file mode 100644 index d8261d2d79f..00000000000 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalDeploymentTester.java +++ /dev/null @@ -1,295 +0,0 @@ -// 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.deployment; - -import com.yahoo.component.Version; -import com.yahoo.config.provision.ApplicationId; -import com.yahoo.config.provision.zone.ZoneId; -import com.yahoo.log.LogLevel; -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.Controller; -import com.yahoo.vespa.hosted.controller.ControllerTester; -import com.yahoo.vespa.hosted.controller.Instance; -import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId; -import com.yahoo.vespa.hosted.controller.api.integration.athenz.AthenzDbMock; -import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion; -import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; -import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId; -import com.yahoo.vespa.hosted.controller.api.integration.deployment.SourceRevision; -import com.yahoo.vespa.hosted.controller.api.integration.deployment.TesterId; -import com.yahoo.vespa.hosted.controller.api.integration.routing.RoutingGeneratorMock; -import com.yahoo.vespa.hosted.controller.api.integration.stubs.MockTesterCloud; -import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; -import com.yahoo.vespa.hosted.controller.application.TenantAndApplicationId; -import com.yahoo.vespa.hosted.controller.integration.ConfigServerMock; -import com.yahoo.vespa.hosted.controller.maintenance.JobControl; -import com.yahoo.vespa.hosted.controller.maintenance.JobRunner; -import com.yahoo.vespa.hosted.controller.maintenance.JobRunnerTest; -import com.yahoo.vespa.hosted.controller.maintenance.NameServiceDispatcher; -import com.yahoo.vespa.hosted.controller.maintenance.OutstandingChangeDeployer; -import com.yahoo.vespa.hosted.controller.maintenance.ReadyJobsTrigger; -import com.yahoo.vespa.hosted.controller.maintenance.Upgrader; - -import java.time.Duration; -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.ZoneOffset; -import java.util.Collections; -import java.util.Optional; -import java.util.logging.Logger; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - -/** - * @author jonmv - */ -public class InternalDeploymentTester { - - // Set a long interval so that maintainers never do scheduled runs during tests - private static final Duration maintenanceInterval = Duration.ofDays(1); - - private static final String ATHENZ_DOMAIN = "domain"; - private static final String ATHENZ_SERVICE = "service"; - - public static final TenantAndApplicationId appId = TenantAndApplicationId.from("tenant", "application"); - public static final ApplicationId instanceId = appId.defaultInstance(); - public static final TesterId testerId = TesterId.of(instanceId); - public static final String athenzDomain = "domain"; - - private final DeploymentContext defaultContext; - private final DeploymentTester tester; - private final JobController jobs; - private final RoutingGeneratorMock routing; - private final MockTesterCloud cloud; - private final JobRunner runner; - private final ReadyJobsTrigger readyJobsTrigger; - private final OutstandingChangeDeployer outstandingChangeDeployer; - private final NameServiceDispatcher nameServiceDispatcher; - - public DeploymentTester tester() { return tester; } - public JobController jobs() { return jobs; } - public RoutingGeneratorMock routing() { return routing; } - public MockTesterCloud cloud() { return cloud; } - public JobRunner runner() { return runner; } - public ConfigServerMock configServer() { return tester.configServer(); } - public Controller controller() { return tester.controller(); } - public DeploymentTrigger deploymentTrigger() { return tester.deploymentTrigger(); } - public ControllerTester controllerTester() { return tester.controllerTester(); } - public Upgrader upgrader() { return tester.upgrader(); } - public ApplicationController applications() { return tester.applications(); } - public ManualClock clock() { return tester.clock(); } - public Application application() { return tester.application(appId); } - public Application application(TenantAndApplicationId id ) { return tester.application(id); } - public Instance instance() { return tester.instance(instanceId); } - public Instance instance(ApplicationId id) { return tester.instance(id); } - - public InternalDeploymentTester() { - this(new ControllerTester()); - } - - public InternalDeploymentTester(ControllerTester controllerTester) { - tester = new DeploymentTester(controllerTester); - jobs = tester.controller().jobController(); - routing = tester.controllerTester().serviceRegistry().routingGeneratorMock(); - cloud = (MockTesterCloud) tester.controller().jobController().cloud(); - var jobControl = new JobControl(tester.controller().curator()); - runner = new JobRunner(tester.controller(), Duration.ofDays(1), jobControl, - JobRunnerTest.inThreadExecutor(), new InternalStepRunner(tester.controller())); - readyJobsTrigger = new ReadyJobsTrigger(tester.controller(), maintenanceInterval, jobControl); - outstandingChangeDeployer = new OutstandingChangeDeployer(tester.controller(), maintenanceInterval, jobControl); - nameServiceDispatcher = new NameServiceDispatcher(tester.controller(), maintenanceInterval, jobControl, - Integer.MAX_VALUE); - defaultContext = newDeploymentContext(instanceId); - routing.putEndpoints(new DeploymentId(null, null), Collections.emptyList()); // Turn off default behaviour for the mock. - - // Get deployment job logs to stderr. - Logger.getLogger("").setLevel(LogLevel.DEBUG); - Logger.getLogger(InternalStepRunner.class.getName()).setLevel(LogLevel.DEBUG); - tester.controllerTester().configureDefaultLogHandler(handler -> handler.setLevel(LogLevel.DEBUG)); - - // Mock Athenz domain to allow launch of service - AthenzDbMock.Domain domain = tester.controllerTester().athenzDb().getOrCreateDomain(new com.yahoo.vespa.athenz.api.AthenzDomain(ATHENZ_DOMAIN)); - domain.services.put(ATHENZ_SERVICE, new AthenzDbMock.Service(true)); - } - - public ReadyJobsTrigger readyJobsTrigger() { - return readyJobsTrigger; - } - - public OutstandingChangeDeployer outstandingChangeDeployer() { return outstandingChangeDeployer; } - - public NameServiceDispatcher nameServiceDispatcher() { - return nameServiceDispatcher; - } - - public InternalDeploymentTester atHourOfDay(int hour) { - var dateTime = tester.clock().instant().atZone(ZoneOffset.UTC); - return at(LocalDateTime.of(dateTime.getYear(), dateTime.getMonth(), dateTime.getDayOfMonth(), hour, - dateTime.getMinute(), dateTime.getSecond()) - .toInstant(ZoneOffset.UTC)); - } - - public InternalDeploymentTester at(Instant instant) { - tester.clock().setInstant(instant); - return this; - } - - /** Returns the default deployment context owned by this */ - public DeploymentContext deploymentContext() { - return defaultContext; - } - - /** Create a new deployment context for given application */ - public DeploymentContext newDeploymentContext(String tenantName, String applicationName, String instanceName) { - return newDeploymentContext(ApplicationId.from(tenantName, applicationName, instanceName)); - } - - /** Create a new deployment context for given application */ - public DeploymentContext newDeploymentContext(ApplicationId instance) { - return new DeploymentContext(instance, this); - } - - /** Create a new application with given tenant and application name */ - public Application createApplication(String tenantName, String applicationName, String instanceName) { - return newDeploymentContext(tenantName, applicationName, instanceName).application(); - } - - /** Submits a new application, and returns the version of the new submission. */ - public ApplicationVersion newSubmission(TenantAndApplicationId id, ApplicationPackage applicationPackage, SourceRevision sourceRevision) { - return newDeploymentContext(id.defaultInstance()).submit(applicationPackage, sourceRevision).lastSubmission().get(); - } - - public ApplicationVersion newSubmission(TenantAndApplicationId id, ApplicationPackage applicationPackage) { - return newSubmission(id, applicationPackage, BuildJob.defaultSourceRevision); - } - - /** - * Submits a new application package, and returns the version of the new submission. - */ - public ApplicationVersion newSubmission(ApplicationPackage applicationPackage) { - return newSubmission(appId, applicationPackage); - } - - /** - * Submits a new application, and returns the version of the new submission. - */ - public ApplicationVersion newSubmission() { - return defaultContext.submit().lastSubmission().get(); - } - - /** - * Sets a single endpoint in the routing mock; this matches that required for the tester. - */ - public void setEndpoints(ApplicationId id, ZoneId zone) { - newDeploymentContext(id).setEndpoints(zone); - } - - /** Completely deploys the given application version, assuming it is the last to be submitted. */ - public void deployNewSubmission(ApplicationVersion version) { - deployNewSubmission(appId, version); - } - - /** Completely deploys the given application version, assuming it is the last to be submitted. */ - public void deployNewSubmission(TenantAndApplicationId id, ApplicationVersion version) { - var context = newDeploymentContext(id.defaultInstance()); - var application = context.application(); - assertFalse(application.instances().values().stream() - .anyMatch(instance -> instance.deployments().values().stream() - .anyMatch(deployment -> deployment.applicationVersion().equals(version)))); - assertEquals(version, application.change().application().get()); - assertFalse(application.change().platform().isPresent()); - context.completeRollout(); - assertFalse(context.application().change().hasTargets()); - } - - /** Completely deploys the given, new platform. */ - public void deployNewPlatform(Version version) { - deployNewPlatform(appId, version); - } - - /** Completely deploys the given, new platform. */ - public void deployNewPlatform(TenantAndApplicationId id, Version version) { - newDeploymentContext(id.defaultInstance()).deployPlatform(version); - } - - /** Aborts and finishes all running jobs. */ - public void abortAll() { - triggerJobs(); - for (Run run : jobs.active()) { - jobs.abort(run.id()); - runner.advance(jobs.run(run.id()).get()); - assertTrue(jobs.run(run.id()).get().hasEnded()); - } - } - - /** Triggers jobs until nothing more triggers, and returns the number of triggered jobs. */ - public int triggerJobs() { - int triggered = 0; - while (triggered != (triggered += deploymentTrigger().triggerReadyJobs())); - return triggered; - } - - /** Starts a manual deployment of the given package, and then runs the whole of the given job, successfully. */ - public void runJob(ApplicationId instanceId, JobType type, ApplicationPackage applicationPackage) { - jobs.deploy(instanceId, type, Optional.empty(), applicationPackage); - newDeploymentContext(instanceId).runJob(type); - } - - /** Pulls the ready job trigger, and then runs the whole of the given job, successfully. */ - public void runJob(JobType type) { - defaultContext.runJob(type); - } - - /** Pulls the ready job trigger, and then runs the whole of the given job, successfully. */ - public void runJob(ApplicationId instanceId, JobType type) { - if (type.environment().isManuallyDeployed()) - throw new IllegalArgumentException("Use overload with application package for dev/perf jobs"); - newDeploymentContext(instanceId).runJob(type); - } - - public void failDeployment(JobType type) { - defaultContext.failDeployment(type); - } - - public void failDeployment(ApplicationId instanceId, JobType type) { - newDeploymentContext(instanceId).failDeployment(type); - } - - public void timeOutUpgrade(JobType type) { - defaultContext.timeOutUpgrade(type); - } - - public void timeOutUpgrade(ApplicationId instanceId, JobType type) { - newDeploymentContext(instanceId).timeOutConvergence(type); - } - - public void timeOutConvergence(JobType type) { - defaultContext.timeOutConvergence(type); - } - - public void timeOutConvergence(ApplicationId instanceId, JobType type) { - newDeploymentContext(instanceId).timeOutConvergence(type); - } - - public RunId startSystemTestTests() { - return defaultContext.startSystemTestTests(); - } - - /** Creates and submits a new application, and then starts the job of the given type. Use only once per test. */ - public RunId newRun(JobType type) { - return defaultContext.newRun(type); - } - - public void assertRunning(JobType type) { - assertRunning(instanceId, type); - } - - public void assertRunning(ApplicationId id, JobType type) { - assertTrue(jobs.active().stream().anyMatch(run -> run.id().application().equals(id) && run.id().type() == type)); - } - -} diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java index fc73af6acf7..7be2b6a9797 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java @@ -50,11 +50,10 @@ import java.util.concurrent.Future; import static com.yahoo.vespa.hosted.controller.api.integration.LogEntry.Type.error; import static com.yahoo.vespa.hosted.controller.api.integration.LogEntry.Type.info; import static com.yahoo.vespa.hosted.controller.api.integration.LogEntry.Type.warning; -import static com.yahoo.vespa.hosted.controller.deployment.InternalDeploymentTester.appId; -import static com.yahoo.vespa.hosted.controller.deployment.InternalDeploymentTester.instanceId; +import static com.yahoo.vespa.hosted.controller.deployment.DeploymentTester.instanceId; import static com.yahoo.vespa.hosted.controller.deployment.DeploymentContext.applicationPackage; import static com.yahoo.vespa.hosted.controller.deployment.DeploymentContext.publicCdApplicationPackage; -import static com.yahoo.vespa.hosted.controller.deployment.InternalDeploymentTester.testerId; +import static com.yahoo.vespa.hosted.controller.deployment.DeploymentTester.testerId; import static com.yahoo.vespa.hosted.controller.deployment.Step.Status.failed; import static com.yahoo.vespa.hosted.controller.deployment.Step.Status.succeeded; import static com.yahoo.vespa.hosted.controller.deployment.Step.Status.unfinished; @@ -70,52 +69,20 @@ import static org.junit.Assert.fail; */ public class InternalStepRunnerTest { - private InternalDeploymentTester tester; + private DeploymentTester tester; @Before public void setup() { - tester = new InternalDeploymentTester(); + tester = new DeploymentTester(); } private SystemName system() { - return tester.tester().controller().system(); + return tester.controller().system(); } @Test public void canRegisterAndRunDirectly() { - tester.deployNewSubmission(tester.newSubmission()); - - Version version = new Version("7.1"); - tester.tester().upgradeSystem(version); - tester.deployNewPlatform(version); - } - - @Test - public void canSwitchFromScrewdriverAndBackAgain() { - // Deploys a default application package with default build number. - tester.tester().deployCompletely(tester.application(), DeploymentContext.applicationPackage); - tester.setEndpoints(instanceId, JobType.productionUsCentral1.zone(system())); - tester.setEndpoints(instanceId, JobType.productionUsWest1.zone(system())); - tester.setEndpoints(instanceId, JobType.productionUsEast3.zone(system())); - - // Let application have an ongoing upgrade when it switches (but kill the jobs, as the tester assumes they aren't running). - tester.tester().upgradeSystem(new Version("7.1")); - tester.tester().buildService().clear(); - - tester.deployNewSubmission(tester.newSubmission()); - tester.deployNewSubmission(tester.newSubmission()); - - Version version = new Version("7.2"); - tester.tester().upgradeSystem(version); - tester.deployNewPlatform(version); - - tester.jobs().unregister(appId); - try { - tester.tester().deployCompletely(tester.application(), DeploymentContext.applicationPackage, BuildJob.defaultBuildNumber + 1); - throw new IllegalStateException("Component job should get even again with build numbers to produce a change."); - } - catch (AssertionError expected) { } - tester.tester().deployCompletely(tester.application(), DeploymentContext.applicationPackage, BuildJob.defaultBuildNumber + 2); + tester.deploymentContext().submit().deploy(); } @Test @@ -123,7 +90,7 @@ public class InternalStepRunnerTest { tester.newRun(JobType.stagingTest); tester.runner().run(); DeploymentSpec spec = tester.configServer() - .application(InternalDeploymentTester.testerId.id(), JobType.stagingTest.zone(system())).get() + .application(DeploymentTester.testerId.id(), JobType.stagingTest.zone(system())).get() .applicationPackage().deploymentSpec(); assertEquals("domain", spec.athenzDomain().get().value()); ZoneId zone = JobType.stagingTest.zone(system()); @@ -247,13 +214,13 @@ public class InternalStepRunnerTest { assertEquals(unfinished, tester.jobs().last(instanceId, JobType.systemTest).get().steps().get(Step.installReal)); assertEquals(unfinished, tester.jobs().last(instanceId, JobType.systemTest).get().steps().get(Step.installTester)); - tester.tester().controller().curator().writeRoutingPolicies(instanceId, Set.of(new RoutingPolicy(instanceId, + tester.controller().curator().writeRoutingPolicies(instanceId, Set.of(new RoutingPolicy(instanceId, ClusterSpec.Id.from("default"), JobType.systemTest.zone(system()), HostName.from("host"), Optional.empty(), emptySet()))); - tester.tester().controller().curator().writeRoutingPolicies(testerId.id(), Set.of(new RoutingPolicy(testerId.id(), + tester.controller().curator().writeRoutingPolicies(testerId.id(), Set.of(new RoutingPolicy(testerId.id(), ClusterSpec.Id.from("default"), JobType.systemTest.zone(system()), HostName.from("host"), @@ -367,7 +334,7 @@ public class InternalStepRunnerTest { tester.configServer().setVersion(instanceId, zone, version); tester.runner().run(); assertEquals(1, tester.jobs().active().size()); - assertEquals(version, tester.tester().instance(instanceId).deployments().get(zone).version()); + assertEquals(version, tester.instance(instanceId).deployments().get(zone).version()); try { tester.jobs().deploy(instanceId, JobType.productionApNortheast1, Optional.empty(), applicationPackage); @@ -381,7 +348,7 @@ public class InternalStepRunnerTest { tester.startSystemTestTests(); tester.cloud().set(TesterCloud.Status.NOT_STARTED); tester.runner().run(); - MockMailer mailer = ((MockMailer) tester.tester().controller().serviceRegistry().mailer()); + MockMailer mailer = ((MockMailer) tester.controller().serviceRegistry().mailer()); assertEquals(1, mailer.inbox("a@b").size()); assertEquals("Vespa application tenant.application: System test failing due to system error", mailer.inbox("a@b").get(0).subject()); @@ -415,8 +382,8 @@ public class InternalStepRunnerTest { @Test public void certificateTimeoutAbortsJob() { - tester.tester().controllerTester().zoneRegistry().setSystemName(SystemName.PublicCd); - tester.tester().controllerTester().zoneRegistry().setZones(ZoneApiMock.fromId("prod.aws-us-east-1c")); + tester.controllerTester().zoneRegistry().setSystemName(SystemName.PublicCd); + tester.controllerTester().zoneRegistry().setZones(ZoneApiMock.fromId("prod.aws-us-east-1c")); RunId id = tester.startSystemTestTests(); List<X509Certificate> trusted = new ArrayList<>(publicCdApplicationPackage.trustedCertificates()); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/TestConfigSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/TestConfigSerializerTest.java index e28e5dab555..2fc49c3dc21 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/TestConfigSerializerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/TestConfigSerializerTest.java @@ -14,7 +14,7 @@ import java.nio.file.Paths; import java.util.List; import java.util.Map; -import static com.yahoo.vespa.hosted.controller.deployment.InternalDeploymentTester.instanceId; +import static com.yahoo.vespa.hosted.controller.deployment.DeploymentTester.instanceId; import static org.junit.Assert.assertEquals; /** diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ServiceRegistryMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ServiceRegistryMock.java index 672017bec3e..a3c06c75a26 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ServiceRegistryMock.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ServiceRegistryMock.java @@ -2,6 +2,7 @@ package com.yahoo.vespa.hosted.controller.integration; import com.yahoo.component.AbstractComponent; +import com.yahoo.test.ManualClock; import com.yahoo.vespa.hosted.controller.api.integration.BuildService; import com.yahoo.vespa.hosted.controller.api.integration.RunDataStore; import com.yahoo.vespa.hosted.controller.api.integration.ServiceRegistry; @@ -42,6 +43,8 @@ import com.yahoo.vespa.hosted.controller.api.integration.stubs.MockMeteringClien import com.yahoo.vespa.hosted.controller.api.integration.stubs.MockRunDataStore; import com.yahoo.vespa.hosted.controller.api.integration.stubs.MockTesterCloud; +import java.time.Clock; + /** * A mock implementation of a {@link ServiceRegistry} for testing purposes. * @@ -49,6 +52,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.stubs.MockTesterCloud; */ public class ServiceRegistryMock extends AbstractComponent implements ServiceRegistry { + private final ManualClock clock = new ManualClock(); private final ZoneRegistryMock zoneRegistryMock = new ZoneRegistryMock(); private final ConfigServerMock configServerMock = new ConfigServerMock(zoneRegistryMock); private final MemoryNameService memoryNameService = new MemoryNameService(); @@ -78,6 +82,11 @@ public class ServiceRegistryMock extends AbstractComponent implements ServiceReg } @Override + public ManualClock clock() { + return clock; + } + + @Override public GlobalRoutingService globalRoutingService() { return memoryGlobalRoutingService; } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ApplicationOwnershipConfirmerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ApplicationOwnershipConfirmerTest.java index 18acd91969b..88d1626b834 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ApplicationOwnershipConfirmerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ApplicationOwnershipConfirmerTest.java @@ -11,7 +11,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.organization.OwnershipI import com.yahoo.vespa.hosted.controller.api.integration.organization.User; import com.yahoo.vespa.hosted.controller.application.TenantAndApplicationId; import com.yahoo.vespa.hosted.controller.deployment.DeploymentContext; -import com.yahoo.vespa.hosted.controller.deployment.InternalDeploymentTester; +import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; import com.yahoo.vespa.hosted.controller.persistence.MockCuratorDb; import com.yahoo.vespa.hosted.controller.tenant.UserTenant; import org.junit.Before; @@ -22,7 +22,7 @@ import java.util.List; import java.util.Optional; import java.util.function.Supplier; -import static com.yahoo.vespa.hosted.controller.deployment.InternalDeploymentTester.appId; +import static com.yahoo.vespa.hosted.controller.deployment.DeploymentTester.appId; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -34,11 +34,11 @@ public class ApplicationOwnershipConfirmerTest { private MockOwnershipIssues issues; private ApplicationOwnershipConfirmer confirmer; - private InternalDeploymentTester tester; + private DeploymentTester tester; @Before public void setup() { - tester = new InternalDeploymentTester(); + tester = new DeploymentTester(); issues = new MockOwnershipIssues(); confirmer = new ApplicationOwnershipConfirmer(tester.controller(), Duration.ofDays(1), new JobControl(new MockCuratorDb()), issues); } 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 222ec9dfb66..4df1336ac1f 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 @@ -10,7 +10,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.application.Deployment; import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder; -import com.yahoo.vespa.hosted.controller.deployment.InternalDeploymentTester; +import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; import com.yahoo.vespa.hosted.controller.persistence.MockCuratorDb; import org.junit.Test; @@ -25,7 +25,7 @@ import static org.junit.Assert.assertEquals; */ public class DeploymentExpirerTest { - private final InternalDeploymentTester tester = new InternalDeploymentTester(); + private final DeploymentTester tester = new DeploymentTester(); @Test public void testDeploymentExpiry() { diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporterTest.java index fdc8185a45f..070171ad399 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporterTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporterTest.java @@ -13,7 +13,7 @@ import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.application.Change; import com.yahoo.vespa.hosted.controller.application.TenantAndApplicationId; import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder; -import com.yahoo.vespa.hosted.controller.deployment.InternalDeploymentTester; +import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; import com.yahoo.vespa.hosted.controller.persistence.MockCuratorDb; import com.yahoo.vespa.hosted.controller.versions.VespaVersion; import org.junit.Before; @@ -49,13 +49,13 @@ public class DeploymentIssueReporterTest { .upgradePolicy("canary") .build(); - private InternalDeploymentTester tester; + private DeploymentTester tester; private DeploymentIssueReporter reporter; private MockDeploymentIssues issues; @Before public void setup() { - tester = new InternalDeploymentTester(); + tester = new DeploymentTester(); issues = new MockDeploymentIssues(); reporter = new DeploymentIssueReporter(tester.controller(), issues, Duration.ofDays(1), new JobControl(new MockCuratorDb())); } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentMetricsMaintainerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentMetricsMaintainerTest.java index 73ddeeaa0c6..4e4fbe00bb7 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentMetricsMaintainerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentMetricsMaintainerTest.java @@ -3,14 +3,13 @@ package com.yahoo.vespa.hosted.controller.maintenance; import com.yahoo.component.Version; import com.yahoo.config.provision.ApplicationId; -import com.yahoo.config.provision.Environment; -import com.yahoo.config.provision.RegionName; import com.yahoo.config.provision.zone.ZoneId; import com.yahoo.vespa.hosted.controller.Application; -import com.yahoo.vespa.hosted.controller.Instance; import com.yahoo.vespa.hosted.controller.Controller; +import com.yahoo.vespa.hosted.controller.Instance; import com.yahoo.vespa.hosted.controller.api.application.v4.model.ClusterMetrics; import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId; +import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.application.Deployment; import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; @@ -20,7 +19,6 @@ import java.time.Duration; import java.time.Instant; import java.util.HashMap; import java.util.Map; -import java.util.Optional; import java.util.function.Supplier; import static java.time.temporal.ChronoUnit.MILLIS; @@ -37,13 +35,13 @@ public class DeploymentMetricsMaintainerTest { @Test public void updates_metrics() { - var application = tester.createApplication("app1", "tenant1", 123L, 1L); - deploy(application.id().defaultInstance(), Version.fromString("7.1")); + var application = tester.deploymentContext(); + application.runJob(JobType.devUsEast1, new ApplicationPackage(new byte[0]), Version.fromString("7.1")); DeploymentMetricsMaintainer maintainer = maintainer(tester.controller()); - Supplier<Application> app = () -> tester.application(application.id()); - Supplier<Instance> instance = () -> tester.defaultInstance(application.id()); - Supplier<Deployment> deployment = () -> instance.get().deployments().values().stream().findFirst().get(); + Supplier<Application> app = application::application; + Supplier<Instance> instance = application::instance; + Supplier<Deployment> deployment = () -> application.deployment(ZoneId.from("dev", "us-east-1")); // No metrics gathered yet assertEquals(0, app.get().metrics().queryServiceQuality(), 0); @@ -53,7 +51,7 @@ public class DeploymentMetricsMaintainerTest { assertFalse("Never received any writes", deployment.get().activity().lastWritten().isPresent()); // Only get application metrics for old version - deploy(application.id().defaultInstance(), Version.fromString("6.3.3")); + application.runJob(JobType.devUsEast1, new ApplicationPackage(new byte[0]), Version.fromString("6.3.3")); maintainer.maintain(); assertEquals(0, app.get().metrics().queryServiceQuality(), 0); assertEquals(0, deployment.get().metrics().documentCount(), 0); @@ -62,13 +60,13 @@ public class DeploymentMetricsMaintainerTest { assertFalse("Never received any writes", deployment.get().activity().lastWritten().isPresent()); // Metrics are gathered and saved to application - deploy(application.id().defaultInstance(), Version.fromString("7.5.5")); + application.runJob(JobType.devUsEast1, new ApplicationPackage(new byte[0]), Version.fromString("7.5.5")); var metrics0 = Map.of(ClusterMetrics.QUERIES_PER_SECOND, 1D, ClusterMetrics.FEED_PER_SECOND, 2D, ClusterMetrics.DOCUMENT_COUNT, 3D, ClusterMetrics.QUERY_LATENCY, 4D, ClusterMetrics.FEED_LATENCY, 5D); - setMetrics(application.id().defaultInstance(), metrics0); + setMetrics(application.application().id().defaultInstance(), metrics0); maintainer.maintain(); Instant t1 = tester.clock().instant().truncatedTo(MILLIS); assertEquals(0.0, app.get().metrics().queryServiceQuality(), Double.MIN_VALUE); @@ -98,7 +96,7 @@ public class DeploymentMetricsMaintainerTest { var metrics1 = new HashMap<>(metrics0); metrics1.put(ClusterMetrics.QUERIES_PER_SECOND, 0D); metrics1.put(ClusterMetrics.FEED_PER_SECOND, 5D); - setMetrics(application.id().defaultInstance(), metrics1); + setMetrics(application.application().id().defaultInstance(), metrics1); maintainer.maintain(); assertEquals(t2, deployment.get().activity().lastQueried().get()); assertEquals(t3, deployment.get().activity().lastWritten().get()); @@ -109,7 +107,7 @@ public class DeploymentMetricsMaintainerTest { tester.clock().advance(Duration.ofHours(1)); var metrics2 = new HashMap<>(metrics1); metrics2.put(ClusterMetrics.FEED_PER_SECOND, 0D); - setMetrics(application.id().defaultInstance(), metrics2); + setMetrics(application.application().id().defaultInstance(), metrics2); maintainer.maintain(); assertEquals(t2, deployment.get().activity().lastQueried().get()); assertEquals(t3, deployment.get().activity().lastWritten().get()); @@ -129,12 +127,4 @@ public class DeploymentMetricsMaintainerTest { return new DeploymentMetricsMaintainer(controller, Duration.ofDays(1), new JobControl(controller.curator())); } - private void deploy(ApplicationId id, Version version) { - tester.controllerTester().deploy(id, - ZoneId.from(Environment.dev, RegionName.from("us-east-1")), - Optional.of(new ApplicationPackage(new byte[0])), - false, - Optional.of(version)); - } - } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/JobRunnerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/JobRunnerTest.java index 7a341dc7441..0f6aec804e2 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/JobRunnerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/JobRunnerTest.java @@ -8,7 +8,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId; import com.yahoo.vespa.hosted.controller.api.integration.deployment.SourceRevision; import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.application.TenantAndApplicationId; -import com.yahoo.vespa.hosted.controller.deployment.InternalDeploymentTester; +import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; import com.yahoo.vespa.hosted.controller.deployment.JobController; import com.yahoo.vespa.hosted.controller.deployment.Run; import com.yahoo.vespa.hosted.controller.deployment.RunStatus; @@ -76,7 +76,7 @@ public class JobRunnerTest { @Test public void multiThreadedExecutionFinishes() { - InternalDeploymentTester tester = new InternalDeploymentTester(); + DeploymentTester tester = new DeploymentTester(); JobController jobs = tester.controller().jobController(); StepRunner stepRunner = (step, id) -> id.type() == stagingTest && step.get() == startTests? Optional.of(error) : Optional.of(running); Phaser phaser = new Phaser(1); @@ -109,7 +109,7 @@ public class JobRunnerTest { @Test public void stepLogic() { - InternalDeploymentTester tester = new InternalDeploymentTester(); + DeploymentTester tester = new DeploymentTester(); JobController jobs = tester.controller().jobController(); Map<Step, RunStatus> outcomes = new EnumMap<>(Step.class); JobRunner runner = new JobRunner(tester.controller(), Duration.ofDays(1), new JobControl(tester.controller().curator()), @@ -197,7 +197,7 @@ public class JobRunnerTest { @Test public void locksAndGarbage() throws InterruptedException, BrokenBarrierException { - InternalDeploymentTester tester = new InternalDeploymentTester(); + DeploymentTester tester = new DeploymentTester(); JobController jobs = tester.controller().jobController(); // Hang during tester deployment, until notified. CyclicBarrier barrier = new CyclicBarrier(2); @@ -236,7 +236,7 @@ public class JobRunnerTest { @Test public void historyPruning() { - InternalDeploymentTester tester = new InternalDeploymentTester(); + DeploymentTester tester = new DeploymentTester(); JobController jobs = tester.controller().jobController(); JobRunner runner = new JobRunner(tester.controller(), Duration.ofDays(1), new JobControl(tester.controller().curator()), inThreadExecutor(), (id, step) -> Optional.of(running)); @@ -264,7 +264,7 @@ public class JobRunnerTest { @Test public void timeout() { - InternalDeploymentTester tester = new InternalDeploymentTester(); + DeploymentTester tester = new DeploymentTester(); JobController jobs = tester.controller().jobController(); Map<Step, RunStatus> outcomes = new EnumMap<>(Step.class); JobRunner runner = new JobRunner(tester.controller(), Duration.ofDays(1), new JobControl(tester.controller().curator()), diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporterTest.java index af6017c1188..31f55be92a9 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporterTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporterTest.java @@ -12,7 +12,7 @@ import com.yahoo.vespa.hosted.controller.ControllerTester; import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.application.SystemApplication; import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder; -import com.yahoo.vespa.hosted.controller.deployment.InternalDeploymentTester; +import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; import com.yahoo.vespa.hosted.controller.integration.MetricsMock; import com.yahoo.vespa.hosted.controller.integration.ZoneApiMock; import com.yahoo.vespa.hosted.controller.persistence.MockCuratorDb; @@ -36,7 +36,7 @@ public class MetricsReporterTest { @Test public void deployment_fail_ratio() { - var tester = new InternalDeploymentTester(); + var tester = new DeploymentTester(); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .region("us-west-1") @@ -70,7 +70,7 @@ public class MetricsReporterTest { @Test public void deployment_average_duration() { - var tester = new InternalDeploymentTester(); + var tester = new DeploymentTester(); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .region("us-west-1") @@ -115,7 +115,7 @@ public class MetricsReporterTest { @Test public void deployments_failing_upgrade() { - var tester = new InternalDeploymentTester(); + var tester = new DeploymentTester(); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .region("us-west-1") @@ -167,7 +167,7 @@ public class MetricsReporterTest { @Test public void deployment_warnings_metric() { - var tester = new InternalDeploymentTester(); + var tester = new DeploymentTester(); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .region("us-west-1") @@ -184,14 +184,14 @@ public class MetricsReporterTest { @Test public void build_time_reporting() { - var tester = new InternalDeploymentTester(); + var tester = new DeploymentTester(); var applicationPackage = new ApplicationPackageBuilder().region("us-west-1").build(); var context = tester.deploymentContext() .submit(applicationPackage) .deploy(); assertEquals(1000, context.lastSubmission().get().buildTime().get().toEpochMilli()); - MetricsReporter reporter = createReporter(tester.tester().controller()); + MetricsReporter reporter = createReporter(tester.controller()); reporter.maintain(); assertEquals(tester.clock().instant().getEpochSecond() - 1, getMetric(MetricsReporter.DEPLOYMENT_BUILD_AGE_SECONDS, context.instanceId())); @@ -199,7 +199,7 @@ public class MetricsReporterTest { @Test public void name_service_queue_size_metric() { - var tester = new InternalDeploymentTester(); + var tester = new DeploymentTester(); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .environment(Environment.prod) .globalServiceId("default") @@ -214,7 +214,7 @@ public class MetricsReporterTest { context.submit(applicationPackage).deploy(); reporter.maintain(); - assertEquals("Deployment queues name services requests", 6, metrics.getMetric(MetricsReporter.NAME_SERVICE_REQUESTS_QUEUED).intValue()); + assertEquals("Deployment queues name services requests", 15, metrics.getMetric(MetricsReporter.NAME_SERVICE_REQUESTS_QUEUED).intValue()); context.flushDnsUpdates(); reporter.maintain(); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployerTest.java index 0a6d5d7698d..0be873f80ed 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployerTest.java @@ -10,7 +10,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.deployment.SourceRevisi import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.application.Change; import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder; -import com.yahoo.vespa.hosted.controller.deployment.InternalDeploymentTester; +import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; import com.yahoo.vespa.hosted.controller.deployment.Run; import com.yahoo.vespa.hosted.controller.persistence.MockCuratorDb; import org.junit.Test; @@ -29,7 +29,7 @@ public class OutstandingChangeDeployerTest { @Test public void testChangeDeployer() { - InternalDeploymentTester tester = new InternalDeploymentTester(); + DeploymentTester tester = new DeploymentTester(); OutstandingChangeDeployer deployer = new OutstandingChangeDeployer(tester.controller(), Duration.ofMinutes(10), new JobControl(new MockCuratorDb())); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RotationStatusUpdaterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RotationStatusUpdaterTest.java index 127104724a5..d7a28708049 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RotationStatusUpdaterTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RotationStatusUpdaterTest.java @@ -4,19 +4,13 @@ package com.yahoo.vespa.hosted.controller.maintenance; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.zone.ZoneId; -import com.yahoo.vespa.hosted.controller.ControllerTester; -import com.yahoo.vespa.hosted.controller.Instance; import com.yahoo.vespa.hosted.controller.api.integration.routing.RotationStatus; -import com.yahoo.vespa.hosted.controller.application.Deployment; import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder; -import com.yahoo.vespa.hosted.controller.deployment.BuildJob; import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; -import com.yahoo.vespa.hosted.controller.deployment.InternalDeploymentTester; import com.yahoo.vespa.hosted.controller.rotation.RotationState; import org.junit.Test; import java.time.Duration; -import java.util.function.Supplier; import static org.junit.Assert.assertEquals; @@ -27,7 +21,7 @@ public class RotationStatusUpdaterTest { @Test public void updates_rotation_status() { - var tester = new InternalDeploymentTester(); + var tester = new DeploymentTester(); var globalRotationService = tester.controllerTester().serviceRegistry().globalRoutingServiceMock(); var updater = new RotationStatusUpdater(tester.controller(), Duration.ofDays(1), new JobControl(tester.controller().curator())); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPoliciesTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPoliciesTest.java index 1aa88dde258..f5f1605a699 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPoliciesTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPoliciesTest.java @@ -6,9 +6,7 @@ import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.zone.ZoneId; -import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.Instance; -import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId; import com.yahoo.vespa.hosted.controller.api.integration.configserver.LoadBalancer; import com.yahoo.vespa.hosted.controller.api.integration.dns.Record; import com.yahoo.vespa.hosted.controller.api.integration.dns.RecordData; @@ -19,7 +17,6 @@ import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder; import com.yahoo.vespa.hosted.controller.deployment.BuildJob; import com.yahoo.vespa.hosted.controller.deployment.DeploymentContext; import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; -import com.yahoo.vespa.hosted.controller.deployment.InternalDeploymentTester; import org.junit.Test; import java.net.URI; @@ -40,7 +37,7 @@ import static org.junit.Assert.assertTrue; */ public class RoutingPoliciesTest { - private final InternalDeploymentTester tester = new InternalDeploymentTester(); + private final DeploymentTester tester = new DeploymentTester(); private final DeploymentContext context1 = tester.newDeploymentContext(ApplicationId.from("tenant1", "app1", "default")); private final DeploymentContext context2 = tester.newDeploymentContext(ApplicationId.from("tenant1", "app2", "default")); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java index 4e910fe2d80..58a49307733 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java @@ -8,7 +8,7 @@ import com.yahoo.vespa.hosted.controller.application.Change; import com.yahoo.vespa.hosted.controller.application.Deployment; import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder; import com.yahoo.vespa.hosted.controller.deployment.DeploymentContext; -import com.yahoo.vespa.hosted.controller.deployment.InternalDeploymentTester; +import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; import com.yahoo.vespa.hosted.controller.versions.VespaVersion; import org.junit.Test; @@ -35,7 +35,7 @@ import static org.junit.Assert.assertTrue; */ public class UpgraderTest { - private final InternalDeploymentTester tester = new InternalDeploymentTester().atHourOfDay(5); + private final DeploymentTester tester = new DeploymentTester().atHourOfDay(5); @Test public void testUpgrading() { 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 f7af8ff4ce4..cf28845b4e1 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 @@ -17,6 +17,7 @@ import com.yahoo.config.provision.TenantName; import com.yahoo.config.provision.zone.ZoneId; import com.yahoo.slime.Cursor; import com.yahoo.slime.Slime; +import com.yahoo.test.ManualClock; import com.yahoo.vespa.athenz.api.AthenzDomain; import com.yahoo.vespa.athenz.api.AthenzIdentity; import com.yahoo.vespa.athenz.api.AthenzUser; @@ -62,6 +63,7 @@ import com.yahoo.vespa.hosted.controller.application.TenantAndApplicationId; import com.yahoo.vespa.hosted.controller.athenz.HostedAthenzIdentities; import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder; import com.yahoo.vespa.hosted.controller.deployment.BuildJob; +import com.yahoo.vespa.hosted.controller.deployment.DeploymentContext; import com.yahoo.vespa.hosted.controller.deployment.DeploymentTrigger; import com.yahoo.vespa.hosted.controller.integration.ConfigServerMock; import com.yahoo.vespa.hosted.controller.integration.ServiceRegistryMock; @@ -315,7 +317,7 @@ public class ApplicationApiTest extends ControllerContainerTest { // POST an application deployment to a production zone - operator emergency deployment - fails since package is unknown entity = createApplicationDeployData(Optional.empty(), - Optional.of(ApplicationVersion.from(BuildJob.defaultSourceRevision, + Optional.of(ApplicationVersion.from(DeploymentContext.defaultSourceRevision, BuildJob.defaultBuildNumber - 1)), true); tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-central-1/instance/instance1/", POST) @@ -326,7 +328,7 @@ public class ApplicationApiTest extends ControllerContainerTest { // POST an application deployment to a production zone - operator emergency deployment - works with known package entity = createApplicationDeployData(Optional.empty(), - Optional.of(ApplicationVersion.from(BuildJob.defaultSourceRevision, + Optional.of(ApplicationVersion.from(DeploymentContext.defaultSourceRevision, BuildJob.defaultBuildNumber)), true); tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-central-1/instance/instance1/", POST) @@ -731,7 +733,7 @@ public class ApplicationApiTest extends ControllerContainerTest { 1234, 123, Optional.empty(), - BuildJob.defaultSourceRevision))), + DeploymentContext.defaultSourceRevision))), "{\"error-code\":\"BAD_REQUEST\",\"message\":\"" + app1 + " is set up to be deployed from internally," + " and no longer accepts submissions from Screwdriver v3 jobs. If you need to revert " + "to the old pipeline, please file a ticket at yo/vespa-support and request this.\"}", @@ -769,7 +771,7 @@ public class ApplicationApiTest extends ControllerContainerTest { 1234, 123, Optional.empty(), - BuildJob.defaultSourceRevision))), + DeploymentContext.defaultSourceRevision))), "{\"message\":\"ok\"}"); // PUT (create) the authenticated user @@ -1645,6 +1647,7 @@ public class ApplicationApiTest extends ControllerContainerTest { .projectId(projectId); job.type(JobType.component).uploadArtifact(applicationPackage).submit(); controllerTester.deploy(app.id().defaultInstance(), applicationPackage, TEST_ZONE); + ((ManualClock) controllerTester.controller().clock()).advance(Duration.ofSeconds(1)); job.type(JobType.systemTest).submit(); // Notifying about job started not by the controller fails diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java index 1105a478e14..daf1a4c2ea7 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java @@ -9,7 +9,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServ import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion; import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder; -import com.yahoo.vespa.hosted.controller.deployment.InternalDeploymentTester; +import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; import org.json.JSONException; import org.json.JSONObject; import org.junit.Test; @@ -33,9 +33,9 @@ import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobTy import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.stagingTest; import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.systemTest; import static com.yahoo.vespa.hosted.controller.api.integration.deployment.TesterCloud.Status.FAILURE; -import static com.yahoo.vespa.hosted.controller.deployment.InternalDeploymentTester.instanceId; +import static com.yahoo.vespa.hosted.controller.deployment.DeploymentTester.instanceId; import static com.yahoo.vespa.hosted.controller.deployment.DeploymentContext.applicationPackage; -import static com.yahoo.vespa.hosted.controller.deployment.InternalDeploymentTester.testerId; +import static com.yahoo.vespa.hosted.controller.deployment.DeploymentTester.testerId; import static com.yahoo.vespa.hosted.controller.deployment.RunStatus.deploymentFailed; import static com.yahoo.vespa.hosted.controller.deployment.RunStatus.installationFailed; import static com.yahoo.vespa.hosted.controller.deployment.RunStatus.running; @@ -50,7 +50,7 @@ public class JobControllerApiHandlerHelperTest { @Test public void testResponses() { - InternalDeploymentTester tester = new InternalDeploymentTester(); + DeploymentTester tester = new DeploymentTester(); tester.clock().setInstant(Instant.EPOCH); // Revision 1 gets deployed everywhere. @@ -65,14 +65,14 @@ public class JobControllerApiHandlerHelperTest { tester.runJob(stagingTest); tester.runJob(productionUsCentral1); - tester.tester().readyJobTrigger().maintain(); + tester.triggerJobs(); // us-east-3 eats the deployment failure and fails before deployment, while us-west-1 fails after. tester.configServer().throwOnNextPrepare(new ConfigServerException(URI.create("url"), "ERROR!", INVALID_APPLICATION_PACKAGE, null)); tester.runner().run(); assertEquals(deploymentFailed, tester.jobs().last(instanceId, productionUsEast3).get().status()); - ZoneId usWest1 = productionUsWest1.zone(tester.tester().controller().system()); + ZoneId usWest1 = productionUsWest1.zone(tester.controller().system()); tester.configServer().convergeServices(instanceId, usWest1); tester.configServer().convergeServices(testerId.id(), usWest1); tester.setEndpoints(instanceId, usWest1); @@ -81,9 +81,9 @@ public class JobControllerApiHandlerHelperTest { tester.cloud().set(FAILURE); tester.runner().run(); assertEquals(testFailure, tester.jobs().last(instanceId, productionUsWest1).get().status()); - assertEquals(revision2, tester.instance().deployments().get(productionUsCentral1.zone(tester.tester().controller().system())).applicationVersion()); - assertEquals(revision1, tester.instance().deployments().get(productionUsEast3.zone(tester.tester().controller().system())).applicationVersion()); - assertEquals(revision2, tester.instance().deployments().get(productionUsWest1.zone(tester.tester().controller().system())).applicationVersion()); + assertEquals(revision2, tester.instance().deployments().get(productionUsCentral1.zone(tester.controller().system())).applicationVersion()); + assertEquals(revision1, tester.instance().deployments().get(productionUsEast3.zone(tester.controller().system())).applicationVersion()); + assertEquals(revision2, tester.instance().deployments().get(productionUsWest1.zone(tester.controller().system())).applicationVersion()); tester.clock().advance(Duration.ofMillis(1000)); @@ -91,24 +91,26 @@ public class JobControllerApiHandlerHelperTest { tester.newSubmission(); tester.runJob(systemTest); tester.runJob(stagingTest); - tester.tester().readyJobTrigger().maintain(); // Starts a run for us-central-1. - tester.tester().readyJobTrigger().maintain(); // Starts a new staging test run. + tester.triggerJobs(); // Starts a run for us-central-1. + tester.triggerJobs(); // Starts a new staging test run. tester.runner().run(); assertEquals(running, tester.jobs().last(instanceId, productionUsCentral1).get().status()); assertEquals(running, tester.jobs().last(instanceId, stagingTest).get().status()); // Staging is expired, and the job fails and won't be retried immediately. - tester.tester().controller().applications().deactivate(instanceId, stagingTest.zone(tester.tester().controller().system())); + tester.controller().applications().deactivate(instanceId, stagingTest.zone(tester.controller().system())); tester.runner().run(); assertEquals(installationFailed, tester.jobs().last(instanceId, stagingTest).get().status()); tester.clock().advance(Duration.ofMillis(100_000)); // More than the minute within which there are immediate retries. - tester.tester().readyJobTrigger().maintain(); + tester.triggerJobs(); assertEquals(installationFailed, tester.jobs().last(instanceId, stagingTest).get().status()); // System upgrades to a new version, which won't yet start. Version platform = new Version("7.1"); - tester.tester().upgradeSystem(platform); + tester.controllerTester().upgradeSystem(platform); + tester.upgrader().maintain(); + tester.triggerJobs(); // us-central-1 has started, deployed, and is installing. Deployment is not yet verified. // us-east-3 is waiting for the failed staging test and us-central-1, while us-west-1 is waiting only for us-central-1. @@ -117,7 +119,7 @@ public class JobControllerApiHandlerHelperTest { // one success from revision2 to revision3 and one failure from revision1 to revision3. assertResponse(JobControllerApiHandlerHelper.runResponse(tester.jobs().runs(instanceId, stagingTest), URI.create("https://some.url:43/root")), "staging-runs.json"); assertResponse(JobControllerApiHandlerHelper.runDetailsResponse(tester.jobs(), tester.jobs().last(instanceId, productionUsEast3).get().id(), "0"), "us-east-3-log-without-first.json"); - assertResponse(JobControllerApiHandlerHelper.jobTypeResponse(tester.tester().controller(), instanceId, URI.create("https://some.url:43/root/")), "overview.json"); + assertResponse(JobControllerApiHandlerHelper.jobTypeResponse(tester.controller(), instanceId, URI.create("https://some.url:43/root/")), "overview.json"); tester.runJob(instanceId, JobType.devAwsUsEast2a, applicationPackage); assertResponse(JobControllerApiHandlerHelper.runResponse(tester.jobs().runs(instanceId, devAwsUsEast2a), URI.create("https://some.url:43/root")), "dev-aws-us-east-2a-runs.json"); @@ -125,10 +127,10 @@ public class JobControllerApiHandlerHelperTest { @Test public void testDevResponses() { - InternalDeploymentTester tester = new InternalDeploymentTester(); + DeploymentTester tester = new DeploymentTester(); tester.clock().setInstant(Instant.EPOCH); - ZoneId zone = JobType.devUsEast1.zone(tester.tester().controller().system()); + ZoneId zone = JobType.devUsEast1.zone(tester.controller().system()); tester.jobs().deploy(instanceId, JobType.devUsEast1, Optional.empty(), applicationPackage); tester.configServer().setLogStream("1554970337.935104\t17491290-v6-1.ostk.bm2.prod.ne1.yahoo.com\t5480\tcontainer\tstdout\tinfo\tERROR: Bundle canary-application [71] Unable to get module class path. (java.lang.NullPointerException)\n"); assertResponse(JobControllerApiHandlerHelper.runDetailsResponse(tester.jobs(), tester.jobs().last(instanceId, devUsEast1).get().id(), null), "dev-us-east-1-log-first-part.json"); @@ -138,22 +140,22 @@ public class JobControllerApiHandlerHelperTest { tester.setEndpoints(instanceId, zone); tester.runner().run(); - assertResponse(JobControllerApiHandlerHelper.jobTypeResponse(tester.tester().controller(), instanceId, URI.create("https://some.url:43/root")), "dev-overview.json"); + assertResponse(JobControllerApiHandlerHelper.jobTypeResponse(tester.controller(), instanceId, URI.create("https://some.url:43/root")), "dev-overview.json"); assertResponse(JobControllerApiHandlerHelper.runDetailsResponse(tester.jobs(), tester.jobs().last(instanceId, devUsEast1).get().id(), "9"), "dev-us-east-1-log-second-part.json"); } @Test public void testResponsesWithDirectDeployment() { - var tester = new InternalDeploymentTester(); + var tester = new DeploymentTester(); tester.clock().setInstant(Instant.EPOCH); var region = "us-west-1"; var applicationPackage = new ApplicationPackageBuilder().region(region).build(); // Deploy directly to production zone, like integration tests. - tester.tester().controller().applications().deploy(tester.instance().id(), ZoneId.from("prod", region), + tester.controller().applications().deploy(tester.instance().id(), ZoneId.from("prod", region), Optional.of(applicationPackage), new DeployOptions(true, Optional.empty(), false, false)); - assertResponse(JobControllerApiHandlerHelper.jobTypeResponse(tester.tester().controller(), instanceId, URI.create("https://some.url:43/root/")), + assertResponse(JobControllerApiHandlerHelper.jobTypeResponse(tester.controller(), instanceId, URI.create("https://some.url:43/root/")), "jobs-direct-deployment.json"); } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/rotation/RotationRepositoryTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/rotation/RotationRepositoryTest.java index b298cfcc889..c76046b3f67 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/rotation/RotationRepositoryTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/rotation/RotationRepositoryTest.java @@ -2,12 +2,11 @@ package com.yahoo.vespa.hosted.controller.rotation; import com.yahoo.config.provision.SystemName; -import com.yahoo.vespa.hosted.controller.Application; -import com.yahoo.vespa.hosted.controller.Instance; import com.yahoo.vespa.hosted.controller.ControllerTester; import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.application.AssignedRotation; import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder; +import com.yahoo.vespa.hosted.controller.deployment.DeploymentContext; import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; import com.yahoo.vespa.hosted.rotation.config.RotationsConfig; import org.junit.Before; @@ -39,7 +38,7 @@ public class RotationRepositoryTest { private final RotationsConfig rotationsConfigWhitespaces = new RotationsConfig( new RotationsConfig.Builder() - .rotations("foo-1", "\n foo-1.com \n") + .rotations("foo-1", "\n \t foo-1.com \n") .rotations("foo-2", "foo-2.com") ); @@ -51,56 +50,46 @@ public class RotationRepositoryTest { private DeploymentTester tester; private RotationRepository repository; - private Application application; - private Instance instance; - + private DeploymentContext application; + @Before public void before() { tester = new DeploymentTester(new ControllerTester(rotationsConfig)); - repository = tester.controller().applications().rotationRepository(); - application = tester.createApplication("app1", "tenant1", 11L, 1L); - instance = tester.defaultInstance(application.id()); + repository = tester.applications().rotationRepository(); + application = tester.newDeploymentContext("tenant1", "app1", "default"); } @Test public void assigns_and_reuses_rotation() { - // Deploying assigns a rotation - tester.deployCompletely(application, applicationPackage); + // Submitting assigns a rotation + application.submit(applicationPackage); Rotation expected = new Rotation(new RotationId("foo-1"), "foo-1.com"); - instance = tester.applications().requireInstance(instance.id()); - assertEquals(List.of(expected.id()), rotationIds(instance.rotations())); + assertEquals(List.of(expected.id()), rotationIds(application.instance().rotations())); assertEquals(URI.create("https://app1--tenant1.global.vespa.oath.cloud:4443/"), - instance.endpointsIn(SystemName.main).main().get().url()); + application.instance().endpointsIn(SystemName.main).main().get().url()); try (RotationLock lock = repository.lock()) { - List<AssignedRotation> rotations = repository.getOrAssignRotations(application.deploymentSpec(), - tester.applications().requireInstance(instance.id()), + List<AssignedRotation> rotations = repository.getOrAssignRotations(application.application().deploymentSpec(), + application.instance(), lock); assertSingleRotation(expected, rotations, repository); } - // 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, 43); - assertEquals(List.of(expected.id()), rotationIds(tester.applications().requireInstance(instance.id()).rotations())); + // Submitting once more assigns same rotation + application.submit(applicationPackage); + assertEquals(List.of(expected.id()), rotationIds(application.instance().rotations())); } @Test public void strips_whitespace_in_rotation_fqdn() { - DeploymentTester tester = new DeploymentTester(new ControllerTester(rotationsConfigWhitespaces)); + tester = new DeploymentTester(new ControllerTester(rotationsConfigWhitespaces)); RotationRepository repository = tester.controller().applications().rotationRepository(); - Application application2 = tester.createApplication("app2", "tenant2", 22L, 2L); + var application2 = tester.newDeploymentContext("tenant1", "app2", "default"); - tester.deployCompletely(application2, applicationPackage); - Instance instance2 = tester.defaultInstance(application2.id()); + application2.submit(applicationPackage); try (RotationLock lock = repository.lock()) { - List<AssignedRotation> rotations = repository.getOrAssignRotations(application2.deploymentSpec(), instance2, lock); + List<AssignedRotation> rotations = repository.getOrAssignRotations(application2.application().deploymentSpec(), application2.instance(), lock); Rotation assignedRotation = new Rotation(new RotationId("foo-1"), "foo-1.com"); assertSingleRotation(assignedRotation, rotations, repository); } @@ -109,17 +98,17 @@ public class RotationRepositoryTest { @Test public void out_of_rotations() { // Assigns 1 rotation - tester.deployCompletely(application, applicationPackage); + application.submit(applicationPackage); // Assigns 1 more - Application application2 = tester.createApplication("app2", "tenant2", 22L, 2L); - tester.deployCompletely(application2, applicationPackage); + var application2 = tester.newDeploymentContext("tenant2", "app2", "default"); + application2.submit(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); + var application3 = tester.newDeploymentContext("tenant3", "app3", "default"); + application3.submit(applicationPackage); } @Test @@ -128,10 +117,9 @@ public class RotationRepositoryTest { .globalServiceId("foo") .region("us-east-3") .build(); - Application application2 = tester.createApplication("app2", "tenant2", 22L, 2L); thrown.expect(RuntimeException.class); thrown.expectMessage("less than 2 prod zones are defined"); - tester.deployCompletely(application2, applicationPackage); + application.submit(applicationPackage); } @Test @@ -140,8 +128,8 @@ public class RotationRepositoryTest { .region("us-east-3") .region("us-west-1") .build(); - tester.deployCompletely(application, applicationPackage); - assertTrue(tester.defaultInstance(application.id()).rotations().isEmpty()); + application.submit(applicationPackage); + assertTrue(application.instance().rotations().isEmpty()); } @Test @@ -151,11 +139,11 @@ public class RotationRepositoryTest { .region("us-east-3") .region("us-west-1") .build(); - Application application2 = tester.createApplication("app2", "tenant2", 22L, 2L); - tester.deployCompletely(application2, applicationPackage); - assertEquals(List.of(new RotationId("foo-1")), rotationIds(tester.defaultInstance(application2.id()).rotations())); - assertEquals("https://cd--app2--tenant2.global.vespa.oath.cloud:4443/", tester.defaultInstance(application2.id()) - .endpointsIn(SystemName.cd).main().get().url().toString()); + var application2 = tester.newDeploymentContext("tenant2", "app2", "default"); + application2.submit(applicationPackage); + assertEquals(List.of(new RotationId("foo-1")), rotationIds(application2.instance().rotations())); + assertEquals("https://cd--app2--tenant2.global.vespa.oath.cloud:4443/", + application2.instance().endpointsIn(SystemName.cd).main().get().url().toString()); } private void assertSingleRotation(Rotation expected, List<AssignedRotation> assignedRotations, RotationRepository repository) { diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java index 899a0228b48..5c68fd2e370 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java @@ -14,7 +14,7 @@ import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.application.SystemApplication; import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder; import com.yahoo.vespa.hosted.controller.deployment.DeploymentContext; -import com.yahoo.vespa.hosted.controller.deployment.InternalDeploymentTester; +import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; import com.yahoo.vespa.hosted.controller.persistence.CuratorDb; import com.yahoo.vespa.hosted.controller.persistence.MockCuratorDb; import com.yahoo.vespa.hosted.controller.versions.VespaVersion.Confidence; @@ -122,7 +122,7 @@ public class VersionStatusTest { @Test public void testVersionStatusAfterApplicationUpdates() { - InternalDeploymentTester tester = new InternalDeploymentTester(); + DeploymentTester tester = new DeploymentTester(); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .upgradePolicy("default") .environment(Environment.prod) @@ -177,11 +177,10 @@ public class VersionStatusTest { @Test public void testVersionConfidence() { - InternalDeploymentTester tester = new InternalDeploymentTester(); + DeploymentTester tester = new DeploymentTester().atHourOfDay(5); Version version0 = new Version("6.2"); tester.controllerTester().upgradeSystem(version0); tester.upgrader().maintain(); - var builder = new ApplicationPackageBuilder().region("us-west-1").region("us-east-3"); // Setup applications - all running on version0 @@ -353,7 +352,7 @@ public class VersionStatusTest { @Test public void testConfidenceOverride() { - InternalDeploymentTester tester = new InternalDeploymentTester(); + DeploymentTester tester = new DeploymentTester(); Version version0 = new Version("6.2"); tester.controllerTester().upgradeSystem(version0); @@ -390,7 +389,7 @@ public class VersionStatusTest { MockCuratorDb db = new MockCuratorDb(Stream.of(controller1, controller2, controller3) .map(hostName -> hostName.value() + ":2222") .collect(Collectors.joining(","))); - InternalDeploymentTester tester = new InternalDeploymentTester(new ControllerTester(db)); + DeploymentTester tester = new DeploymentTester(new ControllerTester(db)); // Commit details are set for initial version var version0 = tester.controllerTester().nextVersion(); @@ -421,9 +420,8 @@ public class VersionStatusTest { @Test public void testConfidenceChangeRespectsTimeWindow() { - InternalDeploymentTester tester = new InternalDeploymentTester(); + DeploymentTester tester = new DeploymentTester().atHourOfDay(5); // Canaries and normal application deploys on initial version - assertEquals(5, tester.controllerTester().hourOfDayAfter(Duration.ZERO)); Version version0 = Version.fromString("7.1"); tester.controllerTester().upgradeSystem(version0); var canary0 = tester.newDeploymentContext("tenant1", "canary0", "default") |