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 2016/01/13 19:06:00 UTC

[1/6] incubator-brooklyn git commit: Added LoopOverGroupMembersTestCase. Removed some targeting functionality from BaseTest and added it to a new Interface called TargetabeTestComponent Made TestCase and ParallelTestCase TargetabeTestComponent Infrastruc

Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master 58337c4e4 -> e2392c3a0


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCaseTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCaseTest.java b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCaseTest.java
new file mode 100644
index 0000000..39c85c5
--- /dev/null
+++ b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCaseTest.java
@@ -0,0 +1,286 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.brooklyn.test.framework;
+
+import static org.apache.brooklyn.core.entity.trait.Startable.SERVICE_UP;
+import static org.apache.brooklyn.test.Asserts.fail;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.entity.Group;
+import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.entity.group.DynamicGroup;
+import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+import org.apache.brooklyn.util.collections.MutableSet;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.text.Identifiers;
+
+/**
+ * @author Graeme Miller on 27/10/2015.
+ */
+public class LoopOverGroupMembersTestCaseTest {
+
+    private TestApplication app;
+    private Group testGroup;
+    private ManagementContext managementContext;
+    private LocalhostMachineProvisioningLocation loc;
+    private String testId;
+    private final String SENSOR_VAL = "Hello World!";
+
+    private static final AttributeSensorAndConfigKey<String, String> STRING_SENSOR = ConfigKeys.newSensorAndConfigKey(String.class, "string-sensor", "String Sensor");
+
+    @BeforeMethod
+    public void setup() {
+        testId = Identifiers.makeRandomId(8);
+        app = TestApplication.Factory.newManagedInstanceForTests();
+        managementContext = app.getManagementContext();
+
+        loc = managementContext.getLocationManager()
+                .createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class)
+                        .configure("name", testId));
+
+        testGroup = app.createAndManageChild(EntitySpec.create(DynamicGroup.class));
+    }
+
+    @AfterMethod(alwaysRun = true)
+    public void tearDown() throws Exception {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+
+    @Test
+    public void testOneChildWhichPasses() {
+        EmptySoftwareProcess emptySoftwareProcess = addEmptySoftwareProcessToGroup();
+        EntitySpec<TestSensor> testSpec = createPassingTestSensorSpec();
+
+        LoopOverGroupMembersTestCase loopOverGroupMembersTestCase = app.createAndManageChild(EntitySpec.create(LoopOverGroupMembersTestCase.class));
+        loopOverGroupMembersTestCase.config().set(LoopOverGroupMembersTestCase.TEST_SPEC, testSpec);
+        loopOverGroupMembersTestCase.config().set(LoopOverGroupMembersTestCase.TARGET_ENTITY, testGroup);
+
+        app.start(ImmutableList.of(app.newSimulatedLocation()));
+
+        assertThat(loopOverGroupMembersTestCase.getChildren().size()).isEqualTo(1);
+        assertThat(loopOverGroupMembersTestCase.sensors().get(SERVICE_UP)).isTrue();
+
+        Entity loopChildEntity = loopOverGroupMembersTestCase.getChildren().iterator().next();
+        assertThat(loopChildEntity).isInstanceOf(TestSensor.class);
+        assertThat(loopChildEntity.sensors().get(SERVICE_UP)).isTrue();
+        assertThat(loopChildEntity.config().get(LoopOverGroupMembersTestCase.TARGET_ENTITY)).isEqualTo(emptySoftwareProcess);
+    }
+
+    @Test
+    public void testMultipleChildrenWhichPass() {
+        Set<EmptySoftwareProcess> emptySoftwareProcesses = addMultipleEmptySoftwareProcessesToGroup(4);
+        EntitySpec<TestSensor> testSpec = createPassingTestSensorSpec();
+
+        LoopOverGroupMembersTestCase loopOverGroupMembersTestCase = app.createAndManageChild(EntitySpec.create(LoopOverGroupMembersTestCase.class));
+        loopOverGroupMembersTestCase.config().set(LoopOverGroupMembersTestCase.TEST_SPEC, testSpec);
+        loopOverGroupMembersTestCase.config().set(LoopOverGroupMembersTestCase.TARGET_ENTITY, testGroup);
+
+        app.start(ImmutableList.of(app.newSimulatedLocation()));
+
+        assertThat(loopOverGroupMembersTestCase.getChildren().size()).isEqualTo(4);
+        assertThat(loopOverGroupMembersTestCase.sensors().get(SERVICE_UP)).isTrue();
+
+        for (Entity loopChildEntity : loopOverGroupMembersTestCase.getChildren()) {
+            assertThat(loopChildEntity).isInstanceOf(TestSensor.class);
+            assertThat(loopChildEntity.sensors().get(SERVICE_UP)).isTrue();
+            assertThat(emptySoftwareProcesses.contains(loopChildEntity.config().get(LoopOverGroupMembersTestCase.TARGET_ENTITY))).isTrue();
+            emptySoftwareProcesses.remove(loopChildEntity.config().get(LoopOverGroupMembersTestCase.TARGET_ENTITY));
+        }
+    }
+
+    @Test
+    public void testMultipleChildrenWhichAllFail() {
+        Set<EmptySoftwareProcess> emptySoftwareProcesses = addMultipleEmptySoftwareProcessesToGroup(4);
+        EntitySpec<TestSensor> testSpec = createFailingTestSensorSpec();
+
+        LoopOverGroupMembersTestCase loopOverGroupMembersTestCase = app.createAndManageChild(EntitySpec.create(LoopOverGroupMembersTestCase.class));
+        loopOverGroupMembersTestCase.config().set(LoopOverGroupMembersTestCase.TEST_SPEC, testSpec);
+        loopOverGroupMembersTestCase.config().set(LoopOverGroupMembersTestCase.TARGET_ENTITY, testGroup);
+
+        app.start(ImmutableList.of(app.newSimulatedLocation()));
+
+        assertThat(loopOverGroupMembersTestCase.getChildren().size()).isEqualTo(4);
+        assertThat(loopOverGroupMembersTestCase.sensors().get(SERVICE_UP)).isFalse();
+
+        for (Entity loopChildEntity : loopOverGroupMembersTestCase.getChildren()) {
+            assertThat(loopChildEntity).isInstanceOf(TestSensor.class);
+            assertThat(loopChildEntity.sensors().get(SERVICE_UP)).isFalse();
+            assertThat(emptySoftwareProcesses.contains(loopChildEntity.config().get(LoopOverGroupMembersTestCase.TARGET_ENTITY))).isTrue();
+            emptySoftwareProcesses.remove(loopChildEntity.config().get(LoopOverGroupMembersTestCase.TARGET_ENTITY));
+        }
+    }
+
+    @Test
+    public void testMultipleChildrenOneOfWhichFails() {
+        Set<EmptySoftwareProcess> emptySoftwareProcesses = addMultipleEmptySoftwareProcessesToGroup(3);
+        EntitySpec<TestSensor> testSpec = createPassingTestSensorSpec();
+
+        EmptySoftwareProcess failingProcess = testGroup.addMemberChild(EntitySpec.create(EmptySoftwareProcess.class));
+        failingProcess.sensors().set(STRING_SENSOR, "THIS STRING WILL CAUSE SENSOR TEST TO FAIL");
+
+        LoopOverGroupMembersTestCase loopOverGroupMembersTestCase = app.createAndManageChild(EntitySpec.create(LoopOverGroupMembersTestCase.class));
+        loopOverGroupMembersTestCase.config().set(LoopOverGroupMembersTestCase.TEST_SPEC, testSpec);
+        loopOverGroupMembersTestCase.config().set(LoopOverGroupMembersTestCase.TARGET_ENTITY, testGroup);
+
+        app.start(ImmutableList.of(app.newSimulatedLocation()));
+
+        assertThat(loopOverGroupMembersTestCase.getChildren().size()).isEqualTo(4);
+        assertThat(loopOverGroupMembersTestCase.sensors().get(SERVICE_UP)).isFalse();
+
+        for (Entity loopChildEntity : loopOverGroupMembersTestCase.getChildren()) {
+            assertThat(loopChildEntity).isInstanceOf(TestSensor.class);
+
+            Entity targetedEntity = loopChildEntity.config().get(LoopOverGroupMembersTestCase.TARGET_ENTITY);
+
+            if (targetedEntity.equals(failingProcess)) {
+                assertThat(loopChildEntity.sensors().get(SERVICE_UP)).isFalse();
+            } else if (emptySoftwareProcesses.contains(targetedEntity)) {
+                assertThat(loopChildEntity.sensors().get(SERVICE_UP)).isTrue();
+                emptySoftwareProcesses.remove(targetedEntity);
+            } else {
+                fail("Targeted entity not recognized");
+            }
+        }
+    }
+
+    @Test
+    public void testOneChildWhichFails() {
+        EmptySoftwareProcess emptySoftwareProcess = addEmptySoftwareProcessToGroup();
+        EntitySpec<TestSensor> testSpec = createFailingTestSensorSpec();
+
+        LoopOverGroupMembersTestCase loopOverGroupMembersTestCase = app.createAndManageChild(EntitySpec.create(LoopOverGroupMembersTestCase.class));
+        loopOverGroupMembersTestCase.config().set(LoopOverGroupMembersTestCase.TEST_SPEC, testSpec);
+        loopOverGroupMembersTestCase.config().set(LoopOverGroupMembersTestCase.TARGET_ENTITY, testGroup);
+
+        app.start(ImmutableList.of(app.newSimulatedLocation()));
+
+        assertThat(loopOverGroupMembersTestCase.getChildren().size()).isEqualTo(1);
+        assertThat(loopOverGroupMembersTestCase.sensors().get(SERVICE_UP)).isFalse();
+
+        Entity loopChildEntity = loopOverGroupMembersTestCase.getChildren().iterator().next();
+        assertThat(loopChildEntity).isInstanceOf(TestSensor.class);
+        assertThat(loopChildEntity.sensors().get(SERVICE_UP)).isFalse();
+        assertThat(loopChildEntity.config().get(LoopOverGroupMembersTestCase.TARGET_ENTITY)).isEqualTo(emptySoftwareProcess);
+    }
+
+    //negative
+    // without test spec
+    // without target + taget id
+    // not a group
+
+    @Test
+    public void testNoTarget() {
+        EmptySoftwareProcess emptySoftwareProcess = addEmptySoftwareProcessToGroup();
+        EntitySpec<TestSensor> testSpec = createFailingTestSensorSpec();
+
+        LoopOverGroupMembersTestCase loopOverGroupMembersTestCase = app.createAndManageChild(EntitySpec.create(LoopOverGroupMembersTestCase.class));
+        loopOverGroupMembersTestCase.config().set(LoopOverGroupMembersTestCase.TEST_SPEC, testSpec);
+
+        app.start(ImmutableList.of(app.newSimulatedLocation()));
+
+        assertThat(loopOverGroupMembersTestCase.getChildren().size()).isEqualTo(0);
+        assertThat(loopOverGroupMembersTestCase.sensors().get(SERVICE_UP)).isFalse();
+    }
+
+    @Test
+    public void testNotTargetingGroup() {
+        EmptySoftwareProcess emptySoftwareProcess = addEmptySoftwareProcessToGroup();
+        EntitySpec<TestSensor> testSpec = createFailingTestSensorSpec();
+
+        LoopOverGroupMembersTestCase loopOverGroupMembersTestCase = app.createAndManageChild(EntitySpec.create(LoopOverGroupMembersTestCase.class));
+        loopOverGroupMembersTestCase.config().set(LoopOverGroupMembersTestCase.TEST_SPEC, testSpec);
+        loopOverGroupMembersTestCase.config().set(LoopOverGroupMembersTestCase.TARGET_ENTITY, app);
+
+        app.start(ImmutableList.of(app.newSimulatedLocation()));
+
+        assertThat(loopOverGroupMembersTestCase.getChildren().size()).isEqualTo(0);
+        assertThat(loopOverGroupMembersTestCase.sensors().get(SERVICE_UP)).isFalse();
+    }
+
+    @Test
+    public void testNoSpec() {
+        EmptySoftwareProcess emptySoftwareProcess = addEmptySoftwareProcessToGroup();
+        EntitySpec<TestSensor> testSpec = createFailingTestSensorSpec();
+
+        LoopOverGroupMembersTestCase loopOverGroupMembersTestCase = app.createAndManageChild(EntitySpec.create(LoopOverGroupMembersTestCase.class));
+        loopOverGroupMembersTestCase.config().set(LoopOverGroupMembersTestCase.TARGET_ENTITY, testGroup);
+
+        app.start(ImmutableList.of(app.newSimulatedLocation()));
+
+        assertThat(loopOverGroupMembersTestCase.getChildren().size()).isEqualTo(0);
+        assertThat(loopOverGroupMembersTestCase.sensors().get(SERVICE_UP)).isFalse();
+    }
+
+    //UTILITY METHODS
+    private EntitySpec<TestSensor> createFailingTestSensorSpec() {
+        List<Map<String, Object>> assertions = ImmutableList.<Map<String, Object>>of(
+                ImmutableMap.<String, Object>of(TestFrameworkAssertions.EQUAL_TO, "THIS IS THE WRONG STRING")
+        );
+
+        return EntitySpec.create(TestSensor.class)
+                .configure(TestSensor.SENSOR_NAME, STRING_SENSOR.getName())
+                .configure(TestSensor.ASSERTIONS, assertions);
+    }
+
+    private EntitySpec<TestSensor> createPassingTestSensorSpec() {
+        List<Map<String, Object>> assertions = ImmutableList.<Map<String, Object>>of(
+                ImmutableMap.<String, Object>of(TestFrameworkAssertions.EQUAL_TO, SENSOR_VAL)
+        );
+
+        return EntitySpec.create(TestSensor.class)
+                .configure(TestSensor.SENSOR_NAME, STRING_SENSOR.getName())
+                .configure(TestSensor.ASSERTIONS, assertions);
+    }
+
+    private Set<EmptySoftwareProcess> addMultipleEmptySoftwareProcessesToGroup(int number) {
+        MutableSet<EmptySoftwareProcess> softwareProcesses = MutableSet.<EmptySoftwareProcess>of();
+        for (int i = 0; i < number; i++) {
+            softwareProcesses.add(addEmptySoftwareProcessToGroup());
+        }
+
+        return softwareProcesses;
+    }
+
+    private EmptySoftwareProcess addEmptySoftwareProcessToGroup() {
+        EmptySoftwareProcess emptySoftwareProcess = testGroup.addMemberChild(EntitySpec.create(EmptySoftwareProcess.class));
+        emptySoftwareProcess.sensors().set(STRING_SENSOR, SENSOR_VAL);
+        return emptySoftwareProcess;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/entity/TestInfrastructure.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/entity/TestInfrastructure.java b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/entity/TestInfrastructure.java
new file mode 100644
index 0000000..abcd679
--- /dev/null
+++ b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/entity/TestInfrastructure.java
@@ -0,0 +1,31 @@
+/*
+ * 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.entity;
+
+import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.entity.stock.BasicApplication;
+
+/**
+ * Created by graememiller on 17/12/2015.
+ */
+
+@ImplementedBy(TestInfrastructureImpl.class)
+public interface TestInfrastructure extends BasicApplication {
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/entity/TestInfrastructureImpl.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/entity/TestInfrastructureImpl.java b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/entity/TestInfrastructureImpl.java
new file mode 100644
index 0000000..6ec0638
--- /dev/null
+++ b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/entity/TestInfrastructureImpl.java
@@ -0,0 +1,46 @@
+/*
+ * 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.entity;
+
+import java.util.Collection;
+
+import com.google.common.reflect.TypeToken;
+
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+import org.apache.brooklyn.entity.stock.BasicApplicationImpl;
+
+/**
+ * Created by graememiller on 17/12/2015.
+ */
+public class TestInfrastructureImpl extends BasicApplicationImpl implements TestInfrastructure {
+
+    private final AttributeSensorAndConfigKey<Location, Location> DEPLOYMENT_LOCATION = ConfigKeys.newSensorAndConfigKey(
+            new TypeToken<Location>() {
+            },
+            "deploymentLocationSensor", "The location to deploy to");
+
+    @Override
+    public void postStart(Collection<? extends Location> locations) {
+        super.postStart(locations);
+        sensors().set(DEPLOYMENT_LOCATION, config().get(DEPLOYMENT_LOCATION));
+    }
+}


[4/6] incubator-brooklyn git commit: fixes for restructured directory

Posted by he...@apache.org.
fixes for restructured directory


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

Branch: refs/heads/master
Commit: eb541cf56e0baaf83b59b4b43308f5d2f6c24873
Parents: 25ead1d
Author: Graeme-Miller <gr...@cloudsoftcorp.com>
Authored: Thu Jan 7 17:01:30 2016 +0000
Committer: Graeme-Miller <gr...@cloudsoftcorp.com>
Committed: Thu Jan 7 17:01:30 2016 +0000

----------------------------------------------------------------------
 .../framework/LoopOverGroupMembersTestCase.java |  45 -------
 .../LoopOverGroupMembersTestCaseImpl.java       | 134 -------------------
 .../test/framework/TargetableTestComponent.java |  53 --------
 .../framework/TargetableTestComponentImpl.java  |  83 ------------
 4 files changed, 315 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eb541cf5/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCase.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCase.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCase.java
deleted file mode 100644
index 4e76604..0000000
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCase.java
+++ /dev/null
@@ -1,45 +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.reflect.TypeToken;
-
-import org.apache.brooklyn.api.entity.EntitySpec;
-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;
-
-/**
- * Created by graememiller on 11/12/2015.
- */
-@ImplementedBy(value = LoopOverGroupMembersTestCaseImpl.class)
-public interface LoopOverGroupMembersTestCase extends TargetableTestComponent {
-
-    /**
-     * The test spec that will be run against each member of the group
-     */
-    @SetFromFlag("testSpec")
-    ConfigKey<EntitySpec<? extends TargetableTestComponent>> TEST_SPEC = ConfigKeys.newConfigKey(
-            new TypeToken<EntitySpec<? extends TargetableTestComponent>>(){},
-            "test.spec",
-            "Test spec. The test case will create one of these per child");
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eb541cf5/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCaseImpl.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCaseImpl.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCaseImpl.java
deleted file mode 100644
index f4bb06d..0000000
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCaseImpl.java
+++ /dev/null
@@ -1,134 +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 java.util.Collection;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.Lists;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.entity.Group;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.core.annotation.EffectorParam;
-import org.apache.brooklyn.core.entity.Attributes;
-import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
-import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-
-/**
- * Created by graememiller on 11/12/2015.
- */
-public class LoopOverGroupMembersTestCaseImpl extends TargetableTestComponentImpl implements LoopOverGroupMembersTestCase {
-
-    private static final Logger logger = LoggerFactory.getLogger(LoopOverGroupMembersTestCaseImpl.class);
-
-    @Override
-    public void start(@EffectorParam(name = "locations") Collection<? extends Location> locations) {
-        // Let everyone know we're starting up (so that the GUI shows the correct icon).
-        sensors().set(Attributes.SERVICE_STATE_ACTUAL, Lifecycle.STARTING);
-
-        Entity target = resolveTarget();
-        if (target == null) {
-            logger.debug("Tasks NOT successfully run. LoopOverGroupMembersTestCaseImpl group not set");
-            setServiceState(false, Lifecycle.ON_FIRE);
-            return;
-        }
-
-        if (!(target instanceof Group)) {
-            logger.debug("Tasks NOT successfully run. LoopOverGroupMembersTestCaseImpl target is not a group");
-            setServiceState(false, Lifecycle.ON_FIRE);
-            return;
-        }
-
-        EntitySpec<? extends TargetableTestComponent> testSpec = config().get(TEST_SPEC);
-        if (testSpec == null) {
-            logger.debug("Tasks NOT successfully run. LoopOverGroupMembersTestCaseImpl test spec not set");
-            setServiceState(false, Lifecycle.ON_FIRE);
-            return;
-        }
-
-        Group group = (Group) target;
-
-        Collection<Entity> children = group.getMembers();
-        boolean allSuccesful = true;
-        for (Entity child : children) {
-            testSpec.configure(TestCase.TARGET_ENTITY, child);
-
-            try {
-                TargetableTestComponent targetableTestComponent = this.addChild(testSpec);
-                targetableTestComponent.start(locations);
-            } catch (Throwable t) {
-                allSuccesful = false;
-            }
-        }
-
-        if (allSuccesful) {
-            // Let everyone know we've started up successfully (changes the icon in the GUI).
-            logger.debug("Tasks successfully run. Update state of {} to RUNNING.", this);
-            setServiceState(true, Lifecycle.RUNNING);
-        } else {
-            // Let everyone know we've npt started up successfully (changes the icon in the GUI).
-            logger.debug("Tasks NOT successfully run. Update state of {} to ON_FIRE.", this);
-            setServiceState(false, Lifecycle.ON_FIRE);
-        }
-
-    }
-
-    @Override
-    public void stop() {
-        // Let everyone know we're stopping (so that the GUI shows the correct icon).
-        sensors().set(Attributes.SERVICE_STATE_ACTUAL, Lifecycle.STOPPING);
-
-        try {
-            for (Entity child : this.getChildren()) {
-                if (child instanceof Startable) ((Startable) child).stop();
-            }
-
-            // Let everyone know we've stopped successfully (changes the icon in the GUI).
-            logger.debug("Tasks successfully run. Update state of {} to STOPPED.", this);
-            setServiceState(false, Lifecycle.STOPPED);
-        } catch (Throwable t) {
-            logger.debug("Tasks NOT successfully run. Update state of {} to ON_FIRE.", this);
-            setServiceState(false, Lifecycle.ON_FIRE);
-            throw Exceptions.propagate(t);
-        }
-    }
-
-    @Override
-    public void restart() {
-        final Collection<Location> locations = Lists.newArrayList(getLocations());
-        stop();
-        start(locations);
-    }
-
-    /**
-     * Sets the state of the Entity. Useful so that the GUI shows the correct icon.
-     *
-     * @param serviceUpState     Whether or not the entity is up.
-     * @param serviceStateActual The actual state of the entity.
-     */
-    private void setServiceState(final boolean serviceUpState, final Lifecycle serviceStateActual) {
-        sensors().set(SERVICE_UP, serviceUpState);
-        sensors().set(Attributes.SERVICE_STATE_ACTUAL, serviceStateActual);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eb541cf5/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponent.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponent.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponent.java
deleted file mode 100644
index 8ae44ad..0000000
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponent.java
+++ /dev/null
@@ -1,53 +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.core.config.ConfigKeys;
-import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
-
-/**
- * Entity that can target another entity for the purpouse of testing
- *
- * @author m4rkmckenna
- */
-@ImplementedBy(value = TargetableTestComponentImpl.class)
-public interface TargetableTestComponent extends Entity, Startable {
-
-    /**
-     * The target entity to test (optional, use either this or targetId).
-     */
-    AttributeSensorAndConfigKey<Entity, Entity> TARGET_ENTITY = ConfigKeys.newSensorAndConfigKey(Entity.class, "target", "Entity under test");
-
-    /**
-     * Id of the target entity to test (optional, use either this or target).
-     */
-    AttributeSensorAndConfigKey<String, String> TARGET_ID = ConfigKeys.newStringSensorAndConfigKey("targetId", "Id of the entity under test");
-
-    /**
-     * Get the target of the test.
-     *
-     * @return The target.
-     * @throws IllegalArgumentException if the target cannot be found.
-     */
-    Entity resolveTarget();
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/eb541cf5/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponentImpl.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponentImpl.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponentImpl.java
deleted file mode 100644
index 5b133bd..0000000
--- a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponentImpl.java
+++ /dev/null
@@ -1,83 +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 java.util.concurrent.ExecutionException;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-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;
-import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-
-/**
- * Class that can resolve the target for a test component
- */
-public abstract class TargetableTestComponentImpl extends AbstractEntity implements TargetableTestComponent {
-
-    private static final Logger LOG = LoggerFactory.getLogger(TargetableTestComponentImpl.class);
-
-    /**
-     * Find the target entity using "target" config key, if entity provided directly in config, or by doing an implicit
-     * lookup using DSL ($brooklyn:component("myNginX")), if id of entity provided as "targetId" config key.
-     *
-     * @return The target entity.
-     * @throws @RuntimeException if no target can be determined.
-     */
-    public Entity resolveTarget() {
-        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 target;
-    }
-
-    private static Entity getTargetById(ExecutionContext executionContext, Entity entity) {
-        String targetId = entity.getConfig(TARGET_ID);
-
-        if(targetId == null){
-            return null;
-        }
-
-        final Task<Entity> targetLookup = new DslComponent(targetId).newTask();
-        Entity target = null;
-        try {
-            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 target;
-    }
-}


[6/6] incubator-brooklyn git commit: This closes #1115

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


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

Branch: refs/heads/master
Commit: e2392c3a0487bef61e156f2fc784bdb0a26b8d19
Parents: 58337c4 9eb4105
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Jan 13 18:05:43 2016 +0000
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jan 13 18:05:43 2016 +0000

----------------------------------------------------------------------
 brooklyn-docs/guide/yaml/test/index.md          |   8 +-
 brooklyn-docs/guide/yaml/test/test-entities.md  |  33 ++-
 .../brooklyn/test/framework/AbstractTest.java   |  77 -----
 .../brooklyn/test/framework/BaseTest.java       |  31 +-
 .../InfrastructureDeploymentTestCase.java       |  11 +-
 .../InfrastructureDeploymentTestCaseImpl.java   |  52 +++-
 .../framework/LoopOverGroupMembersTestCase.java |  45 +++
 .../LoopOverGroupMembersTestCaseImpl.java       | 134 +++++++++
 .../test/framework/ParallelTestCase.java        |   4 +-
 .../test/framework/ParallelTestCaseImpl.java    |  10 +-
 .../test/framework/SimpleShellCommandTest.java  |  12 +-
 .../framework/SimpleShellCommandTestImpl.java   |  39 +--
 .../test/framework/TargetableTestComponent.java |  53 ++++
 .../framework/TargetableTestComponentImpl.java  |  83 ++++++
 .../brooklyn/test/framework/TestCase.java       |   4 +-
 .../brooklyn/test/framework/TestCaseImpl.java   |  15 +-
 .../test/framework/TestEffectorImpl.java        |  40 ++-
 .../test/framework/TestFrameworkAssertions.java |  11 +-
 .../test/framework/TestHttpCallImpl.java        |  27 +-
 .../brooklyn/test/framework/TestSensorImpl.java |  20 +-
 .../test/framework/TestEffectorTest.java        |  65 +++++
 .../test/framework/entity/TestEntity.java       |   3 +
 .../test/framework/entity/TestEntityImpl.java   |   5 +
 ...infrastructuredeploymenttestcase-entity.yaml |  11 +
 .../entities/loopovergroupmembers-entity.yaml   |   6 +
 .../InfrastructureDeploymentTestCaseTest.java   | 267 +++++++++++++++++
 .../LoopOverGroupMembersTestCaseTest.java       | 286 +++++++++++++++++++
 .../framework/entity/TestInfrastructure.java    |  31 ++
 .../entity/TestInfrastructureImpl.java          |  46 +++
 29 files changed, 1232 insertions(+), 197 deletions(-)
----------------------------------------------------------------------



[5/6] incubator-brooklyn git commit: add LoopOverGroupMembersTestCase & TargetableTestComponent. Should have been in previous commit but were excluded due to re-org

Posted by he...@apache.org.
add LoopOverGroupMembersTestCase & TargetableTestComponent. Should have been in previous commit but were excluded due to re-org


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

Branch: refs/heads/master
Commit: 9eb41059e0311eb1e68e8833cdeeff54c1961b26
Parents: eb541cf
Author: Graeme-Miller <gr...@cloudsoftcorp.com>
Authored: Fri Jan 8 11:56:27 2016 +0000
Committer: Graeme-Miller <gr...@cloudsoftcorp.com>
Committed: Fri Jan 8 11:56:27 2016 +0000

----------------------------------------------------------------------
 .../framework/LoopOverGroupMembersTestCase.java |  45 +++++++
 .../LoopOverGroupMembersTestCaseImpl.java       | 134 +++++++++++++++++++
 .../test/framework/TargetableTestComponent.java |  53 ++++++++
 .../framework/TargetableTestComponentImpl.java  |  83 ++++++++++++
 .../brooklyn/test/framework/TestSensorImpl.java |   1 -
 5 files changed, 315 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9eb41059/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCase.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCase.java b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCase.java
new file mode 100644
index 0000000..4e76604
--- /dev/null
+++ b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCase.java
@@ -0,0 +1,45 @@
+/*
+ * 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.reflect.TypeToken;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+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;
+
+/**
+ * Created by graememiller on 11/12/2015.
+ */
+@ImplementedBy(value = LoopOverGroupMembersTestCaseImpl.class)
+public interface LoopOverGroupMembersTestCase extends TargetableTestComponent {
+
+    /**
+     * The test spec that will be run against each member of the group
+     */
+    @SetFromFlag("testSpec")
+    ConfigKey<EntitySpec<? extends TargetableTestComponent>> TEST_SPEC = ConfigKeys.newConfigKey(
+            new TypeToken<EntitySpec<? extends TargetableTestComponent>>(){},
+            "test.spec",
+            "Test spec. The test case will create one of these per child");
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9eb41059/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCaseImpl.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCaseImpl.java b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCaseImpl.java
new file mode 100644
index 0000000..f4bb06d
--- /dev/null
+++ b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCaseImpl.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 java.util.Collection;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.entity.Group;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.annotation.EffectorParam;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+
+/**
+ * Created by graememiller on 11/12/2015.
+ */
+public class LoopOverGroupMembersTestCaseImpl extends TargetableTestComponentImpl implements LoopOverGroupMembersTestCase {
+
+    private static final Logger logger = LoggerFactory.getLogger(LoopOverGroupMembersTestCaseImpl.class);
+
+    @Override
+    public void start(@EffectorParam(name = "locations") Collection<? extends Location> locations) {
+        // Let everyone know we're starting up (so that the GUI shows the correct icon).
+        sensors().set(Attributes.SERVICE_STATE_ACTUAL, Lifecycle.STARTING);
+
+        Entity target = resolveTarget();
+        if (target == null) {
+            logger.debug("Tasks NOT successfully run. LoopOverGroupMembersTestCaseImpl group not set");
+            setServiceState(false, Lifecycle.ON_FIRE);
+            return;
+        }
+
+        if (!(target instanceof Group)) {
+            logger.debug("Tasks NOT successfully run. LoopOverGroupMembersTestCaseImpl target is not a group");
+            setServiceState(false, Lifecycle.ON_FIRE);
+            return;
+        }
+
+        EntitySpec<? extends TargetableTestComponent> testSpec = config().get(TEST_SPEC);
+        if (testSpec == null) {
+            logger.debug("Tasks NOT successfully run. LoopOverGroupMembersTestCaseImpl test spec not set");
+            setServiceState(false, Lifecycle.ON_FIRE);
+            return;
+        }
+
+        Group group = (Group) target;
+
+        Collection<Entity> children = group.getMembers();
+        boolean allSuccesful = true;
+        for (Entity child : children) {
+            testSpec.configure(TestCase.TARGET_ENTITY, child);
+
+            try {
+                TargetableTestComponent targetableTestComponent = this.addChild(testSpec);
+                targetableTestComponent.start(locations);
+            } catch (Throwable t) {
+                allSuccesful = false;
+            }
+        }
+
+        if (allSuccesful) {
+            // Let everyone know we've started up successfully (changes the icon in the GUI).
+            logger.debug("Tasks successfully run. Update state of {} to RUNNING.", this);
+            setServiceState(true, Lifecycle.RUNNING);
+        } else {
+            // Let everyone know we've npt started up successfully (changes the icon in the GUI).
+            logger.debug("Tasks NOT successfully run. Update state of {} to ON_FIRE.", this);
+            setServiceState(false, Lifecycle.ON_FIRE);
+        }
+
+    }
+
+    @Override
+    public void stop() {
+        // Let everyone know we're stopping (so that the GUI shows the correct icon).
+        sensors().set(Attributes.SERVICE_STATE_ACTUAL, Lifecycle.STOPPING);
+
+        try {
+            for (Entity child : this.getChildren()) {
+                if (child instanceof Startable) ((Startable) child).stop();
+            }
+
+            // Let everyone know we've stopped successfully (changes the icon in the GUI).
+            logger.debug("Tasks successfully run. Update state of {} to STOPPED.", this);
+            setServiceState(false, Lifecycle.STOPPED);
+        } catch (Throwable t) {
+            logger.debug("Tasks NOT successfully run. Update state of {} to ON_FIRE.", this);
+            setServiceState(false, Lifecycle.ON_FIRE);
+            throw Exceptions.propagate(t);
+        }
+    }
+
+    @Override
+    public void restart() {
+        final Collection<Location> locations = Lists.newArrayList(getLocations());
+        stop();
+        start(locations);
+    }
+
+    /**
+     * Sets the state of the Entity. Useful so that the GUI shows the correct icon.
+     *
+     * @param serviceUpState     Whether or not the entity is up.
+     * @param serviceStateActual The actual state of the entity.
+     */
+    private void setServiceState(final boolean serviceUpState, final Lifecycle serviceStateActual) {
+        sensors().set(SERVICE_UP, serviceUpState);
+        sensors().set(Attributes.SERVICE_STATE_ACTUAL, serviceStateActual);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9eb41059/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponent.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponent.java b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponent.java
new file mode 100644
index 0000000..8ae44ad
--- /dev/null
+++ b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponent.java
@@ -0,0 +1,53 @@
+/*
+ * 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.core.config.ConfigKeys;
+import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+
+/**
+ * Entity that can target another entity for the purpouse of testing
+ *
+ * @author m4rkmckenna
+ */
+@ImplementedBy(value = TargetableTestComponentImpl.class)
+public interface TargetableTestComponent extends Entity, Startable {
+
+    /**
+     * The target entity to test (optional, use either this or targetId).
+     */
+    AttributeSensorAndConfigKey<Entity, Entity> TARGET_ENTITY = ConfigKeys.newSensorAndConfigKey(Entity.class, "target", "Entity under test");
+
+    /**
+     * Id of the target entity to test (optional, use either this or target).
+     */
+    AttributeSensorAndConfigKey<String, String> TARGET_ID = ConfigKeys.newStringSensorAndConfigKey("targetId", "Id of the entity under test");
+
+    /**
+     * Get the target of the test.
+     *
+     * @return The target.
+     * @throws IllegalArgumentException if the target cannot be found.
+     */
+    Entity resolveTarget();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9eb41059/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponentImpl.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponentImpl.java b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponentImpl.java
new file mode 100644
index 0000000..5b133bd
--- /dev/null
+++ b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponentImpl.java
@@ -0,0 +1,83 @@
+/*
+ * 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 java.util.concurrent.ExecutionException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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;
+import org.apache.brooklyn.util.core.task.Tasks;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+
+/**
+ * Class that can resolve the target for a test component
+ */
+public abstract class TargetableTestComponentImpl extends AbstractEntity implements TargetableTestComponent {
+
+    private static final Logger LOG = LoggerFactory.getLogger(TargetableTestComponentImpl.class);
+
+    /**
+     * Find the target entity using "target" config key, if entity provided directly in config, or by doing an implicit
+     * lookup using DSL ($brooklyn:component("myNginX")), if id of entity provided as "targetId" config key.
+     *
+     * @return The target entity.
+     * @throws @RuntimeException if no target can be determined.
+     */
+    public Entity resolveTarget() {
+        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 target;
+    }
+
+    private static Entity getTargetById(ExecutionContext executionContext, Entity entity) {
+        String targetId = entity.getConfig(TARGET_ID);
+
+        if(targetId == null){
+            return null;
+        }
+
+        final Task<Entity> targetLookup = new DslComponent(targetId).newTask();
+        Entity target = null;
+        try {
+            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 target;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9eb41059/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java
index ff2596e..633e982 100644
--- a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java
+++ b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java
@@ -27,7 +27,6 @@ import java.util.Map;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.api.client.util.Objects;
 import com.google.common.base.Objects;
 import com.google.common.base.Predicate;
 import com.google.common.base.Supplier;


[2/6] incubator-brooklyn git commit: Added LoopOverGroupMembersTestCase. Removed some targeting functionality from BaseTest and added it to a new Interface called TargetabeTestComponent Made TestCase and ParallelTestCase TargetabeTestComponent Infrastruc

Posted by he...@apache.org.
Added LoopOverGroupMembersTestCase. Removed some targeting functionality from BaseTest and added it to a new Interface called TargetabeTestComponent
Made TestCase and ParallelTestCase TargetabeTestComponent
InfrastructureDeploymentTestCaseImpl can now deploy multiple specs
TestEffector will now check assertions
InfrastructureDeploymentTestCaseImpl made more resilient


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

Branch: refs/heads/master
Commit: 74a22487a6359bc2c39ae4590bc1496d1357121a
Parents: 7bcb392
Author: Graeme-Miller <gr...@cloudsoftcorp.com>
Authored: Mon Dec 14 16:32:38 2015 +0000
Committer: Graeme-Miller <gr...@cloudsoftcorp.com>
Committed: Thu Jan 7 16:44:39 2016 +0000

----------------------------------------------------------------------
 .../brooklyn/test/framework/AbstractTest.java   |  77 -----
 .../brooklyn/test/framework/BaseTest.java       |  31 +-
 .../InfrastructureDeploymentTestCase.java       |  11 +-
 .../InfrastructureDeploymentTestCaseImpl.java   |  52 +++-
 .../test/framework/ParallelTestCase.java        |   4 +-
 .../test/framework/ParallelTestCaseImpl.java    |  10 +-
 .../test/framework/SimpleShellCommandTest.java  |  12 +-
 .../framework/SimpleShellCommandTestImpl.java   |  39 +--
 .../brooklyn/test/framework/TestCase.java       |   4 +-
 .../brooklyn/test/framework/TestCaseImpl.java   |  15 +-
 .../test/framework/TestEffectorImpl.java        |  40 ++-
 .../test/framework/TestFrameworkAssertions.java |  11 +-
 .../test/framework/TestHttpCallImpl.java        |  27 +-
 .../brooklyn/test/framework/TestSensorImpl.java |  21 +-
 .../test/framework/TestEffectorTest.java        |  65 +++++
 .../test/framework/entity/TestEntity.java       |   3 +
 .../test/framework/entity/TestEntityImpl.java   |   5 +
 .../framework/LoopOverGroupMembersTestCase.java |  45 +++
 .../LoopOverGroupMembersTestCaseImpl.java       | 134 +++++++++
 .../test/framework/TargetableTestComponent.java |  53 ++++
 .../framework/TargetableTestComponentImpl.java  |  83 ++++++
 .../InfrastructureDeploymentTestCaseTest.java   | 267 +++++++++++++++++
 .../LoopOverGroupMembersTestCaseTest.java       | 286 +++++++++++++++++++
 .../framework/entity/TestInfrastructure.java    |  31 ++
 .../entity/TestInfrastructureImpl.java          |  46 +++
 25 files changed, 1180 insertions(+), 192 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/AbstractTest.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/AbstractTest.java b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/AbstractTest.java
deleted file mode 100644
index 434be8e..0000000
--- a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/AbstractTest.java
+++ /dev/null
@@ -1,77 +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.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;
-import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.concurrent.ExecutionException;
-
-/**
- * Abstract base class for tests, providing common target lookup.
- */
-public abstract class AbstractTest extends AbstractEntity implements BaseTest {
-
-    private static final Logger LOG = LoggerFactory.getLogger(AbstractTest.class);
-
-    /**
-     * Find the target entity using "target" config key, if entity provided directly in config, or by doing an implicit
-     * lookup using DSL ($brooklyn:component("myNginX")), if id of entity provided as "targetId" config key.
-     *
-     * @return The target entity.
-     * @throws @RuntimeException if no target can be determined.
-     */
-    public Entity resolveTarget() {
-        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 target;
-    }
-
-    private static Entity getTargetById(ExecutionContext executionContext, Entity entity) {
-        String targetId = entity.getConfig(TARGET_ID);
-        final Task<Entity> targetLookup = new DslComponent(targetId).newTask();
-        Entity target = null;
-        try {
-            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 target;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/BaseTest.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/BaseTest.java b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/BaseTest.java
index a97b9db..f5eb30b 100644
--- a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/BaseTest.java
+++ b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/BaseTest.java
@@ -18,34 +18,20 @@
  */
 package org.apache.brooklyn.test.framework;
 
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
 import com.google.common.collect.ImmutableList;
-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;
 import org.apache.brooklyn.util.time.Duration;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
 /**
  * A base interface for all tests.
  */
-public interface BaseTest extends Entity, Startable {
-
-    /**
-     * The target entity to test (optional, use either this or targetId).
-     */
-    ConfigKey<Entity> TARGET_ENTITY = ConfigKeys.newConfigKey(Entity.class, "target", "Entity under test");
-
-    /**
-     * Id of the target entity to test (optional, use either this or target).
-     */
-    ConfigKey<String> TARGET_ID = ConfigKeys.newStringConfigKey("targetId", "Id of the entity under test");
+public interface BaseTest extends TargetableTestComponent, Startable {
 
     /**
      * The assertions to be made.
@@ -59,12 +45,5 @@ public interface BaseTest extends Entity, Startable {
     ConfigKey<Duration> TIMEOUT = ConfigKeys.newConfigKey(Duration.class, "timeout", "Time to wait on result",
         new Duration(1L, TimeUnit.SECONDS));
 
-    /**
-     * Get the target of the test.
-     *
-     * @return The target.
-     * @throws IllegalArgumentException if the target cannot be found.
-     */
-    Entity resolveTarget();
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/InfrastructureDeploymentTestCase.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/InfrastructureDeploymentTestCase.java b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/InfrastructureDeploymentTestCase.java
index 5f368df..a3ffa53 100644
--- a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/InfrastructureDeploymentTestCase.java
+++ b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/InfrastructureDeploymentTestCase.java
@@ -18,7 +18,10 @@
  */
 package org.apache.brooklyn.test.framework;
 
+import java.util.List;
+
 import com.google.common.reflect.TypeToken;
+
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.config.ConfigKey;
@@ -30,19 +33,19 @@ import org.apache.brooklyn.entity.software.base.SoftwareProcess;
  * Created by graememiller on 04/12/2015.
  */
 @ImplementedBy(value = InfrastructureDeploymentTestCaseImpl.class)
-public interface InfrastructureDeploymentTestCase extends TestCase {
+public interface InfrastructureDeploymentTestCase extends TargetableTestComponent {
 
     /**
-     * Entity spec to deploy. This will be deployed second, after the INFRASTRUCTURE_SPEC has been deployed. This will be deployed to the DEPLOYMENT_LOCATION.
+     * Entity specs to deploy. These will be deployed second, after the INFRASTRUCTURE_SPEC has been deployed. These specs will be deployed to the DEPLOYMENT_LOCATION.
      * All children will be deployed after this
      */
-    ConfigKey<EntitySpec<SoftwareProcess>> ENTITY_SPEC_TO_DEPLOY = ConfigKeys.newConfigKey(new TypeToken<EntitySpec<SoftwareProcess>>(){}, "infrastructure.deployment.entity.spec", "Entity spec to deploy to infrastructure");
+    ConfigKey<List<EntitySpec<? extends SoftwareProcess>>> ENTITY_SPEC_TO_DEPLOY = ConfigKeys.newConfigKey(new TypeToken<List<EntitySpec<? extends SoftwareProcess>>>(){}, "infrastructure.deployment.entity.specs", "Entity specs to deploy to infrastructure");
 
 
     /**
      * Infrastructure to deploy. This will be deployed first, then the ENTITY_SPEC_TO_DEPLOY will be deployed, then any children
      */
-    ConfigKey<EntitySpec<StartableApplication>> INFRASTRUCTURE_SPEC = ConfigKeys.newConfigKey(new TypeToken<EntitySpec<StartableApplication>>(){}, "infrastructure.deployment.spec", "Infrastructure to deploy");
+    ConfigKey<EntitySpec<? extends StartableApplication>> INFRASTRUCTURE_SPEC = ConfigKeys.newConfigKey(new TypeToken<EntitySpec<? extends StartableApplication>>(){}, "infrastructure.deployment.spec", "Infrastructure to deploy");
 
 
     /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/InfrastructureDeploymentTestCaseImpl.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/InfrastructureDeploymentTestCaseImpl.java b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/InfrastructureDeploymentTestCaseImpl.java
index 900c0a0..55f3e63 100644
--- a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/InfrastructureDeploymentTestCaseImpl.java
+++ b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/InfrastructureDeploymentTestCaseImpl.java
@@ -18,16 +18,20 @@
  */
 package org.apache.brooklyn.test.framework;
 
+import java.util.Collection;
+import java.util.List;
+
 import com.google.common.collect.ImmutableList;
+
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.core.annotation.EffectorParam;
+import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.StartableApplication;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 
-import java.util.Collection;
-
 /**
  * Created by graememiller on 04/12/2015.
  */
@@ -35,23 +39,55 @@ public class InfrastructureDeploymentTestCaseImpl extends TestCaseImpl implement
 
     @Override
     public void start(@EffectorParam(name = "locations") Collection<? extends Location> locations) {
+        setServiceState(false, Lifecycle.STARTING);
+
         //Create the infrastructure
-        EntitySpec<StartableApplication> infrastructureSpec = config().get(INFRASTRUCTURE_SPEC);
+        EntitySpec<? extends StartableApplication> infrastructureSpec = config().get(INFRASTRUCTURE_SPEC);
+        if (infrastructureSpec == null) {
+            setServiceState(false, Lifecycle.ON_FIRE);
+            throw new IllegalArgumentException(INFRASTRUCTURE_SPEC + " not configured");
+        }
+
         StartableApplication infrastructure = this.addChild(infrastructureSpec);
         infrastructure.start(locations);
 
         //Get the location
         String deploymentLocationSensorName = config().get(DEPLOYMENT_LOCATION_SENSOR_NAME);
-        Location locationToDeployTo = infrastructure.sensors().get(Sensors.newSensor(Location.class, deploymentLocationSensorName));
+        if (deploymentLocationSensorName == null) {
+            setServiceState(false, Lifecycle.ON_FIRE);
+            throw new IllegalArgumentException(DEPLOYMENT_LOCATION_SENSOR_NAME + " not configured");
+        }
 
+        Location locationToDeployTo = infrastructure.sensors().get(Sensors.newSensor(Location.class, deploymentLocationSensorName));
+        if (locationToDeployTo == null) {
+            setServiceState(false, Lifecycle.ON_FIRE);
+            throw new IllegalArgumentException("Infrastructure does not have a location configured on sensor "+deploymentLocationSensorName);
+        }
 
         //Start the child entity
-        EntitySpec<SoftwareProcess> entityToDeploySpec = config().get(ENTITY_SPEC_TO_DEPLOY);
-        SoftwareProcess entityToDeploy = this.addChild(entityToDeploySpec);
-        entityToDeploy.start(ImmutableList.of(locationToDeployTo));
-
+        List<EntitySpec<? extends SoftwareProcess>> entitySpecsToDeploy = config().get(ENTITY_SPEC_TO_DEPLOY);
+        if (entitySpecsToDeploy == null || entitySpecsToDeploy.isEmpty()) {
+            setServiceState(false, Lifecycle.ON_FIRE);
+            throw new IllegalArgumentException(ENTITY_SPEC_TO_DEPLOY + " not configured");
+        }
+        for (EntitySpec<? extends SoftwareProcess> softwareProcessEntitySpec : entitySpecsToDeploy) {
+            SoftwareProcess entityToDeploy = this.addChild(softwareProcessEntitySpec);
+            entityToDeploy.start(ImmutableList.of(locationToDeployTo));
+        }
 
         //Defer to super class to start children
         super.start(locations);
+        setServiceState(true, Lifecycle.RUNNING);
+    }
+
+    /**
+     * Sets the state of the Entity. Useful so that the GUI shows the correct icon.
+     *
+     * @param serviceUpState     Whether or not the entity is up.
+     * @param serviceStateActual The actual state of the entity.
+     */
+    private void setServiceState(final boolean serviceUpState, final Lifecycle serviceStateActual) {
+        sensors().set(Attributes.SERVICE_UP, serviceUpState);
+        sensors().set(Attributes.SERVICE_STATE_ACTUAL, serviceStateActual);
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/ParallelTestCase.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/ParallelTestCase.java b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/ParallelTestCase.java
index 63fe60f..96f54b8 100644
--- a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/ParallelTestCase.java
+++ b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/ParallelTestCase.java
@@ -18,9 +18,7 @@
  */
 package org.apache.brooklyn.test.framework;
 
-import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.ImplementedBy;
-import org.apache.brooklyn.core.entity.trait.Startable;
 
 /**
  * This implementation will start all child entities in parallel.
@@ -28,5 +26,5 @@ import org.apache.brooklyn.core.entity.trait.Startable;
  * @author Chris Burke
  */
 @ImplementedBy(value = ParallelTestCaseImpl.class)
-public interface ParallelTestCase extends Entity, Startable {
+public interface ParallelTestCase extends TargetableTestComponent {
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/ParallelTestCaseImpl.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/ParallelTestCaseImpl.java b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/ParallelTestCaseImpl.java
index 2fcd83c..469bc3d 100644
--- a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/ParallelTestCaseImpl.java
+++ b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/ParallelTestCaseImpl.java
@@ -20,23 +20,23 @@ package org.apache.brooklyn.test.framework;
 
 import java.util.Collection;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.mgmt.TaskAdaptable;
-import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.trait.StartableMethods;
 import org.apache.brooklyn.util.core.task.DynamicTasks;
 import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * This implementation will start all child entities in parallel.
  * 
  * @author Chris Burke
  */
-public class ParallelTestCaseImpl extends AbstractEntity implements ParallelTestCase {
+public class ParallelTestCaseImpl extends TargetableTestComponentImpl implements ParallelTestCase {
 
     private static final Logger logger = LoggerFactory.getLogger(ParallelTestCaseImpl.class);
 
@@ -136,7 +136,7 @@ public class ParallelTestCaseImpl extends AbstractEntity implements ParallelTest
      * @param serviceStateActual The actual state of the entity.
      */
     private void setServiceState(final boolean serviceUpState, final Lifecycle serviceStateActual) {
-        sensors().set(SERVICE_UP, serviceUpState);
+        sensors().set(Attributes.SERVICE_UP, serviceUpState);
         sensors().set(Attributes.SERVICE_STATE_ACTUAL, serviceStateActual);
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandTest.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandTest.java b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandTest.java
index f9ffda6..abd0aea 100644
--- a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandTest.java
+++ b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandTest.java
@@ -18,9 +18,13 @@
  */
 package org.apache.brooklyn.test.framework;
 
+import static org.apache.brooklyn.core.config.ConfigKeys.newConfigKey;
+
+import java.util.Map;
+
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
-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;
@@ -28,12 +32,6 @@ 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.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import static org.apache.brooklyn.core.config.ConfigKeys.newConfigKey;
-
 /**
  * Tests using a simple command execution.
  */

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandTestImpl.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandTestImpl.java b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandTestImpl.java
index 6f2ef12..f523893 100644
--- a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandTestImpl.java
+++ b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/SimpleShellCommandTestImpl.java
@@ -18,21 +18,41 @@
  */
 package org.apache.brooklyn.test.framework;
 
+import static org.apache.brooklyn.core.entity.lifecycle.Lifecycle.ON_FIRE;
+import static org.apache.brooklyn.core.entity.lifecycle.Lifecycle.RUNNING;
+import static org.apache.brooklyn.core.entity.lifecycle.Lifecycle.STARTING;
+import static org.apache.brooklyn.core.entity.lifecycle.Lifecycle.STOPPED;
+import static org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.setExpectedState;
+import static org.apache.brooklyn.test.framework.TestFrameworkAssertions.checkAssertions;
+import static org.apache.brooklyn.test.framework.TestFrameworkAssertions.getAssertions;
+import static org.apache.brooklyn.util.text.Strings.isBlank;
+import static org.apache.brooklyn.util.text.Strings.isNonBlank;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Joiner;
 import com.google.common.base.Splitter;
 import com.google.common.base.Suppliers;
 import com.google.common.collect.ImmutableMap;
+
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.mgmt.TaskFactory;
-import org.apache.brooklyn.config.ConfigKey;
 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.framework.TestFrameworkAssertions.AssertionSupport;
 import org.apache.brooklyn.util.collections.MutableList;
-import org.apache.brooklyn.util.collections.MutableMap;
 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;
@@ -40,22 +60,9 @@ import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.text.Identifiers;
 import org.apache.brooklyn.util.text.Strings;
 import org.apache.brooklyn.util.time.Duration;
-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.test.framework.TestFrameworkAssertions.checkAssertions;
-import static org.apache.brooklyn.test.framework.TestFrameworkAssertions.getAssertions;
-import static org.apache.brooklyn.util.text.Strings.isBlank;
-import static org.apache.brooklyn.util.text.Strings.isNonBlank;
 
 // 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 class SimpleShellCommandTestImpl extends TargetableTestComponentImpl implements SimpleShellCommandTest {
 
     private static final Logger LOG = LoggerFactory.getLogger(SimpleShellCommandTestImpl.class);
     private static final int A_LINE = 80;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java
index 34a2e34..b6d6f61 100644
--- a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java
+++ b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java
@@ -18,9 +18,7 @@
  */
 package org.apache.brooklyn.test.framework;
 
-import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.ImplementedBy;
-import org.apache.brooklyn.core.entity.trait.Startable;
 
 /**
  * Entity that logically groups other test entities
@@ -28,5 +26,5 @@ import org.apache.brooklyn.core.entity.trait.Startable;
  * @author m4rkmckenna
  */
 @ImplementedBy(value = TestCaseImpl.class)
-public interface TestCase extends Entity, Startable {
+public interface TestCase extends TargetableTestComponent {
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCaseImpl.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCaseImpl.java b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCaseImpl.java
index 1508778..eb3a04e 100644
--- a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCaseImpl.java
+++ b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCaseImpl.java
@@ -18,24 +18,25 @@
  */
 package org.apache.brooklyn.test.framework;
 
+import java.util.Collection;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import com.google.common.collect.Lists;
+
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Collection;
 
 /**
  * {@inheritDoc}
  */
-public class TestCaseImpl extends AbstractEntity implements TestCase {
+public class TestCaseImpl extends TargetableTestComponentImpl implements TestCase {
 
     private static final Logger LOG = LoggerFactory.getLogger(TestCaseImpl.class);
 
@@ -46,7 +47,7 @@ public class TestCaseImpl extends AbstractEntity implements TestCase {
         ServiceStateLogic.setExpectedState(this, Lifecycle.STARTING);
         try {
             for (final Entity childEntity : getChildren()) {
-                Boolean serviceUp = childEntity.sensors().get(SERVICE_UP);
+                Boolean serviceUp = childEntity.sensors().get(Attributes.SERVICE_UP);
                 if (childEntity instanceof Startable && !Boolean.TRUE.equals(serviceUp)){
                     ((Startable) childEntity).start(locations);
                 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEffectorImpl.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEffectorImpl.java b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEffectorImpl.java
index 817ef6a..c00bef2 100644
--- a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEffectorImpl.java
+++ b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEffectorImpl.java
@@ -18,7 +18,19 @@
  */
 package org.apache.brooklyn.test.framework;
 
+import static org.apache.brooklyn.test.framework.TestFrameworkAssertions.getAssertions;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
+
 import org.apache.brooklyn.api.effector.Effector;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.Location;
@@ -30,16 +42,11 @@ import org.apache.brooklyn.core.mgmt.internal.EffectorUtils;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.time.Duration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Collection;
-import java.util.Map;
 
 /**
  *
  */
-public class TestEffectorImpl extends AbstractTest implements TestEffector {
+public class TestEffectorImpl extends TargetableTestComponentImpl implements TestEffector {
     private static final Logger LOG = LoggerFactory.getLogger(TestEffectorImpl.class);
 
 
@@ -60,14 +67,27 @@ public class TestEffectorImpl extends AbstractTest implements TestEffector {
             if (effector.isAbsentOrNull()) {
                 throw new AssertionError(String.format("No effector with name [%s]", effectorName));
             }
-            final Task<?> effectorResult;
+            final Task<?> effectorTask;
             if (effectorParams == null || effectorParams.isEmpty()) {
-                effectorResult = Entities.invokeEffector(this, targetEntity, effector.get());
+                effectorTask = Entities.invokeEffector(this, targetEntity, effector.get());
             } else {
-                effectorResult = Entities.invokeEffector(this, targetEntity, effector.get(), effectorParams);
+                effectorTask = Entities.invokeEffector(this, targetEntity, effector.get(), effectorParams);
             }
+
+            final Object effectorResult = effectorTask.get(timeout);
+
+            final List<Map<String, Object>> assertions = getAssertions(this, ASSERTIONS);
+            if(assertions != null && !assertions.isEmpty()){
+                TestFrameworkAssertions.checkAssertions(ImmutableMap.of("timeout", timeout), assertions, effectorName, new Supplier<String>() {
+                    @Override
+                    public String get() {
+                        return (String)effectorResult;
+                    }
+                });
+            }
+
             //Add result of effector to sensor
-            sensors().set(EFFECTOR_RESULT, effectorResult.get(timeout));
+            sensors().set(EFFECTOR_RESULT, effectorResult);
             sensors().set(SERVICE_UP, true);
             ServiceStateLogic.setExpectedState(this, Lifecycle.RUNNING);
         } catch (Throwable t) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestFrameworkAssertions.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestFrameworkAssertions.java b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestFrameworkAssertions.java
index 0e61419..3c00020 100644
--- a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestFrameworkAssertions.java
+++ b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestFrameworkAssertions.java
@@ -18,9 +18,15 @@
  */
 package org.apache.brooklyn.test.framework;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
 import com.google.common.base.Joiner;
 import com.google.common.base.Supplier;
 import com.google.common.reflect.TypeToken;
+
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.test.Asserts;
@@ -30,11 +36,6 @@ import org.apache.brooklyn.util.exceptions.FatalConfigurationRuntimeException;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.text.Strings;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
 
 /**
  * Utility class to evaluate test-framework assertions

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java
index 67451ed..e3e4456 100644
--- a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java
+++ b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java
@@ -18,28 +18,31 @@
  */
 package org.apache.brooklyn.test.framework;
 
+import static org.apache.brooklyn.test.framework.TestFrameworkAssertions.getAssertions;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import com.google.common.base.Supplier;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
+
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
 import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.http.HttpTool;
 import org.apache.brooklyn.util.time.Duration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import static org.apache.brooklyn.test.framework.TestFrameworkAssertions.getAssertions;
 
 /**
  * {@inheritDoc}
  */
-public class TestHttpCallImpl extends AbstractTest implements TestHttpCall {
+public class TestHttpCallImpl extends TargetableTestComponentImpl implements TestHttpCall {
 
     private static final Logger LOG = LoggerFactory.getLogger(TestHttpCallImpl.class);
 
@@ -58,12 +61,12 @@ public class TestHttpCallImpl extends AbstractTest implements TestHttpCall {
 
         try {
             doRequestAndCheckAssertions(ImmutableMap.of("timeout", timeout), assertions, target, url);
-            sensors().set(SERVICE_UP, true);
+            sensors().set(Attributes.SERVICE_UP, true);
             ServiceStateLogic.setExpectedState(this, Lifecycle.RUNNING);
 
         } catch (Throwable t) {
             LOG.info("{} Url [{}] test failed", this, url);
-            sensors().set(SERVICE_UP, false);
+            sensors().set(Attributes.SERVICE_UP, false);
             ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE);
             throw Exceptions.propagate(t);
         }
@@ -105,7 +108,7 @@ public class TestHttpCallImpl extends AbstractTest implements TestHttpCall {
      */
     public void stop() {
         ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPING);
-        sensors().set(SERVICE_UP, false);
+        sensors().set(Attributes.SERVICE_UP, false);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java
index d042991..ff2596e 100644
--- a/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java
+++ b/brooklyn-server/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java
@@ -18,11 +18,22 @@
  */
 package org.apache.brooklyn.test.framework;
 
+import static org.apache.brooklyn.test.framework.TestFrameworkAssertions.getAssertions;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.api.client.util.Objects;
 import com.google.common.base.Objects;
 import com.google.common.base.Predicate;
 import com.google.common.base.Supplier;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
+
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
@@ -31,19 +42,11 @@ import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.util.core.flags.TypeCoercions;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.time.Duration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import static org.apache.brooklyn.test.framework.TestFrameworkAssertions.getAssertions;
 
 /**
  * {@inheritDoc}
  */
-public class TestSensorImpl extends AbstractTest implements TestSensor {
+public class TestSensorImpl extends TargetableTestComponentImpl implements TestSensor {
 
     private static final Logger LOG = LoggerFactory.getLogger(TestSensorImpl.class);
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/brooklyn-server/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEffectorTest.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEffectorTest.java b/brooklyn-server/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEffectorTest.java
index b6f3c4a..d0c6b8c 100644
--- a/brooklyn-server/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEffectorTest.java
+++ b/brooklyn-server/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEffectorTest.java
@@ -28,13 +28,19 @@ import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
 import org.apache.brooklyn.test.framework.entity.TestEntity;
+import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.text.Identifiers;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
+import static org.apache.brooklyn.core.entity.trait.Startable.SERVICE_UP;
+import static org.apache.brooklyn.test.Asserts.fail;
 import static org.assertj.core.api.Assertions.assertThat;
 
+import java.util.List;
+import java.util.Map;
+
 /**
  * @author m4rkmckenna on 27/10/2015.
  */
@@ -83,6 +89,65 @@ public class TestEffectorTest {
     }
 
     @Test
+    public void testEffectorPositiveAssertions() {
+        final TestCase testCase = app.createAndManageChild(EntitySpec.create(TestCase.class));
+        final TestEntity testEntity = testCase.addChild(EntitySpec.create(TestEntity.class));
+
+        String stringToReturn = "Hello World!";
+
+        Map<String, String> effectorParams = ImmutableMap.of("stringToReturn", stringToReturn);
+
+        List<Map<String, Object>> assertions = ImmutableList.<Map<String, Object>>of(
+                ImmutableMap.<String, Object>of(TestFrameworkAssertions.EQUAL_TO, stringToReturn),
+                ImmutableMap.<String, Object>of(TestFrameworkAssertions.CONTAINS, "Hello")
+        );
+
+        final TestEffector testEffector = testCase.addChild(EntitySpec.create(TestEffector.class)
+                .configure(TestEffector.TARGET_ENTITY, testEntity)
+                .configure(TestEffector.EFFECTOR_NAME, "effectorReturnsString")
+                .configure(TestEffector.EFFECTOR_PARAMS, effectorParams)
+                .configure(TestEffector.ASSERTIONS, assertions));
+
+        app.start(ImmutableList.of(app.newSimulatedLocation()));
+
+        assertThat(testEffector.sensors().get(TestEffector.EFFECTOR_RESULT)).isEqualTo(stringToReturn);
+        assertThat(testEffector.sensors().get(SERVICE_UP)).isTrue().withFailMessage("Service should be up");
+    }
+
+    @Test
+    public void testEffectorNegativeAssertions() {
+        final TestCase testCase = app.createAndManageChild(EntitySpec.create(TestCase.class));
+        final TestEntity testEntity = testCase.addChild(EntitySpec.create(TestEntity.class));
+
+        String stringToReturn = "Goodbye World!";
+
+        Map<String, String> effectorParams = ImmutableMap.of("stringToReturn", stringToReturn);
+
+        List<Map<String, Object>> assertions = ImmutableList.<Map<String, Object>>of(
+                ImmutableMap.<String, Object>of(TestFrameworkAssertions.EQUAL_TO, "Not the string I expected"),
+                ImmutableMap.<String, Object>of(TestFrameworkAssertions.CONTAINS, "Hello")
+        );
+
+        final TestEffector testEffector = testCase.addChild(EntitySpec.create(TestEffector.class)
+                .configure(TestEffector.TARGET_ENTITY, testEntity)
+                .configure(TestEffector.EFFECTOR_NAME, "effectorReturnsString")
+                .configure(TestEffector.EFFECTOR_PARAMS, effectorParams)
+                .configure(TestEffector.ASSERTIONS, assertions));
+
+        try {
+            app.start(ImmutableList.of(app.newSimulatedLocation()));
+            fail("Should have thrown execption");
+        } catch (Throwable throwable) {
+            Throwable firstInteresting = Exceptions.getFirstInteresting(throwable);
+            assertThat(firstInteresting).isNotNull();
+            assertThat(throwable).isNotNull();
+            assertThat(firstInteresting).isInstanceOf(AssertionError.class);
+        }
+
+        assertThat(testEffector.sensors().get(SERVICE_UP)).isFalse().withFailMessage("Service should not be up");
+    }
+
+    @Test
     public void testComplexffector() {
         final TestCase testCase = app.createAndManageChild(EntitySpec.create(TestCase.class));
         final TestEntity testEntity = testCase.addChild(EntitySpec.create(TestEntity.class));

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/brooklyn-server/test-framework/src/test/java/org/apache/brooklyn/test/framework/entity/TestEntity.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/test-framework/src/test/java/org/apache/brooklyn/test/framework/entity/TestEntity.java b/brooklyn-server/test-framework/src/test/java/org/apache/brooklyn/test/framework/entity/TestEntity.java
index a0abcf1..4de9587 100644
--- a/brooklyn-server/test-framework/src/test/java/org/apache/brooklyn/test/framework/entity/TestEntity.java
+++ b/brooklyn-server/test-framework/src/test/java/org/apache/brooklyn/test/framework/entity/TestEntity.java
@@ -48,6 +48,9 @@ public interface TestEntity extends Entity, Startable {
                              @EffectorParam(name = "booleanValue") final Boolean booleanValue,
                              @EffectorParam(name = "longValue") final Long longValue);
 
+    @Effector
+    String effectorReturnsString(@EffectorParam(name = "stringToReturn") final String stringToReturn);
+
     class TestPojo {
         private final String stringValue;
         private final Boolean booleanValue;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/brooklyn-server/test-framework/src/test/java/org/apache/brooklyn/test/framework/entity/TestEntityImpl.java
----------------------------------------------------------------------
diff --git a/brooklyn-server/test-framework/src/test/java/org/apache/brooklyn/test/framework/entity/TestEntityImpl.java b/brooklyn-server/test-framework/src/test/java/org/apache/brooklyn/test/framework/entity/TestEntityImpl.java
index 50ef967..7f066a7 100644
--- a/brooklyn-server/test-framework/src/test/java/org/apache/brooklyn/test/framework/entity/TestEntityImpl.java
+++ b/brooklyn-server/test-framework/src/test/java/org/apache/brooklyn/test/framework/entity/TestEntityImpl.java
@@ -56,4 +56,9 @@ public class TestEntityImpl extends AbstractEntity implements TestEntity {
         sensors().set(COMPLEX_EFFECTOR_LONG, longValue);
         return new TestPojo(stringValue, booleanValue, longValue);
     }
+
+    @Override
+    public String effectorReturnsString(@EffectorParam(name = "stringToReturn") String stringToReturn) {
+        return stringToReturn;
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCase.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCase.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCase.java
new file mode 100644
index 0000000..4e76604
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCase.java
@@ -0,0 +1,45 @@
+/*
+ * 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.reflect.TypeToken;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+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;
+
+/**
+ * Created by graememiller on 11/12/2015.
+ */
+@ImplementedBy(value = LoopOverGroupMembersTestCaseImpl.class)
+public interface LoopOverGroupMembersTestCase extends TargetableTestComponent {
+
+    /**
+     * The test spec that will be run against each member of the group
+     */
+    @SetFromFlag("testSpec")
+    ConfigKey<EntitySpec<? extends TargetableTestComponent>> TEST_SPEC = ConfigKeys.newConfigKey(
+            new TypeToken<EntitySpec<? extends TargetableTestComponent>>(){},
+            "test.spec",
+            "Test spec. The test case will create one of these per child");
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCaseImpl.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCaseImpl.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCaseImpl.java
new file mode 100644
index 0000000..f4bb06d
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/LoopOverGroupMembersTestCaseImpl.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 java.util.Collection;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.entity.Group;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.annotation.EffectorParam;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+
+/**
+ * Created by graememiller on 11/12/2015.
+ */
+public class LoopOverGroupMembersTestCaseImpl extends TargetableTestComponentImpl implements LoopOverGroupMembersTestCase {
+
+    private static final Logger logger = LoggerFactory.getLogger(LoopOverGroupMembersTestCaseImpl.class);
+
+    @Override
+    public void start(@EffectorParam(name = "locations") Collection<? extends Location> locations) {
+        // Let everyone know we're starting up (so that the GUI shows the correct icon).
+        sensors().set(Attributes.SERVICE_STATE_ACTUAL, Lifecycle.STARTING);
+
+        Entity target = resolveTarget();
+        if (target == null) {
+            logger.debug("Tasks NOT successfully run. LoopOverGroupMembersTestCaseImpl group not set");
+            setServiceState(false, Lifecycle.ON_FIRE);
+            return;
+        }
+
+        if (!(target instanceof Group)) {
+            logger.debug("Tasks NOT successfully run. LoopOverGroupMembersTestCaseImpl target is not a group");
+            setServiceState(false, Lifecycle.ON_FIRE);
+            return;
+        }
+
+        EntitySpec<? extends TargetableTestComponent> testSpec = config().get(TEST_SPEC);
+        if (testSpec == null) {
+            logger.debug("Tasks NOT successfully run. LoopOverGroupMembersTestCaseImpl test spec not set");
+            setServiceState(false, Lifecycle.ON_FIRE);
+            return;
+        }
+
+        Group group = (Group) target;
+
+        Collection<Entity> children = group.getMembers();
+        boolean allSuccesful = true;
+        for (Entity child : children) {
+            testSpec.configure(TestCase.TARGET_ENTITY, child);
+
+            try {
+                TargetableTestComponent targetableTestComponent = this.addChild(testSpec);
+                targetableTestComponent.start(locations);
+            } catch (Throwable t) {
+                allSuccesful = false;
+            }
+        }
+
+        if (allSuccesful) {
+            // Let everyone know we've started up successfully (changes the icon in the GUI).
+            logger.debug("Tasks successfully run. Update state of {} to RUNNING.", this);
+            setServiceState(true, Lifecycle.RUNNING);
+        } else {
+            // Let everyone know we've npt started up successfully (changes the icon in the GUI).
+            logger.debug("Tasks NOT successfully run. Update state of {} to ON_FIRE.", this);
+            setServiceState(false, Lifecycle.ON_FIRE);
+        }
+
+    }
+
+    @Override
+    public void stop() {
+        // Let everyone know we're stopping (so that the GUI shows the correct icon).
+        sensors().set(Attributes.SERVICE_STATE_ACTUAL, Lifecycle.STOPPING);
+
+        try {
+            for (Entity child : this.getChildren()) {
+                if (child instanceof Startable) ((Startable) child).stop();
+            }
+
+            // Let everyone know we've stopped successfully (changes the icon in the GUI).
+            logger.debug("Tasks successfully run. Update state of {} to STOPPED.", this);
+            setServiceState(false, Lifecycle.STOPPED);
+        } catch (Throwable t) {
+            logger.debug("Tasks NOT successfully run. Update state of {} to ON_FIRE.", this);
+            setServiceState(false, Lifecycle.ON_FIRE);
+            throw Exceptions.propagate(t);
+        }
+    }
+
+    @Override
+    public void restart() {
+        final Collection<Location> locations = Lists.newArrayList(getLocations());
+        stop();
+        start(locations);
+    }
+
+    /**
+     * Sets the state of the Entity. Useful so that the GUI shows the correct icon.
+     *
+     * @param serviceUpState     Whether or not the entity is up.
+     * @param serviceStateActual The actual state of the entity.
+     */
+    private void setServiceState(final boolean serviceUpState, final Lifecycle serviceStateActual) {
+        sensors().set(SERVICE_UP, serviceUpState);
+        sensors().set(Attributes.SERVICE_STATE_ACTUAL, serviceStateActual);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponent.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponent.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponent.java
new file mode 100644
index 0000000..8ae44ad
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponent.java
@@ -0,0 +1,53 @@
+/*
+ * 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.core.config.ConfigKeys;
+import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+
+/**
+ * Entity that can target another entity for the purpouse of testing
+ *
+ * @author m4rkmckenna
+ */
+@ImplementedBy(value = TargetableTestComponentImpl.class)
+public interface TargetableTestComponent extends Entity, Startable {
+
+    /**
+     * The target entity to test (optional, use either this or targetId).
+     */
+    AttributeSensorAndConfigKey<Entity, Entity> TARGET_ENTITY = ConfigKeys.newSensorAndConfigKey(Entity.class, "target", "Entity under test");
+
+    /**
+     * Id of the target entity to test (optional, use either this or target).
+     */
+    AttributeSensorAndConfigKey<String, String> TARGET_ID = ConfigKeys.newStringSensorAndConfigKey("targetId", "Id of the entity under test");
+
+    /**
+     * Get the target of the test.
+     *
+     * @return The target.
+     * @throws IllegalArgumentException if the target cannot be found.
+     */
+    Entity resolveTarget();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponentImpl.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponentImpl.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponentImpl.java
new file mode 100644
index 0000000..5b133bd
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TargetableTestComponentImpl.java
@@ -0,0 +1,83 @@
+/*
+ * 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 java.util.concurrent.ExecutionException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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;
+import org.apache.brooklyn.util.core.task.Tasks;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+
+/**
+ * Class that can resolve the target for a test component
+ */
+public abstract class TargetableTestComponentImpl extends AbstractEntity implements TargetableTestComponent {
+
+    private static final Logger LOG = LoggerFactory.getLogger(TargetableTestComponentImpl.class);
+
+    /**
+     * Find the target entity using "target" config key, if entity provided directly in config, or by doing an implicit
+     * lookup using DSL ($brooklyn:component("myNginX")), if id of entity provided as "targetId" config key.
+     *
+     * @return The target entity.
+     * @throws @RuntimeException if no target can be determined.
+     */
+    public Entity resolveTarget() {
+        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 target;
+    }
+
+    private static Entity getTargetById(ExecutionContext executionContext, Entity entity) {
+        String targetId = entity.getConfig(TARGET_ID);
+
+        if(targetId == null){
+            return null;
+        }
+
+        final Task<Entity> targetLookup = new DslComponent(targetId).newTask();
+        Entity target = null;
+        try {
+            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 target;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/74a22487/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/InfrastructureDeploymentTestCaseTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/InfrastructureDeploymentTestCaseTest.java b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/InfrastructureDeploymentTestCaseTest.java
new file mode 100644
index 0000000..fa0e864
--- /dev/null
+++ b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/InfrastructureDeploymentTestCaseTest.java
@@ -0,0 +1,267 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.brooklyn.test.framework;
+
+import static org.apache.brooklyn.core.entity.trait.Startable.SERVICE_UP;
+import static org.apache.brooklyn.test.Asserts.fail;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.reflect.TypeToken;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess;
+import org.apache.brooklyn.entity.software.base.SoftwareProcess;
+import org.apache.brooklyn.entity.stock.BasicApplication;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+import org.apache.brooklyn.test.framework.entity.TestInfrastructure;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.text.Identifiers;
+
+/**
+ * @author Graeme Miller on 27/10/2015.
+ */
+public class InfrastructureDeploymentTestCaseTest {
+
+    private TestApplication app;
+    private ManagementContext managementContext;
+    private LocalhostMachineProvisioningLocation loc;
+    private LocalhostMachineProvisioningLocation infrastructureLoc;
+    private String LOC_NAME = "location";
+    private String INFRASTRUCTURE_LOC_NAME = "Infrastructure location";
+
+    private static final AttributeSensorAndConfigKey<Location, Location> DEPLOYMENT_LOCATION_SENSOR =
+            ConfigKeys.newSensorAndConfigKey(
+                    new TypeToken<Location>() {
+                    },
+                    "deploymentLocationSensor", "The location to deploy to");
+
+    @BeforeMethod
+    public void setup() {
+        app = TestApplication.Factory.newManagedInstanceForTests();
+        managementContext = app.getManagementContext();
+
+        loc = managementContext.getLocationManager()
+                .createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class)
+                        .configure("name", LOC_NAME));
+
+        infrastructureLoc = managementContext.getLocationManager()
+                .createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class)
+                        .configure("name", INFRASTRUCTURE_LOC_NAME));
+    }
+
+    @AfterMethod(alwaysRun = true)
+    public void tearDown() throws Exception {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+
+    @Test
+    public void testVanilla() {
+        EntitySpec<TestInfrastructure> infrastructureSpec = EntitySpec.create(TestInfrastructure.class);
+        infrastructureSpec.configure(DEPLOYMENT_LOCATION_SENSOR, infrastructureLoc);
+
+        List<EntitySpec<? extends SoftwareProcess>> testSpecs = ImmutableList.<EntitySpec<? extends SoftwareProcess>>of(EntitySpec.create(EmptySoftwareProcess.class));
+
+        InfrastructureDeploymentTestCase infrastructureDeploymentTestCase = app.createAndManageChild(EntitySpec.create(InfrastructureDeploymentTestCase.class));
+        infrastructureDeploymentTestCase.config().set(InfrastructureDeploymentTestCase.INFRASTRUCTURE_SPEC, infrastructureSpec);
+        infrastructureDeploymentTestCase.config().set(InfrastructureDeploymentTestCase.ENTITY_SPEC_TO_DEPLOY, testSpecs);
+        infrastructureDeploymentTestCase.config().set(InfrastructureDeploymentTestCase.DEPLOYMENT_LOCATION_SENSOR_NAME, DEPLOYMENT_LOCATION_SENSOR.getName());
+
+        app.start(ImmutableList.of(loc));
+
+        assertThat(infrastructureDeploymentTestCase.sensors().get(SERVICE_UP)).isTrue();
+        assertThat(infrastructureDeploymentTestCase.getChildren().size()).isEqualTo(2);
+
+        boolean seenInfrastructure = false;
+        boolean seenEntity = false;
+
+        for (Entity entity : infrastructureDeploymentTestCase.getChildren()) {
+            if (entity instanceof BasicApplication) {
+                assertThat(entity.getLocations().size()).isEqualTo(1);
+                assertThat(entity.getLocations().iterator().next().getDisplayName()).isEqualTo(LOC_NAME);
+                assertThat(entity.sensors().get(SERVICE_UP)).isTrue();
+
+                seenInfrastructure = true;
+            } else if (entity instanceof EmptySoftwareProcess) {
+                assertThat(entity.getLocations().size()).isEqualTo(1);
+                assertThat(entity.getLocations().iterator().next().getDisplayName()).isEqualTo(INFRASTRUCTURE_LOC_NAME);
+                assertThat(entity.sensors().get(SERVICE_UP)).isTrue();
+
+                seenEntity = true;
+            } else {
+                fail("Unknown child of InfrastructureDeploymentTestCase");
+            }
+        }
+
+        assertThat(seenInfrastructure).isTrue();
+        assertThat(seenEntity).isTrue();
+    }
+
+    @Test
+    public void testMultipleSpec() {
+        EntitySpec<TestInfrastructure> infrastructureSpec = EntitySpec.create(TestInfrastructure.class);
+        infrastructureSpec.configure(DEPLOYMENT_LOCATION_SENSOR, infrastructureLoc);
+
+        List<EntitySpec<? extends SoftwareProcess>> testSpecs = ImmutableList.<EntitySpec<? extends SoftwareProcess>>of
+                (EntitySpec.create(EmptySoftwareProcess.class),
+                        (EntitySpec.create(EmptySoftwareProcess.class)));
+
+        InfrastructureDeploymentTestCase infrastructureDeploymentTestCase = app.createAndManageChild(EntitySpec.create(InfrastructureDeploymentTestCase.class));
+        infrastructureDeploymentTestCase.config().set(InfrastructureDeploymentTestCase.INFRASTRUCTURE_SPEC, infrastructureSpec);
+        infrastructureDeploymentTestCase.config().set(InfrastructureDeploymentTestCase.ENTITY_SPEC_TO_DEPLOY, testSpecs);
+        infrastructureDeploymentTestCase.config().set(InfrastructureDeploymentTestCase.DEPLOYMENT_LOCATION_SENSOR_NAME, DEPLOYMENT_LOCATION_SENSOR.getName());
+
+        app.start(ImmutableList.of(loc));
+
+        assertThat(infrastructureDeploymentTestCase.sensors().get(SERVICE_UP)).isTrue();
+        assertThat(infrastructureDeploymentTestCase.getChildren().size()).isEqualTo(3);
+
+        boolean seenInfrastructure = false;
+        int entitiesSeen = 0;
+
+        for (Entity entity : infrastructureDeploymentTestCase.getChildren()) {
+            if (entity instanceof BasicApplication) {
+                assertThat(entity.getLocations().size()).isEqualTo(1);
+                assertThat(entity.getLocations().iterator().next().getDisplayName()).isEqualTo(LOC_NAME);
+                assertThat(entity.sensors().get(SERVICE_UP)).isTrue();
+
+                seenInfrastructure = true;
+            } else if (entity instanceof EmptySoftwareProcess) {
+                assertThat(entity.getLocations().size()).isEqualTo(1);
+                assertThat(entity.getLocations().iterator().next().getDisplayName()).isEqualTo(INFRASTRUCTURE_LOC_NAME);
+                assertThat(entity.sensors().get(SERVICE_UP)).isTrue();
+
+                entitiesSeen++;
+            } else {
+                fail("Unknown child of InfrastructureDeploymentTestCase");
+            }
+        }
+
+        assertThat(seenInfrastructure).isTrue();
+        assertThat(entitiesSeen).isEqualTo(2);
+    }
+
+    @Test
+    public void testNoInfrastructureSpec() {
+        List<EntitySpec<? extends SoftwareProcess>> testSpecs = ImmutableList.<EntitySpec<? extends SoftwareProcess>>of(EntitySpec.create(EmptySoftwareProcess.class));
+
+        InfrastructureDeploymentTestCase infrastructureDeploymentTestCase = app.createAndManageChild(EntitySpec.create(InfrastructureDeploymentTestCase.class));
+        infrastructureDeploymentTestCase.config().set(InfrastructureDeploymentTestCase.ENTITY_SPEC_TO_DEPLOY, testSpecs);
+        infrastructureDeploymentTestCase.config().set(InfrastructureDeploymentTestCase.DEPLOYMENT_LOCATION_SENSOR_NAME, DEPLOYMENT_LOCATION_SENSOR.getName());
+
+        try {
+            app.start(ImmutableList.of(app.newSimulatedLocation()));
+            fail("Should have thrown execption");
+        } catch (Throwable throwable) {
+            Throwable firstInteresting = Exceptions.getFirstInteresting(throwable);
+            assertThat(firstInteresting).isNotNull();
+            assertThat(throwable).isNotNull();
+            assertThat(firstInteresting).isInstanceOf(IllegalArgumentException.class);
+        }
+
+        assertThat(infrastructureDeploymentTestCase.sensors().get(SERVICE_UP)).isFalse();
+    }
+
+    @Test
+    public void testNoEntitySpec() {
+        EntitySpec<TestInfrastructure> infrastructureSpec = EntitySpec.create(TestInfrastructure.class);
+        infrastructureSpec.configure(DEPLOYMENT_LOCATION_SENSOR, infrastructureLoc);
+
+        InfrastructureDeploymentTestCase infrastructureDeploymentTestCase = app.createAndManageChild(EntitySpec.create(InfrastructureDeploymentTestCase.class));
+        infrastructureDeploymentTestCase.config().set(InfrastructureDeploymentTestCase.INFRASTRUCTURE_SPEC, infrastructureSpec);
+        infrastructureDeploymentTestCase.config().set(InfrastructureDeploymentTestCase.DEPLOYMENT_LOCATION_SENSOR_NAME, DEPLOYMENT_LOCATION_SENSOR.getName());
+
+        try {
+            app.start(ImmutableList.of(app.newSimulatedLocation()));
+            fail("Should have thrown execption");
+        } catch (Throwable throwable) {
+            Throwable firstInteresting = Exceptions.getFirstInteresting(throwable);
+            assertThat(firstInteresting).isNotNull();
+            assertThat(throwable).isNotNull();
+            assertThat(firstInteresting).isInstanceOf(IllegalArgumentException.class);
+        }
+
+        assertThat(infrastructureDeploymentTestCase.sensors().get(SERVICE_UP)).isFalse();
+    }
+
+    @Test
+    public void testNoDeploymentLocation() {
+        EntitySpec<TestInfrastructure> infrastructureSpec = EntitySpec.create(TestInfrastructure.class);
+        infrastructureSpec.configure(DEPLOYMENT_LOCATION_SENSOR, infrastructureLoc);
+
+        List<EntitySpec<? extends SoftwareProcess>> testSpecs = ImmutableList.<EntitySpec<? extends SoftwareProcess>>of(EntitySpec.create(EmptySoftwareProcess.class));
+
+        InfrastructureDeploymentTestCase infrastructureDeploymentTestCase = app.createAndManageChild(EntitySpec.create(InfrastructureDeploymentTestCase.class));
+        infrastructureDeploymentTestCase.config().set(InfrastructureDeploymentTestCase.INFRASTRUCTURE_SPEC, infrastructureSpec);
+        infrastructureDeploymentTestCase.config().set(InfrastructureDeploymentTestCase.ENTITY_SPEC_TO_DEPLOY, testSpecs);
+
+        try {
+            app.start(ImmutableList.of(app.newSimulatedLocation()));
+            fail("Should have thrown execption");
+        } catch (Throwable throwable) {
+            Throwable firstInteresting = Exceptions.getFirstInteresting(throwable);
+            assertThat(firstInteresting).isNotNull();
+            assertThat(throwable).isNotNull();
+            assertThat(firstInteresting).isInstanceOf(IllegalArgumentException.class);
+        }
+
+        assertThat(infrastructureDeploymentTestCase.sensors().get(SERVICE_UP)).isFalse();
+    }
+
+    @Test
+    public void testInfrastrucutreHasNoLocation() {
+        EntitySpec<TestInfrastructure> infrastructureSpec = EntitySpec.create(TestInfrastructure.class);
+
+        List<EntitySpec<? extends SoftwareProcess>> testSpecs = ImmutableList.<EntitySpec<? extends SoftwareProcess>>of(EntitySpec.create(EmptySoftwareProcess.class));
+
+        InfrastructureDeploymentTestCase infrastructureDeploymentTestCase = app.createAndManageChild(EntitySpec.create(InfrastructureDeploymentTestCase.class));
+        infrastructureDeploymentTestCase.config().set(InfrastructureDeploymentTestCase.INFRASTRUCTURE_SPEC, infrastructureSpec);
+        infrastructureDeploymentTestCase.config().set(InfrastructureDeploymentTestCase.ENTITY_SPEC_TO_DEPLOY, testSpecs);
+        infrastructureDeploymentTestCase.config().set(InfrastructureDeploymentTestCase.DEPLOYMENT_LOCATION_SENSOR_NAME, DEPLOYMENT_LOCATION_SENSOR.getName());
+
+        try {
+            app.start(ImmutableList.of(app.newSimulatedLocation()));
+            fail("Should have thrown execption");
+        } catch (Throwable throwable) {
+            Throwable firstInteresting = Exceptions.getFirstInteresting(throwable);
+            assertThat(firstInteresting).isNotNull();
+            assertThat(throwable).isNotNull();
+            assertThat(firstInteresting).isInstanceOf(IllegalArgumentException.class);
+        }
+
+        assertThat(infrastructureDeploymentTestCase.sensors().get(SERVICE_UP)).isFalse();
+    }
+}


[3/6] incubator-brooklyn git commit: Added new components to documentation

Posted by he...@apache.org.
Added new components to documentation


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

Branch: refs/heads/master
Commit: 25ead1d8ec357e0ea40aca4c36481f62097eaf15
Parents: 74a2248
Author: Graeme-Miller <gr...@cloudsoftcorp.com>
Authored: Tue Dec 22 14:37:05 2015 +0000
Committer: Graeme-Miller <gr...@cloudsoftcorp.com>
Committed: Thu Jan 7 16:44:40 2016 +0000

----------------------------------------------------------------------
 brooklyn-docs/guide/yaml/test/index.md          |  8 +++--
 brooklyn-docs/guide/yaml/test/test-entities.md  | 33 ++++++++++++++++++--
 ...infrastructuredeploymenttestcase-entity.yaml | 11 +++++++
 .../entities/loopovergroupmembers-entity.yaml   |  6 ++++
 4 files changed, 53 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/25ead1d8/brooklyn-docs/guide/yaml/test/index.md
----------------------------------------------------------------------
diff --git a/brooklyn-docs/guide/yaml/test/index.md b/brooklyn-docs/guide/yaml/test/index.md
index ae7f818..02482b7 100644
--- a/brooklyn-docs/guide/yaml/test/index.md
+++ b/brooklyn-docs/guide/yaml/test/index.md
@@ -6,20 +6,24 @@ children:
 - usage-examples.md
 ---
 
-Brooklyn provides a selection of basic test entities which can be used to validate Blueprints via YAML. These are divided into two groups; structural, which effect the order in which child entities are started; and validation, which are used to confirm the application is deployed as intended.
+Brooklyn provides a selection of test entities which can be used to validate Blueprints via YAML. The basic building block is a TargetableTestComponent, which is used to resolve a target. There are two different groups of entities that inherit from TargetableTestComponent. The first is structural, which effects how the tests are run, for example by affecting the order they are run in. The second group is validation, which is used to confirm the application is deployed as intended, for example by checking some sensor value.
 
 Structural test entities include:
 
 - `TestCase`  - starts child entities sequentially.
 - `ParallelTestCase` - starts child entities in parallel.
+- `LoopOverGroupMembersTestCase` - creates a TargetableTestComponent for each member of a group.
+- `InfrastructureDeploymentTestCase` - will create the specified Infrastructure and then deploy the target entity specifications there.
 
 Validation test entities include:
 
 - `TestSensor` - perform assertion on a specified sensor.
-- `TestEffector` - invoke effector on specified target entity.
+- `TestEffector` - perform assertion on response to effector call.
 - `TestHttpCall` - perform assertion on response to specified HTTP GET Request.
 - `SimpleShellCommandTest` - test assertions on the result of a shell command on the same node as the target entity.
 
+TargetableTestComponents can be chained together, with the target being inherited by the components children. For example, a ParallelTestCase could be created that has a TestHttpCall as a child. As long as the TestHttpCall itself does not have a target, it will use the target of it's parent, ParallelTestCase. Using this technique, we can build up complex test scenarios.
+
 The following sections provide details on each test entity along with examples of their use.
 
 {% include list-children.html %}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/25ead1d8/brooklyn-docs/guide/yaml/test/test-entities.md
----------------------------------------------------------------------
diff --git a/brooklyn-docs/guide/yaml/test/test-entities.md b/brooklyn-docs/guide/yaml/test/test-entities.md
index f8eb087..a81a3d6 100644
--- a/brooklyn-docs/guide/yaml/test/test-entities.md
+++ b/brooklyn-docs/guide/yaml/test/test-entities.md
@@ -33,6 +33,32 @@ This can be used to run a subset of entities in parallel as a single step when n
 
 Timeouts on child entities should be set relative to the start of the `ParallelTestCase`.
 
+### LoopOverGroupMembersTestCase
+The `LoopOverGroupMembersTestCase` entity is configured with a target group and a test specification. For each member of the targeted group, the test case will create a TargetableTestComponent entity from the supplied test specification and set the components target to be the group member.
+
+{% highlight yaml %}
+{% readj example_yaml/entities/loopovergroupmembers-entity.yaml %}
+{% endhighlight %}
+
+#### Parameters
+- `target` - group who's members are to be tested, specified via DSL. For example, `$brooklyn:component("tomcat")`. See also the `targetId` parameter.
+- `targetId` - alternative to the `target` parameter which wraps the DSL component lookup requiring only the `id` be supplied. For example, `tomcat`. Please note, this must point to a group.
+- `test.spec` - The TargetableTestComponent to create for each child.
+
+
+### InfrastructureDeploymentTestCase
+The `InfrastructureDeploymentTestCase` will first create and deploy an infrastructure from the `infrastructure.deployment.spec` config. It will then retrieve a deployment location by getting the value of the infrastructures `infrastructure.deployment.location.sensor` sensor. It will then create and deploy all entities from the `infrastructure.deployment.spec` config to the deployment location.
+
+{% highlight yaml %}
+{% readj example_yaml/entities/infrastructuredeploymenttestcase-entity.yaml %}
+{% endhighlight %}
+
+#### Parameters
+
+- `infrastructure.deployment.spec` - the infrastructure to be deployed.
+- `infrastructure.deployment.entity.specs` - the entities to be deployed to the infrastructure
+- `infrastructure.deployment.location.sensor` - the name of the sensor on the infrastructure to retrieve the deployment location
+
 ## Validation Test Entities
 
 ### TestSensor
@@ -50,7 +76,7 @@ The `TestSensor` entity performs an assertion on a specified sensors value.
 - `assert` - assertion to perform on the specified sensor value. See section on assertions below.
 
 ### TestEffector
-The `TestEffector` entity invokes the specified effector on a target entity.
+The `TestEffector` entity invokes the specified effector on a target entity. If the result of the effector is a String, it will then perform assertions on the result.
 {% highlight yaml %}
 {% readj example_yaml/entities/testeffector-entity.yaml %}
 {% endhighlight %}
@@ -61,6 +87,7 @@ The `TestEffector` entity invokes the specified effector on a target entity.
 - `timeout` - duration to wait on the effector task to complete. For example `10s`, `10m`, etc
 - `effector` - effector to invoke, for example `deploy`.
 - `params` - parameters to pass to the effector, these will depend on the entity and effector being tested. The example above shows the `url` and `targetName` parameters being passed to Tomcats `deploy` effector.
+- `assert` - assertion to perform on the returned result. See section on assertions below.
 
 ### TestHttpCall
 The `TestHttpCall` entity performs a HTTP GET on the specified URL and performs an assertion on the response.
@@ -77,7 +104,7 @@ The `TestHttpCall` entity performs a HTTP GET on the specified URL and performs
 ### SimpleShellCommandTest
 
 The SimpleShellCommandTest runs a command on the host of the target entity.
-The script is expected not to run indefinitely, but to return a result (process exit code), along with its 
+The script is expected not to run indefinitely, but to return a result (process exit code), along with its
 standard out and error streams, which can then be tested using assertions.
 If no assertions are explicitly configured, the default is to assert a non-zero exit code.
 
@@ -119,7 +146,7 @@ Assertions may be provided as a simple map:
        matches: .*[\d]* days.*
 ```
 
-If there is the need to make multiple assertions with the same key, the assertions can be specified 
+If there is the need to make multiple assertions with the same key, the assertions can be specified
 as a list of such maps:
 
 ```yaml

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/25ead1d8/docs/guide/yaml/test/example_yaml/entities/infrastructuredeploymenttestcase-entity.yaml
----------------------------------------------------------------------
diff --git a/docs/guide/yaml/test/example_yaml/entities/infrastructuredeploymenttestcase-entity.yaml b/docs/guide/yaml/test/example_yaml/entities/infrastructuredeploymenttestcase-entity.yaml
new file mode 100644
index 0000000..6b344da
--- /dev/null
+++ b/docs/guide/yaml/test/example_yaml/entities/infrastructuredeploymenttestcase-entity.yaml
@@ -0,0 +1,11 @@
+- type: org.apache.brooklyn.test.framework.InfrastructureDeploymentTestCase
+  brooklyn.config:
+    infrastructure.deployment.location.sensor: entity.dynamicLocation
+    infrastructure.deployment.spec:
+      $brooklyn:entitySpec:
+        - type: docker-cloud-calico
+          ...
+    infrastructure.deployment.entity.specs:
+      - $brooklyn:entitySpec:
+          type: org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess
+          ...
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/25ead1d8/docs/guide/yaml/test/example_yaml/entities/loopovergroupmembers-entity.yaml
----------------------------------------------------------------------
diff --git a/docs/guide/yaml/test/example_yaml/entities/loopovergroupmembers-entity.yaml b/docs/guide/yaml/test/example_yaml/entities/loopovergroupmembers-entity.yaml
new file mode 100644
index 0000000..e97ab4c
--- /dev/null
+++ b/docs/guide/yaml/test/example_yaml/entities/loopovergroupmembers-entity.yaml
@@ -0,0 +1,6 @@
+- type: org.apache.brooklyn.test.framework.LoopOverGroupMembersTestCase
+  target: $brooklyn:component("infrastructure").component("child", "DockerHosts")
+  testSpec:
+    $brooklyn:entitySpec:
+      type: org.apache.brooklyn.test.framework.TestSensor
+      ...
\ No newline at end of file