use of com.aws.greengrass.integrationtests.lifecyclemanager.KernelTest.ExpectedStateTransition in project aws-greengrass-nucleus by aws-greengrass.
the class ServiceDependencyLifecycleTest method GIVEN_hard_dependency_WHEN_dependency_goes_through_lifecycle_events_THEN_customer_app_is_impacted.
@Test
void GIVEN_hard_dependency_WHEN_dependency_goes_through_lifecycle_events_THEN_customer_app_is_impacted() throws Throwable {
// setup
kernel = new Kernel();
URL configFile = ServiceDependencyLifecycleTest.class.getResource("service_with_hard_dependency.yaml");
ConfigPlatformResolver.initKernelWithMultiPlatformConfig(kernel, configFile);
// WHEN_kernel_launch_THEN_customer_app_starts_after_hard_dependency_is_running
LinkedList<ExpectedStateTransition> expectedDuringLaunch = new LinkedList<>(Arrays.asList(new ExpectedStateTransition(HardDependency, State.INSTALLED, State.STARTING), new ExpectedStateTransition(HardDependency, State.STARTING, State.RUNNING), new ExpectedStateTransition(CustomerApp, State.INSTALLED, State.STARTING), new ExpectedStateTransition(CustomerApp, State.STARTING, State.RUNNING), new ExpectedStateTransition("main", State.STOPPING, State.FINISHED)));
testRoutine(TEST_ROUTINE_SHORT_TIMEOUT, kernel, kernel::launch, "kernel launched", expectedDuringLaunch, Collections.emptySet());
// WHEN_dependency_removed_THEN_customer_app_stays_running
LinkedList<ExpectedStateTransition> expectedDepRemoved = new LinkedList<>(Arrays.asList(new ExpectedStateTransition(HardDependency, State.RUNNING, State.STOPPING)));
Set<ExpectedStateTransition> unexpectedDepRemoved = new HashSet<>(Arrays.asList(new ExpectedStateTransition(CustomerApp, State.RUNNING, State.STOPPING), new ExpectedStateTransition(CustomerApp, State.STOPPING, State.FINISHED)));
Map<String, Object> configRemoveDep = new HashMap<String, Object>() {
{
put(SERVICES_NAMESPACE_TOPIC, new HashMap<String, Object>() {
{
put("main", new HashMap<String, Object>() {
{
put(SERVICE_DEPENDENCIES_NAMESPACE_TOPIC, Arrays.asList(CustomerApp, DEFAULT_NUCLEUS_COMPONENT_NAME));
}
});
put(CustomerApp, new HashMap<String, Object>() {
{
putAll(kernel.findServiceTopic(CustomerApp).toPOJO());
put(SERVICE_DEPENDENCIES_NAMESPACE_TOPIC, Collections.emptyList());
}
});
put(DEFAULT_NUCLEUS_COMPONENT_NAME, new HashMap<String, Object>() {
{
putAll(kernel.findServiceTopic(DEFAULT_NUCLEUS_COMPONENT_NAME).toPOJO());
}
});
}
});
}
};
DeploymentConfigMerger configMerger = kernel.getContext().get(DeploymentConfigMerger.class);
DeploymentDocument doc1 = mock(DeploymentDocument.class);
when(doc1.getTimestamp()).thenReturn(System.currentTimeMillis());
when(doc1.getDeploymentId()).thenReturn("removeHardDep");
when(doc1.getFailureHandlingPolicy()).thenReturn(FailureHandlingPolicy.DO_NOTHING);
testRoutine(TEST_ROUTINE_LONG_TIMEOUT, kernel, () -> configMerger.mergeInNewConfig(createMockDeployment(doc1), configRemoveDep).get(60, TimeUnit.SECONDS), "dependency removed", expectedDepRemoved, unexpectedDepRemoved);
// WHEN_dependency_added_THEN_customer_app_restarts
LinkedList<ExpectedStateTransition> expectedDepAdded = new LinkedList<>(Arrays.asList(new ExpectedStateTransition(CustomerApp, State.RUNNING, State.STOPPING), new ExpectedStateTransition(CustomerApp, State.STARTING, State.RUNNING)));
Map<String, Object> configAddDep = ConfigPlatformResolver.resolvePlatformMap(configFile);
DeploymentDocument doc2 = mock(DeploymentDocument.class);
when(doc2.getTimestamp()).thenReturn(System.currentTimeMillis());
when(doc2.getDeploymentId()).thenReturn("addHardDep");
when(doc2.getFailureHandlingPolicy()).thenReturn(FailureHandlingPolicy.DO_NOTHING);
testRoutine(60, kernel, () -> configMerger.mergeInNewConfig(createMockDeployment(doc2), configAddDep).get(10, TimeUnit.SECONDS), "dependency added", expectedDepAdded, Collections.emptySet());
// WHEN_dependency_errored_THEN_customer_app_restarts
LinkedList<ExpectedStateTransition> expectedDuringDepError = new LinkedList<>(Arrays.asList(new ExpectedStateTransition(HardDependency, State.RUNNING, State.ERRORED), new ExpectedStateTransition(CustomerApp, State.RUNNING, State.STOPPING), new ExpectedStateTransition(CustomerApp, State.STARTING, State.RUNNING)));
testRoutine(TEST_ROUTINE_SHORT_TIMEOUT, kernel, () -> kernel.locate(HardDependency).serviceErrored("mock dependency error"), "dependency errored", expectedDuringDepError, Collections.emptySet());
// WHEN_dependency_stops_THEN_customer_app_stays_running
LinkedList<ExpectedStateTransition> expectedDepFinish = new LinkedList<>(Arrays.asList(new ExpectedStateTransition(HardDependency, State.STOPPING, State.FINISHED)));
Set<ExpectedStateTransition> unexpectedDepFinish = new HashSet<>(Arrays.asList(new ExpectedStateTransition(CustomerApp, State.RUNNING, State.STOPPING), new ExpectedStateTransition(CustomerApp, State.STOPPING, State.FINISHED)));
testRoutine(TEST_ROUTINE_MEDIUM_TIMEOUT, kernel, () -> kernel.locate(HardDependency).requestStop(), "dependency stop", expectedDepFinish, unexpectedDepFinish);
// WHEN_dependency_restarts_THEN_customer_app_restarts
LinkedList<ExpectedStateTransition> expectedDepRestart = new LinkedList<>(Arrays.asList(new ExpectedStateTransition(HardDependency, State.STARTING, State.RUNNING), new ExpectedStateTransition(CustomerApp, State.STARTING, State.RUNNING)));
testRoutine(TEST_ROUTINE_SHORT_TIMEOUT, kernel, () -> kernel.locate(HardDependency).requestRestart(), "dependency restart", expectedDepRestart, Collections.emptySet());
// WHEN_dependency_reinstalled_THEN_customer_app_restarts
LinkedList<ExpectedStateTransition> expectedDepReinstall = new LinkedList<>(Arrays.asList(new ExpectedStateTransition(HardDependency, State.NEW, State.INSTALLED), new ExpectedStateTransition(HardDependency, State.STARTING, State.RUNNING), new ExpectedStateTransition(CustomerApp, State.STARTING, State.RUNNING)));
testRoutine(TEST_ROUTINE_SHORT_TIMEOUT, kernel, () -> kernel.locate(HardDependency).requestReinstall(), "dependency reinstall", expectedDepReinstall, Collections.emptySet());
// WHEN_kernel_shutdown_THEN_hard_dependency_waits_for_customer_app_to_close
LinkedList<ExpectedStateTransition> expectedDuringShutdown = new LinkedList<>(Arrays.asList(new ExpectedStateTransition(CustomerApp, State.STOPPING, State.FINISHED), new ExpectedStateTransition(HardDependency, State.STOPPING, State.FINISHED)));
testRoutine(TEST_ROUTINE_SHORT_TIMEOUT, kernel, kernel::shutdown, "kernel shutdown", expectedDuringShutdown, Collections.emptySet());
}
use of com.aws.greengrass.integrationtests.lifecyclemanager.KernelTest.ExpectedStateTransition in project aws-greengrass-nucleus by aws-greengrass.
the class ServiceDependencyLifecycleTest method testRoutine.
@SuppressWarnings({ "PMD.LooseCoupling", "PMD.CloseResource" })
private static void testRoutine(long timeoutSeconds, Kernel kernel, Crashable action, String actionName, LinkedList<ExpectedStateTransition> expectedStateTransitions, Set<ExpectedStateTransition> unexpectedStateTransitions) throws Throwable {
Context context = kernel.getContext();
CountDownLatch assertionLatch = new CountDownLatch(1);
List<ExpectedStateTransition> unexpectedSeenInOrder = new LinkedList<>();
GlobalStateChangeListener listener = (GreengrassService service, State oldState, State newState) -> {
if (!expectedStateTransitions.isEmpty()) {
ExpectedStateTransition expected = expectedStateTransitions.peek();
if (service.getName().equals(expected.serviceName) && oldState.equals(expected.was) && newState.equals(expected.current)) {
logger.atWarn().kv("expected", expected).log("Just saw expected state event for service");
expectedStateTransitions.pollFirst();
}
if (expectedStateTransitions.isEmpty()) {
assertionLatch.countDown();
}
}
ExpectedStateTransition actual = new ExpectedStateTransition(service.getName(), oldState, newState);
logger.atInfo().kv("actual", actual).log("Actual state event");
if (unexpectedStateTransitions.contains(actual)) {
unexpectedSeenInOrder.add(actual);
}
};
context.addGlobalStateChangeListener(listener);
action.run();
assertionLatch.await(timeoutSeconds, TimeUnit.SECONDS);
context.removeGlobalStateChangeListener(listener);
if (!expectedStateTransitions.isEmpty()) {
logger.atError().kv("expected", expectedStateTransitions).kv("action", actionName).log("Fail to see state events");
fail("Didn't see all expected state transitions for " + actionName);
}
if (!unexpectedSeenInOrder.isEmpty()) {
logger.atError().kv("unexpected", unexpectedSeenInOrder).kv("action", actionName).log("Saw unexpected state events");
fail("Saw unexpected state transitions for " + actionName);
}
logger.atWarn().log("End of " + actionName);
}
use of com.aws.greengrass.integrationtests.lifecyclemanager.KernelTest.ExpectedStateTransition in project aws-greengrass-nucleus by aws-greengrass.
the class ServiceDependencyLifecycleTest method testStateTransitionsInNoOrder.
@SuppressWarnings({ "PMD.CloseResource" })
private static void testStateTransitionsInNoOrder(long timeoutSeconds, Kernel kernel, Crashable action, String actionName, Set<ExpectedStateTransition> expectedStateTransitions) throws Throwable {
Context context = kernel.getContext();
CountDownLatch assertionLatch = new CountDownLatch(expectedStateTransitions.size());
GlobalStateChangeListener listener = (GreengrassService service, State oldState, State newState) -> {
for (ExpectedStateTransition est : expectedStateTransitions) {
if (service.getName().equals(est.serviceName) && oldState == est.was && newState == est.current) {
logger.atInfo().kv("expected", est).log("Just saw expected state transition");
assertionLatch.countDown();
} else {
ExpectedStateTransition other = new ExpectedStateTransition(service.getName(), oldState, newState);
logger.atInfo().kv("other", other).log("Saw other state transition event");
}
}
};
context.addGlobalStateChangeListener(listener);
action.run();
assertionLatch.await(timeoutSeconds, TimeUnit.SECONDS);
context.removeGlobalStateChangeListener(listener);
if (assertionLatch.getCount() != 0) {
fail("Did not see all the expected state transitions for action " + actionName);
}
}
use of com.aws.greengrass.integrationtests.lifecyclemanager.KernelTest.ExpectedStateTransition in project aws-greengrass-nucleus by aws-greengrass.
the class ServiceDependencyLifecycleTest method GIVEN_soft_dependency_WHEN_dependency_goes_through_lifecycle_events_THEN_customer_app_is_not_impacted.
@Test
void GIVEN_soft_dependency_WHEN_dependency_goes_through_lifecycle_events_THEN_customer_app_is_not_impacted() throws Throwable {
// setup
kernel = new Kernel();
URL configFile = ServiceDependencyLifecycleTest.class.getResource("service_with_soft_dependency.yaml");
ConfigPlatformResolver.initKernelWithMultiPlatformConfig(kernel, configFile);
Set<ExpectedStateTransition> unexpectedDuringAllSoftDepChange = new HashSet<>(Arrays.asList(new ExpectedStateTransition(CustomerApp, State.RUNNING, State.STOPPING), new ExpectedStateTransition(CustomerApp, State.STOPPING, State.FINISHED)));
HashSet<ExpectedStateTransition> expectedStateTransitions = new HashSet<>(Arrays.asList(new ExpectedStateTransition(CustomerApp, State.NEW, State.INSTALLED), new ExpectedStateTransition(CustomerApp, State.INSTALLED, State.STARTING), new ExpectedStateTransition(SoftDependency, State.INSTALLED, State.STARTING), new ExpectedStateTransition(SoftDependency, State.STARTING, State.RUNNING), new ExpectedStateTransition(CustomerApp, State.STARTING, State.RUNNING)));
testStateTransitionsInNoOrder(TEST_ROUTINE_SHORT_TIMEOUT, kernel, kernel::launch, "kernel launch", expectedStateTransitions);
// WHEN_dependency_removed_THEN_customer_app_stays_running
LinkedList<ExpectedStateTransition> expectedDepRemoved = new LinkedList<>(Arrays.asList(new ExpectedStateTransition(SoftDependency, State.RUNNING, State.STOPPING)));
Map<String, Object> configRemoveDep = new HashMap<String, Object>() {
{
put(SERVICES_NAMESPACE_TOPIC, new HashMap<String, Object>() {
{
put("main", new HashMap<String, Object>() {
{
put(SERVICE_DEPENDENCIES_NAMESPACE_TOPIC, Arrays.asList(CustomerApp, DEFAULT_NUCLEUS_COMPONENT_NAME));
}
});
put(CustomerApp, new HashMap<String, Object>() {
{
putAll(kernel.findServiceTopic(CustomerApp).toPOJO());
put(SERVICE_DEPENDENCIES_NAMESPACE_TOPIC, Collections.emptyList());
}
});
put(DEFAULT_NUCLEUS_COMPONENT_NAME, new HashMap<String, Object>() {
{
putAll(kernel.findServiceTopic(DEFAULT_NUCLEUS_COMPONENT_NAME).toPOJO());
}
});
}
});
}
};
DeploymentConfigMerger configMerger = kernel.getContext().get(DeploymentConfigMerger.class);
DeploymentDocument doc1 = mock(DeploymentDocument.class);
when(doc1.getTimestamp()).thenReturn(System.currentTimeMillis());
when(doc1.getDeploymentId()).thenReturn("removeSoftDep");
when(doc1.getFailureHandlingPolicy()).thenReturn(FailureHandlingPolicy.DO_NOTHING);
testRoutine(TEST_ROUTINE_MEDIUM_TIMEOUT, kernel, () -> configMerger.mergeInNewConfig(createMockDeployment(doc1), configRemoveDep).get(30, TimeUnit.SECONDS), "dependency removed", expectedDepRemoved, unexpectedDuringAllSoftDepChange);
// WHEN_dependency_added_THEN_customer_app_restarts
LinkedList<ExpectedStateTransition> expectedDepAdded = new LinkedList<>(Arrays.asList(new ExpectedStateTransition(CustomerApp, State.RUNNING, State.STOPPING), new ExpectedStateTransition(SoftDependency, State.STARTING, State.RUNNING), new ExpectedStateTransition(CustomerApp, State.STARTING, State.RUNNING)));
Map<String, Object> configAddDep = ConfigPlatformResolver.resolvePlatformMap(configFile);
DeploymentDocument doc2 = mock(DeploymentDocument.class);
when(doc2.getTimestamp()).thenReturn(System.currentTimeMillis());
when(doc2.getDeploymentId()).thenReturn("addSoftDep");
when(doc2.getFailureHandlingPolicy()).thenReturn(FailureHandlingPolicy.DO_NOTHING);
testRoutine(TEST_ROUTINE_LONG_TIMEOUT, kernel, () -> configMerger.mergeInNewConfig(createMockDeployment(doc2), configAddDep).get(60, TimeUnit.SECONDS), "dependency added", expectedDepAdded, Collections.emptySet());
// WHEN_dependency_errored_THEN_customer_app_stays_running
LinkedList<ExpectedStateTransition> expectedDuringDepError = new LinkedList<>(Arrays.asList(new ExpectedStateTransition(SoftDependency, State.RUNNING, State.ERRORED), new ExpectedStateTransition(SoftDependency, State.STARTING, State.RUNNING)));
testRoutine(TEST_ROUTINE_LONG_TIMEOUT, kernel, () -> kernel.locate(SoftDependency).serviceErrored("mock dependency error"), "dependency errored", expectedDuringDepError, unexpectedDuringAllSoftDepChange);
// WHEN_dependency_stops_THEN_customer_app_stays_running
LinkedList<ExpectedStateTransition> expectedDepFinish = new LinkedList<>(Arrays.asList(new ExpectedStateTransition(SoftDependency, State.STOPPING, State.FINISHED)));
testRoutine(TEST_ROUTINE_MEDIUM_TIMEOUT, kernel, () -> kernel.locate(SoftDependency).requestStop(), "dependency " + "stop", expectedDepFinish, unexpectedDuringAllSoftDepChange);
// WHEN_dependency_restarts_THEN_customer_app_stays_running
LinkedList<ExpectedStateTransition> expectedDepRestart = new LinkedList<>(Arrays.asList(new ExpectedStateTransition(SoftDependency, State.STARTING, State.RUNNING)));
testRoutine(TEST_ROUTINE_MEDIUM_TIMEOUT, kernel, () -> kernel.locate(SoftDependency).requestRestart(), "dependency restart", expectedDepRestart, unexpectedDuringAllSoftDepChange);
// WHEN_dependency_reinstalled_THEN_customer_app_stays_running
LinkedList<ExpectedStateTransition> expectedDepReinstall = new LinkedList<>(Arrays.asList(new ExpectedStateTransition(SoftDependency, State.NEW, State.INSTALLED), new ExpectedStateTransition(SoftDependency, State.STARTING, State.RUNNING)));
testRoutine(TEST_ROUTINE_MEDIUM_TIMEOUT, kernel, () -> kernel.locate(SoftDependency).requestReinstall(), "dependency reinstall", expectedDepReinstall, unexpectedDuringAllSoftDepChange);
// WHEN_kernel_shutdown_THEN_soft_dependency_does_not_wait_for_customer_app_to_close
LinkedList<ExpectedStateTransition> expectedDuringShutdown = new LinkedList<>(Arrays.asList(new ExpectedStateTransition(SoftDependency, State.STOPPING, State.FINISHED), new ExpectedStateTransition(CustomerApp, State.STOPPING, State.FINISHED)));
testRoutine(TEST_ROUTINE_MEDIUM_TIMEOUT, kernel, () -> kernel.shutdown(60), "kernel shutdown", expectedDuringShutdown, Collections.emptySet());
}
use of com.aws.greengrass.integrationtests.lifecyclemanager.KernelTest.ExpectedStateTransition in project aws-greengrass-nucleus by aws-greengrass.
the class ServiceDependencyLifecycleTest method WHEN_dependency_type_changes_with_no_other_updates_THEN_customer_app_should_not_restart.
@Test
void WHEN_dependency_type_changes_with_no_other_updates_THEN_customer_app_should_not_restart() throws Throwable {
// Assuming no other changes in customer app and dependency service
String Dependency = SoftDependency;
kernel = new Kernel();
URL configFile = ServiceDependencyLifecycleTest.class.getResource("service_with_soft_dependency.yaml");
ConfigPlatformResolver.initKernelWithMultiPlatformConfig(kernel, configFile);
kernel.launch();
assertThat(kernel.locate("main")::getState, eventuallyEval(is(State.FINISHED)));
// The test below assumes SoftDependency is already running and checks against RUNNING->STOPPING and
// STARTING->RUNNING. But I have seen cases where it hasn't get to the initial RUNNING state yet. So we need to
// wait for SoftDependency to be RUNNING first.
assertThat(kernel.locate("SoftDependency")::getState, eventuallyEval(is(State.RUNNING)));
List<ExpectedStateTransition> stateTransitions = Arrays.asList(new ExpectedStateTransition(CustomerApp, State.RUNNING, State.STOPPING), new ExpectedStateTransition(CustomerApp, State.STARTING, State.RUNNING));
Map<String, Object> depTypeSoftToHard = ConfigPlatformResolver.resolvePlatformMap(configFile);
((Map) ((Map) depTypeSoftToHard.get(SERVICES_NAMESPACE_TOPIC)).get(CustomerApp)).put(SERVICE_DEPENDENCIES_NAMESPACE_TOPIC, Arrays.asList(Dependency + ":" + DependencyType.HARD));
DeploymentConfigMerger configMerger = kernel.getContext().get(DeploymentConfigMerger.class);
DeploymentDocument doc2 = mock(DeploymentDocument.class);
when(doc2.getTimestamp()).thenReturn(System.currentTimeMillis());
when(doc2.getDeploymentId()).thenReturn("typeSoftToHard");
when(doc2.getFailureHandlingPolicy()).thenReturn(FailureHandlingPolicy.DO_NOTHING);
testRoutine(TEST_ROUTINE_MEDIUM_TIMEOUT, kernel, () -> configMerger.mergeInNewConfig(createMockDeployment(doc2), depTypeSoftToHard).get(10, TimeUnit.SECONDS), "dependency type changes from soft to hard", new LinkedList<>(), new HashSet<>(stateTransitions));
Map<String, Object> depTypeHardToSoft = ConfigPlatformResolver.resolvePlatformMap(configFile);
((Map) ((Map) depTypeHardToSoft.get(SERVICES_NAMESPACE_TOPIC)).get(CustomerApp)).put(SERVICE_DEPENDENCIES_NAMESPACE_TOPIC, Arrays.asList(Dependency + ":" + DependencyType.SOFT));
DeploymentDocument doc1 = mock(DeploymentDocument.class);
when(doc1.getTimestamp()).thenReturn(System.currentTimeMillis());
when(doc1.getDeploymentId()).thenReturn("typeHardToSoft");
when(doc1.getFailureHandlingPolicy()).thenReturn(FailureHandlingPolicy.DO_NOTHING);
testRoutine(TEST_ROUTINE_MEDIUM_TIMEOUT, kernel, () -> configMerger.mergeInNewConfig(createMockDeployment(doc1), depTypeHardToSoft).get(10, TimeUnit.SECONDS), "dependency type changes from hard to soft", new LinkedList<>(), new HashSet<>(stateTransitions));
}
Aggregations