You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by sv...@apache.org on 2016/09/26 06:35:46 UTC
[1/2] brooklyn-server git commit: Add TestWinrmCommand for
test-framework
Repository: brooklyn-server
Updated Branches:
refs/heads/master 6418c335f -> 8888a4823
Add TestWinrmCommand for test-framework
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/0674a5cc
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/0674a5cc
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/0674a5cc
Branch: refs/heads/master
Commit: 0674a5cc5b9abfe0202be6ec1f3a857e31428c0c
Parents: f4281af
Author: Aled Sage <al...@gmail.com>
Authored: Thu Sep 22 20:35:50 2016 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Thu Sep 22 21:04:09 2016 +0100
----------------------------------------------------------------------
.../core/internal/winrm/RecordingWinRmTool.java | 65 ++++-
test-framework/pom.xml | 7 +
.../test/framework/TestWinrmCommand.java | 84 ++++++
.../test/framework/TestWinrmCommandImpl.java | 262 +++++++++++++++++
.../test/framework/TestWinrmCommandTest.java | 285 +++++++++++++++++++
5 files changed, 699 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0674a5cc/software/winrm/src/test/java/org/apache/brooklyn/util/core/internal/winrm/RecordingWinRmTool.java
----------------------------------------------------------------------
diff --git a/software/winrm/src/test/java/org/apache/brooklyn/util/core/internal/winrm/RecordingWinRmTool.java b/software/winrm/src/test/java/org/apache/brooklyn/util/core/internal/winrm/RecordingWinRmTool.java
index 14fcd76..0795880 100644
--- a/software/winrm/src/test/java/org/apache/brooklyn/util/core/internal/winrm/RecordingWinRmTool.java
+++ b/software/winrm/src/test/java/org/apache/brooklyn/util/core/internal/winrm/RecordingWinRmTool.java
@@ -18,15 +18,19 @@
*/
package org.apache.brooklyn.util.core.internal.winrm;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import java.io.InputStream;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import org.apache.brooklyn.util.stream.Streams;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
/**
* For stubbing out the {@link WinRmTool}, so that no real winrm commands are executed.
@@ -60,13 +64,51 @@ public class RecordingWinRmTool implements WinRmTool {
}
}
+ public interface CustomResponseGenerator {
+ public CustomResponse generate(ExecParams execParams);
+ }
+
+ public static class CustomResponse {
+ public final int exitCode;
+ public final String stdout;
+ public final String stderr;
+
+ public CustomResponse(int exitCode, String stdout, String stderr) {
+ this.exitCode = exitCode;
+ this.stdout = stdout;
+ this.stderr = stderr;
+ }
+
+ @Override
+ 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 List<ExecParams> execs = Lists.newCopyOnWriteArrayList();
public static List<Map<?,?>> constructorProps = Lists.newCopyOnWriteArrayList();
+ public static Map<String, CustomResponseGenerator> customResponses = Maps.newConcurrentMap();
public static void clear() {
execs.clear();
constructorProps.clear();
+ customResponses.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<ExecParams> getExecs() {
@@ -83,14 +125,16 @@ public class RecordingWinRmTool implements WinRmTool {
@Override
public WinRmToolResponse executeCommand(List<String> commands) {
- execs.add(new ExecParams(ExecType.COMMAND, commands));
- return new WinRmToolResponse("", "", 0);
+ ExecParams execParams = new ExecParams(ExecType.COMMAND, commands);
+ execs.add(execParams);
+ return generateResponse(execParams);
}
@Override
public WinRmToolResponse executePs(List<String> commands) {
- execs.add(new ExecParams(ExecType.POWER_SHELL, commands));
- return new WinRmToolResponse("", "", 0);
+ ExecParams execParams = new ExecParams(ExecType.POWER_SHELL, commands);
+ execs.add(execParams);
+ return generateResponse(execParams);
}
@Override
@@ -104,4 +148,17 @@ public class RecordingWinRmTool implements WinRmTool {
public WinRmToolResponse executeScript(List<String> commands) {
throw new UnsupportedOperationException();
}
+
+ protected WinRmToolResponse generateResponse(ExecParams execParams) {
+ for (String cmd : execParams.commands) {
+ for (Entry<String, CustomResponseGenerator> entry : customResponses.entrySet()) {
+ if (cmd.matches(entry.getKey())) {
+ CustomResponseGenerator responseGenerator = entry.getValue();
+ CustomResponse response = responseGenerator.generate(execParams);
+ return new WinRmToolResponse(response.stdout, response.stderr, response.exitCode);
+ }
+ }
+ }
+ return new WinRmToolResponse("", "", 0);
+ }
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0674a5cc/test-framework/pom.xml
----------------------------------------------------------------------
diff --git a/test-framework/pom.xml b/test-framework/pom.xml
index 66e626a..5faf6f7 100644
--- a/test-framework/pom.xml
+++ b/test-framework/pom.xml
@@ -72,6 +72,13 @@
<classifier>tests</classifier>
</dependency>
<dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-software-winrm</artifactId>
+ <version>${brooklyn.version}</version>
+ <scope>test</scope>
+ <classifier>tests</classifier>
+ </dependency>
+ <dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj.version}</version>
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0674a5cc/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestWinrmCommand.java
----------------------------------------------------------------------
diff --git a/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestWinrmCommand.java b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestWinrmCommand.java
new file mode 100644
index 0000000..3466796
--- /dev/null
+++ b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestWinrmCommand.java
@@ -0,0 +1,84 @@
+/*
+ * 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.test.framework;
+
+import static org.apache.brooklyn.core.config.ConfigKeys.newConfigKey;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.util.core.flags.SetFromFlag;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Tests ssh command execution, against the {@link org.apache.brooklyn.location.ssh.SshMachineLocation}
+ * of the target entity.
+ */
+@ImplementedBy(TestWinrmCommandImpl.class)
+public interface TestWinrmCommand extends BaseTest {
+
+ /**
+ * Supply the PowerShell script to invoke directly.
+ */
+ ConfigKey<String> PS_SCRIPT = ConfigKeys.newConfigKey(String.class, "psScript", "PowerShell script to invoke");
+
+ /**
+ * Supply a bat command to invoke directly.
+ */
+ ConfigKey<String> COMMAND = ConfigKeys.newConfigKey(String.class, "command", "Command to invoke");
+
+ /**
+ * The working directory that the script will be run from on the target machine.
+ */
+ @SetFromFlag("runDir")
+ ConfigKey<String> RUN_DIR = newConfigKey(String.class, "run.dir", "directory where downloaded scripts should be run from");
+
+ /**
+ * If no assertions are configured in the test then the default is this assertion that exit status of the command
+ * is zero (successful).
+ */
+ Map<String, Object> DEFAULT_ASSERTION = ImmutableMap.<String,Object>of(TestFrameworkAssertions.EQUALS, 0);
+
+ /**
+ * Assertions on the exit code of the simple command.
+ *
+ * If not explicitly configured, the default assertion is a non-zero exit code.
+ */
+ @SetFromFlag("assertStatus")
+ ConfigKey<Object> ASSERT_STATUS = ConfigKeys.newConfigKey(Object.class, "assert.status", "Assertions on command exit code",
+ ImmutableList.<Map<String, Object>>of());
+
+ /**
+ * Assertions on the standard output of the command as a String.
+ */
+ @SetFromFlag("assertOut")
+ ConfigKey<Object> ASSERT_OUT = ConfigKeys.newConfigKey(Object.class, "assert.out", "Assertions on command standard output",
+ ImmutableList.<Map<String, Object>>of());
+
+ /**
+ * Assertions on the standard error of the command as a String.
+ */
+ @SetFromFlag("assertErr")
+ ConfigKey<Object> ASSERT_ERR = ConfigKeys.newConfigKey(Object.class, "assert.err", "Assertions on command standard error",
+ ImmutableList.<Map<String, Object>>of());
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0674a5cc/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestWinrmCommandImpl.java
----------------------------------------------------------------------
diff --git a/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestWinrmCommandImpl.java b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestWinrmCommandImpl.java
new file mode 100644
index 0000000..f8b9e0d
--- /dev/null
+++ b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestWinrmCommandImpl.java
@@ -0,0 +1,262 @@
+/*
+ * 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.test.framework;
+
+import static org.apache.brooklyn.core.entity.lifecycle.Lifecycle.ON_FIRE;
+import static org.apache.brooklyn.core.entity.lifecycle.Lifecycle.RUNNING;
+import static org.apache.brooklyn.core.entity.lifecycle.Lifecycle.STARTING;
+import static org.apache.brooklyn.core.entity.lifecycle.Lifecycle.STOPPED;
+import static org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.setExpectedState;
+import static org.apache.brooklyn.test.framework.TestFrameworkAssertions.checkActualAgainstAssertions;
+import static org.apache.brooklyn.test.framework.TestFrameworkAssertions.getAssertions;
+import static org.apache.brooklyn.util.text.Strings.isNonBlank;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.location.Machines;
+import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.core.internal.winrm.WinRmToolResponse;
+import org.apache.brooklyn.util.core.task.DynamicTasks;
+import org.apache.brooklyn.util.core.task.TaskBuilder;
+import org.apache.brooklyn.util.core.task.Tasks;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.exceptions.ReferenceWithError;
+import org.apache.brooklyn.util.repeat.Repeater;
+import org.apache.brooklyn.util.text.Strings;
+import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.Iterables;
+
+public class TestWinrmCommandImpl extends TargetableTestComponentImpl implements TestWinrmCommand {
+
+ // FIXME Do we want dest-path?
+ // FIXME Do I need COMPUTER_NAME in flags?
+
+ private static final Logger LOG = LoggerFactory.getLogger(TestWinrmCommandImpl.class);
+
+ private static final int A_LINE = 80;
+
+ @Override
+ public void start(Collection<? extends Location> locations) {
+ setExpectedState(this, STARTING);
+ execute();
+ }
+
+ @Override
+ public void stop() {
+ LOG.debug("{} Stopping simple command", this);
+ setUpAndRunState(false, STOPPED);
+ }
+
+ @Override
+ public void restart() {
+ LOG.debug("{} Restarting simple command", this);
+ execute();
+ }
+
+ private String shorten(String text) {
+ return Strings.maxlenWithEllipsis(text, A_LINE);
+ }
+
+ @SuppressWarnings("serial")
+ private static class MarkerException extends Exception {
+ public MarkerException(Throwable cause) {
+ super(cause);
+ }
+ }
+
+ public void execute() {
+ try {
+ checkConfig();
+ final WinRmMachineLocation machineLocation =
+ Machines.findUniqueMachineLocation(resolveTarget().getLocations(), WinRmMachineLocation.class).get();
+ final Duration timeout = getRequiredConfig(TIMEOUT);
+
+ ReferenceWithError<Boolean> result = Repeater.create("Running winrm-command tests")
+ .limitTimeTo(timeout)
+ .every(timeout.multiply(0.1))
+ .until(new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws Exception {
+ try {
+ WinRmToolResponse result = execute(machineLocation);
+ handle(result);
+ } catch (AssertionError e) {
+ // Repeater will only handle Exceptions gracefully. Other Throwables are thrown
+ // immediately, so the AssertionError thrown by handle causes early exit.
+ throw new MarkerException(e);
+ }
+ return true;
+ }
+ })
+ .runKeepingError();
+
+ if (!result.hasError()) {
+ setUpAndRunState(true, RUNNING);
+ } else {
+ setUpAndRunState(false, ON_FIRE);
+ Throwable error = result.getError();
+ if (error instanceof MarkerException) {
+ error = error.getCause();
+ }
+ throw Exceptions.propagate(error);
+ }
+
+ } catch (Throwable t) {
+ setUpAndRunState(false, ON_FIRE);
+ throw Exceptions.propagate(t);
+ }
+ }
+
+ private WinRmToolResponse execute(WinRmMachineLocation machineLocation) {
+ WinRmToolResponse result = null;
+ String psScript = getConfig(PS_SCRIPT);
+ String command = getConfig(COMMAND);
+
+ if (isNonBlank(psScript)) {
+ result = executePsScript(machineLocation, psScript);
+ } else if (isNonBlank(command)) {
+ result = executeCommand(machineLocation, command);
+ } else {
+ // should have been caught by checkConfig() earlier; maybe someone reconfigured it on-the-fly?!
+ throw illegal("Must specify exactly one of", PS_SCRIPT.getName(), "and", COMMAND.getName());
+ }
+
+ return result;
+ }
+
+ protected void checkConfig() {
+ String psScript = getConfig(PS_SCRIPT);
+ String command = getConfig(COMMAND);
+
+ if (!(isNonBlank(psScript) ^ isNonBlank(command))) {
+ String psScriptName = PS_SCRIPT.getName();
+ String commandName = COMMAND.getName();
+ throw illegal("Must specify exactly one of", psScriptName, "and", commandName);
+ }
+ }
+
+ protected void handle(WinRmToolResponse result) {
+ LOG.debug("{}, Result is {}\nwith output [\n{}\n] and error [\n{}\n]", new Object[] {
+ this, result.getStatusCode(), shorten(result.getStdOut()), shorten(result.getStdErr())
+ });
+ TestFrameworkAssertions.AssertionSupport support = new TestFrameworkAssertions.AssertionSupport();
+ for (Map<String, Object> assertion : exitCodeAssertions()) {
+ checkActualAgainstAssertions(support, assertion, "exit code", result.getStatusCode());
+ }
+ for (Map<String, Object> assertion : getAssertions(this, ASSERT_OUT)) {
+ checkActualAgainstAssertions(support, assertion, "stdout", result.getStdOut());
+ }
+ for (Map<String, Object> assertion : getAssertions(this, ASSERT_ERR)) {
+ checkActualAgainstAssertions(support, assertion, "stderr", result.getStdErr());
+ }
+ support.validate();
+ }
+
+ private WinRmToolResponse executeCommand(final WinRmMachineLocation machine, final String command) {
+ TaskBuilder<WinRmToolResponse> tb = Tasks.<WinRmToolResponse>builder().displayName("winrm-exec").body(
+ new Callable<WinRmToolResponse>() {
+ public WinRmToolResponse call() throws Exception {
+ return machine.executeCommand(command);
+ }
+ });
+ return execute(tb, command);
+ }
+
+ private WinRmToolResponse executePsScript(final WinRmMachineLocation machine, final String psScript) {
+ TaskBuilder<WinRmToolResponse> tb = Tasks.<WinRmToolResponse>builder().displayName("winrm-exec").body(
+ new Callable<WinRmToolResponse>() {
+ public WinRmToolResponse call() throws Exception {
+ // FIXME Do I need COMPUTER_NAME in flags?
+ return machine.executePsScript(psScript);
+ }
+ });
+ return execute(tb, psScript);
+ }
+
+ private WinRmToolResponse execute(TaskBuilder<WinRmToolResponse> tb, String cmdIn) {
+ try {
+ ByteArrayOutputStream stdin = new ByteArrayOutputStream();
+ if (cmdIn != null) {
+ stdin.write(cmdIn.getBytes());
+ }
+ tb.tag(BrooklynTaskTags.tagForStreamSoft(BrooklynTaskTags.STREAM_STDIN, stdin));
+ } catch (IOException e) {
+ LOG.warn("Error registering stream "+BrooklynTaskTags.STREAM_STDIN+" on "+tb+": "+e, e);
+ }
+
+ ByteArrayOutputStream stdout = new ByteArrayOutputStream();
+ tb.tag(BrooklynTaskTags.tagForStreamSoft(BrooklynTaskTags.STREAM_STDOUT, stdout));
+ ByteArrayOutputStream stderr = new ByteArrayOutputStream();
+ tb.tag(BrooklynTaskTags.tagForStreamSoft(BrooklynTaskTags.STREAM_STDERR, stderr));
+
+ Task<WinRmToolResponse> task = tb.build();
+
+ WinRmToolResponse result;
+ DynamicTasks.queueIfPossible(task).orSubmitAndBlock().getTask().blockUntilEnded();
+ try {
+ result = task.get();
+ if (result.getStdOut() != null) stdout.write(result.getStdOut().getBytes());
+ if (result.getStdErr() != null) stderr.write(result.getStdErr().getBytes());
+ } catch (InterruptedException | ExecutionException e) {
+ throw Exceptions.propagate(e);
+ } catch (IOException e) {
+ // Should not happen, as just using ByteArrayOutputStream
+ throw Exceptions.propagate(e);
+ }
+
+ return result;
+ }
+
+ private IllegalArgumentException illegal(String message, String... messages) {
+ Iterable<String> allmsgs = Iterables.concat(MutableList.of(this.toString() + ":", message), Arrays.asList(messages));
+ return new IllegalArgumentException(Joiner.on(' ').join(allmsgs));
+ }
+
+ private List<Map<String, Object>> exitCodeAssertions() {
+
+ List<Map<String, Object>> assertStatus = getAssertions(this, ASSERT_STATUS);
+ List<Map<String, Object>> assertOut = getAssertions(this, ASSERT_OUT);
+ List<Map<String, Object>> assertErr = getAssertions(this, ASSERT_ERR);
+
+ List<Map<String, Object>> result;
+ if (assertStatus.isEmpty() && assertOut.isEmpty() && assertErr.isEmpty()) {
+ Map<String, Object> shouldSucceed = DEFAULT_ASSERTION;
+ result = MutableList.of(shouldSucceed);
+ } else {
+ result = assertStatus;
+ }
+ return result;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0674a5cc/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestWinrmCommandTest.java
----------------------------------------------------------------------
diff --git a/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestWinrmCommandTest.java b/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestWinrmCommandTest.java
new file mode 100644
index 0000000..ff387e5
--- /dev/null
+++ b/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestWinrmCommandTest.java
@@ -0,0 +1,285 @@
+/*
+ * 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.test.framework;
+
+import static org.apache.brooklyn.core.entity.EntityAsserts.assertEntityFailed;
+import static org.apache.brooklyn.core.entity.EntityAsserts.assertEntityHealthy;
+import static org.apache.brooklyn.test.framework.BaseTest.TIMEOUT;
+import static org.apache.brooklyn.test.framework.TargetableTestComponent.TARGET_ENTITY;
+import static org.apache.brooklyn.test.framework.TestFrameworkAssertions.CONTAINS;
+import static org.apache.brooklyn.test.framework.TestFrameworkAssertions.EQUALS;
+import static org.apache.brooklyn.test.framework.TestWinrmCommand.ASSERT_ERR;
+import static org.apache.brooklyn.test.framework.TestWinrmCommand.ASSERT_OUT;
+import static org.apache.brooklyn.test.framework.TestWinrmCommand.ASSERT_STATUS;
+import static org.apache.brooklyn.test.framework.TestWinrmCommand.COMMAND;
+import static org.apache.brooklyn.test.framework.TestWinrmCommand.PS_SCRIPT;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.List;
+import java.util.Map;
+
+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.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.core.internal.winrm.RecordingWinRmTool;
+import org.apache.brooklyn.util.core.internal.winrm.RecordingWinRmTool.ExecType;
+import org.apache.brooklyn.util.text.Identifiers;
+import org.apache.brooklyn.util.time.Duration;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class TestWinrmCommandTest extends BrooklynAppUnitTestSupport {
+
+ private TestEntity testEntity;
+
+ @BeforeMethod(alwaysRun=true)
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ RecordingWinRmTool.clear();
+ LocationSpec<WinRmMachineLocation> machineSpec = LocationSpec.create(WinRmMachineLocation.class)
+ .configure("address", "1.2.3.4")
+ .configure(WinRmMachineLocation.WINRM_TOOL_CLASS, RecordingWinRmTool.class.getName());
+ testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class)
+ .location(machineSpec));
+ }
+
+ @AfterMethod(alwaysRun=true)
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ RecordingWinRmTool.clear();
+ }
+
+ @DataProvider(name = "insistOnJustOneOfCommandAndPsScript")
+ public Object[][] commandAndPsScriptPermutations() {
+ return new Object[][] {
+ { "pwd", "pwd", Boolean.FALSE },
+ { null, null, Boolean.FALSE },
+ { "pwd", null, Boolean.TRUE },
+ { null, "pwd", Boolean.TRUE }
+ };
+ }
+
+ @Test(dataProvider = "insistOnJustOneOfCommandAndPsScript")
+ public void shouldInsistOnJustOneOfCommandAndPsScript(String command, String psScript, boolean valid) throws Exception {
+ try {
+ app.createAndManageChild(EntitySpec.create(TestWinrmCommand.class)
+ .configure(TARGET_ENTITY, testEntity)
+ .configure(COMMAND, command)
+ .configure(PS_SCRIPT, psScript));
+
+ app.start(ImmutableList.<Location>of());
+ if (!valid) {
+ Asserts.shouldHaveFailedPreviously();
+ }
+
+ } catch (Exception e) {
+ if (valid) {
+ throw e;
+ }
+ Asserts.expectedFailureContains(e, "Must specify exactly one of psScript and command");
+ }
+ }
+
+ @Test
+ public void shouldInvokePsScript() throws Exception {
+ TestWinrmCommand test = app.createAndManageChild(EntitySpec.create(TestWinrmCommand.class)
+ .configure(TARGET_ENTITY, testEntity)
+ .configure(PS_SCRIPT, "uptime"));
+
+ app.start(ImmutableList.<Location>of());
+
+ assertEntityHealthy(test);
+ assertThat(RecordingWinRmTool.getLastExec().commands.toString()).contains("uptime");
+ assertThat(RecordingWinRmTool.getLastExec().type).isEqualTo(ExecType.POWER_SHELL);
+ }
+
+ @Test
+ public void shouldSucceedUsingSuccessfulExitAsDefaultCondition() {
+ TestWinrmCommand test = app.createAndManageChild(EntitySpec.create(TestWinrmCommand.class)
+ .configure(TARGET_ENTITY, testEntity)
+ .configure(COMMAND, "uptime"));
+
+ app.start(ImmutableList.<Location>of());
+
+ assertEntityHealthy(test);
+ assertThat(RecordingWinRmTool.getLastExec().commands).isEqualTo(ImmutableList.of("uptime"));
+ assertThat(RecordingWinRmTool.getLastExec().type).isEqualTo(ExecType.COMMAND);
+ }
+
+ @Test
+ public void shouldFailUsingSuccessfulExitAsDefaultCondition() {
+ String cmd = "commandExpectedToFail-" + Identifiers.randomLong();
+ RecordingWinRmTool.setCustomResponse(cmd, new RecordingWinRmTool.CustomResponse(1, null, null));
+
+ TestWinrmCommand test = app.createAndManageChild(EntitySpec.create(TestWinrmCommand.class)
+ .configure(TARGET_ENTITY, testEntity)
+ .configure(COMMAND, cmd));
+
+ try {
+ app.start(ImmutableList.<Location>of());
+ Asserts.shouldHaveFailedPreviously();
+ } catch (Throwable t) {
+ Asserts.expectedFailureContains(t, "exit code expected equals 0 but found 1");
+ }
+
+ assertEntityFailed(test);
+ assertThat(RecordingWinRmTool.getLastExec().commands).isEqualTo(ImmutableList.of(cmd));
+ }
+
+ @Test
+ public void shouldMatchStdoutAndStderr() {
+ String cmd = "stdoutAndStderr-" + Identifiers.randomLong();
+ RecordingWinRmTool.setCustomResponse(cmd, new RecordingWinRmTool.CustomResponse(0, "mystdout", "mystderr"));
+
+ TestWinrmCommand test = app.createAndManageChild(EntitySpec.create(TestWinrmCommand.class)
+ .configure(TARGET_ENTITY, testEntity)
+ .configure(COMMAND, cmd)
+ .configure(ASSERT_OUT, makeAssertions(ImmutableMap.of(CONTAINS, "mystdout")))
+ .configure(ASSERT_ERR, makeAssertions(ImmutableMap.of(CONTAINS, "mystderr"))));
+
+ app.start(ImmutableList.<Location>of());
+
+ assertEntityHealthy(test);
+ }
+
+ @Test
+ public void shouldFailOnUnmatchedStdout() {
+ String cmd = "stdoutAndStderr-" + Identifiers.randomLong();
+ RecordingWinRmTool.setCustomResponse(cmd, new RecordingWinRmTool.CustomResponse(0, "wrongstdout", null));
+
+ TestWinrmCommand test = app.createAndManageChild(EntitySpec.create(TestWinrmCommand.class)
+ .configure(TARGET_ENTITY, testEntity)
+ .configure(COMMAND, cmd)
+ .configure(ASSERT_OUT, makeAssertions(ImmutableMap.of(CONTAINS, "mystdout"))));
+
+ try {
+ app.start(ImmutableList.<Location>of());
+ Asserts.shouldHaveFailedPreviously();
+ } catch (Throwable t) {
+ Asserts.expectedFailureContains(t, "stdout expected contains mystdout but found wrongstdout");
+ }
+
+ assertEntityFailed(test);
+ }
+
+ @Test
+ public void shouldFailOnUnmatchedStderr() {
+ String cmd = "stdoutAndStderr-" + Identifiers.randomLong();
+ RecordingWinRmTool.setCustomResponse(cmd, new RecordingWinRmTool.CustomResponse(0, null, "wrongstderr"));
+
+ TestWinrmCommand test = app.createAndManageChild(EntitySpec.create(TestWinrmCommand.class)
+ .configure(TARGET_ENTITY, testEntity)
+ .configure(COMMAND, cmd)
+ .configure(ASSERT_ERR, makeAssertions(ImmutableMap.of(CONTAINS, "mystderr"))));
+
+ try {
+ app.start(ImmutableList.<Location>of());
+ Asserts.shouldHaveFailedPreviously();
+ } catch (Throwable t) {
+ Asserts.expectedFailureContains(t, "stderr expected contains mystderr but found wrongstderr");
+ }
+
+ assertEntityFailed(test);
+ }
+
+ @Test
+ public void shouldNotBeUpIfAssertionsFail() {
+ Map<String, ?> equalsOne = ImmutableMap.of(EQUALS, 1);
+
+ Map<String, ?> equals255 = ImmutableMap.of(EQUALS, 255);
+
+ TestWinrmCommand test = app.createAndManageChild(EntitySpec.create(TestWinrmCommand.class)
+ .configure(TARGET_ENTITY, testEntity)
+ .configure(COMMAND, "uptime")
+ .configure(ASSERT_STATUS, makeAssertions(equalsOne, equals255)));
+
+ try {
+ app.start(ImmutableList.<Location>of());
+ Asserts.shouldHaveFailedPreviously();
+ } catch (Exception e) {
+ Asserts.expectedFailureContains(e, "exit code expected equals 1 but found 0", "exit code expected equals 255 but found 0");
+ }
+
+ assertEntityFailed(test);
+ }
+
+ @Test
+ public void shouldFailIfTestEntityHasNoMachine() throws Exception {
+ TestEntity testEntityWithNoMachine = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+
+ TestWinrmCommand test = app.createAndManageChild(EntitySpec.create(TestWinrmCommand.class)
+ .configure(TARGET_ENTITY, testEntityWithNoMachine)
+ .configure(COMMAND, "mycmd"));
+
+ try {
+ app.start(ImmutableList.<Location>of());
+ Asserts.shouldHaveFailedPreviously();
+ } catch (Exception e) {
+ Asserts.expectedFailureContains(e, "No instances of class "+WinRmMachineLocation.class.getName()+" available");
+ }
+
+ assertEntityFailed(test);
+ }
+
+ @Test
+ public void shouldFailFastIfNoCommand() throws Exception {
+ Duration longTimeout = Asserts.DEFAULT_LONG_TIMEOUT;
+
+ Map<String, ?> equalsZero = ImmutableMap.of(EQUALS, 0);
+
+ TestWinrmCommand test = app.createAndManageChild(EntitySpec.create(TestWinrmCommand.class)
+ .configure(TIMEOUT, longTimeout.multiply(2))
+ .configure(TARGET_ENTITY, testEntity)
+ .configure(ASSERT_STATUS, makeAssertions(equalsZero)));
+
+ Stopwatch stopwatch = Stopwatch.createStarted();
+ try {
+ app.start(ImmutableList.<Location>of());
+ Asserts.shouldHaveFailedPreviously();
+ } catch (Exception e) {
+ // note: sleep(1000) can take a few millis less than 1000ms, according to a stopwatch.
+ Asserts.expectedFailureContains(e, "Must specify exactly one of psScript and command");
+ Duration elapsed = Duration.of(stopwatch);
+ Asserts.assertTrue(elapsed.isShorterThan(longTimeout.subtract(Duration.millis(20))), "elapsed="+elapsed);
+ }
+
+ assertEntityFailed(test);
+ }
+
+ private List<Map<String, ?>> makeAssertions(Map<String, ?> map) {
+ return ImmutableList.<Map<String, ?>>of(map);
+ }
+
+ private List<Map<String, ?>> makeAssertions(Map<String, ?> map1, Map<String, ?> map2) {
+ return ImmutableList.of(map1, map2);
+ }
+}
[2/2] brooklyn-server git commit: Closes #343
Posted by sv...@apache.org.
Closes #343
Add TestWinrmCommand for test-framework
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/8888a482
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/8888a482
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/8888a482
Branch: refs/heads/master
Commit: 8888a4823dfa938ee6ebbef8e154d61161d624ef
Parents: 6418c33 0674a5c
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Mon Sep 26 09:35:19 2016 +0300
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Mon Sep 26 09:35:19 2016 +0300
----------------------------------------------------------------------
.../core/internal/winrm/RecordingWinRmTool.java | 65 ++++-
test-framework/pom.xml | 7 +
.../test/framework/TestWinrmCommand.java | 84 ++++++
.../test/framework/TestWinrmCommandImpl.java | 262 +++++++++++++++++
.../test/framework/TestWinrmCommandTest.java | 285 +++++++++++++++++++
5 files changed, 699 insertions(+), 4 deletions(-)
----------------------------------------------------------------------