You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by al...@apache.org on 2016/11/08 21:01:37 UTC

[1/3] brooklyn-server git commit: DynamicFabric.includeInitialChildren: address review comments

Repository: brooklyn-server
Updated Branches:
  refs/heads/master 63cb4c54b -> fd0097803


DynamicFabric.includeInitialChildren: address review comments


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/7c2379b2
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/7c2379b2
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/7c2379b2

Branch: refs/heads/master
Commit: 7c2379b246a1e93579008f67a68bde9c9d2b2549
Parents: a757cdf
Author: Aled Sage <al...@gmail.com>
Authored: Tue Nov 8 10:09:42 2016 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Tue Nov 8 11:26:35 2016 +0000

----------------------------------------------------------------------
 .../entity/group/DynamicFabricImpl.java         | 107 ++++++++++---------
 1 file changed, 56 insertions(+), 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/7c2379b2/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java
index a02d797..f95c38d 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java
@@ -113,65 +113,19 @@ public class DynamicFabricImpl extends AbstractGroupImpl implements DynamicFabri
         boolean includeInitialChildren = Boolean.TRUE.equals(config().get(INCLUDE_INITIAL_CHILDREN));
         
         addLocations(locsO);
-        List<Location> locationsToStart = MutableList.copyOf(Locations.getLocationsCheckingAncestors(locsO, this));
+        Collection<? extends Location> allLocations = Locations.getLocationsCheckingAncestors(locsO, this);
         
-        Preconditions.checkNotNull(locationsToStart, "locations must be supplied");
-        Preconditions.checkArgument(locationsToStart.size() >= 1, "One or more locations must be supplied");
-        
-        int locIndex = 0;
+        Preconditions.checkNotNull(allLocations, "locations must be supplied");
+        Preconditions.checkArgument(allLocations.size() >= 1, "One or more locations must be supplied");
         
         ServiceStateLogic.setExpectedState(this, Lifecycle.STARTING);
         try {
             Map<Entity, Task<?>> tasks = Maps.newLinkedHashMap();
-            
-            if (includeInitialChildren) {
-                // first look at existing Startable children - start them with the locations passed in here,
-                // if they have no locations yet
-                for (Entity child: getChildren()) {
-                    if (child instanceof Startable) {
-                        addMember(child);
-                        Location it = null;
-                        if (child.getLocations().isEmpty()) {
-                            // give him any of these locations if he has none, allowing round robin here
-                            if (!locationsToStart.isEmpty()) {
-                                it = locationsToStart.get(locIndex++ % locationsToStart.size());
-                                ((EntityInternal)child).addLocations(Arrays.asList(it));
-                            }
-                        }
-                        
-                        tasks.put(child, Entities.submit(this,
-                            Effectors.invocation(child, START, ImmutableMap.of("locations", 
-                                it==null ? ImmutableList.of() : ImmutableList.of(it))).asTask()));
-                    }
-                }
-                // remove all the locations we applied to existing nodes
-                while (locIndex-->0 && !locationsToStart.isEmpty())
-                    locationsToStart.remove(0);
-                
-            } else {
-                // Start the existing children, but don't count that as "consuming" the initial
-                // locations.
-                for (Entity child : getChildren()) {
-                    if (child instanceof Startable) {
-                        Location it = null;
-                        if (child.getLocations().isEmpty()) {
-                            // give him the first location
-                            if (!locationsToStart.isEmpty()) {
-                                it = locationsToStart.get(0);
-                                ((EntityInternal)child).addLocations(Arrays.asList(it));
-                            }
-                        }
-                        
-                        tasks.put(child, Entities.submit(this,
-                            Effectors.invocation(child, START, ImmutableMap.of("locations", 
-                                it==null ? ImmutableList.of() : ImmutableList.of(it))).asTask()));
-                    }
-                }
-            }
+            List<Location> locationsForMembers = startChildren(includeInitialChildren, allLocations, tasks);
 
             // finally (and usually) we create new entities for locations passed in
             // (unless they were consumed by pre-existing children which didn't have locations)
-            for (Location it : locationsToStart) {
+            for (Location it : locationsForMembers) {
                 Entity e = addCluster(it);
                 
                 ((EntityInternal)e).addLocations(Arrays.asList(it));
@@ -191,6 +145,57 @@ public class DynamicFabricImpl extends AbstractGroupImpl implements DynamicFabri
         }
     }
 
+    /**
+     * If including initial children, first look at existing Startable children - start them with 
+     * the locations passed in here (if they have no locations yet). This "consumes" a location
+     * so we won't create an additional member in that location.
+     * 
+     * If not {@code includeInitialChildren}, then start those children in the first location but
+     * don't "consume" a location - so we'll create additional members.
+     * 
+     * @param includeInitialChildren
+     * @param allLocations
+     * @param tasks side-effects this map, to add the tasks created for starting the child entities
+     * 
+     * @return unused locations
+     */
+    protected List<Location> startChildren(boolean includeInitialChildren, Collection<? extends Location> allLocations, Map<Entity, Task<?>> tasks) {
+        List<Location> locations = MutableList.copyOf(allLocations);
+        int locIndex = 0;
+        
+        for (Entity child: getChildren()) {
+            if (child instanceof Startable) {
+                if (includeInitialChildren) {
+                    addMember(child);
+                }
+                
+                Location it = null;
+                if (child.getLocations().isEmpty()) {
+                    // give him any of these locations if he has none, allowing round robin here
+                    if (!locations.isEmpty()) {
+                        if (includeInitialChildren) {
+                            it = locations.get(locIndex++ % locations.size());
+                        } else {
+                            it = locations.get(0);
+                        }
+                        ((EntityInternal)child).addLocations(Arrays.asList(it));
+                    }
+                }
+                
+                tasks.put(child, Entities.submit(this,
+                    Effectors.invocation(child, START, ImmutableMap.of("locations", 
+                        it==null ? ImmutableList.of() : ImmutableList.of(it))).asTask()));
+            }
+        }
+            
+        // remove all the locations we applied to existing nodes
+        while (locIndex-->0 && !locations.isEmpty()) {
+            locations.remove(0);
+        }
+        
+        return locations;
+    }
+    
     protected void waitForTasksOnStart(Map<Entity, Task<?>> tasks) {
         // TODO Could do best-effort for waiting for remaining tasks, rather than failing on first?
 


[2/3] brooklyn-server git commit: BROOKLYN-380: Adds DynamicFabric.includeInitialChildren config

Posted by al...@apache.org.
BROOKLYN-380: Adds DynamicFabric.includeInitialChildren config

And adds tests for existing behaviour.


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/a757cdfe
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/a757cdfe
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/a757cdfe

Branch: refs/heads/master
Commit: a757cdfe4564ab41293edd0a52fb60be7ac4886a
Parents: e56de02
Author: Aled Sage <al...@gmail.com>
Authored: Fri Nov 4 12:50:53 2016 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Tue Nov 8 11:26:35 2016 +0000

----------------------------------------------------------------------
 .../brooklyn/entity/group/DynamicFabric.java    |  23 ++--
 .../entity/group/DynamicFabricImpl.java         |  61 ++++++---
 .../entity/group/DynamicRegionsFabricTest.java  | 123 +++++++++++++++++--
 3 files changed, 174 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a757cdfe/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabric.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabric.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabric.java
index 943ed9b..92b9621 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabric.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabric.java
@@ -42,29 +42,38 @@ import com.google.common.reflect.TypeToken;
 @SuppressWarnings("serial")
 public interface DynamicFabric extends AbstractGroup, Startable, Fabric {
 
-    public static final AttributeSensor<Integer> FABRIC_SIZE = Sensors.newIntegerSensor("fabric.size", "Fabric size");
+    ConfigKey<Boolean> INCLUDE_INITIAL_CHILDREN = ConfigKeys.newBooleanConfigKey(
+            "includeInitialChildren",
+            "Whether to include the initial children when handing out the locations to new members "
+                    + "(i.e. if true, these children will each be given a location (round-robin), "
+                    + "rather than creating new members; if false then the children will be given "
+                    + "just the first location (if any), and new members will be created dynamically "
+                    + "for each given location).",
+            true);
     
     @SetFromFlag("memberSpec")
-    public static final ConfigKey<EntitySpec<?>> MEMBER_SPEC = ConfigKeys.newConfigKey(
+    ConfigKey<EntitySpec<?>> MEMBER_SPEC = ConfigKeys.newConfigKey(
             new TypeToken<EntitySpec<?>>() {}, "dynamiccfabric.memberspec", "entity spec for creating new cluster members", null);
 
     @SetFromFlag("factory")
-    public static final ConfigKey<EntityFactory<?>> FACTORY = ConfigKeys.newConfigKey(
+    ConfigKey<EntityFactory<?>> FACTORY = ConfigKeys.newConfigKey(
         new TypeToken<EntityFactory<?>>() {}, "dynamicfabric.factory", "factory for creating new cluster members", null);
 
     @SetFromFlag("displayNamePrefix")
-    public static final ConfigKey<String> DISPLAY_NAME_PREFIX = ConfigKeys.newStringConfigKey(
+    ConfigKey<String> DISPLAY_NAME_PREFIX = ConfigKeys.newStringConfigKey(
             "dynamicfabric.displayNamePrefix", "Display name prefix, for created children");
 
     @SetFromFlag("displayNameSuffix")
-    public static final ConfigKey<String> DISPLAY_NAME_SUFFIX = ConfigKeys.newStringConfigKey(
+    ConfigKey<String> DISPLAY_NAME_SUFFIX = ConfigKeys.newStringConfigKey(
             "dynamicfabric.displayNameSuffix", "Display name suffix, for created children");
 
     @SetFromFlag("customChildFlags")
-    public static final MapConfigKey<Object> CUSTOM_CHILD_FLAGS = new MapConfigKey<Object>(
+    MapConfigKey<Object> CUSTOM_CHILD_FLAGS = new MapConfigKey<Object>(
             Object.class, "dynamicfabric.customChildFlags", "Additional flags to be passed to children when they are being created", ImmutableMap.<String,Object>of());
 
-    public static final AttributeSensor<Lifecycle> SERVICE_STATE_ACTUAL = Attributes.SERVICE_STATE_ACTUAL;
+    AttributeSensor<Integer> FABRIC_SIZE = Sensors.newIntegerSensor("fabric.size", "Fabric size");
+    
+    AttributeSensor<Lifecycle> SERVICE_STATE_ACTUAL = Attributes.SERVICE_STATE_ACTUAL;
 
     public void setMemberSpec(EntitySpec<?> memberSpec);
     

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a757cdfe/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java
index 34051c5..a02d797 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicFabricImpl.java
@@ -110,6 +110,8 @@ public class DynamicFabricImpl extends AbstractGroupImpl implements DynamicFabri
     
     @Override
     public void start(Collection<? extends Location> locsO) {
+        boolean includeInitialChildren = Boolean.TRUE.equals(config().get(INCLUDE_INITIAL_CHILDREN));
+        
         addLocations(locsO);
         List<Location> locationsToStart = MutableList.copyOf(Locations.getLocationsCheckingAncestors(locsO, this));
         
@@ -122,27 +124,50 @@ public class DynamicFabricImpl extends AbstractGroupImpl implements DynamicFabri
         try {
             Map<Entity, Task<?>> tasks = Maps.newLinkedHashMap();
             
-            // first look at existing Startable children - start them with the locations passed in here,
-            // if they have no locations yet
-            for (Entity child: getChildren()) {
-                if (child instanceof Startable) {
-                    addMember(child);
-                    Location it = null;
-                    if (child.getLocations().isEmpty())
-                        // give him any of these locations if he has none, allowing round robin here
-                        if (!locationsToStart.isEmpty()) {
-                            it = locationsToStart.get(locIndex++ % locationsToStart.size());
-                            ((EntityInternal)child).addLocations(Arrays.asList(it));
+            if (includeInitialChildren) {
+                // first look at existing Startable children - start them with the locations passed in here,
+                // if they have no locations yet
+                for (Entity child: getChildren()) {
+                    if (child instanceof Startable) {
+                        addMember(child);
+                        Location it = null;
+                        if (child.getLocations().isEmpty()) {
+                            // give him any of these locations if he has none, allowing round robin here
+                            if (!locationsToStart.isEmpty()) {
+                                it = locationsToStart.get(locIndex++ % locationsToStart.size());
+                                ((EntityInternal)child).addLocations(Arrays.asList(it));
+                            }
+                        }
+                        
+                        tasks.put(child, Entities.submit(this,
+                            Effectors.invocation(child, START, ImmutableMap.of("locations", 
+                                it==null ? ImmutableList.of() : ImmutableList.of(it))).asTask()));
+                    }
+                }
+                // remove all the locations we applied to existing nodes
+                while (locIndex-->0 && !locationsToStart.isEmpty())
+                    locationsToStart.remove(0);
+                
+            } else {
+                // Start the existing children, but don't count that as "consuming" the initial
+                // locations.
+                for (Entity child : getChildren()) {
+                    if (child instanceof Startable) {
+                        Location it = null;
+                        if (child.getLocations().isEmpty()) {
+                            // give him the first location
+                            if (!locationsToStart.isEmpty()) {
+                                it = locationsToStart.get(0);
+                                ((EntityInternal)child).addLocations(Arrays.asList(it));
+                            }
                         }
-                    
-                    tasks.put(child, Entities.submit(this,
-                        Effectors.invocation(child, START, ImmutableMap.of("locations", 
-                            it==null ? ImmutableList.of() : ImmutableList.of(it))).asTask()));
+                        
+                        tasks.put(child, Entities.submit(this,
+                            Effectors.invocation(child, START, ImmutableMap.of("locations", 
+                                it==null ? ImmutableList.of() : ImmutableList.of(it))).asTask()));
+                    }
                 }
             }
-            // remove all the locations we applied to existing nodes
-            while (locIndex-->0 && !locationsToStart.isEmpty())
-                locationsToStart.remove(0);
 
             // finally (and usually) we create new entities for locations passed in
             // (unless they were consumed by pre-existing children which didn't have locations)

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/a757cdfe/core/src/test/java/org/apache/brooklyn/entity/group/DynamicRegionsFabricTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/entity/group/DynamicRegionsFabricTest.java b/core/src/test/java/org/apache/brooklyn/entity/group/DynamicRegionsFabricTest.java
index c54bb3a..5227c8d 100644
--- a/core/src/test/java/org/apache/brooklyn/entity/group/DynamicRegionsFabricTest.java
+++ b/core/src/test/java/org/apache/brooklyn/entity/group/DynamicRegionsFabricTest.java
@@ -19,6 +19,8 @@
 package org.apache.brooklyn.entity.group;
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
 
 import java.util.Collection;
 import java.util.List;
@@ -27,10 +29,12 @@ import java.util.Set;
 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.BrooklynConfigKeys;
 import org.apache.brooklyn.core.location.SimulatedLocation;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntity;
-import org.apache.brooklyn.entity.group.DynamicRegionsFabric;
+import org.apache.brooklyn.entity.stock.BasicEntity;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.testng.annotations.BeforeMethod;
@@ -60,16 +64,98 @@ public class DynamicRegionsFabricTest extends BrooklynAppUnitTestSupport {
     }
 
     @Test
-    public void testUsesInitialLocations() throws Exception {
+    public void testUsesInitialLocationsFromStartEffectorArgs() throws Exception {
         app.start(ImmutableList.of(loc1, loc2));
 
-        assertEquals(fabric.getChildren().size(), 2, "children="+fabric.getChildren());
-        assertEquals(fabric.getMembers().size(), 2, "members="+fabric.getMembers());
-        assertEqualsIgnoringOrder(fabric.getChildren(), fabric.getMembers());
-        assertEqualsIgnoringOrder(getLocationsOfChildren(fabric), ImmutableList.of(loc1, loc2));
+        assertFabricChildren(fabric, 2, ImmutableList.of(loc1, loc2));
+    }
+    
+    @Test
+    @SuppressWarnings("deprecation")
+    public void testUsesInitialLocationsFromAppSpec() throws Exception {
+        TestApplication app2 = mgmt.getEntityManager().createEntity(EntitySpec.create(TestApplication.class)
+            .configure(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, true)
+            .child(EntitySpec.create(DynamicRegionsFabric.class)
+                .configure("memberSpec", EntitySpec.create(TestEntity.class)))
+            .locations(ImmutableList.of(loc1, loc2)));
+        DynamicRegionsFabric fabric2 = (DynamicRegionsFabric) Iterables.getOnlyElement(app2.getChildren());
+        app2.start(ImmutableList.<Location>of());
+        
+        assertFabricChildren(fabric2, 2, ImmutableList.of(loc1, loc2));
     }
     
     @Test
+    @SuppressWarnings("deprecation")
+    public void testUsesInitialLocationsFromEntitySpec() throws Exception {
+        TestApplication app2 = mgmt.getEntityManager().createEntity(EntitySpec.create(TestApplication.class)
+            .configure(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, true)
+            .child(EntitySpec.create(DynamicRegionsFabric.class)
+                .configure("memberSpec", EntitySpec.create(TestEntity.class))
+                .locations(ImmutableList.of(loc1, loc2))));
+        DynamicRegionsFabric fabric2 = (DynamicRegionsFabric) Iterables.getOnlyElement(app2.getChildren());
+        app2.start(ImmutableList.<Location>of());
+        
+        assertFabricChildren(fabric2, 2, ImmutableList.of(loc1, loc2));
+    }
+    
+    @Test
+    public void testUsesInitialLocationsForExistingChildCreatingExtras() throws Exception {
+        // Expect existing child to be used for one location, and a second child to be created 
+        // automatically for the second location
+        runUsesInitialLocationsForExistingChildren(1);
+    }
+
+    @Test
+    public void testUsesInitialLocationsForExistingChildren() throws Exception {
+        // Expect the two existing children to be used for the two locations; no additional
+        // children should be created automatically.
+        runUsesInitialLocationsForExistingChildren(2);
+    }
+
+    @Test
+    public void testUsesInitialLocationsRoundRobinForExistingChildren() throws Exception {
+        // Expect the two locations to be used round-robin for the three existing children;
+        // no additional children should be created automatically.
+        runUsesInitialLocationsForExistingChildren(3);
+    }
+
+    @Test
+    public void testIgnoredNonStartableChildren() throws Exception {
+        // Add a basic entity; this will not count as a "member" because it is not startable.
+        // Therefore expect two new children to be created.
+        BasicEntity existingChild = fabric.addChild(EntitySpec.create(BasicEntity.class));
+        app.start(ImmutableList.of(loc1, loc2));
+        assertFabricMembers(fabric, 2, ImmutableList.of(loc1, loc2));
+        assertFalse(fabric.getMembers().contains(existingChild));
+    }
+
+    @Test
+    public void testTurnOffIncludeInitialChildren() throws Exception {
+        // Turning off "include initial children" means they will be ignored in the member-count.
+        fabric.config().set(DynamicFabric.INCLUDE_INITIAL_CHILDREN, false);
+        TestEntity existingChild = fabric.addChild(EntitySpec.create(TestEntity.class));
+        app.start(ImmutableList.of(loc1, loc2));
+        assertFabricMembers(fabric, 2, ImmutableList.of(loc1, loc2));
+        
+        assertFalse(fabric.getMembers().contains(existingChild));
+        assertEqualsIgnoringOrder(existingChild.getLocations(), ImmutableList.of(loc1));
+    }
+
+    protected void runUsesInitialLocationsForExistingChildren(int numChildren) throws Exception {
+        List<TestEntity> existingChildren = Lists.newArrayList();
+        for (int i = 0; i < numChildren; i++) {
+            existingChildren.add(fabric.addChild(EntitySpec.create(TestEntity.class)));
+        }
+        app.start(ImmutableList.of(loc1, loc2));
+
+        int expectedNumChildren = Math.max(numChildren, 2);
+        Iterable<Location> expectedChildLocations = Iterables.limit(Iterables.cycle(ImmutableList.of(loc1, loc2)), expectedNumChildren);
+        
+        assertFabricChildren(fabric, expectedNumChildren, ImmutableList.copyOf(expectedChildLocations));
+        assertTrue(fabric.getChildren().containsAll(existingChildren));
+    }
+
+    @Test
     public void testDynamicallyAddLocations() throws Exception {
         app.start(ImmutableList.of(loc1));
         Set<Entity> initialChildren = ImmutableSet.copyOf(fabric.getChildren());
@@ -156,9 +242,17 @@ public class DynamicRegionsFabricTest extends BrooklynAppUnitTestSupport {
     }
     
     private List<Location> getLocationsOfChildren(DynamicRegionsFabric fabric) {
+        return getLocationsOf(fabric.getChildren());
+    }
+
+    private List<Location> getLocationsOfMembers(DynamicRegionsFabric fabric) {
+        return getLocationsOf(fabric.getMembers());
+    }
+
+    private List<Location> getLocationsOf(Iterable<? extends Entity> entities) {
         List<Location> result = Lists.newArrayList();
-        for (Entity child : fabric.getChildren()) {
-            result.addAll(child.getLocations());
+        for (Entity entity : entities) {
+            result.addAll(entity.getLocations());
         }
         return result;
     }
@@ -167,4 +261,17 @@ public class DynamicRegionsFabricTest extends BrooklynAppUnitTestSupport {
         assertEquals(Iterables.size(col1), Iterables.size(col2), "col2="+col1+"; col2="+col2);
         assertEquals(MutableSet.copyOf(col1), MutableSet.copyOf(col2), "col1="+col1+"; col2="+col2);
     }
+    
+    private void assertFabricChildren(DynamicRegionsFabric fabric, int expectedSize, List<? extends Location> expectedLocs) {
+        assertEquals(fabric.getChildren().size(), expectedSize, "children="+fabric.getChildren());
+        assertEquals(fabric.getMembers().size(), expectedSize, "members="+fabric.getMembers());
+        assertEqualsIgnoringOrder(fabric.getChildren(), fabric.getMembers());
+        assertEqualsIgnoringOrder(getLocationsOfChildren(fabric), expectedLocs);
+    }
+    
+    private void assertFabricMembers(DynamicRegionsFabric fabric, int expectedSize, List<? extends Location> expectedLocs) {
+        assertEquals(fabric.getMembers().size(), expectedSize, "members="+fabric.getMembers());
+        assertTrue(fabric.getChildren().containsAll(fabric.getMembers()));
+        assertEqualsIgnoringOrder(getLocationsOfMembers(fabric), expectedLocs);
+    }
 }


[3/3] brooklyn-server git commit: This closes #403

Posted by al...@apache.org.
This closes #403


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/fd009780
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/fd009780
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/fd009780

Branch: refs/heads/master
Commit: fd00978035758ba80a3b944a096407d985188a97
Parents: 63cb4c5 7c2379b
Author: Aled Sage <al...@gmail.com>
Authored: Tue Nov 8 21:01:21 2016 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Tue Nov 8 21:01:21 2016 +0000

----------------------------------------------------------------------
 .../brooklyn/entity/group/DynamicFabric.java    |  23 ++--
 .../entity/group/DynamicFabricImpl.java         |  86 ++++++++-----
 .../entity/group/DynamicRegionsFabricTest.java  | 123 +++++++++++++++++--
 3 files changed, 189 insertions(+), 43 deletions(-)
----------------------------------------------------------------------