some tests and comments exploring location unmanagement as there is a slow leak around locations, no one unmanages them after use by an entity
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/3c97a577 Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/3c97a577 Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/3c97a577 Branch: refs/heads/master Commit: 3c97a5774e30be0e9e6b7dfa0fb0613b2cc419e3 Parents: 35142c8 Author: Alex Heneveld <[email protected]> Authored: Mon Feb 9 11:10:10 2015 +0000 Committer: Alex Heneveld <[email protected]> Committed: Mon Feb 9 11:10:10 2015 +0000 ---------------------------------------------------------------------- .../brooklyn/entity/basic/AbstractEntity.java | 4 +-- .../entity/rebind/RebindEntityTest.java | 27 +++++++++++++++++++- .../rebind/RebindLocalhostLocationTest.java | 22 ++++++++++++++++ .../entity/rebind/RebindTestFixture.java | 23 +++++++++++++---- 4 files changed, 68 insertions(+), 8 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3c97a577/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java index 215b13a..a004bc0 100644 --- a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java +++ b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java @@ -770,10 +770,10 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E public void removeLocations(Collection<? extends Location> removedLocations) { synchronized (locations) { List<Location> oldLocations = locations.get(); - Set<Location> truelyRemovedLocations = Sets.intersection(ImmutableSet.copyOf(removedLocations), ImmutableSet.copyOf(oldLocations)); + Set<Location> trulyRemovedLocations = Sets.intersection(ImmutableSet.copyOf(removedLocations), ImmutableSet.copyOf(oldLocations)); locations.set(MutableList.<Location>builder().addAll(oldLocations).removeAll(removedLocations).buildImmutable()); - for (Location loc : truelyRemovedLocations) { + for (Location loc : trulyRemovedLocations) { emit(AbstractEntity.LOCATION_REMOVED, loc); } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3c97a577/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java index ab55346..9b1e05d 100644 --- a/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java +++ b/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java @@ -62,9 +62,11 @@ import brooklyn.event.basic.BasicSensorEvent; import brooklyn.event.basic.DependentConfiguration; import brooklyn.event.basic.Sensors; import brooklyn.location.Location; +import brooklyn.location.LocationSpec; import brooklyn.location.basic.LocationConfigTest.MyLocation; import brooklyn.management.ha.ManagementNodeState; import brooklyn.management.internal.LocalManagementContext; +import brooklyn.mementos.BrooklynMementoManifest; import brooklyn.mementos.EntityMemento; import brooklyn.test.Asserts; import brooklyn.test.entity.TestApplication; @@ -181,7 +183,30 @@ public class RebindEntityTest extends RebindTestFixtureWithApp { MyEntity newE = (MyEntity) Iterables.find(newApp.getChildren(), Predicates.instanceOf(MyEntity.class)); assertEquals(newE.getAttribute(myCustomAttribute), "myval"); } - + + @Test + public void testRestoresEntityLocationAndCleansUp() throws Exception { + MyLocation loc = origManagementContext.getLocationManager().createLocation(LocationSpec.create(MyLocation.class)); + origApp.createAndManageChild(EntitySpec.create(MyEntity.class).location(loc)); + + newApp = rebind(); + MyEntity newE = (MyEntity) Iterables.find(newApp.getChildren(), Predicates.instanceOf(MyEntity.class)); + + Assert.assertEquals(newE.getLocations().size(), 1); + Location loc2 = Iterables.getOnlyElement(newE.getLocations()); + Assert.assertEquals(loc, loc2); + Assert.assertFalse(loc==loc2); + + newApp.stop(); + // TODO how to trigger automatic unmanagement? see notes in RebindLocalhostLocationTest + newManagementContext.getLocationManager().unmanage(loc2); + switchOriginalToNewManagementContext(); + RebindTestUtils.waitForPersisted(origManagementContext); + + BrooklynMementoManifest mf = loadMementoManifest(); + Assert.assertTrue(mf.getLocationIdToType().isEmpty(), "Expected no locations; had "+mf.getLocationIdToType()); + } + @Test public void testRestoresEntityIdAndDisplayName() throws Exception { MyEntity origE = origApp.createAndManageChild(EntitySpec.create(MyEntity.class) http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3c97a577/core/src/test/java/brooklyn/entity/rebind/RebindLocalhostLocationTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindLocalhostLocationTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindLocalhostLocationTest.java index 16fc7fc..00e88d7 100644 --- a/core/src/test/java/brooklyn/entity/rebind/RebindLocalhostLocationTest.java +++ b/core/src/test/java/brooklyn/entity/rebind/RebindLocalhostLocationTest.java @@ -24,12 +24,14 @@ import java.util.Collections; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import brooklyn.location.LocationSpec; import brooklyn.location.basic.LocalhostMachineProvisioningLocation; import brooklyn.location.basic.SshMachineLocation; +import brooklyn.mementos.BrooklynMementoManifest; import brooklyn.test.entity.TestApplication; import com.google.common.collect.ImmutableList; @@ -79,5 +81,25 @@ public class RebindLocalhostLocationTest extends RebindTestFixtureWithApp { SshMachineLocation newChildLoc = (SshMachineLocation) Iterables.get(newLoc.getChildren(), 0); assertEquals(newChildLoc.execScript(Collections.<String,Object>emptyMap(), "mysummary", ImmutableList.of("true")), 0); } + + @Test(groups="Integration") + public void testMachineCleansUp() throws Exception { + testMachineUsableAfterRebind(); + newApp.stop(); + + switchOriginalToNewManagementContext(); + + // TODO how should we automatically unmanage these? + // (in this test, locations are created manually, so probably should be destroyed manually, + // but in most cases we should probably unmanage the location as part of the entity; + // could keep the entity ID only in the location, then safely reverse-check usages?) + // see related non-integration test in RebindEntityTest + origManagementContext.getLocationManager().unmanage(origLoc); + + RebindTestUtils.waitForPersisted(origManagementContext); + + BrooklynMementoManifest mf = loadMementoManifest(); + Assert.assertTrue(mf.getLocationIdToType().isEmpty(), "Expected no locations; had "+mf.getLocationIdToType()); + } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3c97a577/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java b/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java index 39004f6..8f1c1c6 100644 --- a/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java +++ b/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java @@ -107,7 +107,7 @@ public abstract class RebindTestFixture<T extends StartableApplication> { protected void switchOriginalToNewManagementContext() { origManagementContext.getRebindManager().stopPersistence(); for (Application e: origManagementContext.getApplications()) ((Startable)e).stop(); - waitForTaskCountToBecome(origManagementContext, 0); + waitForTaskCountToBecome(origManagementContext, 0, true); origManagementContext.terminate(); origManagementContext = (LocalManagementContext) newManagementContext; origApp = newApp; @@ -116,19 +116,32 @@ public abstract class RebindTestFixture<T extends StartableApplication> { } public static void waitForTaskCountToBecome(final ManagementContext mgmt, final int allowedMax) { + waitForTaskCountToBecome(mgmt, allowedMax, false); + } + + public static void waitForTaskCountToBecome(final ManagementContext mgmt, final int allowedMax, final boolean skipKnownBackgroundTasks) { Repeater.create().every(Duration.millis(20)).limitTimeTo(Duration.TEN_SECONDS).until(new Callable<Boolean>() { @Override public Boolean call() throws Exception { ((LocalManagementContext)mgmt).getGarbageCollector().gcIteration(); long taskCountAfterAtOld = ((BasicExecutionManager)mgmt.getExecutionManager()).getNumIncompleteTasks(); List<Task<?>> tasks = ((BasicExecutionManager)mgmt.getExecutionManager()).getAllTasks(); - int unendedTasks = 0; + int unendedTasks = 0, extraAllowedMax = 0; for (Task<?> t: tasks) { - if (!t.isDone()) unendedTasks++; + if (!t.isDone()) { + if (skipKnownBackgroundTasks) { + if (t.toString().indexOf("ssh-location cache cleaner")>=0) { + extraAllowedMax++; + } + } + unendedTasks++; + } } - LOG.info("Count of incomplete tasks now "+taskCountAfterAtOld+", "+unendedTasks+" unended; tasks remembered are: "+ + LOG.info("Count of incomplete tasks now "+taskCountAfterAtOld+", "+unendedTasks+" unended" + + (extraAllowedMax>0 ? " ("+extraAllowedMax+" allowed)" : "") + + "; tasks remembered are: "+ tasks); - return taskCountAfterAtOld<=allowedMax; + return taskCountAfterAtOld<=allowedMax+extraAllowedMax; } }).runRequiringTrue(); }
