You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2015/11/23 19:29:41 UTC
[12/20] incubator-brooklyn git commit: Rename everything as
SimpleShellCommand.
Rename everything as SimpleShellCommand.
https://github.com/apache/incubator-brooklyn/pull/1030#issuecomment-157311566
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/5f98079e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/5f98079e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/5f98079e
Branch: refs/heads/master
Commit: 5f98079e62a7668aec8139fab4848b8e064824b6
Parents: f3a6395
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Tue Nov 17 14:14:57 2015 +0000
Committer: Geoff Macartney <ge...@cloudsoftcorp.com>
Committed: Tue Nov 17 14:14:57 2015 +0000
----------------------------------------------------------------------
.../brooklyn/test/framework/SimpleCommand.java | 75 ------
.../test/framework/SimpleCommandDriver.java | 70 ------
.../test/framework/SimpleCommandImpl.java | 252 -------------------
.../SimpleCommandLifecycleEffectorTasks.java | 58 -----
.../test/framework/SimpleCommandTest.java | 78 ------
.../test/framework/SimpleCommandTestImpl.java | 149 -----------
.../test/framework/SimpleShellCommand.java | 75 ++++++
.../test/framework/SimpleShellCommandImpl.java | 252 +++++++++++++++++++
...impleShellCommandLifecycleEffectorTasks.java | 57 +++++
.../test/framework/SimpleShellCommandTest.java | 78 ++++++
.../framework/SimpleShellCommandTestImpl.java | 147 +++++++++++
.../framework/SimpleCommandIntegrationTest.java | 166 ------------
.../SimpleShellCommandIntegrationTest.java | 166 ++++++++++++
13 files changed, 775 insertions(+), 848 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f98079e/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommand.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommand.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommand.java
deleted file mode 100644
index 3959b39..0000000
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommand.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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 org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.ImplementedBy;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
-import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.util.core.flags.SetFromFlag;
-
-import static org.apache.brooklyn.core.config.ConfigKeys.newConfigKey;
-
-/**
- * Entity to invoke on a node a simple command that will immediately succeed or fail.
- *
- * Invokes the command in the start operation, and declares itself RUNNING.
- */
-@ImplementedBy(SimpleCommandImpl.class)
-public interface SimpleCommand extends Entity, Startable {
-
- String TMP_DEFAULT = "/tmp";
-
- /**
- * Result of a command invocation.
- */
- interface Result {
- int getExitCode();
- String getStdout();
- String getStderr();
-
- }
-
- /**
- * Supply the command to invoke directly. Cannot be used together with {@link #DOWNLOAD_URL}.
- */
- @SetFromFlag(nullable = false)
- ConfigKey<String> COMMAND = ConfigKeys.newConfigKey(String.class, "command", "Command to invoke");
-
- /**
- * Download a script to invoke. Cannot be used together with {@link #COMMAND}.
- */
- @SetFromFlag("downloadUrl")
- AttributeSensorAndConfigKey<String, String> DOWNLOAD_URL = SoftwareProcess.DOWNLOAD_URL;
-
- /**
- * Where the script will be downloaded on the target machine.
- */
- @SetFromFlag("scriptDir")
- ConfigKey<String> SCRIPT_DIR = newConfigKey("script.dir", "directory where downloaded scripts should be put", TMP_DEFAULT);
-
- /**
- * The working directory that the script will be run from on the target machine.
- */
- @SetFromFlag("runDir")
- ConfigKey<String> RUN_DIR = newConfigKey("run.dir", "directory where downloaded scripts should be put", TMP_DEFAULT);
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f98079e/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandDriver.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandDriver.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandDriver.java
deleted file mode 100644
index d95d509..0000000
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandDriver.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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 org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.entity.drivers.EntityDriver;
-import org.apache.brooklyn.api.location.Location;
-
-import java.util.Collection;
-
-/**
- * Driver to invoke a command on a node.
- */
-public interface SimpleCommandDriver extends EntityDriver {
-
- /**
- * Result of the command invocation.
- */
- interface Result {
- int getExitCode();
- String getStdout();
- String getStderr();
- }
-
- /**
- * The entity whose components we are controlling.
- */
- EntityLocal getEntity();
-
- /**
- * Execute the simple command during the start operation.
- */
- void start();
-
- /**
- * Execute the simple command during the restart.
- */
- void restart();
-
- /**
- * Does nothing.
- */
- void stop();
-
- /**
- * Execute the given command on the supplied host.
- */
- Result execute(Collection<? extends Location> hostLocations, String command);
-
- /**
- * Download the script at the given URL to the given directory on the host and execute it.
- */
- Result executeDownloadedScript(Collection<? extends Location> hostLocations, String url, String directory);
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f98079e/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandImpl.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandImpl.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandImpl.java
deleted file mode 100644
index 7731801..0000000
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandImpl.java
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * 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 com.google.common.base.Joiner;
-import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.location.MachineLocation;
-import org.apache.brooklyn.api.mgmt.TaskFactory;
-import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
-import org.apache.brooklyn.core.entity.AbstractEntity;
-import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
-import org.apache.brooklyn.core.location.Locations;
-import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.util.collections.MutableList;
-import org.apache.brooklyn.util.core.task.DynamicTasks;
-import org.apache.brooklyn.util.core.task.ssh.SshTasks;
-import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.guava.Maybe;
-import org.apache.brooklyn.util.text.Strings;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.Random;
-
-import static org.apache.brooklyn.core.entity.lifecycle.Lifecycle.*;
-import static org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.setExpectedState;
-import static org.apache.brooklyn.util.text.Strings.isBlank;
-import static org.apache.brooklyn.util.text.Strings.isNonBlank;
-
-/**
- * Implementation for {@link SimpleCommand}.
- */
-public class SimpleCommandImpl extends AbstractEntity implements SimpleCommand {
-
- private static final Logger LOG = LoggerFactory.getLogger(SimpleCommandImpl.class);
- private static final int A_LINE = 80;
- public static final String DEFAULT_NAME = "download.sh";
- private static final String CD = "cd";
- private static final String SHELL_AND = "&&";
-
- @Override
- public void init() {
- super.init();
- getLifecycleEffectorTasks().attachLifecycleEffectors(this);
- }
-
- protected SimpleCommandLifecycleEffectorTasks getLifecycleEffectorTasks() {
- return new SimpleCommandLifecycleEffectorTasks();
- }
-
- /**
- * Gives the opportunity to sub-classes to do additional work based on the result of the command.
- */
- protected void handle(SimpleCommand.Result result) {
- LOG.debug("{}, Result is {}\nwith output [\n{}\n] and error [\n{}\n]", new Object[] {
- this, result.getExitCode(), shorten(result.getStdout()), shorten(result.getStderr())
- });
- }
-
- private String shorten(String text) {
- return Strings.maxlenWithEllipsis(text, A_LINE);
- }
-
- /**
- * Does nothing in this class but gives sub-classes the opportunity to filter locations according to some criterion.
- */
- public Collection<? extends Location> filterLocations(Collection<? extends Location> locations) {
- return locations;
- }
-
-
- @Override
- public void start(Collection<? extends Location> locations) {
- addLocations(locations);
- setExpectedState(this, STARTING);
- }
-
- @Override
- public void stop() {
- LOG.debug("{} Stopping simple command", this);
- setUpAndRunState(false, STOPPED);
- }
-
- @Override
- public void restart() {
- LOG.debug("{} Restarting simple command", this);
- setUpAndRunState(true, RUNNING);
- }
-
- private void setUpAndRunState(boolean up, Lifecycle status) {
- sensors().set(SERVICE_UP, up);
- setExpectedState(this, status);
- }
-
- public void execute(MachineLocation machineLocation) {
- try {
- executeCommand(machineLocation);
- setUpAndRunState(true, RUNNING);
- } catch (Exception e) {
- setUpAndRunState(false, ON_FIRE);
- throw Exceptions.propagate(e);
- }
- }
-
- private void executeCommand(MachineLocation machineLocation) {
-
- SimpleCommand.Result result = null;
- String downloadUrl = getConfig(DOWNLOAD_URL);
- String command = getConfig(COMMAND);
-
- String downloadName = DOWNLOAD_URL.getName();
- String commandName = COMMAND.getName();
-
- if (isNonBlank(downloadUrl) && isNonBlank(command)) {
- throw illegal("Cannot specify both", downloadName, "and", commandName);
- }
-
- if (isBlank(downloadUrl) && isBlank(commandName)) {
- throw illegal("No", downloadName, "and no", commandName, "provided");
- }
-
- if (Strings.isNonBlank(downloadUrl)) {
- String scriptDir = getConfig(SCRIPT_DIR);
- String scriptPath = calculateDestPath(downloadUrl, scriptDir);
- result = executeDownloadedScript(machineLocation, downloadUrl, scriptPath);
- }
-
- if (Strings.isNonBlank(command)) {
- result = executeShellCommand(machineLocation, command);
- }
-
- handle(result);
- }
-
- private IllegalArgumentException illegal(String ...messages) {
- return new IllegalArgumentException(Joiner.on(' ').join(this.toString() + ":", messages));
- }
-
- private SimpleCommand.Result executeDownloadedScript(MachineLocation machineLocation, String url, String scriptPath) {
-
- SshMachineLocation machine = getSshMachine(ImmutableList.<Location>of(machineLocation));
-
- TaskFactory<?> install = SshTasks.installFromUrl(ImmutableMap.<String, Object>of(), machine, url, scriptPath);
- DynamicTasks.queue(install);
- DynamicTasks.waitForLast();
-
- machine.execCommands("make the script executable", ImmutableList.<String>of("chmod u+x " + scriptPath));
-
- String runDir = getConfig(RUN_DIR);
- String cdAndRun = Joiner.on(' ').join(CD, runDir, SHELL_AND, scriptPath);
-
- return executeShellCommand(machineLocation, cdAndRun);
- }
-
-
- private SimpleCommand.Result executeShellCommand(MachineLocation machineLocation, String command) {
-
- SshMachineLocation machine = getSshMachine(ImmutableList.of(machineLocation));
- SshEffectorTasks.SshEffectorTaskFactory<Integer> etf = SshEffectorTasks.ssh(machine, command);
-
- LOG.debug("{} Creating task to execute '{}' on location {}", new Object[] {this, command, machine});
- ProcessTaskWrapper<Integer> job = DynamicTasks.queue(etf);
- DynamicTasks.waitForLast();
- return buildResult(job);
- }
-
-
- private <T> SimpleCommand.Result buildResult(final ProcessTaskWrapper<Integer> job) {
- return new SimpleCommand.Result() {
-
- @Override
- public int getExitCode() {
- return job.get();
- }
-
- @Override
- public String getStdout() {
- return job.getStdout().trim();
- }
-
- @Override
- public String getStderr() {
- return job.getStderr().trim();
- }
- };
- }
-
- private SshMachineLocation getSshMachine(Collection<? extends Location> hostLocations) {
- Maybe<SshMachineLocation> host = Locations.findUniqueSshMachineLocation(hostLocations);
- if (host.isAbsent()) {
- throw new IllegalArgumentException("No SSH machine found to run command");
- }
- return host.get();
- }
-
- private String calculateDestPath(String url, String directory) {
- try {
- URL asUrl = new URL(url);
- Iterable<String> path = Splitter.on("/").split(asUrl.getPath());
- String scriptName = getLastPartOfPath(path, DEFAULT_NAME);
- return Joiner.on("/").join(directory, "test-" + randomDir(), scriptName);
- } catch (MalformedURLException e) {
- throw illegal("Malformed URL:", url);
- }
- }
-
- private String randomDir() {
- return Integer.valueOf(new Random(System.currentTimeMillis()).nextInt(100000)).toString();
- }
-
- private static String getLastPartOfPath(Iterable<String> path, String defaultName) {
- MutableList<String> parts = MutableList.copyOf(path);
- Collections.reverse(parts);
- Iterator<String> it = parts.iterator();
- String scriptName = null;
-
- // strip any trailing "/" parts of URL
- while (isBlank(scriptName) && it.hasNext()) {
- scriptName = it.next();
- }
- if (isBlank(scriptName)) {
- scriptName = defaultName;
- }
- return scriptName;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f98079e/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandLifecycleEffectorTasks.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandLifecycleEffectorTasks.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandLifecycleEffectorTasks.java
deleted file mode 100644
index ae318ed..0000000
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandLifecycleEffectorTasks.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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 com.google.common.base.Supplier;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.location.MachineLocation;
-import org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks;
-import org.apache.http.util.Asserts;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.annotation.Nullable;
-import java.util.Collection;
-
-public class SimpleCommandLifecycleEffectorTasks extends MachineLifecycleEffectorTasks {
-
- private static final Logger LOG = LoggerFactory.getLogger(SimpleCommandLifecycleEffectorTasks.class);
-
- protected Location getLocation(@Nullable Collection<? extends Location> locations) {
- return super.getLocation(entity().filterLocations(locations));
- }
-
-
- @Override
- protected String startProcessesAtMachine(Supplier<MachineLocation> machineS) {
- LOG.debug("Performing lifecycle startProcessesAtMachine on simple command");
- MachineLocation machineLocation = machineS.get();
- entity().execute(machineLocation);
- return "Started simple command on " + machineLocation;
- }
-
- @Override
- protected String stopProcessesAtMachine() {
- LOG.debug("No action needed on simple command stopped");
- return "Stopped";
- }
-
- protected SimpleCommandImpl entity() {
- return (SimpleCommandImpl) super.entity();
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f98079e/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandTest.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandTest.java
deleted file mode 100644
index c962403..0000000
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandTest.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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 com.google.common.collect.Maps;
-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 java.util.Map;
-
-/**
- * Tests using a simple command execution.
- */
-@ImplementedBy(SimpleCommandTestImpl.class)
-public interface SimpleCommandTest extends SimpleCommand, BaseTest {
-
- /**
- * Equals assertion on command result.
- */
- String EQUALS = "equals";
-
- /**
- * String contains assertion on command result.
- */
- String CONTAINS = "contains";
-
- /**
- * Regex match assertion on command result.
- */
- String MATCHES = "matches";
-
- /**
- * Is-empty match assertion on command result.
- */
- String IS_EMPTY = "isEmpty";
-
- /**
- * 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<Map> ASSERT_STATUS = ConfigKeys.newConfigKey(Map.class, "assert.status",
- "Assertions on command exit code", Maps.newLinkedHashMap());
-
- /**
- * Assertions on the standard output of the command as a String.
- */
- @SetFromFlag("assertOut")
- ConfigKey<Map> ASSERT_OUT = ConfigKeys.newConfigKey(Map.class, "assert.out",
- "Assertions on command standard output", Maps.newLinkedHashMap());
-
- /**
- * Assertions on the standard error of the command as a String.
- */
- @SetFromFlag("assertErr")
- ConfigKey<Map> ASSERT_ERR = ConfigKeys.newConfigKey(Map.class, "assert.err",
- "Assertions on command standard error", Maps.newLinkedHashMap());
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f98079e/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandTestImpl.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandTestImpl.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandTestImpl.java
deleted file mode 100644
index cf85b37..0000000
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandTestImpl.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * 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 com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableMap;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.core.location.Locations;
-import org.apache.brooklyn.test.Asserts;
-import org.apache.brooklyn.util.groovy.GroovyJavaMethods;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import static org.apache.brooklyn.util.groovy.GroovyJavaMethods.truth;
-import static org.apache.commons.collections.MapUtils.isEmpty;
-
-public class SimpleCommandTestImpl extends SimpleCommandImpl implements SimpleCommandTest {
-
- public static final int SUCCESS = 0;
-
- @Override
- public Entity resolveTarget() {
- return AbstractTest.resolveTarget(getExecutionContext(), this);
- }
-
- /**
- * The test will choose the location of its target entity.
- */
- public Collection<? extends Location> filterLocations(Collection<? extends Location> locations) {
- Entity target = resolveTarget();
- return target.getLocations();
- }
-
- @Override
- protected void handle(SimpleCommand.Result result) {
- AssertionSupport support = new AssertionSupport();
- checkAssertions(support, exitCodeAssertions(), "exit code", result.getExitCode());
- checkAssertions(support, getConfig(ASSERT_OUT), "stdout", result.getStdout());
- checkAssertions(support, getConfig(ASSERT_ERR), "stderr", result.getStderr());
- support.validate();
- }
-
- private <T> void checkAssertions(AssertionSupport support, Map<?, ?> assertions, String target, T actual) {
- if (null == assertions) {
- return;
- }
- if (null == actual) {
- support.fail(target, "no actual value", "");
- return;
- }
- for (Map.Entry<?, ?> assertion : assertions.entrySet()) {
- String condition = assertion.getKey().toString();
- Object expected = assertion.getValue();
- switch (condition) {
- case EQUALS :
- if (!actual.equals(expected)) {
- support.fail(target, EQUALS, expected);
- }
- break;
- case CONTAINS :
- if (!actual.toString().contains(expected.toString())) {
- support.fail(target, CONTAINS, expected);
- }
- break;
- case IS_EMPTY:
- if (!actual.toString().isEmpty() && truth(expected)) {
- support.fail(target, IS_EMPTY, expected);
- }
- break;
- case MATCHES :
- if (!actual.toString().matches(expected.toString())) {
- support.fail(target, MATCHES, expected);
- }
- break;
- default:
- support.fail(target, "unknown condition", condition);
- }
- }
- }
-
- private Map<?, ?> exitCodeAssertions() {
- Map<?, ?> assertStatus = getConfig(ASSERT_STATUS);
- if (isEmpty(assertStatus)) {
- assertStatus = ImmutableMap.of(EQUALS, SUCCESS);
- }
- return assertStatus;
- }
-
- public static class FailedAssertion {
- String target;
- String assertion;
- String expected;
-
- public FailedAssertion(String target, String assertion, String expected) {
- this.target = target;
- this.assertion = assertion;
- this.expected = expected;
- }
- public String description() {
- return Joiner.on(' ').join(target, assertion, expected);
- }
- }
-
- /**
- * A convenience to collect and validate any assertion failures.
- */
- public static class AssertionSupport {
- private List<FailedAssertion> failures = new ArrayList<>();
-
- public void fail(String target, String assertion, Object expected) {
- failures.add(new FailedAssertion(target, assertion, expected.toString()));
- }
-
- /**
- * @throws AssertionError if any failures were collected.
- */
- public void validate() {
- if (0 < failures.size()) {
- StringBuilder summary = new StringBuilder();
- summary.append("Assertion Failures: \n");
- for (FailedAssertion fail : failures) {
- summary.append(fail.description()).append("\n");
- }
- Asserts.fail(summary.toString());
- }
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f98079e/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommand.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommand.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommand.java
new file mode 100644
index 0000000..1f430a7
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommand.java
@@ -0,0 +1,75 @@
+/*
+ * 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 org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+import org.apache.brooklyn.entity.software.base.SoftwareProcess;
+import org.apache.brooklyn.util.core.flags.SetFromFlag;
+
+import static org.apache.brooklyn.core.config.ConfigKeys.newConfigKey;
+
+/**
+ * Entity to invoke on a node a simple command that will immediately succeed or fail.
+ *
+ * Invokes the command in the start operation, and declares itself RUNNING.
+ */
+@ImplementedBy(SimpleShellCommandImpl.class)
+public interface SimpleShellCommand extends Entity, Startable {
+
+ String TMP_DEFAULT = "/tmp";
+
+ /**
+ * Result of a command invocation.
+ */
+ interface Result {
+ int getExitCode();
+ String getStdout();
+ String getStderr();
+
+ }
+
+ /**
+ * Supply the command to invoke directly. Cannot be used together with {@link #DOWNLOAD_URL}.
+ */
+ @SetFromFlag(nullable = false)
+ ConfigKey<String> COMMAND = ConfigKeys.newConfigKey(String.class, "command", "Command to invoke");
+
+ /**
+ * Download a script to invoke. Cannot be used together with {@link #COMMAND}.
+ */
+ @SetFromFlag("downloadUrl")
+ AttributeSensorAndConfigKey<String, String> DOWNLOAD_URL = SoftwareProcess.DOWNLOAD_URL;
+
+ /**
+ * Where the script will be downloaded on the target machine.
+ */
+ @SetFromFlag("scriptDir")
+ ConfigKey<String> SCRIPT_DIR = newConfigKey("script.dir", "directory where downloaded scripts should be put", TMP_DEFAULT);
+
+ /**
+ * The working directory that the script will be run from on the target machine.
+ */
+ @SetFromFlag("runDir")
+ ConfigKey<String> RUN_DIR = newConfigKey("run.dir", "directory where downloaded scripts should be put", TMP_DEFAULT);
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f98079e/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandImpl.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandImpl.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandImpl.java
new file mode 100644
index 0000000..1ccce5e
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandImpl.java
@@ -0,0 +1,252 @@
+/*
+ * 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 com.google.common.base.Joiner;
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.location.MachineLocation;
+import org.apache.brooklyn.api.mgmt.TaskFactory;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
+import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.core.location.Locations;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.core.task.DynamicTasks;
+import org.apache.brooklyn.util.core.task.ssh.SshTasks;
+import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Random;
+
+import static org.apache.brooklyn.core.entity.lifecycle.Lifecycle.*;
+import static org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.setExpectedState;
+import static org.apache.brooklyn.util.text.Strings.isBlank;
+import static org.apache.brooklyn.util.text.Strings.isNonBlank;
+
+/**
+ * Implementation for {@link SimpleShellCommand}.
+ */
+public class SimpleShellCommandImpl extends AbstractEntity implements SimpleShellCommand {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SimpleShellCommandImpl.class);
+ private static final int A_LINE = 80;
+ public static final String DEFAULT_NAME = "download.sh";
+ private static final String CD = "cd";
+ private static final String SHELL_AND = "&&";
+
+ @Override
+ public void init() {
+ super.init();
+ getLifecycleEffectorTasks().attachLifecycleEffectors(this);
+ }
+
+ protected SimpleShellCommandLifecycleEffectorTasks getLifecycleEffectorTasks() {
+ return new SimpleShellCommandLifecycleEffectorTasks();
+ }
+
+ /**
+ * Gives the opportunity to sub-classes to do additional work based on the result of the command.
+ */
+ protected void handle(SimpleShellCommand.Result result) {
+ LOG.debug("{}, Result is {}\nwith output [\n{}\n] and error [\n{}\n]", new Object[] {
+ this, result.getExitCode(), shorten(result.getStdout()), shorten(result.getStderr())
+ });
+ }
+
+ private String shorten(String text) {
+ return Strings.maxlenWithEllipsis(text, A_LINE);
+ }
+
+ /**
+ * Does nothing in this class but gives sub-classes the opportunity to filter locations according to some criterion.
+ */
+ public Collection<? extends Location> filterLocations(Collection<? extends Location> locations) {
+ return locations;
+ }
+
+
+ @Override
+ public void start(Collection<? extends Location> locations) {
+ addLocations(locations);
+ setExpectedState(this, STARTING);
+ }
+
+ @Override
+ public void stop() {
+ LOG.debug("{} Stopping simple command", this);
+ setUpAndRunState(false, STOPPED);
+ }
+
+ @Override
+ public void restart() {
+ LOG.debug("{} Restarting simple command", this);
+ setUpAndRunState(true, RUNNING);
+ }
+
+ private void setUpAndRunState(boolean up, Lifecycle status) {
+ sensors().set(SERVICE_UP, up);
+ setExpectedState(this, status);
+ }
+
+ public void execute(MachineLocation machineLocation) {
+ try {
+ executeCommand(machineLocation);
+ setUpAndRunState(true, RUNNING);
+ } catch (Exception e) {
+ setUpAndRunState(false, ON_FIRE);
+ throw Exceptions.propagate(e);
+ }
+ }
+
+ private void executeCommand(MachineLocation machineLocation) {
+
+ SimpleShellCommand.Result result = null;
+ String downloadUrl = getConfig(DOWNLOAD_URL);
+ String command = getConfig(COMMAND);
+
+ String downloadName = DOWNLOAD_URL.getName();
+ String commandName = COMMAND.getName();
+
+ if (isNonBlank(downloadUrl) && isNonBlank(command)) {
+ throw illegal("Cannot specify both", downloadName, "and", commandName);
+ }
+
+ if (isBlank(downloadUrl) && isBlank(commandName)) {
+ throw illegal("No", downloadName, "and no", commandName, "provided");
+ }
+
+ if (Strings.isNonBlank(downloadUrl)) {
+ String scriptDir = getConfig(SCRIPT_DIR);
+ String scriptPath = calculateDestPath(downloadUrl, scriptDir);
+ result = executeDownloadedScript(machineLocation, downloadUrl, scriptPath);
+ }
+
+ if (Strings.isNonBlank(command)) {
+ result = executeShellCommand(machineLocation, command);
+ }
+
+ handle(result);
+ }
+
+ private IllegalArgumentException illegal(String ...messages) {
+ return new IllegalArgumentException(Joiner.on(' ').join(this.toString() + ":", messages));
+ }
+
+ private SimpleShellCommand.Result executeDownloadedScript(MachineLocation machineLocation, String url, String scriptPath) {
+
+ SshMachineLocation machine = getSshMachine(ImmutableList.<Location>of(machineLocation));
+
+ TaskFactory<?> install = SshTasks.installFromUrl(ImmutableMap.<String, Object>of(), machine, url, scriptPath);
+ DynamicTasks.queue(install);
+ DynamicTasks.waitForLast();
+
+ machine.execCommands("make the script executable", ImmutableList.<String>of("chmod u+x " + scriptPath));
+
+ String runDir = getConfig(RUN_DIR);
+ String cdAndRun = Joiner.on(' ').join(CD, runDir, SHELL_AND, scriptPath);
+
+ return executeShellCommand(machineLocation, cdAndRun);
+ }
+
+
+ private SimpleShellCommand.Result executeShellCommand(MachineLocation machineLocation, String command) {
+
+ SshMachineLocation machine = getSshMachine(ImmutableList.of(machineLocation));
+ SshEffectorTasks.SshEffectorTaskFactory<Integer> etf = SshEffectorTasks.ssh(machine, command);
+
+ LOG.debug("{} Creating task to execute '{}' on location {}", new Object[] {this, command, machine});
+ ProcessTaskWrapper<Integer> job = DynamicTasks.queue(etf);
+ DynamicTasks.waitForLast();
+ return buildResult(job);
+ }
+
+
+ private <T> SimpleShellCommand.Result buildResult(final ProcessTaskWrapper<Integer> job) {
+ return new SimpleShellCommand.Result() {
+
+ @Override
+ public int getExitCode() {
+ return job.get();
+ }
+
+ @Override
+ public String getStdout() {
+ return job.getStdout().trim();
+ }
+
+ @Override
+ public String getStderr() {
+ return job.getStderr().trim();
+ }
+ };
+ }
+
+ private SshMachineLocation getSshMachine(Collection<? extends Location> hostLocations) {
+ Maybe<SshMachineLocation> host = Locations.findUniqueSshMachineLocation(hostLocations);
+ if (host.isAbsent()) {
+ throw new IllegalArgumentException("No SSH machine found to run command");
+ }
+ return host.get();
+ }
+
+ private String calculateDestPath(String url, String directory) {
+ try {
+ URL asUrl = new URL(url);
+ Iterable<String> path = Splitter.on("/").split(asUrl.getPath());
+ String scriptName = getLastPartOfPath(path, DEFAULT_NAME);
+ return Joiner.on("/").join(directory, "test-" + randomDir(), scriptName);
+ } catch (MalformedURLException e) {
+ throw illegal("Malformed URL:", url);
+ }
+ }
+
+ private String randomDir() {
+ return Integer.valueOf(new Random(System.currentTimeMillis()).nextInt(100000)).toString();
+ }
+
+ private static String getLastPartOfPath(Iterable<String> path, String defaultName) {
+ MutableList<String> parts = MutableList.copyOf(path);
+ Collections.reverse(parts);
+ Iterator<String> it = parts.iterator();
+ String scriptName = null;
+
+ // strip any trailing "/" parts of URL
+ while (isBlank(scriptName) && it.hasNext()) {
+ scriptName = it.next();
+ }
+ if (isBlank(scriptName)) {
+ scriptName = defaultName;
+ }
+ return scriptName;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f98079e/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandLifecycleEffectorTasks.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandLifecycleEffectorTasks.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandLifecycleEffectorTasks.java
new file mode 100644
index 0000000..fdccd99
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandLifecycleEffectorTasks.java
@@ -0,0 +1,57 @@
+/*
+ * 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 com.google.common.base.Supplier;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.location.MachineLocation;
+import org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nullable;
+import java.util.Collection;
+
+public class SimpleShellCommandLifecycleEffectorTasks extends MachineLifecycleEffectorTasks {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SimpleShellCommandLifecycleEffectorTasks.class);
+
+ protected Location getLocation(@Nullable Collection<? extends Location> locations) {
+ return super.getLocation(entity().filterLocations(locations));
+ }
+
+
+ @Override
+ protected String startProcessesAtMachine(Supplier<MachineLocation> machineS) {
+ LOG.debug("Performing lifecycle startProcessesAtMachine on simple command");
+ MachineLocation machineLocation = machineS.get();
+ entity().execute(machineLocation);
+ return "Started simple command on " + machineLocation;
+ }
+
+ @Override
+ protected String stopProcessesAtMachine() {
+ LOG.debug("No action needed on simple command stopped");
+ return "Stopped";
+ }
+
+ protected SimpleShellCommandImpl entity() {
+ return (SimpleShellCommandImpl) super.entity();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f98079e/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandTest.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandTest.java
new file mode 100644
index 0000000..17621d9
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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 com.google.common.collect.Maps;
+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 java.util.Map;
+
+/**
+ * Tests using a simple command execution.
+ */
+@ImplementedBy(SimpleShellCommandTestImpl.class)
+public interface SimpleShellCommandTest extends SimpleShellCommand, BaseTest {
+
+ /**
+ * Equals assertion on command result.
+ */
+ String EQUALS = "equals";
+
+ /**
+ * String contains assertion on command result.
+ */
+ String CONTAINS = "contains";
+
+ /**
+ * Regex match assertion on command result.
+ */
+ String MATCHES = "matches";
+
+ /**
+ * Is-empty match assertion on command result.
+ */
+ String IS_EMPTY = "isEmpty";
+
+ /**
+ * 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<Map> ASSERT_STATUS = ConfigKeys.newConfigKey(Map.class, "assert.status",
+ "Assertions on command exit code", Maps.newLinkedHashMap());
+
+ /**
+ * Assertions on the standard output of the command as a String.
+ */
+ @SetFromFlag("assertOut")
+ ConfigKey<Map> ASSERT_OUT = ConfigKeys.newConfigKey(Map.class, "assert.out",
+ "Assertions on command standard output", Maps.newLinkedHashMap());
+
+ /**
+ * Assertions on the standard error of the command as a String.
+ */
+ @SetFromFlag("assertErr")
+ ConfigKey<Map> ASSERT_ERR = ConfigKeys.newConfigKey(Map.class, "assert.err",
+ "Assertions on command standard error", Maps.newLinkedHashMap());
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f98079e/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandTestImpl.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandTestImpl.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandTestImpl.java
new file mode 100644
index 0000000..9c9a15a
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandTestImpl.java
@@ -0,0 +1,147 @@
+/*
+ * 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 com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableMap;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.test.Asserts;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.brooklyn.util.groovy.GroovyJavaMethods.truth;
+import static org.apache.commons.collections.MapUtils.isEmpty;
+
+public class SimpleShellCommandTestImpl extends SimpleShellCommandImpl implements SimpleShellCommandTest {
+
+ public static final int SUCCESS = 0;
+
+ @Override
+ public Entity resolveTarget() {
+ return AbstractTest.resolveTarget(getExecutionContext(), this);
+ }
+
+ /**
+ * The test will choose the location of its target entity.
+ */
+ public Collection<? extends Location> filterLocations(Collection<? extends Location> locations) {
+ Entity target = resolveTarget();
+ return target.getLocations();
+ }
+
+ @Override
+ protected void handle(SimpleShellCommand.Result result) {
+ AssertionSupport support = new AssertionSupport();
+ checkAssertions(support, exitCodeAssertions(), "exit code", result.getExitCode());
+ checkAssertions(support, getConfig(ASSERT_OUT), "stdout", result.getStdout());
+ checkAssertions(support, getConfig(ASSERT_ERR), "stderr", result.getStderr());
+ support.validate();
+ }
+
+ private <T> void checkAssertions(AssertionSupport support, Map<?, ?> assertions, String target, T actual) {
+ if (null == assertions) {
+ return;
+ }
+ if (null == actual) {
+ support.fail(target, "no actual value", "");
+ return;
+ }
+ for (Map.Entry<?, ?> assertion : assertions.entrySet()) {
+ String condition = assertion.getKey().toString();
+ Object expected = assertion.getValue();
+ switch (condition) {
+ case EQUALS :
+ if (!actual.equals(expected)) {
+ support.fail(target, EQUALS, expected);
+ }
+ break;
+ case CONTAINS :
+ if (!actual.toString().contains(expected.toString())) {
+ support.fail(target, CONTAINS, expected);
+ }
+ break;
+ case IS_EMPTY:
+ if (!actual.toString().isEmpty() && truth(expected)) {
+ support.fail(target, IS_EMPTY, expected);
+ }
+ break;
+ case MATCHES :
+ if (!actual.toString().matches(expected.toString())) {
+ support.fail(target, MATCHES, expected);
+ }
+ break;
+ default:
+ support.fail(target, "unknown condition", condition);
+ }
+ }
+ }
+
+ private Map<?, ?> exitCodeAssertions() {
+ Map<?, ?> assertStatus = getConfig(ASSERT_STATUS);
+ if (isEmpty(assertStatus)) {
+ assertStatus = ImmutableMap.of(EQUALS, SUCCESS);
+ }
+ return assertStatus;
+ }
+
+ public static class FailedAssertion {
+ String target;
+ String assertion;
+ String expected;
+
+ public FailedAssertion(String target, String assertion, String expected) {
+ this.target = target;
+ this.assertion = assertion;
+ this.expected = expected;
+ }
+ public String description() {
+ return Joiner.on(' ').join(target, assertion, expected);
+ }
+ }
+
+ /**
+ * A convenience to collect and validate any assertion failures.
+ */
+ public static class AssertionSupport {
+ private List<FailedAssertion> failures = new ArrayList<>();
+
+ public void fail(String target, String assertion, Object expected) {
+ failures.add(new FailedAssertion(target, assertion, expected.toString()));
+ }
+
+ /**
+ * @throws AssertionError if any failures were collected.
+ */
+ public void validate() {
+ if (0 < failures.size()) {
+ StringBuilder summary = new StringBuilder();
+ summary.append("Assertion Failures: \n");
+ for (FailedAssertion fail : failures) {
+ summary.append(fail.description()).append("\n");
+ }
+ Asserts.fail(summary.toString());
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f98079e/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandIntegrationTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandIntegrationTest.java b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandIntegrationTest.java
deleted file mode 100644
index 0b7b121..0000000
--- a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandIntegrationTest.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * 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 com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.location.LocationSpec;
-import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
-import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
-import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.Test;
-
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Random;
-import java.util.UUID;
-
-import static org.apache.brooklyn.test.framework.BaseTest.TARGET_ENTITY;
-import static org.apache.brooklyn.test.framework.SimpleCommand.COMMAND;
-import static org.apache.brooklyn.test.framework.SimpleCommandTest.*;
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class SimpleCommandIntegrationTest extends BrooklynAppUnitTestSupport {
- private static final Logger LOG = LoggerFactory.getLogger(SimpleCommandIntegrationTest.class);
-
- private static final String UP = "up";
- private LocalhostMachineProvisioningLocation localhost;
- private String testId;
-
-
- protected void setUpApp() {
- super.setUpApp();
- testId = UUID.randomUUID().toString();
-
- localhost = app.getManagementContext().getLocationManager()
- .createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class)
- .configure("name", testId));
- }
-
- @Test(groups = "Integration")
- public void shouldInvokeCommand() {
- TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-
- SimpleCommandTest uptime = app.createAndManageChild(EntitySpec.create(SimpleCommandTest.class)
- .configure(TARGET_ENTITY, testEntity)
- .configure(COMMAND, "uptime")
- .configure(ASSERT_STATUS, ImmutableMap.of(EQUALS, 0))
- .configure(ASSERT_OUT, ImmutableMap.of(CONTAINS, UP)));
-
- app.start(ImmutableList.of(localhost));
-
- assertThat(uptime.sensors().get(SERVICE_UP)).isTrue()
- .withFailMessage("Service should be up");
- assertThat(ServiceStateLogic.getExpectedState(uptime)).isEqualTo(Lifecycle.RUNNING)
- .withFailMessage("Service should be marked running");
-
- }
-
- @Test(groups = "Integration")
- public void shouldNotBeUpIfAssertionFails() {
- TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-
- SimpleCommandTest uptime = app.createAndManageChild(EntitySpec.create(SimpleCommandTest.class)
- .configure(TARGET_ENTITY, testEntity)
- .configure(COMMAND, "uptime")
- .configure(ASSERT_STATUS, ImmutableMap.of(EQUALS, 1)));
-
- try {
- app.start(ImmutableList.of(localhost));
- } catch (Exception e) {
- assertThat(e.getCause().getMessage().contains("exit code equals 1"));
- }
-
- assertThat(ServiceStateLogic.getExpectedState(uptime)).isEqualTo(Lifecycle.ON_FIRE)
- .withFailMessage("Service should be marked on fire");
-
- }
-
- @Test(groups = "Integration")
- public void shouldInvokeScript() {
- TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-
- String text = "hello world";
- String testUrl = createTempScript("script.sh", "echo " + text);
-
- SimpleCommandTest uptime = app.createAndManageChild(EntitySpec.create(SimpleCommandTest.class)
- .configure(TARGET_ENTITY, testEntity)
- .configure(DOWNLOAD_URL, testUrl)
- .configure(ASSERT_STATUS, ImmutableMap.of(EQUALS, 0))
- .configure(ASSERT_OUT, ImmutableMap.of(CONTAINS, text)));
-
- app.start(ImmutableList.of(localhost));
-
- assertThat(uptime.sensors().get(SERVICE_UP)).isTrue()
- .withFailMessage("Service should be up");
- assertThat(ServiceStateLogic.getExpectedState(uptime)).isEqualTo(Lifecycle.RUNNING)
- .withFailMessage("Service should be marked running");
- }
-
- @Test
- public void shouldExecuteInTheRightPlace() throws Exception {
- TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-
- String remoteTmp = randomName();
- SimpleCommandTest uptime = app.createAndManageChild(EntitySpec.create(SimpleCommandTest.class)
- .configure(TARGET_ENTITY, testEntity)
- .configure(COMMAND, "mkdir " + remoteTmp)
- .configure(ASSERT_STATUS, ImmutableMap.of(EQUALS, 0)));
-
- String pwdUrl = createTempScript("pwd.sh", "pwd");
-
- SimpleCommandTest pwd = app.createAndManageChild(EntitySpec.create(SimpleCommandTest.class)
- .configure(TARGET_ENTITY, testEntity)
- .configure(DOWNLOAD_URL, pwdUrl)
- .configure(RUN_DIR, remoteTmp)
- .configure(ASSERT_STATUS, ImmutableMap.of(EQUALS, 0))
- .configure(ASSERT_OUT, ImmutableMap.of(CONTAINS, remoteTmp)));
-
- app.start(ImmutableList.of(localhost));
-
- assertThat(uptime.sensors().get(SERVICE_UP)).isTrue()
- .withFailMessage("Service should be up");
- assertThat(ServiceStateLogic.getExpectedState(uptime)).isEqualTo(Lifecycle.RUNNING)
- .withFailMessage("Service should be marked running");
- }
-
- private String createTempScript(String filename, String contents) {
- try {
- Path tempDirectory = Files.createTempDirectory(randomName());
- tempDirectory.toFile().deleteOnExit();
- Path tempFile = Files.createFile(tempDirectory.resolve(filename));
- Files.write(tempFile, contents.getBytes());
- return "file:" + tempFile.toString();
- } catch (IOException e) {
- throw Exceptions.propagate(e);
- }
- }
-
- private String randomName() {
- return Integer.valueOf(new Random(System.currentTimeMillis()).nextInt(100000)).toString();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/5f98079e/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleShellCommandIntegrationTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleShellCommandIntegrationTest.java b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleShellCommandIntegrationTest.java
new file mode 100644
index 0000000..d6ff949
--- /dev/null
+++ b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleShellCommandIntegrationTest.java
@@ -0,0 +1,166 @@
+/*
+ * 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 com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Random;
+import java.util.UUID;
+
+import static org.apache.brooklyn.test.framework.BaseTest.TARGET_ENTITY;
+import static org.apache.brooklyn.test.framework.SimpleShellCommand.COMMAND;
+import static org.apache.brooklyn.test.framework.SimpleShellCommandTest.*;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class SimpleShellCommandIntegrationTest extends BrooklynAppUnitTestSupport {
+ private static final Logger LOG = LoggerFactory.getLogger(SimpleShellCommandIntegrationTest.class);
+
+ private static final String UP = "up";
+ private LocalhostMachineProvisioningLocation localhost;
+ private String testId;
+
+
+ protected void setUpApp() {
+ super.setUpApp();
+ testId = UUID.randomUUID().toString();
+
+ localhost = app.getManagementContext().getLocationManager()
+ .createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class)
+ .configure("name", testId));
+ }
+
+ @Test(groups = "Integration")
+ public void shouldInvokeCommand() {
+ TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+
+ SimpleShellCommandTest uptime = app.createAndManageChild(EntitySpec.create(SimpleShellCommandTest.class)
+ .configure(TARGET_ENTITY, testEntity)
+ .configure(COMMAND, "uptime")
+ .configure(ASSERT_STATUS, ImmutableMap.of(EQUALS, 0))
+ .configure(ASSERT_OUT, ImmutableMap.of(CONTAINS, UP)));
+
+ app.start(ImmutableList.of(localhost));
+
+ assertThat(uptime.sensors().get(SERVICE_UP)).isTrue()
+ .withFailMessage("Service should be up");
+ assertThat(ServiceStateLogic.getExpectedState(uptime)).isEqualTo(Lifecycle.RUNNING)
+ .withFailMessage("Service should be marked running");
+
+ }
+
+ @Test(groups = "Integration")
+ public void shouldNotBeUpIfAssertionFails() {
+ TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+
+ SimpleShellCommandTest uptime = app.createAndManageChild(EntitySpec.create(SimpleShellCommandTest.class)
+ .configure(TARGET_ENTITY, testEntity)
+ .configure(COMMAND, "uptime")
+ .configure(ASSERT_STATUS, ImmutableMap.of(EQUALS, 1)));
+
+ try {
+ app.start(ImmutableList.of(localhost));
+ } catch (Exception e) {
+ assertThat(e.getCause().getMessage().contains("exit code equals 1"));
+ }
+
+ assertThat(ServiceStateLogic.getExpectedState(uptime)).isEqualTo(Lifecycle.ON_FIRE)
+ .withFailMessage("Service should be marked on fire");
+
+ }
+
+ @Test(groups = "Integration")
+ public void shouldInvokeScript() {
+ TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+
+ String text = "hello world";
+ String testUrl = createTempScript("script.sh", "echo " + text);
+
+ SimpleShellCommandTest uptime = app.createAndManageChild(EntitySpec.create(SimpleShellCommandTest.class)
+ .configure(TARGET_ENTITY, testEntity)
+ .configure(DOWNLOAD_URL, testUrl)
+ .configure(ASSERT_STATUS, ImmutableMap.of(EQUALS, 0))
+ .configure(ASSERT_OUT, ImmutableMap.of(CONTAINS, text)));
+
+ app.start(ImmutableList.of(localhost));
+
+ assertThat(uptime.sensors().get(SERVICE_UP)).isTrue()
+ .withFailMessage("Service should be up");
+ assertThat(ServiceStateLogic.getExpectedState(uptime)).isEqualTo(Lifecycle.RUNNING)
+ .withFailMessage("Service should be marked running");
+ }
+
+ @Test
+ public void shouldExecuteInTheRightPlace() throws Exception {
+ TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+
+ String remoteTmp = randomName();
+ SimpleShellCommandTest uptime = app.createAndManageChild(EntitySpec.create(SimpleShellCommandTest.class)
+ .configure(TARGET_ENTITY, testEntity)
+ .configure(COMMAND, "mkdir " + remoteTmp)
+ .configure(ASSERT_STATUS, ImmutableMap.of(EQUALS, 0)));
+
+ String pwdUrl = createTempScript("pwd.sh", "pwd");
+
+ SimpleShellCommandTest pwd = app.createAndManageChild(EntitySpec.create(SimpleShellCommandTest.class)
+ .configure(TARGET_ENTITY, testEntity)
+ .configure(DOWNLOAD_URL, pwdUrl)
+ .configure(RUN_DIR, remoteTmp)
+ .configure(ASSERT_STATUS, ImmutableMap.of(EQUALS, 0))
+ .configure(ASSERT_OUT, ImmutableMap.of(CONTAINS, remoteTmp)));
+
+ app.start(ImmutableList.of(localhost));
+
+ assertThat(uptime.sensors().get(SERVICE_UP)).isTrue()
+ .withFailMessage("Service should be up");
+ assertThat(ServiceStateLogic.getExpectedState(uptime)).isEqualTo(Lifecycle.RUNNING)
+ .withFailMessage("Service should be marked running");
+ }
+
+ private String createTempScript(String filename, String contents) {
+ try {
+ Path tempDirectory = Files.createTempDirectory(randomName());
+ tempDirectory.toFile().deleteOnExit();
+ Path tempFile = Files.createFile(tempDirectory.resolve(filename));
+ Files.write(tempFile, contents.getBytes());
+ return "file:" + tempFile.toString();
+ } catch (IOException e) {
+ throw Exceptions.propagate(e);
+ }
+ }
+
+ private String randomName() {
+ return Integer.valueOf(new Random(System.currentTimeMillis()).nextInt(100000)).toString();
+ }
+
+}