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/07/22 02:14:46 UTC
[07/10] brooklyn-server git commit: tests for activity limits/depths
tests for activity limits/depths
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/157c3858
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/157c3858
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/157c3858
Branch: refs/heads/master
Commit: 157c3858e62d3345ac81cefb093cae1d64480c43
Parents: 36fd318
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Jul 6 23:43:01 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Thu Jul 6 23:43:01 2017 +0100
----------------------------------------------------------------------
.../brooklyn/core/effector/AddEffector.java | 2 +-
.../apache/brooklyn/core/entity/Entities.java | 4 +
.../apache/brooklyn/util/core/task/Tasks.java | 29 +-
.../core/effector/SampleManyTasksEffector.java | 23 +-
.../rest/resources/ActivityResource.java | 4 +-
.../rest/resources/ActivityRestTest.java | 344 +++++++++++++++++++
.../rest/resources/ApplicationResourceTest.java | 13 +-
.../rest/resources/EffectorUtilsRestTest.java | 1 +
.../rest/resources/ErrorResponseTest.java | 2 -
9 files changed, 403 insertions(+), 19 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/157c3858/core/src/main/java/org/apache/brooklyn/core/effector/AddEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/AddEffector.java b/core/src/main/java/org/apache/brooklyn/core/effector/AddEffector.java
index 9590bcf..04c1364 100644
--- a/core/src/main/java/org/apache/brooklyn/core/effector/AddEffector.java
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/AddEffector.java
@@ -63,7 +63,7 @@ public class AddEffector implements EntityInitializer {
public static final ConfigKey<Map<String,Object>> EFFECTOR_PARAMETER_DEFS = new MapConfigKey<Object>(Object.class, "parameters");
- final Effector<?> effector;
+ protected final Effector<?> effector;
public AddEffector(Effector<?> effector) {
this.effector = Preconditions.checkNotNull(effector, "effector");
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/157c3858/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java b/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java
index 46a9cea..df904d3 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java
@@ -480,6 +480,10 @@ public class Entities {
out.flush();
}
+ public static void dumpInfo(Task<?> t) {
+ Tasks.dumpInfo(t);
+ }
+
public static void dumpInfo(Enricher enr) {
try {
dumpInfo(enr, new PrintWriter(System.out), "", " ");
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/157c3858/core/src/main/java/org/apache/brooklyn/util/core/task/Tasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/task/Tasks.java b/core/src/main/java/org/apache/brooklyn/util/core/task/Tasks.java
index 09116af..0677f74 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/task/Tasks.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/task/Tasks.java
@@ -18,6 +18,9 @@
*/
package org.apache.brooklyn.util.core.task;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
@@ -39,7 +42,6 @@ import org.apache.brooklyn.util.repeat.Repeater;
import org.apache.brooklyn.util.time.CountdownTimer;
import org.apache.brooklyn.util.time.Duration;
import org.apache.brooklyn.util.time.Time;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -492,4 +494,29 @@ public class Tasks {
return "in "+timeout;
}
+
+ public static void dumpInfo(Task<?> t) {
+ try {
+ dumpInfo(t, new PrintWriter(System.out), "", " ");
+ } catch (IOException exc) {
+ // system.out throwing an exception is odd, so don't have IOException on signature
+ throw new RuntimeException(exc);
+ }
+ }
+ public static void dumpInfo(Task<?> t, Writer out) throws IOException {
+ dumpInfo(t, out, "", " ");
+ }
+ public static void dumpInfo(Task<?> t, String currentIndentation, String tab) throws IOException {
+ dumpInfo(t, new PrintWriter(System.out), currentIndentation, tab);
+ }
+ public static void dumpInfo(Task<?> t, Writer out, String currentIndentation, String tab) throws IOException {
+ out.append(currentIndentation+t+": "+t.getStatusDetail(false)+"\n");
+
+ if (t instanceof HasTaskChildren) {
+ for (Task<?> child: ((HasTaskChildren)t).getChildren()) {
+ dumpInfo(child, out, currentIndentation+tab, tab);
+ }
+ }
+ out.flush();
+ }
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/157c3858/core/src/test/java/org/apache/brooklyn/core/effector/SampleManyTasksEffector.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/effector/SampleManyTasksEffector.java b/core/src/test/java/org/apache/brooklyn/core/effector/SampleManyTasksEffector.java
index 6cf4e2c..da36de3 100644
--- a/core/src/test/java/org/apache/brooklyn/core/effector/SampleManyTasksEffector.java
+++ b/core/src/test/java/org/apache/brooklyn/core/effector/SampleManyTasksEffector.java
@@ -1,12 +1,15 @@
package org.apache.brooklyn.core.effector;
import java.util.List;
+import java.util.Random;
import java.util.concurrent.Callable;
import org.apache.brooklyn.api.effector.Effector;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.mgmt.Task;
import org.apache.brooklyn.api.mgmt.TaskAdaptable;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
import org.apache.brooklyn.core.effector.EffectorTasks.EffectorTaskFactory;
import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.core.config.ConfigBag;
@@ -39,11 +42,21 @@ services:
*/
public class SampleManyTasksEffector extends AddEffector {
+ public static final ConfigKey<Integer> RANDOM_SEED = ConfigKeys.newIntegerConfigKey("random.seed");
+
public SampleManyTasksEffector(ConfigBag params) {
super(Effectors.effector(String.class, params.get(EFFECTOR_NAME)).name("eatand").impl(body(params)).build());
}
+ public Effector<?> getEffector() {
+ return effector;
+ }
+
private static EffectorTaskFactory<String> body(ConfigBag params) {
+ Integer seed = params.get(RANDOM_SEED);
+ final Random random = seed!=null ? new Random(seed) : new Random();
+
+ // NOTE: not nicely serializable
return new EffectorTaskFactory<String>() {
@Override
public TaskAdaptable<String> newTask(Entity entity, Effector<String> effector, ConfigBag parameters) {
@@ -53,13 +66,13 @@ public class SampleManyTasksEffector extends AddEffector {
List<Task<Object>> result = MutableList.of();
do {
TaskBuilder<Object> t = Tasks.builder();
- double x = Math.random();
- if (depth>4) x *= Math.random();
- if (depth>6) x *= Math.random();
+ double x = random.nextDouble();
+ if (depth>4) x *= random.nextDouble();
+ if (depth>6) x *= random.nextDouble();
if (x<0.3) {
t.displayName("eat").body(new Callable<Object>() { public Object call() { return "eat"; }});
} else if (x<0.6) {
- final Duration time = Duration.millis(Math.round(10*1000*Math.random()*Math.random()*Math.random()*Math.random()*Math.random()));
+ final Duration time = Duration.millis(Math.round(10*1000*random.nextDouble()*random.nextDouble()*random.nextDouble()*random.nextDouble()*random.nextDouble()));
t.displayName("sleep").description("Sleeping "+time).body(new Callable<Object>() { public Object call() {
Tasks.setBlockingDetails("sleeping "+time);
Time.sleep(time);
@@ -78,7 +91,7 @@ public class SampleManyTasksEffector extends AddEffector {
}
result.add(t.build());
- } while (Math.random()<0.8);
+ } while (random.nextDouble()<0.8);
return result;
}
};
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/157c3858/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ActivityResource.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ActivityResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ActivityResource.java
index 2bc90ad..6e3c2eb 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ActivityResource.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ActivityResource.java
@@ -79,13 +79,13 @@ public class ActivityResource extends AbstractBrooklynRestResource implements Ac
return result;
}
Set<Task<?>> nextLayer = MutableSet.copyOf( ((HasTaskChildren) parentTask).getChildren() );
- outer: while (!nextLayer.isEmpty() && maxDepth-- != 0) {
+ outer: while (limit!=0 && !nextLayer.isEmpty() && maxDepth-- != 0) {
Set<Task<?>> thisLayer = nextLayer;
nextLayer = MutableSet.of();
for (final Task<?> childTask : thisLayer) {
TaskSummary wasThere = result.put(childTask.getId(), TaskTransformer.fromTask(ui.getBaseUriBuilder()).apply(childTask));
if (wasThere==null) {
- if (limit-- == 0) {
+ if (--limit == 0) {
break outer;
}
if (childTask instanceof HasTaskChildren) {
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/157c3858/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ActivityRestTest.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ActivityRestTest.java b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ActivityRestTest.java
new file mode 100644
index 0000000..a5424f8
--- /dev/null
+++ b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ActivityRestTest.java
@@ -0,0 +1,344 @@
+/*
+ * 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.rest.resources;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeoutException;
+
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.mgmt.HasTaskChildren;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.core.effector.SampleManyTasksEffector;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.mgmt.EntityManagementUtils;
+import org.apache.brooklyn.core.mgmt.EntityManagementUtils.CreationResult;
+import org.apache.brooklyn.core.mgmt.internal.TestEntityWithEffectors;
+import org.apache.brooklyn.entity.stock.BasicApplication;
+import org.apache.brooklyn.rest.domain.TaskSummary;
+import org.apache.brooklyn.rest.testing.BrooklynRestResourceTest;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.collections.MutableList;
+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.HttpAsserts;
+import org.apache.brooklyn.util.time.CountdownTimer;
+import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.Iterables;
+
+/** Tests {@link ActivityResource} and activity methods on {@link EntityResource} */
+public class ActivityRestTest extends BrooklynRestResourceTest {
+
+ private static final Logger log = LoggerFactory.getLogger(ActivityRestTest.class);
+
+ /* a nice seed, initial run as follows;
+
+Task[eatand]@J90TKfIX: Waiting on Task[eat-sleep-rave-repeat]@QPa5o4kF
+ Task[eat-sleep-rave-repeat]@QPa5o4kF: Waiting on Task[rave]@yP9KjuWD
+ Task[rave]@yP9KjuWD: Waiting on Task[repeat]@Dd1AqB7Q
+ Task[repeat]@Dd1AqB7Q: Waiting on Task[repeat]@remQL5eD
+ Task[repeat]@remQL5eD: Waiting on Task[repeat]@g1ReP4BP
+ Task[sleep]@iV3iWg2N: Completed, result: slept 46ms
+ Task[eat]@fpIttX07: Completed, result: eat
+ Task[eat]@w6sxLefq: Completed, result: eat
+ Task[repeat]@g1ReP4BP: Waiting on Task[sleep]@zRTOQ4ak
+ Task[eat]@TvcdOUx7: Completed, result: eat
+ Task[rave]@yJndzNLf: Completed, result: raved with 1 tasks
+ Task[eat]@oiJ3eZZQ: Completed, result: eat
+ Task[sleep]@zRTOQ4ak: sleeping 74ms
+ Task[eat]@qoFRPEfM: Not submitted
+ Task[sleep]@fNX16uvi: Not submitted
+
+ */
+ private final int SEED = 1;
+
+ private Entity entity;
+ private Effector<?> effector;
+
+ private Task<?> lastTask;
+
+ @BeforeClass(alwaysRun = true)
+ public void setUp() throws Exception {
+ startServer();
+ }
+
+ @BeforeMethod(alwaysRun = true)
+ public void setUpOneTest() throws Exception {
+ initEntity(SEED);
+ }
+
+ @SuppressWarnings("deprecation")
+ protected void initEntity(int seed) {
+ if (entity!=null) {
+ Entities.destroy(entity.getApplication());
+ }
+
+ CreationResult<BasicApplication, Void> app = EntityManagementUtils.createStarting(getManagementContext(),
+ EntitySpec.create(BasicApplication.class)
+ .child(EntitySpec.create(TestEntityWithEffectors.class)) );
+ app.blockUntilComplete();
+ entity = Iterables.getOnlyElement( app.get().getChildren() );
+
+ SampleManyTasksEffector manyTasksAdder = new SampleManyTasksEffector(ConfigBag.newInstance().configure(SampleManyTasksEffector.RANDOM_SEED, seed));
+ effector = manyTasksAdder.getEffector();
+ manyTasksAdder.apply((org.apache.brooklyn.api.entity.EntityLocal) entity);
+ }
+
+ /** finds a good seed, in case the effector changes */
+ public static void main(String[] args) throws Exception {
+ ActivityRestTest me = new ActivityRestTest();
+ me.setUpClass();
+ int i=0;
+ do {
+ me.initEntity(i);
+ try {
+ log.info("Trying seed "+i+"...");
+ me.testGood(Duration.millis(200));
+ break;
+ } catch (Throwable e) {
+ log.info(" "+Exceptions.collapseText(e));
+ // e.printStackTrace();
+ // continue
+ }
+ i++;
+ } while (true);
+ Tasks.dumpInfo(me.lastTask);
+ log.info("Seed "+i+" is good ^");
+ }
+
+ @Test
+ public void testGood() {
+ testGood(Duration.ONE_SECOND);
+ }
+
+ void testGood(Duration timeout) {
+ lastTask = entity.invoke(effector, null);
+ Task<?> leaf = waitForCompletedDescendantWithChildAndSibling(lastTask, lastTask, CountdownTimer.newInstanceStarted(timeout), 0);
+ Assert.assertTrue(depthOf(leaf)>=4, "Not deep enough: "+depthOf(leaf));
+ }
+
+ @Test
+ public void testGetActivity() {
+ Task<?> t = entity.invoke(effector, null);
+
+ Response response = client().path("/activities/"+t.getId())
+ .accept(MediaType.APPLICATION_JSON)
+ .get();
+ assertHealthy(response);
+ TaskSummary task = response.readEntity(TaskSummary.class);
+ Assert.assertEquals(task.getId(), t.getId());
+ }
+
+ @Test
+ public void testGetActivitiesChildren() {
+ Task<?> t = entity.invoke(effector, null);
+ Task<?> leaf = waitForCompletedDescendantWithChildAndSibling(t, t, CountdownTimer.newInstanceStarted(Duration.ONE_SECOND), 0);
+
+ Response response = client().path("/activities/"+leaf.getSubmittedByTask().getId()+"/children")
+ .accept(MediaType.APPLICATION_JSON)
+ .get();
+ assertHealthy(response);
+ List<TaskSummary> tasks = response.readEntity(new GenericType<List<TaskSummary>>() {});
+ log.info("Tasks children: "+tasks.size());
+ Assert.assertTrue(tasksContain(tasks, leaf), "tasks should have included leaf "+leaf+"; was "+tasks);
+ }
+
+ @Test
+ public void testGetActivitiesRecursiveAndWithLimit() {
+ Task<?> t = entity.invoke(effector, null);
+ Task<?> leaf = waitForCompletedDescendantWithChildAndSibling(t, t, CountdownTimer.newInstanceStarted(Duration.ONE_SECOND), 0);
+ Task<?> leafParent = leaf.getSubmittedByTask();
+ Task<?> leafGrandparent = leafParent.getSubmittedByTask();
+
+ Response response = client().path("/activities/"+leafGrandparent.getId()+"/children")
+ .accept(MediaType.APPLICATION_JSON)
+ .get();
+ assertHealthy(response);
+ List<TaskSummary> tasksL = response.readEntity(new GenericType<List<TaskSummary>>() {});
+ Assert.assertFalse(tasksContain(tasksL, leaf), "non-recursive tasks should not have included leaf "+leaf+"; was "+tasksL);
+ Assert.assertTrue(tasksContain(tasksL, leafParent), "non-recursive tasks should have included leaf parent "+leafParent+"; was "+tasksL);
+ Assert.assertFalse(tasksContain(tasksL, leafGrandparent), "non-recursive tasks should not have included leaf grandparent "+leafGrandparent+"; was "+tasksL);
+
+ response = client().path("/activities/"+leafGrandparent.getId()+"/children/recurse")
+ .accept(MediaType.APPLICATION_JSON)
+ .get();
+ assertHealthy(response);
+ Map<String,TaskSummary> tasks = response.readEntity(new GenericType<Map<String,TaskSummary>>() {});
+ Assert.assertTrue(tasksContain(tasks, leaf), "recursive tasks should have included leaf "+leaf+"; was "+tasks);
+ Assert.assertTrue(tasksContain(tasks, leafParent), "recursive tasks should have included leaf parent "+leafParent+"; was "+tasks);
+ Assert.assertFalse(tasksContain(tasks, leafGrandparent), "recursive tasks should not have included leaf grandparent "+leafGrandparent+"; was "+tasks);
+
+ response = client().path("/activities/"+leafGrandparent.getId()+"/children/recurse")
+ .query("maxDepth", 1)
+ .accept(MediaType.APPLICATION_JSON)
+ .get();
+ assertHealthy(response);
+ tasks = response.readEntity(new GenericType<Map<String,TaskSummary>>() {});
+ Assert.assertFalse(tasksContain(tasks, leaf), "depth 1 recursive tasks should nont have included leaf "+leaf+"; was "+tasks);
+ Assert.assertTrue(tasksContain(tasks, leafParent), "depth 1 recursive tasks should have included leaf parent "+leafParent+"; was "+tasks);
+
+ response = client().path("/activities/"+leafGrandparent.getId()+"/children/recurse")
+ .query("maxDepth", 2)
+ .accept(MediaType.APPLICATION_JSON)
+ .get();
+ assertHealthy(response);
+ tasks = response.readEntity(new GenericType<Map<String,TaskSummary>>() {});
+ Assert.assertTrue(tasksContain(tasks, leaf), "depth 2 recursive tasks should have included leaf "+leaf+"; was "+tasks);
+ Assert.assertTrue(tasksContain(tasks, leafParent), "depth 2 recursive tasks should have included leaf parent "+leafParent+"; was "+tasks);
+ Assert.assertFalse(tasksContain(tasks, leafGrandparent), "depth 2 recursive tasks should not have included leaf grandparent "+leafGrandparent+"; was "+tasks);
+
+ Assert.assertTrue(children(leafGrandparent).size() >= 2, "children: "+children(leafGrandparent));
+ response = client().path("/activities/"+leafGrandparent.getId()+"/children/recurse")
+ .query("limit", children(leafGrandparent).size())
+ .accept(MediaType.APPLICATION_JSON)
+ .get();
+ assertHealthy(response);
+ tasks = response.readEntity(new GenericType<Map<String,TaskSummary>>() {});
+ Assert.assertEquals(tasks.size(), children(leafGrandparent).size());
+ Assert.assertTrue(tasksContain(tasks, leafParent), "count limited recursive tasks should have included leaf parent "+leafParent+"; was "+tasks);
+ Assert.assertFalse(tasksContain(tasks, leaf), "count limited recursive tasks should not have included leaf "+leaf+"; was "+tasks);
+
+ response = client().path("/activities/"+leafGrandparent.getId()+"/children/recurse")
+ .query("limit", children(leafGrandparent).size()+1)
+ .accept(MediaType.APPLICATION_JSON)
+ .get();
+ assertHealthy(response);
+ tasks = response.readEntity(new GenericType<Map<String,TaskSummary>>() {});
+ Assert.assertEquals(tasks.size(), children(leafGrandparent).size()+1);
+ tasks = response.readEntity(new GenericType<Map<String,TaskSummary>>() {});
+ Assert.assertTrue(tasksContain(tasks, leafParent), "count+1 limited recursive tasks should have included leaf parent "+leafParent+"; was "+tasks);
+ Assert.assertTrue(tasksContain(tasks, leaf), "count+1 limited recursive tasks should have included leaf "+leaf+"; was "+tasks);
+ }
+
+ private boolean tasksContain(Map<String, TaskSummary> tasks, Task<?> leaf) {
+ return tasks.keySet().contains(leaf.getId());
+ }
+
+ private List<Task<?>> children(Task<?> t) {
+ return MutableList.copyOf( ((HasTaskChildren)t).getChildren() );
+ }
+
+ @Test
+ public void testGetEntityActivitiesAndWithLimit() {
+ Task<?> t = entity.invoke(effector, null);
+ Task<?> leaf = waitForCompletedDescendantWithChildAndSibling(t, t, CountdownTimer.newInstanceStarted(Duration.ONE_SECOND), 0);
+
+ Response response = client().path("/applications/"+entity.getApplicationId()+
+ "/entities/"+entity.getId()+"/activities")
+ .accept(MediaType.APPLICATION_JSON)
+ .get();
+ assertHealthy(response);
+ List<TaskSummary> tasks = response.readEntity(new GenericType<List<TaskSummary>>() {});
+ log.info("Tasks now: "+tasks.size());
+ Assert.assertTrue(tasks.size() > 4, "tasks should have been big; was "+tasks);
+ Assert.assertTrue(tasksContain(tasks, leaf), "tasks should have included leaf "+leaf+"; was "+tasks);
+
+ response = client().path("/applications/"+entity.getApplicationId()+
+ "/entities/"+entity.getId()+"/activities")
+ .query("limit", 3)
+ .accept(MediaType.APPLICATION_JSON)
+ .get();
+ assertHealthy(response);
+ tasks = response.readEntity(new GenericType<List<TaskSummary>>() {});
+ log.info("Tasks limited: "+tasks.size());
+ Assert.assertEquals(tasks.size(), 3, "tasks should have been limited; was "+tasks);
+ Assert.assertFalse(tasksContain(tasks, leaf), "tasks should not have included leaf "+leaf+"; was "+tasks);
+ }
+
+ private void assertHealthy(Response response) {
+ if (!HttpAsserts.isHealthyStatusCode(response.getStatus())) {
+ Asserts.fail("Bad response: "+response.getStatus()+" "+response.readEntity(String.class));
+ }
+ }
+
+ private static boolean tasksContain(List<TaskSummary> tasks, Task<?> leaf) {
+ for (TaskSummary ts: tasks) {
+ if (ts.getId().equals(leaf.getId())) return true;
+ }
+ return false;
+ }
+
+ private int depthOf(Task<?> t) {
+ int depth = -1;
+ while (t!=null) {
+ t = t.getSubmittedByTask();
+ depth++;
+ }
+ return depth;
+ }
+
+ private Task<?> waitForCompletedDescendantWithChildAndSibling(Task<?> tRoot, Task<?> t, CountdownTimer timer, int depthSoFar) {
+ while (timer.isLive()) {
+ Iterable<Task<?>> children = ((HasTaskChildren)t).getChildren();
+ Iterator<Task<?>> ci = children.iterator();
+ Task<?> bestFinishedDescendant = null;
+ while (ci.hasNext()) {
+ Task<?> tc = ci.next();
+ Task<?> finishedDescendant = waitForCompletedDescendantWithChildAndSibling(tRoot, tc, timer, depthSoFar+1);
+ if (depthOf(finishedDescendant) > depthOf(bestFinishedDescendant)) {
+ bestFinishedDescendant = finishedDescendant;
+ }
+ int finishedDescendantDepth = depthOf(bestFinishedDescendant);
+ // log.info("finished "+tc+", depth "+finishedDescendantDepth);
+ if (finishedDescendantDepth < 2) {
+ if (ci.hasNext()) continue;
+ throw new IllegalStateException("not deep enough: "+finishedDescendantDepth);
+ }
+ if (finishedDescendantDepth == depthSoFar+1) {
+ // child completed; now check we complete soon, and assert we have siblings
+ if (ci.hasNext()) continue;
+ if (!t.blockUntilEnded(timer.getDurationRemaining())) {
+ Entities.dumpInfo(tRoot);
+ // log.info("Incomplete after "+t+": "+t.getStatusDetail(false));
+ throw Exceptions.propagate( new TimeoutException("parent didn't complete after child depth "+finishedDescendantDepth) );
+ }
+ }
+ if (finishedDescendantDepth == depthSoFar+2) {
+ if (Iterables.size(children)<2) {
+ Entities.dumpInfo(tRoot);
+ throw new IllegalStateException("finished child's parent has no sibling");
+ }
+ }
+
+ return bestFinishedDescendant;
+ }
+ Thread.yield();
+
+ // leaf nodeƄ
+ if (t.isDone()) return t;
+ }
+ throw Exceptions.propagate( new TimeoutException("expired waiting for children") );
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/157c3858/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ApplicationResourceTest.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ApplicationResourceTest.java b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ApplicationResourceTest.java
index 277fd32..76c08e8 100644
--- a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ApplicationResourceTest.java
+++ b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ApplicationResourceTest.java
@@ -32,7 +32,11 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeoutException;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
@@ -71,7 +75,7 @@ import org.apache.brooklyn.util.collections.CollectionFunctionals;
import org.apache.brooklyn.util.exceptions.Exceptions;
import org.apache.brooklyn.util.http.HttpAsserts;
import org.apache.brooklyn.util.text.Strings;
-import org.apache.brooklyn.util.time.Duration;
+import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.http.HttpHeaders;
import org.apache.http.entity.ContentType;
import org.slf4j.Logger;
@@ -87,13 +91,6 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.core.GenericType;
-import javax.ws.rs.core.MultivaluedHashMap;
-
-import org.apache.cxf.jaxrs.client.WebClient;
-
@Test(singleThreaded = true,
// by using a different suite name we disallow interleaving other tests between the methods of this test class, which wrecks the test fixtures
suiteName = "ApplicationResourceTest")
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/157c3858/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/EffectorUtilsRestTest.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/EffectorUtilsRestTest.java b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/EffectorUtilsRestTest.java
index 5fe729d..d7157fd 100644
--- a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/EffectorUtilsRestTest.java
+++ b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/EffectorUtilsRestTest.java
@@ -85,6 +85,7 @@ public class EffectorUtilsRestTest extends BrooklynAppUnitTestSupport {
} catch (InterruptedException|ExecutionException e) {
throw Exceptions.propagate(e);
}
+ log.debug("Result description: "+summary.getDescription());
assertEquals(
summary.getDescription(),
"Invoking effector resetPassword on "+TestEntityWithEffectors.class.getSimpleName()+":"+entity.getId().substring(0,4)
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/157c3858/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ErrorResponseTest.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ErrorResponseTest.java b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ErrorResponseTest.java
index 27d8ea5..af5007d 100644
--- a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ErrorResponseTest.java
+++ b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ErrorResponseTest.java
@@ -23,7 +23,6 @@ import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import java.io.IOException;
-import java.io.InputStream;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@@ -36,7 +35,6 @@ import org.apache.brooklyn.rest.domain.PolicySummary;
import org.apache.brooklyn.rest.testing.BrooklynRestResourceTest;
import org.apache.brooklyn.rest.testing.mocks.RestMockSimpleEntity;
import org.apache.brooklyn.rest.testing.mocks.RestMockSimplePolicy;
-import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;