/** * Verifies that a pod was launched with exactly the provided task names in the last accept call. */ public static Expect launchedTasks(Collection<String> taskNames) { return launchedTasks(1, taskNames); }
/** * Verifies that the resources for the provided task names have been unreserved. */ public static Expect unreservedTasks(String... taskNames) { return unreservedTasks(Arrays.asList(taskNames)); }
@Test public void testParallelStrategyParallelSteps() throws Exception { Collection<SimulationTick> ticks = new ArrayList<>(); ticks.add(Send.register()); ticks.add(Expect.reconciledImplicitly()); // Service should launch all of hello-0/1-first/second using the provided offers: ticks.add(Send.offerBuilder("hello").setCount(3).build()); // Launches will end up being split across two offers/agents: ticks.add(Expect.launchedTasks(2, "hello-0-first", "hello-0-second", "hello-1-first", "hello-1-second")); ticks.add(Send.taskStatus("hello-0-first", Protos.TaskState.TASK_RUNNING).build()); ticks.add(Send.taskStatus("hello-0-second", Protos.TaskState.TASK_RUNNING).build()); ticks.add(Send.taskStatus("hello-1-first", Protos.TaskState.TASK_RUNNING).build()); ticks.add(Send.taskStatus("hello-1-second", Protos.TaskState.TASK_RUNNING).build()); ticks.add(Expect.samePod("hello-0-first", "hello-0-second")); ticks.add(Expect.samePod("hello-1-first", "hello-1-second")); // No more hellos to launch: ticks.add(Send.offerBuilder("hello").setCount(3).build()); ticks.add(Expect.declinedLastOffer()); ticks.add(Expect.allPlansComplete()); new ServiceTestRunner("custom_steps.yml") .setSchedulerEnv( "DEPLOY_STRATEGY", "parallel", "DEPLOY_STEPS", "[[first, second]]") .run(ticks); }
ticks.add(Expect.revivedOffers(3)); ticks.add(Expect.recoveryStepStatus("world-0:[server]", "world-0:[server]", Status.PREPARED)); ticks.add(Expect.reconciledExplicitly(result.getPersister())); ticks.add(Send.taskStatus("hello-0-server", Protos.TaskState.TASK_RUNNING).build()); ticks.add(Send.taskStatus("world-1-server", Protos.TaskState.TASK_FAILED).build()); ticks.add(Expect.revivedOffers(1)); ticks.add(Expect.taskNameKilled("hello-0-server", 1)); // killed for deploy plan ticks.add(Expect.deployStepCount(3)); ticks.add(Expect.deployStepStatus("hello", "hello-0:[server]", Status.PREPARED)); ticks.add(Expect.deployStepStatus("world", "world-0:[server]", Status.PENDING)); ticks.add(Expect.deployStepStatus("world", "world-1:[server]", Status.PENDING)); ticks.add(Expect.recoveryStepCount(2)); ticks.add(Expect.recoveryStepStatus("world-0:[server]", "world-0:[server]", Status.PREPARED)); ticks.add(Expect.recoveryStepStatus("world-1:[server]", "world-1:[server]", Status.PREPARED)); ticks.add(Expect.revivedOffers(1)); ticks.add(Expect.revivedOffers(2)); ticks.add(Expect.deployStepCount(3)); ticks.add(Expect.deployStepStatus("hello", "hello-0:[server]", Status.PREPARED)); ticks.add(Expect.deployStepStatus("world", "world-0:[server]", Status.PENDING)); ticks.add(Expect.deployStepStatus("world", "world-1:[server]", Status.PENDING)); ticks.add(Expect.taskNameKilled("world-0-server", 1)); // killed regardless of current TASK_FAILED state ticks.add(Expect.recoveryStepCount(2));
ticks.add(Expect.reconciledImplicitly()); ticks.add(Expect.deployStepStatus("hello-deploy", "hello-0:[server]", Status.PENDING)); ticks.add(Send.offerBuilder("hello").build()); ticks.add(Expect.launchedTasks("hello-0-server")); ticks.add(Expect.deployStepStatus("hello-deploy", "hello-0:[server]", Status.STARTING)); ticks.add(Expect.revivedOffers(1)); ticks.add(Expect.suppressedOffers(0)); ticks.add(Expect.reconciledExplicitly(result.getPersister())); ticks.add(Expect.reconciledImplicitly()); ticks.add(Expect.deployStepStatus("hello-deploy", "hello-0:[server]", Status.PENDING)); ticks.add(Send.offerBuilder("hello").build()); ticks.add(Expect.taskNameKilled("hello-0-server", 1)); ticks.add(Expect.launchedTasks("hello-0-server")); ticks.add(Expect.deployStepStatus("hello-deploy", "hello-0:[server]", Status.STARTING)); ticks.add(Send.taskStatus("hello-0-server", Protos.TaskState.TASK_RUNNING).build()); ticks.add(Expect.deployStepStatus("hello-deploy", "hello-0:[server]", Status.COMPLETE)); ticks.add(Expect.allPlansComplete()); ticks.add(Expect.suppressedOffers(0)); ticks.add(Send.offerBuilder("hello").build()); ticks.add(Expect.declinedLastOffer()); ticks.add(Expect.suppressedOffers(1));
ticks.add(Expect.reconciledImplicitly()); ticks.add(Expect.launchedTasks("hello-0-essential", "hello-0-nonessential")); ticks.add(Expect.declinedLastOffer()); ticks.add(Expect.allPlansComplete()); ticks.add(Expect.declinedLastOffer()); if (essential) { ticks.add(Expect.taskNameKilled("hello-0-nonessential", 1)); ticks.add(Expect.taskNameNotKilled("hello-0-essential")); } else { ticks.add(Expect.taskNameNotKilled("hello-0-nonessential")); ticks.add(Expect.taskNameNotKilled("hello-0-essential")); ticks.add(Expect.launchedTasks("hello-0-essential", "hello-0-nonessential")); ticks.add(Send.taskStatus("hello-0-nonessential", Protos.TaskState.TASK_RUNNING).build()); ticks.add(Send.taskStatus("hello-0-essential", Protos.TaskState.TASK_RUNNING).build()); } else { ticks.add(Expect.launchedTasks("hello-0-nonessential")); ticks.add(Send.taskStatus("hello-0-nonessential", Protos.TaskState.TASK_RUNNING).build()); ticks.add(Expect.allPlansComplete()); ticks.add(Expect.samePod("hello-0-essential", "hello-0-nonessential"));
ticks.add(Expect.reconciledExplicitly(result.getPersister())); ticks.add(Send.taskStatus("hello-0-server", Protos.TaskState.TASK_RUNNING).build()); ticks.add(Send.taskStatus("world-0-server", Protos.TaskState.TASK_RUNNING).setReadinessCheckExitCode(0).build()); ticks.add(Expect.reconciledImplicitly()); ticks.add(Expect.declinedLastOffer()); ticks.add(Expect.taskNameKilled("world-1-server", 1)); ticks.add(Expect.unreservedTasks("world-1-server")); ticks.add(new ExpectDecommissionPlanProgress(Arrays.asList( new StepCount("world-1", 1, 0, stepCount - 1), new StepCount("world-0", stepCount, 0, 0)))); // FAIL ticks.add(Expect.knownTasks(result.getPersister(), "hello-0-server", "world-0-server", "world-1-server")); ticks.add(Send.offerBuilder("world").build()); ticks.add(Expect.declinedLastOffer()); ticks.add(Expect.knownTasks(result.getPersister(), "hello-0-server", "world-0-server")); ticks.add(new ExpectDecommissionPlanProgress(Arrays.asList( new StepCount("world-1", 0, 0, stepCount), new StepCount("world-0", stepCount, 0, 0)))); ticks.add(new ExpectDecommissionPlanProgress(Arrays.asList( new StepCount("world-1", 0, 0, stepCount), new StepCount("world-0", 1, 0, stepCount - 1)))); ticks.add(Expect.taskNameKilled("world-0-server", 1)); ticks.add(new ExpectEmptyResources(result.getPersister(), "world-0-server")); ticks.add(Expect.knownTasks(result.getPersister(), "hello-0-server", "world-0-server")); ticks.add(Send.offerBuilder("world").build()); ticks.add(Expect.declinedLastOffer()); ticks.add(Expect.knownTasks(result.getPersister(), "hello-0-server"));
ticks.add(Expect.reconciledImplicitly()); ticks.add(Expect.launchedTasks("hello-0-server")); ticks.add(Expect.revivedOffers(1)); ticks.add(Expect.declinedLastOffer()); ticks.add(Expect.launchedTasks("world-0-server")); ticks.add(Expect.revivedOffers(2)); ticks.add(Expect.declinedLastOffer()); ticks.add(Expect.revivedOffers(3)); ticks.add(Send.offerBuilder("world").build()); ticks.add(Expect.declinedLastOffer()); ticks.add(Expect.launchedTasks("world-1-server")); ticks.add(Send.taskStatus("world-1-server", Protos.TaskState.TASK_RUNNING).setReadinessCheckExitCode(0).build()); ticks.add(Expect.declinedLastOffer()); ticks.add(Expect.suppressedOffers(1)); ticks.add(Expect.allPlansComplete());
ticks.add(Expect.reconciledImplicitly()); ticks.add(Expect.launchedTasks("hello-0-server")); ticks.add(Expect.declinedLastOffer()); ticks.add(Expect.launchedTasks("world-0-server")); ticks.add(Expect.deployStepStatus("world", "world-0:[server]", Status.STARTING)); postReadinessStatus = Status.STARTED; ticks.add(Expect.deployStepStatus("world", "world-0:[server]", postReadinessStatus)); ticks.add(Expect.declinedLastOffer()); ticks.add(Expect.reconciledExplicitly(result.getPersister())); ticks.add(Expect.deployStepStatus("world", "world-0:[server]", expectedStatus));
/** * Checks that unexpected Tasks are killed. */ @Test public void testZombieTaskKilling() throws Exception { Collection<SimulationTick> ticks = new ArrayList<>(); ticks.add(Send.register()); ticks.add(Expect.reconciledImplicitly()); // Verify that service launches 1 hello pod. ticks.add(Send.offerBuilder("hello").build()); ticks.add(Expect.launchedTasks("hello-0-server")); // Running, no readiness check is applicable: ticks.add(Send.taskStatus("hello-0-server", Protos.TaskState.TASK_RUNNING).build()); String taskId = CommonIdUtils.toTaskId("bogus", "taskid").getValue(); ticks.add(Send.taskStatus("hello-0-server", Protos.TaskState.TASK_RUNNING) .setTaskId(taskId) .build()); // Unknown task that we made up above was killed, but the launched task was not killed: ticks.add(Expect.taskIdKilled(taskId)); ticks.add(Expect.taskNameNotKilled("hello-0-server")); new ServiceTestRunner("simple.yml").run(ticks); }
ticks.add(Expect.revivedOffers(3)); ticks.add(Expect.recoveryStepStatus("hello-0:[server]", "hello-0:[server]", Status.PREPARED)); ticks.add(Expect.revivedOffers(4)); ticks.add(Expect.launchedTasks("hello-0-server")); ticks.add(Send.taskStatus("hello-0-server", Protos.TaskState.TASK_RUNNING).build()); ticks.add(Expect.allPlansComplete());
ticks.add(Expect.reconciledExplicitly(result.getPersister())); ticks.add(Send.taskStatus("hello-0-server", Protos.TaskState.TASK_RUNNING).build()); ticks.add(Send.taskStatus("world-0-server", Protos.TaskState.TASK_RUNNING).setReadinessCheckExitCode(0).build()); ticks.add(Expect.reconciledImplicitly()); ticks.add(Expect.declinedLastOffer());
ticks.add(Expect.planStatus(Constants.DEPLOY_PLAN_NAME, Status.ERROR));
LOGGER.info("EXPECT: {}", tick.getDescription()); try { ((Expect) tick).expect(clusterState, mockDriver); } catch (Throwable e) { throw buildSimulationError(ticks, tick, e);
@Test public void testSerialStrategyParallelSteps() throws Exception { Collection<SimulationTick> ticks = new ArrayList<>(); ticks.add(Send.register()); ticks.add(Expect.reconciledImplicitly()); // Service should launch hello-0-first and hello-0-second at the same time. ticks.add(Send.offerBuilder("hello").setCount(3).build()); ticks.add(Expect.launchedTasks("hello-0-first", "hello-0-second")); ticks.add(Send.taskStatus("hello-0-first", Protos.TaskState.TASK_RUNNING).build()); // New offer declined since hello-0-second isn't RUNNING yet: ticks.add(Send.offerBuilder("hello").setCount(3).build()); ticks.add(Expect.declinedLastOffer()); ticks.add(Send.taskStatus("hello-0-second", Protos.TaskState.TASK_RUNNING).build()); ticks.add(Expect.samePod("hello-0-first", "hello-0-second")); // Now hello-1 may be deployed: ticks.add(Send.offerBuilder("hello").setCount(3).build()); ticks.add(Expect.launchedTasks("hello-1-first", "hello-1-second")); ticks.add(Send.taskStatus("hello-1-first", Protos.TaskState.TASK_RUNNING).build()); ticks.add(Send.taskStatus("hello-1-second", Protos.TaskState.TASK_RUNNING).build()); ticks.add(Expect.samePod("hello-1-first", "hello-1-second")); // No more hellos to launch: ticks.add(Send.offerBuilder("hello").setCount(3).build()); ticks.add(Expect.declinedLastOffer()); ticks.add(Expect.allPlansComplete()); new ServiceTestRunner("custom_steps.yml") .setSchedulerEnv( "DEPLOY_STRATEGY", "serial", "DEPLOY_STEPS", "[[first, second]]") .run(ticks); }
@Test public void testSwitchToInvalidPlacementConstraint() throws Exception { ServiceTestResult initial = new ServiceTestRunner() .setSchedulerEnv("HELLO_PLACEMENT", VALID_HOSTNAME_CONSTRAINT) .run(getDefaultDeploymentTicks()); Collection<SimulationTick> ticks = new ArrayList<>(); ticks.add(Send.register()); ticks.add(Expect.planStatus("deploy", Status.ERROR)); new ServiceTestRunner() .setState(initial) .setSchedulerEnv("HELLO_PLACEMENT", INVALID_HOSTNAME_CONSTRAINT) .run(ticks); }
ticks.add(Expect.reconciledImplicitly()); ticks.add(Expect.launchedTasks(2, "hello-0-first", "hello-1-first")); ticks.add(Expect.declinedLastOffer()); // hello-0-first not running yet ticks.add(Send.offerBuilder("hello").setCount(3).setPodIndexToReoffer(1).build()); ticks.add(Expect.declinedLastOffer()); // hello-1-first not running yet ticks.add(Expect.declinedLastOffer()); // need to reoffer hello-0 or hello-1's resources ticks.add(Expect.launchedTasks("hello-0-second")); ticks.add(Send.offerBuilder("hello").setCount(3).setPodIndexToReoffer(1).build()); ticks.add(Expect.launchedTasks("hello-1-second")); ticks.add(Expect.samePod("hello-0-first", "hello-0-second")); ticks.add(Expect.samePod("hello-1-first", "hello-1-second")); ticks.add(Expect.declinedLastOffer()); ticks.add(Expect.allPlansComplete());
/** * Verifies that a pod was launched with exactly the provided task names in the last accept call. */ public static Expect launchedTasks(String... taskNames) { return launchedTasks(Arrays.asList(taskNames)); }
ticks.add(Expect.reconciledImplicitly()); ticks.add(Expect.launchedTasks("hello-0-first")); ticks.add(Expect.declinedLastOffer()); ticks.add(Expect.declinedLastOffer()); ticks.add(Expect.launchedTasks("hello-0-second")); ticks.add(Expect.samePod("hello-0-first", "hello-0-second")); ticks.add(Expect.launchedTasks("hello-1-first")); ticks.add(Expect.declinedLastOffer()); ticks.add(Expect.declinedLastOffer()); ticks.add(Expect.launchedTasks("hello-1-second")); ticks.add(Expect.samePod("hello-1-first", "hello-1-second")); ticks.add(Expect.allPlansComplete());
/** * Verifies that a pod was launched with exactly the provided task names over the last N accept calls. If the last * offer cycle had multiple offers from different agents, then separate accept calls are made on a per-agent basis. */ public static Expect launchedTasks(int acceptsToCheck, String... taskNames) { return launchedTasks(acceptsToCheck, Arrays.asList(taskNames)); }