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:30 UTC

[01/20] incubator-brooklyn git commit: Initial draft of SimpleCommand.

Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master faf08c116 -> bbacc2b94


Initial draft of SimpleCommand.


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/b4e3ac7b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/b4e3ac7b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/b4e3ac7b

Branch: refs/heads/master
Commit: b4e3ac7b68ed26f3efa74be7285de013d1f8c02a
Parents: ca89ed4
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Thu Nov 5 15:06:45 2015 +0000
Committer: Geoff Macartney <ge...@cloudsoftcorp.com>
Committed: Fri Nov 13 12:01:49 2015 +0000

----------------------------------------------------------------------
 .../brooklyn/util/core/task/ssh/SshTasks.java   |   5 +
 usage/test-framework/pom.xml                    |   6 +
 .../brooklyn/test/framework/AbstractTest.java   |  28 ++-
 .../brooklyn/test/framework/BaseTest.java       |   2 +
 .../brooklyn/test/framework/SimpleCommand.java  |  50 +++++
 .../test/framework/SimpleCommandDriver.java     |  70 +++++++
 .../test/framework/SimpleCommandImpl.java       | 177 +++++++++++++++++
 .../SimpleCommandLifecycleEffectorTasks.java    |  73 +++++++
 .../test/framework/SimpleCommandSshDriver.java  | 192 +++++++++++++++++++
 .../test/framework/SimpleCommandTest.java       |  78 ++++++++
 .../test/framework/SimpleCommandTestImpl.java   | 149 ++++++++++++++
 .../brooklyn/test/framework/TestCase.java       |   1 +
 .../brooklyn/test/framework/TestEffector.java   |   1 +
 .../test/framework/TestHttpCallImpl.java        |   4 +-
 .../brooklyn/test/framework/TestSensor.java     |   1 +
 .../brooklyn/test/framework/TestSensorImpl.java |   2 +-
 .../test/framework/SimpleCommandImplTest.java   | 117 +++++++++++
 .../SimpleCommandScriptIntegrationTest.java     | 134 +++++++++++++
 .../test/framework/TestEffectorTest.java        |   3 +-
 .../brooklyn/logback-appender-stdout.xml        |  37 ++++
 20 files changed, 1117 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b4e3ac7b/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshTasks.java b/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshTasks.java
index e939ca8..c9fd66b 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshTasks.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/ssh/SshTasks.java
@@ -215,6 +215,11 @@ public class SshTasks {
         return installFromUrl(ResourceUtils.create(SshTasks.class), ImmutableMap.<String,Object>of(), location, url, destPath);
     }
     /** task to install a file given a url, where the url is resolved remotely first then locally */
+    public static TaskFactory<?> installFromUrl(final Map<String, ?> props, final SshMachineLocation location, final String url, final String destPath) {
+        return installFromUrl(ResourceUtils.create(SshTasks.class), props, location, url, destPath);
+    }
+
+    /** task to install a file given a url, where the url is resolved remotely first then locally */
     public static TaskFactory<?> installFromUrl(final ResourceUtils utils, final Map<String, ?> props, final SshMachineLocation location, final String url, final String destPath) {
         return new TaskFactory<TaskAdaptable<?>>() {
             @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b4e3ac7b/usage/test-framework/pom.xml
----------------------------------------------------------------------
diff --git a/usage/test-framework/pom.xml b/usage/test-framework/pom.xml
index 006afdc..b4297a9 100644
--- a/usage/test-framework/pom.xml
+++ b/usage/test-framework/pom.xml
@@ -47,6 +47,12 @@
 
         <!--TEST SCOPE :: START-->
         <dependency>
+            <groupId>org.apache.brooklyn</groupId>
+            <artifactId>brooklyn-logback-xml</artifactId>
+            <version>${brooklyn.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>org.testng</groupId>
             <artifactId>testng</artifactId>
             <version>${testng.version}</version>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b4e3ac7b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/AbstractTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/AbstractTest.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/AbstractTest.java
index d97d09b..434be8e 100644
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/AbstractTest.java
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/AbstractTest.java
@@ -19,6 +19,7 @@
 package org.apache.brooklyn.test.framework;
 
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.mgmt.ExecutionContext;
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent;
 import org.apache.brooklyn.core.entity.AbstractEntity;
@@ -44,24 +45,33 @@ public abstract class AbstractTest extends AbstractEntity implements BaseTest {
      * @throws @RuntimeException if no target can be determined.
      */
     public Entity resolveTarget() {
-        Entity entity = getConfig(TARGET_ENTITY);
-        if (null == entity) {
-            entity = getTargetById();
+        return resolveTarget(getExecutionContext(), this);
+    }
+
+    /**
+     * Find the target entity in the given execution context.
+     *
+     * @see {@link #resolveTarget()}.
+     */
+    public static Entity resolveTarget(ExecutionContext executionContext, Entity entity) {
+        Entity target = entity.getConfig(TARGET_ENTITY);
+        if (null == target) {
+            target = getTargetById(executionContext, entity);
         }
-        return entity;
+        return target;
     }
 
-    private Entity getTargetById() {
-        String targetId = getConfig(TARGET_ID);
+    private static Entity getTargetById(ExecutionContext executionContext, Entity entity) {
+        String targetId = entity.getConfig(TARGET_ID);
         final Task<Entity> targetLookup = new DslComponent(targetId).newTask();
-        Entity entity = null;
+        Entity target = null;
         try {
-            entity = Tasks.resolveValue(targetLookup, Entity.class, getExecutionContext(), "Finding entity " + targetId);
+            target = Tasks.resolveValue(targetLookup, Entity.class, executionContext, "Finding entity " + targetId);
             LOG.debug("Found target by id {}", targetId);
         } catch (final ExecutionException | InterruptedException e) {
             LOG.error("Error finding target {}", targetId);
             Exceptions.propagate(e);
         }
-        return entity;
+        return target;
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b4e3ac7b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/BaseTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/BaseTest.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/BaseTest.java
index 7fd70ef..4043bcc 100644
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/BaseTest.java
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/BaseTest.java
@@ -20,6 +20,7 @@ package org.apache.brooklyn.test.framework;
 
 import com.google.common.collect.Maps;
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.mgmt.ExecutionContext;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.trait.Startable;
@@ -60,4 +61,5 @@ public interface BaseTest extends Entity, Startable {
      * @throws IllegalArgumentException if the target cannot be found.
      */
     Entity resolveTarget();
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b4e3ac7b/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
new file mode 100644
index 0000000..3332a04
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommand.java
@@ -0,0 +1,50 @@
+/*
+ * 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 org.apache.brooklyn.util.os.Os;
+
+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 {
+
+    @SetFromFlag(nullable = false)
+    ConfigKey<String> DEFAULT_COMMAND = ConfigKeys.newConfigKey(String.class, "defaultCommand",
+            "Command to invoke if no script is provided via a downloadUrl");
+
+    @SetFromFlag("downloadUrl")
+    AttributeSensorAndConfigKey<String, String> DOWNLOAD_URL = SoftwareProcess.DOWNLOAD_URL;
+
+    @SetFromFlag("scriptDir")
+    ConfigKey<String> SCRIPT_DIR = newConfigKey("scriptDir", "directory where downloaded scripts should be put", Os.tmp());
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b4e3ac7b/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
new file mode 100644
index 0000000..d95d509
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandDriver.java
@@ -0,0 +1,70 @@
+/*
+ * 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/b4e3ac7b/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
new file mode 100644
index 0000000..8b3d27f
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandImpl.java
@@ -0,0 +1,177 @@
+/*
+ * 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.drivers.DriverDependentEntity;
+import org.apache.brooklyn.api.entity.drivers.EntityDriverManager;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.location.MachineLocation;
+import org.apache.brooklyn.core.annotation.EffectorParam;
+import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+
+import static org.apache.brooklyn.core.entity.lifecycle.Lifecycle.*;
+import static org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.setExpectedState;
+
+/**
+ * Implementation for {@link SimpleCommand}.
+ */
+public class SimpleCommandImpl extends AbstractEntity
+        implements SimpleCommand, DriverDependentEntity<SimpleCommandDriver> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SimpleCommandImpl.class);
+    private static final int A_LINE = 80;
+    private transient SimpleCommandDriver driver;
+
+    private Collection<? extends Location> locations;
+
+    @Override
+    public SimpleCommandDriver getDriver() {
+        return driver;
+    }
+
+    @Override
+    public Class<SimpleCommandDriver> getDriverInterface() {
+        return SimpleCommandDriver.class;
+    }
+
+    /**
+     * Gives the opportunity to sub-classes to do additional work based on the result of the command.
+     */
+    protected void handle(SimpleCommandDriver.Result result) {
+        LOG.debug("Result is {}\nwith output [\n{}\n] and error [\n{}\n]", new Object[] {
+                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 init() {
+        super.init();
+        getLifecycleEffectorTasks().attachLifecycleEffectors(this);
+    }
+
+
+    protected void initDriver(MachineLocation machine) {
+        LOG.debug("Initializing simple command driver");
+        SimpleCommandDriver newDriver = doInitDriver(machine);
+        if (newDriver == null) {
+            throw new UnsupportedOperationException("cannot start "+this+" on "+machine+": no driver available");
+        }
+        driver = newDriver;
+    }
+
+    protected SimpleCommandDriver doInitDriver(MachineLocation machine) {
+        if (driver!=null) {
+            if (machine.equals(driver.getLocation())) {
+                return driver; //just reuse
+            } else {
+                LOG.warn("driver/location change is untested for {} at {}; changing driver and continuing", this, machine);
+                return newDriver(machine);
+            }
+        } else {
+            return newDriver(machine);
+        }
+    }
+
+    protected SimpleCommandDriver newDriver(MachineLocation machine) {
+        LOG.debug("Creating new simple command driver for {} from management context", machine);
+        EntityDriverManager entityDriverManager = getManagementContext().getEntityDriverManager();
+        return entityDriverManager.build(this, machine);
+    }
+
+    @Override
+    public void start(@EffectorParam(name = "locations") Collection<? extends Location> locations) {
+        this.locations = locations;
+        startOnLocations();
+    }
+
+    protected void startOnLocations() {
+        setExpectedState(this, STARTING);
+        int size = locations.size();
+        LOG.debug("Starting simple command at {} locations{}", size,
+                size > 0 ? " beginning " + locations.iterator().next() : "");
+        try {
+            execute(locations);
+            setUpAndRunState(true, RUNNING);
+
+        } catch (final Exception e) {
+            setUpAndRunState(false, ON_FIRE);
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    private void execute(Collection<? extends Location> locations) {
+        SimpleCommandDriver.Result result = null;
+        String downloadUrl = getConfig(DOWNLOAD_URL);
+        if (Strings.isNonBlank(downloadUrl)) {
+            String scriptDir = getConfig(SCRIPT_DIR);
+            result = getDriver().executeDownloadedScript(locations, downloadUrl, scriptDir);
+
+        } else {
+            String command = getConfig(DEFAULT_COMMAND);
+            if (Strings.isBlank(command)) {
+                throw new IllegalArgumentException("No default command and no downloadUrl provided");
+            }
+
+            result = getDriver().execute(locations, command);
+        }
+        handle(result);
+    }
+
+
+    @Override
+    public void stop() {
+        LOG.debug("Stopping simple command");
+        setUpAndRunState(false, STOPPED);
+    }
+
+    @Override
+    public void restart() {
+        LOG.debug("Restarting simple command");
+        setUpAndRunState(true, RUNNING);
+    }
+
+    private void setUpAndRunState(boolean up, Lifecycle status) {
+        sensors().set(SERVICE_UP, up);
+        setExpectedState(this, status);
+    }
+
+    protected SimpleCommandLifecycleEffectorTasks getLifecycleEffectorTasks () {
+        return new SimpleCommandLifecycleEffectorTasks();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b4e3ac7b/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
new file mode 100644
index 0000000..d044212
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandLifecycleEffectorTasks.java
@@ -0,0 +1,73 @@
+/*
+ * 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);
+    private MachineLocation location;
+
+    protected Location getLocation(@Nullable Collection<? extends Location> locations) {
+        return super.getLocation(entity().filterLocations(locations));
+    }
+
+    @Override
+    protected void preStartCustom(MachineLocation machine) {
+        location = machine;
+        super.preStartCustom(location);
+        LOG.debug("Performing lifecycle preStartCustom on simple command");
+        entity().initDriver(location);
+    }
+
+    @Override
+    protected void preRestartCustom() {
+        LOG.debug("Performing lifecycle preStartCustom on simple command");
+        Asserts.notNull(location, "Cannot restart with no location");
+        entity().initDriver(location);
+    }
+
+    @Override
+    protected String startProcessesAtMachine(Supplier<MachineLocation> machineS) {
+        LOG.debug("Performing lifecycle startProcessesAtMachine on simple command");
+        entity().getDriver().start();
+        return "Started with driver " + entity().getDriver();
+    }
+
+    @Override
+    protected String stopProcessesAtMachine() {
+        LOG.debug("Performing lifecycle stopProcessesAtMachine on simple command");
+        entity().getDriver().stop();
+        return "Stopped";
+    }
+
+    protected SimpleCommandImpl entity() {
+        return (SimpleCommandImpl) super.entity();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b4e3ac7b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandSshDriver.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandSshDriver.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandSshDriver.java
new file mode 100644
index 0000000..f386b1e
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandSshDriver.java
@@ -0,0 +1,192 @@
+/*
+ * 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.entity.EntityLocal;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.mgmt.TaskAdaptable;
+import org.apache.brooklyn.api.mgmt.TaskFactory;
+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.ResourceUtils;
+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.ProcessTaskFactory;
+import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.exceptions.FatalRuntimeException;
+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 com.google.common.base.Preconditions.checkNotNull;
+import static org.apache.brooklyn.util.text.Strings.isBlank;
+
+/**
+ * Driver for {@link SimpleCommand}.
+ */
+public class SimpleCommandSshDriver implements SimpleCommandDriver {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SimpleCommandSshDriver.class);
+    public static final String DEFAULT_NAME = "download.sh";
+
+    protected final EntityLocal entity;
+    protected final ResourceUtils resource;
+    protected final Location location;
+
+    public SimpleCommandSshDriver(EntityLocal entity, SshMachineLocation location) {
+        LOG.debug("Constructing SSH driver for simple command for {} at {}", entity, location);
+        this.entity = checkNotNull(entity, "entity");
+        this.location = checkNotNull(location, "location");
+        this.resource = ResourceUtils.create(entity);
+    }
+
+    @Override
+    public EntityLocal getEntity() {
+        return entity;
+    }
+
+    @Override
+    public void start() {
+        LOG.debug("Performing start in SSH driver for simple command");
+        invoke();
+    }
+
+    private void invoke() {
+        SimpleCommand simpleCommand = (SimpleCommand) getEntity();
+        simpleCommand.start(ImmutableList.of(location));
+    }
+
+    @Override
+    public void restart() {
+        LOG.debug("Performing restart in SSH driver for simple command");
+        invoke();
+    }
+
+    @Override
+    public void stop() {
+        LOG.debug("Performing stop in SSH driver for simple command");
+    }
+
+    @Override
+    public Result execute(Collection<? extends Location> hostLocations, String command) {
+
+        SshMachineLocation machine = getSshMachine(hostLocations);
+        ProcessTaskFactory<Integer> taskFactory = SshTasks.newSshExecTaskFactory(machine, command);
+
+        LOG.debug("Creating task to execute '{}' on location {}", command, machine);
+        final ProcessTaskWrapper<Integer> job = DynamicTasks.queue(taskFactory);
+        DynamicTasks.waitForLast();
+        return buildResult(job);
+    }
+
+    private <T> Result buildResult(final ProcessTaskWrapper<Integer> job) {
+        return new Result() {
+
+            @Override
+            public int getExitCode() {
+                return job.get();
+            }
+
+            @Override
+            public String getStdout() {
+                return job.getStdout().trim();
+            }
+
+            @Override
+            public String getStderr() {
+                return job.getStderr().trim();
+            }
+        };
+    }
+
+    @Override
+    public Result executeDownloadedScript(Collection<? extends Location> hostLocations,
+                                          String url, String directory) {
+
+        SshMachineLocation machine = getSshMachine(hostLocations);
+        String destPath = calculateDestPath(url, directory);
+
+        TaskFactory<?> install = SshTasks.installFromUrl(ImmutableMap.<String, Object>of(), machine, url, destPath);
+        DynamicTasks.queue(install);
+        DynamicTasks.waitForLast();
+
+        machine.execCommands("make the script executable", ImmutableList.<String>of("chmod u+x " + destPath));
+
+        return execute(hostLocations, destPath);
+    }
+
+    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 Exceptions.propagate(new FatalRuntimeException("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;
+    }
+
+    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();
+    }
+
+    @Override
+    public Location getLocation() {
+        return location;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b4e3ac7b/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
new file mode 100644
index 0000000..c962403
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandTest.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(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/b4e3ac7b/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
new file mode 100644
index 0000000..261afe7
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandTestImpl.java
@@ -0,0 +1,149 @@
+/*
+ * 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(SimpleCommandDriver.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/b4e3ac7b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java
index 78fd8d6..d05889d 100644
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java
@@ -19,6 +19,7 @@
 package org.apache.brooklyn.test.framework;
 
 import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.core.entity.trait.Startable;
 
 /**
  * Entity that logically groups other test entities

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b4e3ac7b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEffector.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEffector.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEffector.java
index 14c45f5..6639845 100644
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEffector.java
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEffector.java
@@ -23,6 +23,7 @@ import com.google.common.reflect.TypeToken;
 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.util.core.flags.SetFromFlag;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b4e3ac7b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java
index 66e24da..a1d84bf 100644
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java
@@ -58,7 +58,7 @@ public class TestHttpCallImpl extends AbstractTest implements TestHttpCall {
             sensors().set(SERVICE_UP, true);
             ServiceStateLogic.setExpectedState(this, Lifecycle.RUNNING);
         } catch (Throwable t) {
-            LOG.info("Url [{}] test failed", url);
+            LOG.debug("Url [{}] test failed", url);
             sensors().set(SERVICE_UP, false);
             ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE);
             throw Exceptions.propagate(t);
@@ -89,7 +89,7 @@ public class TestHttpCallImpl extends AbstractTest implements TestHttpCall {
 
         for (final Map.Entry<?, ?> entry : assertions.entrySet()) {
             if (Objects.equal(entry.getKey(), "regex")) {
-                LOG.info("Testing if url [{}] matches regex [{}]",
+                LOG.debug("Testing if url [{}] matches regex [{}]",
                         new Object[]{url, entry.getValue()});
                 assertContentEventuallyMatches(flags, url, TypeCoercions.coerce(entry.getValue(), String.class));
             } else if (Objects.equal(entry.getKey(), "bodyContains")) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b4e3ac7b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensor.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensor.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensor.java
index ec070d1..3655501 100644
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensor.java
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensor.java
@@ -21,6 +21,7 @@ package org.apache.brooklyn.test.framework;
 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.util.core.flags.SetFromFlag;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b4e3ac7b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java
index c2d6169..f8c96a0 100644
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java
@@ -65,7 +65,7 @@ public class TestSensorImpl extends AbstractTest implements TestSensor {
             sensors().set(SERVICE_UP, true);
             ServiceStateLogic.setExpectedState(this, Lifecycle.RUNNING);
         } catch (Throwable t) {
-            LOG.info("Sensor [{}] test failed", sensor);
+            LOG.debug("Sensor [{}] test failed", sensor);
             sensors().set(SERVICE_UP, false);
             ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE);
             throw Exceptions.propagate(t);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b4e3ac7b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplTest.java b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplTest.java
new file mode 100644
index 0000000..fac54aa
--- /dev/null
+++ b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.Predicate;
+import com.google.common.base.Strings;
+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.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+import org.apache.brooklyn.util.core.task.Tasks;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import javax.annotation.Nullable;
+import java.util.UUID;
+
+import static org.apache.brooklyn.test.framework.BaseTest.TARGET_ENTITY;
+import static org.apache.brooklyn.test.framework.SimpleCommand.DEFAULT_COMMAND;
+import static org.apache.brooklyn.test.framework.SimpleCommandTest.*;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class SimpleCommandImplTest {
+    private static final Logger LOG = LoggerFactory.getLogger(SimpleCommandImplTest.class);
+
+    private static final String UP = "up";
+    private TestApplication app;
+    private ManagementContext managementContext;
+    private LocalhostMachineProvisioningLocation localhost;
+    private String testId;
+
+
+    @BeforeMethod
+    public void setUp() {
+
+        testId = UUID.randomUUID().toString();
+
+        app = TestApplication.Factory.newManagedInstanceForTests();
+        managementContext = app.getManagementContext();
+
+        localhost = managementContext.getLocationManager()
+            .createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class)
+                .configure("name", testId));
+    }
+
+    @AfterMethod(alwaysRun = true)
+    public void tearDown() throws Exception {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+
+    @Test
+    public void shouldInvokeCommand() {
+        TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+
+        SimpleCommandTest uptime = app.createAndManageChild(EntitySpec.create(SimpleCommandTest.class)
+            .configure(TARGET_ENTITY, testEntity)
+            .configure(DEFAULT_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
+    public void shouldNotBeUpIfAssertionFails() {
+        TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+
+        SimpleCommandTest uptime = app.createAndManageChild(EntitySpec.create(SimpleCommandTest.class)
+            .configure(TARGET_ENTITY, testEntity)
+            .configure(DEFAULT_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");
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b4e3ac7b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java
new file mode 100644
index 0000000..e081cef
--- /dev/null
+++ b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java
@@ -0,0 +1,134 @@
+/*
+ * 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.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+import org.apache.brooklyn.test.http.TestHttpRequestHandler;
+import org.apache.brooklyn.test.http.TestHttpServer;
+import org.apache.brooklyn.util.core.task.Tasks;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.exceptions.FatalRuntimeException;
+import org.apache.brooklyn.util.http.HttpAsserts;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.*;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.UUID;
+
+import static org.apache.brooklyn.test.framework.BaseTest.TARGET_ENTITY;
+import static org.apache.brooklyn.test.framework.SimpleCommand.DEFAULT_COMMAND;
+import static org.apache.brooklyn.test.framework.SimpleCommandTest.*;
+import static org.assertj.core.api.Assertions.assertThat;
+
+@Test(groups = "Integration")
+public class SimpleCommandScriptIntegrationTest {
+    private static final Logger LOG = LoggerFactory.getLogger(SimpleCommandScriptIntegrationTest.class);
+
+    private static final String UP = "up";
+    private static final String SCRIPT_NAME = "script.sh";
+    private static final String TEXT = "hello world";
+    private TestApplication app;
+    private ManagementContext managementContext;
+    private LocalhostMachineProvisioningLocation localhost;
+    private TestHttpServer server;
+    private String testId;
+
+
+    @BeforeClass
+    public void setUpTests() {
+        server = initializeServer();
+    }
+
+    @AfterClass
+    public void tearDownTests() {
+        if (null != server) {
+            server.stop();
+        }
+    }
+
+    @BeforeMethod
+    public void setUp() {
+
+        testId = UUID.randomUUID().toString();
+
+        app = TestApplication.Factory.newManagedInstanceForTests();
+        managementContext = app.getManagementContext();
+
+        localhost = managementContext.getLocationManager()
+            .createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class)
+                .configure("name", testId));
+    }
+
+    @AfterMethod(alwaysRun = true)
+    public void tearDown() throws Exception {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+
+
+    private TestHttpServer initializeServerUnstarted() {
+        return new TestHttpServer()
+            .handler("/" + SCRIPT_NAME,
+                new TestHttpRequestHandler().response("#!/bin/sh\necho " + TEXT + "\n"));
+    }
+    private TestHttpServer initializeServer() {
+        return initializeServerUnstarted().start();
+    }
+
+
+
+    @Test
+    public void shouldInvokeScript() {
+        TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+
+        String testUrl = server.getUrl() + "/" + SCRIPT_NAME;
+        HttpAsserts.assertContentContainsText(testUrl, 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");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b4e3ac7b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEffectorTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEffectorTest.java b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEffectorTest.java
index ab01eea..b6f3c4a 100644
--- a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEffectorTest.java
+++ b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEffectorTest.java
@@ -51,7 +51,8 @@ public class TestEffectorTest {
         app = TestApplication.Factory.newManagedInstanceForTests();
         managementContext = app.getManagementContext();
 
-        loc = managementContext.getLocationManager().createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class)
+        loc = managementContext.getLocationManager()
+                .createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class)
                 .configure("name", testId));
 
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b4e3ac7b/usage/test-framework/src/test/resources/brooklyn/logback-appender-stdout.xml
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/resources/brooklyn/logback-appender-stdout.xml b/usage/test-framework/src/test/resources/brooklyn/logback-appender-stdout.xml
new file mode 100644
index 0000000..f2515ad
--- /dev/null
+++ b/usage/test-framework/src/test/resources/brooklyn/logback-appender-stdout.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<included>
+
+    <!-- change settings in this file for (temporary!) debug purposes, e.g. change filter level to DEBUG below -->
+
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%d %-5level %msg%n%xEx{0}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>INFO</level>
+        </filter>
+    </appender>
+
+    <root>
+        <appender-ref ref="STDOUT" />
+    </root>
+
+</included>
\ No newline at end of file


[19/20] incubator-brooklyn git commit: Add TODO comment about updating the assertion code.

Posted by he...@apache.org.
Add TODO comment about updating the assertion code.


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/22f34302
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/22f34302
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/22f34302

Branch: refs/heads/master
Commit: 22f34302d9cbacbb71f2da91cec909565cd9b1b7
Parents: a046197
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Mon Nov 23 17:14:46 2015 +0000
Committer: Geoff Macartney <ge...@cloudsoftcorp.com>
Committed: Mon Nov 23 17:14:46 2015 +0000

----------------------------------------------------------------------
 .../apache/brooklyn/test/framework/SimpleShellCommandTestImpl.java  | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/22f34302/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
index c0ce8fc..b8cceb8 100644
--- 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
@@ -50,6 +50,7 @@ import static org.apache.brooklyn.util.text.Strings.isBlank;
 import static org.apache.brooklyn.util.text.Strings.isNonBlank;
 import static org.apache.commons.collections.MapUtils.isEmpty;
 
+// TODO assertions below should use TestFrameworkAssertions but that class needs to be improved to give better error messages
 public class SimpleShellCommandTestImpl extends AbstractTest implements SimpleShellCommandTest {
 
     public static final int SUCCESS = 0;


[15/20] incubator-brooklyn git commit: Fix location handling in integration test and remove unnecessary classes.

Posted by he...@apache.org.
Fix location handling in integration test and remove unnecessary classes.


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/b2713ca4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/b2713ca4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/b2713ca4

Branch: refs/heads/master
Commit: b2713ca4d7382ff1057531a6ef92a8a038a59d39
Parents: 6017880
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Wed Nov 18 12:59:25 2015 +0000
Committer: Geoff Macartney <ge...@cloudsoftcorp.com>
Committed: Wed Nov 18 14:35:48 2015 +0000

----------------------------------------------------------------------
 .../test/framework/SimpleShellCommand.java      |  75 ------
 .../test/framework/SimpleShellCommandImpl.java  | 260 -------------------
 ...impleShellCommandLifecycleEffectorTasks.java |  57 ----
 .../test/framework/SimpleShellCommandTest.java  |  31 ++-
 .../framework/SimpleShellCommandTestImpl.java   | 199 ++++++++++++--
 .../SimpleShellCommandIntegrationTest.java      |  47 ++--
 6 files changed, 236 insertions(+), 433 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b2713ca4/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
deleted file mode 100644
index fc182ef..0000000
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommand.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(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(String.class, "run.dir", "directory where downloaded scripts should be run from");
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b2713ca4/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
deleted file mode 100644
index c63e1fc..0000000
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandImpl.java
+++ /dev/null
@@ -1,260 +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.*;
-
-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";
-
-    @Override
-    public void init() {
-        super.init();
-        getLifecycleEffectorTasks().attachLifecycleEffectors(this);
-    }
-
-    @Override
-    public void start(Collection<? extends Location> locations) {
-        addLocations(filterLocations(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);
-    }
-
-    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;
-    }
-
-    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("Must specify exactly one of", downloadName, "and", commandName);
-        }
-
-        if (isNonBlank(downloadUrl)) {
-            String scriptDir = getConfig(SCRIPT_DIR);
-            String scriptPath = calculateDestPath(downloadUrl, scriptDir);
-            result = executeDownloadedScript(machineLocation, downloadUrl, scriptPath);
-        }
-
-        if (isNonBlank(command)) {
-            result = executeShellCommand(machineLocation, command);
-        }
-
-        handle(result);
-    }
-
-    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();
-
-        List<String> commands = new ArrayList<>();
-        commands.add("chmod u+x " + scriptPath);
-        maybeCdToRunDir(commands);
-        commands.add(scriptPath);
-
-        return runCommands(machine, commands);
-    }
-
-    private SimpleShellCommand.Result executeShellCommand(MachineLocation machineLocation, String command) {
-
-        SshMachineLocation machine = getSshMachine(ImmutableList.of(machineLocation));
-
-        List<String> commands = new ArrayList<>();
-        maybeCdToRunDir(commands);
-        commands.add(command);
-
-        return runCommands(machine, commands);
-    }
-
-    private void maybeCdToRunDir(List<String> commands) {
-        String runDir = getConfig(RUN_DIR);
-        if (!isBlank(runDir)) {
-            commands.add(CD + " " + runDir);
-        }
-    }
-
-    private Result runCommands(SshMachineLocation machine, List<String> commands) {
-        SshEffectorTasks.SshEffectorTaskFactory<Integer> etf = SshEffectorTasks.ssh(machine, commands.toArray(new String[]{}));
-
-        ProcessTaskWrapper<Integer> job = DynamicTasks.queue(etf);
-        DynamicTasks.waitForLast();
-        return buildResult(job);
-    }
-
-    private <T> SimpleShellCommand.Result buildResult(final ProcessTaskWrapper<Integer> job) {
-        final int exitCode = job.get();
-        final String stdout = job.getStdout().trim();
-        final String stderr = job.getStderr().trim();
-        return new SimpleShellCommand.Result() {
-
-            @Override
-            public int getExitCode() {
-                return exitCode;
-            }
-
-            @Override
-            public String getStdout() {
-                return stdout;
-            }
-
-            @Override
-            public String getStderr() {
-                return stderr;
-            }
-        };
-    }
-
-    private IllegalArgumentException illegal(String message, String ...messages) {
-        return new IllegalArgumentException(Joiner.on(' ').join(this.toString() + ":", message, messages));
-    }
-
-    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/b2713ca4/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
deleted file mode 100644
index fdccd99..0000000
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandLifecycleEffectorTasks.java
+++ /dev/null
@@ -1,57 +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.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/b2713ca4/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
index 17621d9..0b71f2f 100644
--- 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
@@ -22,15 +22,21 @@ 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.core.sensor.AttributeSensorAndConfigKey;
+import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 
 import java.util.Map;
 
+import static org.apache.brooklyn.core.config.ConfigKeys.newConfigKey;
+
 /**
  * Tests using a simple command execution.
  */
 @ImplementedBy(SimpleShellCommandTestImpl.class)
-public interface SimpleShellCommandTest extends SimpleShellCommand, BaseTest {
+public interface SimpleShellCommandTest extends BaseTest {
+
+    String TMP_DEFAULT = "/tmp";
 
     /**
      * Equals assertion on command result.
@@ -53,6 +59,29 @@ public interface SimpleShellCommandTest extends SimpleShellCommand, BaseTest {
     String IS_EMPTY = "isEmpty";
 
     /**
+     * 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(String.class, "run.dir", "directory where downloaded scripts should be run from");
+    /**
      * Assertions on the exit code of the simple command.
      *
      * If not explicitly configured, the default assertion is a non-zero exit code.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b2713ca4/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
index 6a35e73..c0ce8fc 100644
--- 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
@@ -20,39 +20,92 @@ package org.apache.brooklyn.test.framework;
 
 
 import com.google.common.base.Joiner;
+import com.google.common.base.Splitter;
 import com.google.common.collect.ImmutableMap;
-import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.mgmt.TaskFactory;
+import org.apache.brooklyn.core.effector.ssh.SshEffectorTasks;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.core.location.Machines;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.test.Asserts;
+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.text.Identifiers;
+import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.*;
 
+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.groovy.GroovyJavaMethods.truth;
+import static org.apache.brooklyn.util.text.Strings.isBlank;
+import static org.apache.brooklyn.util.text.Strings.isNonBlank;
 import static org.apache.commons.collections.MapUtils.isEmpty;
 
-public class SimpleShellCommandTestImpl extends SimpleShellCommandImpl implements SimpleShellCommandTest {
+public class SimpleShellCommandTestImpl extends AbstractTest implements SimpleShellCommandTest {
 
     public static final int SUCCESS = 0;
 
+    private static final Logger LOG = LoggerFactory.getLogger(SimpleShellCommandTestImpl.class);
+    private static final int A_LINE = 80;
+    public static final String DEFAULT_NAME = "download.sh";
+    private static final String CD = "cd";
+
     @Override
-    public Entity resolveTarget() {
-        return AbstractTest.resolveTarget(getExecutionContext(), this);
+    public void start(Collection<? extends Location> locations) {
+        setExpectedState(this, STARTING);
+        execute();
     }
 
-    /**
-     * The test will choose the location of its target entity.
-     */
-    public Collection<? extends Location> filterLocations(Collection<? extends Location> locations) {
-        Entity target = resolveTarget();
-        Collection<Location> targetLocations = target.getLocations();
-        return targetLocations;
+    @Override
+    public void stop() {
+        LOG.debug("{} Stopping simple command", this);
+        setUpAndRunState(false, STOPPED);
     }
 
     @Override
-    protected void handle(SimpleShellCommand.Result result) {
+    public void restart() {
+        LOG.debug("{} Restarting simple command", this);
+        execute();
+    }
+
+    private void setUpAndRunState(boolean up, Lifecycle status) {
+        sensors().set(SERVICE_UP, up);
+        setExpectedState(this, status);
+    }
+
+    private static class Result {
+        int exitCode;
+        String stdout;
+        String stderr;
+        public Result(final ProcessTaskWrapper<Integer> job) {
+            exitCode = job.get();
+            stdout = job.getStdout().trim();
+            stderr = job.getStderr().trim();
+        }
+        public int getExitCode() {
+            return exitCode;
+        }
+        public String getStdout() {
+            return stdout;
+        }
+        public String getStderr() {
+            return stderr;
+        }
+    }
+
+    protected void handle(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())
+        });
         AssertionSupport support = new AssertionSupport();
         checkAssertions(support, exitCodeAssertions(), "exit code", result.getExitCode());
         checkAssertions(support, getConfig(ASSERT_OUT), "stdout", result.getStdout());
@@ -60,6 +113,120 @@ public class SimpleShellCommandTestImpl extends SimpleShellCommandImpl implement
         support.validate();
     }
 
+    private String shorten(String text) {
+        return Strings.maxlenWithEllipsis(text, A_LINE);
+    }
+
+    public void execute() {
+        try {
+            SshMachineLocation machineLocation =
+                Machines.findUniqueMachineLocation(resolveTarget().getLocations(), SshMachineLocation.class).get();
+            executeCommand(machineLocation);
+            setUpAndRunState(true, RUNNING);
+        } catch (Throwable t) {
+            setUpAndRunState(false, ON_FIRE);
+            throw Exceptions.propagate(t);
+        }
+    }
+
+    private void executeCommand(SshMachineLocation machineLocation) {
+
+        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("Must specify exactly one of", downloadName, "and", commandName);
+        }
+
+        if (isNonBlank(downloadUrl)) {
+            String scriptDir = getConfig(SCRIPT_DIR);
+            String scriptPath = calculateDestPath(downloadUrl, scriptDir);
+            result = executeDownloadedScript(machineLocation, downloadUrl, scriptPath);
+        }
+
+        if (isNonBlank(command)) {
+            result = executeShellCommand(machineLocation, command);
+        }
+
+        handle(result);
+    }
+
+    private Result executeDownloadedScript(SshMachineLocation machineLocation, String url, String scriptPath) {
+
+        TaskFactory<?> install = SshTasks.installFromUrl(ImmutableMap.<String, Object>of(), machineLocation, url, scriptPath);
+        DynamicTasks.queue(install);
+        DynamicTasks.waitForLast();
+
+        List<String> commands = new ArrayList<>();
+        commands.add("chmod u+x " + scriptPath);
+        maybeCdToRunDir(commands);
+        commands.add(scriptPath);
+
+        return runCommands(machineLocation, commands);
+    }
+
+    private Result executeShellCommand(SshMachineLocation machineLocation, String command) {
+
+        List<String> commands = new ArrayList<>();
+        maybeCdToRunDir(commands);
+        commands.add(command);
+
+        return runCommands(machineLocation, commands);
+    }
+
+    private void maybeCdToRunDir(List<String> commands) {
+        String runDir = getConfig(RUN_DIR);
+        if (!isBlank(runDir)) {
+            commands.add(CD + " " + runDir);
+        }
+    }
+
+    private Result runCommands(SshMachineLocation machine, List<String> commands) {
+        SshEffectorTasks.SshEffectorTaskFactory<Integer> etf = SshEffectorTasks.ssh(commands.toArray(new String[]{}))
+            .machine(machine);
+
+        ProcessTaskWrapper<Integer> job = DynamicTasks.queue(etf);
+        job.asTask().blockUntilEnded();
+        return new Result(job);
+    }
+
+
+
+    private IllegalArgumentException illegal(String message, String ...messages) {
+        return new IllegalArgumentException(Joiner.on(' ').join(this.toString() + ":", message, messages));
+    }
+
+    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-" + Identifiers.makeRandomId(8), scriptName);
+        } catch (MalformedURLException e) {
+            throw illegal("Malformed URL:", url);
+        }
+    }
+
+    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;
+    }
+    
     private <T> void checkAssertions(AssertionSupport support, Map<?, ?> assertions, String target, T actual) {
         if (null == assertions) {
             return;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b2713ca4/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
index 7f8f078..c6b5b87 100644
--- 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
@@ -21,38 +21,37 @@ 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.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.util.Random;
 
 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 String UP = "up";
-    private LocalhostMachineProvisioningLocation localhost;
-
-    protected void setUpApp() {
-        super.setUpApp();
-        localhost = app.getManagementContext().getLocationManager()
-            .createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class));
+    private LocalhostMachineProvisioningLocation loc;
+    private SshMachineLocation machine;
+
+    @BeforeMethod(alwaysRun = true)
+    public void setUp() throws Exception {
+        super.setUp();
+        loc = app.newLocalhostProvisioningLocation();
+        machine = loc.obtain();
     }
 
     @DataProvider(name = "shouldInsistOnJustOneOfCommandAndScript")
@@ -66,15 +65,15 @@ public class SimpleShellCommandIntegrationTest extends BrooklynAppUnitTestSuppor
         };
     }
 
-    @Test(dataProvider = "shouldInsistOnJustOneOfCommandAndScript")
-    public void shouldInsistOnJustOneOfCommandAndScript(String command, String script, boolean valid) throws  Exception{
+    @Test(groups= "Integration", dataProvider = "shouldInsistOnJustOneOfCommandAndScript")
+    public void shouldInsistOnJustOneOfCommandAndScript(String command, String script, boolean valid) throws Exception {
         Path scriptPath = null;
         String scriptUrl = null;
         if (null != script) {
             scriptPath = createTempScript("pwd", "pwd");
             scriptUrl = "file:" + scriptPath;
         }
-        TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class).location(machine));
 
         app.createAndManageChild(EntitySpec.create(SimpleShellCommandTest.class)
             .configure(TARGET_ENTITY, testEntity)
@@ -82,7 +81,7 @@ public class SimpleShellCommandIntegrationTest extends BrooklynAppUnitTestSuppor
             .configure(DOWNLOAD_URL, scriptUrl));
 
         try {
-            app.start(ImmutableList.of(localhost));
+            app.start(ImmutableList.of(loc));
             if (!valid) {
                 Asserts.shouldHaveFailedPreviously();
             }
@@ -99,7 +98,7 @@ public class SimpleShellCommandIntegrationTest extends BrooklynAppUnitTestSuppor
 
     @Test(groups = "Integration")
     public void shouldInvokeCommand() {
-        TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class).location(machine));
 
         SimpleShellCommandTest uptime = app.createAndManageChild(EntitySpec.create(SimpleShellCommandTest.class)
             .configure(TARGET_ENTITY, testEntity)
@@ -107,7 +106,7 @@ public class SimpleShellCommandIntegrationTest extends BrooklynAppUnitTestSuppor
             .configure(ASSERT_STATUS, ImmutableMap.of(EQUALS, 0))
             .configure(ASSERT_OUT, ImmutableMap.of(CONTAINS, UP)));
 
-        app.start(ImmutableList.of(localhost));
+        app.start(ImmutableList.of(loc));
 
         assertThat(uptime.sensors().get(SERVICE_UP)).isTrue()
             .withFailMessage("Service should be up");
@@ -118,7 +117,7 @@ public class SimpleShellCommandIntegrationTest extends BrooklynAppUnitTestSuppor
 
     @Test(groups = "Integration")
     public void shouldNotBeUpIfAssertionFails() {
-        TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class).location(machine));
 
         SimpleShellCommandTest uptime = app.createAndManageChild(EntitySpec.create(SimpleShellCommandTest.class)
             .configure(TARGET_ENTITY, testEntity)
@@ -126,7 +125,7 @@ public class SimpleShellCommandIntegrationTest extends BrooklynAppUnitTestSuppor
             .configure(ASSERT_STATUS, ImmutableMap.of(EQUALS, 1)));
 
         try {
-            app.start(ImmutableList.of(localhost));
+            app.start(ImmutableList.of(loc));
         } catch (Exception e) {
             assertThat(e.getCause().getMessage().contains("exit code equals 1"));
         }
@@ -138,7 +137,7 @@ public class SimpleShellCommandIntegrationTest extends BrooklynAppUnitTestSuppor
 
     @Test(groups = "Integration")
     public void shouldInvokeScript() throws Exception {
-        TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class).location(machine));
 
         String text = "hello world";
         Path testScript = createTempScript("script", "echo " + text);
@@ -150,7 +149,7 @@ public class SimpleShellCommandIntegrationTest extends BrooklynAppUnitTestSuppor
                 .configure(ASSERT_STATUS, ImmutableMap.of(EQUALS, 0))
                 .configure(ASSERT_OUT, ImmutableMap.of(CONTAINS, text)));
 
-            app.start(ImmutableList.of(localhost));
+            app.start(ImmutableList.of(loc));
 
             assertThat(uptime.sensors().get(SERVICE_UP)).isTrue()
                 .withFailMessage("Service should be up");
@@ -162,9 +161,9 @@ public class SimpleShellCommandIntegrationTest extends BrooklynAppUnitTestSuppor
         }
     }
 
-    @Test
+    @Test(groups = "Integration")
     public void shouldExecuteInTheRunDir() throws Exception {
-        TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class).location(machine));
 
         Path pwdPath = createTempScript("pwd", "pwd");
 
@@ -184,7 +183,7 @@ public class SimpleShellCommandIntegrationTest extends BrooklynAppUnitTestSuppor
                 .configure(ASSERT_STATUS, ImmutableMap.of(EQUALS, 0))
                 .configure(ASSERT_OUT, ImmutableMap.of(CONTAINS, "/tmp")));
 
-            app.start(ImmutableList.of(localhost));
+            app.start(ImmutableList.of(loc));
 
             assertThat(pwd.sensors().get(SERVICE_UP)).isTrue().withFailMessage("Service should be up");
             assertThat(ServiceStateLogic.getExpectedState(pwd)).isEqualTo(Lifecycle.RUNNING)



[16/20] incubator-brooklyn git commit: Updates for github comments.

Posted by he...@apache.org.
Updates for github comments.

Remove unneeded logback file.
https://github.com/apache/incubator-brooklyn/pull/1030#discussion_r45317465

Remove spurious imports.
https://github.com/apache/incubator-brooklyn/pull/1030#discussion_r45317585
https://github.com/apache/incubator-brooklyn/pull/1030#discussion_r45317643

Include 'this' in log messages.
https://github.com/apache/incubator-brooklyn/pull/1030#discussion_r45317630


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/ad756062
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/ad756062
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/ad756062

Branch: refs/heads/master
Commit: ad756062604b39364b081f0aae7465edbbae23bc
Parents: b2713ca
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Thu Nov 19 10:05:17 2015 +0000
Committer: Geoff Macartney <ge...@cloudsoftcorp.com>
Committed: Thu Nov 19 10:15:25 2015 +0000

----------------------------------------------------------------------
 .../brooklyn/test/framework/TestCase.java       |  1 -
 .../test/framework/TestHttpCallImpl.java        | 14 ++++----
 .../brooklyn/test/framework/TestSensor.java     |  1 -
 .../brooklyn/logback-appender-stdout.xml        | 37 --------------------
 4 files changed, 7 insertions(+), 46 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ad756062/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java
index d05889d..78fd8d6 100644
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java
@@ -19,7 +19,6 @@
 package org.apache.brooklyn.test.framework;
 
 import org.apache.brooklyn.api.entity.ImplementedBy;
-import org.apache.brooklyn.core.entity.trait.Startable;
 
 /**
  * Entity that logically groups other test entities

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ad756062/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java
index a1d84bf..5f64f3c 100644
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java
@@ -58,7 +58,7 @@ public class TestHttpCallImpl extends AbstractTest implements TestHttpCall {
             sensors().set(SERVICE_UP, true);
             ServiceStateLogic.setExpectedState(this, Lifecycle.RUNNING);
         } catch (Throwable t) {
-            LOG.debug("Url [{}] test failed", url);
+            LOG.info("{} Url [{}] test failed", this, url);
             sensors().set(SERVICE_UP, false);
             ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE);
             throw Exceptions.propagate(t);
@@ -89,16 +89,16 @@ public class TestHttpCallImpl extends AbstractTest implements TestHttpCall {
 
         for (final Map.Entry<?, ?> entry : assertions.entrySet()) {
             if (Objects.equal(entry.getKey(), "regex")) {
-                LOG.debug("Testing if url [{}] matches regex [{}]",
-                        new Object[]{url, entry.getValue()});
+                LOG.debug("{} Testing if url [{}] matches regex [{}]",
+                        new Object[]{this, url, entry.getValue()});
                 assertContentEventuallyMatches(flags, url, TypeCoercions.coerce(entry.getValue(), String.class));
             } else if (Objects.equal(entry.getKey(), "bodyContains")) {
-                LOG.debug("Testing if url [{}] contains string [{}]",
-                        new Object[]{url, entry.getValue()});
+                LOG.debug("{} Testing if url [{}] contains string [{}]",
+                        new Object[]{this, url, entry.getValue()});
                 assertContentEventuallyContainsText(flags, url, TypeCoercions.coerce(entry.getValue(), String.class));
             } else if (Objects.equal(entry.getKey(), "status")) {
-                LOG.debug("Testing if url [{}] returns status code [{}]",
-                        new Object[]{url, entry.getValue()});
+                LOG.debug("{} Testing if url [{}] returns status code [{}]",
+                        new Object[]{this, url, entry.getValue()});
                 assertHttpStatusCodeEventuallyEquals(flags, url, TypeCoercions.coerce(entry.getValue(), Integer.class));
             }
         }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ad756062/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensor.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensor.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensor.java
index 3655501..ec070d1 100644
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensor.java
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensor.java
@@ -21,7 +21,6 @@ package org.apache.brooklyn.test.framework;
 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.util.core.flags.SetFromFlag;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ad756062/usage/test-framework/src/test/resources/brooklyn/logback-appender-stdout.xml
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/resources/brooklyn/logback-appender-stdout.xml b/usage/test-framework/src/test/resources/brooklyn/logback-appender-stdout.xml
deleted file mode 100644
index f2515ad..0000000
--- a/usage/test-framework/src/test/resources/brooklyn/logback-appender-stdout.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-    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.
--->
-<included>
-
-    <!-- change settings in this file for (temporary!) debug purposes, e.g. change filter level to DEBUG below -->
-
-    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
-        <encoder>
-            <pattern>%d %-5level %msg%n%xEx{0}</pattern>
-        </encoder>
-        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
-            <level>INFO</level>
-        </filter>
-    </appender>
-
-    <root>
-        <appender-ref ref="STDOUT" />
-    </root>
-
-</included>
\ No newline at end of file


[02/20] incubator-brooklyn git commit: Disable failing tests while I inquire about proper use of tests that require SSH access on Jenkins build machine.

Posted by he...@apache.org.
Disable failing tests while I inquire about proper use of tests that require SSH access on Jenkins build machine.


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/6cd62e7d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/6cd62e7d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/6cd62e7d

Branch: refs/heads/master
Commit: 6cd62e7d3b58876f40bbea9efb49426c9464589f
Parents: b4e3ac7
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Fri Nov 13 15:31:13 2015 +0000
Committer: Geoff Macartney <ge...@cloudsoftcorp.com>
Committed: Fri Nov 13 15:31:13 2015 +0000

----------------------------------------------------------------------
 .../apache/brooklyn/test/framework/SimpleCommandImplTest.java   | 5 +++--
 .../test/framework/SimpleCommandScriptIntegrationTest.java      | 4 ++--
 2 files changed, 5 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6cd62e7d/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplTest.java b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplTest.java
index fac54aa..3450952 100644
--- a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplTest.java
+++ b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplTest.java
@@ -47,6 +47,7 @@ import static org.apache.brooklyn.test.framework.SimpleCommand.DEFAULT_COMMAND;
 import static org.apache.brooklyn.test.framework.SimpleCommandTest.*;
 import static org.assertj.core.api.Assertions.assertThat;
 
+// TODO investigate proper status of this test that requires SSH access to localhost
 public class SimpleCommandImplTest {
     private static final Logger LOG = LoggerFactory.getLogger(SimpleCommandImplTest.class);
 
@@ -75,7 +76,7 @@ public class SimpleCommandImplTest {
         if (app != null) Entities.destroyAll(app.getManagementContext());
     }
 
-    @Test
+    @Test(enabled = false)
     public void shouldInvokeCommand() {
         TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
 
@@ -94,7 +95,7 @@ public class SimpleCommandImplTest {
 
     }
 
-    @Test
+    @Test(enabled = false)
     public void shouldNotBeUpIfAssertionFails() {
         TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6cd62e7d/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java
index e081cef..ef773d7 100644
--- a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java
+++ b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java
@@ -54,7 +54,7 @@ import static org.apache.brooklyn.test.framework.SimpleCommand.DEFAULT_COMMAND;
 import static org.apache.brooklyn.test.framework.SimpleCommandTest.*;
 import static org.assertj.core.api.Assertions.assertThat;
 
-@Test(groups = "Integration")
+@Test(groups = "Integration")  // TODO investigate proper status of this test that requires SSH access to localhost
 public class SimpleCommandScriptIntegrationTest {
     private static final Logger LOG = LoggerFactory.getLogger(SimpleCommandScriptIntegrationTest.class);
 
@@ -110,7 +110,7 @@ public class SimpleCommandScriptIntegrationTest {
 
 
 
-    @Test
+    @Test(enabled = false)
     public void shouldInvokeScript() {
         TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
 


[12/20] incubator-brooklyn git commit: Rename everything as SimpleShellCommand.

Posted by he...@apache.org.
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();
+    }
+
+}


[13/20] incubator-brooklyn git commit: Don't need to configure name in integration test.

Posted by he...@apache.org.
Don't need to configure name in integration test.

https://github.com/apache/incubator-brooklyn/pull/1030#discussion_r44860541


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/89d69269
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/89d69269
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/89d69269

Branch: refs/heads/master
Commit: 89d69269cad450f342a622c375b92c00c5482670
Parents: 5f98079
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Tue Nov 17 14:18:17 2015 +0000
Committer: Geoff Macartney <ge...@cloudsoftcorp.com>
Committed: Tue Nov 17 14:29:29 2015 +0000

----------------------------------------------------------------------
 .../test/framework/SimpleShellCommandIntegrationTest.java     | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/89d69269/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
index d6ff949..7b6c732 100644
--- 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
@@ -48,16 +48,11 @@ public class SimpleShellCommandIntegrationTest extends BrooklynAppUnitTestSuppor
 
     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));
+            .createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class));
     }
 
     @Test(groups = "Integration")


[11/20] incubator-brooklyn git commit: Simplify integration test, avoid TestHttpServer and just have one test file.

Posted by he...@apache.org.
Simplify integration test, avoid TestHttpServer and just have one test file.

https://github.com/apache/incubator-brooklyn/pull/1030#discussion_r44860563
https://github.com/apache/incubator-brooklyn/pull/1030#discussion_r44860570


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/f3a6395e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/f3a6395e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/f3a6395e

Branch: refs/heads/master
Commit: f3a6395e0028d26af473428f9d248a7d917ee7d1
Parents: 4467878
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Tue Nov 17 13:19:43 2015 +0000
Committer: Geoff Macartney <ge...@cloudsoftcorp.com>
Committed: Tue Nov 17 14:10:59 2015 +0000

----------------------------------------------------------------------
 .../SimpleCommandImplIntegrationTest.java       | 112 -------------
 .../framework/SimpleCommandIntegrationTest.java | 166 +++++++++++++++++++
 .../SimpleCommandScriptIntegrationTest.java     | 165 ------------------
 3 files changed, 166 insertions(+), 277 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f3a6395e/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplIntegrationTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplIntegrationTest.java b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplIntegrationTest.java
deleted file mode 100644
index dea50e9..0000000
--- a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplIntegrationTest.java
+++ /dev/null
@@ -1,112 +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.api.mgmt.ManagementContext;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
-import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
-import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-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 SimpleCommandImplIntegrationTest {
-    private static final Logger LOG = LoggerFactory.getLogger(SimpleCommandImplIntegrationTest.class);
-
-    private static final String UP = "up";
-    private TestApplication app;
-    private ManagementContext managementContext;
-    private LocalhostMachineProvisioningLocation localhost;
-    private String testId;
-
-
-    @BeforeMethod
-    public void setUp() {
-
-        testId = UUID.randomUUID().toString();
-
-        app = TestApplication.Factory.newManagedInstanceForTests();
-        managementContext = app.getManagementContext();
-
-        localhost = managementContext.getLocationManager()
-            .createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class)
-                .configure("name", testId));
-    }
-
-    @AfterMethod(alwaysRun = true)
-    public void tearDown() throws Exception {
-        if (app != null) Entities.destroyAll(app.getManagementContext());
-    }
-
-    @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");
-
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f3a6395e/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
new file mode 100644
index 0000000..0b7b121
--- /dev/null
+++ b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandIntegrationTest.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.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/f3a6395e/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java
deleted file mode 100644
index 3b6b875..0000000
--- a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java
+++ /dev/null
@@ -1,165 +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.api.mgmt.ManagementContext;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
-import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
-import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
-import org.apache.brooklyn.test.http.TestHttpRequestHandler;
-import org.apache.brooklyn.test.http.TestHttpServer;
-import org.apache.brooklyn.util.http.HttpAsserts;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.*;
-
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-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 SimpleCommandScriptIntegrationTest {
-    private static final Logger LOG = LoggerFactory.getLogger(SimpleCommandScriptIntegrationTest.class);
-
-    private static final String UP = "up";
-    private static final String SCRIPT_NAME = "script.sh";
-    private static final String TEXT = "hello world";
-    private TestApplication app;
-    private ManagementContext managementContext;
-    private LocalhostMachineProvisioningLocation localhost;
-    private TestHttpServer server;
-    private String testId;
-
-
-    @BeforeClass
-    public void setUpTests() {
-        server = initializeServer();
-    }
-
-    @AfterClass
-    public void tearDownTests() {
-        if (null != server) {
-            server.stop();
-        }
-    }
-
-    @BeforeMethod
-    public void setUp() {
-
-        testId = UUID.randomUUID().toString();
-
-        app = TestApplication.Factory.newManagedInstanceForTests();
-        managementContext = app.getManagementContext();
-
-        localhost = managementContext.getLocationManager()
-            .createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class)
-                .configure("name", testId));
-    }
-
-    @AfterMethod(alwaysRun = true)
-    public void tearDown() throws Exception {
-        if (app != null) Entities.destroyAll(app.getManagementContext());
-    }
-
-
-    private TestHttpServer initializeServerUnstarted() {
-        return new TestHttpServer()
-            .handler("/" + SCRIPT_NAME,
-                new TestHttpRequestHandler().response("#!/bin/sh\necho " + TEXT + "\n"));
-    }
-    private TestHttpServer initializeServer() {
-        return initializeServerUnstarted().start();
-    }
-
-
-
-    @Test(groups = "Integration")
-    public void shouldInvokeScript() {
-        TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-
-        String testUrl = server.getUrl() + "/" + SCRIPT_NAME;
-        HttpAsserts.assertContentContainsText(testUrl, 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 testUrl = server.getUrl() + "/" + SCRIPT_NAME;
-        HttpAsserts.assertContentContainsText(testUrl, TEXT);
-
-        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)));
-
-        Path localTmpPath = Paths.get("/tmp/").resolve(randomName());
-        Path pwdSh = localTmpPath.resolve("pwd.sh");
-        Files.createDirectory(localTmpPath);
-        Files.createFile(pwdSh);
-        Files.write(pwdSh, "pwd".getBytes());
-        String pwdUrl = "file:" + pwdSh.toString();
-
-        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 randomName() {
-        return Integer.valueOf(new Random(System.currentTimeMillis()).nextInt(100000)).toString();
-    }
-
-}


[05/20] incubator-brooklyn git commit: Use /tmp rather than Os.tmp()

Posted by he...@apache.org.
Use /tmp rather than Os.tmp()

https://github.com/apache/incubator-brooklyn/pull/1030#discussion_r44859808


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/93039184
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/93039184
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/93039184

Branch: refs/heads/master
Commit: 93039184a736a9fc698758d014e545a010438e42
Parents: b30489e
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Tue Nov 17 11:41:00 2015 +0000
Committer: Geoff Macartney <ge...@cloudsoftcorp.com>
Committed: Tue Nov 17 11:41:06 2015 +0000

----------------------------------------------------------------------
 .../java/org/apache/brooklyn/test/framework/SimpleCommand.java | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/93039184/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
index 40e26a9..c5ff777 100644
--- 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
@@ -26,7 +26,6 @@ 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 org.apache.brooklyn.util.os.Os;
 
 import static org.apache.brooklyn.core.config.ConfigKeys.newConfigKey;
 
@@ -38,6 +37,8 @@ import static org.apache.brooklyn.core.config.ConfigKeys.newConfigKey;
 @ImplementedBy(SimpleCommandImpl.class)
 public interface SimpleCommand extends Entity, Startable {
 
+    String TMP_DEFAULT = "/tmp";
+
     /**
      * Result of a command invocation.
      */
@@ -45,6 +46,7 @@ public interface SimpleCommand extends Entity, Startable {
         int getExitCode();
         String getStdout();
         String getStderr();
+
     }
 
     @SetFromFlag(nullable = false)
@@ -55,5 +57,5 @@ public interface SimpleCommand extends Entity, Startable {
     AttributeSensorAndConfigKey<String, String> DOWNLOAD_URL = SoftwareProcess.DOWNLOAD_URL;
 
     @SetFromFlag("scriptDir")
-    ConfigKey<String> SCRIPT_DIR = newConfigKey("scriptDir", "directory where downloaded scripts should be put", Os.tmp());
+    ConfigKey<String> SCRIPT_DIR = newConfigKey("scriptDir", "directory where downloaded scripts should be put", TMP_DEFAULT);
 }


[04/20] incubator-brooklyn git commit: Initial restructuring due to review comments.

Posted by he...@apache.org.
Initial restructuring due to review comments.

Removes as much as possible of the driver/lifecycle material, in response to
https://github.com/apache/incubator-brooklyn/pull/1030#issuecomment-156714424

Driver related classes removed.

SshEffectorTasks used where possible.

The lifecycle class is slimmed down but retained as it takes care of getting
hold of the MachineLocation.


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/b30489ed
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/b30489ed
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/b30489ed

Branch: refs/heads/master
Commit: b30489ed043da00162f5102dbb6ccfd8582d05df
Parents: 014b6bf
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Tue Nov 17 10:41:42 2015 +0000
Committer: Geoff Macartney <ge...@cloudsoftcorp.com>
Committed: Tue Nov 17 11:33:10 2015 +0000

----------------------------------------------------------------------
 .../brooklyn/test/framework/SimpleCommand.java  |   9 +
 .../test/framework/SimpleCommandImpl.java       | 226 +++++++++++++------
 .../SimpleCommandLifecycleEffectorTasks.java    |  23 +-
 .../test/framework/SimpleCommandSshDriver.java  | 192 ----------------
 .../test/framework/SimpleCommandTestImpl.java   |   2 +-
 5 files changed, 165 insertions(+), 287 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b30489ed/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
index 3332a04..40e26a9 100644
--- 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
@@ -38,6 +38,15 @@ import static org.apache.brooklyn.core.config.ConfigKeys.newConfigKey;
 @ImplementedBy(SimpleCommandImpl.class)
 public interface SimpleCommand extends Entity, Startable {
 
+    /**
+     * Result of a command invocation.
+     */
+    interface Result {
+        int getExitCode();
+        String getStdout();
+        String getStderr();
+    }
+
     @SetFromFlag(nullable = false)
     ConfigKey<String> DEFAULT_COMMAND = ConfigKeys.newConfigKey(String.class, "defaultCommand",
             "Command to invoke if no script is provided via a downloadUrl");

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b30489ed/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
index 8b3d27f..6b5f87c 100644
--- 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
@@ -18,49 +18,69 @@
  */
 package org.apache.brooklyn.test.framework;
 
-import org.apache.brooklyn.api.entity.drivers.DriverDependentEntity;
-import org.apache.brooklyn.api.entity.drivers.EntityDriverManager;
+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.annotation.EffectorParam;
+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.ResourceUtils;
+import org.apache.brooklyn.util.core.task.DynamicTasks;
+import org.apache.brooklyn.util.core.task.ssh.SshPutTaskWrapper;
+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, DriverDependentEntity<SimpleCommandDriver> {
+public class SimpleCommandImpl extends AbstractEntity implements SimpleCommand {
 
     private static final Logger LOG = LoggerFactory.getLogger(SimpleCommandImpl.class);
     private static final int A_LINE = 80;
-    private transient SimpleCommandDriver driver;
+    public static final String DEFAULT_NAME = "download.sh";
 
-    private Collection<? extends Location> locations;
+    private ResourceUtils resourceUtils;
 
     @Override
-    public SimpleCommandDriver getDriver() {
-        return driver;
+    public void init() {
+        super.init();
+        resourceUtils = ResourceUtils.create(this);
+        getLifecycleEffectorTasks().attachLifecycleEffectors(this);
     }
 
-    @Override
-    public Class<SimpleCommandDriver> getDriverInterface() {
-        return SimpleCommandDriver.class;
+    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(SimpleCommandDriver.Result result) {
+    protected void handle(SimpleCommand.Result result) {
         LOG.debug("Result is {}\nwith output [\n{}\n] and error [\n{}\n]", new Object[] {
                 result.getExitCode(), shorten(result.getStdout()), shorten(result.getStderr())
         });
@@ -79,99 +99,155 @@ public class SimpleCommandImpl extends AbstractEntity
 
 
     @Override
-    public void init() {
-        super.init();
-        getLifecycleEffectorTasks().attachLifecycleEffectors(this);
-    }
-
-
-    protected void initDriver(MachineLocation machine) {
-        LOG.debug("Initializing simple command driver");
-        SimpleCommandDriver newDriver = doInitDriver(machine);
-        if (newDriver == null) {
-            throw new UnsupportedOperationException("cannot start "+this+" on "+machine+": no driver available");
-        }
-        driver = newDriver;
+    public void start(@EffectorParam(name = "locations") Collection<? extends Location> locations) {
+        addLocations(locations);
+        setExpectedState(this, STARTING);
     }
 
-    protected SimpleCommandDriver doInitDriver(MachineLocation machine) {
-        if (driver!=null) {
-            if (machine.equals(driver.getLocation())) {
-                return driver; //just reuse
-            } else {
-                LOG.warn("driver/location change is untested for {} at {}; changing driver and continuing", this, machine);
-                return newDriver(machine);
-            }
-        } else {
-            return newDriver(machine);
-        }
+    @Override
+    public void stop() {
+        LOG.debug("Stopping simple command");
+        setUpAndRunState(false, STOPPED);
     }
 
-    protected SimpleCommandDriver newDriver(MachineLocation machine) {
-        LOG.debug("Creating new simple command driver for {} from management context", machine);
-        EntityDriverManager entityDriverManager = getManagementContext().getEntityDriverManager();
-        return entityDriverManager.build(this, machine);
+    @Override
+    public void restart() {
+        LOG.debug("Restarting simple command");
+        setUpAndRunState(true, RUNNING);
     }
 
-    @Override
-    public void start(@EffectorParam(name = "locations") Collection<? extends Location> locations) {
-        this.locations = locations;
-        startOnLocations();
+    private void setUpAndRunState(boolean up, Lifecycle status) {
+        sensors().set(SERVICE_UP, up);
+        setExpectedState(this, status);
     }
 
-    protected void startOnLocations() {
-        setExpectedState(this, STARTING);
-        int size = locations.size();
-        LOG.debug("Starting simple command at {} locations{}", size,
-                size > 0 ? " beginning " + locations.iterator().next() : "");
+    public void execute(MachineLocation machineLocation) {
         try {
-            execute(locations);
+            executeCommand(machineLocation);
             setUpAndRunState(true, RUNNING);
-
-        } catch (final Exception e) {
+        } catch (Exception e) {
             setUpAndRunState(false, ON_FIRE);
             throw Exceptions.propagate(e);
         }
     }
 
-    private void execute(Collection<? extends Location> locations) {
-        SimpleCommandDriver.Result result = null;
+    private void executeCommand(MachineLocation machineLocation) {
+
+        SimpleCommand.Result result = null;
         String downloadUrl = getConfig(DOWNLOAD_URL);
+        String command = getConfig(DEFAULT_COMMAND);
+
+        String downloadName = DOWNLOAD_URL.getName();
+        String commandName = DEFAULT_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);
-            result = getDriver().executeDownloadedScript(locations, downloadUrl, scriptDir);
-
-        } else {
-            String command = getConfig(DEFAULT_COMMAND);
-            if (Strings.isBlank(command)) {
-                throw new IllegalArgumentException("No default command and no downloadUrl provided");
-            }
+            String destPath = calculateDestPath(downloadUrl, scriptDir);
+            result = executeDownloadedScript(machineLocation, downloadUrl, destPath);
+        }
 
-            result = getDriver().execute(locations, command);
+        if (Strings.isNonBlank(command)) {
+            result = executeShellCommand(machineLocation, command);
         }
+
         handle(result);
     }
 
+    private IllegalArgumentException illegal(String ...messages) {
+        return new IllegalArgumentException(Joiner.on(' ').join(this.toString() + ":", messages));
+    }
 
-    @Override
-    public void stop() {
-        LOG.debug("Stopping simple command");
-        setUpAndRunState(false, STOPPED);
+    private SimpleCommand.Result executeDownloadedScript(MachineLocation machineLocation, String downloadUrl, String destPath) {
+
+        SshMachineLocation machine = getSshMachine(ImmutableList.<Location>of(machineLocation));
+
+        TaskFactory<?> install = SshTasks.installFromUrl(ImmutableMap.<String, Object>of(), machine, downloadUrl, destPath);
+        DynamicTasks.queue(install);
+        DynamicTasks.waitForLast();
+
+        machine.execCommands("make the script executable", ImmutableList.<String>of("chmod u+x " + destPath));
+
+        return executeShellCommand(machineLocation, destPath);
     }
 
-    @Override
-    public void restart() {
-        LOG.debug("Restarting simple command");
-        setUpAndRunState(true, RUNNING);
+
+    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 {}", command, machine);
+        ProcessTaskWrapper<Integer> job = DynamicTasks.queue(etf);
+        DynamicTasks.waitForLast();
+        return buildResult(job);
     }
 
-    private void setUpAndRunState(boolean up, Lifecycle status) {
-        sensors().set(SERVICE_UP, up);
-        setExpectedState(this, status);
+
+    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();
+            }
+        };
     }
 
-    protected SimpleCommandLifecycleEffectorTasks getLifecycleEffectorTasks () {
-        return new SimpleCommandLifecycleEffectorTasks();
+    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/b30489ed/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
index d044212..ae318ed 100644
--- 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
@@ -32,38 +32,23 @@ import java.util.Collection;
 public class SimpleCommandLifecycleEffectorTasks extends MachineLifecycleEffectorTasks {
 
     private static final Logger LOG = LoggerFactory.getLogger(SimpleCommandLifecycleEffectorTasks.class);
-    private MachineLocation location;
 
     protected Location getLocation(@Nullable Collection<? extends Location> locations) {
         return super.getLocation(entity().filterLocations(locations));
     }
 
-    @Override
-    protected void preStartCustom(MachineLocation machine) {
-        location = machine;
-        super.preStartCustom(location);
-        LOG.debug("Performing lifecycle preStartCustom on simple command");
-        entity().initDriver(location);
-    }
-
-    @Override
-    protected void preRestartCustom() {
-        LOG.debug("Performing lifecycle preStartCustom on simple command");
-        Asserts.notNull(location, "Cannot restart with no location");
-        entity().initDriver(location);
-    }
 
     @Override
     protected String startProcessesAtMachine(Supplier<MachineLocation> machineS) {
         LOG.debug("Performing lifecycle startProcessesAtMachine on simple command");
-        entity().getDriver().start();
-        return "Started with driver " + entity().getDriver();
+        MachineLocation machineLocation = machineS.get();
+        entity().execute(machineLocation);
+        return "Started simple command on " + machineLocation;
     }
 
     @Override
     protected String stopProcessesAtMachine() {
-        LOG.debug("Performing lifecycle stopProcessesAtMachine on simple command");
-        entity().getDriver().stop();
+        LOG.debug("No action needed on simple command stopped");
         return "Stopped";
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b30489ed/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandSshDriver.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandSshDriver.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandSshDriver.java
deleted file mode 100644
index f386b1e..0000000
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleCommandSshDriver.java
+++ /dev/null
@@ -1,192 +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.entity.EntityLocal;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.mgmt.TaskAdaptable;
-import org.apache.brooklyn.api.mgmt.TaskFactory;
-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.ResourceUtils;
-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.ProcessTaskFactory;
-import org.apache.brooklyn.util.core.task.system.ProcessTaskWrapper;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.exceptions.FatalRuntimeException;
-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 com.google.common.base.Preconditions.checkNotNull;
-import static org.apache.brooklyn.util.text.Strings.isBlank;
-
-/**
- * Driver for {@link SimpleCommand}.
- */
-public class SimpleCommandSshDriver implements SimpleCommandDriver {
-
-    private static final Logger LOG = LoggerFactory.getLogger(SimpleCommandSshDriver.class);
-    public static final String DEFAULT_NAME = "download.sh";
-
-    protected final EntityLocal entity;
-    protected final ResourceUtils resource;
-    protected final Location location;
-
-    public SimpleCommandSshDriver(EntityLocal entity, SshMachineLocation location) {
-        LOG.debug("Constructing SSH driver for simple command for {} at {}", entity, location);
-        this.entity = checkNotNull(entity, "entity");
-        this.location = checkNotNull(location, "location");
-        this.resource = ResourceUtils.create(entity);
-    }
-
-    @Override
-    public EntityLocal getEntity() {
-        return entity;
-    }
-
-    @Override
-    public void start() {
-        LOG.debug("Performing start in SSH driver for simple command");
-        invoke();
-    }
-
-    private void invoke() {
-        SimpleCommand simpleCommand = (SimpleCommand) getEntity();
-        simpleCommand.start(ImmutableList.of(location));
-    }
-
-    @Override
-    public void restart() {
-        LOG.debug("Performing restart in SSH driver for simple command");
-        invoke();
-    }
-
-    @Override
-    public void stop() {
-        LOG.debug("Performing stop in SSH driver for simple command");
-    }
-
-    @Override
-    public Result execute(Collection<? extends Location> hostLocations, String command) {
-
-        SshMachineLocation machine = getSshMachine(hostLocations);
-        ProcessTaskFactory<Integer> taskFactory = SshTasks.newSshExecTaskFactory(machine, command);
-
-        LOG.debug("Creating task to execute '{}' on location {}", command, machine);
-        final ProcessTaskWrapper<Integer> job = DynamicTasks.queue(taskFactory);
-        DynamicTasks.waitForLast();
-        return buildResult(job);
-    }
-
-    private <T> Result buildResult(final ProcessTaskWrapper<Integer> job) {
-        return new Result() {
-
-            @Override
-            public int getExitCode() {
-                return job.get();
-            }
-
-            @Override
-            public String getStdout() {
-                return job.getStdout().trim();
-            }
-
-            @Override
-            public String getStderr() {
-                return job.getStderr().trim();
-            }
-        };
-    }
-
-    @Override
-    public Result executeDownloadedScript(Collection<? extends Location> hostLocations,
-                                          String url, String directory) {
-
-        SshMachineLocation machine = getSshMachine(hostLocations);
-        String destPath = calculateDestPath(url, directory);
-
-        TaskFactory<?> install = SshTasks.installFromUrl(ImmutableMap.<String, Object>of(), machine, url, destPath);
-        DynamicTasks.queue(install);
-        DynamicTasks.waitForLast();
-
-        machine.execCommands("make the script executable", ImmutableList.<String>of("chmod u+x " + destPath));
-
-        return execute(hostLocations, destPath);
-    }
-
-    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 Exceptions.propagate(new FatalRuntimeException("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;
-    }
-
-    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();
-    }
-
-    @Override
-    public Location getLocation() {
-        return location;
-    }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b30489ed/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
index 261afe7..cf85b37 100644
--- 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
@@ -53,7 +53,7 @@ public class SimpleCommandTestImpl extends SimpleCommandImpl implements SimpleCo
     }
 
     @Override
-    protected void handle(SimpleCommandDriver.Result result) {
+    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());


[09/20] incubator-brooklyn git commit: Rename DEFAULT_COMMAND to COMMAND.

Posted by he...@apache.org.
Rename DEFAULT_COMMAND to COMMAND.

https://github.com/apache/incubator-brooklyn/pull/1030#discussion_r44859961


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/f173ad31
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/f173ad31
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/f173ad31

Branch: refs/heads/master
Commit: f173ad31f2ec08ac3602d92d4c0a14cb71406f4b
Parents: f06fb74
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Tue Nov 17 12:31:58 2015 +0000
Committer: Geoff Macartney <ge...@cloudsoftcorp.com>
Committed: Tue Nov 17 12:31:58 2015 +0000

----------------------------------------------------------------------
 .../brooklyn/test/framework/SimpleCommand.java     |  9 +++++++--
 .../brooklyn/test/framework/SimpleCommandImpl.java | 10 ++--------
 .../SimpleCommandImplIntegrationTest.java          |  6 +++---
 .../SimpleCommandScriptIntegrationTest.java        | 17 ++---------------
 4 files changed, 14 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f173ad31/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
index 0a58fe2..3959b39 100644
--- 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
@@ -49,10 +49,15 @@ public interface SimpleCommand extends Entity, Startable {
 
     }
 
+    /**
+     * Supply the command to invoke directly. Cannot be used together with {@link #DOWNLOAD_URL}.
+     */
     @SetFromFlag(nullable = false)
-    ConfigKey<String> DEFAULT_COMMAND = ConfigKeys.newConfigKey(String.class, "defaultCommand",
-            "Command to invoke if no script is provided via a downloadUrl");
+    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;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f173ad31/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
index 8af801f..24f6903 100644
--- 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
@@ -25,16 +25,13 @@ 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.annotation.EffectorParam;
 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.ResourceUtils;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
-import org.apache.brooklyn.util.core.task.ssh.SshPutTaskWrapper;
 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;
@@ -66,12 +63,9 @@ public class SimpleCommandImpl extends AbstractEntity implements SimpleCommand {
     private static final String CD = "cd";
     private static final String SHELL_AND = "&&";
 
-    private ResourceUtils resourceUtils;
-
     @Override
     public void init() {
         super.init();
-        resourceUtils = ResourceUtils.create(this);
         getLifecycleEffectorTasks().attachLifecycleEffectors(this);
     }
 
@@ -137,10 +131,10 @@ public class SimpleCommandImpl extends AbstractEntity implements SimpleCommand {
 
         SimpleCommand.Result result = null;
         String downloadUrl = getConfig(DOWNLOAD_URL);
-        String command = getConfig(DEFAULT_COMMAND);
+        String command = getConfig(COMMAND);
 
         String downloadName = DOWNLOAD_URL.getName();
-        String commandName = DEFAULT_COMMAND.getName();
+        String commandName = COMMAND.getName();
 
         if (isNonBlank(downloadUrl) && isNonBlank(command)) {
             throw illegal("Cannot specify both", downloadName, "and", commandName);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f173ad31/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplIntegrationTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplIntegrationTest.java b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplIntegrationTest.java
index 9d261b8..dea50e9 100644
--- a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplIntegrationTest.java
+++ b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplIntegrationTest.java
@@ -38,7 +38,7 @@ import org.testng.annotations.Test;
 import java.util.UUID;
 
 import static org.apache.brooklyn.test.framework.BaseTest.TARGET_ENTITY;
-import static org.apache.brooklyn.test.framework.SimpleCommand.DEFAULT_COMMAND;
+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;
 
@@ -76,7 +76,7 @@ public class SimpleCommandImplIntegrationTest {
 
         SimpleCommandTest uptime = app.createAndManageChild(EntitySpec.create(SimpleCommandTest.class)
             .configure(TARGET_ENTITY, testEntity)
-            .configure(DEFAULT_COMMAND, "uptime")
+            .configure(COMMAND, "uptime")
             .configure(ASSERT_STATUS, ImmutableMap.of(EQUALS, 0))
             .configure(ASSERT_OUT, ImmutableMap.of(CONTAINS, UP)));
 
@@ -95,7 +95,7 @@ public class SimpleCommandImplIntegrationTest {
 
         SimpleCommandTest uptime = app.createAndManageChild(EntitySpec.create(SimpleCommandTest.class)
             .configure(TARGET_ENTITY, testEntity)
-            .configure(DEFAULT_COMMAND, "uptime")
+            .configure(COMMAND, "uptime")
             .configure(ASSERT_STATUS, ImmutableMap.of(EQUALS, 1)));
 
         try {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f173ad31/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java
index cb6c9ed..3b6b875 100644
--- a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java
+++ b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java
@@ -18,16 +18,11 @@
  */
 package org.apache.brooklyn.test.framework;
 
-import com.google.common.base.Joiner;
-import com.google.common.base.Splitter;
-import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
-import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
@@ -36,27 +31,19 @@ import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
 import org.apache.brooklyn.test.http.TestHttpRequestHandler;
 import org.apache.brooklyn.test.http.TestHttpServer;
-import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.core.task.system.internal.SystemProcessTaskFactory;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.exceptions.FatalRuntimeException;
 import org.apache.brooklyn.util.http.HttpAsserts;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.annotations.*;
 
-import java.net.MalformedURLException;
-import java.net.URL;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.nio.file.attribute.FileAttribute;
-import java.util.Iterator;
 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.DEFAULT_COMMAND;
+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;
 
@@ -146,7 +133,7 @@ public class SimpleCommandScriptIntegrationTest {
         String remoteTmp = randomName();
         SimpleCommandTest uptime = app.createAndManageChild(EntitySpec.create(SimpleCommandTest.class)
             .configure(TARGET_ENTITY, testEntity)
-            .configure(DEFAULT_COMMAND, "mkdir " + remoteTmp)
+            .configure(COMMAND, "mkdir " + remoteTmp)
             .configure(ASSERT_STATUS, ImmutableMap.of(EQUALS, 0)));
 
         Path localTmpPath = Paths.get("/tmp/").resolve(randomName());


[07/20] incubator-brooklyn git commit: Add 'this' to loggers for context.

Posted by he...@apache.org.
Add 'this' to loggers for context.

https://github.com/apache/incubator-brooklyn/pull/1030#discussion_r44859887


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/f6801227
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/f6801227
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/f6801227

Branch: refs/heads/master
Commit: f6801227a90ebe0710a4f98509e61036606a2e81
Parents: cff1961
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Tue Nov 17 12:23:46 2015 +0000
Committer: Geoff Macartney <ge...@cloudsoftcorp.com>
Committed: Tue Nov 17 12:23:46 2015 +0000

----------------------------------------------------------------------
 .../apache/brooklyn/test/framework/SimpleCommandImpl.java | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f6801227/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
index b339e4d..39193ac 100644
--- 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
@@ -83,8 +83,8 @@ public class SimpleCommandImpl extends AbstractEntity implements SimpleCommand {
      * 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[] {
-                result.getExitCode(), shorten(result.getStdout()), shorten(result.getStderr())
+        LOG.debug("{}, Result is {}\nwith output [\n{}\n] and error [\n{}\n]", new Object[] {
+                this, result.getExitCode(), shorten(result.getStdout()), shorten(result.getStderr())
         });
     }
 
@@ -108,13 +108,13 @@ public class SimpleCommandImpl extends AbstractEntity implements SimpleCommand {
 
     @Override
     public void stop() {
-        LOG.debug("Stopping simple command");
+        LOG.debug("{} Stopping simple command", this);
         setUpAndRunState(false, STOPPED);
     }
 
     @Override
     public void restart() {
-        LOG.debug("Restarting simple command");
+        LOG.debug("{} Restarting simple command", this);
         setUpAndRunState(true, RUNNING);
     }
 
@@ -189,7 +189,7 @@ public class SimpleCommandImpl extends AbstractEntity implements SimpleCommand {
         SshMachineLocation machine = getSshMachine(ImmutableList.of(machineLocation));
         SshEffectorTasks.SshEffectorTaskFactory<Integer> etf = SshEffectorTasks.ssh(machine, command);
 
-        LOG.debug("Creating task to execute '{}' on location {}", command, machine);
+        LOG.debug("{} Creating task to execute '{}' on location {}", new Object[] {this, command, machine});
         ProcessTaskWrapper<Integer> job = DynamicTasks.queue(etf);
         DynamicTasks.waitForLast();
         return buildResult(job);


[10/20] incubator-brooklyn git commit: Format change.

Posted by he...@apache.org.
Format change.

https://github.com/apache/incubator-brooklyn/pull/1030#discussion_r44859977


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/4467878d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/4467878d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/4467878d

Branch: refs/heads/master
Commit: 4467878da3e5f5738c469fe67da2ce544f0082da
Parents: f173ad3
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Tue Nov 17 12:34:22 2015 +0000
Committer: Geoff Macartney <ge...@cloudsoftcorp.com>
Committed: Tue Nov 17 12:34:22 2015 +0000

----------------------------------------------------------------------
 .../java/org/apache/brooklyn/test/framework/SimpleCommandImpl.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4467878d/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
index 24f6903..7731801 100644
--- 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
@@ -69,7 +69,7 @@ public class SimpleCommandImpl extends AbstractEntity implements SimpleCommand {
         getLifecycleEffectorTasks().attachLifecycleEffectors(this);
     }
 
-    protected SimpleCommandLifecycleEffectorTasks getLifecycleEffectorTasks () {
+    protected SimpleCommandLifecycleEffectorTasks getLifecycleEffectorTasks() {
         return new SimpleCommandLifecycleEffectorTasks();
     }
 


[18/20] incubator-brooklyn git commit: Merge branch 'master' into simplecommand

Posted by he...@apache.org.
Merge branch 'master' into simplecommand


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/a0461971
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/a0461971
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/a0461971

Branch: refs/heads/master
Commit: a0461971c3330958cf27fbc149f2a4b02a9fb326
Parents: 4a37d07 cf4d77b
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Mon Nov 23 17:12:22 2015 +0000
Committer: Geoff Macartney <ge...@cloudsoftcorp.com>
Committed: Mon Nov 23 17:12:22 2015 +0000

----------------------------------------------------------------------
 .../org/apache/brooklyn/core/internal/BrooklynProperties.java     | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
----------------------------------------------------------------------



[03/20] incubator-brooklyn git commit: Make SimpleCommand tests be Integration tests as they use SSH.

Posted by he...@apache.org.
Make SimpleCommand tests be Integration tests as they use SSH.


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/014b6bf1
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/014b6bf1
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/014b6bf1

Branch: refs/heads/master
Commit: 014b6bf162c2ca5df7cedf55c63232eed8028e22
Parents: 6cd62e7
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Fri Nov 13 15:44:46 2015 +0000
Committer: Geoff Macartney <ge...@cloudsoftcorp.com>
Committed: Fri Nov 13 15:44:46 2015 +0000

----------------------------------------------------------------------
 .../SimpleCommandImplIntegrationTest.java       | 112 ++++++++++++++++++
 .../test/framework/SimpleCommandImplTest.java   | 118 -------------------
 .../SimpleCommandScriptIntegrationTest.java     |   3 +-
 3 files changed, 113 insertions(+), 120 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/014b6bf1/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplIntegrationTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplIntegrationTest.java b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplIntegrationTest.java
new file mode 100644
index 0000000..9d261b8
--- /dev/null
+++ b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplIntegrationTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.api.mgmt.ManagementContext;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.util.UUID;
+
+import static org.apache.brooklyn.test.framework.BaseTest.TARGET_ENTITY;
+import static org.apache.brooklyn.test.framework.SimpleCommand.DEFAULT_COMMAND;
+import static org.apache.brooklyn.test.framework.SimpleCommandTest.*;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class SimpleCommandImplIntegrationTest {
+    private static final Logger LOG = LoggerFactory.getLogger(SimpleCommandImplIntegrationTest.class);
+
+    private static final String UP = "up";
+    private TestApplication app;
+    private ManagementContext managementContext;
+    private LocalhostMachineProvisioningLocation localhost;
+    private String testId;
+
+
+    @BeforeMethod
+    public void setUp() {
+
+        testId = UUID.randomUUID().toString();
+
+        app = TestApplication.Factory.newManagedInstanceForTests();
+        managementContext = app.getManagementContext();
+
+        localhost = managementContext.getLocationManager()
+            .createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class)
+                .configure("name", testId));
+    }
+
+    @AfterMethod(alwaysRun = true)
+    public void tearDown() throws Exception {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+
+    @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(DEFAULT_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(DEFAULT_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");
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/014b6bf1/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplTest.java b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplTest.java
deleted file mode 100644
index 3450952..0000000
--- a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandImplTest.java
+++ /dev/null
@@ -1,118 +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.Predicate;
-import com.google.common.base.Strings;
-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.api.mgmt.ManagementContext;
-import org.apache.brooklyn.api.mgmt.Task;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
-import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
-import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
-import org.apache.brooklyn.util.core.task.Tasks;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import javax.annotation.Nullable;
-import java.util.UUID;
-
-import static org.apache.brooklyn.test.framework.BaseTest.TARGET_ENTITY;
-import static org.apache.brooklyn.test.framework.SimpleCommand.DEFAULT_COMMAND;
-import static org.apache.brooklyn.test.framework.SimpleCommandTest.*;
-import static org.assertj.core.api.Assertions.assertThat;
-
-// TODO investigate proper status of this test that requires SSH access to localhost
-public class SimpleCommandImplTest {
-    private static final Logger LOG = LoggerFactory.getLogger(SimpleCommandImplTest.class);
-
-    private static final String UP = "up";
-    private TestApplication app;
-    private ManagementContext managementContext;
-    private LocalhostMachineProvisioningLocation localhost;
-    private String testId;
-
-
-    @BeforeMethod
-    public void setUp() {
-
-        testId = UUID.randomUUID().toString();
-
-        app = TestApplication.Factory.newManagedInstanceForTests();
-        managementContext = app.getManagementContext();
-
-        localhost = managementContext.getLocationManager()
-            .createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class)
-                .configure("name", testId));
-    }
-
-    @AfterMethod(alwaysRun = true)
-    public void tearDown() throws Exception {
-        if (app != null) Entities.destroyAll(app.getManagementContext());
-    }
-
-    @Test(enabled = false)
-    public void shouldInvokeCommand() {
-        TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-
-        SimpleCommandTest uptime = app.createAndManageChild(EntitySpec.create(SimpleCommandTest.class)
-            .configure(TARGET_ENTITY, testEntity)
-            .configure(DEFAULT_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(enabled = false)
-    public void shouldNotBeUpIfAssertionFails() {
-        TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-
-        SimpleCommandTest uptime = app.createAndManageChild(EntitySpec.create(SimpleCommandTest.class)
-            .configure(TARGET_ENTITY, testEntity)
-            .configure(DEFAULT_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");
-
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/014b6bf1/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java
index ef773d7..b65a3e3 100644
--- a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java
+++ b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java
@@ -54,7 +54,6 @@ import static org.apache.brooklyn.test.framework.SimpleCommand.DEFAULT_COMMAND;
 import static org.apache.brooklyn.test.framework.SimpleCommandTest.*;
 import static org.assertj.core.api.Assertions.assertThat;
 
-@Test(groups = "Integration")  // TODO investigate proper status of this test that requires SSH access to localhost
 public class SimpleCommandScriptIntegrationTest {
     private static final Logger LOG = LoggerFactory.getLogger(SimpleCommandScriptIntegrationTest.class);
 
@@ -110,7 +109,7 @@ public class SimpleCommandScriptIntegrationTest {
 
 
 
-    @Test(enabled = false)
+    @Test(groups = "Integration")
     public void shouldInvokeScript() {
         TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
 


[17/20] incubator-brooklyn git commit: Merge branch 'master' into simplecommand

Posted by he...@apache.org.
Merge branch 'master' into simplecommand


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/4a37d079
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/4a37d079
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/4a37d079

Branch: refs/heads/master
Commit: 4a37d07927a292ea6317035c9e450b57bfb6a72a
Parents: ad75606 15faad3
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Mon Nov 23 11:55:15 2015 +0000
Committer: Geoff Macartney <ge...@cloudsoftcorp.com>
Committed: Mon Nov 23 11:55:15 2015 +0000

----------------------------------------------------------------------
 .../brooklyn/api/catalog/CatalogItem.java       |   28 +-
 .../apache/brooklyn/api/entity/EntitySpec.java  |   93 --
 .../internal/AbstractBrooklynObjectSpec.java    |  100 +-
 .../brooklyn/api/location/LocationSpec.java     |   78 +-
 .../BrooklynClassLoadingContext.java            |   50 +
 .../api/mgmt/rebind/RebindExceptionHandler.java |    4 +
 .../apache/brooklyn/api/policy/PolicySpec.java  |   75 -
 .../brooklyn/api/sensor/EnricherSpec.java       |   75 +-
 .../api/typereg/BrooklynTypeRegistry.java       |   32 +-
 .../brooklyn/api/typereg/RegisteredType.java    |   45 +-
 .../api/typereg/RegisteredTypeConstraint.java   |   45 -
 .../typereg/RegisteredTypeLoadingContext.java   |   50 +
 camp/camp-server/pom.xml                        |    6 -
 .../server/dto/ApplicationComponentDto.java     |    4 -
 .../dto/ApplicationComponentTemplateDto.java    |    4 -
 .../brooklyn/camp/server/dto/AssemblyDto.java   |    4 -
 .../camp/server/dto/AssemblyTemplateDto.java    |    4 -
 .../camp/server/dto/PlatformComponentDto.java   |    4 -
 .../dto/PlatformComponentTemplateDto.java       |    4 -
 .../brooklyn/camp/server/dto/PlatformDto.java   |    4 -
 .../camp/server/rest/CampRestResources.java     |   10 +-
 .../rest/resource/ApidocRestResource.java       |    6 +-
 .../ApplicationComponentRestResource.java       |   10 +-
 ...pplicationComponentTemplateRestResource.java |   10 +-
 .../rest/resource/AssemblyRestResource.java     |   10 +-
 .../resource/AssemblyTemplateRestResource.java  |   10 +-
 .../resource/PlatformComponentRestResource.java |   10 +-
 .../PlatformComponentTemplateRestResource.java  |   10 +-
 .../rest/resource/PlatformRestResource.java     |    8 +-
 .../catalog/internal/BasicBrooklynCatalog.java  |   73 +-
 .../catalog/internal/CatalogClasspathDo.java    |    8 -
 .../catalog/internal/CatalogItemBuilder.java    |   54 +-
 .../core/catalog/internal/CatalogItemDo.java    |    5 -
 .../internal/CatalogItemDtoAbstract.java        |   24 +-
 .../core/catalog/internal/CatalogUtils.java     |   33 +-
 .../vault/VaultExternalConfigSupplier.java      |   22 +-
 .../org/apache/brooklyn/core/feed/Poller.java   |    9 +-
 .../core/location/CatalogLocationResolver.java  |    3 +-
 .../core/mgmt/EntityManagementUtils.java        |   17 +-
 .../AbstractBrooklynClassLoadingContext.java    |    5 +-
 .../BrooklynClassLoadingContext.java            |   30 +-
 .../BrooklynClassLoadingContextSequential.java  |    1 +
 ...ssLoaderFromBrooklynClassLoadingContext.java |    2 +
 .../mgmt/ha/HighAvailabilityManagerImpl.java    |    2 +-
 .../internal/AbstractManagementContext.java     |    2 +-
 .../mgmt/internal/EntityManagementSupport.java  |   10 +-
 .../core/mgmt/persist/XmlMementoSerializer.java |    2 +-
 .../mgmt/rebind/BasicEntityRebindSupport.java   |    9 +-
 .../mgmt/rebind/RebindExceptionHandlerImpl.java |   27 +
 .../core/mgmt/rebind/RebindIteration.java       |    2 +-
 .../core/mgmt/rebind/RebindManagerImpl.java     |    8 +
 .../brooklyn/core/objs/BasicSpecParameter.java  |    2 +-
 .../core/plan/PlanNotRecognizedException.java   |    5 +
 .../brooklyn/core/plan/PlanToSpecFactory.java   |   40 +-
 .../core/plan/PlanToSpecTransformer.java        |    3 +-
 .../entity/AbstractEntitySpecResolver.java      |    2 +-
 .../entity/CatalogEntitySpecResolver.java       |    6 +-
 .../entity/DelegatingEntitySpecResolver.java    |    4 +-
 .../core/resolve/entity/EntitySpecResolver.java |    2 +-
 .../resolve/entity/JavaEntitySpecResolver.java  |    2 +-
 ...actFormatSpecificTypeImplementationPlan.java |   52 +
 .../typereg/AbstractTypePlanTransformer.java    |  142 ++
 .../core/typereg/BasicBrooklynTypeRegistry.java |  126 +-
 .../core/typereg/BasicRegisteredType.java       |  135 ++
 .../typereg/BasicTypeImplementationPlan.java    |   41 +
 .../typereg/BrooklynTypePlanTransformer.java    |   88 ++
 .../JavaClassNameTypePlanTransformer.java       |   91 ++
 .../core/typereg/RegisteredTypeConstraints.java |  156 --
 .../core/typereg/RegisteredTypeKindVisitor.java |   45 +
 .../typereg/RegisteredTypeLoadingContexts.java  |  236 +++
 .../core/typereg/RegisteredTypePredicates.java  |   28 +-
 .../brooklyn/core/typereg/RegisteredTypes.java  |  389 +++--
 .../core/typereg/TypePlanTransformers.java      |  165 ++
 .../typereg/UnsupportedTypePlanException.java   |   37 +
 .../location/ssh/SshMachineLocation.java        |   43 +-
 .../brooklyn/util/core/ResourcePredicates.java  |   11 +
 .../brooklyn/util/core/ResourceUtils.java       |    6 +-
 .../brooklyn/util/core/http/HttpTool.java       |   63 +-
 .../util/core/http/HttpToolResponse.java        |   14 +-
 .../util/core/task/BasicExecutionManager.java   |   50 +-
 .../brooklyn/util/core/task/ScheduledTask.java  |   54 +-
 ...lyn.core.typereg.BrooklynTypePlanTransformer |   19 +
 .../policy/basic/AbstractEntityAdjunctTest.java |   52 -
 .../internal/SpecParameterInMetaTest.java       |  139 --
 .../internal/StaticTypePlanTransformer.java     |  124 ++
 .../internal/StaticTypePlanTransformerTest.java |   63 +
 .../catalog/internal/TestToSpecTransformer.java |  118 --
 .../apache/brooklyn/core/feed/PollerTest.java   |  191 ++-
 .../FileBasedStoreObjectAccessorWriterTest.java |   18 -
 .../core/objs/AbstractEntityAdjunctTest.java    |   52 +
 .../objs/BasicSpecParameterFromListTest.java    |    2 +-
 .../core/plan/XmlPlanToSpecTransformer.java     |    5 +-
 .../core/plan/XmlPlanToSpecTransformerTest.java |    2 +
 .../brooklyn/core/sensor/StaticSensorTest.java  |    8 +-
 .../core/test/BrooklynAppLiveTestSupport.java   |   26 +-
 .../core/test/BrooklynAppUnitTestSupport.java   |   38 +-
 .../core/test/BrooklynMgmtUnitTestSupport.java  |   61 +
 .../core/test/entity/TestEntityImpl.java        |    1 -
 .../qa/performance/AbstractPerformanceTest.java |   47 +-
 .../qa/performance/EntityPerformanceTest.java   |   84 +-
 .../FilePersistencePerformanceTest.java         |  146 +-
 .../GroovyYardStickPerformanceTest.groovy       |    7 +-
 .../JavaYardStickPerformanceTest.java           |   35 +-
 .../SubscriptionPerformanceTest.java            |   58 +-
 .../qa/performance/TaskPerformanceTest.java     |   63 +-
 .../typereg/ExampleXmlTypePlanTransformer.java  |  140 ++
 .../ExampleXmlTypePlanTransformerTest.java      |   67 +
 .../JavaClassNameTypePlanTransformerTest.java   |   90 ++
 .../ssh/SshMachineLocationSshToolTest.java      |   47 +-
 .../location/ssh/SshMachineLocationTest.java    |    4 +-
 .../core/internal/ssh/RecordingSshTool.java     |    7 +
 .../util/core/task/ScheduledExecutionTest.java  |   48 +-
 ...che.brooklyn.core.plan.PlanToSpecTransformer |   19 -
 docs/guide/index.md                             |    1 +
 docs/guide/misc/release-notes.md                |   51 +-
 docs/guide/ops/catalog/index.md                 |   25 -
 docs/guide/ops/persistence/index.md             |    2 +
 docs/guide/start/concept-quickstart.md          |    5 +-
 docs/guide/start/index.md                       |    3 +-
 docs/guide/start/running.md                     |    2 +
 docs/guide/test/entities.md                     |  143 ++
 docs/guide/test/index.md                        |    8 +
 docs/guide/yaml/yaml-reference.md               |   35 +-
 docs/website/documentation/faq.md               |   28 +
 docs/website/index.md                           |    2 +-
 .../demo/WebClusterDatabaseExampleApp.java      |   18 +-
 .../features/src/main/history/dependencies.xml  |    6 +-
 .../location/jclouds/BrooklynImageChooser.java  |    2 +-
 .../location/jclouds/JcloudsLocation.java       |  226 +--
 .../brooklyn/location/jclouds/JcloudsUtil.java  |   50 +-
 .../BlobStorePersistencePerformanceTest.java    |   39 +-
 .../jclouds/AbstractJcloudsLiveTest.java        |    4 +
 .../location/jclouds/JcloudsLoginLiveTest.java  |  126 +-
 parent/pom.xml                                  |   34 +-
 pom.xml                                         |    6 +-
 .../entity/resolve/ChefEntitySpecResolver.java  |    2 +-
 .../HardcodedCatalogEntitySpecResolver.java     |    2 +-
 .../base/AbstractSoftwareProcessDriver.java     |    2 +-
 .../brooklyn/entity/java/JavaOptsTest.java      |    4 +-
 .../entity/software/base/EntitySshToolTest.java |    8 +-
 .../nosql/couchbase/CouchbaseNodeImpl.java      |    3 +-
 .../nosql/elasticsearch/ElasticSearchNode.java  |   29 +-
 .../nosql/mongodb/AbstractMongoDBServer.java    |   14 +-
 .../brooklyn/entity/nosql/redis/RedisStore.java |   10 +-
 .../entity/nosql/redis/RedisStoreImpl.java      |    2 +-
 .../entity/webapp/jboss/JBoss7Server.java       |   14 +-
 .../entity/webapp/tomcat/TomcatServer.java      |   19 +-
 .../api/AssemblyTemplateSpecInstantiator.java   |    7 +-
 .../BrooklynAssemblyTemplateInstantiator.java   |   13 +-
 .../BrooklynComponentTemplateResolver.java      |    2 +-
 .../BrooklynEntityDecorationResolver.java       |    5 +-
 .../spi/creation/BrooklynEntityMatcher.java     |    2 +-
 .../creation/BrooklynYamlTypeInstantiator.java  |    2 +-
 .../brooklyn/spi/creation/CampCatalogUtils.java |   54 +-
 .../spi/creation/CampInternalUtils.java         |  247 +++
 .../brooklyn/spi/creation/CampResolver.java     |  147 ++
 .../spi/creation/CampToSpecTransformer.java     |   17 +-
 .../spi/creation/CampTypePlanTransformer.java   |   98 ++
 .../camp/brooklyn/spi/creation/CampUtils.java   |  267 ----
 .../service/ServiceTypeResolverAdaptor.java     |    2 +-
 .../service/UrlServiceSpecResolver.java         |   20 +-
 ...lyn.core.typereg.BrooklynTypePlanTransformer |   19 +
 .../camp/brooklyn/AbstractYamlTest.java         |   39 +-
 .../BrooklynYamlTypeInstantiatorTest.java       |    2 +-
 .../camp/brooklyn/DslAndRebindYamlTest.java     |    3 +-
 .../camp/brooklyn/EntitiesYamlTest.java         |    2 +
 .../camp/brooklyn/LocationsYamlTest.java        |    4 +-
 .../camp/brooklyn/ReferencedYamlTest.java       |    1 +
 .../CatalogOsgiVersionMoreEntityTest.java       |   18 +-
 .../brooklyn/catalog/CatalogParametersTest.java |  317 ----
 .../catalog/CatalogYamlLocationTest.java        |    3 +-
 .../catalog/SpecParameterParsingTest.java       |  156 ++
 .../catalog/SpecParameterUnwrappingTest.java    |  379 +++++
 .../brooklyn/test/lite/CampYamlLiteTest.java    |    6 +-
 .../test/lite/TestAppAssemblyInstantiator.java  |   10 +-
 usage/dist/licensing/overrides.yaml             |   96 +-
 usage/dist/src/main/license/files/LICENSE       |   92 +-
 usage/jsgui/pom.xml                             |    9 +-
 usage/jsgui/src/main/license/files/LICENSE      |   54 +-
 .../src/main/license/source-inclusions.yaml     |    1 +
 .../src/main/webapp/assets/html/swagger-ui.html |   78 +
 .../main/webapp/assets/js/libs/swagger-ui.js    | 1410 ------------------
 .../src/main/webapp/assets/js/libs/swagger.js   |  708 ---------
 usage/jsgui/src/main/webapp/assets/js/router.js |   16 +-
 .../src/main/webapp/assets/js/view/apidoc.js    |   82 -
 .../assets/js/view/application-add-wizard.js    |   11 +-
 .../webapp/assets/js/view/entity-details.js     |    2 +-
 .../main/webapp/assets/swagger-ui/css/print.css | 1195 +++++++++++++++
 .../main/webapp/assets/swagger-ui/css/reset.css |  144 ++
 .../webapp/assets/swagger-ui/css/screen.css     | 1301 ++++++++++++++++
 .../main/webapp/assets/swagger-ui/css/style.css |  269 ++++
 .../webapp/assets/swagger-ui/css/typography.css |   45 +
 .../fonts/droid-sans-v6-latin-700.eot           |  Bin 0 -> 22922 bytes
 .../fonts/droid-sans-v6-latin-700.svg           |  411 +++++
 .../fonts/droid-sans-v6-latin-700.ttf           |  Bin 0 -> 40513 bytes
 .../fonts/droid-sans-v6-latin-700.woff          |  Bin 0 -> 25992 bytes
 .../fonts/droid-sans-v6-latin-700.woff2         |  Bin 0 -> 11480 bytes
 .../fonts/droid-sans-v6-latin-regular.eot       |  Bin 0 -> 22008 bytes
 .../fonts/droid-sans-v6-latin-regular.svg       |  403 +++++
 .../fonts/droid-sans-v6-latin-regular.ttf       |  Bin 0 -> 39069 bytes
 .../fonts/droid-sans-v6-latin-regular.woff      |  Bin 0 -> 24868 bytes
 .../fonts/droid-sans-v6-latin-regular.woff2     |  Bin 0 -> 11304 bytes
 .../assets/swagger-ui/images/explorer_icons.png |  Bin 0 -> 5763 bytes
 .../assets/swagger-ui/images/pet_store_api.png  |  Bin 0 -> 824 bytes
 .../assets/swagger-ui/images/throbber.gif       |  Bin 0 -> 9257 bytes
 .../assets/swagger-ui/images/wordnik_api.png    |  Bin 0 -> 980 bytes
 .../assets/swagger-ui/lib/backbone-min.js       |   34 +
 .../assets/swagger-ui/lib/handlebars-2.0.0.js   |   20 +
 .../assets/swagger-ui/lib/jquery-1.8.0.min.js   |   21 +
 .../assets/swagger-ui/lib/jquery.ba-bbq.min.js  |   29 +
 .../assets/swagger-ui/lib/jquery.wiggle.min.js  |   27 +
 .../main/webapp/assets/swagger-ui/lib/marked.js | 1285 ++++++++++++++++
 .../assets/swagger-ui/lib/swagger-ui.min.js     |   37 +
 .../assets/swagger-ui/lib/underscore-min.js     |   25 +
 .../assets/swagger-ui/lib/underscore-min.map    |    1 +
 usage/jsgui/src/main/webapp/index.html          |   32 +-
 .../jsgui/BrooklynJavascriptGuiLauncher.java    |    2 +-
 .../brooklyn/launcher/BrooklynWebServer.java    |    2 +
 usage/rest-api/pom.xml                          |    9 +-
 .../org/apache/brooklyn/rest/api/AccessApi.java |   10 +-
 .../apache/brooklyn/rest/api/ActivityApi.java   |   26 +-
 .../brooklyn/rest/api/ApplicationApi.java       |   68 +-
 .../apache/brooklyn/rest/api/CatalogApi.java    |  132 +-
 .../apache/brooklyn/rest/api/EffectorApi.java   |   24 +-
 .../org/apache/brooklyn/rest/api/EntityApi.java |   72 +-
 .../brooklyn/rest/api/EntityConfigApi.java      |   40 +-
 .../apache/brooklyn/rest/api/LocationApi.java   |   18 +-
 .../org/apache/brooklyn/rest/api/PolicyApi.java |   42 +-
 .../brooklyn/rest/api/PolicyConfigApi.java      |   34 +-
 .../org/apache/brooklyn/rest/api/ScriptApi.java |   10 +-
 .../org/apache/brooklyn/rest/api/SensorApi.java |   44 +-
 .../org/apache/brooklyn/rest/api/ServerApi.java |   31 +-
 .../org/apache/brooklyn/rest/api/UsageApi.java  |   34 +-
 .../apache/brooklyn/rest/api/VersionApi.java    |    9 +-
 usage/rest-api/src/main/webapp/WEB-INF/web.xml  |   10 +-
 usage/rest-client/pom.xml                       |   57 +-
 .../brooklyn/rest/client/BrooklynApi.java       |    5 +-
 usage/rest-server/pom.xml                       |    9 +-
 .../apache/brooklyn/rest/BrooklynRestApi.java   |    4 +-
 .../brooklyn/rest/filter/SwaggerFilter.java     |   76 +
 .../brooklyn/rest/resources/ApidocResource.java |   10 +-
 .../rest/resources/ApplicationResource.java     |   14 +-
 .../rest/resources/CatalogResource.java         |    5 +-
 .../rest/transform/CatalogTransformer.java      |    5 +-
 .../rest/util/BrooklynRestResourceUtils.java    |    2 +-
 .../rest-server/src/main/webapp/WEB-INF/web.xml |   13 +-
 .../brooklyn/rest/BrooklynRestApiLauncher.java  |    4 +-
 .../rest/resources/ApiDocResourceTest.java      |  138 --
 .../rest/resources/ApidocResourceTest.java      |  177 +++
 .../rest/testing/BrooklynRestApiTest.java       |   31 +-
 .../rest/util/NullServletConfigProvider.java    |    5 +
 usage/test-framework/README.md                  |  129 --
 .../brooklyn/test/framework/BaseTest.java       |    8 +-
 .../test/framework/ParallelTestCaseImpl.java    |   41 +-
 .../test/framework/TestFrameworkAssertions.java |  160 ++
 .../brooklyn/test/framework/TestHttpCall.java   |   16 +
 .../test/framework/TestHttpCallImpl.java        |   72 +-
 .../brooklyn/test/framework/TestSensorImpl.java |   73 +-
 .../framework/TestFrameworkAssertionsTest.java  |  135 ++
 .../test/framework/TestHttpCallTest.java        |  121 ++
 .../brooklyn/test/framework/TestSensorTest.java |   48 +-
 .../example-catalog-test.bom                    |    2 +-
 .../nginx-test-examples.yml                     |   21 +-
 .../testhttpcall-examples.yml                   |   27 +-
 .../tomcat-test-examples.yml                    |    8 +-
 .../brooklyn/test/PerformanceTestUtils.java     |   82 +-
 .../test/performance/FilePersister.java         |   85 ++
 .../brooklyn/test/performance/Histogram.java    |   89 ++
 .../performance/MeasurementResultPersister.java |   29 +
 .../test/performance/PerformanceMeasurer.java   |  156 ++
 .../performance/PerformanceTestDescriptor.java  |  208 +++
 .../test/performance/PerformanceTestResult.java |   62 +
 .../test/performance/PerformanceTestUtils.java  |  107 ++
 .../exceptions/PropagatedRuntimeException.java  |    6 +
 .../apache/brooklyn/util/net/Networking.java    |    7 +
 .../util/net/ReachableSocketFinder.java         |  154 ++
 .../apache/brooklyn/util/text/Identifiers.java  |   13 +-
 .../brooklyn/util/net/NetworkingUtilsTest.java  |    9 +-
 .../util/net/ReachableSocketFinderTest.java     |  165 ++
 .../brooklyn/util/text/IdentifiersTest.java     |   13 +
 utils/rest-swagger/pom.xml                      |   33 +-
 .../rest/apidoc/ApiListingResource.java         |  259 ++++
 .../org/apache/brooklyn/rest/apidoc/Apidoc.java |   33 -
 .../brooklyn/rest/apidoc/ApidocEndpoint.java    |   54 -
 .../apidoc/ApidocHelpMessageBodyWriter.java     |   28 -
 .../brooklyn/rest/apidoc/ApidocResource.java    |  291 ----
 .../apache/brooklyn/rest/apidoc/ApidocRoot.java |   47 -
 .../rest/apidoc/RestApiResourceScanner.java     |   81 +
 .../osgi/more-entities-v2-evil-twin/pom.xml     |    2 +-
 .../dependencies/osgi/more-entities-v2/pom.xml  |    4 +-
 .../brooklyn-test-osgi-more-entities_0.2.0.jar  |  Bin 15745 -> 15646 bytes
 ...-test-osgi-more-entities_evil-twin_0.2.0.jar |  Bin 13922 -> 13811 bytes
 292 files changed, 13212 insertions(+), 6403 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4a37d079/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/BaseTest.java
----------------------------------------------------------------------
diff --cc usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/BaseTest.java
index 4043bcc,f458018..19043e7
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/BaseTest.java
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/BaseTest.java
@@@ -18,9 -18,8 +18,9 @@@
   */
  package org.apache.brooklyn.test.framework;
  
- import com.google.common.collect.Maps;
+ import com.google.common.reflect.TypeToken;
  import org.apache.brooklyn.api.entity.Entity;
 +import org.apache.brooklyn.api.mgmt.ExecutionContext;
  import org.apache.brooklyn.config.ConfigKey;
  import org.apache.brooklyn.core.config.ConfigKeys;
  import org.apache.brooklyn.core.entity.trait.Startable;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4a37d079/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4a37d079/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java
----------------------------------------------------------------------


[08/20] incubator-brooklyn git commit: Remove unnecessary annotation.

Posted by he...@apache.org.
Remove unnecessary annotation.

https://github.com/apache/incubator-brooklyn/pull/1030#discussion_r44859924


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/f06fb74f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/f06fb74f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/f06fb74f

Branch: refs/heads/master
Commit: f06fb74fed0b92d97f037efe4b958212df6d3156
Parents: f680122
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Tue Nov 17 12:25:14 2015 +0000
Committer: Geoff Macartney <ge...@cloudsoftcorp.com>
Committed: Tue Nov 17 12:25:14 2015 +0000

----------------------------------------------------------------------
 .../java/org/apache/brooklyn/test/framework/SimpleCommandImpl.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f06fb74f/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
index 39193ac..8af801f 100644
--- 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
@@ -101,7 +101,7 @@ public class SimpleCommandImpl extends AbstractEntity implements SimpleCommand {
 
 
     @Override
-    public void start(@EffectorParam(name = "locations") Collection<? extends Location> locations) {
+    public void start(Collection<? extends Location> locations) {
         addLocations(locations);
         setExpectedState(this, STARTING);
     }


[14/20] incubator-brooklyn git commit: Additional tests and improvements.

Posted by he...@apache.org.
Additional tests and improvements.


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/60178809
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/60178809
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/60178809

Branch: refs/heads/master
Commit: 60178809b3c51a429e6871bb68404245baa86269
Parents: 89d6926
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Tue Nov 17 16:23:23 2015 +0000
Committer: Geoff Macartney <ge...@cloudsoftcorp.com>
Committed: Wed Nov 18 01:12:24 2015 +0000

----------------------------------------------------------------------
 .../test/framework/SimpleShellCommand.java      |   2 +-
 .../test/framework/SimpleShellCommandImpl.java  | 106 ++++++++-------
 .../framework/SimpleShellCommandTestImpl.java   |   3 +-
 .../SimpleShellCommandIntegrationTest.java      | 133 +++++++++++++------
 4 files changed, 152 insertions(+), 92 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/60178809/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
index 1f430a7..fc182ef 100644
--- 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
@@ -71,5 +71,5 @@ public interface SimpleShellCommand extends Entity, Startable {
      * 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);
+    ConfigKey<String> RUN_DIR = newConfigKey(String.class, "run.dir", "directory where downloaded scripts should be run from");
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/60178809/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
index 1ccce5e..c63e1fc 100644
--- 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
@@ -42,10 +42,7 @@ 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 java.util.*;
 
 import static org.apache.brooklyn.core.entity.lifecycle.Lifecycle.*;
 import static org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.setExpectedState;
@@ -61,7 +58,6 @@ public class SimpleShellCommandImpl extends AbstractEntity implements SimpleShel
     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() {
@@ -69,6 +65,25 @@ public class SimpleShellCommandImpl extends AbstractEntity implements SimpleShel
         getLifecycleEffectorTasks().attachLifecycleEffectors(this);
     }
 
+    @Override
+    public void start(Collection<? extends Location> locations) {
+        addLocations(filterLocations(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);
+    }
+
     protected SimpleShellCommandLifecycleEffectorTasks getLifecycleEffectorTasks() {
         return new SimpleShellCommandLifecycleEffectorTasks();
     }
@@ -78,7 +93,7 @@ public class SimpleShellCommandImpl extends AbstractEntity implements SimpleShel
      */
     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())
+            this, result.getExitCode(), shorten(result.getStdout()), shorten(result.getStderr())
         });
     }
 
@@ -93,25 +108,6 @@ public class SimpleShellCommandImpl extends AbstractEntity implements SimpleShel
         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);
@@ -136,31 +132,23 @@ public class SimpleShellCommandImpl extends AbstractEntity implements SimpleShel
         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 (!(isNonBlank(downloadUrl) ^ isNonBlank(command))) {
+            throw illegal("Must specify exactly one of", downloadName, "and", commandName);
         }
 
-        if (Strings.isNonBlank(downloadUrl)) {
+        if (isNonBlank(downloadUrl)) {
             String scriptDir = getConfig(SCRIPT_DIR);
             String scriptPath = calculateDestPath(downloadUrl, scriptDir);
             result = executeDownloadedScript(machineLocation, downloadUrl, scriptPath);
         }
 
-        if (Strings.isNonBlank(command)) {
+        if (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));
@@ -169,47 +157,67 @@ public class SimpleShellCommandImpl extends AbstractEntity implements SimpleShel
         DynamicTasks.queue(install);
         DynamicTasks.waitForLast();
 
-        machine.execCommands("make the script executable", ImmutableList.<String>of("chmod u+x " + scriptPath));
+        List<String> commands = new ArrayList<>();
+        commands.add("chmod u+x " + scriptPath);
+        maybeCdToRunDir(commands);
+        commands.add(scriptPath);
 
-        String runDir = getConfig(RUN_DIR);
-        String cdAndRun = Joiner.on(' ').join(CD, runDir, SHELL_AND, scriptPath);
-
-        return executeShellCommand(machineLocation, cdAndRun);
+        return runCommands(machine, commands);
     }
 
-
     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});
+        List<String> commands = new ArrayList<>();
+        maybeCdToRunDir(commands);
+        commands.add(command);
+
+        return runCommands(machine, commands);
+    }
+
+    private void maybeCdToRunDir(List<String> commands) {
+        String runDir = getConfig(RUN_DIR);
+        if (!isBlank(runDir)) {
+            commands.add(CD + " " + runDir);
+        }
+    }
+
+    private Result runCommands(SshMachineLocation machine, List<String> commands) {
+        SshEffectorTasks.SshEffectorTaskFactory<Integer> etf = SshEffectorTasks.ssh(machine, commands.toArray(new String[]{}));
+
         ProcessTaskWrapper<Integer> job = DynamicTasks.queue(etf);
         DynamicTasks.waitForLast();
         return buildResult(job);
     }
 
-
     private <T> SimpleShellCommand.Result buildResult(final ProcessTaskWrapper<Integer> job) {
+        final int exitCode = job.get();
+        final String stdout = job.getStdout().trim();
+        final String stderr = job.getStderr().trim();
         return new SimpleShellCommand.Result() {
 
             @Override
             public int getExitCode() {
-                return job.get();
+                return exitCode;
             }
 
             @Override
             public String getStdout() {
-                return job.getStdout().trim();
+                return stdout;
             }
 
             @Override
             public String getStderr() {
-                return job.getStderr().trim();
+                return stderr;
             }
         };
     }
 
+    private IllegalArgumentException illegal(String message, String ...messages) {
+        return new IllegalArgumentException(Joiner.on(' ').join(this.toString() + ":", message, messages));
+    }
+
     private SshMachineLocation getSshMachine(Collection<? extends Location> hostLocations) {
         Maybe<SshMachineLocation> host = Locations.findUniqueSshMachineLocation(hostLocations);
         if (host.isAbsent()) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/60178809/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
index 9c9a15a..6a35e73 100644
--- 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
@@ -47,7 +47,8 @@ public class SimpleShellCommandTestImpl extends SimpleShellCommandImpl implement
      */
     public Collection<? extends Location> filterLocations(Collection<? extends Location> locations) {
         Entity target = resolveTarget();
-        return target.getLocations();
+        Collection<Location> targetLocations = target.getLocations();
+        return targetLocations;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/60178809/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
index 7b6c732..7f8f078 100644
--- 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
@@ -27,16 +27,17 @@ 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.test.Asserts;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.testng.annotations.DataProvider;
 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;
@@ -44,7 +45,6 @@ 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;
@@ -55,6 +55,48 @@ public class SimpleShellCommandIntegrationTest extends BrooklynAppUnitTestSuppor
             .createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class));
     }
 
+    @DataProvider(name = "shouldInsistOnJustOneOfCommandAndScript")
+    public Object[][] createData1() {
+
+        return new Object[][] {
+            { "pwd", "pwd.sh", Boolean.FALSE },
+            { null, null, Boolean.FALSE },
+            { "pwd", null, Boolean.TRUE },
+            { null, "pwd.sh", Boolean.TRUE }
+        };
+    }
+
+    @Test(dataProvider = "shouldInsistOnJustOneOfCommandAndScript")
+    public void shouldInsistOnJustOneOfCommandAndScript(String command, String script, boolean valid) throws  Exception{
+        Path scriptPath = null;
+        String scriptUrl = null;
+        if (null != script) {
+            scriptPath = createTempScript("pwd", "pwd");
+            scriptUrl = "file:" + scriptPath;
+        }
+        TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+
+        app.createAndManageChild(EntitySpec.create(SimpleShellCommandTest.class)
+            .configure(TARGET_ENTITY, testEntity)
+            .configure(COMMAND, command)
+            .configure(DOWNLOAD_URL, scriptUrl));
+
+        try {
+            app.start(ImmutableList.of(localhost));
+            if (!valid) {
+                Asserts.shouldHaveFailedPreviously();
+            }
+
+        } catch (Exception e) {
+            Asserts.expectedFailureContains(e, "Must specify exactly one of download.url and command");
+
+        } finally {
+            if (null != scriptPath) {
+                Files.delete(scriptPath);
+            }
+        }
+    }
+
     @Test(groups = "Integration")
     public void shouldInvokeCommand() {
         TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
@@ -95,67 +137,76 @@ public class SimpleShellCommandIntegrationTest extends BrooklynAppUnitTestSuppor
     }
 
     @Test(groups = "Integration")
-    public void shouldInvokeScript() {
+    public void shouldInvokeScript() throws Exception {
         TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
 
         String text = "hello world";
-        String testUrl = createTempScript("script.sh", "echo " + text);
+        Path testScript = createTempScript("script", "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)));
+        try {
+            SimpleShellCommandTest uptime = app.createAndManageChild(EntitySpec.create(SimpleShellCommandTest.class)
+                .configure(TARGET_ENTITY, testEntity)
+                .configure(DOWNLOAD_URL, "file:" + testScript)
+                .configure(ASSERT_STATUS, ImmutableMap.of(EQUALS, 0))
+                .configure(ASSERT_OUT, ImmutableMap.of(CONTAINS, text)));
 
-        app.start(ImmutableList.of(localhost));
+            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");
+            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");
+
+        } finally {
+            Files.delete(testScript);
+        }
     }
 
     @Test
-    public void shouldExecuteInTheRightPlace() throws Exception {
+    public void shouldExecuteInTheRunDir() 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)));
+        Path pwdPath = createTempScript("pwd", "pwd");
 
-        String pwdUrl = createTempScript("pwd.sh", "pwd");
+        try {
+            SimpleShellCommandTest pwd = app.createAndManageChild(EntitySpec.create(SimpleShellCommandTest.class)
+                .configure(TARGET_ENTITY, testEntity)
+                .configure(DOWNLOAD_URL, "file:" + pwdPath)
+                .configure(RUN_DIR, "/tmp")
+                .configure(ASSERT_STATUS, ImmutableMap.of(EQUALS, 0))
+                .configure(ASSERT_OUT, ImmutableMap.of(CONTAINS, "/tmp")));
 
-        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));
+            SimpleShellCommandTest alsoPwd = app.createAndManageChild(EntitySpec.create(SimpleShellCommandTest.class)
+                .configure(TARGET_ENTITY, testEntity)
+                .configure(COMMAND, "pwd")
+                .configure(RUN_DIR, "/tmp")
+                .configure(ASSERT_STATUS, ImmutableMap.of(EQUALS, 0))
+                .configure(ASSERT_OUT, ImmutableMap.of(CONTAINS, "/tmp")));
 
-        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");
+            app.start(ImmutableList.of(localhost));
+
+            assertThat(pwd.sensors().get(SERVICE_UP)).isTrue().withFailMessage("Service should be up");
+            assertThat(ServiceStateLogic.getExpectedState(pwd)).isEqualTo(Lifecycle.RUNNING)
+                .withFailMessage("Service should be marked running");
+
+            assertThat(alsoPwd.sensors().get(SERVICE_UP)).isTrue().withFailMessage("Service should be up");
+            assertThat(ServiceStateLogic.getExpectedState(alsoPwd)).isEqualTo(Lifecycle.RUNNING)
+                .withFailMessage("Service should be marked running");
+
+        } finally {
+            Files.delete(pwdPath);
+        }
     }
 
-    private String createTempScript(String filename, String contents) {
+    private Path createTempScript(String filename, String contents) {
         try {
-            Path tempDirectory = Files.createTempDirectory(randomName());
-            tempDirectory.toFile().deleteOnExit();
-            Path tempFile = Files.createFile(tempDirectory.resolve(filename));
+            Path tempFile = Files.createTempFile("SimpleShellCommandIntegrationTest-" + filename, ".sh");
             Files.write(tempFile, contents.getBytes());
-            return "file:" + tempFile.toString();
+            return tempFile;
         } catch (IOException e) {
             throw Exceptions.propagate(e);
         }
     }
 
-    private String randomName() {
-        return Integer.valueOf(new Random(System.currentTimeMillis()).nextInt(100000)).toString();
-    }
-
 }


[20/20] incubator-brooklyn git commit: This closes #1030

Posted by he...@apache.org.
This closes #1030


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/bbacc2b9
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/bbacc2b9
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/bbacc2b9

Branch: refs/heads/master
Commit: bbacc2b945a0a20e975bfc2b2f66254c1090a654
Parents: faf08c1 22f3430
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Nov 23 18:29:16 2015 +0000
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Mon Nov 23 18:29:16 2015 +0000

----------------------------------------------------------------------
 .../brooklyn/util/core/task/ssh/SshTasks.java   |   5 +
 usage/test-framework/pom.xml                    |   6 +
 .../brooklyn/test/framework/AbstractTest.java   |  28 +-
 .../brooklyn/test/framework/BaseTest.java       |   2 +
 .../test/framework/SimpleShellCommandTest.java  | 107 +++++++
 .../framework/SimpleShellCommandTestImpl.java   | 316 +++++++++++++++++++
 .../brooklyn/test/framework/TestEffector.java   |   1 +
 .../test/framework/TestHttpCallImpl.java        |   2 +-
 .../brooklyn/test/framework/TestSensorImpl.java |   2 +-
 .../SimpleShellCommandIntegrationTest.java      | 211 +++++++++++++
 .../test/framework/TestEffectorTest.java        |   3 +-
 11 files changed, 671 insertions(+), 12 deletions(-)
----------------------------------------------------------------------



[06/20] incubator-brooklyn git commit: Add RUN_DIR.

Posted by he...@apache.org.
Add RUN_DIR.

https://github.com/apache/incubator-brooklyn/pull/1030#discussion_r45050093


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/cff1961f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/cff1961f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/cff1961f

Branch: refs/heads/master
Commit: cff1961fa442f6695ebc3b891f87a3235c3988c5
Parents: 9303918
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Tue Nov 17 12:18:52 2015 +0000
Committer: Geoff Macartney <ge...@cloudsoftcorp.com>
Committed: Tue Nov 17 12:18:52 2015 +0000

----------------------------------------------------------------------
 .../brooklyn/test/framework/SimpleCommand.java  | 11 ++++-
 .../test/framework/SimpleCommandImpl.java       | 17 +++++---
 .../SimpleCommandScriptIntegrationTest.java     | 45 ++++++++++++++++++++
 3 files changed, 66 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cff1961f/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
index c5ff777..0a58fe2 100644
--- 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
@@ -56,6 +56,15 @@ public interface SimpleCommand extends Entity, Startable {
     @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("scriptDir", "directory where downloaded scripts should be put", TMP_DEFAULT);
+    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/cff1961f/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
index 6b5f87c..b339e4d 100644
--- 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
@@ -63,6 +63,8 @@ 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 = "&&";
 
     private ResourceUtils resourceUtils;
 
@@ -150,8 +152,8 @@ public class SimpleCommandImpl extends AbstractEntity implements SimpleCommand {
 
         if (Strings.isNonBlank(downloadUrl)) {
             String scriptDir = getConfig(SCRIPT_DIR);
-            String destPath = calculateDestPath(downloadUrl, scriptDir);
-            result = executeDownloadedScript(machineLocation, downloadUrl, destPath);
+            String scriptPath = calculateDestPath(downloadUrl, scriptDir);
+            result = executeDownloadedScript(machineLocation, downloadUrl, scriptPath);
         }
 
         if (Strings.isNonBlank(command)) {
@@ -165,17 +167,20 @@ public class SimpleCommandImpl extends AbstractEntity implements SimpleCommand {
         return new IllegalArgumentException(Joiner.on(' ').join(this.toString() + ":", messages));
     }
 
-    private SimpleCommand.Result executeDownloadedScript(MachineLocation machineLocation, String downloadUrl, String destPath) {
+    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, downloadUrl, destPath);
+        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 " + destPath));
+        machine.execCommands("make the script executable", ImmutableList.<String>of("chmod u+x " + scriptPath));
 
-        return executeShellCommand(machineLocation, destPath);
+        String runDir = getConfig(RUN_DIR);
+        String cdAndRun = Joiner.on(' ').join(CD, runDir, SHELL_AND, scriptPath);
+
+        return executeShellCommand(machineLocation, cdAndRun);
     }
 
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cff1961f/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java
index b65a3e3..cb6c9ed 100644
--- a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java
+++ b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/SimpleCommandScriptIntegrationTest.java
@@ -37,6 +37,7 @@ import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocati
 import org.apache.brooklyn.test.http.TestHttpRequestHandler;
 import org.apache.brooklyn.test.http.TestHttpServer;
 import org.apache.brooklyn.util.core.task.Tasks;
+import org.apache.brooklyn.util.core.task.system.internal.SystemProcessTaskFactory;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.exceptions.FatalRuntimeException;
 import org.apache.brooklyn.util.http.HttpAsserts;
@@ -46,7 +47,12 @@ import org.testng.annotations.*;
 
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.FileAttribute;
 import java.util.Iterator;
+import java.util.Random;
 import java.util.UUID;
 
 import static org.apache.brooklyn.test.framework.BaseTest.TARGET_ENTITY;
@@ -130,4 +136,43 @@ public class SimpleCommandScriptIntegrationTest {
             .withFailMessage("Service should be marked running");
     }
 
+    @Test
+    public void shouldExecuteInTheRightPlace() throws Exception {
+        TestEntity testEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+
+        String testUrl = server.getUrl() + "/" + SCRIPT_NAME;
+        HttpAsserts.assertContentContainsText(testUrl, TEXT);
+
+        String remoteTmp = randomName();
+        SimpleCommandTest uptime = app.createAndManageChild(EntitySpec.create(SimpleCommandTest.class)
+            .configure(TARGET_ENTITY, testEntity)
+            .configure(DEFAULT_COMMAND, "mkdir " + remoteTmp)
+            .configure(ASSERT_STATUS, ImmutableMap.of(EQUALS, 0)));
+
+        Path localTmpPath = Paths.get("/tmp/").resolve(randomName());
+        Path pwdSh = localTmpPath.resolve("pwd.sh");
+        Files.createDirectory(localTmpPath);
+        Files.createFile(pwdSh);
+        Files.write(pwdSh, "pwd".getBytes());
+        String pwdUrl = "file:" + pwdSh.toString();
+
+        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 randomName() {
+        return Integer.valueOf(new Random(System.currentTimeMillis()).nextInt(100000)).toString();
+    }
+
 }