You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by al...@apache.org on 2016/05/19 15:40:18 UTC
[1/4] brooklyn-server git commit: YAML built-in types: include
boolean etc
Repository: brooklyn-server
Updated Branches:
refs/heads/master 6944ac5e1 -> dee107447
YAML built-in types: include boolean etc
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/0aba4ffd
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/0aba4ffd
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/0aba4ffd
Branch: refs/heads/master
Commit: 0aba4ffd1789b3591d70b0975e0a8088fa5d7129
Parents: f4a6bb8
Author: Aled Sage <al...@gmail.com>
Authored: Tue May 17 10:53:11 2016 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Tue May 17 10:53:11 2016 +0100
----------------------------------------------------------------------
.../java/org/apache/brooklyn/core/objs/BasicSpecParameter.java | 4 ++++
1 file changed, 4 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0aba4ffd/core/src/main/java/org/apache/brooklyn/core/objs/BasicSpecParameter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/BasicSpecParameter.java b/core/src/main/java/org/apache/brooklyn/core/objs/BasicSpecParameter.java
index ea041b2..89b7cd0 100644
--- a/core/src/main/java/org/apache/brooklyn/core/objs/BasicSpecParameter.java
+++ b/core/src/main/java/org/apache/brooklyn/core/objs/BasicSpecParameter.java
@@ -186,6 +186,10 @@ public class BasicSpecParameter<T> implements SpecParameter<T>{
private static final String DEFAULT_TYPE = "string";
private static final Map<String, Class<?>> BUILT_IN_TYPES = ImmutableMap.<String, Class<?>>builder()
.put(DEFAULT_TYPE, String.class)
+ .put("boolean", Boolean.class)
+ .put("byte", Byte.class)
+ .put("char", Character.class)
+ .put("short", Short.class)
.put("integer", Integer.class)
.put("long", Long.class)
.put("float", Float.class)
[4/4] brooklyn-server git commit: This closes #142
Posted by al...@apache.org.
This closes #142
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/dee10744
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/dee10744
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/dee10744
Branch: refs/heads/master
Commit: dee1074475d4837997504265478afca08f3e1dd8
Parents: 6944ac5 4f98035
Author: Aled Sage <al...@gmail.com>
Authored: Thu May 19 16:39:57 2016 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Thu May 19 16:39:57 2016 +0100
----------------------------------------------------------------------
.../brooklyn/core/objs/BasicSpecParameter.java | 4 +
.../test/framework/TestEffectorImpl.java | 2 +-
.../test/framework/TestEndpointReachable.java | 103 ++++++++
.../framework/TestEndpointReachableImpl.java | 223 ++++++++++++++++
.../test/framework/TestHttpCallImpl.java | 2 +-
.../brooklyn/test/framework/TestSensorImpl.java | 2 +-
.../framework/TestEndpointReachableTest.java | 252 +++++++++++++++++++
7 files changed, 585 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
[3/4] brooklyn-server git commit: TestEndpointReachable: incorporate
review comments PR #142
Posted by al...@apache.org.
TestEndpointReachable: incorporate review comments PR #142
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/4f98035f
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/4f98035f
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/4f98035f
Branch: refs/heads/master
Commit: 4f98035f21c2fba001b88317a4dca1209373505b
Parents: 9337ebf
Author: Aled Sage <al...@gmail.com>
Authored: Thu May 19 14:25:22 2016 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Thu May 19 15:01:08 2016 +0100
----------------------------------------------------------------------
.../test/framework/TestEffectorImpl.java | 2 +-
.../test/framework/TestEndpointReachable.java | 31 ++++++++--
.../framework/TestEndpointReachableImpl.java | 53 ++++++++++++++--
.../test/framework/TestHttpCallImpl.java | 2 +-
.../brooklyn/test/framework/TestSensorImpl.java | 2 +-
.../framework/TestEndpointReachableTest.java | 64 ++++++++++++++------
6 files changed, 123 insertions(+), 31 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4f98035f/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEffectorImpl.java
----------------------------------------------------------------------
diff --git a/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEffectorImpl.java b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEffectorImpl.java
index c00bef2..bd94ad8 100644
--- a/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEffectorImpl.java
+++ b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEffectorImpl.java
@@ -101,7 +101,7 @@ public class TestEffectorImpl extends TargetableTestComponentImpl implements Tes
* {@inheritDoc}
*/
public void stop() {
- ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPING);
+ ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPED);
sensors().set(SERVICE_UP, false);
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4f98035f/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEndpointReachable.java
----------------------------------------------------------------------
diff --git a/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEndpointReachable.java b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEndpointReachable.java
index 8fdcfd7..425b348 100644
--- a/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEndpointReachable.java
+++ b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEndpointReachable.java
@@ -51,12 +51,7 @@ import org.apache.brooklyn.core.config.ConfigKeys;
* the target entity):
* <pre>
* {@code
- * services:
- * - type: MyEntityUnderTest
- * id: entity-under-test
- * - type: org.apache.brooklyn.test.framework.TestCase
- * name: Tests
- * brooklyn.children:
+ * ...
* - type: org.apache.brooklyn.test.framework.TestEndpointReachable
* name: Endpoint reachable
* brooklyn.config:
@@ -69,6 +64,24 @@ import org.apache.brooklyn.core.config.ConfigKeys;
* - $brooklyn:entity("entity-under-test").attributeWhenReady("https.port")
* }
* </pre>
+ *
+ * One can also assert that the given endpoint is not reachable. Here the timeout means that at
+ * some point within this timeout period, we expect the endpoint to become unreachable. As soon
+ * as it is unreachable, we return:
+ *
+ * <pre>
+ * {@code
+ * ...
+ * - type: org.apache.brooklyn.test.framework.TestEndpointReachable
+ * name: Endpoint reachable
+ * brooklyn.config:
+ * targetId: entity-under-test
+ * timeout: 2m
+ * endpointSensor: datastore.url
+ * assertions:
+ * reachable: false
+ * }
+ * </pre>
*/
@ImplementedBy(value = TestEndpointReachableImpl.class)
public interface TestEndpointReachable extends BaseTest {
@@ -81,4 +94,10 @@ public interface TestEndpointReachable extends BaseTest {
Object.class,
"endpointSensor",
"Sensor (or name of sensor) on target that advertises the endpoint (to test for tcp-reachability); mutually exclusive with 'endpoint'");
+
+ /**
+ * A key within the assertions map, to say whether we should assert that the endpoint is reachable or not reachable.
+ * The value in the map should be a boolean. If absent, defaults to true.
+ */
+ public static final String REACHABLE_KEY = "reachable";
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4f98035f/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEndpointReachableImpl.java
----------------------------------------------------------------------
diff --git a/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEndpointReachableImpl.java b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEndpointReachableImpl.java
index d759507..913be27 100644
--- a/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEndpointReachableImpl.java
+++ b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEndpointReachableImpl.java
@@ -25,6 +25,7 @@ import java.net.URL;
import java.util.Collection;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.location.Location;
@@ -34,19 +35,21 @@ import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
import org.apache.brooklyn.core.sensor.Sensors;
import org.apache.brooklyn.test.Asserts;
-import org.apache.brooklyn.test.framework.TestFrameworkAssertions.AssertionSupport;
-import org.apache.brooklyn.test.framework.TestHttpCall.HttpAssertionTarget;
+import org.apache.brooklyn.util.core.flags.TypeCoercions;
import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.http.HttpTool;
+import org.apache.brooklyn.util.guava.Maybe;
import org.apache.brooklyn.util.net.Networking;
import org.apache.brooklyn.util.text.Strings;
import org.apache.brooklyn.util.time.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Objects;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
import com.google.common.net.HostAndPort;
/**
@@ -65,6 +68,8 @@ public class TestEndpointReachableImpl extends TargetableTestComponentImpl imple
final String endpoint = getConfig(ENDPOINT);
final Object endpointSensor = getConfig(ENDPOINT_SENSOR);
final Duration timeout = getConfig(TIMEOUT);
+ final List<Map<String, Object>> assertions = getAssertions(this, ASSERTIONS);
+
final Entity target = resolveTarget();
if (endpoint == null && endpointSensor == null) {
@@ -101,7 +106,7 @@ public class TestEndpointReachableImpl extends TargetableTestComponentImpl imple
public void run() {
HostAndPort val = supplier.get();
Asserts.assertNotNull(val);
- Asserts.assertTrue(Networking.isReachable(val), val+" not reachable");
+ assertSucceeds(assertions, val);
}});
sensors().set(Attributes.SERVICE_UP, true);
ServiceStateLogic.setExpectedState(this, Lifecycle.RUNNING);
@@ -114,6 +119,44 @@ public class TestEndpointReachableImpl extends TargetableTestComponentImpl imple
}
}
+ protected void assertSucceeds(List<Map<String, Object>> assertions, HostAndPort endpoint) {
+ Maybe<Object> checkReachableMaybe = getOnlyAssertionsValue(assertions, REACHABLE_KEY);
+ boolean checkReachable = checkReachableMaybe.isAbsentOrNull() || Boolean.TRUE.equals(TypeCoercions.coerce(checkReachableMaybe.get(), Boolean.class));
+ boolean reachable = Networking.isReachable(endpoint);
+ Asserts.assertEquals(reachable, checkReachable, endpoint+" "+(reachable ? "" : "not ")+"reachable");
+ }
+
+ /**
+ * Finds the value for the given key in one of the maps (or {@link Maybe#absent()} if not found).
+ *
+ * @throws IllegalArgumentException if multiple conflicts values for the key, or if there are other (unexpected) keys.
+ */
+ protected Maybe<Object> getOnlyAssertionsValue(List<Map<String, Object>> assertions, String key) {
+ Maybe<Object> result = Maybe.absent();
+ Set<String> keys = Sets.newLinkedHashSet();
+ boolean foundConflictingDuplicate = false;
+ if (assertions != null) {
+ for (Map<String, Object> assertionMap : assertions) {
+ if (assertionMap.containsKey(key)) {
+ Object val = assertionMap.get(REACHABLE_KEY);
+ if (result.isPresent() && !Objects.equal(result.get(), val)) {
+ foundConflictingDuplicate = true;
+ } else {
+ result = Maybe.of(val);
+ }
+ }
+ keys.addAll(assertionMap.keySet());
+ }
+ }
+ Set<String> unhandledKeys = Sets.difference(keys, ImmutableSet.of(key));
+ if (foundConflictingDuplicate) {
+ throw new IllegalArgumentException("Multiple conflicting values for assertion '"+key+"' in "+this);
+ } else if (unhandledKeys.size() > 0) {
+ throw new IllegalArgumentException("Unknown assertions "+unhandledKeys+" in "+this);
+ }
+ return result;
+ }
+
protected HostAndPort toHostAndPort(Object endpoint) {
if (endpoint == null) {
throw new IllegalArgumentException(String.format("The entity [%s] has no endpoint", getClass().getName()));
@@ -164,7 +207,7 @@ public class TestEndpointReachableImpl extends TargetableTestComponentImpl imple
* {@inheritDoc}
*/
public void stop() {
- ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPING);
+ ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPED);
sensors().set(Attributes.SERVICE_UP, false);
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4f98035f/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java
----------------------------------------------------------------------
diff --git a/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java
index e3e4456..45b04d0 100644
--- a/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java
+++ b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestHttpCallImpl.java
@@ -107,7 +107,7 @@ public class TestHttpCallImpl extends TargetableTestComponentImpl implements Tes
* {@inheritDoc}
*/
public void stop() {
- ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPING);
+ ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPED);
sensors().set(Attributes.SERVICE_UP, false);
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4f98035f/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java
----------------------------------------------------------------------
diff --git a/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java
index 633e982..df50064 100644
--- a/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java
+++ b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestSensorImpl.java
@@ -86,7 +86,7 @@ public class TestSensorImpl extends TargetableTestComponentImpl implements TestS
* {@inheritDoc}
*/
public void stop() {
- ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPING);
+ ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPED);
sensors().set(SERVICE_UP, false);
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/4f98035f/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEndpointReachableTest.java
----------------------------------------------------------------------
diff --git a/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEndpointReachableTest.java b/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEndpointReachableTest.java
index 20391df..efeb7eb 100644
--- a/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEndpointReachableTest.java
+++ b/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEndpointReachableTest.java
@@ -34,7 +34,6 @@ import org.apache.brooklyn.core.sensor.Sensors;
import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.javalang.JavaClassNames;
import org.apache.brooklyn.util.net.Networking;
import org.apache.brooklyn.util.time.Duration;
import org.slf4j.Logger;
@@ -45,6 +44,7 @@ import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.net.HostAndPort;
public class TestEndpointReachableTest extends BrooklynAppUnitTestSupport {
@@ -138,6 +138,50 @@ public class TestEndpointReachableTest extends BrooklynAppUnitTestSupport {
app.start(ImmutableList.of(loc));
}
+ @Test
+ public void testHardcodedEndpointReachableWithExplicitAssertionForReachable() throws Exception {
+ app.createAndManageChild(EntitySpec.create(TestEndpointReachable.class)
+ .configure(TestEndpointReachable.TARGET_ENTITY, app)
+ .configure(TestEndpointReachable.ENDPOINT, serverSocketHostAndPort.toString())
+ .configure(TestEndpointReachable.ASSERTIONS, ImmutableMap.of(TestEndpointReachable.REACHABLE_KEY, "true")));
+
+ app.start(ImmutableList.of(loc));
+ }
+
+ @Test
+ public void testExplicitAssertionForNotReachableWhenReachable() throws Exception {
+ TestEndpointReachable test = app.createAndManageChild(EntitySpec.create(TestEndpointReachable.class)
+ .configure(TestEndpointReachable.TARGET_ENTITY, app)
+ .configure(TestEndpointReachable.ENDPOINT, serverSocketHostAndPort.toString())
+ .configure(TestEndpointReachable.TIMEOUT, Duration.millis(100))
+ .configure(TestEndpointReachable.ASSERTIONS, ImmutableMap.of(TestEndpointReachable.REACHABLE_KEY, "false")));
+
+ try {
+ app.start(ImmutableList.of(loc));
+ } catch (Exception e) {
+ // It should fail to start
+ Exceptions.propagateIfFatal(e);
+ LOG.debug("As desired, failed to start app with TestEndpointReachable: "+e.toString());
+ }
+ EntityAsserts.assertAttributeEqualsEventually(test, TestEndpointReachable.SERVICE_UP, false);
+ EntityAsserts.assertAttributeEqualsEventually(test, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.ON_FIRE);
+ }
+
+ // Not a normal unit-test, because other processes on shared infrastructure can grab the port between
+ // us identifying it is free and us checking the reachability.
+ @Test(groups="Integration")
+ public void testExplicitAssertionForNotReachableWhenNotReachable() throws Exception {
+ HostAndPort unusedPort = findUnusedPort();
+ TestEndpointReachable test = app.createAndManageChild(EntitySpec.create(TestEndpointReachable.class)
+ .configure(TestEndpointReachable.TARGET_ENTITY, app)
+ .configure(TestEndpointReachable.ENDPOINT, unusedPort.toString())
+ .configure(TestEndpointReachable.ASSERTIONS, ImmutableMap.of(TestEndpointReachable.REACHABLE_KEY, "false")));
+
+ app.start(ImmutableList.of(loc));
+ EntityAsserts.assertAttributeEqualsEventually(test, TestEndpointReachable.SERVICE_UP, true);
+ EntityAsserts.assertAttributeEqualsEventually(test, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.RUNNING);
+ }
+
// Not a normal unit-test, because other processes on shared infrastructure can grab the port between
// us identifying it is free and us checking the reachability.
@Test(groups="Integration")
@@ -182,23 +226,9 @@ public class TestEndpointReachableTest extends BrooklynAppUnitTestSupport {
EntityAsserts.assertAttributeEqualsEventually(test, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.ON_FIRE);
}
- protected ServerSocket openServerPort() {
- int startPort = 58767;
- int endPort = 60000;
- int port = startPort;
+ protected ServerSocket openServerPort() throws IOException {
InetAddress localAddress = Networking.getLocalHost();
- do {
- try {
- ServerSocket ss = new ServerSocket(port, 1024, localAddress);
- LOG.info("acquired server-socket on port "+port+" for test "+JavaClassNames.niceClassAndMethod());
- return ss;
- } catch (IOException e) {
- // try next port
- port++;
- }
- } while (port <= endPort);
- Assert.fail("Could not open any local port in range "+startPort+"-"+endPort);
- throw new IllegalStateException("Impossible code to reach");
+ return new ServerSocket(0, 1024, localAddress);
}
protected HostAndPort findUnusedPort() {
[2/4] brooklyn-server git commit: Adds TestEndpointReachable (for
yaml test-cases)
Posted by al...@apache.org.
Adds TestEndpointReachable (for yaml test-cases)
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/9337ebff
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/9337ebff
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/9337ebff
Branch: refs/heads/master
Commit: 9337ebff6ce5c071a9b9585708010ed1f8b3bc2a
Parents: 0aba4ff
Author: Aled Sage <al...@gmail.com>
Authored: Tue May 17 11:14:36 2016 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Tue May 17 17:27:06 2016 +0100
----------------------------------------------------------------------
.../test/framework/TestEndpointReachable.java | 84 +++++++
.../framework/TestEndpointReachableImpl.java | 180 +++++++++++++++
.../framework/TestEndpointReachableTest.java | 222 +++++++++++++++++++
3 files changed, 486 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9337ebff/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEndpointReachable.java
----------------------------------------------------------------------
diff --git a/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEndpointReachable.java b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEndpointReachable.java
new file mode 100644
index 0000000..8fdcfd7
--- /dev/null
+++ b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEndpointReachable.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.test.framework;
+
+import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+
+/**
+ * Entity that checks if a TCP endpoint is reachable.
+ *
+ * For example:
+ * <pre>
+ * {@code
+ * services:
+ * - type: com.acme.MyEntityUnderTest
+ * id: entity-under-test
+ * - type: org.apache.brooklyn.test.framework.TestCase
+ * name: Tests
+ * brooklyn.children:
+ * - type: org.apache.brooklyn.test.framework.TestEndpointReachable
+ * name: Endpoint reachable
+ * brooklyn.config:
+ * targetId: entity-under-test
+ * timeout: 2m
+ * endpointSensor: datastore.url
+ * }
+ * </pre>
+ *
+ * The sensor's value can be in a number of different formats: a string in the form of {@code ip:port}
+ * or URI format; or a {@link com.google.common.net.HostAndPort}; or a {@link java.net.URI}; or a
+ * {@link java.net.URL} instance.
+ *
+ * Alternatively an explicit endpoint can be used (e.g. constructed from other sensors of
+ * the target entity):
+ * <pre>
+ * {@code
+ * services:
+ * - type: MyEntityUnderTest
+ * id: entity-under-test
+ * - type: org.apache.brooklyn.test.framework.TestCase
+ * name: Tests
+ * brooklyn.children:
+ * - type: org.apache.brooklyn.test.framework.TestEndpointReachable
+ * name: Endpoint reachable
+ * brooklyn.config:
+ * targetId: entity-under-test
+ * timeout: 2m
+ * endpoint:
+ * $brooklyn:formatString:
+ * - %s:%s"
+ * - $brooklyn:entity("entity-under-test").attributeWhenReady("host.name")
+ * - $brooklyn:entity("entity-under-test").attributeWhenReady("https.port")
+ * }
+ * </pre>
+ */
+@ImplementedBy(value = TestEndpointReachableImpl.class)
+public interface TestEndpointReachable extends BaseTest {
+
+ ConfigKey<String> ENDPOINT = ConfigKeys.newStringConfigKey(
+ "endpoint",
+ "Endpoint (be it URL or host:port) to test, for tcp-reachability; mutually exclusive with 'endpointSensor'");
+
+ ConfigKey<Object> ENDPOINT_SENSOR = ConfigKeys.newConfigKey(
+ Object.class,
+ "endpointSensor",
+ "Sensor (or name of sensor) on target that advertises the endpoint (to test for tcp-reachability); mutually exclusive with 'endpoint'");
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9337ebff/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEndpointReachableImpl.java
----------------------------------------------------------------------
diff --git a/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEndpointReachableImpl.java b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEndpointReachableImpl.java
new file mode 100644
index 0000000..d759507
--- /dev/null
+++ b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestEndpointReachableImpl.java
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.test.framework;
+
+import static org.apache.brooklyn.test.framework.TestFrameworkAssertions.getAssertions;
+
+import java.net.URI;
+import java.net.URL;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.test.framework.TestFrameworkAssertions.AssertionSupport;
+import org.apache.brooklyn.test.framework.TestHttpCall.HttpAssertionTarget;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.http.HttpTool;
+import org.apache.brooklyn.util.net.Networking;
+import org.apache.brooklyn.util.text.Strings;
+import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.net.HostAndPort;
+
+/**
+ * {@inheritDoc}
+ */
+public class TestEndpointReachableImpl extends TargetableTestComponentImpl implements TestEndpointReachable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(TestEndpointReachableImpl.class);
+
+ @Override
+ public void start(Collection<? extends Location> locations) {
+ if (!getChildren().isEmpty()) {
+ throw new RuntimeException(String.format("The entity [%s] cannot have child entities", getClass().getName()));
+ }
+ ServiceStateLogic.setExpectedState(this, Lifecycle.STARTING);
+ final String endpoint = getConfig(ENDPOINT);
+ final Object endpointSensor = getConfig(ENDPOINT_SENSOR);
+ final Duration timeout = getConfig(TIMEOUT);
+ final Entity target = resolveTarget();
+
+ if (endpoint == null && endpointSensor == null) {
+ throw new RuntimeException(String.format("The entity [%s] must be configured with one of endpoint or endpointSensor", getClass().getName()));
+ } else if (endpoint != null && endpointSensor != null) {
+ throw new RuntimeException(String.format("The entity [%s] must be configured with only one of endpoint or endpointSensor", getClass().getName()));
+ }
+
+ final Supplier<HostAndPort> supplier = new Supplier<HostAndPort>() {
+ @Override
+ public HostAndPort get() {
+ Object val;
+ if (endpoint != null) {
+ val = endpoint;
+ } else if (endpointSensor instanceof AttributeSensor) {
+ val = target.sensors().get((AttributeSensor<?>)endpointSensor);
+ } else if (endpointSensor instanceof CharSequence) {
+ AttributeSensor<Object> sensor = Sensors.newSensor(Object.class, ((CharSequence)endpointSensor).toString());
+ val = target.sensors().get(sensor);
+ } else {
+ throw new IllegalArgumentException(String.format("The entity [%s] has endpointSensor of invalid type %s [%s]", getClass().getName(), endpointSensor.getClass().getName(), endpointSensor));
+ }
+ return (val == null) ? null : toHostAndPort(val);
+ }
+ };
+ if (endpoint != null) {
+ // fail-fast if have a static endpoint value
+ supplier.get();
+ }
+
+ try {
+ Asserts.succeedsEventually(ImmutableMap.of("timeout", timeout), new Runnable() {
+ @Override
+ public void run() {
+ HostAndPort val = supplier.get();
+ Asserts.assertNotNull(val);
+ Asserts.assertTrue(Networking.isReachable(val), val+" not reachable");
+ }});
+ sensors().set(Attributes.SERVICE_UP, true);
+ ServiceStateLogic.setExpectedState(this, Lifecycle.RUNNING);
+
+ } catch (Throwable t) {
+ LOG.info("{} [{}] test failed", this, endpoint != null ? endpoint : endpointSensor);
+ sensors().set(Attributes.SERVICE_UP, false);
+ ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE);
+ throw Exceptions.propagate(t);
+ }
+ }
+
+ protected HostAndPort toHostAndPort(Object endpoint) {
+ if (endpoint == null) {
+ throw new IllegalArgumentException(String.format("The entity [%s] has no endpoint", getClass().getName()));
+ } else if (endpoint instanceof String) {
+ return toHostAndPort((String)endpoint);
+ } else if (endpoint instanceof URI) {
+ return toHostAndPort(((URI)endpoint).toString());
+ } else if (endpoint instanceof URL) {
+ return toHostAndPort(((URL)endpoint).toString());
+ } else if (endpoint instanceof HostAndPort) {
+ return (HostAndPort)endpoint;
+ } else {
+ throw new IllegalArgumentException(String.format("The entity [%s] has endpoint of invalid type %s [%s]", getClass().getName(), endpoint.getClass().getName(), endpoint));
+ }
+ }
+
+ protected HostAndPort toHostAndPort(String endpoint) {
+ if (Strings.isEmpty(endpoint)) {
+ throw new IllegalArgumentException(String.format("The entity [%s] has no endpoint", getClass().getName()));
+ }
+ try {
+ URI uri = URI.create(endpoint);
+ int port;
+ if (uri.getPort() != -1) {
+ port = uri.getPort();
+ } else {
+ if ("http".equalsIgnoreCase(uri.getScheme())) {
+ port = 80;
+ } else if ("https".equalsIgnoreCase(uri.getScheme())) {
+ port = 443;
+ } else {
+ throw new IllegalArgumentException(String.format("The entity [%s] with endpoint [%s] has no port", getClass().getName(), endpoint));
+ }
+ }
+ return HostAndPort.fromParts(uri.getHost(), port);
+ } catch (IllegalArgumentException e) {
+ // Not a URL; fall-back to host-and-port
+ }
+
+ HostAndPort result = HostAndPort.fromString(endpoint);
+ if (!result.hasPort()) {
+ throw new IllegalArgumentException(String.format("The entity [%s] with endpoint [%s] has no port", getClass().getName(), endpoint));
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void stop() {
+ ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPING);
+ sensors().set(Attributes.SERVICE_UP, false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void restart() {
+ final Collection<Location> locations = Lists.newArrayList(getLocations());
+ stop();
+ start(locations);
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9337ebff/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEndpointReachableTest.java
----------------------------------------------------------------------
diff --git a/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEndpointReachableTest.java b/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEndpointReachableTest.java
new file mode 100644
index 0000000..20391df
--- /dev/null
+++ b/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestEndpointReachableTest.java
@@ -0,0 +1,222 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.brooklyn.test.framework;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.URI;
+import java.net.URL;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.EntityAsserts;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.javalang.JavaClassNames;
+import org.apache.brooklyn.util.net.Networking;
+import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.net.HostAndPort;
+
+public class TestEndpointReachableTest extends BrooklynAppUnitTestSupport {
+
+ private static final Logger LOG = LoggerFactory.getLogger(TestEndpointReachableTest.class);
+
+ private LocalhostMachineProvisioningLocation loc;
+ private ServerSocket serverSocket;
+ private HostAndPort serverSocketHostAndPort;
+
+ @BeforeMethod(alwaysRun=true)
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ loc = app.newLocalhostProvisioningLocation();
+ serverSocket = openServerPort();
+ serverSocketHostAndPort = toHostAndPort(serverSocket);
+ }
+
+ @AfterMethod(alwaysRun=true)
+ @Override
+ public void tearDown() throws Exception {
+ try {
+ if (serverSocket != null) serverSocket.close();
+ } catch (IOException e) {
+ // keep going; stop the other server sockets etc.
+ LOG.warn("Error closing server socket "+serverSocket+"; continuing", e);
+ }
+ super.tearDown();
+ }
+
+ @Test
+ public void testHardcodedEndpointReachable() throws Exception {
+ app.createAndManageChild(EntitySpec.create(TestEndpointReachable.class)
+ .configure(TestEndpointReachable.TARGET_ENTITY, app)
+ .configure(TestEndpointReachable.ENDPOINT, serverSocketHostAndPort.toString()));
+
+ app.start(ImmutableList.of(loc));
+ }
+
+ @Test
+ public void testSensorHostAndPortStringReachable() throws Exception {
+ AttributeSensor<String> sensor = Sensors.newStringSensor("test.reachable.endpoint");
+ app.createAndManageChild(EntitySpec.create(TestEndpointReachable.class)
+ .configure(TestEndpointReachable.TARGET_ENTITY, app)
+ .configure(TestEndpointReachable.ENDPOINT_SENSOR, sensor));
+ app.sensors().set(sensor, serverSocketHostAndPort.toString());
+ app.start(ImmutableList.of(loc));
+ }
+
+ @Test
+ public void testSensorHostAndPortReachable() throws Exception {
+ AttributeSensor<HostAndPort> sensor = Sensors.newSensor(HostAndPort.class, "test.reachable.endpoint");
+ app.createAndManageChild(EntitySpec.create(TestEndpointReachable.class)
+ .configure(TestEndpointReachable.TARGET_ENTITY, app)
+ .configure(TestEndpointReachable.ENDPOINT_SENSOR, sensor));
+ app.sensors().set(sensor, serverSocketHostAndPort);
+ app.start(ImmutableList.of(loc));
+ }
+
+ @Test
+ public void testSensorUriStringReachable() throws Exception {
+ String sensorVal = "http://"+serverSocketHostAndPort.getHostText()+":"+serverSocketHostAndPort.getPort();
+ AttributeSensor<String> sensor = Sensors.newStringSensor("test.reachable.endpoint");
+ app.createAndManageChild(EntitySpec.create(TestEndpointReachable.class)
+ .configure(TestEndpointReachable.TARGET_ENTITY, app)
+ .configure(TestEndpointReachable.ENDPOINT_SENSOR, sensor));
+ app.sensors().set(sensor, sensorVal);
+ app.start(ImmutableList.of(loc));
+ }
+
+ @Test
+ public void testSensorUriReachable() throws Exception {
+ URI sensorVal = URI.create("http://"+serverSocketHostAndPort.getHostText()+":"+serverSocketHostAndPort.getPort());
+ AttributeSensor<URI> sensor = Sensors.newSensor(URI.class, "test.reachable.endpoint");
+ app.createAndManageChild(EntitySpec.create(TestEndpointReachable.class)
+ .configure(TestEndpointReachable.TARGET_ENTITY, app)
+ .configure(TestEndpointReachable.ENDPOINT_SENSOR, sensor));
+ app.sensors().set(sensor, sensorVal);
+ app.start(ImmutableList.of(loc));
+ }
+
+ @Test
+ public void testSensorUrlReachable() throws Exception {
+ URL sensorVal = new URL("http://"+serverSocketHostAndPort.getHostText()+":"+serverSocketHostAndPort.getPort());
+ AttributeSensor<URL> sensor = Sensors.newSensor(URL.class, "test.reachable.endpoint");
+ app.createAndManageChild(EntitySpec.create(TestEndpointReachable.class)
+ .configure(TestEndpointReachable.TARGET_ENTITY, app)
+ .configure(TestEndpointReachable.ENDPOINT_SENSOR, sensor));
+ app.sensors().set(sensor, sensorVal);
+ app.start(ImmutableList.of(loc));
+ }
+
+ // Not a normal unit-test, because other processes on shared infrastructure can grab the port between
+ // us identifying it is free and us checking the reachability.
+ @Test(groups="Integration")
+ public void testHardcodedEndpointNotReachable() throws Exception {
+ HostAndPort unusedPort = findUnusedPort();
+ TestEndpointReachable test = app.createAndManageChild(EntitySpec.create(TestEndpointReachable.class)
+ .configure(TestEndpointReachable.TARGET_ENTITY, app)
+ .configure(TestEndpointReachable.ENDPOINT, unusedPort.toString())
+ .configure(TestEndpointReachable.TIMEOUT, Duration.millis(100)));
+
+ try {
+ app.start(ImmutableList.of(loc));
+ } catch (Exception e) {
+ // It should fail to start
+ Exceptions.propagateIfFatal(e);
+ LOG.debug("As desired, failed to start app with TestEndpointReachable: "+e.toString());
+ }
+ EntityAsserts.assertAttributeEqualsEventually(test, TestEndpointReachable.SERVICE_UP, false);
+ EntityAsserts.assertAttributeEqualsEventually(test, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.ON_FIRE);
+ }
+
+ // Not a normal unit-test, because other processes on shared infrastructure can grab the port between
+ // us identifying it is free and us checking the reachability.
+ @Test(groups="Integration")
+ public void testSensorEndpointNotReachable() throws Exception {
+ AttributeSensor<String> sensor = Sensors.newStringSensor("test.reachable.endpoint");
+ HostAndPort unusedPort = findUnusedPort();
+ TestEndpointReachable test = app.createAndManageChild(EntitySpec.create(TestEndpointReachable.class)
+ .configure(TestEndpointReachable.TARGET_ENTITY, app)
+ .configure(TestEndpointReachable.ENDPOINT, unusedPort.toString())
+ .configure(TestEndpointReachable.TIMEOUT, Duration.millis(100)));
+ app.sensors().set(sensor, unusedPort.toString());
+
+ try {
+ app.start(ImmutableList.of(loc));
+ } catch (Exception e) {
+ // It should fail to start
+ Exceptions.propagateIfFatal(e);
+ LOG.debug("As desired, failed to start app with TestEndpointReachable: "+e.toString());
+ }
+ EntityAsserts.assertAttributeEqualsEventually(test, TestEndpointReachable.SERVICE_UP, false);
+ EntityAsserts.assertAttributeEqualsEventually(test, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.ON_FIRE);
+ }
+
+ protected ServerSocket openServerPort() {
+ int startPort = 58767;
+ int endPort = 60000;
+ int port = startPort;
+ InetAddress localAddress = Networking.getLocalHost();
+ do {
+ try {
+ ServerSocket ss = new ServerSocket(port, 1024, localAddress);
+ LOG.info("acquired server-socket on port "+port+" for test "+JavaClassNames.niceClassAndMethod());
+ return ss;
+ } catch (IOException e) {
+ // try next port
+ port++;
+ }
+ } while (port <= endPort);
+ Assert.fail("Could not open any local port in range "+startPort+"-"+endPort);
+ throw new IllegalStateException("Impossible code to reach");
+ }
+
+ protected HostAndPort findUnusedPort() {
+ int startPort = 58767;
+ int endPort = 60000;
+ int port = startPort;
+ InetAddress localAddress = Networking.getLocalHost();
+ do {
+ if (Networking.isPortAvailable(localAddress, port)) {
+ return HostAndPort.fromParts(localAddress.getHostAddress(), port);
+ }
+ port++;
+ } while (port <= endPort);
+ Assert.fail("Could not find available port in range "+startPort+"-"+endPort);
+ throw new IllegalStateException("Impossible code to reach");
+ }
+
+ protected HostAndPort toHostAndPort(ServerSocket ss) {
+ return HostAndPort.fromParts(serverSocket.getInetAddress().getHostAddress(), serverSocket.getLocalPort());
+ }
+}