You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2015/02/09 16:36:27 UTC

[08/22] incubator-brooklyn git commit: Partial rebind - test that version has successfully changed

Partial rebind - test that version has successfully changed


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

Branch: refs/heads/master
Commit: 07aaa8994237c2ef260d1996660b94fd04064b71
Parents: be6fd97
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Feb 5 18:28:29 2015 +0000
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Feb 6 22:12:13 2015 +0000

----------------------------------------------------------------------
 .../rebind/ActivePartialRebindIteration.java    | 21 +++--
 .../rebind/InitialFullRebindIteration.java      |  9 +--
 .../brooklyn/entity/rebind/RebindIteration.java |  9 ++-
 .../entity/rebind/RebindManagerImpl.java        | 15 +++-
 .../brooklyn/management/ha/OsgiManager.java     |  4 +-
 .../entity/rebind/ActivePartialRebindTest.java  |  8 +-
 .../rebind/ActivePartialRebindVersionTest.java  | 84 ++++++++++++++++++++
 .../brooklyn/entity/rebind/RebindTestUtils.java |  8 +-
 .../osgi/OsgiVersionMoreEntityTest.java         | 40 ++++++++--
 9 files changed, 160 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/07aaa899/core/src/main/java/brooklyn/entity/rebind/ActivePartialRebindIteration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/ActivePartialRebindIteration.java b/core/src/main/java/brooklyn/entity/rebind/ActivePartialRebindIteration.java
index fdcc810..56c467f 100644
--- a/core/src/main/java/brooklyn/entity/rebind/ActivePartialRebindIteration.java
+++ b/core/src/main/java/brooklyn/entity/rebind/ActivePartialRebindIteration.java
@@ -74,7 +74,8 @@ public class ActivePartialRebindIteration extends RebindIteration {
     }
     
     public void applyTransformer(CompoundTransformer transformer) {
-        transformers.add(transformer);
+        if (transformer!=null)
+            transformers.add(transformer);
     }
     
     @Override
@@ -88,10 +89,7 @@ public class ActivePartialRebindIteration extends RebindIteration {
         Builder mementoRawBuilder = BrooklynMementoRawData.builder();
 
         /*
-         * TODO detail...
-         * This unmanages and re-manages. Not sure if that's ideal.
-         * Probably we should try to pause it, or switch to a model
-         * where each entity can be managed by any node.
+         * Unmanagement is done as part of the "manage" call, entity by entity.
          */
 
         objectsToRebindFinal = MutableSet.of();
@@ -107,7 +105,6 @@ public class ActivePartialRebindIteration extends RebindIteration {
             }
         }
         
-        // TODO unmanage? pause?
         // get serialization
         for (BrooklynObject bo: objectsToRebindFinal) {
             Memento m = ((BrooklynObjectInternal)bo).getRebindSupport().getMemento();
@@ -115,13 +112,10 @@ public class ActivePartialRebindIteration extends RebindIteration {
             String mr = ((BrooklynMementoPersisterToObjectStore)p).getMementoSerializer().toString(m);
             mementoRawBuilder.put(BrooklynObjectType.of(bo), bo.getId(), mr);
         }
-
         // then rebuild
         mementoRawData = mementoRawBuilder.build();
-        // TODO see comment in InitialFullRebindIteration
-        mementoManifest = persistenceStoreAccess.loadMementoManifest(mementoRawData, exceptionHandler);
 
-        determineStateFromManifestFiles();
+        preprocessManifestFiles();
 
         // skip this phase, as catalog is not being changed
         // (and we don't want to unload things)
@@ -138,8 +132,11 @@ public class ActivePartialRebindIteration extends RebindIteration {
     }
 
     @Override
-    protected void determineStateFromManifestFiles() {
-        super.determineStateFromManifestFiles();
+    protected void preprocessManifestFiles() throws Exception {
+        for (CompoundTransformer transformer: transformers) {
+            mementoRawData = transformer.transform(mementoRawData);
+        }
+        super.preprocessManifestFiles();
         overwritingMaster = true;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/07aaa899/core/src/main/java/brooklyn/entity/rebind/InitialFullRebindIteration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/InitialFullRebindIteration.java b/core/src/main/java/brooklyn/entity/rebind/InitialFullRebindIteration.java
index b045873..9906f30 100644
--- a/core/src/main/java/brooklyn/entity/rebind/InitialFullRebindIteration.java
+++ b/core/src/main/java/brooklyn/entity/rebind/InitialFullRebindIteration.java
@@ -78,15 +78,10 @@ public class InitialFullRebindIteration extends RebindIteration {
 
     protected void loadManifestFiles() throws Exception {
         checkEnteringPhase(1);
-        Preconditions.checkState(mementoRawData==null && mementoManifest==null, "Memento data should not yet be set when calling this");
-        
+        Preconditions.checkState(mementoRawData==null, "Memento raw data should not yet be set when calling this");
         mementoRawData = persistenceStoreAccess.loadMementoRawData(exceptionHandler);
         
-        // TODO building the manifests should be part of this class (or parent)
-        // it does not have anything to do with the persistence store!
-        mementoManifest = persistenceStoreAccess.loadMementoManifest(mementoRawData, exceptionHandler);
-
-        determineStateFromManifestFiles();
+        preprocessManifestFiles();
         
         if (mode!=ManagementNodeState.HOT_STANDBY && mode!=ManagementNodeState.HOT_BACKUP) {
             if (!isEmpty) { 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/07aaa899/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java b/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
index fd4fded..3582030 100644
--- a/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
+++ b/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
@@ -278,9 +278,16 @@ public abstract class RebindIteration {
             throw new IllegalStateException("Phase mismatch: should be phase "+targetPhase+" but is currently "+phase);
     }
     
-    protected void determineStateFromManifestFiles() {
+    protected void preprocessManifestFiles() throws Exception {
         checkContinuingPhase(1);
 
+        Preconditions.checkState(mementoRawData!=null, "Memento raw data should be set when calling this");
+        Preconditions.checkState(mementoManifest==null, "Memento data should not yet be set when calling this");
+        
+        // TODO building the manifests should be part of this class (or parent)
+        // it does not have anything to do with the persistence store!
+        mementoManifest = persistenceStoreAccess.loadMementoManifest(mementoRawData, exceptionHandler);
+        
         overwritingMaster = false;
         isEmpty = mementoManifest.isEmpty();
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/07aaa899/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java b/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
index 9e30f7e..e6f4aea 100644
--- a/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
+++ b/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
@@ -20,6 +20,7 @@ package brooklyn.entity.rebind;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Callable;
@@ -43,6 +44,7 @@ import brooklyn.entity.rebind.persister.BrooklynMementoPersisterToObjectStore;
 import brooklyn.entity.rebind.persister.BrooklynPersistenceUtils;
 import brooklyn.entity.rebind.persister.BrooklynPersistenceUtils.CreateBackupMode;
 import brooklyn.entity.rebind.persister.PersistenceActivityMetrics;
+import brooklyn.entity.rebind.transformer.CompoundTransformer;
 import brooklyn.internal.BrooklynFeatureEnablement;
 import brooklyn.management.ExecutionContext;
 import brooklyn.management.Task;
@@ -362,7 +364,8 @@ public class RebindManagerImpl implements RebindManager {
         if (persistenceStoreAccess != null) persistenceStoreAccess.stop(true);
     }
     
-    public void testRebindNodeXXX(String ...objectsToRebindIds) {
+        
+    public void rebindPartialActive(CompoundTransformer transformer, Iterator<BrooklynObject> objectsToRebind) {
         final ClassLoader classLoader = 
             managementContext.getCatalog().getRootClassLoader();
         final RebindExceptionHandler exceptionHandler = 
@@ -378,15 +381,19 @@ public class RebindManagerImpl implements RebindManager {
         ActivePartialRebindIteration iteration = new ActivePartialRebindIteration(this, mode, classLoader, exceptionHandler,
             rebindActive, readOnlyRebindCount, rebindMetrics, persistenceStoreAccess);
 
+        iteration.setObjectIterator(objectsToRebind);
+        iteration.applyTransformer(transformer);
+        iteration.run();
+    }
+    
+    public void rebindPartialActive(CompoundTransformer transformer, String ...objectsToRebindIds) {
         List<BrooklynObject> objectsToRebind = MutableList.of();
         for (String objectId: objectsToRebindIds) {
             BrooklynObject obj = managementContext.lookup(objectId);
             if (obj instanceof Entity) obj = Entities.deproxy((Entity)obj);
             objectsToRebind.add(obj);
         }
-        
-        iteration.setObjectIterator(objectsToRebind.iterator());
-        iteration.run();
+        rebindPartialActive(transformer, objectsToRebind.iterator());
     }
     
     protected ManagementNodeState getRebindMode() {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/07aaa899/core/src/main/java/brooklyn/management/ha/OsgiManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/ha/OsgiManager.java b/core/src/main/java/brooklyn/management/ha/OsgiManager.java
index a3cbba2..260f5ff 100644
--- a/core/src/main/java/brooklyn/management/ha/OsgiManager.java
+++ b/core/src/main/java/brooklyn/management/ha/OsgiManager.java
@@ -32,6 +32,7 @@ import org.osgi.framework.launch.Framework;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import brooklyn.BrooklynVersion;
 import brooklyn.catalog.CatalogItem.CatalogBundle;
 import brooklyn.config.BrooklynServerConfig;
 import brooklyn.config.BrooklynServerPaths;
@@ -215,7 +216,8 @@ public class OsgiManager {
 
                 Throwable cause = e.getCause();
                 if (cause != null && cause.getMessage().contains("Unresolved constraint in bundle")) {
-                    log.warn("Unresolved constraint resolving OSGi bundle "+catalogBundle+" to load "+type+": "+cause.getMessage());
+                    log.warn("Unresolved constraint resolving OSGi bundle "+catalogBundle+" to load "+type+": "+cause.getMessage()+
+                        (BrooklynVersion.isDevelopmentEnvironment() ? " (may be due to IDE / dev env; try a maven build)" : ""));
                     if (log.isDebugEnabled()) log.debug("Trace for OSGi resolution failure", e);
                 }
             }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/07aaa899/core/src/test/java/brooklyn/entity/rebind/ActivePartialRebindTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/ActivePartialRebindTest.java b/core/src/test/java/brooklyn/entity/rebind/ActivePartialRebindTest.java
index 52cd3b1..80e13b6 100644
--- a/core/src/test/java/brooklyn/entity/rebind/ActivePartialRebindTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/ActivePartialRebindTest.java
@@ -35,9 +35,9 @@ public class ActivePartialRebindTest extends RebindTestFixtureWithApp {
 
     private static final Logger log = LoggerFactory.getLogger(ActivePartialRebindTest.class);
     
-    protected void doPartialRebindByObjectById(String ...ids) {
+    protected void doPartialRebindOfIds(String ...objectsToRebindIds) {
         RebindManagerImpl rm = (RebindManagerImpl) origManagementContext.getRebindManager();
-        rm.testRebindNodeXXX(ids);        
+        rm.rebindPartialActive(null, objectsToRebindIds);        
     }
     
     @Test
@@ -46,7 +46,7 @@ public class ActivePartialRebindTest extends RebindTestFixtureWithApp {
         Entities.manage(c1);
         AbstractEntity c1r = Entities.deproxy(c1);
         
-        doPartialRebindByObjectById(c1.getId());
+        doPartialRebindOfIds(c1.getId());
         
         BrooklynObject c2 = origManagementContext.lookup(c1.getId());
         AbstractEntity c2r = Entities.deproxy((Entity)c2);
@@ -64,7 +64,7 @@ public class ActivePartialRebindTest extends RebindTestFixtureWithApp {
         gcAndLog("before");
         long used0 = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
         for (int i=0; i<500; i++) {
-            doPartialRebindByObjectById(c1.getId());
+            doPartialRebindOfIds(c1.getId());
             origManagementContext.getGarbageCollector().gcIteration();
             gcAndLog("iteration "+i);
             if (i==5) used0 = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/07aaa899/core/src/test/java/brooklyn/entity/rebind/ActivePartialRebindVersionTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/ActivePartialRebindVersionTest.java b/core/src/test/java/brooklyn/entity/rebind/ActivePartialRebindVersionTest.java
new file mode 100644
index 0000000..46c1bb6
--- /dev/null
+++ b/core/src/test/java/brooklyn/entity/rebind/ActivePartialRebindVersionTest.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.entity.rebind;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import brooklyn.catalog.CatalogItem;
+import brooklyn.entity.Entity;
+import brooklyn.entity.rebind.transformer.CompoundTransformer;
+import brooklyn.management.internal.LocalManagementContext;
+import brooklyn.management.osgi.OsgiTestResources;
+import brooklyn.management.osgi.OsgiVersionMoreEntityTest;
+
+public class ActivePartialRebindVersionTest extends RebindTestFixtureWithApp {
+
+    @SuppressWarnings("unused")
+    private static final Logger log = LoggerFactory.getLogger(ActivePartialRebindVersionTest.class);
+    
+    protected LocalManagementContext createOrigManagementContext() {
+        return RebindTestUtils.managementContextBuilder(mementoDir, classLoader)
+                .persistPeriodMillis(getPersistPeriodMillis())
+                .forLive(useLiveManagementContext())
+                .emptyCatalog(useEmptyCatalog())
+                .enableOsgi(true)
+                .buildStarted();
+    }
+    
+    protected void doPartialRebindByObjectById(CompoundTransformer transformer, String ...objectsToRebindIds) {
+        RebindManagerImpl rm = (RebindManagerImpl) origManagementContext.getRebindManager();
+        rm.rebindPartialActive(transformer, objectsToRebindIds);        
+    }
+    
+    @Test
+    public void testSwitchingVersions() throws Exception {
+        CatalogItem<?, ?> catV1 = OsgiVersionMoreEntityTest.addMoreEntityV1(origManagementContext, "1.0");
+        Entity childV1 = OsgiVersionMoreEntityTest.addItemFromCatalog(origManagementContext, origApp, catV1);
+        
+        // v1 says Hi Brooklyn
+        // v2 says HI Brooklyn
+        
+        Assert.assertEquals(OsgiVersionMoreEntityTest.doEffectorCallBrooklyn(childV1), "Hi BROOKLYN");
+        
+        // simply adding to catalog doesn't change
+        CatalogItem<?, ?> catV2 = OsgiVersionMoreEntityTest.addMoreEntityV2(origManagementContext, "1.1");
+        Assert.assertEquals(OsgiVersionMoreEntityTest.doEffectorCallBrooklyn(childV1), "Hi BROOKLYN");
+        Entity child2V2 = OsgiVersionMoreEntityTest.addItemFromCatalog(origManagementContext, origApp, catV2);
+        Assert.assertEquals(OsgiVersionMoreEntityTest.doEffectorCallBrooklyn(child2V2), "HI BROOKLYN");
+        
+        // now transform, with a version change
+        CompoundTransformer transformer = CompoundTransformer.builder().changeCatalogItemId(
+            OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY, "1.0",
+            OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY, "1.1").build();
+        doPartialRebindByObjectById(transformer, childV1.getId());
+
+        Entity childV2 = origManagementContext.lookup(childV1.getId(), Entity.class);
+        Assert.assertEquals(OsgiVersionMoreEntityTest.doEffectorCallBrooklyn(childV2), "HI BROOKLYN");
+        
+        // _v1_ child also points to new implementation -- saying HI
+        Assert.assertEquals(OsgiVersionMoreEntityTest.doEffectorCallBrooklyn(childV1), "HI BROOKLYN");
+
+        // in fact they are the same
+        Assert.assertTrue(childV1==childV2, "Expected same instance: "+childV1+" / "+childV2);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/07aaa899/core/src/test/java/brooklyn/entity/rebind/RebindTestUtils.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindTestUtils.java b/core/src/test/java/brooklyn/entity/rebind/RebindTestUtils.java
index daafe58..ea901af 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindTestUtils.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindTestUtils.java
@@ -145,6 +145,7 @@ public class RebindTestUtils {
         PersistenceObjectStore objectStore;
         Duration persistPeriod = Duration.millis(100);
         boolean forLive;
+        boolean enableOsgi = false;
         boolean emptyCatalog;
         
         ManagementContextBuilder(File mementoDir, ClassLoader classLoader) {
@@ -178,6 +179,11 @@ public class RebindTestUtils {
             return this;
         }
 
+        public ManagementContextBuilder enableOsgi(boolean val) {
+            this.enableOsgi = val;
+            return this;
+        }
+
         public ManagementContextBuilder emptyCatalog() {
             this.emptyCatalog = true;
             return this;
@@ -199,7 +205,7 @@ public class RebindTestUtils {
             if (forLive) {
                 unstarted = new LocalManagementContext(properties);
             } else {
-                unstarted = new LocalManagementContextForTests(properties);
+                unstarted = LocalManagementContextForTests.builder(true).useProperties(properties).disableOsgi(!enableOsgi).build();
             }
             
             objectStore.injectManagementContext(unstarted);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/07aaa899/core/src/test/java/brooklyn/management/osgi/OsgiVersionMoreEntityTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/management/osgi/OsgiVersionMoreEntityTest.java b/core/src/test/java/brooklyn/management/osgi/OsgiVersionMoreEntityTest.java
index e8d9860..b4a3511 100644
--- a/core/src/test/java/brooklyn/management/osgi/OsgiVersionMoreEntityTest.java
+++ b/core/src/test/java/brooklyn/management/osgi/OsgiVersionMoreEntityTest.java
@@ -24,7 +24,6 @@ import java.lang.reflect.InvocationTargetException;
 import java.util.Arrays;
 import java.util.List;
 
-import brooklyn.test.TestResourceUnavailableException;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleException;
 import org.osgi.framework.launch.Framework;
@@ -44,16 +43,19 @@ import brooklyn.entity.effector.Effectors;
 import brooklyn.entity.proxying.EntitySpec;
 import brooklyn.entity.proxying.InternalEntityFactory;
 import brooklyn.entity.proxying.InternalPolicyFactory;
+import brooklyn.management.ManagementContext;
 import brooklyn.management.classloading.BrooklynClassLoadingContext;
 import brooklyn.management.internal.LocalManagementContext;
 import brooklyn.management.internal.ManagementContextInternal;
 import brooklyn.policy.PolicySpec;
+import brooklyn.test.TestResourceUnavailableException;
 import brooklyn.test.entity.LocalManagementContextForTests;
 import brooklyn.test.entity.TestApplication;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.os.Os;
 import brooklyn.util.osgi.Osgis;
 
+import com.google.common.annotations.Beta;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 
@@ -128,8 +130,12 @@ public class OsgiVersionMoreEntityTest {
     protected CatalogItem<?, ?> addCatalogItemWithTypeAsName(String type, String version, String ...libraries) {
         return addCatalogItemWithNameAndType(type, version, type, libraries);
     }
-    @SuppressWarnings("deprecation")
     protected CatalogItem<?, ?> addCatalogItemWithNameAndType(String symName, String version, String type, String ...libraries) {
+        return addCatalogItemWithNameAndType(mgmt, symName, version, type, libraries);
+    }
+
+    @SuppressWarnings("deprecation")
+    static CatalogItem<?, ?> addCatalogItemWithNameAndType(ManagementContext mgmt, String symName, String version, String type, String ...libraries) {
         CatalogEntityItemDto c1 = newCatalogItemWithNameAndType(symName, version, type, libraries);
         mgmt.getCatalog().addItem(c1);
         CatalogItem<?, ?> c2 = mgmt.getCatalog().getCatalogItem(type, version);
@@ -148,15 +154,20 @@ public class OsgiVersionMoreEntityTest {
         return c1;
     }
 
-    @SuppressWarnings({ "unchecked", "rawtypes" })
     protected Entity addItemFromCatalog(CatalogItem<?, ?> c2) {
+        return addItemFromCatalog(mgmt, app, c2);
+    }
+    
+    @Beta
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public static Entity addItemFromCatalog(ManagementContext mgmt, TestApplication parent, CatalogItem<?, ?> c2) {
         BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContext(mgmt, c2);
         EntitySpec spec = EntitySpec.create( (Class)loader.loadClass(c2.getJavaType()) );
         // not a great test as we set the ID here; but:
         // YAML test will do better;
         // and we can check that downstream items are loaded correctly
         spec.catalogItemId(c2.getId());
-        Entity me = app.createAndManageChild(spec);
+        Entity me = parent.createAndManageChild(spec);
         return me;
     }
 
@@ -188,14 +199,27 @@ public class OsgiVersionMoreEntityTest {
         return me.invoke(Effectors.effector(String.class, "sayHI").buildAbstract(), ImmutableMap.of("name", "brooklyn")).getUnchecked();
     }
 
+    public static CatalogItem<?, ?> addMoreEntityV1(ManagementContext mgmt, String versionToRegister) {
+        return addCatalogItemWithNameAndType(mgmt, 
+            OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY,
+            versionToRegister,
+            OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY,
+            BROOKLYN_TEST_MORE_ENTITIES_V1_URL);
+    }
+    public static CatalogItem<?, ?> addMoreEntityV2(ManagementContext mgmt, String versionToRegister) {
+        return addCatalogItemWithNameAndType(mgmt,
+            OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY,
+            versionToRegister,
+            OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY,
+            BROOKLYN_TEST_MORE_ENTITIES_V2_URL,
+            BROOKLYN_TEST_OSGI_ENTITIES_URL);
+    }
+    
     @Test
     public void testMoreEntitiesV1() throws Exception {
         TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), BROOKLYN_TEST_MORE_ENTITIES_V1_PATH);
 
-        CatalogItem<?, ?> c2 = addCatalogItemWithTypeAsName(
-                OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY,
-                TEST_VERSION,
-                BROOKLYN_TEST_MORE_ENTITIES_V1_URL);
+        CatalogItem<?, ?> c2 = addMoreEntityV1(mgmt, TEST_VERSION);
         
         // test load and instantiate
         Entity me = addItemFromCatalog(c2);