You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2015/11/11 18:21:32 UTC

[05/21] incubator-brooklyn git commit: Moved sandbox/brooklyn-sandbox-test-framework to usage/test-framework

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/813bba02/usage/test-framework/etc/exampl-catalog.bom
----------------------------------------------------------------------
diff --git a/usage/test-framework/etc/exampl-catalog.bom b/usage/test-framework/etc/exampl-catalog.bom
new file mode 100644
index 0000000..ab7e54b
--- /dev/null
+++ b/usage/test-framework/etc/exampl-catalog.bom
@@ -0,0 +1,15 @@
+brooklyn.catalog:
+  id: simple-tomcat
+  version: 1.0
+  itemType: template
+  iconUrl: http://tomcat.apache.org/images/tomcat.png
+  name: Simple Tomcat
+  license: Apache-2.0
+  item:
+    brooklyn.config:
+      simple.confg: someValue
+    services:
+    - type: org.apache.brooklyn.entity.webapp.tomcat.TomcatServer
+      id: tomcat
+      name: Tomcat
+      war: https://tomcat.apache.org/tomcat-6.0-doc/appdev/sample/sample.war
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/813bba02/usage/test-framework/etc/example-catalog-test.bom
----------------------------------------------------------------------
diff --git a/usage/test-framework/etc/example-catalog-test.bom b/usage/test-framework/etc/example-catalog-test.bom
new file mode 100644
index 0000000..0605f9d
--- /dev/null
+++ b/usage/test-framework/etc/example-catalog-test.bom
@@ -0,0 +1,22 @@
+brooklyn.catalog:
+  id: simple-tomcat-test
+  version: 1.0
+  itemType: template
+  iconUrl: http://tomcat.apache.org/images/tomcat.png
+  name: Simple Tomcat Test
+  license: Apache-2.0
+  item:
+    brooklyn.config:
+      simple.confg: someValue
+    services:
+    - type: org.apache.brooklyn.test.framework.TestCase
+      name: Simple Tomcat Tests
+      brooklyn.children:
+      - type: simple-tomcat
+        id: tomcat
+      - type: org.apache.brooklyn.test.framework.TestSensor
+        target: $brooklyn:component("tomcat")
+        sensor: service.isUp
+        timeout: 10m
+        assert:
+          equals: true
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/813bba02/usage/test-framework/etc/nginx-test-examples.yml
----------------------------------------------------------------------
diff --git a/usage/test-framework/etc/nginx-test-examples.yml b/usage/test-framework/etc/nginx-test-examples.yml
new file mode 100644
index 0000000..f1711ea
--- /dev/null
+++ b/usage/test-framework/etc/nginx-test-examples.yml
@@ -0,0 +1,98 @@
+---
+# 1. Start an nginx
+# 2. Test it is running
+# 3. Stop it
+# 4. Test it stopped
+# Note there are two alternative forms to look up target - either just provide the 'targetId' to do an implicit DSL lookup,
+# or look it up with explicit DSL and provide it as 'target'.
+name: NGINX Test
+location: localhost
+services:
+- type: org.apache.brooklyn.test.framework.TestCase
+  name: Stop Test
+  brooklyn.children:
+  - type: org.apache.brooklyn.entity.proxy.nginx.NginxController
+    id: nginx1
+  - type: org.apache.brooklyn.test.framework.TestSensor
+    target: $brooklyn:component("nginx1")
+    sensor: service.isUp
+    equals: true
+    timeout: 5m
+  - type: org.apache.brooklyn.test.framework.TestEffector
+    target: $brooklyn:component("nginx1")
+    effector: stop
+  - type: org.apache.brooklyn.test.framework.TestSensor
+    target: $brooklyn:component("nginx1")
+    sensor: service.isUp
+    assert:
+      equals: false
+...
+
+---
+name: NGINX Test
+location: localhost
+services:
+- type: org.apache.brooklyn.test.framework.TestCase
+  name: Stop Test
+  targetId: nginx1
+  brooklyn.children:
+  - type: org.apache.brooklyn.entity.proxy.nginx.NginxController
+    id: nginx1
+  - type: org.apache.brooklyn.test.framework.TestSensor
+    sensor: service.isUp
+    equals: true
+    timeout: 5m
+  - type: org.apache.brooklyn.test.framework.TestEffector
+    effector: stop
+  - type: org.apache.brooklyn.test.framework.TestSensor
+    sensor: service.isUp
+    equals: false
+
+
+
+---
+name: NGINX Test
+location: localhost
+services:
+- type: org.apache.brooklyn.test.framework.TestCase
+  name: Stop Test
+  brooklyn.children:
+  - type: org.apache.brooklyn.entity.proxy.nginx.NginxController
+    id: nginx1
+  - type: org.apache.brooklyn.test.framework.TestSensor
+    target: $brooklyn:component("nginx1")
+    sensor: service.isUp
+    timeout: 5m
+    assert:
+      equals: true
+  - type: org.apache.brooklyn.test.framework.TestEffector
+    target: $brooklyn:component("nginx1")
+    effector: stop
+  - type: org.apache.brooklyn.test.framework.TestSensor
+    target: $brooklyn:component("nginx1")
+    sensor: service.isUp
+    assert:
+      equals: false
+      regex: .*
+...
+
+---
+name: NGINX Test
+location: localhost
+services:
+- type: org.apache.brooklyn.entity.proxy.nginx.NginxController
+  id: nginx1
+- type: org.apache.brooklyn.test.framework.TestSensor
+  target: $brooklyn:component("nginx1")
+  sensor: service.isUp
+  timeout: 5m
+  assert:
+    equals: true
+- type: org.apache.brooklyn.test.framework.TestSensor
+  name: Test Regex
+  target: $brooklyn:component("nginx1")
+  sensor: service.isUp
+  timeout: 5m
+  assert:
+    regex: .*
+...
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/813bba02/usage/test-framework/etc/testhttpcall-examples.yml
----------------------------------------------------------------------
diff --git a/usage/test-framework/etc/testhttpcall-examples.yml b/usage/test-framework/etc/testhttpcall-examples.yml
new file mode 100644
index 0000000..a418fd8
--- /dev/null
+++ b/usage/test-framework/etc/testhttpcall-examples.yml
@@ -0,0 +1,124 @@
+---
+name: Basic HTTP Call Tests
+location: localhost
+services:
+- type: org.apache.brooklyn.test.framework.TestCase
+  brooklyn.children:
+  - type: org.apache.brooklyn.entity.webapp.tomcat.TomcatServer
+    id: tomcat
+    brooklyn.config:
+      war: "http://search.maven.org/remotecontent?filepath=io/brooklyn/example/brooklyn-example-hello-world-sql-webapp/0.6.0/brooklyn-example-hello-world-sql-webapp-0.6.0.war"
+  - type: org.apache.brooklyn.test.framework.TestHttpCall
+    name: Status Code 200
+    url: $brooklyn:component("tomcat").attributeWhenReady("webapp.url")
+    assert:
+      status: 200
+  - type: org.apache.brooklyn.test.framework.TestHttpCall
+    name: Status Code 404
+    url: $brooklyn:formatString("%s/invalidpath/", component("tomcat").attributeWhenReady("webapp.url"))
+    timeout: 10s
+    assert:
+      status: 404
+  - type: org.apache.brooklyn.test.framework.TestHttpCall
+    name: String match
+    url: $brooklyn:component("tomcat").attributeWhenReady("webapp.url")
+    assert:
+      string: Sample Brooklyn Deployed
+  - type: org.apache.brooklyn.test.framework.TestHttpCall
+    name: Regex match
+    url: $brooklyn:component("tomcat").attributeWhenReady("webapp.url")
+    # the regex assert uses java.lang.String under the hood so if the url is expected to returns
+    # a multi-line response you should use the embedded dotall flag expression `(?s)` in your regex.
+    # See: http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html
+    assert:
+      regex: "(?s).*illustrate(\\s)*how(\\s)*web(\\s)*applications.*"
+...
+
+---
+name: HTTP Call Test with Effector
+location: localhost
+services:
+- type: org.apache.brooklyn.test.framework.TestCase
+  brooklyn.children:
+  - type: org.apache.brooklyn.entity.webapp.tomcat.TomcatServer
+    id: tomcat
+    brooklyn.config:
+      war: "http://search.maven.org/remotecontent?filepath=io/brooklyn/example/brooklyn-example-hello-world-sql-webapp/0.6.0/brooklyn-example-hello-world-sql-webapp-0.6.0.war"
+  - type: org.apache.brooklyn.test.framework.TestHttpCall
+    name: / Status Code 200
+    url: $brooklyn:component("tomcat").attributeWhenReady("webapp.url")
+    assert:
+      status: 200
+  - type: org.apache.brooklyn.test.framework.TestHttpCall
+    name: /newcontext Status Code 404
+    url: $brooklyn:formatString("%s/newcontext/", component("tomcat").attributeWhenReady("webapp.url"))
+    assert:
+      status: 404
+  - type: org.apache.brooklyn.test.framework.TestEffector
+    name: Deploy WAR in /newcontext
+    target: $brooklyn:component("tomcat")
+    effector: deploy
+    params:
+      url: http://search.maven.org/remotecontent?filepath=io/brooklyn/example/brooklyn-example-hello-world-sql-webapp/0.6.0/brooklyn-example-hello-world-sql-webapp-0.6.0.war
+      targetName: newcontext
+  - type: org.apache.brooklyn.test.framework.TestHttpCall
+    name: /newcontext Status Code 200
+    url: $brooklyn:formatString("%s/newcontext/", component("tomcat").attributeWhenReady("webapp.url"))
+    # Give Tomcat time to make the newly deployed War accessible
+    timeout: 10s
+    assert:
+      status: 200
+...
+
+---
+name: HTTP Call Test with Eventual String and Regex Matches
+location: localhost
+services:
+- type: org.apache.brooklyn.test.framework.TestCase
+  brooklyn.children:
+  - type: org.apache.brooklyn.entity.webapp.tomcat.TomcatServer
+    id: tomcat
+    brooklyn.config:
+      war: "http://search.maven.org/remotecontent?filepath=io/brooklyn/example/brooklyn-example-hello-world-sql-webapp/0.6.0/brooklyn-example-hello-world-sql-webapp-0.6.0.war"
+  - type: org.apache.brooklyn.test.framework.TestEffector
+    name: Deploy WAR in /newcontext
+    target: $brooklyn:component("tomcat")
+    effector: deploy
+    params:
+      url: http://search.maven.org/remotecontent?filepath=io/brooklyn/example/brooklyn-example-hello-world-sql-webapp/0.6.0/brooklyn-example-hello-world-sql-webapp-0.6.0.war
+      targetName: newcontext
+  - type: org.apache.brooklyn.test.framework.TestHttpCall
+    name: Regex match
+    url: $brooklyn:formatString("%s/newcontext/", component("tomcat").attributeWhenReady("webapp.url"))
+    timeout: 10s
+    assert:
+      regex: "(?s).*illustrate(\\s)*how(\\s)*web(\\s)*applications.*"
+  - type: org.apache.brooklyn.test.framework.TestEffector
+    name: Deploy WAR in /newcontext2
+    target: $brooklyn:component("tomcat")
+    effector: deploy
+    params:
+      url: http://search.maven.org/remotecontent?filepath=io/brooklyn/example/brooklyn-example-hello-world-sql-webapp/0.6.0/brooklyn-example-hello-world-sql-webapp-0.6.0.war
+      targetName: newcontext2
+  - type: org.apache.brooklyn.test.framework.TestHttpCall
+    name: String match
+    url: $brooklyn:formatString("%s/newcontext2/", component("tomcat").attributeWhenReady("webapp.url"))
+    timeout: 10s
+    assert:
+      string: Sample Brooklyn Deployed
+    assert:
+      status: 404
+  - type: org.apache.brooklyn.test.framework.TestHttpCall
+    name: String match
+    url: $brooklyn:component("tomcat").attributeWhenReady("webapp.url")
+    assert:
+      string: Sample Brooklyn Deployed
+  - type: org.apache.brooklyn.test.framework.TestHttpCall
+    name: Regex match
+    url: $brooklyn:component("tomcat").attributeWhenReady("webapp.url")
+    # the regex assert uses java.lang.String under the hood so if the url is expected to returns
+    # a multi-line response you should use the embedded dotall flag expression `(?s)` in your regex.
+    # See: http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html
+    assert:
+      regex: "(?s).*illustrate(\\s)*how(\\s)*web(\\s)*applications.*"
+...
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/813bba02/usage/test-framework/etc/tomcat-test-examples.yml
----------------------------------------------------------------------
diff --git a/usage/test-framework/etc/tomcat-test-examples.yml b/usage/test-framework/etc/tomcat-test-examples.yml
new file mode 100644
index 0000000..37d7f4d
--- /dev/null
+++ b/usage/test-framework/etc/tomcat-test-examples.yml
@@ -0,0 +1,45 @@
+---
+name: Tomcat Multi-War Test
+location: localhost
+services:
+- type: org.apache.brooklyn.entity.webapp.tomcat.TomcatServer
+  id: tomcat
+  name: Tomcat
+  brooklyn.config:
+    wars.by.context:
+      hello1: "http://search.maven.org/remotecontent?filepath=io/brooklyn/example/brooklyn-example-hello-world-sql-webapp/0.6.0/brooklyn-example-hello-world-sql-webapp-0.6.0.war"
+      hello2: "http://search.maven.org/remotecontent?filepath=io/brooklyn/example/brooklyn-example-hello-world-sql-webapp/0.6.0/brooklyn-example-hello-world-sql-webapp-0.6.0.war"
+    start.timeout: 10m
+- type: org.apache.brooklyn.test.framework.TestSensor
+  target: $brooklyn:component("tomcat")
+  sensor: service.isUp
+  assert:
+    equals: true
+  timeout: 10m
+...
+
+---
+name: Tomcat Tests
+location: BYON 1
+services:
+  - type: org.apache.brooklyn.test.framework.TestCase
+    name: Effector - Deploy Test
+    brooklyn.children:
+    - type: org.apache.brooklyn.entity.webapp.tomcat.TomcatServer
+      id: tomcat
+      name: Tomcat
+      war: https://tomcat.apache.org/tomcat-6.0-doc/appdev/sample/sample.war
+    - type: org.apache.brooklyn.test.framework.TestEffector
+      name: Deploy Another WAR
+      target: $brooklyn:component("tomcat")
+      effector: deploy
+      params:
+        url: https://tomcat.apache.org/tomcat-6.0-doc/appdev/sample/sample.war
+        targetName: sample1
+#    - type: org.apache.brooklyn.test.framework.TestSensor
+#      target: $brooklyn:component("tomcat")
+#      sensor: webapp.deployedWars
+#      assert:
+#        regex: .*sample1.*
+#      timeout: 1m
+...
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/813bba02/usage/test-framework/pom.xml
----------------------------------------------------------------------
diff --git a/usage/test-framework/pom.xml b/usage/test-framework/pom.xml
new file mode 100644
index 0000000..5606a8d
--- /dev/null
+++ b/usage/test-framework/pom.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>brooklyn</artifactId>
+        <groupId>org.apache.brooklyn</groupId>
+        <version>0.9.0-SNAPSHOT</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>test-framework</artifactId>
+    <name>Brooklyn Test Framework</name>
+
+    <properties>
+        <assertj.version>3.2.0</assertj.version>
+    </properties>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.apache.brooklyn</groupId>
+            <artifactId>brooklyn-core</artifactId>
+            <version>${brooklyn.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.brooklyn</groupId>
+            <artifactId>brooklyn-camp</artifactId>
+            <version>${brooklyn.version}</version>
+        </dependency>
+
+        <!--TEST SCOPE :: START-->
+        <dependency>
+            <groupId>org.testng</groupId>
+            <artifactId>testng</artifactId>
+            <version>${testng.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.brooklyn</groupId>
+            <artifactId>brooklyn-test-support</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.brooklyn</groupId>
+            <artifactId>brooklyn-core</artifactId>
+            <version>${brooklyn.version}</version>
+            <scope>test</scope>
+            <classifier>tests</classifier>
+        </dependency>
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+            <version>${assertj.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <!--TEST SCOPE :: END-->
+        
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.3</version>
+                <configuration>
+                    <source>${java.version}</source>
+                    <target>${java.version}</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/813bba02/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/AbstractTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/AbstractTest.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/AbstractTest.java
new file mode 100644
index 0000000..2194286
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/AbstractTest.java
@@ -0,0 +1,50 @@
+package org.apache.brooklyn.test.framework;
+
+import org.apache.brooklyn.api.entity.Entity;
+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() {
+        Entity entity = getConfig(TARGET_ENTITY);
+        if (null == entity) {
+            entity = getTargetById();
+        }
+        return entity;
+    }
+
+    private Entity getTargetById() {
+        String targetId = getConfig(TARGET_ID);
+        final Task<Entity> targetLookup = new DslComponent(targetId).newTask();
+        Entity entity = null;
+        try {
+            entity = Tasks.resolveValue(targetLookup, Entity.class, getExecutionContext(), "Finding entity " + targetId);
+            LOG.debug("Found target by id {}", targetId);
+        } catch (final ExecutionException | InterruptedException e) {
+            LOG.error("Error finding target {}", targetId);
+            Exceptions.propagate(e);
+        }
+        return entity;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/813bba02/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/BaseTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/BaseTest.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/BaseTest.java
new file mode 100644
index 0000000..b0f347d
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/BaseTest.java
@@ -0,0 +1,34 @@
+package org.apache.brooklyn.test.framework;
+
+import org.apache.brooklyn.api.entity.Entity;
+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;
+
+/**
+ *  A base interface for all tests.
+ */
+public interface BaseTest extends Entity, Startable {
+
+    /**
+     * The target entity to test (optional, use either this or targetId).
+     */
+    @SetFromFlag(nullable = false)
+    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).
+     */
+    @SetFromFlag(nullable = false)
+    ConfigKey<String> TARGET_ID = ConfigKeys.newStringConfigKey("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/813bba02/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/ParallelTestCase.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/ParallelTestCase.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/ParallelTestCase.java
new file mode 100644
index 0000000..b5dc1ea
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/ParallelTestCase.java
@@ -0,0 +1,13 @@
+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;
+
+/**
+ * 
+ * @author Chris Burke
+ */
+@ImplementedBy(value = ParallelTestCaseImpl.class)
+public interface ParallelTestCase extends Entity, Startable {
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/813bba02/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/ParallelTestCaseImpl.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/ParallelTestCaseImpl.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/ParallelTestCaseImpl.java
new file mode 100644
index 0000000..67e972a
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/ParallelTestCaseImpl.java
@@ -0,0 +1,130 @@
+package org.apache.brooklyn.test.framework;
+
+import java.util.Collection;
+import java.util.concurrent.ExecutionException;
+
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.mgmt.Task;
+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 {
+
+    private static final Logger logger = LoggerFactory.getLogger(ParallelTestCaseImpl.class);
+
+    /**
+     * {@inheritDoc}
+     */
+    public void start(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);
+        try {
+            // Get an unsubmitted task for starting all the children of this entity in parallel,
+            // at the same location as this entity.
+            final TaskAdaptable<?> taskAdaptable = StartableMethods.startingChildren(this);
+            logger.trace("{}, TaskAdaptable: {}", this, taskAdaptable);
+
+            // Submit the task to the ExecutionManager so that they actually get started
+            // and then wait until all the parallel child entities have completed.
+            submitTaskAndWait(taskAdaptable);
+
+            // 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);
+        } 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);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    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);
+
+        // Get an unsubmitted task for stopping all the children of this entity in parallel.
+        final TaskAdaptable<?> taskAdaptable = StartableMethods.stoppingChildren(this);
+        logger.trace("{}, TaskAdaptable: {}", this, taskAdaptable);
+        try {
+            // Submit the task to the ExecutionManager so that they actually get stopped
+            // and then wait until all the parallel entities have completed.
+            submitTaskAndWait(taskAdaptable);
+            // 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);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void restart() {
+        // Let everyone know we're restarting (so that the GUI shows the correct icon).
+        setServiceState(false, Lifecycle.STARTING);
+
+        // Get an unsubmitted task for restarting all the children of this entity in parallel.
+        final TaskAdaptable<?> taskAdaptable = StartableMethods.restartingChildren(this);
+        logger.trace("{}, TaskAdaptable: {}", this, taskAdaptable);
+
+        try {
+            // Submit the task to the ExecutionManager so that they actually get stopped
+            // and then wait until all the parallel entities have completed.
+            submitTaskAndWait(taskAdaptable);
+
+            // 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);
+        } 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);
+        }
+    }
+
+    /**
+     * Submits the task to the ExecutionManager and then waits until the task has completed.
+     * 
+     * @param taskAdaptable the TaskAdaptable to submit for execution.
+     * @throws ExecutionException if the task threw an exception
+     * @throws InterruptedException if the current thread was interrupted while waiting
+     */
+    private void submitTaskAndWait(final TaskAdaptable<?> taskAdaptable)
+            throws InterruptedException, ExecutionException {
+        logger.debug("{}, Submitting taskAdaptable: {}", this, taskAdaptable);
+        // Submit the task to the ExecutionManager.
+        final Task<?> task = DynamicTasks.submit(taskAdaptable, this);
+
+        // Block until the task has completed.
+        logger.debug("{}, Blocking until task complete.", this);
+        task.blockUntilEnded();
+        logger.debug("{}, Task complete.", this);
+
+        // Get the result of the task. We don't really care about the
+        // actual result but this will throw an exception if the task failed.
+        task.get();
+    }
+
+    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/813bba02/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java
new file mode 100644
index 0000000..6d2ae11
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java
@@ -0,0 +1,12 @@
+package org.apache.brooklyn.test.framework;
+
+import org.apache.brooklyn.api.entity.ImplementedBy;
+
+/**
+ * Entity that logically groups other test entities
+ *
+ * @author m4rkmckenna
+ */
+@ImplementedBy(value = TestCaseImpl.class)
+public interface TestCase extends BaseTest {
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/813bba02/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCaseImpl.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCaseImpl.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCaseImpl.java
new file mode 100644
index 0000000..1b443fb
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCaseImpl.java
@@ -0,0 +1,61 @@
+package org.apache.brooklyn.test.framework;
+
+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;
+import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
+import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+
+import java.util.Collection;
+
+/**
+ * {@inheritDoc}
+ */
+public class TestCaseImpl extends AbstractTest implements TestCase {
+
+    /**
+     * {@inheritDoc}
+     */
+    public void start(Collection<? extends Location> locations) {
+        ServiceStateLogic.setExpectedState(this, Lifecycle.STARTING);
+        try {
+            for (final Entity childEntity : getChildren()) {
+                if (childEntity instanceof Startable) ((Startable) childEntity).start(locations);
+            }
+            sensors().set(SERVICE_UP, true);
+            ServiceStateLogic.setExpectedState(this, Lifecycle.RUNNING);
+        } catch (Throwable t) {
+            sensors().set(SERVICE_UP, false);
+            ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE);
+            throw Exceptions.propagate(t);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void stop() {
+        ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPING);
+        sensors().set(SERVICE_UP, false);
+        try {
+            for (Entity child : getChildren()) {
+                if (child instanceof Startable) ((Startable) child).stop();
+            }
+            ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPED);
+        } catch (Exception e) {
+            ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE);
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void restart() {
+        final Collection<Location> locations = Lists.newArrayList(getLocations());
+        stop();
+        start(locations);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/813bba02/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEffector.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEffector.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEffector.java
new file mode 100644
index 0000000..e9ec832
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEffector.java
@@ -0,0 +1,33 @@
+package org.apache.brooklyn.test.framework;
+
+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;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+import org.apache.brooklyn.util.core.flags.SetFromFlag;
+import org.apache.brooklyn.util.time.Duration;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Entity that invokes an effector on another entity
+ *
+ * @author m4rkmckenna
+ */
+@ImplementedBy(value = TestEffectorImpl.class)
+public interface TestEffector extends BaseTest {
+
+    @SetFromFlag(nullable = false)
+    ConfigKey<String> EFFECTOR_NAME = ConfigKeys.newConfigKey(String.class, "effector", "The name of the effector to invoke");
+
+    ConfigKey<Map<String, ?>> EFFECTOR_PARAMS = ConfigKeys.newConfigKey(new TypeToken<Map<String, ?>>() {
+    }, "params", "The parameters to pass to the effector", ImmutableMap.<String, Object>of());
+
+    ConfigKey<Duration> TIMEOUT = ConfigKeys.newConfigKey(Duration.class, "timeout", "Time to wait on sensor result", new Duration(5L, TimeUnit.SECONDS));
+
+    AttributeSensorAndConfigKey<Object, Object> EFFECTOR_RESULT = ConfigKeys.newSensorAndConfigKey(Object.class, "result", "The result of invoking the effector");
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/813bba02/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEffectorImpl.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEffectorImpl.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEffectorImpl.java
new file mode 100644
index 0000000..442797e
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEffectorImpl.java
@@ -0,0 +1,91 @@
+package org.apache.brooklyn.test.framework;
+
+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;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
+import org.apache.brooklyn.core.entity.trait.Startable;
+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 {
+    private static final Logger LOG = LoggerFactory.getLogger(TestEffectorImpl.class);
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void start(Collection<? extends Location> locations) {
+        ServiceStateLogic.setExpectedState(this, Lifecycle.STARTING);
+        final Entity targetEntity = resolveTarget();
+        final String effectorName = getConfig(EFFECTOR_NAME);
+        final Map<String, ?> effectorParams = getConfig(EFFECTOR_PARAMS);
+        final Duration timeout = getConfig(TIMEOUT);
+        try {
+            Maybe<Effector<?>> effector = EffectorUtils.findEffectorDeclared(targetEntity, effectorName);
+            if (effector.isAbsentOrNull()) {
+                throw new AssertionError(String.format("No effector with name [%s]", effectorName));
+            }
+            final Task<?> effectorResult;
+            if (effectorParams == null || effectorParams.isEmpty()) {
+                effectorResult = Entities.invokeEffector(this, targetEntity, effector.get());
+            } else {
+                effectorResult = Entities.invokeEffector(this, targetEntity, effector.get(), effectorParams);
+            }
+
+            //Add result of effector to sensor
+            sensors().set(EFFECTOR_RESULT, effectorResult.get(timeout));
+
+            //Start Children
+            for (Entity childEntity : getChildren()) {
+                if (childEntity instanceof Startable) ((Startable) childEntity).start(locations);
+            }
+            sensors().set(SERVICE_UP, true);
+            ServiceStateLogic.setExpectedState(this, Lifecycle.RUNNING);
+        } catch (Throwable t) {
+            sensors().set(SERVICE_UP, false);
+            ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE);
+            throw Exceptions.propagate(t);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void stop() {
+        ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPING);
+        sensors().set(SERVICE_UP, false);
+        try {
+            for (Entity child : getChildren()) {
+                if (child instanceof Startable) ((Startable) child).stop();
+            }
+            ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPED);
+        } catch (Exception e) {
+            ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE);
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void restart() {
+        final Collection<Location> locations = Lists.newArrayList(getLocations());
+        stop();
+        start(locations);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/813bba02/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCall.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCall.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCall.java
new file mode 100644
index 0000000..5dfa1c8
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCall.java
@@ -0,0 +1,33 @@
+package org.apache.brooklyn.test.framework;
+
+import com.google.common.collect.Maps;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.util.core.flags.SetFromFlag;
+import org.apache.brooklyn.util.time.Duration;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Entity that makes a HTTP Request and tests the respose
+ *
+ * @author johnmccabe
+ */
+@ImplementedBy(value = TestHttpCallImpl.class)
+public interface TestHttpCall extends Entity, Startable {
+
+    @SetFromFlag(nullable = false)
+    ConfigKey<String> TARGET_URL = ConfigKeys.newStringConfigKey("url", "URL to test");
+
+    @SetFromFlag(nullable = false)
+    ConfigKey<Map> ASSERTIONS = ConfigKeys.newConfigKey(Map.class, "assert",
+            "Assertions to be evaluated", Maps.newLinkedHashMap());
+
+    ConfigKey<Duration> TIMEOUT = ConfigKeys.newConfigKey(Duration.class, "timeout",
+            "The duration to wait for assertion result", new Duration(1L, TimeUnit.SECONDS));
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/813bba02/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java
new file mode 100644
index 0000000..7413066
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java
@@ -0,0 +1,107 @@
+package org.apache.brooklyn.test.framework;
+
+import com.google.api.client.util.Objects;
+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.AbstractEntity;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
+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.Map;
+
+import static org.apache.brooklyn.util.http.HttpAsserts.assertContentEventuallyContainsText;
+import static org.apache.brooklyn.util.http.HttpAsserts.assertContentEventuallyMatches;
+import static org.apache.brooklyn.util.http.HttpAsserts.assertHttpStatusCodeEventuallyEquals;
+
+/**
+ * {@inheritDoc}
+ */
+public class TestHttpCallImpl extends AbstractEntity implements TestHttpCall {
+
+    private static final Logger LOG = LoggerFactory.getLogger(TestHttpCallImpl.class);
+
+    /**
+     * {@inheritDoc}
+     */
+    public void start(Collection<? extends Location> locations) {
+        ServiceStateLogic.setExpectedState(this, Lifecycle.STARTING);
+        final String url = getConfig(TARGET_URL);
+        final Map assertions = getConfig(ASSERTIONS);
+        final Duration timeout = getConfig(TIMEOUT);
+        try {
+            checkAssertions(url.toString(), ImmutableMap.of("timeout", timeout), assertions);
+            sensors().set(SERVICE_UP, true);
+            ServiceStateLogic.setExpectedState(this, Lifecycle.RUNNING);
+        } catch (Throwable t) {
+            LOG.info("Url [{}] test failed", url);
+            sensors().set(SERVICE_UP, false);
+            ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE);
+            throw Exceptions.propagate(t);
+        }
+    }
+
+    /**
+     * Tests HTTP Request reponse matches assertions
+     * <p>
+     * Supported keys in the <code>assertions</code> {@link Map} include:
+     * <ul>
+     * <li>string - simple string match
+     * <li>regex - uses {@link java.lang.String#matches(String)}, if the url returns a multi-line response you should
+     * use the embedded dotall flag expression <code>(?s)</code> in your regex.
+     * <li>status - HTTP status code
+     * </ul>
+     * Wraps the {@link org.apache.brooklyn.util.http.HttpAsserts} immediate assertion methods.
+     * <p>
+     * See the test/resources directory for examples.
+     *
+     * @param url        The target URL to be tested
+     * @param flags      Passed to {@link org.apache.brooklyn.util.http.HttpAsserts#assertContentEventuallyContainsText(Map, String, String, String...)},
+     *                   {@link org.apache.brooklyn.util.http.HttpAsserts#assertContentEventuallyMatches(Map, String, String)},
+     *                   {@link org.apache.brooklyn.util.http.HttpAsserts#assertHttpStatusCodeEventuallyEquals(Map, String, int)}
+     *
+     * @param assertions The map of assertions
+     */
+    private void checkAssertions(final String url, final Map<String,?> flags, final Map<?, ?> assertions) {
+
+        for (final Map.Entry<?, ?> entry : assertions.entrySet()) {
+            if (Objects.equal(entry.getKey(), "regex")) {
+                LOG.info("Testing if url [{}] matches regex [{}]",
+                        new Object[]{url, entry.getValue()});
+                assertContentEventuallyMatches( flags, url, TypeCoercions.coerce(entry.getValue(), String.class));
+            } else if (Objects.equal(entry.getKey(), "string")) {
+                LOG.debug("Testing if url [{}] contains string [{}]",
+                        new Object[]{url, entry.getValue()});
+                assertContentEventuallyContainsText(flags, url, TypeCoercions.coerce(entry.getValue(), String.class));
+            } else if (Objects.equal(entry.getKey(), "status")) {
+                LOG.debug("Testing if url [{}] returns status code [{}]",
+                        new Object[]{url, entry.getValue()});
+                assertHttpStatusCodeEventuallyEquals(flags, url, TypeCoercions.coerce(entry.getValue(), Integer.class));
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void stop() {
+        ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPING);
+        sensors().set(SERVICE_UP, false);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void restart() {
+        final Collection<Location> locations = Lists.newArrayList(getLocations());
+        stop();
+        start(locations);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/813bba02/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensor.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensor.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensor.java
new file mode 100644
index 0000000..c6303eb
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensor.java
@@ -0,0 +1,27 @@
+package org.apache.brooklyn.test.framework;
+
+import com.google.common.collect.Maps;
+import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.util.core.flags.SetFromFlag;
+import org.apache.brooklyn.util.time.Duration;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Entity that tests a sensor value on another entity
+ *
+ * @author m4rkmckenna
+ */
+@ImplementedBy(value = TestSensorImpl.class)
+public interface TestSensor extends BaseTest {
+
+    @SetFromFlag(nullable = false)
+    ConfigKey<String> SENSOR_NAME = ConfigKeys.newConfigKey(String.class, "sensor", "Sensor to evaluate");
+
+    ConfigKey<Map> ASSERTIONS = ConfigKeys.newConfigKey(Map.class, "assert", "Assertions to be evaluated", Maps.newLinkedHashMap());
+
+    ConfigKey<Duration> TIMEOUT = ConfigKeys.newConfigKey(Duration.class, "timeout", "Time to wait on sensor result", new Duration(1L, TimeUnit.SECONDS));
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/813bba02/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java
new file mode 100644
index 0000000..94151c6
--- /dev/null
+++ b/usage/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java
@@ -0,0 +1,144 @@
+package org.apache.brooklyn.test.framework;
+
+import com.google.api.client.util.Objects;
+import com.google.common.base.Predicate;
+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.api.sensor.AttributeSensor;
+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.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.Map;
+import java.util.regex.Pattern;
+
+import static org.apache.brooklyn.core.entity.EntityAsserts.assertAttributeEventually;
+
+/**
+ * {@inheritDoc}
+ */
+public class TestSensorImpl extends AbstractTest implements TestSensor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(TestSensorImpl.class);
+
+    /**
+     * {@inheritDoc}
+     */
+    public void start(Collection<? extends Location> locations) {
+        ServiceStateLogic.setExpectedState(this, Lifecycle.STARTING);
+        final Entity target = resolveTarget();
+        final String sensor = getConfig(SENSOR_NAME);
+        final Duration timeout = getConfig(TIMEOUT);
+        final Map assertions = getConfig(ASSERTIONS);
+        try {
+            checkAssertions(target, Sensors.newSensor(Object.class, sensor), ImmutableMap.of("timeout", timeout),
+                    assertions);
+            sensors().set(SERVICE_UP, true);
+            ServiceStateLogic.setExpectedState(this, Lifecycle.RUNNING);
+        } catch (Throwable t) {
+            LOG.info("Sensor [{}] test failed", sensor);
+            sensors().set(SERVICE_UP, false);
+            ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE);
+            throw Exceptions.propagate(t);
+        }
+    }
+
+    /**
+     * Tests sensor values match assertions
+     *
+     * @param target     The {@link Entity} that has the sensor under test
+     * @param sensor     The sensor to test
+     * @param flags      Passed to {@link org.apache.brooklyn.core.entity.EntityAsserts#assertAttributeEventually(Map, Entity, AttributeSensor, Predicate)}
+     * @param assertions The map of assertions
+     */
+    private void checkAssertions(final Entity target, final AttributeSensor<Object> sensor, final Map<?, ?> flags, final Map<?, ?> assertions) {
+        for (final Map.Entry<?, ?> entry : assertions.entrySet()) {
+            if (Objects.equal(entry.getKey(), "equals")) {
+                assertAttributeEventually(flags, target, sensor, isEqualTo(entry.getValue()));
+            } else if (Objects.equal(entry.getKey(), "regex")) {
+                assertAttributeEventually(flags, target, sensor, regexMatches(entry.getValue()));
+            } else if (Objects.equal(entry.getKey(), "isNull")) {
+                assertAttributeEventually(flags, target, sensor, isNull(entry.getValue()));
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void stop() {
+        ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPING);
+        sensors().set(SERVICE_UP, false);
+        try {
+            for (Entity child : getChildren()) {
+                if (child instanceof Startable) ((Startable) child).stop();
+            }
+            ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPED);
+        } catch (Exception e) {
+            ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE);
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void restart() {
+        final Collection<Location> locations = Lists.newArrayList(getLocations());
+        stop();
+        start(locations);
+    }
+
+    /**
+     * Predicate to check the equality of object
+     *
+     * @param value
+     * @return The created {@link Predicate}
+     */
+    private Predicate<Object> isEqualTo(final Object value) {
+        return new Predicate<Object>() {
+            public boolean apply(final Object input) {
+                return (input != null) && Objects.equal(TypeCoercions.coerce(value, input.getClass()), input);
+            }
+        };
+    }
+
+    /**
+     * Predicate to check if a sensor matches a regex pattern
+     *
+     * @param patternValue
+     * @return
+     */
+    private Predicate<Object> regexMatches(final Object patternValue) {
+        final Pattern pattern = Pattern.compile(TypeCoercions.coerce(patternValue, String.class));
+        return new Predicate<Object>() {
+            public boolean apply(final Object input) {
+                return (input != null) && pattern.matcher(input.toString()).matches();
+            }
+        };
+    }
+
+    /**
+     * Predicate to check if a sensor value is null
+     *
+     * @param isNullValue
+     * @return
+     */
+    private Predicate<Object> isNull(final Object isNullValue) {
+        return new Predicate<Object>() {
+            public boolean apply(final Object input) {
+                return (input == null) == TypeCoercions.coerce(isNullValue, Boolean.class);
+            }
+        };
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/813bba02/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEffectorTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEffectorTest.java b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEffectorTest.java
new file mode 100644
index 0000000..b43c76b
--- /dev/null
+++ b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEffectorTest.java
@@ -0,0 +1,106 @@
+package org.apache.brooklyn.test.framework;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.util.UUID;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @author m4rkmckenna on 27/10/2015.
+ */
+public class TestEffectorTest {
+
+    private TestApplication app;
+    private ManagementContext managementContext;
+    private LocalhostMachineProvisioningLocation loc;
+    private String testId;
+
+    @BeforeMethod
+    public void setup() {
+        testId = UUID.randomUUID().toString();
+        app = TestApplication.Factory.newManagedInstanceForTests();
+        managementContext = app.getManagementContext();
+
+        loc = managementContext.getLocationManager().createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class)
+                .configure("name", testId));
+
+    }
+
+
+    @AfterMethod(alwaysRun = true)
+    public void tearDown() throws Exception {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+
+
+    @Test
+    public void testSimpleEffector() {
+        final TestCase testCase = app.createAndManageChild(EntitySpec.create(TestCase.class));
+        final TestEntity testEntity = testCase.addChild(EntitySpec.create(TestEntity.class));
+
+
+        final TestEffector testEffector = testCase.addChild(EntitySpec.create(TestEffector.class)
+                .configure(TestEffector.TARGET_ENTITY, testEntity)
+                .configure(TestEffector.EFFECTOR_NAME, "simpleEffector"));
+
+        app.start(ImmutableList.of(app.newSimulatedLocation()));
+
+        assertThat(testEntity.sensors().get(TestEntity.SIMPLE_EFFECTOR_INVOKED)).isNotNull();
+        assertThat(testEntity.sensors().get(TestEntity.SIMPLE_EFFECTOR_INVOKED)).isTrue();
+
+        assertThat(testEffector.sensors().get(TestEffector.EFFECTOR_RESULT)).isNull();
+    }
+
+    @Test
+    public void testComplexffector() {
+        final TestCase testCase = app.createAndManageChild(EntitySpec.create(TestCase.class));
+        final TestEntity testEntity = testCase.addChild(EntitySpec.create(TestEntity.class));
+
+        final long expectedLongValue = System.currentTimeMillis();
+        final boolean expectedBooleanValue = expectedLongValue % 2 == 0;
+
+        final TestEffector testEffector = testCase.addChild(EntitySpec.create(TestEffector.class)
+                .configure(TestEffector.TARGET_ENTITY, testEntity)
+                .configure(TestEffector.EFFECTOR_NAME, "complexEffector")
+                .configure(TestEffector.EFFECTOR_PARAMS, ImmutableMap.of(
+                        "stringValue", testId,
+                        "booleanValue", expectedBooleanValue,
+                        "longValue", expectedLongValue)));
+
+        app.start(ImmutableList.of(app.newSimulatedLocation()));
+
+        assertThat(testEntity.sensors().get(TestEntity.SIMPLE_EFFECTOR_INVOKED)).isNull();
+        assertThat(testEntity.sensors().get(TestEntity.COMPLEX_EFFECTOR_INVOKED)).isNotNull();
+        assertThat(testEntity.sensors().get(TestEntity.COMPLEX_EFFECTOR_INVOKED)).isTrue();
+
+        assertThat(testEntity.sensors().get(TestEntity.COMPLEX_EFFECTOR_STRING)).isNotNull();
+        assertThat(testEntity.sensors().get(TestEntity.COMPLEX_EFFECTOR_STRING)).isEqualTo(testId);
+
+        assertThat(testEntity.sensors().get(TestEntity.COMPLEX_EFFECTOR_BOOLEAN)).isNotNull();
+        assertThat(testEntity.sensors().get(TestEntity.COMPLEX_EFFECTOR_BOOLEAN)).isEqualTo(expectedBooleanValue);
+
+        assertThat(testEntity.sensors().get(TestEntity.COMPLEX_EFFECTOR_LONG)).isNotNull();
+        assertThat(testEntity.sensors().get(TestEntity.COMPLEX_EFFECTOR_LONG)).isEqualTo(expectedLongValue);
+
+        assertThat(testEffector.sensors().get(TestEffector.EFFECTOR_RESULT)).isNotNull();
+        assertThat(testEffector.sensors().get(TestEffector.EFFECTOR_RESULT)).isInstanceOf(TestEntity.TestPojo.class);
+
+        final TestEntity.TestPojo effectorResult = (TestEntity.TestPojo) testEffector.sensors().get(TestEffector.EFFECTOR_RESULT);
+        assertThat(effectorResult.getBooleanValue()).isEqualTo(expectedBooleanValue);
+        assertThat(effectorResult.getStringValue()).isEqualTo(testId);
+        assertThat(effectorResult.getLongValue()).isEqualTo(expectedLongValue);
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/813bba02/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEntity.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEntity.java b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEntity.java
new file mode 100644
index 0000000..933b227
--- /dev/null
+++ b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEntity.java
@@ -0,0 +1,55 @@
+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.annotation.Effector;
+import org.apache.brooklyn.core.annotation.EffectorParam;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
+
+/**
+ * @author m4rkmckenna on 27/10/2015.
+ */
+
+@ImplementedBy(TestEntityImpl.class)
+public interface TestEntity extends Entity, Startable {
+
+    AttributeSensorAndConfigKey<Boolean, Boolean> SIMPLE_EFFECTOR_INVOKED = ConfigKeys.newSensorAndConfigKey(Boolean.class, "simple-effector-invoked", "");
+    AttributeSensorAndConfigKey<Boolean, Boolean> COMPLEX_EFFECTOR_INVOKED = ConfigKeys.newSensorAndConfigKey(Boolean.class, "complex-effector-invoked", "");
+    AttributeSensorAndConfigKey<String, String> COMPLEX_EFFECTOR_STRING = ConfigKeys.newSensorAndConfigKey(String.class, "complex-effector-string", "");
+    AttributeSensorAndConfigKey<Boolean, Boolean> COMPLEX_EFFECTOR_BOOLEAN = ConfigKeys.newSensorAndConfigKey(Boolean.class, "complex-effector-boolean", "");
+    AttributeSensorAndConfigKey<Long, Long> COMPLEX_EFFECTOR_LONG = ConfigKeys.newSensorAndConfigKey(Long.class, "complex-effector-long", "");
+
+    @Effector
+    void simpleEffector();
+
+    @Effector
+    TestPojo complexEffector(@EffectorParam(name = "stringValue") final String stringValue,
+                             @EffectorParam(name = "booleanValue") final Boolean booleanValue,
+                             @EffectorParam(name = "longValue") final Long longValue);
+
+    class TestPojo {
+        private final String stringValue;
+        private final Boolean booleanValue;
+        private final Long longValue;
+
+        public TestPojo(final String stringValue, final Boolean booleanValue, final Long longValue) {
+            this.stringValue = stringValue;
+            this.booleanValue = booleanValue;
+            this.longValue = longValue;
+        }
+
+        public String getStringValue() {
+            return stringValue;
+        }
+
+        public Boolean getBooleanValue() {
+            return booleanValue;
+        }
+
+        public Long getLongValue() {
+            return longValue;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/813bba02/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEntityImpl.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEntityImpl.java b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEntityImpl.java
new file mode 100644
index 0000000..b3386f2
--- /dev/null
+++ b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEntityImpl.java
@@ -0,0 +1,39 @@
+package org.apache.brooklyn.test.framework;
+
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.annotation.EffectorParam;
+import org.apache.brooklyn.core.entity.AbstractEntity;
+
+import java.util.Collection;
+
+/**
+ * @author m4rkmckenna on 27/10/2015.
+ */
+public class TestEntityImpl extends AbstractEntity implements TestEntity {
+    @Override
+    public void start(final Collection<? extends Location> locations) {
+    }
+
+    @Override
+    public void stop() {
+
+    }
+
+    @Override
+    public void restart() {
+    }
+
+    @Override
+    public void simpleEffector() {
+        sensors().set(SIMPLE_EFFECTOR_INVOKED, Boolean.TRUE);
+    }
+
+    @Override
+    public TestPojo complexEffector(@EffectorParam(name = "stringValue") final String stringValue, @EffectorParam(name = "booleanValue") final Boolean booleanValue, @EffectorParam(name = "longValue") final Long longValue) {
+        sensors().set(COMPLEX_EFFECTOR_INVOKED, Boolean.TRUE);
+        sensors().set(COMPLEX_EFFECTOR_STRING, stringValue);
+        sensors().set(COMPLEX_EFFECTOR_BOOLEAN, booleanValue);
+        sensors().set(COMPLEX_EFFECTOR_LONG, longValue);
+        return new TestPojo(stringValue, booleanValue, longValue);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/813bba02/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestSensorTest.java
----------------------------------------------------------------------
diff --git a/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestSensorTest.java b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestSensorTest.java
new file mode 100644
index 0000000..0b653eb
--- /dev/null
+++ b/usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestSensorTest.java
@@ -0,0 +1,270 @@
+package org.apache.brooklyn.test.framework;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.core.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.location.localhost.LocalhostMachineProvisioningLocation;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.exceptions.PropagatedRuntimeException;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.util.UUID;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @author m4rkmckenna on 27/10/2015.
+ */
+public class TestSensorTest {
+
+    private static final AttributeSensorAndConfigKey<Boolean, Boolean> BOOLEAN_SENSOR = ConfigKeys.newSensorAndConfigKey(Boolean.class, "boolean-sensor", "Boolean Sensor");
+    private static final AttributeSensorAndConfigKey<String, String> STRING_SENSOR = ConfigKeys.newSensorAndConfigKey(String.class, "string-sensor", "String Sensor");
+    private static final AttributeSensorAndConfigKey<Object, Object> OBJECT_SENSOR = ConfigKeys.newSensorAndConfigKey(Object.class, "object-sensor", "Object Sensor");
+
+    private TestApplication app;
+    private ManagementContext managementContext;
+    private LocalhostMachineProvisioningLocation loc;
+    private String testId;
+
+    @BeforeMethod
+    public void setup() {
+        testId = UUID.randomUUID().toString();
+        app = TestApplication.Factory.newManagedInstanceForTests();
+        managementContext = app.getManagementContext();
+        loc = managementContext.getLocationManager().createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class)
+                .configure("name", testId));
+    }
+
+    @AfterMethod(alwaysRun = true)
+    public void tearDown() throws Exception {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+
+    @Test
+    public void testAssertEqual() {
+        //Add Sensor Test for BOOLEAN sensor
+        app.createAndManageChild(EntitySpec.create(TestSensor.class)
+                .configure(TestSensor.TARGET_ENTITY, app)
+                .configure(TestSensor.SENSOR_NAME, BOOLEAN_SENSOR.getName())
+                .configure(TestSensor.ASSERTIONS, ImmutableMap.of("equals", true)));
+        //Add Sensor Test for STRING sensor
+        app.createAndManageChild(EntitySpec.create(TestSensor.class)
+                .configure(TestSensor.TARGET_ENTITY, app)
+                .configure(TestSensor.SENSOR_NAME, STRING_SENSOR.getName())
+                .configure(TestSensor.ASSERTIONS, ImmutableMap.of("equals", testId)));
+
+        //Set BOOLEAN Sensor to true
+        app.sensors().set(BOOLEAN_SENSOR, Boolean.TRUE);
+        //Set STRING sensor to random string
+        app.sensors().set(STRING_SENSOR, testId);
+
+
+        app.start(ImmutableList.of(loc));
+
+    }
+
+    @Test
+    public void testAssertEqualFailure() {
+        boolean booleanAssertFailed = false;
+
+        //Add Sensor Test for BOOLEAN sensor
+        app.createAndManageChild(EntitySpec.create(TestSensor.class)
+                .configure(TestSensor.TARGET_ENTITY, app)
+                .configure(TestSensor.SENSOR_NAME, BOOLEAN_SENSOR.getName())
+                .configure(TestSensor.ASSERTIONS, ImmutableMap.of("equals", true)));
+
+        //Set BOOLEAN Sensor to false
+        app.sensors().set(BOOLEAN_SENSOR, Boolean.FALSE);
+
+        try {
+            app.start(ImmutableList.of(loc));
+        } catch (final PropagatedRuntimeException pre) {
+            final AssertionError assertionError = Exceptions.getFirstThrowableOfType(pre, AssertionError.class);
+            assertThat(assertionError).isNotNull();
+            booleanAssertFailed = true;
+        } finally {
+            assertThat(booleanAssertFailed).isTrue();
+        }
+    }
+
+    @Test
+    public void testAssertEqualOnNullSenor() {
+        boolean booleanAssertFailed = false;
+
+        //Add Sensor Test for BOOLEAN sensor
+        app.createAndManageChild(EntitySpec.create(TestSensor.class)
+                .configure(TestSensor.TARGET_ENTITY, app)
+                .configure(TestSensor.SENSOR_NAME, BOOLEAN_SENSOR.getName())
+                .configure(TestSensor.ASSERTIONS, ImmutableMap.of("equals", false)));
+
+        try {
+            app.start(ImmutableList.of(loc));
+        } catch (final PropagatedRuntimeException pre) {
+            final AssertionError assertionError = Exceptions.getFirstThrowableOfType(pre, AssertionError.class);
+            assertThat(assertionError).isNotNull().as("An assertion error should have been thrown");
+            booleanAssertFailed = true;
+        } finally {
+            assertThat(booleanAssertFailed).isTrue().as("Equals assert should have failed as the sensor is NULL");
+        }
+    }
+
+    @Test
+    public void testAssertNull() {
+        //Add Sensor Test for BOOLEAN sensor
+        app.createAndManageChild(EntitySpec.create(TestSensor.class)
+                .configure(TestSensor.TARGET_ENTITY, app)
+                .configure(TestSensor.SENSOR_NAME, BOOLEAN_SENSOR.getName())
+                .configure(TestSensor.ASSERTIONS, ImmutableMap.of("isNull", true)));
+        //Add Sensor Test for STRING sensor
+        app.createAndManageChild(EntitySpec.create(TestSensor.class)
+                .configure(TestSensor.TARGET_ENTITY, app)
+                .configure(TestSensor.SENSOR_NAME, STRING_SENSOR.getName())
+                .configure(TestSensor.ASSERTIONS, ImmutableMap.of("isNull", false)));
+
+        //Set STRING sensor to random string
+        app.sensors().set(STRING_SENSOR, testId);
+
+        app.start(ImmutableList.of(loc));
+
+    }
+
+
+    @Test
+    public void testAssertNullFail() {
+        boolean sensorTestFail = false;
+        //Add Sensor Test for STRING sensor
+        app.createAndManageChild(EntitySpec.create(TestSensor.class)
+                .configure(TestSensor.TARGET_ENTITY, app)
+                .configure(TestSensor.SENSOR_NAME, STRING_SENSOR.getName())
+                .configure(TestSensor.ASSERTIONS, ImmutableMap.of("isNull", true)));
+
+        //Set STRING sensor to random string
+        app.sensors().set(STRING_SENSOR, testId);
+
+
+        try {
+            app.start(ImmutableList.of(loc));
+        } catch (final PropagatedRuntimeException pre) {
+            final AssertionError assertionError = Exceptions.getFirstThrowableOfType(pre, AssertionError.class);
+            assertThat(assertionError).isNotNull().as("An assertion error should have been thrown");
+            sensorTestFail = true;
+        } finally {
+            assertThat(sensorTestFail).isTrue().as("isNull assert should have failed as the sensor has been set");
+        }
+
+    }
+
+    @Test
+    public void testAssertRegex() {
+        final long time = System.currentTimeMillis();
+        final String sensorValue = String.format("%s%s%s", UUID.randomUUID().toString(), time, UUID.randomUUID().toString());
+
+        //Add Sensor Test for STRING sensor
+        app.createAndManageChild(EntitySpec.create(TestSensor.class)
+                .configure(TestSensor.TARGET_ENTITY, app)
+                .configure(TestSensor.SENSOR_NAME, STRING_SENSOR.getName())
+                .configure(TestSensor.ASSERTIONS, ImmutableMap.of("regex", String.format(".*%s.*", time))));
+        app.createAndManageChild(EntitySpec.create(TestSensor.class)
+                .configure(TestSensor.TARGET_ENTITY, app)
+                .configure(TestSensor.SENSOR_NAME, BOOLEAN_SENSOR.getName())
+                .configure(TestSensor.ASSERTIONS, ImmutableMap.of("regex", "true")));
+
+        //Set STRING sensor
+        app.sensors().set(STRING_SENSOR, sensorValue);
+        app.sensors().set(BOOLEAN_SENSOR, true);
+
+
+        app.start(ImmutableList.of(loc));
+    }
+
+    @Test
+    public void testAssertRegexFail() {
+        boolean sensorTestFail = false;
+        final String sensorValue = String.format("%s%s%s", UUID.randomUUID().toString(), System.currentTimeMillis(), UUID.randomUUID().toString());
+
+        //Add Sensor Test for STRING sensor
+        app.createAndManageChild(EntitySpec.create(TestSensor.class)
+                .configure(TestSensor.TARGET_ENTITY, app)
+                .configure(TestSensor.SENSOR_NAME, STRING_SENSOR.getName())
+                .configure(TestSensor.ASSERTIONS, ImmutableMap.of("regex", String.format(".*%s.*", UUID.randomUUID().toString()))));
+
+        //Set STRING sensor
+        app.sensors().set(STRING_SENSOR, sensorValue);
+
+
+        try {
+            app.start(ImmutableList.of(loc));
+        } catch (final PropagatedRuntimeException pre) {
+            final AssertionError assertionError = Exceptions.getFirstThrowableOfType(pre, AssertionError.class);
+            assertThat(assertionError).isNotNull().as("An assertion error should have been thrown");
+            sensorTestFail = true;
+        } finally {
+            assertThat(sensorTestFail).isTrue().as("regex assert should have failed");
+        }
+    }
+
+    @Test
+    public void testAssertRegexOnNullSensor() {
+        boolean sensorTestFail = false;
+        final String sensorValue = String.format("%s%s%s", UUID.randomUUID().toString(), System.currentTimeMillis(), UUID.randomUUID().toString());
+
+        //Add Sensor Test for STRING sensor
+        app.createAndManageChild(EntitySpec.create(TestSensor.class)
+                .configure(TestSensor.TARGET_ENTITY, app)
+                .configure(TestSensor.SENSOR_NAME, STRING_SENSOR.getName())
+                .configure(TestSensor.ASSERTIONS, ImmutableMap.of("regex", String.format(".*%s.*", UUID.randomUUID().toString()))));
+
+        try {
+            app.start(ImmutableList.of(loc));
+        } catch (final PropagatedRuntimeException pre) {
+            final AssertionError assertionError = Exceptions.getFirstThrowableOfType(pre, AssertionError.class);
+            assertThat(assertionError).isNotNull().as("An assertion error should have been thrown");
+            sensorTestFail = true;
+        } finally {
+            assertThat(sensorTestFail).isTrue().as("regex assert should have failed");
+        }
+    }
+
+
+    @Test
+    public void testAssertRegexOnNonStringSensor() {
+        //Add Sensor Test for OBJECT sensor
+        app.createAndManageChild(EntitySpec.create(TestSensor.class)
+                .configure(TestSensor.TARGET_ENTITY, app)
+                .configure(TestSensor.SENSOR_NAME, OBJECT_SENSOR.getName())
+                .configure(TestSensor.ASSERTIONS, ImmutableMap.of("regex", ".*TestObject.*id=.*")));
+
+        app.sensors().set(OBJECT_SENSOR, new TestObject());
+
+        app.start(ImmutableList.of(loc));
+
+    }
+
+
+    class TestObject {
+        private final String id;
+
+        public TestObject() {
+            id = UUID.randomUUID().toString();
+        }
+
+        public String getId() {
+            return id;
+        }
+
+        @Override
+        public String toString() {
+            return ToStringBuilder.reflectionToString(this);
+        }
+    }
+
+}