Adds VanillaSoftwareProcessTest (as non-integration) Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/13ce4cb8 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/13ce4cb8 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/13ce4cb8
Branch: refs/heads/master Commit: 13ce4cb8c5767a7a99aa77a09e1f91a9ebdee7a7 Parents: bc7e0af Author: Aled Sage <aled.s...@gmail.com> Authored: Tue Jun 28 21:14:37 2016 +0100 Committer: Aled Sage <aled.s...@gmail.com> Committed: Tue Jun 28 21:14:37 2016 +0100 ---------------------------------------------------------------------- .../core/internal/ssh/RecordingSshTool.java | 136 ++++++-- .../base/VanillaSoftwareProcessTest.java | 322 +++++++++++++++++++ 2 files changed, 430 insertions(+), 28 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/13ce4cb8/core/src/test/java/org/apache/brooklyn/util/core/internal/ssh/RecordingSshTool.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/util/core/internal/ssh/RecordingSshTool.java b/core/src/test/java/org/apache/brooklyn/util/core/internal/ssh/RecordingSshTool.java index f7faaca..2ac8acf 100644 --- a/core/src/test/java/org/apache/brooklyn/util/core/internal/ssh/RecordingSshTool.java +++ b/core/src/test/java/org/apache/brooklyn/util/core/internal/ssh/RecordingSshTool.java @@ -28,16 +28,53 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import javax.annotation.Nullable; + import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.text.Strings; +import com.google.common.base.Objects; +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -/** Mock tool */ +/** + * For stubbing out the {@link SshTool}, so that no real ssh/scp commands are executed. + * Records all the commands that are executed, so that assertions can subsequently be made. + * + * By default, all commands return exit code 0, and no stdout/stderr. + * + * This can be customised for particular commands using {@link #setCustomResponse(String, CustomResponseGenerator)} + * to specify the exit code, stdout and stderr of a matching command. + */ public class RecordingSshTool implements SshTool { + public static class ExecParams { + public final Map<String, ?> props; + public final List<String> commands; + public final Map<String, ?> env; + + public ExecParams(Map<String, ?> props, List<String> commands, Map<String, ?> env) { + this.props = props; + this.commands = commands; + this.env = env; + } + + @Override + public String toString() { + return Objects.toStringHelper(this) + .add("props", props) + .add("commands", commands) + .add("env", env).toString(); + } + } + + public interface CustomResponseGenerator { + public CustomResponse generate(ExecParams execParams); + } + public static class CustomResponse { public final int exitCode; public final String stdout; @@ -53,6 +90,14 @@ public class RecordingSshTool implements SshTool { public String toString() { return "CustomResponse["+exitCode+"; "+stdout+"; "+stderr+"]"; } + + public CustomResponseGenerator toGenerator() { + return new CustomResponseGenerator() { + @Override public CustomResponse generate(ExecParams execParams) { + return CustomResponse.this; + } + }; + } } public static class ExecCmd { @@ -74,9 +119,38 @@ public class RecordingSshTool implements SshTool { } } + public static class ExecCmdPredicates { + public static Predicate<ExecCmd> containsEnv(final Map<String, ?> expected) { + return new Predicate<ExecCmd>() { + @Override public boolean apply(@Nullable ExecCmd input) { + if (input == null) return false; + if (input.env == null) return false; + for (Map.Entry<?,?> entry : expected.entrySet()) { + Object key = entry.getKey(); + if (!(input.env.containsKey(key) && Objects.equal(entry.getValue(), input.env.get(key)))) { + return false; + } + } + return true; + }}; + } + public static Predicate<ExecCmd> containsCmd(final String expected) { + return new Predicate<ExecCmd>() { + @Override public boolean apply(@Nullable ExecCmd input) { + if (input == null) return false; + for (String cmd : input.commands) { + if (expected.equals(cmd)) { + return true; + } + } + return false; + }}; + } + } + public static List<ExecCmd> execScriptCmds = Lists.newCopyOnWriteArrayList(); public static List<Map<?,?>> constructorProps = Lists.newCopyOnWriteArrayList(); - public static Map<String, CustomResponse> customResponses = Maps.newConcurrentMap(); + public static Map<String, CustomResponseGenerator> customResponses = Maps.newConcurrentMap(); private boolean connected; @@ -86,10 +160,22 @@ public class RecordingSshTool implements SshTool { customResponses.clear(); } - public static void setCustomResponse(String cmdRegex, CustomResponse response) { + public static void clearCmdHistory() { + execScriptCmds.clear(); + } + + public static void setCustomResponse(String cmdRegex, CustomResponseGenerator response) { customResponses.put(cmdRegex, checkNotNull(response, "response")); } + public static void setCustomResponse(String cmdRegex, CustomResponse response) { + customResponses.put(cmdRegex, checkNotNull(response, "response").toGenerator()); + } + + public static List<ExecCmd> getExecCmds() { + return ImmutableList.copyOf(execScriptCmds); + } + public static ExecCmd getLastExecCmd() { return execScriptCmds.get(execScriptCmds.size()-1); } @@ -110,34 +196,14 @@ public class RecordingSshTool implements SshTool { return connected; } @Override public int execScript(Map<String, ?> props, List<String> commands, Map<String, ?> env) { - execScriptCmds.add(new ExecCmd(props, "", commands, env)); - for (String cmd : commands) { - for (Entry<String, CustomResponse> entry : customResponses.entrySet()) { - if (cmd.matches(entry.getKey())) { - CustomResponse response = entry.getValue(); - writeCustomResponseStreams(props, response); - return response.exitCode; - } - } - } - return 0; + return execInternal(props, commands, env); + } + @Override public int execCommands(Map<String, ?> props, List<String> commands, Map<String, ?> env) { + return execInternal(props, commands, env); } @Override public int execScript(Map<String, ?> props, List<String> commands) { return execScript(props, commands, ImmutableMap.<String,Object>of()); } - @Override public int execCommands(Map<String, ?> props, List<String> commands, Map<String, ?> env) { - execScriptCmds.add(new ExecCmd(props, "", commands, env)); - for (String cmd : commands) { - for (Entry<String, CustomResponse> entry : customResponses.entrySet()) { - if (cmd.matches(entry.getKey())) { - CustomResponse response = entry.getValue(); - writeCustomResponseStreams(props, response); - return response.exitCode; - } - } - } - return 0; - } @Override public int execCommands(Map<String, ?> props, List<String> commands) { return execCommands(props, commands, ImmutableMap.<String,Object>of()); } @@ -153,6 +219,20 @@ public class RecordingSshTool implements SshTool { @Override public int copyFromServer(Map<String, ?> props, String pathAndFileOnRemoteServer, File local) { return 0; } + protected int execInternal(Map<String, ?> props, List<String> commands, Map<String, ?> env) { + execScriptCmds.add(new ExecCmd(props, "", commands, env)); + for (String cmd : commands) { + for (Entry<String, CustomResponseGenerator> entry : customResponses.entrySet()) { + if (cmd.matches(entry.getKey())) { + CustomResponseGenerator responseGenerator = entry.getValue(); + CustomResponse response = responseGenerator.generate(new ExecParams(props, commands, env)); + writeCustomResponseStreams(props, response); + return response.exitCode; + } + } + } + return 0; + } protected void writeCustomResponseStreams(Map<String, ?> props, CustomResponse response) { try { if (Strings.isNonBlank(response.stdout) && props.get(SshTool.PROP_OUT_STREAM.getName()) != null) { @@ -165,4 +245,4 @@ public class RecordingSshTool implements SshTool { Exceptions.propagate(e); } } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/13ce4cb8/software/base/src/test/java/org/apache/brooklyn/entity/software/base/VanillaSoftwareProcessTest.java ---------------------------------------------------------------------- diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/VanillaSoftwareProcessTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/VanillaSoftwareProcessTest.java new file mode 100644 index 0000000..3b30328 --- /dev/null +++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/VanillaSoftwareProcessTest.java @@ -0,0 +1,322 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.brooklyn.entity.software.base; + +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.brooklyn.api.entity.EntitySpec; +import org.apache.brooklyn.api.location.Location; +import org.apache.brooklyn.api.location.LocationSpec; +import org.apache.brooklyn.api.location.MachineLocation; +import org.apache.brooklyn.core.entity.Entities; +import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport; +import org.apache.brooklyn.location.byon.FixedListMachineProvisioningLocation; +import org.apache.brooklyn.location.ssh.SshMachineLocation; +import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool; +import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool.CustomResponse; +import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool.ExecCmd; +import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool.ExecCmdPredicates; +import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool.ExecParams; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +public class VanillaSoftwareProcessTest extends BrooklynAppUnitTestSupport { + + private Location loc; + + @BeforeMethod(alwaysRun=true) + @Override + public void setUp() throws Exception { + super.setUp(); + loc = app.getManagementContext().getLocationManager().createLocation(LocationSpec.create(FixedListMachineProvisioningLocation.class) + .configure(FixedListMachineProvisioningLocation.MACHINE_SPECS, ImmutableList.<LocationSpec<? extends MachineLocation>>of( + LocationSpec.create(SshMachineLocation.class) + .configure("address", "1.2.3.4") + .configure(SshMachineLocation.SSH_TOOL_CLASS, RecordingSshTool.class.getName())))); + + RecordingSshTool.clear(); + } + + @Override + public void tearDown() throws Exception { + super.tearDown(); + RecordingSshTool.clear(); + } + + @Test + public void testAllCmds() throws Exception { + app.createAndManageChild(EntitySpec.create(VanillaSoftwareProcess.class) + .configure(VanillaSoftwareProcess.PRE_INSTALL_COMMAND, "preInstallCommand") + .configure(VanillaSoftwareProcess.INSTALL_COMMAND, "installCommand") + .configure(VanillaSoftwareProcess.POST_INSTALL_COMMAND, "postInstallCommand") + .configure(VanillaSoftwareProcess.PRE_CUSTOMIZE_COMMAND, "preCustomizeCommand") + .configure(VanillaSoftwareProcess.CUSTOMIZE_COMMAND, "customizeCommand") + .configure(VanillaSoftwareProcess.POST_CUSTOMIZE_COMMAND, "postCustomizeCommand") + .configure(VanillaSoftwareProcess.PRE_LAUNCH_COMMAND, "preLaunchCommand") + .configure(VanillaSoftwareProcess.LAUNCH_COMMAND, "launchCommand") + .configure(VanillaSoftwareProcess.POST_LAUNCH_COMMAND, "postLaunchCommand") + .configure(VanillaSoftwareProcess.CHECK_RUNNING_COMMAND, "checkRunningCommand") + .configure(VanillaSoftwareProcess.STOP_COMMAND, "stopCommand")); + app.start(ImmutableList.of(loc)); + + assertExecsContain(RecordingSshTool.getExecCmds(), ImmutableList.of( + "preInstallCommand", "installCommand", "postInstallCommand", + "preCustomizeCommand", "customizeCommand", "postCustomizeCommand", + "preLaunchCommand", "launchCommand", "postLaunchCommand", + "checkRunningCommand")); + + app.stop(); + + assertExecContains(RecordingSshTool.getLastExecCmd(), "stopCommand"); + } + + // See https://issues.apache.org/jira/browse/BROOKLYN-273 + @Test + public void testRestartCmds() throws Exception { + VanillaSoftwareProcess entity = app.createAndManageChild(EntitySpec.create(VanillaSoftwareProcess.class) + .configure(VanillaSoftwareProcess.PRE_INSTALL_COMMAND, "preInstallCommand") + .configure(VanillaSoftwareProcess.INSTALL_COMMAND, "installCommand") + .configure(VanillaSoftwareProcess.POST_INSTALL_COMMAND, "postInstallCommand") + .configure(VanillaSoftwareProcess.PRE_CUSTOMIZE_COMMAND, "customizeCommand") + .configure(VanillaSoftwareProcess.CUSTOMIZE_COMMAND, "postCustomizeCommand") + .configure(VanillaSoftwareProcess.POST_CUSTOMIZE_COMMAND, "preCustomizeCommand") + .configure(VanillaSoftwareProcess.PRE_LAUNCH_COMMAND, "preLaunchCommand") + .configure(VanillaSoftwareProcess.LAUNCH_COMMAND, "launchCommand") + .configure(VanillaSoftwareProcess.POST_LAUNCH_COMMAND, "postLaunchCommand") + .configure(VanillaSoftwareProcess.CHECK_RUNNING_COMMAND, "checkRunningCommand") + .configure(VanillaSoftwareProcess.STOP_COMMAND, "stopCommand")); + app.start(ImmutableList.of(loc)); + + // Stop the entity, and clear out all record of previous execs + Entities.invokeEffector(app, entity, VanillaSoftwareProcess.STOP, ImmutableMap.of( + VanillaSoftwareProcess.StopSoftwareParameters.STOP_MACHINE_MODE.getName(), VanillaSoftwareProcess.StopSoftwareParameters.StopMode.NEVER, + VanillaSoftwareProcess.StopSoftwareParameters.STOP_PROCESS_MODE.getName(), VanillaSoftwareProcess.StopSoftwareParameters.StopMode.ALWAYS)) + .get(); + + RecordingSshTool.clearCmdHistory(); + + // Invoke restart(), and check if all steps were executed + Entities.invokeEffector(app, entity, VanillaSoftwareProcess.RESTART, ImmutableMap.of( + VanillaSoftwareProcess.RestartSoftwareParameters.RESTART_CHILDREN.getName(), false, + VanillaSoftwareProcess.RestartSoftwareParameters.RESTART_MACHINE.getName(), VanillaSoftwareProcess.RestartSoftwareParameters.RestartMachineMode.FALSE)) + .get(); + + assertExecsContain(RecordingSshTool.getExecCmds(), ImmutableList.of( + "checkRunningCommand", "stopCommand", + "preLaunchCommand", "launchCommand", "postLaunchCommand", + "checkRunningCommand")); + } + + + @Test + public void testSkipInstallation() throws Exception { + app.createAndManageChild(EntitySpec.create(VanillaSoftwareProcess.class) + .configure(VanillaSoftwareProcess.SKIP_INSTALLATION, true) + .configure(VanillaSoftwareProcess.PRE_INSTALL_COMMAND, "preInstallCommand") + .configure(VanillaSoftwareProcess.INSTALL_COMMAND, "installCommand") + .configure(VanillaSoftwareProcess.POST_INSTALL_COMMAND, "postInstallCommand") + .configure(VanillaSoftwareProcess.PRE_CUSTOMIZE_COMMAND, "preCustomizeCommand") + .configure(VanillaSoftwareProcess.CUSTOMIZE_COMMAND, "customizeCommand") + .configure(VanillaSoftwareProcess.POST_CUSTOMIZE_COMMAND, "postCustomizeCommand") + .configure(VanillaSoftwareProcess.PRE_LAUNCH_COMMAND, "preLaunchCommand") + .configure(VanillaSoftwareProcess.LAUNCH_COMMAND, "launchCommand") + .configure(VanillaSoftwareProcess.POST_LAUNCH_COMMAND, "postLaunchCommand") + .configure(VanillaSoftwareProcess.CHECK_RUNNING_COMMAND, "checkRunningCommand") + .configure(VanillaSoftwareProcess.STOP_COMMAND, "stopCommand")); + app.start(ImmutableList.of(loc)); + + assertExecsContain(RecordingSshTool.getExecCmds(), ImmutableList.of( + "preCustomizeCommand", "customizeCommand", "postCustomizeCommand", + "preLaunchCommand", "launchCommand", "postLaunchCommand", + "checkRunningCommand")); + + assertExecsNotContains(RecordingSshTool.getExecCmds(), ImmutableList.of( + "preInstallCommand", "installCommand", "postInstallCommand")); + } + + @Test + public void testSkipEntityStartIfRunningWhenAlreadyRunning() throws Exception { + app.createAndManageChild(EntitySpec.create(VanillaSoftwareProcess.class) + .configure(VanillaSoftwareProcess.SKIP_ENTITY_START_IF_RUNNING, true) + .configure(VanillaSoftwareProcess.PRE_INSTALL_COMMAND, "preInstallCommand") + .configure(VanillaSoftwareProcess.INSTALL_COMMAND, "installCommand") + .configure(VanillaSoftwareProcess.POST_INSTALL_COMMAND, "postInstallCommand") + .configure(VanillaSoftwareProcess.PRE_CUSTOMIZE_COMMAND, "preCustomizeCommand") + .configure(VanillaSoftwareProcess.CUSTOMIZE_COMMAND, "customizeCommand") + .configure(VanillaSoftwareProcess.POST_CUSTOMIZE_COMMAND, "postCustomizeCommand") + .configure(VanillaSoftwareProcess.PRE_LAUNCH_COMMAND, "preLaunchCommand") + .configure(VanillaSoftwareProcess.LAUNCH_COMMAND, "launchCommand") + .configure(VanillaSoftwareProcess.POST_LAUNCH_COMMAND, "postLaunchCommand") + .configure(VanillaSoftwareProcess.CHECK_RUNNING_COMMAND, "checkRunningCommand") + .configure(VanillaSoftwareProcess.STOP_COMMAND, "stopCommand")); + app.start(ImmutableList.of(loc)); + + assertExecsContain(RecordingSshTool.getExecCmds(), ImmutableList.of( + "checkRunningCommand")); + + assertExecsNotContains(RecordingSshTool.getExecCmds(), ImmutableList.of( + "launchCommand")); + } + + @Test + public void testSkipEntityStartIfRunningWhenNotYetRunning() throws Exception { + // The custom-responses are so that checkRunning returns success only after launch is done + final AtomicBoolean isStarted = new AtomicBoolean(); + RecordingSshTool.setCustomResponse(".*checkRunningCommand.*", new RecordingSshTool.CustomResponseGenerator() { + @Override public CustomResponse generate(ExecParams execParams) { + int exitCode = isStarted.get() ? 0 : 1; + return new CustomResponse(exitCode, "", ""); + }}); + RecordingSshTool.setCustomResponse(".*launchCommand.*", new RecordingSshTool.CustomResponseGenerator() { + @Override public CustomResponse generate(ExecParams execParams) { + isStarted.set(true); + return new CustomResponse(0, "", ""); + }}); + RecordingSshTool.setCustomResponse(".*stopCommand.*", new RecordingSshTool.CustomResponseGenerator() { + @Override public CustomResponse generate(ExecParams execParams) { + isStarted.set(false); + return new CustomResponse(0, "", ""); + }}); + + app.createAndManageChild(EntitySpec.create(VanillaSoftwareProcess.class) + .configure(VanillaSoftwareProcess.SKIP_ENTITY_START_IF_RUNNING, true) + .configure(VanillaSoftwareProcess.PRE_INSTALL_COMMAND, "preInstallCommand") + .configure(VanillaSoftwareProcess.INSTALL_COMMAND, "installCommand") + .configure(VanillaSoftwareProcess.POST_INSTALL_COMMAND, "postInstallCommand") + .configure(VanillaSoftwareProcess.PRE_CUSTOMIZE_COMMAND, "preCustomizeCommand") + .configure(VanillaSoftwareProcess.CUSTOMIZE_COMMAND, "customizeCommand") + .configure(VanillaSoftwareProcess.POST_CUSTOMIZE_COMMAND, "postCustomizeCommand") + .configure(VanillaSoftwareProcess.PRE_LAUNCH_COMMAND, "preLaunchCommand") + .configure(VanillaSoftwareProcess.LAUNCH_COMMAND, "launchCommand") + .configure(VanillaSoftwareProcess.POST_LAUNCH_COMMAND, "postLaunchCommand") + .configure(VanillaSoftwareProcess.CHECK_RUNNING_COMMAND, "checkRunningCommand") + .configure(VanillaSoftwareProcess.STOP_COMMAND, "stopCommand")); + app.start(ImmutableList.of(loc)); + + assertExecsContain(RecordingSshTool.getExecCmds(), ImmutableList.of( + "checkRunningCommand", + "preInstallCommand", "installCommand", "postInstallCommand", + "preCustomizeCommand", "customizeCommand", "postCustomizeCommand", + "preLaunchCommand", "launchCommand", "postLaunchCommand", + "checkRunningCommand")); + } + + @Test + public void testShellEnv() throws Exception { + app.createAndManageChild(EntitySpec.create(VanillaSoftwareProcess.class) + .configure(VanillaSoftwareProcess.SHELL_ENVIRONMENT.subKey("KEY1"), "VAL1") + .configure(VanillaSoftwareProcess.PRE_INSTALL_COMMAND, "preInstallCommand") + .configure(VanillaSoftwareProcess.INSTALL_COMMAND, "installCommand") + .configure(VanillaSoftwareProcess.POST_INSTALL_COMMAND, "postInstallCommand") + .configure(VanillaSoftwareProcess.PRE_CUSTOMIZE_COMMAND, "preCustomizeCommand") + .configure(VanillaSoftwareProcess.CUSTOMIZE_COMMAND, "customizeCommand") + .configure(VanillaSoftwareProcess.POST_CUSTOMIZE_COMMAND, "postCustomizeCommand") + .configure(VanillaSoftwareProcess.PRE_LAUNCH_COMMAND, "preLaunchCommand") + .configure(VanillaSoftwareProcess.LAUNCH_COMMAND, "launchCommand") + .configure(VanillaSoftwareProcess.POST_LAUNCH_COMMAND, "postLaunchCommand") + .configure(VanillaSoftwareProcess.CHECK_RUNNING_COMMAND, "checkRunningCommand") + .configure(VanillaSoftwareProcess.STOP_COMMAND, "stopCommand")); + app.start(ImmutableList.of(loc)); + + Map<String, String> expectedEnv = ImmutableMap.of("KEY1", "VAL1"); + + assertExecsSatisfy(RecordingSshTool.getExecCmds(), ImmutableList.of( + Predicates.and(ExecCmdPredicates.containsCmd("preInstallCommand"), ExecCmdPredicates.containsEnv(expectedEnv)), + Predicates.and(ExecCmdPredicates.containsCmd("installCommand"), ExecCmdPredicates.containsEnv(expectedEnv)), + Predicates.and(ExecCmdPredicates.containsCmd("postInstallCommand"), ExecCmdPredicates.containsEnv(expectedEnv)), + Predicates.and(ExecCmdPredicates.containsCmd("preCustomizeCommand"), ExecCmdPredicates.containsEnv(expectedEnv)), + Predicates.and(ExecCmdPredicates.containsCmd("customizeCommand"), ExecCmdPredicates.containsEnv(expectedEnv)), + Predicates.and(ExecCmdPredicates.containsCmd("postCustomizeCommand"), ExecCmdPredicates.containsEnv(expectedEnv)), + Predicates.and(ExecCmdPredicates.containsCmd("preLaunchCommand"), ExecCmdPredicates.containsEnv(expectedEnv)), + Predicates.and(ExecCmdPredicates.containsCmd("launchCommand"), ExecCmdPredicates.containsEnv(expectedEnv)), + Predicates.and(ExecCmdPredicates.containsCmd("postLaunchCommand"), ExecCmdPredicates.containsEnv(expectedEnv)), + Predicates.and(ExecCmdPredicates.containsCmd("checkRunningCommand"), ExecCmdPredicates.containsEnv(expectedEnv)))); + + app.stop(); + + assertExecSatisfies( + RecordingSshTool.getLastExecCmd(), + Predicates.and(ExecCmdPredicates.containsCmd("stopCommand"), ExecCmdPredicates.containsEnv(expectedEnv))); + } + + protected void assertExecsContain(List<ExecCmd> actuals, List<String> expectedCmds) { + String errMsg = "actuals="+actuals+"; expected="+expectedCmds; + assertTrue(actuals.size() >= expectedCmds.size(), "actualSize="+actuals.size()+"; expectedSize="+expectedCmds.size()+"; "+errMsg); + for (int i = 0; i < expectedCmds.size(); i++) { + assertExecContains(actuals.get(i), expectedCmds.get(i), errMsg); + } + } + + protected void assertExecContains(ExecCmd actual, String expectedCmdRegex) { + assertExecContains(actual, expectedCmdRegex, null); + } + + protected void assertExecContains(ExecCmd actual, String expectedCmdRegex, String errMsg) { + for (String cmd : actual.commands) { + if (cmd.matches(expectedCmdRegex)) { + return; + } + } + fail(expectedCmdRegex + " not matched by any commands in " + actual+(errMsg != null ? "; "+errMsg : "")); + } + + protected void assertExecsNotContains(List<? extends ExecCmd> actuals, List<String> expectedNotCmdRegexs) { + for (ExecCmd actual : actuals) { + assertExecContains(actual, expectedNotCmdRegexs); + } + } + + protected void assertExecContains(ExecCmd actual, List<String> expectedNotCmdRegexs) { + for (String cmdRegex : expectedNotCmdRegexs) { + for (String subActual : actual.commands) { + if (subActual.matches(cmdRegex)) { + fail("Exec should not contain " + cmdRegex + ", but matched by " + actual); + } + } + } + } + + protected void assertExecsSatisfy(List<ExecCmd> actuals, List<? extends Predicate<? super ExecCmd>> expectedCmds) { + String errMsg = "actuals="+actuals+"; expected="+expectedCmds; + assertTrue(actuals.size() >= expectedCmds.size(), "actualSize="+actuals.size()+"; expectedSize="+expectedCmds.size()+"; "+errMsg); + for (int i = 0; i < expectedCmds.size(); i++) { + assertExecSatisfies(actuals.get(i), expectedCmds.get(i), errMsg); + } + } + + protected void assertExecSatisfies(ExecCmd actual, Predicate<? super ExecCmd> expected) { + assertExecSatisfies(actual, expected, null); + } + + protected void assertExecSatisfies(ExecCmd actual, Predicate<? super ExecCmd> expected, String errMsg) { + if (!expected.apply(actual)) { + fail(expected + " not matched by " + actual + (errMsg != null ? "; "+errMsg : "")); + } + } +}