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/09/30 09:00:32 UTC

[6/9] brooklyn-server git commit: Test hot-standby in SoftwareProcessRebindNotRunningEntityTest

Test hot-standby in SoftwareProcessRebindNotRunningEntityTest


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

Branch: refs/heads/master
Commit: 643b19bc8e82104d59c04214a232eca0606b0e83
Parents: 2520f0d
Author: Aled Sage <al...@gmail.com>
Authored: Thu Sep 29 13:58:38 2016 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Thu Sep 29 14:42:15 2016 +0100

----------------------------------------------------------------------
 .../JcloudsRebindWithExternalConfigTest.java    |  5 ++-
 .../brooklyn/camp/brooklyn/RebindOsgiTest.java  |  5 ++-
 .../core/mgmt/rebind/RebindCatalogItemTest.java |  4 +-
 ...talogWhenCatalogPersistenceDisabledTest.java |  4 +-
 .../core/mgmt/rebind/RebindOptions.java         |  7 ++++
 .../core/mgmt/rebind/RebindTestFixture.java     | 41 ++++++++++++++++++++
 .../core/mgmt/rebind/RebindTestUtils.java       | 17 ++++++--
 ...ClockerDynamicLocationPatternRebindTest.java |  5 ++-
 ...ftwareProcessRebindNotRunningEntityTest.java | 39 +++++++++++++++++++
 9 files changed, 116 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/643b19bc/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsRebindWithExternalConfigTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsRebindWithExternalConfigTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsRebindWithExternalConfigTest.java
index 4d6064f..160a9c2 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsRebindWithExternalConfigTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsRebindWithExternalConfigTest.java
@@ -26,6 +26,7 @@ import java.util.Map;
 import org.apache.brooklyn.api.entity.Application;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
 import org.apache.brooklyn.camp.brooklyn.spi.creation.CampTypePlanTransformer;
 import org.apache.brooklyn.core.config.external.InPlaceExternalConfigSupplier;
 import org.apache.brooklyn.core.entity.trait.Startable;
@@ -105,11 +106,11 @@ public class JcloudsRebindWithExternalConfigTest extends JcloudsRebindStubTest {
     }
 
     @Override
-    protected LocalManagementContext createNewManagementContext(final File mementoDir) {
+    protected LocalManagementContext createNewManagementContext(final File mementoDir, final HighAvailabilityMode haMode) {
         newLauncher = new BrooklynCampPlatformLauncherNoServer() {
             @Override
             protected LocalManagementContext newMgmtContext() {
-                return JcloudsRebindWithExternalConfigTest.super.createNewManagementContext(mementoDir);
+                return JcloudsRebindWithExternalConfigTest.super.createNewManagementContext(mementoDir, haMode);
             }
         };
         newLauncher.launch();

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/643b19bc/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/RebindOsgiTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/RebindOsgiTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/RebindOsgiTest.java
index b4310e8..5d7bd0f 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/RebindOsgiTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/RebindOsgiTest.java
@@ -28,6 +28,7 @@ import java.util.List;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.config.ConfigKeys;
@@ -90,8 +91,8 @@ public class RebindOsgiTest extends AbstractYamlRebindTest {
     }
     
     @Override
-    protected LocalManagementContext createNewManagementContext(File mementoDir) {
-        LocalManagementContext result = super.createNewManagementContext(mementoDir);
+    protected LocalManagementContext createNewManagementContext(File mementoDir, HighAvailabilityMode haMode) {
+        LocalManagementContext result = super.createNewManagementContext(mementoDir, haMode);
         for (String bundleUrl : bundleUrlsToInstallOnRebind) {
             try {
                 installBundle(result, bundleUrl);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/643b19bc/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindCatalogItemTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindCatalogItemTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindCatalogItemTest.java
index 26e1a93..624e733 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindCatalogItemTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindCatalogItemTest.java
@@ -29,6 +29,7 @@ import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.catalog.CatalogItem.CatalogItemType;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
 import org.apache.brooklyn.api.typereg.RegisteredType;
 import org.apache.brooklyn.core.BrooklynFeatureEnablement;
 import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog;
@@ -92,12 +93,13 @@ public class RebindCatalogItemTest extends RebindTestFixtureWithApp {
     }
 
     @Override
-    protected LocalManagementContext createNewManagementContext(File mementoDir) {
+    protected LocalManagementContext createNewManagementContext(File mementoDir, HighAvailabilityMode haMode) {
         BrooklynProperties properties = BrooklynProperties.Factory.newDefault();
         properties.put(BrooklynServerConfig.BROOKLYN_CATALOG_URL, "classpath://brooklyn/entity/rebind/rebind-catalog-item-test-catalog.xml");
         return RebindTestUtils.managementContextBuilder(mementoDir, classLoader)
                 .properties(properties)
                 .forLive(useLiveManagementContext())
+                .haMode(haMode)
                 .emptyCatalog(useEmptyCatalog())
                 .buildUnstarted();
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/643b19bc/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindCatalogWhenCatalogPersistenceDisabledTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindCatalogWhenCatalogPersistenceDisabledTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindCatalogWhenCatalogPersistenceDisabledTest.java
index 65cd1da..70d5a16 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindCatalogWhenCatalogPersistenceDisabledTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindCatalogWhenCatalogPersistenceDisabledTest.java
@@ -24,6 +24,7 @@ import java.io.File;
 
 import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
 import org.apache.brooklyn.core.BrooklynFeatureEnablement;
 import org.apache.brooklyn.core.internal.BrooklynProperties;
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
@@ -68,12 +69,13 @@ public class RebindCatalogWhenCatalogPersistenceDisabledTest extends RebindTestF
     }
 
     @Override
-    protected LocalManagementContext createNewManagementContext(File mementoDir) {
+    protected LocalManagementContext createNewManagementContext(File mementoDir, HighAvailabilityMode haMode) {
         BrooklynProperties properties = BrooklynProperties.Factory.newDefault();
         properties.put(BrooklynServerConfig.BROOKLYN_CATALOG_URL, TEST_CATALOG);
         return RebindTestUtils.managementContextBuilder(mementoDir, classLoader)
                 .properties(properties)
                 .forLive(useLiveManagementContext())
+                .haMode(haMode)
                 .buildUnstarted();
     }
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/643b19bc/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindOptions.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindOptions.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindOptions.java
index eea64d6..618a906 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindOptions.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindOptions.java
@@ -21,6 +21,7 @@ package org.apache.brooklyn.core.mgmt.rebind;
 import java.io.File;
 
 import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
 import org.apache.brooklyn.api.mgmt.rebind.RebindExceptionHandler;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoPersister;
 import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore;
@@ -41,6 +42,7 @@ public class RebindOptions {
     public Function<BrooklynMementoPersister, Void> stateTransformer;
     public ClassLoader classLoader;
     public PersistenceObjectStore objectStore;
+    public HighAvailabilityMode haMode;
     
     public static RebindOptions create() {
         return new RebindOptions();
@@ -57,6 +59,7 @@ public class RebindOptions {
         result.stateTransformer(options.stateTransformer);
         result.classLoader(options.classLoader);
         result.objectStore(options.objectStore);
+        result.haMode(options.haMode);
         return result;
     }
     public RebindOptions checkSerializable(boolean val) {
@@ -99,4 +102,8 @@ public class RebindOptions {
         this.objectStore = val;
         return this;
     }
+    public RebindOptions haMode(HighAvailabilityMode val) {
+        this.haMode = val;
+        return this;
+    }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/643b19bc/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java
index 9a81cea..5af282b 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java
@@ -43,6 +43,7 @@ import org.apache.brooklyn.core.internal.BrooklynProperties;
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.mgmt.persist.BrooklynMementoPersisterToObjectStore;
+import org.apache.brooklyn.core.mgmt.persist.BrooklynPersistenceUtils;
 import org.apache.brooklyn.core.mgmt.persist.FileBasedObjectStore;
 import org.apache.brooklyn.core.mgmt.persist.PersistMode;
 import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
@@ -102,6 +103,7 @@ public abstract class RebindTestFixture<T extends StartableApplication> {
 
         return RebindTestUtils.managementContextBuilder(mementoDir, classLoader)
                 .persistPeriodMillis(getPersistPeriodMillis())
+                .haMode(getHaMode())
                 .forLive(useLiveManagementContext())
                 .enablePersistenceBackups(enablePersistenceBackups())
                 .emptyCatalog(useEmptyCatalog())
@@ -110,6 +112,10 @@ public abstract class RebindTestFixture<T extends StartableApplication> {
                 .buildStarted();
     }
 
+    protected HighAvailabilityMode getHaMode() {
+        return HighAvailabilityMode.DISABLED;
+    }
+    
     protected boolean enablePersistenceBackups() {
         return true;
     }
@@ -121,9 +127,14 @@ public abstract class RebindTestFixture<T extends StartableApplication> {
     
     /** @return An unstarted management context using the specified mementoDir (or default if null) */
     protected LocalManagementContext createNewManagementContext(File mementoDir) {
+        return createNewManagementContext(mementoDir, getHaMode());
+    }
+    
+    protected LocalManagementContext createNewManagementContext(File mementoDir, HighAvailabilityMode haMode) {
         if (mementoDir==null) mementoDir = this.mementoDir;
         return RebindTestUtils.managementContextBuilder(mementoDir, classLoader)
                 .forLive(useLiveManagementContext())
+                .haMode(haMode)
                 .emptyCatalog(useEmptyCatalog())
                 .properties(createBrooklynProperties())
                 .enableOsgi(useOsgi())
@@ -286,6 +297,36 @@ public abstract class RebindTestFixture<T extends StartableApplication> {
         return newApp;
     }
 
+    protected T hotStandby() throws Exception {
+        return hotStandby(RebindOptions.create());
+    }
+
+    protected T hotStandby(RebindOptions options) throws Exception {
+        if (newApp != null || newManagementContext != null) {
+            throw new IllegalStateException("already rebound - use switchOriginalToNewManagementContext() if you are trying to rebind multiple times");
+        }
+        if (options.haMode != null && options.haMode != HighAvailabilityMode.HOT_STANDBY) {
+            throw new IllegalStateException("hotStandby called, but with HA Mode set to "+options.haMode);
+        }
+        if (options.terminateOrigManagementContext) {
+            throw new IllegalStateException("hotStandby called with terminateOrigManagementContext==true");
+        }
+        
+        options = RebindOptions.create(options);
+        options.terminateOrigManagementContext(false);
+        if (options.haMode == null) options.haMode(HighAvailabilityMode.HOT_STANDBY);
+        if (options.classLoader == null) options.classLoader(classLoader);
+        if (options.mementoDir == null) options.mementoDir(mementoDir);
+        if (options.origManagementContext == null) options.origManagementContext(origManagementContext);
+        if (options.newManagementContext == null) options.newManagementContext(createNewManagementContext(options.mementoDir, options.haMode));
+        
+        RebindTestUtils.waitForPersisted(origApp);
+        
+        newManagementContext = options.newManagementContext;
+        newApp = (T) RebindTestUtils.rebind(options);
+        return newApp;
+    }
+
     /**
      * Dumps out the persisted mementos that are at the given directory.
      * 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/643b19bc/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestUtils.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestUtils.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestUtils.java
index ad2bdf8..af3a5e4 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestUtils.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestUtils.java
@@ -44,6 +44,7 @@ import org.apache.brooklyn.core.mgmt.ha.ManagementPlaneSyncRecordPersisterToObje
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.mgmt.persist.BrooklynMementoPersisterToObjectStore;
+import org.apache.brooklyn.core.mgmt.persist.BrooklynPersistenceUtils;
 import org.apache.brooklyn.core.mgmt.persist.FileBasedObjectStore;
 import org.apache.brooklyn.core.mgmt.persist.PersistMode;
 import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore;
@@ -150,6 +151,7 @@ public class RebindTestUtils {
         BrooklynProperties properties;
         PersistenceObjectStore objectStore;
         Duration persistPeriod = Duration.millis(100);
+        HighAvailabilityMode haMode;
         boolean forLive;
         boolean enableOsgi = false;
         boolean emptyCatalog;
@@ -205,6 +207,11 @@ public class RebindTestUtils {
             return this;
         }
 
+        public ManagementContextBuilder haMode(HighAvailabilityMode val) {
+            this.haMode = val;
+            return this;
+        }
+
         public LocalManagementContext buildUnstarted() {
             LocalManagementContext unstarted;
             BrooklynProperties properties = this.properties != null
@@ -225,7 +232,7 @@ public class RebindTestUtils {
             }
             
             objectStore.injectManagementContext(unstarted);
-            objectStore.prepareForSharedUse(PersistMode.AUTO, HighAvailabilityMode.DISABLED);
+            objectStore.prepareForSharedUse(PersistMode.AUTO, (haMode == null ? HighAvailabilityMode.DISABLED : haMode));
             BrooklynMementoPersisterToObjectStore newPersister = new BrooklynMementoPersisterToObjectStore(
                     objectStore, 
                     unstarted.getBrooklynProperties(), 
@@ -394,6 +401,7 @@ public class RebindTestUtils {
         ManagementContextInternal origManagementContext = (ManagementContextInternal) options.origManagementContext;
         ManagementContextInternal newManagementContext = (ManagementContextInternal) options.newManagementContext;
         PersistenceObjectStore objectStore = options.objectStore;
+        HighAvailabilityMode haMode = (options.haMode == null ? HighAvailabilityMode.DISABLED : options.haMode);
         RebindExceptionHandler exceptionHandler = options.exceptionHandler;
         boolean hasPersister = newManagementContext != null && newManagementContext.getRebindManager().getPersister() != null;
         boolean checkSerializable = options.checkSerializable;
@@ -412,7 +420,7 @@ public class RebindTestUtils {
                 objectStore = new FileBasedObjectStore(checkNotNull(mementoDir, "mementoDir and objectStore must not both be null"));
             }
             objectStore.injectManagementContext(newManagementContext);
-            objectStore.prepareForSharedUse(PersistMode.AUTO, HighAvailabilityMode.DISABLED);
+            objectStore.prepareForSharedUse(PersistMode.AUTO, haMode);
             
             BrooklynMementoPersisterToObjectStore newPersister = new BrooklynMementoPersisterToObjectStore(
                     objectStore,
@@ -443,7 +451,10 @@ public class RebindTestUtils {
             stateTransformer.apply(persister);
         }
         
-        List<Application> newApps = newManagementContext.getRebindManager().rebind(classLoader, exceptionHandler, ManagementNodeState.MASTER);
+        List<Application> newApps = newManagementContext.getRebindManager().rebind(
+                classLoader, 
+                exceptionHandler, 
+                (haMode == HighAvailabilityMode.DISABLED) ? ManagementNodeState.MASTER : ManagementNodeState.of(haMode).get());
         newManagementContext.getRebindManager().startPersistence();
         return newApps;
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/643b19bc/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/ClockerDynamicLocationPatternRebindTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/ClockerDynamicLocationPatternRebindTest.java b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/ClockerDynamicLocationPatternRebindTest.java
index 6ccd86c..288bd5e 100644
--- a/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/ClockerDynamicLocationPatternRebindTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/core/location/dynamic/clocker/ClockerDynamicLocationPatternRebindTest.java
@@ -29,6 +29,7 @@ import java.util.Map;
 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.api.mgmt.ha.HighAvailabilityMode;
 import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.location.BasicLocationRegistry;
@@ -56,8 +57,8 @@ public class ClockerDynamicLocationPatternRebindTest extends RebindTestFixtureWi
     }
     
     @Override
-    protected LocalManagementContext createNewManagementContext(File mementoDir) {
-        LocalManagementContext result = super.createNewManagementContext(mementoDir);
+    protected LocalManagementContext createNewManagementContext(File mementoDir, HighAvailabilityMode haMode) {
+        LocalManagementContext result = super.createNewManagementContext(mementoDir, haMode);
         StubResolver stubResolver = new StubResolver();
         ((BasicLocationRegistry)result.getLocationRegistry()).registerResolver(stubResolver);
         return result;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/643b19bc/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessRebindNotRunningEntityTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessRebindNotRunningEntityTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessRebindNotRunningEntityTest.java
index d118629..0e38e3f 100644
--- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessRebindNotRunningEntityTest.java
+++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessRebindNotRunningEntityTest.java
@@ -18,6 +18,7 @@
  */
 package org.apache.brooklyn.entity.software.base;
 
+import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertTrue;
 
 import java.util.Collection;
@@ -35,6 +36,7 @@ import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
 import org.apache.brooklyn.api.location.NoMachinesAvailableException;
+import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.Attributes;
@@ -126,6 +128,11 @@ public class SoftwareProcessRebindNotRunningEntityTest extends RebindTestFixture
         return mgmt().getEntityManager().createEntity(EntitySpec.create(TestApplication.class));
     }
 
+    @Override
+    protected HighAvailabilityMode getHaMode() {
+        return HighAvailabilityMode.MASTER;
+    }
+
     @Test
     public void testRebindWhileWaitingForCheckRunning() throws Exception {
         final CountDownLatch checkRunningCalledLatch = newLatch(1);
@@ -277,6 +284,38 @@ public class SoftwareProcessRebindNotRunningEntityTest extends RebindTestFixture
         EntityAsserts.assertAttributeEqualsEventually(newApp, Attributes.SERVICE_UP, false);
     }
 
+    @Test
+    public void testLaunchHotStandbyWhileEntityStarting() throws Exception {
+        final CountDownLatch launchCalledLatch = newLatch(1);
+        final CountDownLatch launchBlockedLatch = newLatch(1);
+        RecordingSshTool.setCustomResponse(".*myLaunch.*", new CustomResponseGenerator() {
+            @Override
+            public CustomResponse generate(ExecParams execParams) throws Exception {
+                launchCalledLatch.countDown();
+                launchBlockedLatch.await();
+                return new CustomResponse(0, "", "");
+            }});
+        
+        VanillaSoftwareProcess entity = app().createAndManageChild(EntitySpec.create(VanillaSoftwareProcess.class)
+                .configure(VanillaSoftwareProcess.LAUNCH_COMMAND, "myLaunch")
+                .configure(VanillaSoftwareProcess.CHECK_RUNNING_COMMAND, "myCheckRunning"));
+        
+        startAsync(app(), ImmutableList.of(locationProvisioner));
+        awaitOrFail(launchCalledLatch, Asserts.DEFAULT_LONG_TIMEOUT);
+
+        EntityAsserts.assertAttributeEquals(entity, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.STARTING);
+
+        // Check that the read-only hot standby does not overwrite the entity's state; it should still say "STARTING"
+        TestApplication newApp = hotStandby();
+        final VanillaSoftwareProcess newEntity = (VanillaSoftwareProcess) Iterables.find(newApp.getChildren(), Predicates.instanceOf(VanillaSoftwareProcess.class));
+
+        EntityAsserts.assertAttributeEqualsContinually(newEntity, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.STARTING);
+        assertEquals(newEntity.getAttribute(Attributes.SERVICE_STATE_EXPECTED).getState(), Lifecycle.STARTING);
+        
+        EntityAsserts.assertAttributeEqualsEventually(newApp, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.STARTING);
+        assertEquals(newApp.getAttribute(Attributes.SERVICE_STATE_EXPECTED).getState(), Lifecycle.STARTING);
+    }
+
     protected ListenableFuture<Void> startAsync(final Startable entity, final Collection<? extends Location> locs) {
         return executor.submit(new Callable<Void>() {
             @Override public Void call() throws Exception {