Repository: brooklyn-server Updated Branches: refs/heads/master ff7cde116 -> ee367e24d
Adds TestCase.continueOnFailure Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/c1422ed1 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/c1422ed1 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/c1422ed1 Branch: refs/heads/master Commit: c1422ed13136b02490f68c97dfa0d7863f8de598 Parents: b608635 Author: Aled Sage <[email protected]> Authored: Thu Apr 6 12:34:43 2017 +0100 Committer: Aled Sage <[email protected]> Committed: Thu Apr 6 12:34:43 2017 +0100 ---------------------------------------------------------------------- .../brooklyn/test/framework/TestCase.java | 8 ++ .../brooklyn/test/framework/TestCaseImpl.java | 47 ++++++++-- .../brooklyn/test/framework/TestCaseTest.java | 92 ++++++++++++++++++-- 3 files changed, 133 insertions(+), 14 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/c1422ed1/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java ---------------------------------------------------------------------- diff --git a/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java index 7095f00..cd53993 100644 --- a/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java +++ b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCase.java @@ -38,4 +38,12 @@ public interface TestCase extends TargetableTestComponent { .description("Spec of entity to instantiate (and start, if startable) if the test-case fails") .runtimeInheritance(BasicConfigInheritance.NOT_REINHERITED) .build(); + + ConfigKey<Boolean> CONTINUE_ON_FAILURE = ConfigKeys.builder(Boolean.class) + .name("continueOnFailure") + .description("Whether to continue executing subsequent children if an earlier child fails") + .runtimeInheritance(BasicConfigInheritance.NOT_REINHERITED) + .defaultValue(false) + .build(); + } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/c1422ed1/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCaseImpl.java ---------------------------------------------------------------------- diff --git a/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCaseImpl.java b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCaseImpl.java index 849d018..2b7351a 100644 --- a/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCaseImpl.java +++ b/test-framework/src/main/java/org/apache/brooklyn/test/framework/TestCaseImpl.java @@ -19,6 +19,7 @@ package org.apache.brooklyn.test.framework; import java.util.Collection; +import java.util.List; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.entity.EntitySpec; @@ -47,14 +48,32 @@ public class TestCaseImpl extends TargetableTestComponentImpl implements TestCas public void start(Collection<? extends Location> locations) { ServiceStateLogic.setExpectedState(this, Lifecycle.STARTING); try { - for (final Entity childEntity : getChildren()) { - Boolean serviceUp = childEntity.sensors().get(Attributes.SERVICE_UP); - if (childEntity instanceof Startable && !Boolean.TRUE.equals(serviceUp)){ - ((Startable) childEntity).start(locations); + boolean continueOnFailure = Boolean.TRUE.equals(config().get(CONTINUE_ON_FAILURE)); + List<Throwable> childErrors = Lists.newArrayList(); + for (Entity child : getChildren()) { + Boolean serviceUp = child.sensors().get(Attributes.SERVICE_UP); + if (child instanceof Startable && !Boolean.TRUE.equals(serviceUp)){ + try { + ((Startable) child).start(locations); + } catch (Throwable t) { + Exceptions.propagateIfFatal(t); + if (continueOnFailure) { + LOG.warn("Problem starting child "+child+" (continuing, and will throw at end)", t); + childErrors.add(t); + } else { + throw t; + } + } } } + + if (childErrors.size() > 0) { + throw Exceptions.propagate(childErrors); + } + sensors().set(Attributes.SERVICE_UP, true); ServiceStateLogic.setExpectedState(this, Lifecycle.RUNNING); + } catch (Throwable t) { Exceptions.propagateIfInterrupt(t); try { @@ -77,10 +96,28 @@ public class TestCaseImpl extends TargetableTestComponentImpl implements TestCas ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPING); sensors().set(Attributes.SERVICE_UP, false); try { + boolean continueOnFailure = Boolean.TRUE.equals(config().get(CONTINUE_ON_FAILURE)); + List<Throwable> childErrors = Lists.newArrayList(); for (Entity child : getChildren()) { - if (child instanceof Startable) ((Startable) child).stop(); + try { + if (child instanceof Startable) ((Startable) child).stop(); + } catch (Throwable t) { + Exceptions.propagateIfFatal(t); + if (continueOnFailure) { + LOG.warn("Problem stopping child "+child+" (continuing, and will throw at end)", t); + childErrors.add(t); + } else { + throw t; + } + } } + + if (childErrors.size() > 0) { + throw Exceptions.propagate(childErrors); + } + ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPED); + } catch (Exception e) { ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE); throw Exceptions.propagate(e); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/c1422ed1/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestCaseTest.java ---------------------------------------------------------------------- diff --git a/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestCaseTest.java b/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestCaseTest.java index d211076..d599f9f 100644 --- a/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestCaseTest.java +++ b/test-framework/src/test/java/org/apache/brooklyn/test/framework/TestCaseTest.java @@ -29,6 +29,7 @@ import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.entity.EntitySpec; import org.apache.brooklyn.api.location.Location; import org.apache.brooklyn.core.entity.Attributes; +import org.apache.brooklyn.core.entity.Entities; import org.apache.brooklyn.core.entity.EntityAsserts; import org.apache.brooklyn.core.entity.EntityPredicates; import org.apache.brooklyn.core.entity.lifecycle.Lifecycle; @@ -38,6 +39,7 @@ import org.apache.brooklyn.core.test.entity.TestEntity; import org.apache.brooklyn.core.test.entity.TestEntityImpl; import org.apache.brooklyn.test.Asserts; import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import com.google.common.base.Optional; @@ -54,17 +56,28 @@ public class TestCaseTest extends BrooklynAppUnitTestSupport { super.setUp(); } - @Test - public void testSucceedsWhenEmpty() throws Exception { - TestCase testCase = app.createAndManageChild(EntitySpec.create(TestCase.class)); + @DataProvider(name = "continueOnFailurePermutations") + public Object[][] continueOnFailurePermutations() { + return new Object[][] { + { (Boolean)null }, + { Boolean.FALSE }, + { Boolean.TRUE } + }; + } + + @Test(dataProvider = "continueOnFailurePermutations") + public void testSucceedsWhenEmpty(Boolean continueOnFailure) throws Exception { + TestCase testCase = app.createAndManageChild(EntitySpec.create(TestCase.class) + .configure(TestCase.CONTINUE_ON_FAILURE, continueOnFailure)); app.start(locs); assertTestCaseSucceeds(testCase); } - @Test - public void testCallsChildrenSequentially() throws Exception { + @Test(dataProvider = "continueOnFailurePermutations") + public void testCallsChildrenSequentially(Boolean continueOnFailure) throws Exception { TestCase testCase = app.createAndManageChild(EntitySpec.create(TestCase.class) + .configure(TestCase.CONTINUE_ON_FAILURE, continueOnFailure) .child(EntitySpec.create(TestEntity.class).impl(TestEntityConcurrencyTrackerImpl.class)) .child(EntitySpec.create(TestEntity.class).impl(TestEntityConcurrencyTrackerImpl.class))); TestEntity child1 = (TestEntity) Iterables.get(testCase.getChildren(), 0); @@ -77,9 +90,10 @@ public class TestCaseTest extends BrooklynAppUnitTestSupport { assertEquals(TestEntityConcurrencyTrackerImpl.getMaxConcurrent(), 1); } - @Test - public void testDoesNotCallsOnErrorEntityIfSuccessful() throws Exception { + @Test(dataProvider = "continueOnFailurePermutations") + public void testDoesNotCallOnErrorEntityIfSuccessful(Boolean continueOnFailure) throws Exception { TestCase testCase = app.createAndManageChild(EntitySpec.create(TestCase.class) + .configure(TestCase.CONTINUE_ON_FAILURE, continueOnFailure) .configure(TestCase.ON_ERROR_SPEC, EntitySpec.create(TestEntity.class).displayName("onerr")) .child(EntitySpec.create(TestEntity.class))); app.start(locs); @@ -90,9 +104,10 @@ public class TestCaseTest extends BrooklynAppUnitTestSupport { assertTestCaseSucceeds(testCase); } - @Test - public void testCallsOnErrorEntity() throws Exception { + @Test(dataProvider = "continueOnFailurePermutations") + public void testCallsOnErrorEntity(Boolean continueOnFailure) throws Exception { TestCase testCase = app.createAndManageChild(EntitySpec.create(TestCase.class) + .configure(TestCase.CONTINUE_ON_FAILURE, continueOnFailure) .configure(TestCase.ON_ERROR_SPEC, EntitySpec.create(TestEntity.class).displayName("onerr")) .child(EntitySpec.create(FailingEntity.class) .configure(FailingEntity.FAIL_ON_START, true))); @@ -130,6 +145,65 @@ public class TestCaseTest extends BrooklynAppUnitTestSupport { Optional<Entity> innerOnErrEntity = Iterables.tryFind(innerTestCase.getChildren(), EntityPredicates.displayNameEqualTo("onerr")); assertFalse(innerOnErrEntity.isPresent(), "innerOnErrEntity="+innerOnErrEntity); } + + @Test + public void testAbortsOnFailure() throws Exception { + // continueOnFailure defaults to false + TestCase testCase = app.createAndManageChild(EntitySpec.create(TestCase.class) + .child(EntitySpec.create(FailingEntity.class) + .configure(FailingEntity.FAIL_ON_START, true)) + .child(EntitySpec.create(TestEntity.class).displayName("child2"))); + + try { + app.start(locs); + Asserts.shouldHaveFailedPreviously(); + } catch (Throwable t) { + Asserts.expectedFailureContains(t, "Simulating entity start failure for test"); + } + + TestEntity child2 = (TestEntity) Iterables.tryFind(testCase.getChildren(), EntityPredicates.displayNameEqualTo("child2")).get(); + assertEquals(child2.getCallHistory(), ImmutableList.of()); + } + + + @Test + public void testContinuesOnFailure() throws Exception { + TestCase testCase = app.createAndManageChild(EntitySpec.create(TestCase.class) + .configure(TestCase.CONTINUE_ON_FAILURE, true) + .child(EntitySpec.create(FailingEntity.class) + .configure(FailingEntity.FAIL_ON_START, true)) + .child(EntitySpec.create(TestEntity.class).displayName("child2"))); + + try { + app.start(locs); + Asserts.shouldHaveFailedPreviously(); + } catch (Throwable t) { + Asserts.expectedFailureContains(t, "Simulating entity start failure for test"); + } + + TestEntity child2 = (TestEntity) Iterables.tryFind(testCase.getChildren(), EntityPredicates.displayNameEqualTo("child2")).get(); + assertEquals(child2.getCallHistory(), ImmutableList.of("start")); + } + + @Test + public void testContinueOnFailureNotInherited() throws Exception { + app.createAndManageChild(EntitySpec.create(TestCase.class) + .configure(TestCase.CONTINUE_ON_FAILURE, true) + .child(EntitySpec.create(TestCase.class) + .child(EntitySpec.create(FailingEntity.class) + .configure(FailingEntity.FAIL_ON_START, true)) + .child(EntitySpec.create(TestEntity.class).displayName("grandchild2")))); + + try { + app.start(locs); + Asserts.shouldHaveFailedPreviously(); + } catch (Throwable t) { + Asserts.expectedFailureContains(t, "Simulating entity start failure for test"); + } + + TestEntity grandchild2 = (TestEntity) Iterables.tryFind(Entities.descendantsAndSelf(app), EntityPredicates.displayNameEqualTo("grandchild2")).get(); + assertEquals(grandchild2.getCallHistory(), ImmutableList.of()); + } protected void assertTestCaseSucceeds(TestCase entity) { EntityAsserts.assertAttributeEqualsEventually(entity, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.RUNNING);
