You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2017/02/15 18:57:24 UTC
[01/10] brooklyn-server git commit: Add DurationPredicates
Repository: brooklyn-server
Updated Branches:
refs/heads/master 39301e0f7 -> 110482861
Add DurationPredicates
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/070c6f54
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/070c6f54
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/070c6f54
Branch: refs/heads/master
Commit: 070c6f54abb0c689e55656661f7f699c14c571e3
Parents: 6571bab
Author: Mike Zaccardo <mi...@cloudsoftcorp.com>
Authored: Thu Feb 9 11:16:29 2017 -0500
Committer: Mike Zaccardo <mi...@cloudsoftcorp.com>
Committed: Thu Feb 9 16:52:20 2017 -0500
----------------------------------------------------------------------
.../brooklyn/util/time/DurationPredicates.java | 162 +++++++++++++++++++
.../util/time/DurationPredicatesTest.java | 150 +++++++++++++++++
2 files changed, 312 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/070c6f54/utils/common/src/main/java/org/apache/brooklyn/util/time/DurationPredicates.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/time/DurationPredicates.java b/utils/common/src/main/java/org/apache/brooklyn/util/time/DurationPredicates.java
new file mode 100644
index 0000000..162f6f5
--- /dev/null
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/time/DurationPredicates.java
@@ -0,0 +1,162 @@
+/*
+ * 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.util.time;
+
+import java.util.concurrent.TimeUnit;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.base.Stopwatch;
+
+public class DurationPredicates {
+
+ /**
+ * @return A {@link Predicate} that checks if a {@link Duration} supplied to
+ * {@link Predicate#apply(Object)} is positive.
+ */
+ public static Predicate<Duration> positive() {
+ return new Positive();
+ }
+
+ protected static class Positive implements Predicate<Duration> {
+ @Override
+ public boolean apply(Duration input) {
+ return input != null && input.isPositive();
+ }
+ }
+
+ /**
+ * @return A {@link Predicate} that checks if a {@link Duration} supplied to
+ * {@link Predicate#apply(Object)} is negative.
+ */
+ public static Predicate<Duration> negative() {
+ return new Negative();
+ }
+
+ protected static class Negative implements Predicate<Duration> {
+ @Override
+ public boolean apply(Duration input) {
+ return input != null && input.isNegative();
+ }
+ }
+
+ /**
+ * @param duration
+ * The {@link Duration} that will be the basis for comparison in
+ * the returned {@link Predicate}.
+ * @return A {@link Predicate} that checks if a {@link Duration} supplied to
+ * {@link Predicate#apply(Object)} is longer than the
+ * {@link Duration} that was supplied to this method.
+ */
+ public static Predicate<Duration> longerThan(final Duration duration) {
+ return new LongerThan(duration);
+ }
+
+ protected static class LongerThan implements Predicate<Duration> {
+ private final Duration value;
+
+ protected LongerThan(Duration value) {
+ Preconditions.checkNotNull(value);
+ this.value = value;
+ }
+
+ @Override
+ public boolean apply(Duration input) {
+ return input != null && input.isLongerThan(value);
+ }
+ }
+
+ /**
+ * @param duration
+ * The {@link Duration} that will be the basis for comparison in
+ * the returned {@link Predicate}.
+ * @return A {@link Predicate} that checks if a {@link Duration} supplied to
+ * {@link Predicate#apply(Object)} is shorter than the
+ * {@link Duration} that was supplied to this method.
+ */
+ public static Predicate<Duration> shorterThan(final Duration duration) {
+ return new ShorterThan(duration);
+ }
+
+ protected static class ShorterThan implements Predicate<Duration> {
+ private final Duration value;
+
+ protected ShorterThan(Duration value) {
+ Preconditions.checkNotNull(value);
+ this.value = value;
+ }
+
+ @Override
+ public boolean apply(Duration input) {
+ return input != null && input.isShorterThan(value);
+ }
+ }
+
+ /**
+ * @param duration
+ * The {@link Duration} that will be the basis for comparison in
+ * the returned {@link Predicate}.
+ * @return A {@link Predicate} that checks if a {@link Stopwatch} supplied to
+ * {@link Predicate#apply(Object)} is longer than the
+ * {@link Duration} that was supplied to this method.
+ */
+ public static Predicate<Stopwatch> longerThanDuration(final Duration duration) {
+ return new LongerThanDuration(duration);
+ }
+
+ protected static class LongerThanDuration implements Predicate<Stopwatch> {
+ private final Duration value;
+
+ protected LongerThanDuration(Duration value) {
+ Preconditions.checkNotNull(value);
+ this.value = value;
+ }
+
+ @Override
+ public boolean apply(Stopwatch input) {
+ return input != null && Duration.millis(input.elapsed(TimeUnit.MILLISECONDS)).isLongerThan(value);
+ }
+ }
+
+ /**
+ * @param duration
+ * The {@link Duration} that will be the basis for comparison in
+ * the returned {@link Predicate}.
+ * @return A {@link Predicate} that checks if a {@link Stopwatch} supplied to
+ * {@link Predicate#apply(Object)} is shorter than the
+ * {@link Duration} that was supplied to this method.
+ */
+ public static Predicate<Stopwatch> shorterThanDuration(final Duration duration) {
+ return new ShorterThanDuration(duration);
+ }
+
+ protected static class ShorterThanDuration implements Predicate<Stopwatch> {
+ private final Duration value;
+
+ protected ShorterThanDuration(Duration value) {
+ Preconditions.checkNotNull(value);
+ this.value = value;
+ }
+
+ @Override
+ public boolean apply(Stopwatch input) {
+ return input != null && Duration.millis(input.elapsed(TimeUnit.MILLISECONDS)).isShorterThan(value);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/070c6f54/utils/common/src/test/java/org/apache/brooklyn/util/time/DurationPredicatesTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/time/DurationPredicatesTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/time/DurationPredicatesTest.java
new file mode 100644
index 0000000..39d4184
--- /dev/null
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/time/DurationPredicatesTest.java
@@ -0,0 +1,150 @@
+/*
+ * 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.util.time;
+
+import static org.testng.Assert.assertEquals;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+public class DurationPredicatesTest {
+
+ private static final List<Duration> TEST_DURATIONS_POSITIVE = Lists.newArrayList(null,
+ Duration.minutes(1), Duration.minutes(2), Duration.minutes(5), Duration.minutes(10));
+
+ private static final List<Duration> TEST_DURATIONS_NEGATIVE = Lists.newArrayList(null,
+ Duration.minutes(-1), Duration.minutes(-2), Duration.minutes(-5), Duration.minutes(-10));
+
+ private static final List<Stopwatch> TEST_STOPWATCHES = new ArrayList<>(TEST_DURATIONS_POSITIVE.size());
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ for (Duration duration : TEST_DURATIONS_POSITIVE) {
+ TEST_STOPWATCHES.add(createStopwatchWithElapsedTime(duration));
+ }
+ }
+
+ @Test
+ public void testPositive() {
+ Iterable<Duration> result = Iterables.filter(TEST_DURATIONS_POSITIVE, DurationPredicates.positive());
+ assertEquals(Iterables.size(result), Iterables.size(TEST_DURATIONS_POSITIVE) - 1);
+
+ result = Iterables.filter(TEST_DURATIONS_NEGATIVE, DurationPredicates.positive());
+ assertEquals(Iterables.size(result), 0);
+ }
+
+ @Test
+ public void testNegative() {
+ Iterable<Duration> result = Iterables.filter(TEST_DURATIONS_POSITIVE, DurationPredicates.negative());
+ assertEquals(Iterables.size(result), 0);
+
+ result = Iterables.filter(TEST_DURATIONS_NEGATIVE, DurationPredicates.negative());
+ assertEquals(Iterables.size(result), Iterables.size(TEST_DURATIONS_NEGATIVE) - 1);
+ }
+
+ @Test
+ public void testLongerThan() {
+ Duration testDuration = Duration.minutes(3);
+
+ Iterable<Duration> result = Iterables.filter(TEST_DURATIONS_POSITIVE,
+ DurationPredicates.longerThan(testDuration));
+ assertEquals(Iterables.size(result), 2);
+
+ result = Iterables.filter(TEST_DURATIONS_NEGATIVE, DurationPredicates.longerThan(testDuration));
+ assertEquals(Iterables.size(result), 0);
+
+ testDuration = Duration.minutes(-3);
+
+ result = Iterables.filter(TEST_DURATIONS_POSITIVE, DurationPredicates.longerThan(testDuration));
+ assertEquals(Iterables.size(result), 4);
+
+ result = Iterables.filter(TEST_DURATIONS_NEGATIVE, DurationPredicates.longerThan(testDuration));
+ assertEquals(Iterables.size(result), 2);
+ }
+
+ @Test
+ public void testShorterThan() {
+ Duration testDuration = Duration.minutes(3);
+
+ Iterable<Duration> result = Iterables.filter(TEST_DURATIONS_POSITIVE,
+ DurationPredicates.shorterThan(testDuration));
+ assertEquals(Iterables.size(result), 2);
+
+ result = Iterables.filter(TEST_DURATIONS_NEGATIVE, DurationPredicates.shorterThan(testDuration));
+ assertEquals(Iterables.size(result), 4);
+
+ testDuration = Duration.minutes(-3);
+
+ result = Iterables.filter(TEST_DURATIONS_POSITIVE, DurationPredicates.shorterThan(testDuration));
+ assertEquals(Iterables.size(result), 0);
+
+ result = Iterables.filter(TEST_DURATIONS_NEGATIVE, DurationPredicates.shorterThan(testDuration));
+ assertEquals(Iterables.size(result), 2);
+ }
+
+ @Test
+ public void testLongerThanDuration() {
+ Duration testDuration = Duration.minutes(3);
+
+ Iterable<Stopwatch> result = Iterables.filter(TEST_STOPWATCHES,
+ DurationPredicates.longerThanDuration(testDuration));
+ assertEquals(Iterables.size(result), 2);
+
+ testDuration = Duration.minutes(-3);
+
+ result = Iterables.filter(TEST_STOPWATCHES, DurationPredicates.longerThanDuration(testDuration));
+ assertEquals(Iterables.size(result), 4);
+ }
+
+ @Test
+ public void testShorterThanDuration() {
+ Duration testDuration = Duration.minutes(3);
+
+ Iterable<Stopwatch> result = Iterables.filter(TEST_STOPWATCHES,
+ DurationPredicates.shorterThanDuration(testDuration));
+ assertEquals(Iterables.size(result), 2);
+
+ testDuration = Duration.minutes(-3);
+
+ result = Iterables.filter(TEST_STOPWATCHES, DurationPredicates.shorterThanDuration(testDuration));
+ assertEquals(Iterables.size(result), 0);
+ }
+
+ private static Stopwatch createStopwatchWithElapsedTime(Duration duration) throws Exception {
+ if (duration == null) {
+ return null;
+ }
+
+ Stopwatch stopwatch = Stopwatch.createUnstarted();
+
+ Field field = stopwatch.getClass().getDeclaredField("elapsedNanos");
+ field.setAccessible(true);
+ field.set(stopwatch, duration.nanos());
+
+ return stopwatch;
+ }
+}
[08/10] brooklyn-server git commit: fix merge errors
Posted by he...@apache.org.
fix merge errors
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/1871a521
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/1871a521
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/1871a521
Branch: refs/heads/master
Commit: 1871a5219f2a25e172e2b5367315aef55bb79457
Parents: 8809d5c
Author: Andrea Turli <an...@gmail.com>
Authored: Mon Feb 13 15:39:39 2017 +0100
Committer: Andrea Turli <an...@gmail.com>
Committed: Tue Feb 14 12:35:13 2017 +0100
----------------------------------------------------------------------
.../brooklyn/camp/brooklyn/AbstractYamlRebindTest.java | 11 -----------
.../core/effector/http/HttpCommandEffectorTest.java | 2 +-
2 files changed, 1 insertion(+), 12 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/1871a521/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
index 9168b25..0d6d5c2 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
@@ -29,14 +29,7 @@ import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.entity.EntitySpec;
import org.apache.brooklyn.api.mgmt.ManagementContext;
import org.apache.brooklyn.api.mgmt.Task;
-<<<<<<< 3d318e4e78085519233bcc763e22320ca40403df
-import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatform;
-import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatformLauncherNoServer;
import org.apache.brooklyn.camp.brooklyn.spi.creation.CampTypePlanTransformer;
-=======
->>>>>>> add more tests for HttpCommandEffector
-import org.apache.brooklyn.camp.spi.Assembly;
-import org.apache.brooklyn.camp.spi.AssemblyTemplate;
import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
import org.apache.brooklyn.core.entity.Entities;
import org.apache.brooklyn.core.entity.StartableApplication;
@@ -48,7 +41,6 @@ import org.apache.brooklyn.core.mgmt.rebind.RebindTestFixture;
import org.apache.brooklyn.core.typereg.RegisteredTypeLoadingContexts;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.core.ResourceUtils;
-import org.apache.brooklyn.util.core.config.ConfigBag;
import org.apache.brooklyn.util.stream.Streams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -56,9 +48,6 @@ import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
public class AbstractYamlRebindTest extends RebindTestFixture<StartableApplication> {
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/1871a521/core/src/test/java/org/apache/brooklyn/core/effector/http/HttpCommandEffectorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/http/HttpCommandEffectorTest.java b/core/src/test/java/org/apache/brooklyn/core/effector/http/HttpCommandEffectorTest.java
index 0580c39..8d620a4 100644
--- a/core/src/test/java/org/apache/brooklyn/core/effector/http/HttpCommandEffectorTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/http/HttpCommandEffectorTest.java
@@ -202,7 +202,7 @@ public class HttpCommandEffectorTest extends BrooklynAppUnitTestSupport {
Object output = testEntity.invoke(EFFECTOR_HTTP_COMMAND, ImmutableMap.<String, Object>of()).getUnchecked(Duration.seconds(1));
assertEquals(output, "[\"key\", \"value\"]");
- assertEquals(server.getRequestCount(), "[\"key\", \"value\"]");
+ assertEquals(server.getRequestCount(), 1);
assertSent(server, "POST", "/post");
}
[03/10] brooklyn-server git commit: fix CompositeEffector logic
Posted by he...@apache.org.
fix CompositeEffector logic
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/119ba5a4
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/119ba5a4
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/119ba5a4
Branch: refs/heads/master
Commit: 119ba5a47b4a5198ae99927511e35107d2ebce89
Parents: eadec9a
Author: Andrea Turli <an...@gmail.com>
Authored: Mon Jan 23 17:12:14 2017 +0100
Committer: Andrea Turli <an...@gmail.com>
Committed: Mon Feb 13 15:09:31 2017 +0100
----------------------------------------------------------------------
.../core/effector/CompositeEffector.java | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/119ba5a4/core/src/main/java/org/apache/brooklyn/core/effector/CompositeEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/CompositeEffector.java b/core/src/main/java/org/apache/brooklyn/core/effector/CompositeEffector.java
index 88cd92c..ca627bb 100644
--- a/core/src/main/java/org/apache/brooklyn/core/effector/CompositeEffector.java
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/CompositeEffector.java
@@ -36,9 +36,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.annotations.Beta;
+import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
-import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
@@ -95,19 +95,22 @@ public class CompositeEffector extends AddEffector {
List <Object> results = Lists.newArrayList();
if (!override) {
- List<Effector<?>> originalEffectors = FluentIterable.from(entity().getEntityType().getEffectors())
- .filter(new Predicate<Effector<?>>() {
+ Optional<Effector<?>> effectorOptional = Iterables.tryFind(entity().getEntityType().getEffectors(), new Predicate<Effector<?>>() {
@Override
public boolean apply(@Nullable Effector<?> input) {
return input.getName().equals("original-" + effector.getName());
}
- })
- .toList();
-
- for (Effector<?> originalEffector : originalEffectors) {
- results.add(invokeEffectorNamed(originalEffector.getName(), params));
+ });
+ // if it is a stop effector, it has to be executed as last effector
+ if (effectorOptional.isPresent()) {
+ if (effectorOptional.get().getName().endsWith("-stop")) {
+ effectorNames.add(effectorOptional.get().getName());
+ } else {
+ effectorNames.add(0, effectorOptional.get().getName());
+ }
}
}
+
for (String eff : effectorNames) {
results.add(invokeEffectorNamed(eff, params));
}
[10/10] brooklyn-server git commit: This closes #531
Posted by he...@apache.org.
This closes #531
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/11048286
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/11048286
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/11048286
Branch: refs/heads/master
Commit: 1104828610886737323dae9a91d7a2d760cb923a
Parents: fd03312 1871a52
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Feb 15 18:57:12 2017 +0000
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Feb 15 18:57:12 2017 +0000
----------------------------------------------------------------------
.../camp/brooklyn/AbstractYamlRebindTest.java | 26 +-
.../CompositeEffectorYamlRebindTest.java | 102 +++++++
.../brooklyn/CompositeEffectorYamlTest.java | 79 ++++++
.../HttpCommandEffectorYamlRebindTest.java | 92 +++++++
.../brooklyn/HttpCommandEffectorYamlTest.java | 79 ++++++
.../brooklyn/core/effector/AddSensor.java | 2 +
.../core/effector/CompositeEffector.java | 135 +++++++++
.../brooklyn/core/effector/Effectors.java | 4 +
.../core/effector/http/HttpCommandEffector.java | 209 ++++++++++++++
.../core/entity/EntityInitializers.java | 32 ++-
.../core/sensor/http/HttpRequestSensor.java | 47 ++--
.../CompositeEffectorIntegrationTest.java | 91 +++++++
.../core/effector/CompositeEffectorTest.java | 262 ++++++++++++++++++
.../HttpCommandEffectorIntegrationTest.java | 125 +++++++++
.../effector/http/HttpCommandEffectorTest.java | 272 +++++++++++++++++++
.../core/effector/http/int-response.json | 16 ++
.../core/effector/http/list-response.json | 19 ++
.../brooklyn/core/effector/http/login.json | 16 ++
.../core/effector/http/map-response.json | 16 ++
.../org/apache/brooklyn/core/effector/test.json | 16 ++
.../apache/brooklyn/rest/api/EffectorApi.java | 28 +-
21 files changed, 1619 insertions(+), 49 deletions(-)
----------------------------------------------------------------------
[06/10] brooklyn-server git commit: add more tests for
HttpCommandEffector
Posted by he...@apache.org.
add more tests for HttpCommandEffector
- add unit test (HttpCommandEffectorTest)
- add YamlTest (HttpCommandEffectorYamlTest)
- add YamlRebindTest (HttpCommandEffectorYamlRebindTest)
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/b0b83da7
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/b0b83da7
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/b0b83da7
Branch: refs/heads/master
Commit: b0b83da785944b3929866a89470b52cd8215684f
Parents: 3d318e4
Author: Andrea Turli <an...@gmail.com>
Authored: Tue Jan 31 16:51:05 2017 +0100
Committer: Andrea Turli <an...@gmail.com>
Committed: Mon Feb 13 15:16:02 2017 +0100
----------------------------------------------------------------------
.../camp/brooklyn/AbstractYamlRebindTest.java | 21 ++-
.../HttpCommandEffectorYamlRebindTest.java | 92 +++++++++
.../brooklyn/HttpCommandEffectorYamlTest.java | 79 ++++++++
.../core/effector/CompositeEffector.java | 16 +-
.../core/effector/http/HttpCommandEffector.java | 105 ++++++++---
.../HttpCommandEffectorIntegrationTest.java | 42 ++---
.../effector/http/HttpCommandEffectorTest.java | 188 +++++++++++++++++++
.../brooklyn/core/effector/http/login.json | 16 ++
8 files changed, 490 insertions(+), 69 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b0b83da7/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
index 9322866..9168b25 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
@@ -29,9 +29,12 @@ import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.entity.EntitySpec;
import org.apache.brooklyn.api.mgmt.ManagementContext;
import org.apache.brooklyn.api.mgmt.Task;
+<<<<<<< 3d318e4e78085519233bcc763e22320ca40403df
import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatform;
import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatformLauncherNoServer;
import org.apache.brooklyn.camp.brooklyn.spi.creation.CampTypePlanTransformer;
+=======
+>>>>>>> add more tests for HttpCommandEffector
import org.apache.brooklyn.camp.spi.Assembly;
import org.apache.brooklyn.camp.spi.AssemblyTemplate;
import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
@@ -59,13 +62,13 @@ import com.google.common.collect.Iterables;
public class AbstractYamlRebindTest extends RebindTestFixture<StartableApplication> {
- private static final Logger LOG = LoggerFactory.getLogger(AbstractYamlTest.class);
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractYamlRebindTest.class);
protected static final String TEST_VERSION = "0.1.2";
protected BrooklynCampPlatform platform;
protected BrooklynCampPlatformLauncherNoServer launcher;
private boolean forceUpdate;
-
+
@BeforeMethod(alwaysRun = true)
@Override
public void setUp() throws Exception {
@@ -106,7 +109,7 @@ public class AbstractYamlRebindTest extends RebindTestFixture<StartableApplicati
}
return result;
}
-
+
@Override
protected StartableApplication createApp() {
return null;
@@ -116,11 +119,11 @@ public class AbstractYamlRebindTest extends RebindTestFixture<StartableApplicati
protected ManagementContext mgmt() {
return (newManagementContext != null) ? newManagementContext : origManagementContext;
}
-
+
///////////////////////////////////////////////////
// TODO code below is duplicate of AbstractYamlTest
///////////////////////////////////////////////////
-
+
protected void waitForApplicationTasks(Entity app) {
Set<Task<?>> tasks = BrooklynTaskTags.getTasksInEntityContext(mgmt().getExecutionManager(), app);
getLogger().info("Waiting on " + tasks.size() + " task(s)");
@@ -149,7 +152,7 @@ public class AbstractYamlRebindTest extends RebindTestFixture<StartableApplicati
protected Entity createAndStartApplication(String... multiLineYaml) throws Exception {
return createAndStartApplication(joinLines(multiLineYaml));
}
-
+
protected Entity createAndStartApplication(String input) throws Exception {
return createAndStartApplication(input, MutableMap.<String,String>of());
}
@@ -168,18 +171,18 @@ public class AbstractYamlRebindTest extends RebindTestFixture<StartableApplicati
protected Entity createStartWaitAndLogApplication(String... input) throws Exception {
return createStartWaitAndLogApplication(joinLines(input));
}
-
+
protected Entity createStartWaitAndLogApplication(String input) throws Exception {
return createStartWaitAndLogApplication(new StringReader(input));
}
-
+
protected Entity createStartWaitAndLogApplication(Reader input) throws Exception {
Entity app = createAndStartApplication(input);
waitForApplicationTasks(app);
getLogger().info("App started:");
Entities.dumpInfo(app);
-
+
return app;
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b0b83da7/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/HttpCommandEffectorYamlRebindTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/HttpCommandEffectorYamlRebindTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/HttpCommandEffectorYamlRebindTest.java
new file mode 100644
index 0000000..df57bcb
--- /dev/null
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/HttpCommandEffectorYamlRebindTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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.camp.brooklyn;
+
+import static org.apache.brooklyn.test.Asserts.assertFalse;
+import static org.testng.Assert.assertEquals;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.effector.http.HttpCommandEffector;
+import org.apache.brooklyn.core.entity.EntityPredicates;
+import org.apache.brooklyn.core.entity.StartableApplication;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+
+@Test
+public class HttpCommandEffectorYamlRebindTest extends AbstractYamlRebindTest {
+
+ private final static String appId = "my-app-with-http-effector";
+ private final static String appVersion = "1.0.0-SNAPSHOT";
+ static final String appVersionedId = appId + ":" + appVersion;
+
+ static final String catalogYamlSimple = Joiner.on("\n").join(
+ "brooklyn.catalog:",
+ " id: " + appId,
+ " version: " + appVersion,
+ " itemType: entity",
+ " item:",
+ " type: " + TestEntity.class.getName(),
+ " name: targetEntity",
+ " brooklyn.initializers:",
+ " - type: " + HttpCommandEffector.class.getName(),
+ " brooklyn.config:",
+ " name: myEffector",
+ " description: myDescription",
+ " uri: https://httpbin.org/get?id=myId",
+ " httpVerb: GET",
+ " jsonPath: $.args.id",
+ " publishSensor: results");
+
+ @Test
+ public void testRebindWhenHealthy() throws Exception {
+ runRebindWhenIsUp(catalogYamlSimple, appVersionedId);
+ }
+
+ protected void runRebindWhenIsUp(String catalogYaml, String appId) throws Exception {
+ addCatalogItems(catalogYaml);
+
+ String appYaml = Joiner.on("\n").join(
+ "services: ",
+ "- type: " + appId);
+ createStartWaitAndLogApplication(appYaml);
+
+ // Rebind
+ StartableApplication newApp = rebind();
+ TestEntity testEntity = (TestEntity) Iterables.find(newApp.getChildren(), EntityPredicates.displayNameEqualTo("targetEntity"));
+ Effector effector = assertHasInitializers(testEntity, "myEffector");
+
+ // Confirm HttpCommandEffector still functions
+ Object result = testEntity.invoke(effector, ImmutableMap.<String, Object>of()).get();
+ assertEquals(((String)result).trim(), "myId");
+ }
+
+
+ protected static Effector<?> assertHasInitializers(Entity entity, String effectorName) {
+ Maybe<Effector<?>> effectorMaybe = entity.getEntityType().getEffectorByName(effectorName);
+ assertFalse(effectorMaybe.isAbsent());
+ return effectorMaybe.get();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b0b83da7/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/HttpCommandEffectorYamlTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/HttpCommandEffectorYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/HttpCommandEffectorYamlTest.java
new file mode 100644
index 0000000..b36771c
--- /dev/null
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/HttpCommandEffectorYamlTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.camp.brooklyn;
+
+import static org.testng.Assert.assertEquals;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.effector.http.HttpCommandEffector;
+import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+
+public class HttpCommandEffectorYamlTest extends AbstractYamlTest {
+ private static final Logger log = LoggerFactory.getLogger(HttpCommandEffectorYamlTest.class);
+
+ @Test
+ public void testHttpCommandEffectorWithParameters() throws Exception {
+ Entity app = createAndStartApplication(
+ "location: localhost",
+ "services:",
+ "- type: " + EmptySoftwareProcess.class.getName(),
+ " brooklyn.config:",
+ " onbox.base.dir.skipResolution: true",
+ " softwareProcess.serviceProcessIsRunningPollPeriod: forever",
+ " brooklyn.initializers:",
+ " - type: " + HttpCommandEffector.class.getName(),
+ " brooklyn.config:",
+ " name: myEffector",
+ " description: myDescription",
+ " uri: https://httpbin.org/get?id=myId",
+ " httpVerb: GET",
+ " jsonPath: $.args.id",
+ " publishSensor: results"
+ );
+ waitForApplicationTasks(app);
+
+ EmptySoftwareProcess entity = (EmptySoftwareProcess) Iterables.getOnlyElement(app.getChildren());
+ Effector<?> effector = entity.getEntityType().getEffectorByName("myEffector").get();
+
+ // Invoke with parameters
+ {
+ Object result = entity.invoke(effector, ImmutableMap.of("uri", "https://httpbin.org/get?pwd=passwd", "jsonPath", "$.args.pwd")).get();
+ assertEquals(((String)result).trim(), "passwd");
+
+ }
+
+ // Invoke with default parameter
+ {
+ Object result = entity.invoke(effector, ImmutableMap.<String, Object>of()).get();
+ assertEquals(((String)result).trim(), "myId");
+ }
+ }
+
+ @Override
+ protected Logger getLogger() {
+ return log;
+ }
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b0b83da7/core/src/main/java/org/apache/brooklyn/core/effector/CompositeEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/CompositeEffector.java b/core/src/main/java/org/apache/brooklyn/core/effector/CompositeEffector.java
index ca627bb..32f0f1d 100644
--- a/core/src/main/java/org/apache/brooklyn/core/effector/CompositeEffector.java
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/CompositeEffector.java
@@ -93,14 +93,14 @@ public class CompositeEffector extends AddEffector {
final List<String> effectorNames = EntityInitializers.resolve(allConfig, EFFECTORS);
final Boolean override = allConfig.get(OVERRIDE);
- List <Object> results = Lists.newArrayList();
+ List<Object> results = Lists.newArrayList();
if (!override) {
Optional<Effector<?>> effectorOptional = Iterables.tryFind(entity().getEntityType().getEffectors(), new Predicate<Effector<?>>() {
- @Override
- public boolean apply(@Nullable Effector<?> input) {
- return input.getName().equals("original-" + effector.getName());
- }
- });
+ @Override
+ public boolean apply(@Nullable Effector<?> input) {
+ return input.getName().equals("original-" + effector.getName());
+ }
+ });
// if it is a stop effector, it has to be executed as last effector
if (effectorOptional.isPresent()) {
if (effectorOptional.get().getName().endsWith("-stop")) {
@@ -110,7 +110,7 @@ public class CompositeEffector extends AddEffector {
}
}
}
-
+
for (String eff : effectorNames) {
results.add(invokeEffectorNamed(eff, params));
}
@@ -125,7 +125,7 @@ public class CompositeEffector extends AddEffector {
// TODO
}
return entity().invoke(effector.get(), params.getAllConfig()).getUnchecked();
-
+
}
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b0b83da7/core/src/main/java/org/apache/brooklyn/core/effector/http/HttpCommandEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/http/HttpCommandEffector.java b/core/src/main/java/org/apache/brooklyn/core/effector/http/HttpCommandEffector.java
index d2130dd..2d8266e 100644
--- a/core/src/main/java/org/apache/brooklyn/core/effector/http/HttpCommandEffector.java
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/http/HttpCommandEffector.java
@@ -18,9 +18,14 @@
*/
package org.apache.brooklyn.core.effector.http;
+import static com.google.common.base.Preconditions.checkArgument;
+
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.net.MalformedURLException;
import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
import java.util.Map;
import java.util.concurrent.Callable;
@@ -45,8 +50,12 @@ import org.apache.brooklyn.util.http.executor.HttpResponse;
import org.apache.brooklyn.util.http.executor.UsernamePassword;
import org.apache.brooklyn.util.http.executor.apacheclient.HttpExecutorImpl;
+import com.google.common.base.Enums;
+import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.io.ByteStreams;
+import com.google.common.net.HttpHeaders;
import com.jayway.jsonpath.JsonPath;
public final class HttpCommandEffector extends AddEffector {
@@ -60,6 +69,10 @@ public final class HttpCommandEffector extends AddEffector {
public static final ConfigKey<String> JSON_PATH = ConfigKeys.newStringConfigKey("jsonPath", "JSON path to select in HTTP response");
public static final ConfigKey<String> PUBLISH_SENSOR = ConfigKeys.newStringConfigKey("publishSensor", "Sensor name where to store json path extracted value");
+ private enum HttpVerb {
+ GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE;
+ }
+
public HttpCommandEffector(ConfigBag params) {
super(newEffectorBuilder(params).build());
}
@@ -69,7 +82,7 @@ public final class HttpCommandEffector extends AddEffector {
eff.impl(new Body(eff.buildAbstract(), params));
return eff;
}
-
+
protected static class Body extends EffectorBody<String> {
private final Effector<?> effector;
private final ConfigBag params;
@@ -97,32 +110,12 @@ public final class HttpCommandEffector extends AddEffector {
public Object call() throws Exception {
HttpExecutor httpExecutor = HttpExecutorImpl.newInstance();
- String body = "";
- if (payload != null && !payload.isEmpty() && headers.containsKey("Content-Type")) {
- body = Jsonya.newInstance().put(payload).toString();
- }
- HttpRequest.Builder httpRequestBuilder = new HttpRequest.Builder()
- .body(body.getBytes())
- .uri(URI.create(uri))
- .method(httpVerb)
- .config(HttpConfig.builder()
- .trustSelfSigned(true)
- .trustAll(true)
- .laxRedirect(true)
- .build());
-
- if (headers != null) {
- httpRequestBuilder.headers(headers);
- }
-
- if (httpUsername != null && httpPassword != null) {
- httpRequestBuilder.credentials(new UsernamePassword(httpUsername, httpPassword));
- }
-
- HttpRequest httpRequest = httpRequestBuilder.build();
+ String body = getBodyFromPayload(payload, headers);
+ HttpRequest request = buildHttpRequest(httpVerb, uri, headers, httpUsername, httpPassword, body);
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
- HttpResponse response = httpExecutor.execute(httpRequest);
+ HttpResponse response = httpExecutor.execute(request);
+ validateResponse(response);
ByteStreams.copy(response.getContent(), out);
return new String(out.toByteArray());
} catch (IOException e) {
@@ -131,14 +124,64 @@ public final class HttpCommandEffector extends AddEffector {
}
}).build();
- String val = (String) queue(t).getUnchecked();
- if (jsonPath != null) {
- String extractedValue = JsonPath.parse(val).read(jsonPath, String.class);
+ String responseBody = (String) queue(t).getUnchecked();
+
+ if (jsonPath == null) return responseBody;
+ String extractedValue = JsonPath.parse(responseBody).read(jsonPath, String.class);
+ if (publishSensor != null) {
entity().sensors().set(Sensors.newStringSensor(publishSensor), extractedValue);
- return extractedValue;
- } else {
- return val;
}
+ return extractedValue;
+ }
+
+ private void validateResponse(HttpResponse response) {
+ int statusCode = response.code();
+ if (statusCode == 401) {
+ throw new RuntimeException("Authorization exception");
+ } else if (statusCode == 404) {
+ throw new RuntimeException("Resource not found");
+ } else if (statusCode >= 500) {
+ throw new RuntimeException("Server error");
+ }
+ }
+
+ private HttpRequest buildHttpRequest(String httpVerb, String url, Map<String, String> headers, String httpUsername, String httpPassword, String body) throws MalformedURLException, URISyntaxException {
+ // validate url string
+ URI uri = new URL(url).toURI();
+ // validate HTTP verb
+ validateHttpVerb(httpVerb);
+ HttpRequest.Builder httpRequestBuilder = new HttpRequest.Builder()
+ .body(body.getBytes())
+ .uri(uri)
+ .method(httpVerb)
+ .config(HttpConfig.builder()
+ .trustSelfSigned(true)
+ .trustAll(true)
+ .laxRedirect(true)
+ .build());
+
+ if (headers != null) {
+ httpRequestBuilder.headers(headers);
+ }
+
+ if (httpUsername != null && httpPassword != null) {
+ httpRequestBuilder.credentials(new UsernamePassword(httpUsername, httpPassword));
+ }
+
+ return httpRequestBuilder.build();
+ }
+
+ private void validateHttpVerb(String httpVerb) {
+ Optional<HttpVerb> state = Enums.getIfPresent(HttpVerb.class, httpVerb.toUpperCase());
+ checkArgument(state.isPresent(), "Expected one of %s but was %s", Joiner.on(',').join(HttpVerb.values()), httpVerb);
+ }
+
+ private String getBodyFromPayload(Map<String, Object> payload, Map<String, String> headers) {
+ String body = "";
+ if (payload != null && !payload.isEmpty() && headers.containsKey(HttpHeaders.CONTENT_TYPE)) {
+ body = Jsonya.newInstance().put(payload).toString();
+ }
+ return body;
}
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b0b83da7/core/src/test/java/org/apache/brooklyn/core/effector/http/HttpCommandEffectorIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/http/HttpCommandEffectorIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/core/effector/http/HttpCommandEffectorIntegrationTest.java
index 080e08a..7d1a91a 100644
--- a/core/src/test/java/org/apache/brooklyn/core/effector/http/HttpCommandEffectorIntegrationTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/http/HttpCommandEffectorIntegrationTest.java
@@ -40,7 +40,7 @@ import com.jayway.jsonpath.JsonPath;
public class HttpCommandEffectorIntegrationTest {
- final static Effector<String> EFFECTOR_GITHUB_APACHE_ACCOUNT = Effectors.effector(String.class, "GithubApacheAccount").buildAbstract();
+ final static Effector<String> EFFECTOR_HTTPBIN = Effectors.effector(String.class, "Httpbin").buildAbstract();
private TestApplication app;
private EntityLocal entity;
@@ -60,20 +60,20 @@ public class HttpCommandEffectorIntegrationTest {
@Test(groups="Integration")
public void testHttpEffector() throws Exception {
new HttpCommandEffector(ConfigBag.newInstance()
- .configure(HttpCommandEffector.EFFECTOR_NAME, "GithubApacheAccount")
- .configure(HttpCommandEffector.EFFECTOR_URI, "https://api.github.com/users/apache")
+ .configure(HttpCommandEffector.EFFECTOR_NAME, "Httpbin")
+ .configure(HttpCommandEffector.EFFECTOR_URI, "https://httpbin.org/get?login=myLogin")
.configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "GET")
).apply(entity);
- String val = entity.invoke(EFFECTOR_GITHUB_APACHE_ACCOUNT, MutableMap.<String,String>of()).get();
- Assert.assertEquals(JsonPath.parse(val).read("$.login", String.class), "apache");
+ String val = entity.invoke(EFFECTOR_HTTPBIN, MutableMap.<String,String>of()).get();
+ Assert.assertEquals(JsonPath.parse(val).read("$.args.login", String.class), "myLogin");
}
@Test(groups="Integration")
public void testHttpEffectorWithPayload() throws Exception {
new HttpCommandEffector(ConfigBag.newInstance()
- .configure(HttpCommandEffector.EFFECTOR_NAME, "CreateGist")
- .configure(HttpCommandEffector.EFFECTOR_URI, "https://api.github.com/gists")
+ .configure(HttpCommandEffector.EFFECTOR_NAME, "HttpbinPost")
+ .configure(HttpCommandEffector.EFFECTOR_URI, "https://httpbin.org/post")
.configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "POST")
.configure(HttpCommandEffector.EFFECTOR_HTTP_PAYLOAD, ImmutableMap.<String, Object>of(
"description", "Created via API",
@@ -84,42 +84,42 @@ public class HttpCommandEffectorIntegrationTest {
.configure(HttpCommandEffector.PUBLISH_SENSOR, "result")
).apply(entity);
- String url = entity.invoke(Effectors.effector(String.class, "CreateGist").buildAbstract(), MutableMap.<String,String>of()).get();
+ String url = entity.invoke(Effectors.effector(String.class, "HttpbinPost").buildAbstract(), MutableMap.<String,String>of()).get();
Assert.assertNotNull(url, "url");
}
@Test(groups="Integration")
public void testHttpEffectorWithJsonPath() throws Exception {
new HttpCommandEffector(ConfigBag.newInstance()
- .configure(HttpCommandEffector.EFFECTOR_NAME, "GithubApacheAccount")
- .configure(HttpCommandEffector.EFFECTOR_URI, "https://api.github.com/users/apache")
+ .configure(HttpCommandEffector.EFFECTOR_NAME, "Httpbin")
+ .configure(HttpCommandEffector.EFFECTOR_URI, "https://httpbin.org/get?id=myId")
.configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "GET")
- .configure(HttpCommandEffector.JSON_PATH, "$.login")
+ .configure(HttpCommandEffector.JSON_PATH, "$.args.id")
.configure(HttpCommandEffector.PUBLISH_SENSOR, "result")
).apply(entity);
- String val = entity.invoke(EFFECTOR_GITHUB_APACHE_ACCOUNT, MutableMap.<String,String>of()).get();
- Assert.assertEquals(val, "apache");
- Assert.assertEquals(entity.sensors().get(Sensors.newStringSensor("result")), "apache");
+ String val = entity.invoke(EFFECTOR_HTTPBIN, MutableMap.<String,String>of()).get();
+ Assert.assertEquals(val, "myId");
+ Assert.assertEquals(entity.sensors().get(Sensors.newStringSensor("result")), "myId");
}
@Test(groups="Integration")
public void testHttpEffectorWithParameters() throws Exception {
new HttpCommandEffector(ConfigBag.newInstance()
- .configure(HttpCommandEffector.EFFECTOR_NAME, "GithubApacheAccount")
- .configure(HttpCommandEffector.EFFECTOR_URI, "https://api.github.com/users/$user")
+ .configure(HttpCommandEffector.EFFECTOR_NAME, "Httpbin")
+ .configure(HttpCommandEffector.EFFECTOR_URI, "https://httpbin.org/get")
.configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "GET")
.configure(HttpCommandEffector.EFFECTOR_PARAMETER_DEFS,
- MutableMap.<String,Object>of("user", MutableMap.of("defaultValue", "apache"))))
+ MutableMap.<String,Object>of("uri", MutableMap.of("defaultValue", "https://httpbin.org/get"))))
.apply(entity);
String val;
// explicit value
- val = entity.invoke(EFFECTOR_GITHUB_APACHE_ACCOUNT, MutableMap.of("user", "github")).get();
- Assert.assertEquals(JsonPath.parse(val).read("$.login", String.class), "github");
+ val = entity.invoke(EFFECTOR_HTTPBIN, MutableMap.of("uri", "https://httpbin.org/ip")).get();
+ Assert.assertNotNull(JsonPath.parse(val).read("$.origin", String.class));
// default value
- val = entity.invoke(EFFECTOR_GITHUB_APACHE_ACCOUNT, MutableMap.<String,String>of()).get();
- Assert.assertEquals(JsonPath.parse(val).read("$.login", String.class), "apache");
+ val = entity.invoke(EFFECTOR_HTTPBIN, MutableMap.<String,String>of()).get();
+ Assert.assertEquals(JsonPath.parse(val).read("$.url", String.class), "https://httpbin.org/get");
}
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b0b83da7/core/src/test/java/org/apache/brooklyn/core/effector/http/HttpCommandEffectorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/http/HttpCommandEffectorTest.java b/core/src/test/java/org/apache/brooklyn/core/effector/http/HttpCommandEffectorTest.java
new file mode 100644
index 0000000..a4b8ee0
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/http/HttpCommandEffectorTest.java
@@ -0,0 +1,188 @@
+/*
+ * 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.core.effector.http;
+
+import static org.apache.brooklyn.test.Asserts.assertNotNull;
+import static org.testng.Assert.assertEquals;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.concurrent.ExecutionException;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.effector.Effectors;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.core.http.BetterMockWebServer;
+import org.apache.brooklyn.util.exceptions.PropagatedRuntimeException;
+import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.io.Resources;
+import com.google.mockwebserver.MockResponse;
+import com.google.mockwebserver.RecordedRequest;
+
+public class HttpCommandEffectorTest extends BrooklynAppUnitTestSupport {
+
+ private static final Logger log = LoggerFactory.getLogger(HttpCommandEffectorTest.class);
+ private static final String DEFAULT_ENDPOINT = "/";
+
+ final static Effector<String> EFFECTOR_HTTP_COMMAND = Effectors.effector(String.class, "http-command-effector").buildAbstract();
+
+ protected BetterMockWebServer server;
+ protected URL baseUrl;
+
+ protected Location loc;
+ protected HttpCommandEffector httpCommandEffector;
+
+ @BeforeMethod
+ public void start() throws IOException {
+ server = BetterMockWebServer.newInstanceLocalhost();
+ server.play();
+ }
+
+ @AfterMethod(alwaysRun = true)
+ public void stop() throws IOException {
+ server.shutdown();
+ }
+
+ protected String url(String path) {
+ return server.getUrl(path).toString();
+ }
+
+ protected MockResponse jsonResponse(String resource) {
+ return new MockResponse().addHeader("Content-Type", "application/json").setBody(stringFromResource(resource));
+ }
+
+ protected MockResponse response404() {
+ return new MockResponse().setStatus("HTTP/1.1 404 Not Found");
+ }
+
+ protected String stringFromResource(String resourceName) {
+ return stringFromResource("/org/apache/brooklyn/core/effector/http", resourceName);
+ }
+
+ private String stringFromResource(String prefix, String resourceName) {
+ try {
+ return Resources.toString(getClass().getResource(String.format("%s/%s", prefix, resourceName)), Charsets.UTF_8)
+ .replace(DEFAULT_ENDPOINT, url(""));
+ } catch (IOException e) {
+ throw Throwables.propagate(e);
+ }
+ }
+
+ protected RecordedRequest assertSent(BetterMockWebServer server, String method, String path) throws InterruptedException {
+ RecordedRequest request = server.takeRequest();
+ assertEquals(request.getMethod(), method);
+ assertEquals(request.getPath(), path);
+ return request;
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void testMissingURI() {
+ httpCommandEffector = new HttpCommandEffector(ConfigBag.newInstance()
+ .configure(HttpCommandEffector.EFFECTOR_NAME, EFFECTOR_HTTP_COMMAND.getName())
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "GET")
+ );
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void testMissingVerb() {
+ httpCommandEffector = new HttpCommandEffector(ConfigBag.newInstance()
+ .configure(HttpCommandEffector.EFFECTOR_NAME, EFFECTOR_HTTP_COMMAND.getName())
+ .configure(HttpCommandEffector.EFFECTOR_URI, url(""))
+ );
+ }
+
+ @Test(expectedExceptions = ExecutionException.class)
+ public void testInvalidURI() throws ExecutionException, InterruptedException {
+ httpCommandEffector = new HttpCommandEffector(ConfigBag.newInstance()
+ .configure(HttpCommandEffector.EFFECTOR_NAME, EFFECTOR_HTTP_COMMAND.getName())
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "GET")
+ .configure(HttpCommandEffector.EFFECTOR_URI, "invalid-uri")
+ );
+ TestEntity testEntity = app.createAndManageChild(buildEntitySpec(httpCommandEffector));
+ testEntity.invoke(EFFECTOR_HTTP_COMMAND, MutableMap.<String,String>of()).get();
+ }
+
+ @Test(expectedExceptions = ExecutionException.class)
+ public void testInvalidVerb() throws ExecutionException, InterruptedException {
+ httpCommandEffector = new HttpCommandEffector(ConfigBag.newInstance()
+ .configure(HttpCommandEffector.EFFECTOR_NAME, EFFECTOR_HTTP_COMMAND.getName())
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "CHANGE")
+ .configure(HttpCommandEffector.EFFECTOR_URI, url(""))
+ );
+ TestEntity testEntity = app.createAndManageChild(buildEntitySpec(httpCommandEffector));
+ testEntity.invoke(EFFECTOR_HTTP_COMMAND, MutableMap.<String,String>of()).get();
+ }
+
+ @Test
+ public void testHappyPath() throws InterruptedException {
+ server.enqueue(jsonResponse("login.json"));
+
+ httpCommandEffector = new HttpCommandEffector(ConfigBag.newInstance()
+ .configure(HttpCommandEffector.EFFECTOR_NAME, EFFECTOR_HTTP_COMMAND.getName())
+ .configure(HttpCommandEffector.EFFECTOR_URI, url("/get?login=myLogin"))
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "GET")
+ .configure(HttpCommandEffector.JSON_PATH, "$.args.login")
+ );
+ assertNotNull(httpCommandEffector);
+ TestEntity testEntity = app.createAndManageChild(buildEntitySpec(httpCommandEffector));
+ Object output = testEntity.invoke(EFFECTOR_HTTP_COMMAND, ImmutableMap.<String, Object>of()).getUnchecked(Duration.seconds(1));
+ assertEquals(output, "myLogin");
+
+ assertEquals(server.getRequestCount(), 1);
+ assertSent(server, "GET", "/get?login=myLogin");
+ }
+
+ @Test(expectedExceptions = PropagatedRuntimeException.class)
+ public void testWhen404() throws InterruptedException {
+ server.enqueue(response404());
+
+ httpCommandEffector = new HttpCommandEffector(ConfigBag.newInstance()
+ .configure(HttpCommandEffector.EFFECTOR_NAME, EFFECTOR_HTTP_COMMAND.getName())
+ .configure(HttpCommandEffector.EFFECTOR_URI, url("/get?login=myLogin"))
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "GET")
+ .configure(HttpCommandEffector.JSON_PATH, "$.args.login")
+ );
+ assertNotNull(httpCommandEffector);
+ TestEntity testEntity = app.createAndManageChild(buildEntitySpec(httpCommandEffector));
+ Object output = testEntity.invoke(EFFECTOR_HTTP_COMMAND, ImmutableMap.<String, Object>of()).getUnchecked(Duration.seconds(1));
+ assertEquals(output, "myLogin");
+
+ assertEquals(server.getRequestCount(), 1);
+ assertSent(server, "GET", "/get?login=myLogin");
+ }
+
+ private EntitySpec<TestEntity> buildEntitySpec(HttpCommandEffector httpCommandEffector) {
+ return EntitySpec.create(TestEntity.class).addInitializer(httpCommandEffector);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b0b83da7/core/src/test/resources/org/apache/brooklyn/core/effector/http/login.json
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/brooklyn/core/effector/http/login.json b/core/src/test/resources/org/apache/brooklyn/core/effector/http/login.json
new file mode 100644
index 0000000..b39889a
--- /dev/null
+++ b/core/src/test/resources/org/apache/brooklyn/core/effector/http/login.json
@@ -0,0 +1,16 @@
+{
+ "args": {
+ "login": "myLogin"
+ },
+ "headers": {
+ "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
+ "Accept-Encoding": "gzip, deflate, sdch, br",
+ "Accept-Language": "en-US,en;q=0.8,it;q=0.6",
+ "Cookie": "_ga=GA1.2.1060288368.1484053495; _gat=1",
+ "Host": "httpbin.org",
+ "Upgrade-Insecure-Requests": "1",
+ "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36"
+ },
+ "origin": "93.61.99.89",
+ "url": "https://httpbin.org/get?login=myLogin"
+}
[05/10] brooklyn-server git commit: add
CompositeEffectorYamlRebindTest
Posted by he...@apache.org.
add CompositeEffectorYamlRebindTest
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/8809d5cd
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/8809d5cd
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/8809d5cd
Branch: refs/heads/master
Commit: 8809d5cdde60f65636fafdce2917ea37e550f1e1
Parents: b32581d
Author: Andrea Turli <an...@gmail.com>
Authored: Thu Feb 2 17:34:09 2017 +0100
Committer: Andrea Turli <an...@gmail.com>
Committed: Mon Feb 13 15:16:02 2017 +0100
----------------------------------------------------------------------
.../CompositeEffectorYamlRebindTest.java | 102 +++++++++++++++++++
1 file changed, 102 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8809d5cd/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/CompositeEffectorYamlRebindTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/CompositeEffectorYamlRebindTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/CompositeEffectorYamlRebindTest.java
new file mode 100644
index 0000000..09a9075
--- /dev/null
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/CompositeEffectorYamlRebindTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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.camp.brooklyn;
+
+import static org.apache.brooklyn.test.Asserts.assertFalse;
+import static org.testng.Assert.assertEquals;
+
+import java.util.List;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.effector.CompositeEffector;
+import org.apache.brooklyn.core.effector.http.HttpCommandEffector;
+import org.apache.brooklyn.core.entity.EntityPredicates;
+import org.apache.brooklyn.core.entity.StartableApplication;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+
+@Test
+public class CompositeEffectorYamlRebindTest extends AbstractYamlRebindTest {
+
+ private final static String appId = "my-app-with-composite-effector";
+ private final static String appVersion = "1.0.0-SNAPSHOT";
+ static final String appVersionedId = appId + ":" + appVersion;
+
+ static final String catalogYamlSimple = Joiner.on("\n").join(
+ "brooklyn.catalog:",
+ " id: " + appId,
+ " version: " + appVersion,
+ " itemType: entity",
+ " item:",
+ " type: " + TestEntity.class.getName(),
+ " name: targetEntity",
+ " brooklyn.initializers:",
+ " - type: " + HttpCommandEffector.class.getName(),
+ " brooklyn.config:",
+ " name: myEffector",
+ " description: myDescription",
+ " uri: https://httpbin.org/get?id=myId",
+ " httpVerb: GET",
+ " jsonPath: $.args.id",
+ " publishSensor: results",
+ " - type: " + CompositeEffector.class.getName(),
+ " brooklyn.config:",
+ " name: start",
+ " override: true",
+ " effectors:",
+ " - myEffector"
+ );
+
+ @Test
+ public void testRebindWhenHealthy() throws Exception {
+ runRebindWhenIsUp(catalogYamlSimple, appVersionedId);
+ }
+
+ protected void runRebindWhenIsUp(String catalogYaml, String appId) throws Exception {
+ addCatalogItems(catalogYaml);
+
+ String appYaml = Joiner.on("\n").join(
+ "services: ",
+ "- type: " + appId);
+ createStartWaitAndLogApplication(appYaml);
+
+ // Rebind
+ StartableApplication newApp = rebind();
+ TestEntity testEntity = (TestEntity) Iterables.find(newApp.getChildren(), EntityPredicates.displayNameEqualTo("targetEntity"));
+ Effector effector = assertHasInitializers(testEntity, "start");
+
+ // Confirm HttpCommandEffector still functions
+ Object results = testEntity.invoke(effector, ImmutableMap.<String, Object>of()).get();
+ assertEquals(((List<Object>)results).get(0), "myId");
+ }
+
+
+ protected static Effector<?> assertHasInitializers(Entity entity, String effectorName) {
+ Maybe<Effector<?>> effectorMaybe = entity.getEntityType().getEffectorByName(effectorName);
+ assertFalse(effectorMaybe.isAbsent());
+ return effectorMaybe.get();
+ }
+
+}
[02/10] brooklyn-server git commit: remove default value for JSON_PATH
Posted by he...@apache.org.
remove default value for JSON_PATH
- some http calls may not require to parse the output
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/3d318e4e
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/3d318e4e
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/3d318e4e
Branch: refs/heads/master
Commit: 3d318e4e78085519233bcc763e22320ca40403df
Parents: 119ba5a
Author: Andrea Turli <an...@gmail.com>
Authored: Mon Jan 23 17:24:31 2017 +0100
Committer: Andrea Turli <an...@gmail.com>
Committed: Mon Feb 13 15:09:31 2017 +0100
----------------------------------------------------------------------
.../apache/brooklyn/core/effector/http/HttpCommandEffector.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/3d318e4e/core/src/main/java/org/apache/brooklyn/core/effector/http/HttpCommandEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/http/HttpCommandEffector.java b/core/src/main/java/org/apache/brooklyn/core/effector/http/HttpCommandEffector.java
index 7ef2126..d2130dd 100644
--- a/core/src/main/java/org/apache/brooklyn/core/effector/http/HttpCommandEffector.java
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/http/HttpCommandEffector.java
@@ -57,7 +57,7 @@ public final class HttpCommandEffector extends AddEffector {
public static final ConfigKey<String> EFFECTOR_HTTP_PASSWORD = ConfigKeys.newStringConfigKey("httpPassword");
public static final ConfigKey<Map<String, String>> EFFECTOR_HTTP_HEADERS = new MapConfigKey(String.class, "headers");
public static final ConfigKey<Map<String, Object>> EFFECTOR_HTTP_PAYLOAD = new MapConfigKey(String.class, "httpPayload");
- public static final ConfigKey<String> JSON_PATH = ConfigKeys.newStringConfigKey("jsonPath", "JSON path to select in HTTP response; default $", "$");
+ public static final ConfigKey<String> JSON_PATH = ConfigKeys.newStringConfigKey("jsonPath", "JSON path to select in HTTP response");
public static final ConfigKey<String> PUBLISH_SENSOR = ConfigKeys.newStringConfigKey("publishSensor", "Sensor name where to store json path extracted value");
public HttpCommandEffector(ConfigBag params) {
[04/10] brooklyn-server git commit: initial work to support HttpEntity
Posted by he...@apache.org.
initial work to support HttpEntity
- add HttpCommnadEffector
- add CompositeEffector
- add EntityInitializers util class to resolve DSL injected as params
into the HttpCommandEffector
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/eadec9ac
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/eadec9ac
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/eadec9ac
Branch: refs/heads/master
Commit: eadec9ac9ca82ab1b5baea8c69b6ab35b55c452b
Parents: 0f649fe
Author: Andrea Turli <an...@gmail.com>
Authored: Wed Dec 21 12:03:27 2016 +0100
Committer: Andrea Turli <an...@gmail.com>
Committed: Mon Feb 13 15:09:31 2017 +0100
----------------------------------------------------------------------
.../brooklyn/core/effector/AddSensor.java | 2 +
.../core/effector/CompositeEffector.java | 130 +++++++++++++++++
.../brooklyn/core/effector/Effectors.java | 4 +
.../core/effector/http/HttpCommandEffector.java | 145 +++++++++++++++++++
.../core/entity/EntityInitializers.java | 32 +++-
.../core/sensor/http/HttpRequestSensor.java | 47 +++---
.../CompositeEffectorIntegrationTest.java | 78 ++++++++++
.../HttpCommandEffectorIntegrationTest.java | 125 ++++++++++++++++
.../apache/brooklyn/rest/api/EffectorApi.java | 28 ++--
9 files changed, 559 insertions(+), 32 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/eadec9ac/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java b/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java
index ba8d679..92cc4ec 100644
--- a/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java
@@ -57,6 +57,7 @@ public class AddSensor<T> implements EntityInitializer {
protected final Duration period;
protected final String type;
protected AttributeSensor<T> sensor;
+ protected final ConfigBag params;
public AddSensor(Map<String, String> params) {
this(ConfigBag.newInstance(params));
@@ -66,6 +67,7 @@ public class AddSensor<T> implements EntityInitializer {
this.name = Preconditions.checkNotNull(params.get(SENSOR_NAME), "Name must be supplied when defining a sensor");
this.period = params.get(SENSOR_PERIOD);
this.type = params.get(SENSOR_TYPE);
+ this.params = params;
}
@Override
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/eadec9ac/core/src/main/java/org/apache/brooklyn/core/effector/CompositeEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/CompositeEffector.java b/core/src/main/java/org/apache/brooklyn/core/effector/CompositeEffector.java
new file mode 100644
index 0000000..88cd92c
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/CompositeEffector.java
@@ -0,0 +1,130 @@
+/*
+ * 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.core.effector;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.effector.Effectors.EffectorBuilder;
+import org.apache.brooklyn.core.entity.EntityInitializers;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.reflect.TypeToken;
+
+@Beta
+public class CompositeEffector extends AddEffector {
+
+ private static final Logger LOG = LoggerFactory.getLogger(CompositeEffector.class);
+
+ public static final ConfigKey<List<String>> EFFECTORS = ConfigKeys.newConfigKey(new TypeToken<List<String>>() {}, "effectors",
+ "Effector names to be chained together in the composite effector", ImmutableList.<String>of());
+ public static final ConfigKey<Boolean> OVERRIDE = ConfigKeys.newBooleanConfigKey("override",
+ "Wheter additional defined effectors should override pre-existing effector with same name or not (default: false)", Boolean.FALSE);
+ public CompositeEffector(ConfigBag params) {
+ super(newEffectorBuilder(params).build());
+ }
+
+ public CompositeEffector(Map<?, ?> params) {
+ this(ConfigBag.newInstance(params));
+ }
+
+ public static EffectorBuilder<String> newEffectorBuilder(ConfigBag params) {
+ EffectorBuilder<String> eff = AddEffector.newEffectorBuilder(String.class, params);
+ eff.impl(new Body(eff.buildAbstract(), params));
+ return eff;
+ }
+
+ @Override
+ public void apply(EntityLocal entity) {
+ Maybe<Effector<?>> effectorMaybe = entity.getEntityType().getEffectorByName(effector.getName());
+ if (!effectorMaybe.isAbsentOrNull()) {
+ Effector<?> original = Effectors.effector(effectorMaybe.get()).name("original-" + effector.getName()).build();
+ ((EntityInternal)entity).getMutableEntityType().addEffector(original);
+ }
+ super.apply(entity);
+ }
+
+ protected static class Body extends EffectorBody<String> {
+ private final Effector<?> effector;
+ private final ConfigBag params;
+
+ public Body(Effector<?> eff, ConfigBag params) {
+ this.effector = eff;
+ Preconditions.checkNotNull(params.getAllConfigRaw().get(EFFECTORS.getName()), "Effector names must be supplied when defining this effector");
+ this.params = params;
+ }
+
+ @Override
+ public String call(final ConfigBag params) {
+ ConfigBag allConfig = ConfigBag.newInstanceCopying(this.params).putAll(params);
+ final List<String> effectorNames = EntityInitializers.resolve(allConfig, EFFECTORS);
+ final Boolean override = allConfig.get(OVERRIDE);
+
+ List <Object> results = Lists.newArrayList();
+ if (!override) {
+ List<Effector<?>> originalEffectors = FluentIterable.from(entity().getEntityType().getEffectors())
+ .filter(new Predicate<Effector<?>>() {
+ @Override
+ public boolean apply(@Nullable Effector<?> input) {
+ return input.getName().equals("original-" + effector.getName());
+ }
+ })
+ .toList();
+
+ for (Effector<?> originalEffector : originalEffectors) {
+ results.add(invokeEffectorNamed(originalEffector.getName(), params));
+ }
+ }
+ for (String eff : effectorNames) {
+ results.add(invokeEffectorNamed(eff, params));
+ }
+ return Iterables.toString(results);
+ }
+
+ private Object invokeEffectorNamed(String effectorName, ConfigBag params) {
+ LOG.debug("{} invoking effector on {}, effector={}, parameters={}",
+ new Object[]{this, entity(), effectorName, params});
+ Maybe<Effector<?>> effector = entity().getEntityType().getEffectorByName(effectorName);
+ if (effector.isAbsent()) {
+ // TODO
+ }
+ return entity().invoke(effector.get(), params.getAllConfig()).getUnchecked();
+
+ }
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/eadec9ac/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java b/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java
index c644001..53db25a 100644
--- a/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java
@@ -64,6 +64,10 @@ public class Effectors {
this.returnType = returnType;
this.effectorName = effectorName;
}
+ public EffectorBuilder<T> name(String name) {
+ this.effectorName = name;
+ return this;
+ }
public EffectorBuilder<T> description(String description) {
this.description = description;
return this;
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/eadec9ac/core/src/main/java/org/apache/brooklyn/core/effector/http/HttpCommandEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/http/HttpCommandEffector.java b/core/src/main/java/org/apache/brooklyn/core/effector/http/HttpCommandEffector.java
new file mode 100644
index 0000000..7ef2126
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/http/HttpCommandEffector.java
@@ -0,0 +1,145 @@
+/*
+ * 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.core.effector.http;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.config.MapConfigKey;
+import org.apache.brooklyn.core.effector.AddEffector;
+import org.apache.brooklyn.core.effector.EffectorBody;
+import org.apache.brooklyn.core.effector.Effectors.EffectorBuilder;
+import org.apache.brooklyn.core.entity.EntityInitializers;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.util.collections.Jsonya;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.core.task.Tasks;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.http.executor.HttpConfig;
+import org.apache.brooklyn.util.http.executor.HttpExecutor;
+import org.apache.brooklyn.util.http.executor.HttpRequest;
+import org.apache.brooklyn.util.http.executor.HttpResponse;
+import org.apache.brooklyn.util.http.executor.UsernamePassword;
+import org.apache.brooklyn.util.http.executor.apacheclient.HttpExecutorImpl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.io.ByteStreams;
+import com.jayway.jsonpath.JsonPath;
+
+public final class HttpCommandEffector extends AddEffector {
+
+ public static final ConfigKey<String> EFFECTOR_URI = ConfigKeys.newStringConfigKey("uri");
+ public static final ConfigKey<String> EFFECTOR_HTTP_VERB = ConfigKeys.newStringConfigKey("httpVerb");
+ public static final ConfigKey<String> EFFECTOR_HTTP_USERNAME = ConfigKeys.newStringConfigKey("httpUsername");
+ public static final ConfigKey<String> EFFECTOR_HTTP_PASSWORD = ConfigKeys.newStringConfigKey("httpPassword");
+ public static final ConfigKey<Map<String, String>> EFFECTOR_HTTP_HEADERS = new MapConfigKey(String.class, "headers");
+ public static final ConfigKey<Map<String, Object>> EFFECTOR_HTTP_PAYLOAD = new MapConfigKey(String.class, "httpPayload");
+ public static final ConfigKey<String> JSON_PATH = ConfigKeys.newStringConfigKey("jsonPath", "JSON path to select in HTTP response; default $", "$");
+ public static final ConfigKey<String> PUBLISH_SENSOR = ConfigKeys.newStringConfigKey("publishSensor", "Sensor name where to store json path extracted value");
+
+ public HttpCommandEffector(ConfigBag params) {
+ super(newEffectorBuilder(params).build());
+ }
+
+ public static EffectorBuilder<String> newEffectorBuilder(ConfigBag params) {
+ EffectorBuilder<String> eff = AddEffector.newEffectorBuilder(String.class, params);
+ eff.impl(new Body(eff.buildAbstract(), params));
+ return eff;
+ }
+
+ protected static class Body extends EffectorBody<String> {
+ private final Effector<?> effector;
+ private final ConfigBag params;
+
+ public Body(Effector<?> eff, final ConfigBag params) {
+ this.effector = eff;
+ Preconditions.checkNotNull(params.getAllConfigRaw().get(EFFECTOR_URI.getName()), "uri must be supplied when defining this effector");
+ Preconditions.checkNotNull(params.getAllConfigRaw().get(EFFECTOR_HTTP_VERB.getName()), "HTTP verb must be supplied when defining this effector");
+ this.params = params;
+ }
+
+ @Override
+ public String call(final ConfigBag params) {
+ ConfigBag allConfig = ConfigBag.newInstanceCopying(this.params).putAll(params);
+ final String uri = EntityInitializers.resolve(allConfig, EFFECTOR_URI);
+ final String httpVerb = EntityInitializers.resolve(allConfig, EFFECTOR_HTTP_VERB);
+ final String httpUsername = EntityInitializers.resolve(allConfig, EFFECTOR_HTTP_USERNAME);
+ final String httpPassword = EntityInitializers.resolve(allConfig, EFFECTOR_HTTP_PASSWORD);
+ final Map<String, String> headers = EntityInitializers.resolve(allConfig, EFFECTOR_HTTP_HEADERS);
+ final Map<String, Object> payload = EntityInitializers.resolve(allConfig, EFFECTOR_HTTP_PAYLOAD);
+ final String jsonPath = EntityInitializers.resolve(allConfig, JSON_PATH);
+ final String publishSensor = EntityInitializers.resolve(allConfig, PUBLISH_SENSOR);
+ Task t = Tasks.builder().displayName(effector.getName()).body(new Callable<Object>() {
+ @Override
+ public Object call() throws Exception {
+ HttpExecutor httpExecutor = HttpExecutorImpl.newInstance();
+
+ String body = "";
+ if (payload != null && !payload.isEmpty() && headers.containsKey("Content-Type")) {
+ body = Jsonya.newInstance().put(payload).toString();
+ }
+ HttpRequest.Builder httpRequestBuilder = new HttpRequest.Builder()
+ .body(body.getBytes())
+ .uri(URI.create(uri))
+ .method(httpVerb)
+ .config(HttpConfig.builder()
+ .trustSelfSigned(true)
+ .trustAll(true)
+ .laxRedirect(true)
+ .build());
+
+ if (headers != null) {
+ httpRequestBuilder.headers(headers);
+ }
+
+ if (httpUsername != null && httpPassword != null) {
+ httpRequestBuilder.credentials(new UsernamePassword(httpUsername, httpPassword));
+ }
+
+ HttpRequest httpRequest = httpRequestBuilder.build();
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ try {
+ HttpResponse response = httpExecutor.execute(httpRequest);
+ ByteStreams.copy(response.getContent(), out);
+ return new String(out.toByteArray());
+ } catch (IOException e) {
+ throw Exceptions.propagate(e);
+ }
+ }
+ }).build();
+
+ String val = (String) queue(t).getUnchecked();
+ if (jsonPath != null) {
+ String extractedValue = JsonPath.parse(val).read(jsonPath, String.class);
+ entity().sensors().set(Sensors.newStringSensor(publishSensor), extractedValue);
+ return extractedValue;
+ } else {
+ return val;
+ }
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/eadec9ac/core/src/main/java/org/apache/brooklyn/core/entity/EntityInitializers.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntityInitializers.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntityInitializers.java
index a258007..cffcced7 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/EntityInitializers.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntityInitializers.java
@@ -22,6 +22,11 @@ import java.util.List;
import org.apache.brooklyn.api.entity.EntityInitializer;
import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.mgmt.ExecutionContext;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.core.internal.ConfigKeySelfExtracting;
+import org.apache.brooklyn.util.core.task.BasicExecutionContext;
import com.google.common.collect.ImmutableList;
@@ -41,9 +46,32 @@ public class EntityInitializers {
}
}
-
public static EntityInitializer addingTags(Object... tags) {
return new AddTags(tags);
}
-
+
+ /**
+ * Resolves key in the
+ * {@link BasicExecutionContext#getCurrentExecutionContext current execution context}.
+ * @see #resolve(ConfigBag, ConfigKey, ExecutionContext)
+ */
+ public static <T> T resolve(ConfigBag configBag, ConfigKey<T> key) {
+ return resolve(configBag, key, BasicExecutionContext.getCurrentExecutionContext());
+ }
+
+ /**
+ * Gets the value for key from configBag.
+ * <p>
+ * If key is an instance of {@link ConfigKeySelfExtracting} and executionContext is
+ * not null then its value will be retrieved per the key's implementation of
+ * {@link ConfigKeySelfExtracting#extractValue extractValue}. Otherwise, the value
+ * will be retrieved from configBag directly.
+ */
+ public static <T> T resolve(ConfigBag configBag, ConfigKey<T> key, ExecutionContext executionContext) {
+ if (key instanceof ConfigKeySelfExtracting && executionContext != null) {
+ ConfigKeySelfExtracting<T> ckse = ((ConfigKeySelfExtracting<T>) key);
+ return ckse.extractValue(configBag.getAllConfigAsConfigKeyMap(), executionContext);
+ }
+ return configBag.get(key);
+ }
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/eadec9ac/core/src/main/java/org/apache/brooklyn/core/sensor/http/HttpRequestSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/http/HttpRequestSensor.java b/core/src/main/java/org/apache/brooklyn/core/sensor/http/HttpRequestSensor.java
index dea44d3..966a88c 100644
--- a/core/src/main/java/org/apache/brooklyn/core/sensor/http/HttpRequestSensor.java
+++ b/core/src/main/java/org/apache/brooklyn/core/sensor/http/HttpRequestSensor.java
@@ -19,13 +19,14 @@
package org.apache.brooklyn.core.sensor.http;
import java.net.URI;
-
-import net.minidev.json.JSONObject;
+import java.util.Map;
import org.apache.brooklyn.api.entity.EntityLocal;
import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.config.MapConfigKey;
import org.apache.brooklyn.core.effector.AddSensor;
+import org.apache.brooklyn.core.entity.EntityInitializers;
import org.apache.brooklyn.core.sensor.ssh.SshCommandSensor;
import org.apache.brooklyn.feed.http.HttpFeed;
import org.apache.brooklyn.feed.http.HttpPollConfig;
@@ -38,6 +39,8 @@ import com.google.common.annotations.Beta;
import com.google.common.base.Functions;
import com.google.common.base.Supplier;
+import net.minidev.json.JSONObject;
+
/**
* Configurable {@link org.apache.brooklyn.api.entity.EntityInitializer} which adds an HTTP sensor feed to retrieve the
* {@link JSONObject} from a JSON response in order to populate the sensor with the data at the {@code jsonPath}.
@@ -53,24 +56,10 @@ public final class HttpRequestSensor<T> extends AddSensor<T> {
public static final ConfigKey<String> JSON_PATH = ConfigKeys.newStringConfigKey("jsonPath", "JSON path to select in HTTP response; default $", "$");
public static final ConfigKey<String> USERNAME = ConfigKeys.newStringConfigKey("username", "Username for HTTP request, if required");
public static final ConfigKey<String> PASSWORD = ConfigKeys.newStringConfigKey("password", "Password for HTTP request, if required");
-
- protected final Supplier<URI> uri;
- protected final String jsonPath;
- protected final String username;
- protected final String password;
+ public static final ConfigKey<Map<String, String>> HEADERS = new MapConfigKey(String.class, "headers");
public HttpRequestSensor(final ConfigBag params) {
super(params);
-
- uri = new Supplier<URI>() {
- @Override
- public URI get() {
- return URI.create(params.get(SENSOR_URI));
- }
- };
- jsonPath = params.get(JSON_PATH);
- username = params.get(USERNAME);
- password = params.get(PASSWORD);
}
@Override
@@ -81,18 +70,36 @@ public final class HttpRequestSensor<T> extends AddSensor<T> {
LOG.debug("Adding HTTP JSON sensor {} to {}", name, entity);
}
+ final ConfigBag allConfig = ConfigBag.newInstanceCopying(this.params).putAll(params);
+ final Supplier<URI> uri = new Supplier<URI>() {
+ @Override
+ public URI get() {
+ return URI.create(EntityInitializers.resolve(allConfig, SENSOR_URI));
+ }
+ };
+ final String jsonPath = EntityInitializers.resolve(allConfig, JSON_PATH);
+ final String username = EntityInitializers.resolve(allConfig, USERNAME);
+ final String password = EntityInitializers.resolve(allConfig, PASSWORD);
+ final Map<String, String> headers = EntityInitializers.resolve(allConfig, HEADERS);
+
+
HttpPollConfig<T> pollConfig = new HttpPollConfig<T>(sensor)
.checkSuccess(HttpValueFunctions.responseCodeEquals(200))
.onFailureOrException(Functions.constant((T) null))
.onSuccess(HttpValueFunctions.<T>jsonContentsFromPath(jsonPath))
.period(period);
- HttpFeed feed = HttpFeed.builder().entity(entity)
+ HttpFeed.Builder httpRequestBuilder = HttpFeed.builder().entity(entity)
.baseUri(uri)
.credentialsIfNotNull(username, password)
- .poll(pollConfig)
- .build();
+ .poll(pollConfig);
+ if (headers != null) {
+ httpRequestBuilder.headers(headers);
+ }
+
+ HttpFeed feed = httpRequestBuilder.build();
entity.addFeed(feed);
}
+
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/eadec9ac/core/src/test/java/org/apache/brooklyn/core/effector/CompositeEffectorIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/CompositeEffectorIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/core/effector/CompositeEffectorIntegrationTest.java
new file mode 100644
index 0000000..e8cc30e
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/CompositeEffectorIntegrationTest.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.effector;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.effector.http.HttpCommandEffector;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+
+public class CompositeEffectorIntegrationTest {
+
+ final static Effector<String> EFFECTOR_START = Effectors.effector(String.class, "start").buildAbstract();
+
+ private TestApplication app;
+ private EntityLocal entity;
+
+ @BeforeMethod(alwaysRun=true)
+ public void setUp() throws Exception {
+ app = TestApplication.Factory.newManagedInstanceForTests();
+ entity = app.createAndManageChild(EntitySpec.create(TestEntity.class).location(TestApplication.LOCALHOST_MACHINE_SPEC));
+ app.start(ImmutableList.<Location>of());
+ }
+
+ @AfterMethod(alwaysRun=true)
+ public void tearDown() throws Exception {
+ if (app != null) Entities.destroyAll(app.getManagementContext());
+ }
+
+ @Test(groups="Integration")
+ public void testCompositeEffector() throws Exception {
+ new HttpCommandEffector(ConfigBag.newInstance()
+ .configure(HttpCommandEffector.EFFECTOR_NAME, "eff1")
+ .configure(HttpCommandEffector.EFFECTOR_URI, "https://api.github.com/users/apache")
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "GET"))
+ .apply(entity);
+ new HttpCommandEffector(ConfigBag.newInstance()
+ .configure(HttpCommandEffector.EFFECTOR_NAME, "eff2")
+ .configure(HttpCommandEffector.EFFECTOR_URI, "https://api.github.com/users/brooklyncentral")
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "GET"))
+ .apply(entity);
+ new CompositeEffector(ConfigBag.newInstance()
+ .configure(CompositeEffector.EFFECTOR_NAME, "start")
+ .configure(CompositeEffector.EFFECTORS, ImmutableList.of("eff1", "eff2")))
+ .apply(entity);
+
+ String val = entity.invoke(EFFECTOR_START, MutableMap.<String,String>of()).get();
+ // TODO
+ System.out.println(val);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/eadec9ac/core/src/test/java/org/apache/brooklyn/core/effector/http/HttpCommandEffectorIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/http/HttpCommandEffectorIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/core/effector/http/HttpCommandEffectorIntegrationTest.java
new file mode 100644
index 0000000..080e08a
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/http/HttpCommandEffectorIntegrationTest.java
@@ -0,0 +1,125 @@
+/*
+ * 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.core.effector.http;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.effector.Effectors;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+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.collect.ImmutableMap;
+import com.jayway.jsonpath.JsonPath;
+
+public class HttpCommandEffectorIntegrationTest {
+
+ final static Effector<String> EFFECTOR_GITHUB_APACHE_ACCOUNT = Effectors.effector(String.class, "GithubApacheAccount").buildAbstract();
+
+ private TestApplication app;
+ private EntityLocal entity;
+
+ @BeforeMethod(alwaysRun=true)
+ public void setUp() throws Exception {
+ app = TestApplication.Factory.newManagedInstanceForTests();
+ entity = app.createAndManageChild(EntitySpec.create(TestEntity.class).location(TestApplication.LOCALHOST_MACHINE_SPEC));
+ app.start(ImmutableList.<Location>of());
+ }
+
+ @AfterMethod(alwaysRun=true)
+ public void tearDown() throws Exception {
+ if (app != null) Entities.destroyAll(app.getManagementContext());
+ }
+
+ @Test(groups="Integration")
+ public void testHttpEffector() throws Exception {
+ new HttpCommandEffector(ConfigBag.newInstance()
+ .configure(HttpCommandEffector.EFFECTOR_NAME, "GithubApacheAccount")
+ .configure(HttpCommandEffector.EFFECTOR_URI, "https://api.github.com/users/apache")
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "GET")
+ ).apply(entity);
+
+ String val = entity.invoke(EFFECTOR_GITHUB_APACHE_ACCOUNT, MutableMap.<String,String>of()).get();
+ Assert.assertEquals(JsonPath.parse(val).read("$.login", String.class), "apache");
+ }
+
+ @Test(groups="Integration")
+ public void testHttpEffectorWithPayload() throws Exception {
+ new HttpCommandEffector(ConfigBag.newInstance()
+ .configure(HttpCommandEffector.EFFECTOR_NAME, "CreateGist")
+ .configure(HttpCommandEffector.EFFECTOR_URI, "https://api.github.com/gists")
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "POST")
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_PAYLOAD, ImmutableMap.<String, Object>of(
+ "description", "Created via API",
+ "public", "false",
+ "files", ImmutableMap.of("demo.txt", ImmutableMap.of("content","Demo"))))
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_HEADERS, ImmutableMap.of("Content-Type", "application/json"))
+ .configure(HttpCommandEffector.JSON_PATH, "$.url")
+ .configure(HttpCommandEffector.PUBLISH_SENSOR, "result")
+ ).apply(entity);
+
+ String url = entity.invoke(Effectors.effector(String.class, "CreateGist").buildAbstract(), MutableMap.<String,String>of()).get();
+ Assert.assertNotNull(url, "url");
+ }
+
+ @Test(groups="Integration")
+ public void testHttpEffectorWithJsonPath() throws Exception {
+ new HttpCommandEffector(ConfigBag.newInstance()
+ .configure(HttpCommandEffector.EFFECTOR_NAME, "GithubApacheAccount")
+ .configure(HttpCommandEffector.EFFECTOR_URI, "https://api.github.com/users/apache")
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "GET")
+ .configure(HttpCommandEffector.JSON_PATH, "$.login")
+ .configure(HttpCommandEffector.PUBLISH_SENSOR, "result")
+ ).apply(entity);
+
+ String val = entity.invoke(EFFECTOR_GITHUB_APACHE_ACCOUNT, MutableMap.<String,String>of()).get();
+ Assert.assertEquals(val, "apache");
+ Assert.assertEquals(entity.sensors().get(Sensors.newStringSensor("result")), "apache");
+ }
+
+ @Test(groups="Integration")
+ public void testHttpEffectorWithParameters() throws Exception {
+ new HttpCommandEffector(ConfigBag.newInstance()
+ .configure(HttpCommandEffector.EFFECTOR_NAME, "GithubApacheAccount")
+ .configure(HttpCommandEffector.EFFECTOR_URI, "https://api.github.com/users/$user")
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "GET")
+ .configure(HttpCommandEffector.EFFECTOR_PARAMETER_DEFS,
+ MutableMap.<String,Object>of("user", MutableMap.of("defaultValue", "apache"))))
+ .apply(entity);
+
+ String val;
+ // explicit value
+ val = entity.invoke(EFFECTOR_GITHUB_APACHE_ACCOUNT, MutableMap.of("user", "github")).get();
+ Assert.assertEquals(JsonPath.parse(val).read("$.login", String.class), "github");
+
+ // default value
+ val = entity.invoke(EFFECTOR_GITHUB_APACHE_ACCOUNT, MutableMap.<String,String>of()).get();
+ Assert.assertEquals(JsonPath.parse(val).read("$.login", String.class), "apache");
+ }
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/eadec9ac/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/EffectorApi.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/EffectorApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/EffectorApi.java
index 2865223..6143b6f 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/EffectorApi.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/EffectorApi.java
@@ -18,19 +18,27 @@
*/
package org.apache.brooklyn.rest.api;
-import io.swagger.annotations.Api;
-import org.apache.brooklyn.rest.domain.EffectorSummary;
-import io.swagger.annotations.ApiResponse;
-import io.swagger.annotations.ApiResponses;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
+import java.util.List;
+import java.util.Map;
import javax.validation.Valid;
-import javax.ws.rs.*;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
-import java.util.List;
-import java.util.Map;
+
+import org.apache.brooklyn.rest.domain.EffectorSummary;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
@Path("/applications/{application}/entities/{entity}/effectors")
@Api("Entity Effectors")
@@ -54,7 +62,7 @@ public interface EffectorApi {
@POST
@Path("/{effector}")
@ApiOperation(value = "Trigger an effector",
- notes="Returns the return value (status 200) if it completes, or an activity task ID (status 202) if it times out")
+ notes="Returns the return value (status 200) if it completes, or an activity task ID (status 202) if it times out", response = String.class)
@ApiResponses(value = {
@ApiResponse(code = 404, message = "Could not find application, entity or effector")
})
[07/10] brooklyn-server git commit: add CompositeEffector tests and
improve its implementation
Posted by he...@apache.org.
add CompositeEffector tests and improve its implementation
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/b32581dd
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/b32581dd
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/b32581dd
Branch: refs/heads/master
Commit: b32581dd81a390d69ff63779465cd83520c7dcab
Parents: b0b83da
Author: Andrea Turli <an...@gmail.com>
Authored: Thu Feb 2 17:27:41 2017 +0100
Committer: Andrea Turli <an...@gmail.com>
Committed: Mon Feb 13 15:16:02 2017 +0100
----------------------------------------------------------------------
.../brooklyn/CompositeEffectorYamlTest.java | 79 ++++++
.../core/effector/CompositeEffector.java | 68 ++---
.../core/effector/http/HttpCommandEffector.java | 71 +++--
.../CompositeEffectorIntegrationTest.java | 27 +-
.../core/effector/CompositeEffectorTest.java | 262 +++++++++++++++++++
.../effector/http/HttpCommandEffectorTest.java | 88 ++++++-
.../core/effector/http/int-response.json | 16 ++
.../core/effector/http/list-response.json | 19 ++
.../core/effector/http/map-response.json | 16 ++
.../org/apache/brooklyn/core/effector/test.json | 16 ++
10 files changed, 595 insertions(+), 67 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b32581dd/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/CompositeEffectorYamlTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/CompositeEffectorYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/CompositeEffectorYamlTest.java
new file mode 100644
index 0000000..f114f23
--- /dev/null
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/CompositeEffectorYamlTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.camp.brooklyn;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.List;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.effector.CompositeEffector;
+import org.apache.brooklyn.core.effector.http.HttpCommandEffector;
+import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+
+public class CompositeEffectorYamlTest extends AbstractYamlTest {
+ private static final Logger log = LoggerFactory.getLogger(CompositeEffectorYamlTest.class);
+
+ @Test
+ public void testCompositeEffector() throws Exception {
+ Entity app = createAndStartApplication(
+ "location: localhost",
+ "services:",
+ "- type: " + EmptySoftwareProcess.class.getName(),
+ " brooklyn.config:",
+ " onbox.base.dir.skipResolution: true",
+ " softwareProcess.serviceProcessIsRunningPollPeriod: forever",
+ " brooklyn.initializers:",
+ " - type: " + HttpCommandEffector.class.getName(),
+ " brooklyn.config:",
+ " name: myEffector",
+ " description: myDescription",
+ " uri: https://httpbin.org/get?id=myId",
+ " httpVerb: GET",
+ " jsonPath: $.args.id",
+ " publishSensor: results",
+ " - type: " + CompositeEffector.class.getName(),
+ " brooklyn.config:",
+ " name: start",
+ " override: true",
+ " effectors:",
+ " - myEffector"
+ );
+ waitForApplicationTasks(app);
+
+ EmptySoftwareProcess entity = (EmptySoftwareProcess) Iterables.getOnlyElement(app.getChildren());
+ Effector<?> effector = entity.getEntityType().getEffectorByName("start").get();
+
+ // Invoke without parameter
+ Object results = entity.invoke(effector, ImmutableMap.<String, Object>of()).get();
+ assertEquals(((List<Object>)results).get(0), "myId");
+ }
+
+ @Override
+ protected Logger getLogger() {
+ return log;
+ }
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b32581dd/core/src/main/java/org/apache/brooklyn/core/effector/CompositeEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/CompositeEffector.java b/core/src/main/java/org/apache/brooklyn/core/effector/CompositeEffector.java
index 32f0f1d..5345b4a 100644
--- a/core/src/main/java/org/apache/brooklyn/core/effector/CompositeEffector.java
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/CompositeEffector.java
@@ -18,11 +18,12 @@
*/
package org.apache.brooklyn.core.effector;
+import static org.apache.brooklyn.core.entity.trait.Startable.START;
+import static org.apache.brooklyn.core.entity.trait.Startable.STOP;
+
import java.util.List;
import java.util.Map;
-import javax.annotation.Nullable;
-
import org.apache.brooklyn.api.effector.Effector;
import org.apache.brooklyn.api.entity.EntityLocal;
import org.apache.brooklyn.config.ConfigKey;
@@ -36,11 +37,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.annotations.Beta;
-import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
-import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.reflect.TypeToken;
@@ -48,11 +46,14 @@ import com.google.common.reflect.TypeToken;
public class CompositeEffector extends AddEffector {
private static final Logger LOG = LoggerFactory.getLogger(CompositeEffector.class);
+ private static final String ORIGINAL_PREFIX = "original-";
- public static final ConfigKey<List<String>> EFFECTORS = ConfigKeys.newConfigKey(new TypeToken<List<String>>() {}, "effectors",
+ public static final ConfigKey<List<String>> EFFECTORS = ConfigKeys.newConfigKey(new TypeToken<List<String>>() {
+ }, "effectors",
"Effector names to be chained together in the composite effector", ImmutableList.<String>of());
public static final ConfigKey<Boolean> OVERRIDE = ConfigKeys.newBooleanConfigKey("override",
"Wheter additional defined effectors should override pre-existing effector with same name or not (default: false)", Boolean.FALSE);
+
public CompositeEffector(ConfigBag params) {
super(newEffectorBuilder(params).build());
}
@@ -61,8 +62,8 @@ public class CompositeEffector extends AddEffector {
this(ConfigBag.newInstance(params));
}
- public static EffectorBuilder<String> newEffectorBuilder(ConfigBag params) {
- EffectorBuilder<String> eff = AddEffector.newEffectorBuilder(String.class, params);
+ public static EffectorBuilder<List> newEffectorBuilder(ConfigBag params) {
+ EffectorBuilder<List> eff = AddEffector.newEffectorBuilder(List.class, params);
eff.impl(new Body(eff.buildAbstract(), params));
return eff;
}
@@ -71,13 +72,13 @@ public class CompositeEffector extends AddEffector {
public void apply(EntityLocal entity) {
Maybe<Effector<?>> effectorMaybe = entity.getEntityType().getEffectorByName(effector.getName());
if (!effectorMaybe.isAbsentOrNull()) {
- Effector<?> original = Effectors.effector(effectorMaybe.get()).name("original-" + effector.getName()).build();
- ((EntityInternal)entity).getMutableEntityType().addEffector(original);
+ Effector<?> original = Effectors.effector(effectorMaybe.get()).name(ORIGINAL_PREFIX + effector.getName()).build();
+ ((EntityInternal) entity).getMutableEntityType().addEffector(original);
}
super.apply(entity);
}
- protected static class Body extends EffectorBody<String> {
+ protected static class Body extends EffectorBody<List> {
private final Effector<?> effector;
private final ConfigBag params;
@@ -88,46 +89,47 @@ public class CompositeEffector extends AddEffector {
}
@Override
- public String call(final ConfigBag params) {
+ public List<Object> call(final ConfigBag params) {
ConfigBag allConfig = ConfigBag.newInstanceCopying(this.params).putAll(params);
final List<String> effectorNames = EntityInitializers.resolve(allConfig, EFFECTORS);
final Boolean override = allConfig.get(OVERRIDE);
List<Object> results = Lists.newArrayList();
- if (!override) {
- Optional<Effector<?>> effectorOptional = Iterables.tryFind(entity().getEntityType().getEffectors(), new Predicate<Effector<?>>() {
- @Override
- public boolean apply(@Nullable Effector<?> input) {
- return input.getName().equals("original-" + effector.getName());
- }
- });
- // if it is a stop effector, it has to be executed as last effector
- if (effectorOptional.isPresent()) {
- if (effectorOptional.get().getName().endsWith("-stop")) {
- effectorNames.add(effectorOptional.get().getName());
- } else {
- effectorNames.add(0, effectorOptional.get().getName());
- }
- }
- }
+ if (!override && isStartRedefined()) {
+ results.add(invokeEffectorNamed(ORIGINAL_PREFIX + START.getName(), params));
+ }
for (String eff : effectorNames) {
results.add(invokeEffectorNamed(eff, params));
}
- return Iterables.toString(results);
+ if (!override && isStopRedefined()) {
+ results.add(invokeEffectorNamed(ORIGINAL_PREFIX + STOP.getName(), params));
+ }
+ return results;
+ }
+
+ private boolean isStartRedefined() {
+ return isEffectorRedefined(ORIGINAL_PREFIX + START.getName());
+ }
+
+ private boolean isStopRedefined() {
+ return isEffectorRedefined(ORIGINAL_PREFIX + STOP.getName());
+ }
+
+ private boolean isEffectorRedefined(String effectorName) {
+ return entity().getEntityType().getEffectorByName(effectorName).isPresent();
}
private Object invokeEffectorNamed(String effectorName, ConfigBag params) {
- LOG.debug("{} invoking effector on {}, effector={}, parameters={}",
+ LOG.info("{} invoking effector on {}, effector={}, parameters={}",
new Object[]{this, entity(), effectorName, params});
Maybe<Effector<?>> effector = entity().getEntityType().getEffectorByName(effectorName);
if (effector.isAbsent()) {
- // TODO
+ throw new IllegalStateException("Cannot find effector " + effectorName);
}
return entity().invoke(effector.get(), params.getAllConfig()).getUnchecked();
-
}
- }
+ }
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b32581dd/core/src/main/java/org/apache/brooklyn/core/effector/http/HttpCommandEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/http/HttpCommandEffector.java b/core/src/main/java/org/apache/brooklyn/core/effector/http/HttpCommandEffector.java
index 2d8266e..1388a926 100644
--- a/core/src/main/java/org/apache/brooklyn/core/effector/http/HttpCommandEffector.java
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/http/HttpCommandEffector.java
@@ -19,6 +19,7 @@
package org.apache.brooklyn.core.effector.http;
import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -49,28 +50,33 @@ import org.apache.brooklyn.util.http.executor.HttpRequest;
import org.apache.brooklyn.util.http.executor.HttpResponse;
import org.apache.brooklyn.util.http.executor.UsernamePassword;
import org.apache.brooklyn.util.http.executor.apacheclient.HttpExecutorImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.google.common.base.Enums;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
import com.google.common.io.ByteStreams;
import com.google.common.net.HttpHeaders;
import com.jayway.jsonpath.JsonPath;
public final class HttpCommandEffector extends AddEffector {
+ private static final Logger LOG = LoggerFactory.getLogger(HttpCommandEffector.class);
+
public static final ConfigKey<String> EFFECTOR_URI = ConfigKeys.newStringConfigKey("uri");
public static final ConfigKey<String> EFFECTOR_HTTP_VERB = ConfigKeys.newStringConfigKey("httpVerb");
public static final ConfigKey<String> EFFECTOR_HTTP_USERNAME = ConfigKeys.newStringConfigKey("httpUsername");
public static final ConfigKey<String> EFFECTOR_HTTP_PASSWORD = ConfigKeys.newStringConfigKey("httpPassword");
public static final ConfigKey<Map<String, String>> EFFECTOR_HTTP_HEADERS = new MapConfigKey(String.class, "headers");
- public static final ConfigKey<Map<String, Object>> EFFECTOR_HTTP_PAYLOAD = new MapConfigKey(String.class, "httpPayload");
+ public static final ConfigKey<Object> EFFECTOR_HTTP_PAYLOAD = ConfigKeys.newConfigKey(Object.class, "httpPayload");
public static final ConfigKey<String> JSON_PATH = ConfigKeys.newStringConfigKey("jsonPath", "JSON path to select in HTTP response");
public static final ConfigKey<String> PUBLISH_SENSOR = ConfigKeys.newStringConfigKey("publishSensor", "Sensor name where to store json path extracted value");
+ public static final String APPLICATION_JSON = "application/json";
+
private enum HttpVerb {
- GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE;
+ GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
}
public HttpCommandEffector(ConfigBag params) {
@@ -89,29 +95,28 @@ public final class HttpCommandEffector extends AddEffector {
public Body(Effector<?> eff, final ConfigBag params) {
this.effector = eff;
- Preconditions.checkNotNull(params.getAllConfigRaw().get(EFFECTOR_URI.getName()), "uri must be supplied when defining this effector");
- Preconditions.checkNotNull(params.getAllConfigRaw().get(EFFECTOR_HTTP_VERB.getName()), "HTTP verb must be supplied when defining this effector");
+ checkNotNull(params.getAllConfigRaw().get(EFFECTOR_URI.getName()), "uri must be supplied when defining this effector");
+ checkNotNull(params.getAllConfigRaw().get(EFFECTOR_HTTP_VERB.getName()), "HTTP verb must be supplied when defining this effector");
this.params = params;
}
@Override
public String call(final ConfigBag params) {
ConfigBag allConfig = ConfigBag.newInstanceCopying(this.params).putAll(params);
- final String uri = EntityInitializers.resolve(allConfig, EFFECTOR_URI);
- final String httpVerb = EntityInitializers.resolve(allConfig, EFFECTOR_HTTP_VERB);
+ final URI uri = convertToURI(EntityInitializers.resolve(allConfig, EFFECTOR_URI));
+ final String httpVerb = isValidHttpVerb(EntityInitializers.resolve(allConfig, EFFECTOR_HTTP_VERB));
final String httpUsername = EntityInitializers.resolve(allConfig, EFFECTOR_HTTP_USERNAME);
final String httpPassword = EntityInitializers.resolve(allConfig, EFFECTOR_HTTP_PASSWORD);
final Map<String, String> headers = EntityInitializers.resolve(allConfig, EFFECTOR_HTTP_HEADERS);
- final Map<String, Object> payload = EntityInitializers.resolve(allConfig, EFFECTOR_HTTP_PAYLOAD);
+ final Object payload = EntityInitializers.resolve(allConfig, EFFECTOR_HTTP_PAYLOAD);
final String jsonPath = EntityInitializers.resolve(allConfig, JSON_PATH);
final String publishSensor = EntityInitializers.resolve(allConfig, PUBLISH_SENSOR);
+ final HttpExecutor httpExecutor = HttpExecutorImpl.newInstance();
+
+ final HttpRequest request = buildHttpRequest(httpVerb, uri, headers, httpUsername, httpPassword, payload);
Task t = Tasks.builder().displayName(effector.getName()).body(new Callable<Object>() {
@Override
public Object call() throws Exception {
- HttpExecutor httpExecutor = HttpExecutorImpl.newInstance();
-
- String body = getBodyFromPayload(payload, headers);
- HttpRequest request = buildHttpRequest(httpVerb, uri, headers, httpUsername, httpPassword, body);
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
HttpResponse response = httpExecutor.execute(request);
@@ -127,6 +132,7 @@ public final class HttpCommandEffector extends AddEffector {
String responseBody = (String) queue(t).getUnchecked();
if (jsonPath == null) return responseBody;
+
String extractedValue = JsonPath.parse(responseBody).read(jsonPath, String.class);
if (publishSensor != null) {
entity().sensors().set(Sensors.newStringSensor(publishSensor), extractedValue);
@@ -134,6 +140,16 @@ public final class HttpCommandEffector extends AddEffector {
return extractedValue;
}
+ private URI convertToURI(String url) {
+ try {
+ return new URL(url).toURI();
+ } catch (MalformedURLException e) {
+ throw Exceptions.propagate(e);
+ } catch (URISyntaxException e) {
+ throw Exceptions.propagate(e);
+ }
+ }
+
private void validateResponse(HttpResponse response) {
int statusCode = response.code();
if (statusCode == 401) {
@@ -145,13 +161,8 @@ public final class HttpCommandEffector extends AddEffector {
}
}
- private HttpRequest buildHttpRequest(String httpVerb, String url, Map<String, String> headers, String httpUsername, String httpPassword, String body) throws MalformedURLException, URISyntaxException {
- // validate url string
- URI uri = new URL(url).toURI();
- // validate HTTP verb
- validateHttpVerb(httpVerb);
+ private HttpRequest buildHttpRequest(String httpVerb, URI uri, Map<String, String> headers, String httpUsername, String httpPassword, Object payload) {
HttpRequest.Builder httpRequestBuilder = new HttpRequest.Builder()
- .body(body.getBytes())
.uri(uri)
.method(httpVerb)
.config(HttpConfig.builder()
@@ -164,6 +175,19 @@ public final class HttpCommandEffector extends AddEffector {
httpRequestBuilder.headers(headers);
}
+ if (payload != null) {
+ String body = "";
+ String contentType = headers.get(HttpHeaders.CONTENT_TYPE);
+ if (contentType == null || contentType.equalsIgnoreCase(APPLICATION_JSON)) {
+ LOG.warn("Content-Type not specified. Using {}, as default (continuing)", APPLICATION_JSON);
+ body = toJsonString(payload);
+ } else if (!(payload instanceof String) && !contentType.equalsIgnoreCase(APPLICATION_JSON)) {
+ LOG.warn("the http request may fail with payload {} and 'Content-Type= {}, (continuing)", payload, contentType);
+ body = payload.toString();
+ }
+ httpRequestBuilder.body(body.getBytes());
+ }
+
if (httpUsername != null && httpPassword != null) {
httpRequestBuilder.credentials(new UsernamePassword(httpUsername, httpPassword));
}
@@ -171,17 +195,14 @@ public final class HttpCommandEffector extends AddEffector {
return httpRequestBuilder.build();
}
- private void validateHttpVerb(String httpVerb) {
+ private String isValidHttpVerb(String httpVerb) {
Optional<HttpVerb> state = Enums.getIfPresent(HttpVerb.class, httpVerb.toUpperCase());
checkArgument(state.isPresent(), "Expected one of %s but was %s", Joiner.on(',').join(HttpVerb.values()), httpVerb);
+ return httpVerb;
}
- private String getBodyFromPayload(Map<String, Object> payload, Map<String, String> headers) {
- String body = "";
- if (payload != null && !payload.isEmpty() && headers.containsKey(HttpHeaders.CONTENT_TYPE)) {
- body = Jsonya.newInstance().put(payload).toString();
- }
- return body;
+ private String toJsonString(Object payload) {
+ return Jsonya.newInstance().add(payload).toString();
}
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b32581dd/core/src/test/java/org/apache/brooklyn/core/effector/CompositeEffectorIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/CompositeEffectorIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/core/effector/CompositeEffectorIntegrationTest.java
index e8cc30e..dd168ed 100644
--- a/core/src/test/java/org/apache/brooklyn/core/effector/CompositeEffectorIntegrationTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/CompositeEffectorIntegrationTest.java
@@ -18,6 +18,12 @@
*/
package org.apache.brooklyn.core.effector;
+import static org.apache.brooklyn.test.Asserts.assertEquals;
+import static org.apache.brooklyn.test.Asserts.assertNull;
+import static org.apache.brooklyn.test.Asserts.assertTrue;
+
+import java.util.List;
+
import org.apache.brooklyn.api.effector.Effector;
import org.apache.brooklyn.api.entity.EntityLocal;
import org.apache.brooklyn.api.entity.EntitySpec;
@@ -36,11 +42,11 @@ import com.google.common.collect.ImmutableList;
public class CompositeEffectorIntegrationTest {
- final static Effector<String> EFFECTOR_START = Effectors.effector(String.class, "start").buildAbstract();
+ final static Effector<List> EFFECTOR_START = Effectors.effector(List.class, "start").buildAbstract();
private TestApplication app;
private EntityLocal entity;
-
+
@BeforeMethod(alwaysRun=true)
public void setUp() throws Exception {
app = TestApplication.Factory.newManagedInstanceForTests();
@@ -58,21 +64,28 @@ public class CompositeEffectorIntegrationTest {
new HttpCommandEffector(ConfigBag.newInstance()
.configure(HttpCommandEffector.EFFECTOR_NAME, "eff1")
.configure(HttpCommandEffector.EFFECTOR_URI, "https://api.github.com/users/apache")
- .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "GET"))
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "GET")
+ .configure(HttpCommandEffector.JSON_PATH, "$.login"))
.apply(entity);
new HttpCommandEffector(ConfigBag.newInstance()
.configure(HttpCommandEffector.EFFECTOR_NAME, "eff2")
.configure(HttpCommandEffector.EFFECTOR_URI, "https://api.github.com/users/brooklyncentral")
- .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "GET"))
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "GET")
+ .configure(HttpCommandEffector.JSON_PATH, "$.login"))
.apply(entity);
new CompositeEffector(ConfigBag.newInstance()
.configure(CompositeEffector.EFFECTOR_NAME, "start")
.configure(CompositeEffector.EFFECTORS, ImmutableList.of("eff1", "eff2")))
.apply(entity);
- String val = entity.invoke(EFFECTOR_START, MutableMap.<String,String>of()).get();
- // TODO
- System.out.println(val);
+ List<Object> results = entity.invoke(EFFECTOR_START, MutableMap.<String,String>of()).get();
+
+ assertEquals(results.size(), 3);
+ assertNull(results.get(0));
+ assertTrue(results.get(1) instanceof String);
+ assertEquals(results.get(1), "apache");
+ assertTrue(results.get(2) instanceof String);
+ assertEquals(results.get(2), "brooklyncentral");
}
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b32581dd/core/src/test/java/org/apache/brooklyn/core/effector/CompositeEffectorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/CompositeEffectorTest.java b/core/src/test/java/org/apache/brooklyn/core/effector/CompositeEffectorTest.java
new file mode 100644
index 0000000..3bf0018
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/CompositeEffectorTest.java
@@ -0,0 +1,262 @@
+/*
+ * 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.core.effector;
+
+import static org.apache.brooklyn.core.effector.http.HttpCommandEffectorTest.EFFECTOR_HTTP_COMMAND;
+import static org.apache.brooklyn.test.Asserts.assertNotNull;
+import static org.apache.brooklyn.test.Asserts.assertNull;
+import static org.apache.brooklyn.test.Asserts.assertTrue;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.List;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.effector.http.HttpCommandEffector;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.core.http.BetterMockWebServer;
+import org.apache.brooklyn.util.exceptions.PropagatedRuntimeException;
+import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.io.Resources;
+import com.google.mockwebserver.MockResponse;
+
+public class CompositeEffectorTest extends BrooklynAppUnitTestSupport {
+
+ private static final Logger log = LoggerFactory.getLogger(CompositeEffectorTest.class);
+ private static final String DEFAULT_ENDPOINT = "/";
+
+ final static Effector<List> EFFECTOR_COMPOSITE = Effectors.effector(List.class, "CompositeEffector").buildAbstract();
+
+ protected BetterMockWebServer server;
+ protected URL baseUrl;
+
+ protected Location loc;
+ protected CompositeEffector compositeEffector;
+
+ @BeforeMethod
+ public void start() throws IOException {
+ server = BetterMockWebServer.newInstanceLocalhost();
+ server.play();
+ }
+
+ @AfterMethod(alwaysRun = true)
+ public void stop() throws IOException {
+ server.shutdown();
+ }
+
+ protected String url(String path) {
+ return server.getUrl(path).toString();
+ }
+
+ protected MockResponse jsonResponse(String resource) {
+ return new MockResponse().addHeader("Content-Type", "application/json").setBody(stringFromResource(resource));
+ }
+
+ protected MockResponse response404() {
+ return new MockResponse().setStatus("HTTP/1.1 404 Not Found");
+ }
+
+ protected MockResponse response204() {
+ return new MockResponse().setStatus("HTTP/1.1 204 No Content");
+ }
+
+ protected String stringFromResource(String resourceName) {
+ return stringFromResource("/org/apache/brooklyn/core/effector", resourceName);
+ }
+
+ private String stringFromResource(String prefix, String resourceName) {
+ try {
+ return Resources.toString(getClass().getResource(String.format("%s/%s", prefix, resourceName)), Charsets.UTF_8)
+ .replace(DEFAULT_ENDPOINT, url(""));
+ } catch (IOException e) {
+ throw Throwables.propagate(e);
+ }
+ }
+
+ @Test
+ public void testCompositeEffectorWithNonExistingName() throws InterruptedException {
+ server.enqueue(jsonResponse("test.json"));
+
+ HttpCommandEffector httpCommandEffector = new HttpCommandEffector(ConfigBag.newInstance()
+ .configure(HttpCommandEffector.EFFECTOR_NAME, EFFECTOR_HTTP_COMMAND.getName())
+ .configure(HttpCommandEffector.EFFECTOR_URI, url("/get?login=myLogin"))
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "GET")
+ .configure(HttpCommandEffector.JSON_PATH, "$.args.login")
+ );
+ assertNotNull(httpCommandEffector);
+ compositeEffector = new CompositeEffector(ConfigBag.newInstance()
+ .configure(CompositeEffector.EFFECTOR_NAME, EFFECTOR_COMPOSITE.getName())
+ .configure(CompositeEffector.EFFECTORS, ImmutableList.of(EFFECTOR_HTTP_COMMAND.getName()))
+ );
+ assertNotNull(compositeEffector);
+ TestEntity testEntity = app.createAndManageChild(buildEntitySpec(httpCommandEffector, compositeEffector));
+ List<Object> results = testEntity.invoke(EFFECTOR_COMPOSITE, ImmutableMap.<String, Object>of()).getUnchecked(Duration.seconds(1));
+ Asserts.assertEquals(results.size(), 1);
+
+ assertTrue(results.get(0) instanceof String);
+ Asserts.assertEquals(results.get(0), "myLogin");
+ }
+
+ @Test
+ public void testCompositeEffectorWithStartName() throws InterruptedException {
+ server.enqueue(jsonResponse("test.json"));
+
+ HttpCommandEffector httpCommandEffector = new HttpCommandEffector(ConfigBag.newInstance()
+ .configure(HttpCommandEffector.EFFECTOR_NAME, EFFECTOR_HTTP_COMMAND.getName())
+ .configure(HttpCommandEffector.EFFECTOR_URI, url("/get?login=myLogin"))
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "GET")
+ .configure(HttpCommandEffector.JSON_PATH, "$.args.login")
+ );
+ assertNotNull(httpCommandEffector);
+ compositeEffector = new CompositeEffector(ConfigBag.newInstance()
+ .configure(CompositeEffector.EFFECTOR_NAME, "start")
+ .configure(CompositeEffector.EFFECTORS, ImmutableList.of(EFFECTOR_HTTP_COMMAND.getName()))
+ );
+ assertNotNull(compositeEffector);
+ TestEntity testEntity = app.createAndManageChild(buildEntitySpec(httpCommandEffector, compositeEffector));
+ List<Object> results = testEntity.invoke(Effectors.effector(List.class, "start").buildAbstract(), ImmutableMap.<String, Object>of()).getUnchecked(Duration.seconds(1));
+ Asserts.assertEquals(results.size(), 2);
+ assertNull(results.get(0));
+ assertTrue(results.get(1) instanceof String);
+ Asserts.assertEquals(results.get(1), "myLogin");
+ }
+
+ @Test
+ public void testCompositeEffectorWithStartNameAndOverriding() throws InterruptedException {
+ server.enqueue(jsonResponse("test.json"));
+
+ HttpCommandEffector httpCommandEffector = new HttpCommandEffector(ConfigBag.newInstance()
+ .configure(HttpCommandEffector.EFFECTOR_NAME, EFFECTOR_HTTP_COMMAND.getName())
+ .configure(HttpCommandEffector.EFFECTOR_URI, url("/get?login=myLogin"))
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "GET")
+ .configure(HttpCommandEffector.JSON_PATH, "$.args.login")
+ );
+ assertNotNull(httpCommandEffector);
+ compositeEffector = new CompositeEffector(ConfigBag.newInstance()
+ .configure(CompositeEffector.EFFECTOR_NAME, "start")
+ .configure(CompositeEffector.OVERRIDE, true)
+ .configure(CompositeEffector.EFFECTORS, ImmutableList.of(EFFECTOR_HTTP_COMMAND.getName()))
+ );
+ assertNotNull(compositeEffector);
+ TestEntity testEntity = app.createAndManageChild(buildEntitySpec(httpCommandEffector, compositeEffector));
+ List<Object> results = testEntity.invoke(Effectors.effector(List.class, "start").buildAbstract(), ImmutableMap.<String, Object>of()).getUnchecked(Duration.seconds(1));
+ Asserts.assertEquals(results.size(), 1);
+ assertTrue(results.get(0) instanceof String);
+ Asserts.assertEquals(results.get(0), "myLogin");
+ }
+
+ @Test
+ public void testCompositeEffectorWithStopName() throws InterruptedException {
+ server.enqueue(jsonResponse("test.json"));
+
+ HttpCommandEffector httpCommandEffector = new HttpCommandEffector(ConfigBag.newInstance()
+ .configure(HttpCommandEffector.EFFECTOR_NAME, EFFECTOR_HTTP_COMMAND.getName())
+ .configure(HttpCommandEffector.EFFECTOR_URI, url("/get?login=myLogin"))
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "GET")
+ .configure(HttpCommandEffector.JSON_PATH, "$.args.login")
+ );
+ assertNotNull(httpCommandEffector);
+ compositeEffector = new CompositeEffector(ConfigBag.newInstance()
+ .configure(CompositeEffector.EFFECTOR_NAME, "stop")
+ .configure(CompositeEffector.EFFECTORS, ImmutableList.of(EFFECTOR_HTTP_COMMAND.getName()))
+ );
+ assertNotNull(compositeEffector);
+ TestEntity testEntity = app.createAndManageChild(buildEntitySpec(httpCommandEffector, compositeEffector));
+ List<Object> results = testEntity.invoke(Effectors.effector(List.class, "stop").buildAbstract(), ImmutableMap.<String, Object>of()).getUnchecked(Duration.minutes(1));
+ Asserts.assertEquals(results.size(), 2);
+ assertTrue(results.get(0) instanceof String);
+ Asserts.assertEquals(results.get(0), "myLogin");
+ assertNull(results.get(1));
+ }
+
+ @Test
+ public void testCompositeEffectorWithStopNameAndOverriding() throws InterruptedException {
+ server.enqueue(jsonResponse("test.json"));
+
+ HttpCommandEffector httpCommandEffector = new HttpCommandEffector(ConfigBag.newInstance()
+ .configure(HttpCommandEffector.EFFECTOR_NAME, EFFECTOR_HTTP_COMMAND.getName())
+ .configure(HttpCommandEffector.EFFECTOR_URI, url("/get?login=myLogin"))
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "GET")
+ .configure(HttpCommandEffector.JSON_PATH, "$.args.login")
+ );
+ assertNotNull(httpCommandEffector);
+ compositeEffector = new CompositeEffector(ConfigBag.newInstance()
+ .configure(CompositeEffector.EFFECTOR_NAME, "stop")
+ .configure(CompositeEffector.OVERRIDE, true)
+ .configure(CompositeEffector.EFFECTORS, ImmutableList.of(EFFECTOR_HTTP_COMMAND.getName()))
+ );
+ assertNotNull(compositeEffector);
+ TestEntity testEntity = app.createAndManageChild(buildEntitySpec(httpCommandEffector, compositeEffector));
+ List<Object> results = testEntity.invoke(Effectors.effector(List.class, "stop").buildAbstract(), ImmutableMap.<String, Object>of()).getUnchecked(Duration.minutes(1));
+ Asserts.assertEquals(results.size(), 1);
+ assertTrue(results.get(0) instanceof String);
+ Asserts.assertEquals(results.get(0), "myLogin");
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void testMissingEffectors() {
+ compositeEffector = new CompositeEffector(ConfigBag.newInstance()
+ .configure(CompositeEffector.EFFECTOR_NAME, EFFECTOR_COMPOSITE.getName())
+ .configure(CompositeEffector.EFFECTORS, null)
+ );
+ }
+
+ @Test(expectedExceptions = PropagatedRuntimeException.class)
+ public void testWhenOneEffectorFails() throws InterruptedException {
+ server.enqueue(response404());
+
+ HttpCommandEffector eff1 = new HttpCommandEffector(ConfigBag.newInstance()
+ .configure(HttpCommandEffector.EFFECTOR_NAME, "eff1")
+ .configure(HttpCommandEffector.EFFECTOR_URI, url("/get?login=myLogin"))
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "GET")
+ .configure(HttpCommandEffector.JSON_PATH, "$.args.login"));
+ compositeEffector = new CompositeEffector(ConfigBag.newInstance()
+ .configure(CompositeEffector.EFFECTOR_NAME, EFFECTOR_COMPOSITE.getName())
+ .configure(CompositeEffector.EFFECTORS, ImmutableList.of("eff1", "eff2"))
+ );
+ assertNotNull(compositeEffector);
+ TestEntity testEntity = app.createAndManageChild(buildEntitySpec(eff1, compositeEffector));
+ List<Object> results = testEntity.invoke(EFFECTOR_COMPOSITE, ImmutableMap.<String, Object>of()).getUnchecked(Duration.seconds(1));
+ Asserts.assertEquals(results.size(), 2);
+ }
+
+ private EntitySpec<TestEntity> buildEntitySpec(AddEffector... effectors) {
+ EntitySpec<TestEntity> testEntitySpec = EntitySpec.create(TestEntity.class);
+ for (AddEffector effector : effectors) {
+ testEntitySpec.addInitializer(effector);
+ }
+ return testEntitySpec;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b32581dd/core/src/test/java/org/apache/brooklyn/core/effector/http/HttpCommandEffectorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/http/HttpCommandEffectorTest.java b/core/src/test/java/org/apache/brooklyn/core/effector/http/HttpCommandEffectorTest.java
index a4b8ee0..0580c39 100644
--- a/core/src/test/java/org/apache/brooklyn/core/effector/http/HttpCommandEffectorTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/http/HttpCommandEffectorTest.java
@@ -44,8 +44,10 @@ import org.testng.annotations.Test;
import com.google.common.base.Charsets;
import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.Resources;
+import com.google.common.net.HttpHeaders;
import com.google.mockwebserver.MockResponse;
import com.google.mockwebserver.RecordedRequest;
@@ -54,7 +56,7 @@ public class HttpCommandEffectorTest extends BrooklynAppUnitTestSupport {
private static final Logger log = LoggerFactory.getLogger(HttpCommandEffectorTest.class);
private static final String DEFAULT_ENDPOINT = "/";
- final static Effector<String> EFFECTOR_HTTP_COMMAND = Effectors.effector(String.class, "http-command-effector").buildAbstract();
+ public final static Effector<String> EFFECTOR_HTTP_COMMAND = Effectors.effector(String.class, "http-command-effector").buildAbstract();
protected BetterMockWebServer server;
protected URL baseUrl;
@@ -78,7 +80,7 @@ public class HttpCommandEffectorTest extends BrooklynAppUnitTestSupport {
}
protected MockResponse jsonResponse(String resource) {
- return new MockResponse().addHeader("Content-Type", "application/json").setBody(stringFromResource(resource));
+ return new MockResponse().addHeader(HttpHeaders.CONTENT_TYPE, "application/json").setBody(stringFromResource(resource));
}
protected MockResponse response404() {
@@ -144,6 +146,88 @@ public class HttpCommandEffectorTest extends BrooklynAppUnitTestSupport {
}
@Test
+ public void testPayloadWithContentTypeHeaderJson() throws InterruptedException {
+ server.enqueue(jsonResponse("map-response.json"));
+
+ httpCommandEffector = new HttpCommandEffector(ConfigBag.newInstance()
+ .configure(HttpCommandEffector.EFFECTOR_NAME, EFFECTOR_HTTP_COMMAND.getName())
+ .configure(HttpCommandEffector.EFFECTOR_URI, url("/post"))
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "POST")
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_PAYLOAD, ImmutableMap.of("key", "value"))
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_HEADERS, ImmutableMap.of(HttpHeaders.CONTENT_TYPE, "application/json"))
+ .configure(HttpCommandEffector.JSON_PATH, "$.data")
+ );
+ assertNotNull(httpCommandEffector);
+ TestEntity testEntity = app.createAndManageChild(buildEntitySpec(httpCommandEffector));
+ Object output = testEntity.invoke(EFFECTOR_HTTP_COMMAND, ImmutableMap.<String, Object>of()).getUnchecked(Duration.minutes(1));
+ assertEquals(output, "{\"key\", \"value\"}");
+
+ assertEquals(server.getRequestCount(), 1);
+ assertSent(server, "POST", "/post");
+ }
+
+ @Test
+ public void testPayloadWithoutContentTypeHeader() throws InterruptedException {
+ server.enqueue(jsonResponse("map-response.json"));
+
+ httpCommandEffector = new HttpCommandEffector(ConfigBag.newInstance()
+ .configure(HttpCommandEffector.EFFECTOR_NAME, EFFECTOR_HTTP_COMMAND.getName())
+ .configure(HttpCommandEffector.EFFECTOR_URI, url("/post"))
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "POST")
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_PAYLOAD, ImmutableMap.of("key", "value"))
+ .configure(HttpCommandEffector.JSON_PATH, "$.data")
+ );
+ assertNotNull(httpCommandEffector);
+ TestEntity testEntity = app.createAndManageChild(buildEntitySpec(httpCommandEffector));
+ Object output = testEntity.invoke(EFFECTOR_HTTP_COMMAND, ImmutableMap.<String, Object>of()).getUnchecked(Duration.seconds(1));
+ assertEquals(output, "{\"key\", \"value\"}");
+
+ assertEquals(server.getRequestCount(), 1);
+ assertSent(server, "POST", "/post");
+ }
+
+ @Test
+ public void testListPayloadWithoutContentTypeHeader() throws InterruptedException {
+ server.enqueue(jsonResponse("list-response.json"));
+
+ httpCommandEffector = new HttpCommandEffector(ConfigBag.newInstance()
+ .configure(HttpCommandEffector.EFFECTOR_NAME, EFFECTOR_HTTP_COMMAND.getName())
+ .configure(HttpCommandEffector.EFFECTOR_URI, url("/post"))
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "POST")
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_PAYLOAD, ImmutableList.of("key", "value"))
+ .configure(HttpCommandEffector.JSON_PATH, "$.data")
+ );
+ assertNotNull(httpCommandEffector);
+ TestEntity testEntity = app.createAndManageChild(buildEntitySpec(httpCommandEffector));
+ Object output = testEntity.invoke(EFFECTOR_HTTP_COMMAND, ImmutableMap.<String, Object>of()).getUnchecked(Duration.seconds(1));
+ assertEquals(output, "[\"key\", \"value\"]");
+
+ assertEquals(server.getRequestCount(), "[\"key\", \"value\"]");
+ assertSent(server, "POST", "/post");
+ }
+
+ @Test
+ public void testPayloadWithContentTypeHeaderXml() throws InterruptedException {
+ server.enqueue(jsonResponse("int-response.json"));
+
+ httpCommandEffector = new HttpCommandEffector(ConfigBag.newInstance()
+ .configure(HttpCommandEffector.EFFECTOR_NAME, EFFECTOR_HTTP_COMMAND.getName())
+ .configure(HttpCommandEffector.EFFECTOR_URI, url("/post"))
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_VERB, "POST")
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_PAYLOAD, 1)
+ .configure(HttpCommandEffector.EFFECTOR_HTTP_HEADERS, ImmutableMap.of(HttpHeaders.CONTENT_TYPE, "application/xml"))
+ .configure(HttpCommandEffector.JSON_PATH, "$.data")
+ );
+ assertNotNull(httpCommandEffector);
+ TestEntity testEntity = app.createAndManageChild(buildEntitySpec(httpCommandEffector));
+ Object output = testEntity.invoke(EFFECTOR_HTTP_COMMAND, ImmutableMap.<String, Object>of()).getUnchecked(Duration.seconds(1));
+ assertEquals(output, "1");
+
+ assertEquals(server.getRequestCount(), 1);
+ assertSent(server, "POST", "/post");
+ }
+
+ @Test
public void testHappyPath() throws InterruptedException {
server.enqueue(jsonResponse("login.json"));
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b32581dd/core/src/test/resources/org/apache/brooklyn/core/effector/http/int-response.json
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/brooklyn/core/effector/http/int-response.json b/core/src/test/resources/org/apache/brooklyn/core/effector/http/int-response.json
new file mode 100644
index 0000000..9b133f7
--- /dev/null
+++ b/core/src/test/resources/org/apache/brooklyn/core/effector/http/int-response.json
@@ -0,0 +1,16 @@
+{
+ "args": {},
+ "data": "1",
+ "files": {},
+ "form": {},
+ "headers": {
+ "Accept": "*/*",
+ "Content-Length": "1",
+ "Content-Type": "application/json",
+ "Host": "httpbin.org",
+ "User-Agent": "curl/7.49.1"
+ },
+ "json": 1,
+ "origin": "93.61.99.89",
+ "url": "http://httpbin.org/post"
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b32581dd/core/src/test/resources/org/apache/brooklyn/core/effector/http/list-response.json
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/brooklyn/core/effector/http/list-response.json b/core/src/test/resources/org/apache/brooklyn/core/effector/http/list-response.json
new file mode 100644
index 0000000..88394ea
--- /dev/null
+++ b/core/src/test/resources/org/apache/brooklyn/core/effector/http/list-response.json
@@ -0,0 +1,19 @@
+{
+ "args": {},
+ "data": "[\"key\", \"value\"]",
+ "files": {},
+ "form": {},
+ "headers": {
+ "Accept": "*/*",
+ "Content-Length": "16",
+ "Content-Type": "application/json",
+ "Host": "httpbin.org",
+ "User-Agent": "curl/7.49.1"
+ },
+ "json": [
+ "key",
+ "value"
+ ],
+ "origin": "93.61.99.89",
+ "url": "http://httpbin.org/post"
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b32581dd/core/src/test/resources/org/apache/brooklyn/core/effector/http/map-response.json
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/brooklyn/core/effector/http/map-response.json b/core/src/test/resources/org/apache/brooklyn/core/effector/http/map-response.json
new file mode 100644
index 0000000..959b763
--- /dev/null
+++ b/core/src/test/resources/org/apache/brooklyn/core/effector/http/map-response.json
@@ -0,0 +1,16 @@
+{
+ "args": {},
+ "data": "{\"key\", \"value\"}",
+ "files": {},
+ "form": {},
+ "headers": {
+ "Accept": "*/*",
+ "Content-Length": "16",
+ "Content-Type": "application/json",
+ "Host": "httpbin.org",
+ "User-Agent": "curl/7.49.1"
+ },
+ "json": null,
+ "origin": "93.61.99.89",
+ "url": "http://httpbin.org/post"
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b32581dd/core/src/test/resources/org/apache/brooklyn/core/effector/test.json
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/brooklyn/core/effector/test.json b/core/src/test/resources/org/apache/brooklyn/core/effector/test.json
new file mode 100644
index 0000000..b39889a
--- /dev/null
+++ b/core/src/test/resources/org/apache/brooklyn/core/effector/test.json
@@ -0,0 +1,16 @@
+{
+ "args": {
+ "login": "myLogin"
+ },
+ "headers": {
+ "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
+ "Accept-Encoding": "gzip, deflate, sdch, br",
+ "Accept-Language": "en-US,en;q=0.8,it;q=0.6",
+ "Cookie": "_ga=GA1.2.1060288368.1484053495; _gat=1",
+ "Host": "httpbin.org",
+ "Upgrade-Insecure-Requests": "1",
+ "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36"
+ },
+ "origin": "93.61.99.89",
+ "url": "https://httpbin.org/get?login=myLogin"
+}
[09/10] brooklyn-server git commit: This closes #555
Posted by he...@apache.org.
This closes #555
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/fd033127
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/fd033127
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/fd033127
Branch: refs/heads/master
Commit: fd033127c2661175c8142094faaf1c1c0b969bf8
Parents: 39301e0 070c6f5
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Feb 15 18:47:17 2017 +0000
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Feb 15 18:47:17 2017 +0000
----------------------------------------------------------------------
.../brooklyn/util/time/DurationPredicates.java | 162 +++++++++++++++++++
.../util/time/DurationPredicatesTest.java | 150 +++++++++++++++++
2 files changed, 312 insertions(+)
----------------------------------------------------------------------