From 44d7133acb852bb42895c08ff6bcd91def1eaa51 Mon Sep 17 00:00:00 2001 From: Alasdair Hodge Date: Wed, 8 Mar 2017 08:06:51 +0000 Subject: [PATCH 1/2] Add Functionals.isSatisfied(subject, predicate) --- .../org/apache/brooklyn/util/guava/Functionals.java | 12 ++++++++++++ .../apache/brooklyn/util/guava/FunctionalsTest.java | 13 ++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/guava/Functionals.java b/utils/common/src/main/java/org/apache/brooklyn/util/guava/Functionals.java index 4a9a8c4267..18238d2bed 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/guava/Functionals.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/guava/Functionals.java @@ -148,4 +148,16 @@ public String toString() { return new FunctionAsPredicate(); } + /** + * Simple adapter from {@link Predicate} to {@link Callable} by currying the passed subject parameter. + */ + public static Callable isSatisfied(final T subject, final Predicate predicate) { + return new Callable() { + @Override + public Boolean call() { + return predicate.apply(subject); + } + }; + } + } diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/guava/FunctionalsTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/guava/FunctionalsTest.java index d33552bba9..bb871c3a7e 100644 --- a/utils/common/src/test/java/org/apache/brooklyn/util/guava/FunctionalsTest.java +++ b/utils/common/src/test/java/org/apache/brooklyn/util/guava/FunctionalsTest.java @@ -18,11 +18,11 @@ */ package org.apache.brooklyn.util.guava; -import org.apache.brooklyn.util.guava.Functionals; import org.apache.brooklyn.util.math.MathFunctions; import org.testng.Assert; import org.testng.annotations.Test; +import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.base.Suppliers; @@ -55,4 +55,15 @@ public void testIfNotEqual() { IfFunctionsTest.checkTF(Functionals.ifNotEquals(false).value("T").defaultValue("F").build(), "T"); } + @Test + public void testIsSatisfied() throws Exception { + Predicate isEven = new Predicate() { + @Override public boolean apply(Integer input) { + return (input % 2 == 0); + } + }; + Assert.assertFalse(Functionals.isSatisfied(11, isEven).call()); + Assert.assertTrue(Functionals.isSatisfied(22, isEven).call()); + } + } From fc8ec90542224c6b0b41c490a8a81b6f7b188dfd Mon Sep 17 00:00:00 2001 From: Alasdair Hodge Date: Wed, 8 Mar 2017 08:07:21 +0000 Subject: [PATCH 2/2] Add generalised Entities.waitFor(entity, condition, timeout) --- .../apache/brooklyn/core/entity/Entities.java | 38 ++++++++++++------- .../brooklyn/core/entity/EntitiesTest.java | 22 +++++++++-- 2 files changed, 42 insertions(+), 18 deletions(-) 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 9c8ebc8bbe..22e84b4e23 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 @@ -18,6 +18,9 @@ */ package org.apache.brooklyn.core.entity; +import static org.apache.brooklyn.core.entity.EntityPredicates.attributeEqualTo; +import static org.apache.brooklyn.util.guava.Functionals.isSatisfied; + import java.io.Closeable; import java.io.IOException; import java.io.PrintWriter; @@ -32,7 +35,6 @@ import java.util.Map; import java.util.Set; import java.util.Stack; -import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; @@ -1139,24 +1141,32 @@ public static void warnOnIgnoringConfig(Entity entity, ConfigKey key) { log.warn("Ignoring "+key+" set on "+entity+" ("+entity.getConfig(key)+")"); } - /** Waits until {@link Startable#SERVICE_UP} returns true. */ - public static void waitForServiceUp(final Entity entity, Duration timeout) { - String description = "Waiting for SERVICE_UP on "+entity; - Tasks.setBlockingDetails(description); + /** Waits until the passed entity satisfies the supplied predicate. */ + public static void waitFor(Entity entity, Predicate condition, Duration timeout) { try { - if (!Repeater.create(description).limitTimeTo(timeout) - .rethrowException().backoffTo(Duration.ONE_SECOND) - .until(new Callable() { - public Boolean call() { - return Boolean.TRUE.equals(entity.getAttribute(Startable.SERVICE_UP)); - }}) - .run()) { - throw new IllegalStateException("Timeout waiting for SERVICE_UP from "+entity); + String description = "Waiting for " + condition + " on " + entity; + Tasks.setBlockingDetails(description); + + Repeater repeater = Repeater.create(description) + .until(isSatisfied(entity, condition)) + .limitTimeTo(timeout) + .backoffTo(Duration.ONE_SECOND) + .rethrowException(); + + if (!repeater.run()) { + throw new IllegalStateException("Timeout waiting for " + condition + " on " + entity); } + } finally { Tasks.resetBlockingDetails(); } - log.debug("Detected SERVICE_UP for software {}", entity); + + log.debug("Detected {} for {}", condition, entity); + } + + /** Waits until {@link Startable#SERVICE_UP} returns true. */ + public static void waitForServiceUp(final Entity entity, Duration timeout) { + waitFor(entity, attributeEqualTo(Startable.SERVICE_UP, true), timeout); } public static void waitForServiceUp(final Entity entity, long duration, TimeUnit units) { waitForServiceUp(entity, Duration.of(duration, units)); diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/EntitiesTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/EntitiesTest.java index b5d2099d23..8a43059b22 100644 --- a/core/src/test/java/org/apache/brooklyn/core/entity/EntitiesTest.java +++ b/core/src/test/java/org/apache/brooklyn/core/entity/EntitiesTest.java @@ -18,6 +18,7 @@ */ package org.apache.brooklyn.core.entity; +import static org.apache.brooklyn.core.entity.EntityPredicates.applicationIdEqualTo; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; @@ -26,14 +27,12 @@ import org.apache.brooklyn.api.entity.EntitySpec; import org.apache.brooklyn.api.location.LocationSpec; -import org.apache.brooklyn.core.entity.Entities; -import org.apache.brooklyn.core.entity.EntityAndAttribute; -import org.apache.brooklyn.core.entity.EntityInitializers; import org.apache.brooklyn.core.location.SimulatedLocation; 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.collections.MutableSet; +import org.apache.brooklyn.util.time.Duration; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -130,5 +129,20 @@ public void testCreateGetContainsAndRemoveTags() throws Exception { entity.tags().removeTag(2); Assert.assertEquals(entity.tags().getTags(), MutableSet.of(app)); } - + + @Test + public void testWaitFor() throws Exception { + entity = app.createAndManageChild(EntitySpec.create(TestEntity.class)); + Duration timeout = Duration.ONE_MILLISECOND; + + Entities.waitFor(entity, applicationIdEqualTo(app.getApplicationId()), timeout); + + try { + Entities.waitFor(entity, applicationIdEqualTo(app.getApplicationId() + "-wrong"), timeout); + Asserts.shouldHaveFailedPreviously("Entities.waitFor() should have timed out"); + } catch (Exception e) { + Asserts.expectedFailureContains(e, "Timeout waiting for "); + } + } + }