You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@brooklyn.apache.org by m4rkmckenna <gi...@git.apache.org> on 2015/11/02 19:52:21 UTC

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

GitHub user m4rkmckenna opened a pull request:

    https://github.com/apache/incubator-brooklyn/pull/999

    Implementation of proposed Test Entities to allow testing directly from blueprints

    **Proposal**
    http://mail-archives.apache.org/mod_mbox/incubator-brooklyn-dev/201510.mbox/%3CE185CA37-E693-4733-8DE1-208872BC1978%40cloudsoftcorp.com%3E
    
    This PR relies on #994  

You can merge this pull request into a Git repository by running:

    $ git pull https://github.com/m4rkmckenna/incubator-brooklyn test-framework

Alternatively you can review and apply these changes as the patch at:

    https://github.com/apache/incubator-brooklyn/pull/999.patch

To close this pull request, make a commit to your master/trunk branch
with (at least) the following in the commit message:

    This closes #999
    
----
commit 106bc5595f7c186d4199803f18daf363681076ed
Author: Mark McKenna <m4...@gmail.com>
Date:   2015-11-02T17:17:07Z

    Implementation of proposed Test Entities to allow testing directly from blueprints
    
    Proposal :: http://mail-archives.apache.org/mod_mbox/incubator-brooklyn-dev/201510.mbox/%3CE185CA37-E693-4733-8DE1-208872BC1978%40cloudsoftcorp.com%3E

----


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#issuecomment-155851140
  
    LGTM merging


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by m4rkmckenna <gi...@git.apache.org>.
Github user m4rkmckenna commented on the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#issuecomment-155196565
  
    @ahgittin Moved `sandbox/brooklyn-sandbox-test-framework` to `usage/test-framework`


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on a diff in the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#discussion_r44517031
  
    --- Diff: 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());
    --- End diff --
    
    btw this should be `null`, or removed (in this test only)


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on a diff in the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#discussion_r44513938
  
    --- Diff: usage/test-framework/etc/exampl-catalog.bom ---
    @@ -0,0 +1,15 @@
    +brooklyn.catalog:
    --- End diff --
    
    name of this file is misspelled -- `exampl`


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on a diff in the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#discussion_r44515597
  
    --- Diff: 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")) {
    --- End diff --
    
    call this `contains` ?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on a diff in the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#discussion_r44514563
  
    --- Diff: 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.
    --- End diff --
    
    javadoc should probably be on the interface?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on a diff in the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#discussion_r44517148
  
    --- Diff: 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();
    --- End diff --
    
    FWIW we tend to use `Identifiers.makeRandomId(/* length */ 8)` instead of `UUID` -- no big reason but it makes for more easily distinguishable identifiers, shorter and more chars


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on a diff in the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#discussion_r44515270
  
    --- Diff: 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",
    --- End diff --
    
    as above, inheriting these would be good, or at least defining the constants in an interface which is either extended or referenced, as in
    
        ConfigKey<Duration> TIMEOUT = TestAssertionsConfig.TIMEOUT;



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on a diff in the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#discussion_r44516297
  
    --- Diff: usage/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEntity.java ---
    @@ -0,0 +1,55 @@
    +package org.apache.brooklyn.test.framework;
    --- End diff --
    
    move this entity and related tests to its own sub-package?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by johnmccabe <gi...@git.apache.org>.
Github user johnmccabe commented on a diff in the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#discussion_r43693285
  
    --- Diff: sandbox/brooklyn-sandbox-test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java ---
    @@ -0,0 +1,98 @@
    +package org.apache.brooklyn.test.framework;
    +
    +import com.google.api.client.util.Objects;
    +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.slf4j.Logger;
    +import org.slf4j.LoggerFactory;
    +
    +import java.util.Collection;
    +import java.util.Map;
    +
    +import static org.apache.brooklyn.util.http.HttpUtils.*;
    +
    +/**
    + * {@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);
    +        try {
    +            checkAssertions(url, 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.HttpUtils} immediate assertion methods.
    +     * <p>
    +     * See the test/resources directory for examples.
    +     *
    +     * @param url        The target URL to be tested
    +     * @param assertions The map of assertions
    +     */
    +    private void checkAssertions(final String url, 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()});
    +                assertContentMatches(url, TypeCoercions.coerce(entry.getValue(), String.class));
    +            } else if (Objects.equal(entry.getKey(), "string")) {
    --- End diff --
    
    agree with @m4rkmckenna that `contains` would be more meaningful than `string` in this context


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on a diff in the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#discussion_r44515581
  
    --- Diff: 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()) {
    --- End diff --
    
    this kind of map feels like the wrong syntax as it prevents multiple tests of the same type (e.g. multiple `regex` checks)
    
    i think we should take a list of maps, where the maps should be single-entry.  (if a map is provided we could support the current implementation but with a warning.)  this would also allow us to define more complex assertions which might require multiple settings (e.g. `ignoreCase` for `string` (aka `contains`)


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on a diff in the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#discussion_r44514226
  
    --- Diff: 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)
    --- End diff --
    
    why `nullable=false`; it can be `null` if `TARGET_ID` is supplied, in fact it should be an error if both are non-null and they don't agree ?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#issuecomment-155178790
  
    I say move it across in this PR.
    
    Best
    Alex
    On 9 Nov 2015 15:36, "Mark McKenna" <no...@github.com> wrote:
    
    > @ahgittin <https://github.com/ahgittin> @aledsage
    > <https://github.com/aledsage> @rdowner <https://github.com/rdowner> Do
    > you want me to move to usage/test-framework ... or is it ok where it is
    > in sandbox/brooklyn-sandbox-test-framework?
    >
    > —
    > Reply to this email directly or view it on GitHub
    > <https://github.com/apache/incubator-brooklyn/pull/999#issuecomment-155098132>
    > .
    >



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on a diff in the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#discussion_r44516156
  
    --- Diff: 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",
    --- End diff --
    
    i note the implementation of this one does not permit children; that's probably a useful distinction to call out, and probably cleaner if the assertions in general do not (and they should assert on `init` that they have no children)


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on a diff in the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#discussion_r44514528
  
    --- Diff: 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)
    --- End diff --
    
    feels like it would make more sense for this to take an `EntitySpec` (cf `DynamicCluster.memberSpec` -- and let's also find a way to remove the `$brooklyn:entitySpec` requirement), and if supplied, for it to be started *before* the defined `brooklyn.children`.
    
    btw at present this can only be used as a more long-winded way of `targetId` right?
    
    and we could make it polymorphic; i.e. if it's a string then it's taken as an entity ID, if it's an `EntitySpec` or a `Map` it is taken as a spec, and if it's an Entity (using `$brooklyn:component`) we take it as an entity.  then no need for `targetId`.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on a diff in the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#discussion_r44517297
  
    --- Diff: usage/test-framework/etc/exampl-catalog.bom ---
    @@ -0,0 +1,15 @@
    +brooklyn.catalog:
    --- End diff --
    
    the files in `etc` at present don't look like they are used for anything.
    
    maybe move them to `src/test/resources/test-framework-examples` with a `README.md` in that dir explaining what they are used for.  and maybe in the `qa` project we could run them all as integration tests?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on a diff in the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#discussion_r44513891
  
    --- Diff: usage/test-framework/README.md ---
    @@ -0,0 +1,109 @@
    +# Entities
    --- End diff --
    
    These docs should be moved to the integrated `docs/guide/`.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by johnmccabe <gi...@git.apache.org>.
Github user johnmccabe commented on a diff in the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#discussion_r43692507
  
    --- Diff: sandbox/brooklyn-sandbox-test-framework/README.md ---
    @@ -0,0 +1,94 @@
    +# Entities
    +
    +## TestCase
    +A logical grouping for tests eg Restart tests
    +```
    +type: org.apache.brooklyn.test.framework.TestCase
    +  name: Stop Test
    +  brooklyn.children:
    +  - ***
    +  - ***
    +```
    +
    +## TestSensor
    +Entity that tests a sensor value on another entity eg service.isUp == TRUE
    +
    +#### Configuration
    +| Key | Description | Required |
    +| --- | ----------- | -------- |
    +| target | The target entity to test | yes (no if *targetId* is supplied) |
    +| targetId | The id of the target entity to test | yes (no if *target* is supplied) |
    +| assert | Assertions to be evaluated | yes |
    +| timeout | The duration to wait on a result | no |
    +
    +```
    +type: org.apache.brooklyn.test.framework.TestSensor
    +target: $brooklyn:component("nginx1")
    +sensor: service.isUp
    +equals: true
    +timeout: 5m
    +```
    +
    +## TestEffector
    +Entity that invokes an effector on another entity eg restart
    +
    +#### Configuration
    +| Key | Description | Required |
    +| --- | ----------- | -------- |
    +| target | The target entity to effect | yes (no if *targetId* is supplied) |
    +| targetId | The id of the target entity to effect | yes (no if *target* is supplied) |
    +| effector | The name of the effector to invoke | yes |
    +| params | Parameters to pass to the effector | no |
    +| timeout | The duration to wait on a response from an effector | no |
    +
    +#### Sensors
    +| Key | Description |
    +| --- | ----------- |
    +| result | The result of invoking the effector (null if no result) |
    +
    +```
    +type: org.apache.brooklyn.test.framework.TestEffector
    +name: Deploy WAR
    +target: $brooklyn:component("tomcat")
    +effector: deploy
    +params:
    +  url: https://tomcat.apache.org/tomcat-6.0-doc/appdev/sample/sample.war
    +  targetName: sample1
    +```
    +
    +## TestHtmlCall
    +Entity that makes a HTTP Request and tests the response
    +
    +#### Configuration
    +| Key | Description | Required |
    +| --- | ----------- | -------- |
    +| target | The target entity to effect | yes (no if *targetId* is supplied) |
    +| targetId | The id of the target entity to effect | yes (no if *target* is supplied) |
    --- End diff --
    
    `target`/`targetId` aren't used, need to add `assert` - see the javadoc for the assertion keywords


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by m4rkmckenna <gi...@git.apache.org>.
Github user m4rkmckenna commented on the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#issuecomment-155098132
  
    @ahgittin @aledsage @rdowner Do you want me to move to ```usage/test-framework``` ... or is it ok where it is in ```sandbox/brooklyn-sandbox-test-framework```?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on a diff in the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#discussion_r44516678
  
    --- Diff: 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)
    --- End diff --
    
    i now see it's very useful to pass the `Entity` when writing in java; we should definitely continue to support this.



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#issuecomment-154093910
  
    Should this be moved to `usage/test-framework` ?  /cc @aledsage @rdowner 



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#issuecomment-155721160
  
    completed review.  superb start.  as there is more than i first thought including type hierarchy changes i'm inclined to leave this open until you've addressed the ones that you think should be addresed soon.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by asfgit <gi...@git.apache.org>.
Github user asfgit closed the pull request at:

    https://github.com/apache/incubator-brooklyn/pull/999


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#issuecomment-155710670
  
    This looks great at first blush.  I'll add comments but so far nothing looks major so I'm of a mind to merge it unless I find anything else, and we can address comments as a separate PR.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by m4rkmckenna <gi...@git.apache.org>.
Github user m4rkmckenna commented on the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#issuecomment-155835746
  
    @ahgittin Addressed most of the comments.
    * Im currently working on the `TestFrameworkAssertions` utility class ... is it ok for this to be a fast follow or would you rather it included?
    * @burkechris has already fixed the issues with `ParallelTestCase` ... is it ok if this is addressed in a separate PR?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on a diff in the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#discussion_r44516988
  
    --- Diff: 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) {
    --- End diff --
    
    I've added a few things to `Asserts` to simplify this; you should be able to simplify many of the tests here using:
    
        try {
            app.start(ImmutableList.of(loc));
            Asserts.shouldHaveFailedPreviously();
        } catch (Throwable t) {
            Asserts.expectedFailureOfType(t, AssertionError.class);
            // and assert the error message has good detail, including the actual and expected values
            // (assuming we set `regexExpected` as ".*"+UUID.randomUUID()+".*" and pass that in above
            Asserts.expectedFailureContainsIgnoreCase(t, "sensor", "regex", /* actual */ "null", /* expected */ regexExpected);
        }



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on a diff in the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#discussion_r44514991
  
    --- Diff: 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);
    --- End diff --
    
    what you've done works but I'd probably do:
    
        DynamicTasks.queue(taskAdaptable);
        DynamicTasks.waitForLast();
    
    because it's an effector it's guaranteed to have a queueing context, and the advantage of a queueing context is that you can build up more complicated task logic (e.g. starting `target` if required) ahead of time and that task logic shows up nicely in the UI.  obviously you want to wait for the queue to drain before setting the service state or catching, which is what `waitForLast()` does, and it throws if there's a problem.  i wish we had better guidance on tasks (though i think @sjcorbett wrote some?).
    
    more logging than we'd usually do as all the info will be available in the effector/task logging, but no issues with that especially if it's helpful to learn.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#issuecomment-155851590
  
    I look forward to the follow-on PR's.  Moving the root `README.md` into the `docs/guide` is particularly important as that makes it something people can actually find and use!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on a diff in the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#discussion_r44516010
  
    --- Diff: 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) {
    --- End diff --
    
    and the implementation could do a `getPredicate(Map)` which does a lookup on the key(s) in the maps to return e.g. `StringPredicates.containsStringLiteral(xxx)`, which is then checked with a new method `Asserts.assertThatEventually(Map flags, Supplier<T>, Predicate<T>)`


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on a diff in the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#discussion_r44515398
  
    --- Diff: 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) {
    --- End diff --
    
    this logic should be pulled out to a convenience class, e.g. `TestFrameworkAssertions`
    
    in time i'd like to make it so the set of assertions is extensible using the catalog (this is the work I've been doing with `BrooklynTypeRegister.createBean`)


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on a diff in the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#discussion_r44515191
  
    --- Diff: 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 {
    --- End diff --
    
    feels odd that `EffectorTest` extends `BaseTest` but this has no such marker; some sort of marker would be useful here -- especially if it can inherit `ASSERTIONS` and `TIMEOUT`


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] incubator-brooklyn pull request: Implementation of proposed Test E...

Posted by ahgittin <gi...@git.apache.org>.
Github user ahgittin commented on a diff in the pull request:

    https://github.com/apache/incubator-brooklyn/pull/999#discussion_r44515732
  
    --- Diff: 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) {
    --- End diff --
    
    e.g.
    
        TestFrameworkAssertions.checkAssertions(Supplier<String> dataSupplier, Map flags, Object assertions)
    
    where `assertions` is preferred as a `List<Map>` but `Map` might also be supported


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---