add {forbidden,required}{If,Unless} constraints
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/0d6f5721 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/0d6f5721 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/0d6f5721 Branch: refs/heads/master Commit: 0d6f57219bd7ce36c912fddd26f37a46c6f8dbc2 Parents: bd34655 Author: Alex Heneveld <alex.henev...@cloudsoftcorp.com> Authored: Fri Sep 21 11:49:47 2018 +0100 Committer: Alex Heneveld <alex.henev...@cloudsoftcorp.com> Committed: Fri Sep 21 11:49:47 2018 +0100 ---------------------------------------------------------------------- .../brooklyn/core/config/ConfigConstraints.java | 69 ++++++++++ .../core/objs/ConstraintSerialization.java | 13 +- .../brooklyn/util/core/ResourcePredicates.java | 6 +- .../core/config/ConfigKeyConstraintTest.java | 133 ++++++++++++++----- .../java/org/apache/brooklyn/test/Asserts.java | 16 ++- 5 files changed, 195 insertions(+), 42 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0d6f5721/core/src/main/java/org/apache/brooklyn/core/config/ConfigConstraints.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/config/ConfigConstraints.java b/core/src/main/java/org/apache/brooklyn/core/config/ConfigConstraints.java index 35f672e..4ee584d 100644 --- a/core/src/main/java/org/apache/brooklyn/core/config/ConfigConstraints.java +++ b/core/src/main/java/org/apache/brooklyn/core/config/ConfigConstraints.java @@ -30,6 +30,7 @@ import org.apache.brooklyn.api.objs.BrooklynObject; import org.apache.brooklyn.api.objs.EntityAdjunct; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.entity.EntityInternal; +import org.apache.brooklyn.core.mgmt.BrooklynTaskTags; import org.apache.brooklyn.core.objs.AbstractEntityAdjunct; import org.apache.brooklyn.core.objs.BrooklynObjectInternal; import org.apache.brooklyn.core.objs.BrooklynObjectPredicate; @@ -37,6 +38,7 @@ import org.apache.brooklyn.core.objs.ConstraintSerialization; import org.apache.brooklyn.util.core.task.Tasks; import org.apache.brooklyn.util.exceptions.ReferenceWithError; import org.apache.brooklyn.util.guava.Maybe; +import org.apache.brooklyn.util.text.StringEscapes.JavaStringEscapes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -243,4 +245,71 @@ public abstract class ConfigConstraints<T extends BrooklynObject> { return "required()"; } } + + private static abstract class OtherKeyPredicate implements BrooklynObjectPredicate<Object> { + private String otherKeyName; + + public OtherKeyPredicate(String otherKeyName) { + this.otherKeyName = otherKeyName; + } + + public abstract String predicateName(); + + @Override + public String toString() { + return predicateName()+"("+JavaStringEscapes.wrapJavaString(otherKeyName)+")"; + } + + @Override + public boolean apply(Object input) { + return apply(input, BrooklynTaskTags.getContextEntity(Tasks.current())); + } + + @Override + public boolean apply(Object input, BrooklynObject context) { + if (context==null) return true; + // would be nice to offer an explanation, but that will need a richer API or a thread local + return test(input, context.config().get(ConfigKeys.newConfigKey(Object.class, otherKeyName))); + } + + public abstract boolean test(Object thisValue, Object otherValue); + + } + + public static Predicate<Object> forbiddenIf(String otherKeyName) { return new ForbiddenIfPredicate(otherKeyName); } + public static class ForbiddenIfPredicate extends OtherKeyPredicate { + public ForbiddenIfPredicate(String otherKeyName) { super(otherKeyName); } + @Override public String predicateName() { return "forbiddenIf"; } + @Override public boolean test(Object thisValue, Object otherValue) { + return (thisValue==null) || (otherValue==null); + } + } + + public static Predicate<Object> forbiddenUnless(String otherKeyName) { return new ForbiddenUnlessPredicate(otherKeyName); } + public static class ForbiddenUnlessPredicate extends OtherKeyPredicate { + public ForbiddenUnlessPredicate(String otherKeyName) { super(otherKeyName); } + @Override public String predicateName() { return "forbiddenUnless"; } + @Override public boolean test(Object thisValue, Object otherValue) { + return (thisValue==null) || (otherValue!=null); + } + } + + public static Predicate<Object> requiredIf(String otherKeyName) { return new RequiredIfPredicate(otherKeyName); } + public static class RequiredIfPredicate extends OtherKeyPredicate { + public RequiredIfPredicate(String otherKeyName) { super(otherKeyName); } + @Override public String predicateName() { return "requiredIf"; } + @Override public boolean test(Object thisValue, Object otherValue) { + return (thisValue!=null) || (otherValue==null); + } + } + + public static Predicate<Object> requiredUnless(String otherKeyName) { return new RequiredUnlessPredicate(otherKeyName); } + public static class RequiredUnlessPredicate extends OtherKeyPredicate { + public RequiredUnlessPredicate(String otherKeyName) { super(otherKeyName); } + @Override public String predicateName() { return "requiredUnless"; } + @Override public boolean test(Object thisValue, Object otherValue) { + return (thisValue!=null) || (otherValue!=null); + } + } + } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0d6f5721/core/src/main/java/org/apache/brooklyn/core/objs/ConstraintSerialization.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/ConstraintSerialization.java b/core/src/main/java/org/apache/brooklyn/core/objs/ConstraintSerialization.java index a6b7039..57258bc 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/ConstraintSerialization.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/ConstraintSerialization.java @@ -34,6 +34,7 @@ import org.apache.brooklyn.core.config.ConfigConstraints; import org.apache.brooklyn.util.collections.MutableList; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.collections.MutableSet; +import org.apache.brooklyn.util.core.ResourcePredicates; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.text.StringEscapes.JavaStringEscapes; import org.apache.brooklyn.util.text.StringPredicates; @@ -168,11 +169,19 @@ public class ConstraintSerialization { PredicateSerializationRuleAdder.predicateListConstructor((o) -> Predicates.or((Iterable)o)).preferredName("any").equivalentNames("or").add(this); PredicateSerializationRuleAdder.predicateListConstructor((o) -> /* and predicate is default when given list */ toPredicateFromJson(o)).preferredName("all").sample(Predicates.and(Collections.emptyList())).equivalentNames("and").add(this); - PredicateSerializationRuleAdder.noArgConstructor(() -> Predicates.alwaysFalse()).add(this); - PredicateSerializationRuleAdder.noArgConstructor(() -> Predicates.alwaysTrue()).add(this); + PredicateSerializationRuleAdder.noArgConstructor(Predicates::alwaysFalse).add(this); + PredicateSerializationRuleAdder.noArgConstructor(Predicates::alwaysTrue).add(this); + + PredicateSerializationRuleAdder.noArgConstructor(ResourcePredicates::urlExists).preferredName("urlExists").add(this); + PredicateSerializationRuleAdder.noArgConstructor(StringPredicates::isBlank).add(this); PredicateSerializationRuleAdder.stringConstructor(StringPredicates::matchesRegex).preferredName("regex").add(this); PredicateSerializationRuleAdder.stringConstructor(StringPredicates::matchesGlob).preferredName("glob").add(this); + + PredicateSerializationRuleAdder.stringConstructor(ConfigConstraints::forbiddenIf).add(this); + PredicateSerializationRuleAdder.stringConstructor(ConfigConstraints::forbiddenUnless).add(this); + PredicateSerializationRuleAdder.stringConstructor(ConfigConstraints::requiredIf).add(this); + PredicateSerializationRuleAdder.stringConstructor(ConfigConstraints::requiredUnless).add(this); } public static ConstraintSerialization INSTANCE = new ConstraintSerialization(); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0d6f5721/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java b/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java index 439aaae..240ab52 100644 --- a/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java +++ b/core/src/main/java/org/apache/brooklyn/util/core/ResourcePredicates.java @@ -22,7 +22,9 @@ package org.apache.brooklyn.util.core; import javax.annotation.Nullable; import org.apache.brooklyn.api.objs.BrooklynObject; +import org.apache.brooklyn.core.mgmt.BrooklynTaskTags; import org.apache.brooklyn.core.objs.BrooklynObjectPredicate; +import org.apache.brooklyn.util.core.task.Tasks; import org.apache.brooklyn.util.text.StringPredicates; import org.apache.brooklyn.util.text.Strings; @@ -54,7 +56,7 @@ public class ResourcePredicates { @Override public boolean apply(@Nullable String resource) { - return apply(resource, null); + return apply(resource, BrooklynTaskTags.getContextEntity(Tasks.current())); } @Override @@ -64,7 +66,7 @@ public class ResourcePredicates { @Override public String toString() { - return "ResourcePredicates.exists()"; + return "ResourcePredicates.urlExists()"; } } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0d6f5721/core/src/test/java/org/apache/brooklyn/core/config/ConfigKeyConstraintTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/config/ConfigKeyConstraintTest.java b/core/src/test/java/org/apache/brooklyn/core/config/ConfigKeyConstraintTest.java index 46710fb..a251cbc 100644 --- a/core/src/test/java/org/apache/brooklyn/core/config/ConfigKeyConstraintTest.java +++ b/core/src/test/java/org/apache/brooklyn/core/config/ConfigKeyConstraintTest.java @@ -20,11 +20,10 @@ package org.apache.brooklyn.core.config; import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.fail; import java.util.concurrent.Callable; +import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.entity.EntitySpec; import org.apache.brooklyn.api.entity.ImplementedBy; import org.apache.brooklyn.api.location.Location; @@ -45,7 +44,6 @@ import org.apache.brooklyn.core.test.entity.TestEntityImpl; import org.apache.brooklyn.core.test.policy.TestPolicy; import org.apache.brooklyn.test.Asserts; import org.apache.brooklyn.util.core.task.Tasks; -import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.javalang.JavaClassNames; import org.apache.brooklyn.util.net.Networking; import org.apache.brooklyn.util.time.Duration; @@ -154,10 +152,9 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport { public void testExceptionWhenEntityHasNullConfig() { try { app.createAndManageChild(EntitySpec.create(EntityWithNonNullConstraint.class)); - fail("Expected exception when managing entity with missing config"); + Asserts.shouldHaveFailedPreviously("Expected exception when managing entity with missing config"); } catch (Exception e) { - Throwable t = Exceptions.getFirstThrowableOfType(e, ConstraintViolationException.class); - assertNotNull(t); + Asserts.expectedFailureOfType(e, ConstraintViolationException.class); } } @@ -176,10 +173,9 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport { public void testExceptionWhenSubclassSetsInvalidDefaultValue() { try { app.createAndManageChild(EntitySpec.create(EntityProvidingDefaultValueForConfigKeyInRange.class)); - fail("Expected exception when managing entity setting invalid default value"); + Asserts.shouldHaveFailedPreviously("Expected exception when managing entity setting invalid default value"); } catch (Exception e) { - Throwable t = Exceptions.getFirstThrowableOfType(e, ConstraintViolationException.class); - assertNotNull(t, "Original exception was: " + Exceptions.collapseText(e)); + Asserts.expectedFailureOfType(e, ConstraintViolationException.class); } } @@ -188,10 +184,9 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport { try { app.createAndManageChild(EntitySpec.create(EntityWithNonNullConstraintWithNonNullDefault.class) .configure(EntityWithNonNullConstraintWithNonNullDefault.NON_NULL_WITH_DEFAULT, (Object) null)); - fail("Expected exception when config key set to null"); + Asserts.shouldHaveFailedPreviously("Expected exception when config key set to null"); } catch (Exception e) { - Throwable t = Exceptions.getFirstThrowableOfType(e, ConstraintViolationException.class); - assertNotNull(t, "Original exception was: " + Exceptions.collapseText(e)); + Asserts.expectedFailureOfType(e, ConstraintViolationException.class); } } @@ -200,10 +195,9 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport { try { app.createAndManageChild(EntitySpec.create(EntityRequiringConfigKeyInRange.class) .configure(ImmutableMap.of("test.conf.range", -1))); - fail("Expected exception when managing entity with invalid config"); + Asserts.shouldHaveFailedPreviously("Expected exception when managing entity with invalid config"); } catch (Exception e) { - Throwable t = Exceptions.getFirstThrowableOfType(e, ConstraintViolationException.class); - assertNotNull(t, "Original exception was: " + Exceptions.collapseText(e)); + Asserts.expectedFailureOfType(e, ConstraintViolationException.class); } } @@ -214,10 +208,9 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport { try { testEntity.addChild(EntitySpec.create(EntityRequiringConfigKeyInRange.class) .configure(EntityRequiringConfigKeyInRange.RANGE, -1)); - fail("Expected exception when managing child with invalid config"); + Asserts.shouldHaveFailedPreviously("Expected exception when managing child with invalid config"); } catch (Exception e) { - Throwable t = Exceptions.getFirstThrowableOfType(e, ConstraintViolationException.class); - assertNotNull(t, "Original exception was: " + Exceptions.collapseText(e)); + Asserts.expectedFailureOfType(e, ConstraintViolationException.class); } } @@ -228,10 +221,9 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport { .configure(EntityWithNonNullConstraint.NON_NULL_CONFIG, (Object) null)); try { ConfigConstraints.assertValid(p); - fail("Expected exception when validating policy with missing config"); + Asserts.shouldHaveFailedPreviously("Expected exception when validating policy with missing config"); } catch (Exception e) { - Throwable t = Exceptions.getFirstThrowableOfType(e, ConstraintViolationException.class); - assertNotNull(t, "Original exception was: " + Exceptions.collapseText(e)); + Asserts.expectedFailureOfType(e, ConstraintViolationException.class); } } @@ -240,10 +232,9 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport { try { mgmt.getEntityManager().createPolicy(PolicySpec.create(PolicyWithConfigConstraint.class) .configure(PolicyWithConfigConstraint.NON_NULL_CONFIG, (Object) null)); - fail("Expected exception when creating policy with missing config"); + Asserts.shouldHaveFailedPreviously("Expected exception when creating policy with missing config"); } catch (Exception e) { - Throwable t = Exceptions.getFirstThrowableOfType(e, ConstraintViolationException.class); - assertNotNull(t, "Original exception was: " + Exceptions.collapseText(e)); + Asserts.expectedFailureOfType(e, ConstraintViolationException.class); } } @@ -252,10 +243,9 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport { try { mgmt.getEntityManager().createEnricher(EnricherSpec.create(EnricherWithConfigConstraint.class) .configure(EnricherWithConfigConstraint.PATTERN, "123.123.256.10")); - fail("Expected exception when creating enricher with invalid config"); + Asserts.shouldHaveFailedPreviously("Expected exception when config key set to null"); } catch (Exception e) { - Throwable t = Exceptions.getFirstThrowableOfType(e, ConstraintViolationException.class); - assertNotNull(t, "Original exception was: " + Exceptions.collapseText(e)); + Asserts.expectedFailureOfType(e, ConstraintViolationException.class); } } @@ -289,7 +279,7 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport { app.createAndManageChild(EntitySpec.create(EntityWithContextAwareConstraint.class) .displayName("Mr. Big") .configure("must-be-display-name", "Mr. Bag")); - fail("Expected exception when managing entity with incorrect config"); + Asserts.shouldHaveFailedPreviously("Expected exception when managing entity with incorrect config"); } catch (Exception e) { Asserts.expectedFailureOfType(e, ConstraintViolationException.class); } @@ -306,7 +296,7 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport { // NB the call above does not currently/necessarily apply validation log.debug(JavaClassNames.niceClassAndMethod()+" got "+value+" for "+EntityRequiringConfigKeyInRange.RANGE+", now explicitly validating"); ConfigConstraints.assertValid(child); - fail("Expected exception when managing entity with incorrect config; instead passed assertion and got: "+value); + Asserts.shouldHaveFailedPreviously("Expected exception when managing entity with incorrect config; instead passed assertion and got: "+value); } catch (Exception e) { Asserts.expectedFailureOfType(e, ConstraintViolationException.class); } @@ -349,11 +339,90 @@ public class ConfigKeyConstraintTest extends BrooklynAppUnitTestSupport { public void testCannotUpdateConfigToInvalidValue(BrooklynObject object) { try { object.config().set(EntityRequiringConfigKeyInRange.RANGE, -1); - fail("Expected exception when calling config().set with invalid value on " + object); + Asserts.shouldHaveFailedPreviously("Expected exception when calling config().set with invalid value on " + object); } catch (Exception e) { - Throwable t = Exceptions.getFirstThrowableOfType(e, ConstraintViolationException.class); - assertNotNull(t, "Original exception was: " + Exceptions.collapseText(e)); + Asserts.expectedFailureOfType(e, ConstraintViolationException.class); } } + public static interface EntityForForbiddenAndRequiredConditionalConstraints extends TestEntity { + ConfigKey<Object> X = ConfigKeys.builder(Object.class).name("x") + .build(); + } + @ImplementedBy(EntityForForbiddenAndRequiredConditionalConstraintsForbiddenIfImpl.class) + public static interface EntityForForbiddenAndRequiredConditionalConstraintsForbiddenIf extends EntityForForbiddenAndRequiredConditionalConstraints { + static ConfigKey<Object> FI = ConfigKeys.builder(Object.class).name("forbiddenIfX") + .constraint(ConfigConstraints.forbiddenIf("x")).build(); + } + public static class EntityForForbiddenAndRequiredConditionalConstraintsForbiddenIfImpl extends TestEntityImpl implements EntityForForbiddenAndRequiredConditionalConstraintsForbiddenIf {} + + @ImplementedBy(EntityForForbiddenAndRequiredConditionalConstraintsForbiddenUnlessImpl.class) + public static interface EntityForForbiddenAndRequiredConditionalConstraintsForbiddenUnless extends EntityForForbiddenAndRequiredConditionalConstraints { + static ConfigKey<Object> FU = ConfigKeys.builder(Object.class).name("forbiddenUnlessX") + .constraint(ConfigConstraints.forbiddenUnless("x")).build(); + } + public static class EntityForForbiddenAndRequiredConditionalConstraintsForbiddenUnlessImpl extends TestEntityImpl implements EntityForForbiddenAndRequiredConditionalConstraintsForbiddenUnless {} + + @ImplementedBy(EntityForForbiddenAndRequiredConditionalConstraintsRequiredIfImpl.class) + public static interface EntityForForbiddenAndRequiredConditionalConstraintsRequiredIf extends EntityForForbiddenAndRequiredConditionalConstraints { + static ConfigKey<Object> RI = ConfigKeys.builder(Object.class).name("requiredIfX") + .constraint(ConfigConstraints.requiredIf("x")).build(); + } + public static class EntityForForbiddenAndRequiredConditionalConstraintsRequiredIfImpl extends TestEntityImpl implements EntityForForbiddenAndRequiredConditionalConstraintsRequiredIf {} + + @ImplementedBy(EntityForForbiddenAndRequiredConditionalConstraintsRequiredUnlessImpl.class) + public static interface EntityForForbiddenAndRequiredConditionalConstraintsRequiredUnless extends EntityForForbiddenAndRequiredConditionalConstraints { + static ConfigKey<Object> RU = ConfigKeys.builder(Object.class).name("requiredUnlessX") + .constraint(ConfigConstraints.requiredUnless("x")).build(); + } + public static class EntityForForbiddenAndRequiredConditionalConstraintsRequiredUnlessImpl extends TestEntityImpl implements EntityForForbiddenAndRequiredConditionalConstraintsRequiredUnless {} + + @Test + public void testForbiddenAndRequiredConditionalConstraintsForbiddenIf() { + assertKeyBehaviour(EntityForForbiddenAndRequiredConditionalConstraintsForbiddenIf.class, EntityForForbiddenAndRequiredConditionalConstraintsForbiddenIf.FI, + false, true, true, true); + } + + @Test + public void testForbiddenAndRequiredConditionalConstraintsForbiddenUnless() { + assertKeyBehaviour(EntityForForbiddenAndRequiredConditionalConstraintsForbiddenUnless.class, EntityForForbiddenAndRequiredConditionalConstraintsForbiddenUnless.FU, + true, true, false, true); + } + + @Test + public void testForbiddenAndRequiredConditionalConstraintsRequiredIf() { + assertKeyBehaviour(EntityForForbiddenAndRequiredConditionalConstraintsRequiredIf.class, EntityForForbiddenAndRequiredConditionalConstraintsRequiredIf.RI, + true, false, true, true); + } + + @Test + public void testForbiddenAndRequiredConditionalConstraintsRequiredUnlelss() { + assertKeyBehaviour(EntityForForbiddenAndRequiredConditionalConstraintsRequiredUnless.class, EntityForForbiddenAndRequiredConditionalConstraintsRequiredUnless.RU, + true, true, true, false); + } + + private void assertKeyBehaviour(Class<? extends Entity> clazz, ConfigKey<Object> key, boolean ifBoth, boolean ifJustX, boolean ifJustThis, boolean ifNone) { + assertKeyBehaviour("both set", clazz, true, key, true, ifBoth); + assertKeyBehaviour("only other key set", clazz, true, key, false, ifJustX); + assertKeyBehaviour("only this key set", clazz, false, key, true, ifJustThis); + assertKeyBehaviour("neither key set", clazz, false, key, false, ifNone); + } + + private void assertKeyBehaviour(String description, Class<? extends Entity> clazz, boolean isXSet, ConfigKey<Object> key, boolean isKeySet, boolean shouldSucceed) { + try { + EntitySpec<?> spec = EntitySpec.create(clazz); + if (isXSet) spec.configure(EntityForForbiddenAndRequiredConditionalConstraints.X, "set"); + if (isKeySet) spec.configure(key, "set"); + app.createAndManageChild(spec); + if (!shouldSucceed) { + Asserts.shouldHaveFailedPreviously("Expected failure when testing "+key.getName()+" - "+description); + } + } catch (Exception e) { + if (!shouldSucceed) { + Asserts.expectedFailureOfType("Expected ConstraintViolationException when testing "+key.getName()+" - "+description, e, ConstraintViolationException.class); + } else { + throw new AssertionError("Expected success when testing "+key.getName()+" - "+description+"; instead got "+e, e); + } + } + } } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0d6f5721/utils/common/src/main/java/org/apache/brooklyn/test/Asserts.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/test/Asserts.java b/utils/common/src/main/java/org/apache/brooklyn/test/Asserts.java index 6975139..eb9275a 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/test/Asserts.java +++ b/utils/common/src/main/java/org/apache/brooklyn/test/Asserts.java @@ -1261,17 +1261,21 @@ public class Asserts { * or more usually the test failure of this method is thrown, * with detail of the original {@link Throwable} logged and included in the caused-by. */ - @SuppressWarnings("unchecked") public static void expectedFailureOfType(Throwable e, Class<?> permittedSupertype, Class<?> ...permittedSupertypes) { + expectedFailureOfType(null, e, permittedSupertype, permittedSupertypes); + } + @SuppressWarnings("unchecked") + public static void expectedFailureOfType(String message, Throwable e, Class<?> permittedSupertype, Class<?> ...permittedSupertypeExtras) { + @SuppressWarnings("rawtypes") + List<Class<?>> permittedSupertypes = MutableList.of(permittedSupertype).appendAll((List)Arrays.asList(permittedSupertypeExtras)); if (e instanceof ShouldHaveFailedPreviouslyAssertionError) throw (Error) e; - Throwable match = Exceptions.getFirstThrowableOfType(e, (Class<? extends Throwable>) permittedSupertype); - if (match != null) return; for (Class<?> clazz: permittedSupertypes) { - match = Exceptions.getFirstThrowableOfType(e, (Class<? extends Throwable>)clazz); - if (match != null) return; + if (Exceptions.getFirstThrowableOfType(e, (Class<? extends Throwable>)clazz) != null) { + return; + } } rethrowPreferredException(e, - new AssertionError("Error "+JavaClassNames.simpleClassName(e)+" is not any of the expected types: " + Arrays.asList(permittedSupertypes), e)); + new AssertionError((message!=null ? message+": " : "") + "Error "+JavaClassNames.simpleClassName(e)+" is not any of the expected types: " + permittedSupertypes, e)); } /** Tests {@link #expectedFailure(Throwable)} and that the <code>toString</code>