You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by sv...@apache.org on 2016/10/21 09:20:47 UTC

[5/8] brooklyn-server git commit: Convert jclouds yaml tests to unit tests

Convert jclouds yaml tests to unit tests


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

Branch: refs/heads/master
Commit: 70fd9bdf74d42c3a2a735c782392ae6b771700a3
Parents: cb3bfa5
Author: Aled Sage <al...@gmail.com>
Authored: Wed Oct 19 09:54:48 2016 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Wed Oct 19 10:15:11 2016 +0100

----------------------------------------------------------------------
 camp/camp-brooklyn/pom.xml                      |   7 +
 .../AbstractJcloudsRebindStubYamlTest.java      | 139 ++++++++++++
 .../brooklyn/AbstractJcloudsStubYamlTest.java   | 179 ++++++++++++++++
 ...loudsCustomizerInstantiationYamlDslTest.java |  46 +---
 .../brooklyn/JcloudsExternalConfigYamlTest.java |  45 ++--
 .../brooklyn/JcloudsRebindStubYamlTest.java     |  99 ---------
 .../JcloudsRebindWithExternalConfigTest.java    |  34 ++-
 .../brooklyn/JcloudsRebindWithYamlDslTest.java  |  20 +-
 .../jclouds/AbstractJcloudsLiveTest.java        |   4 +
 .../jclouds/AbstractJcloudsStubbedUnitTest.java |  37 +---
 .../JcloudsLocationExtensionStubbedTest.java    |   2 +-
 .../jclouds/JcloudsRebindStubUnitTest.java      | 212 +++++++++++++++++++
 .../jclouds/JcloudsStubTemplateBuilder.java     |   5 +
 .../jclouds/StubbedComputeServiceRegistry.java  |  22 ++
 .../JcloudsPortForwardingStubbedTest.java       |   2 +-
 15 files changed, 629 insertions(+), 224 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/70fd9bdf/camp/camp-brooklyn/pom.xml
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/pom.xml b/camp/camp-brooklyn/pom.xml
index ac12285..232e5c2 100644
--- a/camp/camp-brooklyn/pom.xml
+++ b/camp/camp-brooklyn/pom.xml
@@ -146,6 +146,13 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>org.apache.brooklyn</groupId>
+            <artifactId>brooklyn-software-winrm</artifactId>
+            <version>${project.version}</version>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <!-- jsr311 excluded from jclouds; see jclouds module's pom for further comments. -->
             <groupId>javax.ws.rs</groupId>
             <artifactId>javax.ws.rs-api</artifactId>

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/70fd9bdf/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractJcloudsRebindStubYamlTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractJcloudsRebindStubYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractJcloudsRebindStubYamlTest.java
new file mode 100644
index 0000000..d12b885
--- /dev/null
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractJcloudsRebindStubYamlTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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 org.apache.brooklyn.camp.brooklyn;
+
+import java.io.File;
+
+import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
+import org.apache.brooklyn.camp.brooklyn.AbstractJcloudsStubYamlTest.ByonComputeServiceStaticRef;
+import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
+import org.apache.brooklyn.location.jclouds.ComputeServiceRegistry;
+import org.apache.brooklyn.location.jclouds.JcloudsLocation;
+import org.apache.brooklyn.location.jclouds.JcloudsRebindStubTest;
+import org.apache.brooklyn.location.jclouds.JcloudsRebindStubUnitTest;
+import org.apache.brooklyn.location.jclouds.JcloudsStubTemplateBuilder;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
+import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool;
+import org.apache.brooklyn.util.core.internal.winrm.RecordingWinRmTool;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Predicates;
+
+/**
+ * Implementation notes. This relies on the test {@link JcloudsRebindStubTest#testRebind()}.
+ * It changes the setup for the test in the following ways:
+ * <ul>
+ *   <li>Location is defined in YAML (added to the catalog, to make it easier for sub-classes to use).
+ *   <li>When creating management context, it also creates {@link BrooklynCampPlatformLauncherNoServer}.
+ *   <li>It uses {@link JcloudsRebindStubYamlTest#ByonComputeServiceStaticRef} to allow
+ *       the test's {@link ComputeServiceRegistry} to be wired up via YAML. This is important so that
+ *       we can serialize/deserialize in the rebind test.
+ * </ul>
+ */
+public abstract class AbstractJcloudsRebindStubYamlTest extends JcloudsRebindStubUnitTest {
+
+    // TODO Some duplication compared to AbstractJcloudsStubYamlTest
+
+    public static final String LOCATION_CATALOG_ID = "stubbed-aws-ec2";
+
+    protected BrooklynCampPlatformLauncherNoServer origLauncher;
+    protected BrooklynCampPlatformLauncherNoServer newLauncher;
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        addStubbedLocationToCatalog();
+    }
+    
+    @Override
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        try {
+            super.tearDown();
+        } finally {
+            ByonComputeServiceStaticRef.clearInstance();
+            if (origLauncher != null) origLauncher.stopServers();
+            if (newLauncher != null) newLauncher.stopServers();
+        }
+    }
+    
+    @Override
+    protected LocalManagementContext createOrigManagementContext() {
+        origLauncher = new BrooklynCampPlatformLauncherNoServer() {
+            @Override
+            protected LocalManagementContext newMgmtContext() {
+                return AbstractJcloudsRebindStubYamlTest.super.createOrigManagementContext();
+            }
+        };
+        origLauncher.launch();
+        LocalManagementContext mgmt = (LocalManagementContext) origLauncher.getBrooklynMgmt();
+        return mgmt;
+    }
+
+    @Override
+    protected LocalManagementContext createNewManagementContext(final File mementoDir, final HighAvailabilityMode haMode) {
+        newLauncher = new BrooklynCampPlatformLauncherNoServer() {
+            @Override
+            protected LocalManagementContext newMgmtContext() {
+                return AbstractJcloudsRebindStubYamlTest.super.createNewManagementContext(mementoDir, haMode);
+            }
+        };
+        newLauncher.launch();
+        return (LocalManagementContext) newLauncher.getBrooklynMgmt();
+    }
+    
+    protected void addStubbedLocationToCatalog() {
+        addCatalogItems(
+                "brooklyn.catalog:",
+                "  id: " + LOCATION_CATALOG_ID,
+                "  version: 1.0.0",
+                "  itemType: location",
+                "  item:",
+                "    type: " + LOCATION_SPEC,
+                "    brooklyn.config:",
+                "      identity: myidentity",
+                "      credential: mycredential",
+                "      jclouds.computeServiceRegistry:",
+                "        $brooklyn:object:",
+                "          type: " + ByonComputeServiceStaticRef.class.getName(),
+                "      " + SshMachineLocation.SSH_TOOL_CLASS.getName() + ": " + RecordingSshTool.class.getName(),
+                "      templateBuilder:",
+                "        $brooklyn:object:",
+                "          type: "+JcloudsStubTemplateBuilder.class.getName(),
+                "          factoryMethod.name: create",
+                "      " + JcloudsLocation.POLL_FOR_FIRST_REACHABLE_ADDRESS_PREDICATE.getName() + ":",
+                "        $brooklyn:object:",
+                "          type: "+Predicates.class.getName(),
+                "          factoryMethod.name: alwaysTrue",
+                "      " + SshMachineLocation.SSH_TOOL_CLASS.getName() + ": " + RecordingSshTool.class.getName(),
+                "      " + WinRmMachineLocation.WINRM_TOOL_CLASS.getName() + ": " + RecordingWinRmTool.class.getName());
+    }
+    
+    protected void addCatalogItems(String... catalogYaml) {
+        addCatalogItems(Joiner.on("\n").join(catalogYaml));
+    }
+    
+    protected void addCatalogItems(String catalogYaml) {
+        mgmt().getCatalog().addItems(catalogYaml, false);
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/70fd9bdf/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractJcloudsStubYamlTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractJcloudsStubYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractJcloudsStubYamlTest.java
new file mode 100644
index 0000000..456f05d
--- /dev/null
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractJcloudsStubYamlTest.java
@@ -0,0 +1,179 @@
+/*
+ * 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 org.apache.brooklyn.camp.brooklyn;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.Reader;
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.camp.brooklyn.AbstractJcloudsStubYamlTest.ByonComputeServiceStaticRef;
+import org.apache.brooklyn.camp.spi.Assembly;
+import org.apache.brooklyn.camp.spi.AssemblyTemplate;
+import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
+import org.apache.brooklyn.location.jclouds.AbstractJcloudsStubbedUnitTest;
+import org.apache.brooklyn.location.jclouds.ComputeServiceRegistry;
+import org.apache.brooklyn.location.jclouds.JcloudsLocation;
+import org.apache.brooklyn.location.jclouds.JcloudsStubTemplateBuilder;
+import org.apache.brooklyn.location.jclouds.StubbedComputeServiceRegistry;
+import org.apache.brooklyn.location.jclouds.StubbedComputeServiceRegistry.NodeCreator;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool;
+import org.apache.brooklyn.util.core.internal.winrm.RecordingWinRmTool;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+
+/**
+ * This is a combination of the jclouds tests and the yaml tests. As such, it extends
+ * {@link AbstractJcloudsStubbedUnitTest} and duplicates some of the utility methods in
+ * {@link AbstractYamlTest}.
+ */
+public abstract class AbstractJcloudsStubYamlTest extends AbstractJcloudsStubbedUnitTest {
+
+    // TODO Some duplication compared to AbstractJcloudsRebindStubYamlTest
+    
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractJcloudsStubYamlTest.class);
+
+    public static final String LOCATION_CATALOG_ID = "stubbed-aws-ec2";
+    
+    protected BrooklynCampPlatformLauncherNoServer launcher;
+    protected BrooklynCampPlatform platform;
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        
+        NodeCreator nodeCreator = newNodeCreator();
+        StubbedComputeServiceRegistry computeServiceRegistry = new StubbedComputeServiceRegistry(nodeCreator, false);
+        ByonComputeServiceStaticRef.setInstance(computeServiceRegistry);
+        
+        addStubbedLocationToCatalog();
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    @Override
+    public void tearDown() throws Exception {
+        try {
+            super.tearDown();
+        } finally {
+            ByonComputeServiceStaticRef.clearInstance();
+            if (launcher != null) launcher.stopServers();
+        }
+    }
+    
+    @Override
+    protected LocalManagementContext newManagementContext() {
+        launcher = new BrooklynCampPlatformLauncherNoServer() {
+            @Override
+            protected LocalManagementContext newMgmtContext() {
+                return AbstractJcloudsStubYamlTest.super.newManagementContext();
+            }
+        };
+        launcher.launch();
+        platform = launcher.getCampPlatform();
+        LocalManagementContext mgmt = (LocalManagementContext) launcher.getBrooklynMgmt();
+        return mgmt;
+    }
+
+    protected void addStubbedLocationToCatalog() {
+        addCatalogItems(
+                "brooklyn.catalog:",
+                "  id: " + LOCATION_CATALOG_ID,
+                "  version: 1.0.0",
+                "  itemType: location",
+                "  item:",
+                "    type: " + LOCATION_SPEC,
+                "    brooklyn.config:",
+                "      identity: myidentity",
+                "      credential: mycredential",
+                "      jclouds.computeServiceRegistry:",
+                "        $brooklyn:object:",
+                "          type: " + ByonComputeServiceStaticRef.class.getName(),
+                "      " + SshMachineLocation.SSH_TOOL_CLASS.getName() + ": " + RecordingSshTool.class.getName(),
+                "      templateBuilder:",
+                "        $brooklyn:object:",
+                "          type: "+JcloudsStubTemplateBuilder.class.getName(),
+                "          factoryMethod.name: create",
+                "      " + JcloudsLocation.POLL_FOR_FIRST_REACHABLE_ADDRESS_PREDICATE.getName() + ":",
+                "        $brooklyn:object:",
+                "          type: "+Predicates.class.getName(),
+                "          factoryMethod.name: alwaysTrue",
+                "      " + SshMachineLocation.SSH_TOOL_CLASS.getName() + ": " + RecordingSshTool.class.getName(),
+                "      " + WinRmMachineLocation.WINRM_TOOL_CLASS.getName() + ": " + RecordingWinRmTool.class.getName());
+    }
+
+    protected void addCatalogItems(String... catalogYaml) {
+        addCatalogItems(Joiner.on("\n").join(catalogYaml));
+    }
+    
+    protected void addCatalogItems(String catalogYaml) {
+        mgmt().getCatalog().addItems(catalogYaml, false);
+    }
+    
+    protected Entity createAndStartApplication(Reader input) throws Exception {
+        AssemblyTemplate at = platform.pdp().registerDeploymentPlan(input);
+        Assembly assembly;
+        try {
+            assembly = at.getInstantiator().newInstance().instantiate(at, platform);
+        } catch (Exception e) {
+            LOG.warn("Unable to instantiate " + at + " (rethrowing): " + e);
+            throw e;
+        }
+        LOG.info("Test - created " + assembly);
+        final Entity app = mgmt().getEntityManager().getEntity(assembly.getId());
+        LOG.info("App - " + app);
+        
+        // wait for app to have started
+        Set<Task<?>> tasks = mgmt().getExecutionManager().getTasksWithAllTags(ImmutableList.of(
+                BrooklynTaskTags.EFFECTOR_TAG, 
+                BrooklynTaskTags.tagForContextEntity(app), 
+                BrooklynTaskTags.tagForEffectorCall(app, "start", ConfigBag.newInstance(ImmutableMap.of("locations", ImmutableMap.of())))));
+        Iterables.getOnlyElement(tasks).get();
+        
+        return app;
+    }
+
+    public static class ByonComputeServiceStaticRef {
+        private static volatile ComputeServiceRegistry instance;
+
+        public ComputeServiceRegistry asComputeServiceRegistry() {
+            return checkNotNull(instance, "instance");
+        }
+        static void setInstance(ComputeServiceRegistry val) {
+            instance = val;
+        }
+        static void clearInstance() {
+            instance = null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/70fd9bdf/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsCustomizerInstantiationYamlDslTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsCustomizerInstantiationYamlDslTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsCustomizerInstantiationYamlDslTest.java
index 7083fc2..a845831 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsCustomizerInstantiationYamlDslTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsCustomizerInstantiationYamlDslTest.java
@@ -22,23 +22,18 @@ import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertSame;
 
 import java.util.List;
-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.camp.brooklyn.spi.creation.CampTypePlanTransformer;
 import org.apache.brooklyn.core.entity.trait.Startable;
-import org.apache.brooklyn.core.location.Machines;
 import org.apache.brooklyn.core.typereg.RegisteredTypeLoadingContexts;
 import org.apache.brooklyn.entity.machine.MachineEntity;
 import org.apache.brooklyn.location.jclouds.BasicJcloudsLocationCustomizer;
-import org.apache.brooklyn.location.jclouds.ComputeServiceRegistry;
 import org.apache.brooklyn.location.jclouds.JcloudsLocation;
 import org.apache.brooklyn.location.jclouds.JcloudsMachineLocation;
-import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.util.collections.MutableList;
-import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool;
 import org.jclouds.compute.ComputeService;
 import org.jclouds.compute.domain.Template;
 import org.jclouds.compute.domain.TemplateBuilder;
@@ -49,7 +44,6 @@ import org.testng.annotations.Test;
 
 import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 
 /**
@@ -72,10 +66,8 @@ import com.google.common.collect.Lists;
  * }
  * </pre>
  */
-@Test(groups = {"Live", "Live-sanity"})
-public class JcloudsCustomizerInstantiationYamlDslTest extends JcloudsRebindStubYamlTest {
-
-    protected Entity origApp;
+@Test
+public class JcloudsCustomizerInstantiationYamlDslTest extends AbstractJcloudsStubYamlTest {
 
     @BeforeMethod(alwaysRun=true)
     @Override
@@ -94,20 +86,10 @@ public class JcloudsCustomizerInstantiationYamlDslTest extends JcloudsRebindStub
         }
     }
     
-    @Override
-    protected JcloudsLocation newJcloudsLocation(ComputeServiceRegistry computeServiceRegistry) throws Exception {
-        ByonComputeServiceStaticRef.setInstance(computeServiceRegistry);
-
+    @Test
+    public void testCustomizers() throws Exception {
         String yaml = Joiner.on("\n").join(
-                "location:",
-                "  " + LOCATION_SPEC + ":",
-                "    imageId: " + IMAGE_ID,
-                "    jclouds.computeServiceRegistry:",
-                "      $brooklyn:object:",
-                "        type: " + ByonComputeServiceStaticRef.class.getName(),
-                "    " + SshMachineLocation.SSH_TOOL_CLASS.getName() + ": " + RecordingSshTool.class.getName(),
-                "    waitForSshable: false",
-                "    useJcloudsSshInit: false",
+                "location: " + LOCATION_CATALOG_ID,
                 "services:\n" +
                 "- type: " + MachineEntity.class.getName(),
                 "  brooklyn.config:",
@@ -122,16 +104,10 @@ public class JcloudsCustomizerInstantiationYamlDslTest extends JcloudsRebindStub
                 "          object.fields:",
                 "            enabled: $brooklyn:config(\"enabled\")");
 
-        EntitySpec<?> spec = mgmt().getTypeRegistry().createSpecFromPlan(CampTypePlanTransformer.FORMAT, yaml, RegisteredTypeLoadingContexts.spec(Application.class), EntitySpec.class);
-        origApp = mgmt().getEntityManager().createEntity(spec);
-        
-        return (JcloudsLocation) Iterables.getOnlyElement(origApp.getLocations());
-    }
+        EntitySpec<?> spec = managementContext.getTypeRegistry().createSpecFromPlan(CampTypePlanTransformer.FORMAT, yaml, RegisteredTypeLoadingContexts.spec(Application.class), EntitySpec.class);
+        Entity app = managementContext.getEntityManager().createEntity(spec);
 
-    @Override
-    protected JcloudsMachineLocation obtainMachine(JcloudsLocation jcloudsLoc, Map<?, ?> props) throws Exception {
-        final MachineEntity entity = (MachineEntity) Iterables.getOnlyElement(origApp.getChildren());
-        origApp.invoke(Startable.START, ImmutableMap.<String, Object>of()).get();
+        app.invoke(Startable.START, ImmutableMap.<String, Object>of()).get();
 
         // Assert all customize functions called
         assertEquals(RecordingLocationCustomizer.calls.size(), 4,
@@ -142,14 +118,8 @@ public class JcloudsCustomizerInstantiationYamlDslTest extends JcloudsRebindStub
         for (RecordingLocationCustomizer.CallParams call : RecordingLocationCustomizer.calls) {
             assertSame(call.instance, firstInstance);
         }
-
-        JcloudsMachineLocation machine =
-                Machines.findUniqueMachineLocation(entity.getLocations(), JcloudsMachineLocation.class).get();
-
-        return machine;
     }
 
-
     public static class RecordingLocationCustomizer extends BasicJcloudsLocationCustomizer {
 
         public static final List<CallParams> calls = Lists.newCopyOnWriteArrayList();

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/70fd9bdf/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsExternalConfigYamlTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsExternalConfigYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsExternalConfigYamlTest.java
index a29a813..e5a5e46 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsExternalConfigYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsExternalConfigYamlTest.java
@@ -21,7 +21,9 @@ package org.apache.brooklyn.camp.brooklyn;
 import static org.testng.Assert.assertEquals;
 
 import java.io.StringReader;
+import java.util.Map;
 
+import org.apache.brooklyn.api.entity.Application;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.camp.brooklyn.ExternalConfigYamlTest.MyExternalConfigSupplier;
@@ -29,10 +31,10 @@ import org.apache.brooklyn.camp.brooklyn.ExternalConfigYamlTest.MyExternalConfig
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.StartableApplication;
-import org.apache.brooklyn.core.internal.BrooklynProperties;
 import org.apache.brooklyn.core.objs.BrooklynObjectInternal;
 import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess;
 import org.apache.brooklyn.location.jclouds.JcloudsLocation;
+import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.internal.ssh.SshTool;
 import org.apache.brooklyn.util.core.task.DeferredSupplier;
 import org.apache.brooklyn.util.guava.Maybe;
@@ -45,34 +47,35 @@ import com.google.common.base.Joiner;
 import com.google.common.collect.Iterables;
 
 // also see ExternalConfigYamlTest
-public class JcloudsExternalConfigYamlTest extends AbstractYamlRebindTest {
+public class JcloudsExternalConfigYamlTest extends AbstractJcloudsStubYamlTest {
 
     private static final Logger log = LoggerFactory.getLogger(JcloudsExternalConfigYamlTest.class);
 
     private static final ConfigKey<String> MY_CONFIG_KEY = ConfigKeys.newStringConfigKey("my.config.key");
-
+    
     @Override
-    protected BrooklynProperties createBrooklynProperties() {
-        BrooklynProperties props = BrooklynProperties.Factory.newDefault();
-        props.put("brooklyn.external.myprovider", MyExternalConfigSupplier.class.getName());
-        props.put("brooklyn.external.myprovider.mykey", "myval");
-        props.put("brooklyn.external.myproviderWithoutMapArg", MyExternalConfigSupplierWithoutMapArg.class.getName());
-        return props;
+    protected Map<String, ?> customBrooklynProperties() {
+        return MutableMap.<String, Object>builder()
+                .putAll(super.customBrooklynProperties())
+                .put("brooklyn.external.myprovider", MyExternalConfigSupplier.class.getName())
+                .put("brooklyn.external.myprovider.mykey", "myval")
+                .put("brooklyn.external.myproviderWithoutMapArg", MyExternalConfigSupplierWithoutMapArg.class.getName())
+                .build();
     }
 
-    @Test(groups="Live")
+    @Test
     public void testJcloudsInheritanceAndPasswordSecret() throws Exception {
         String yaml = Joiner.on("\n").join(
-                "services:",
-                "- type: "+EmptySoftwareProcess.class.getName(),
                 "location:",
-                "  jclouds:aws-ec2:",
+                "  " + LOCATION_CATALOG_ID + ":",
                 "    password: $brooklyn:external(\"myprovider\", \"mykey\")",
-                "    my.config.key: $brooklyn:external(\"myprovider\", \"mykey\")");
+                "    my.config.key: $brooklyn:external(\"myprovider\", \"mykey\")",
+                "services:",
+                "- type: "+EmptySoftwareProcess.class.getName());
 
-        origApp = (StartableApplication) createAndStartApplication(new StringReader(yaml));
+        Application app = (StartableApplication) createAndStartApplication(new StringReader(yaml));
 
-        Entity entity = Iterables.getOnlyElement( origApp.getChildren() );
+        Entity entity = Iterables.getOnlyElement( app.getChildren() );
         Location l = Iterables.getOnlyElement( entity.getLocations() );
         log.info("Location: "+l);
         assertEquals(l.config().get(MY_CONFIG_KEY), "myval");
@@ -88,21 +91,21 @@ public class JcloudsExternalConfigYamlTest extends AbstractYamlRebindTest {
         Assert.assertTrue(rawConfig.get() instanceof DeferredSupplier, "Expected deferred raw value; got "+rawConfig.get());
     }
 
-    @Test(groups="Live")
+    @Test
     public void testProvisioningPropertyInheritance() throws Exception {
         String yaml = Joiner.on("\n").join(
+                "location: " + LOCATION_CATALOG_ID,
                 "services:",
                 "- type: "+EmptySoftwareProcess.class.getName(),
                 "  provisioning.properties:",
                 "      password: $brooklyn:external(\"myprovider\", \"mykey\")",
                 // note that these 2 do not get transferred -- see below
                 "      simple: 42",
-                "      my.config.key: $brooklyn:external(\"myprovider\", \"mykey\")",
-                "location: aws-ec2");
+                "      my.config.key: $brooklyn:external(\"myprovider\", \"mykey\")");
 
-        origApp = (StartableApplication) createAndStartApplication(new StringReader(yaml));
+        StartableApplication app = (StartableApplication) createAndStartApplication(new StringReader(yaml));
 
-        Entity entity = Iterables.getOnlyElement( origApp.getChildren() );
+        Entity entity = Iterables.getOnlyElement( app.getChildren() );
         Location l = Iterables.getOnlyElement( entity.getLocations() );
         log.info("Location: "+l);
         assertEquals(l.config().get(JcloudsLocation.PASSWORD), "myval");

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/70fd9bdf/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsRebindStubYamlTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsRebindStubYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsRebindStubYamlTest.java
deleted file mode 100644
index c6fbcd1..0000000
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsRebindStubYamlTest.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * 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 org.apache.brooklyn.camp.brooklyn;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.io.File;
-
-import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
-import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
-import org.apache.brooklyn.location.jclouds.ComputeServiceRegistry;
-import org.apache.brooklyn.location.jclouds.JcloudsRebindStubTest;
-import org.testng.annotations.AfterMethod;
-
-/**
- * Implementation notes. This relies on the test {@link JcloudsRebindStubTest#testRebind()}.
- * It changes the setup for the test in the following ways:
- * <ul>
- *   <li>Location is defined in YAML, and refers to the external config for the identity/credential.
- *   <li>When creating management context, it also creates {@link BrooklynCampPlatformLauncherNoServer}.
- *   <li>It uses {@link JcloudsRebindStubYamlTest#ByonComputeServiceStaticRef} to allow
- *       the test's {@link ComputeServiceRegistry} to be wired up via YAML.
- * </ul>
- * 
- * See {@link JcloudsRebindStubTest} for explanation why this is "Live" - it will not create VMs,
- * but does retrieve list of images etc.
- */
-public abstract class JcloudsRebindStubYamlTest extends JcloudsRebindStubTest {
-
-    protected BrooklynCampPlatformLauncherNoServer origLauncher;
-    protected BrooklynCampPlatformLauncherNoServer newLauncher;
-
-    @Override
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        try {
-            super.tearDown();
-        } finally {
-            ByonComputeServiceStaticRef.clearInstance();
-            if (origLauncher != null) origLauncher.stopServers();
-            if (newLauncher != null) newLauncher.stopServers();
-        }
-    }
-    
-    @Override
-    protected LocalManagementContext createOrigManagementContext() {
-        origLauncher = new BrooklynCampPlatformLauncherNoServer() {
-            @Override
-            protected LocalManagementContext newMgmtContext() {
-                return JcloudsRebindStubYamlTest.super.createOrigManagementContext();
-            }
-        };
-        origLauncher.launch();
-        LocalManagementContext mgmt = (LocalManagementContext) origLauncher.getBrooklynMgmt();
-        return mgmt;
-    }
-
-    @Override
-    protected LocalManagementContext createNewManagementContext(final File mementoDir, final HighAvailabilityMode haMode) {
-        newLauncher = new BrooklynCampPlatformLauncherNoServer() {
-            @Override
-            protected LocalManagementContext newMgmtContext() {
-                return JcloudsRebindStubYamlTest.super.createNewManagementContext(mementoDir, haMode);
-            }
-        };
-        newLauncher.launch();
-        return (LocalManagementContext) newLauncher.getBrooklynMgmt();
-    }
-    
-    public static class ByonComputeServiceStaticRef {
-        private static volatile ComputeServiceRegistry instance;
-
-        public ComputeServiceRegistry asComputeServiceRegistry() {
-            return checkNotNull(instance, "instance");
-        }
-        static void setInstance(ComputeServiceRegistry val) {
-            instance = val;
-        }
-        static void clearInstance() {
-            instance = null;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/70fd9bdf/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 fd3baa0..3f48acb 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
@@ -18,13 +18,12 @@
  */
 package org.apache.brooklyn.camp.brooklyn;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.Map;
+import static org.testng.Assert.assertEquals;
 
 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.camp.brooklyn.AbstractJcloudsStubYamlTest.ByonComputeServiceStaticRef;
 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;
@@ -32,8 +31,6 @@ import org.apache.brooklyn.core.internal.BrooklynProperties;
 import org.apache.brooklyn.core.typereg.RegisteredTypeLoadingContexts;
 import org.apache.brooklyn.location.jclouds.ComputeServiceRegistry;
 import org.apache.brooklyn.location.jclouds.JcloudsLocation;
-import org.apache.brooklyn.location.jclouds.JcloudsPropertiesFromBrooklynProperties;
-import org.apache.brooklyn.util.collections.MutableMap;
 import org.testng.annotations.Test;
 
 import com.google.common.base.Joiner;
@@ -46,20 +43,15 @@ import com.google.common.collect.Iterables;
  *   <li>Brooklyn properties defines external config
  * </ul>
  */
-@Test(groups={"Live", "Live-sanity"})
-public class JcloudsRebindWithExternalConfigTest extends JcloudsRebindStubYamlTest {
+@Test
+public class JcloudsRebindWithExternalConfigTest extends AbstractJcloudsRebindStubYamlTest {
 
     @Override
     protected BrooklynProperties createBrooklynProperties() {
         BrooklynProperties result = super.createBrooklynProperties();
-        
-        Map<Object,Object> jcloudsProps = MutableMap.<Object,Object>copyOf(new JcloudsPropertiesFromBrooklynProperties().getJcloudsProperties(PROVIDER, null, "testname", result.asMapWithStringKeys()));
-        String identity = checkNotNull((String)jcloudsProps.get("identity"), "identity");
-        String credential = checkNotNull((String)jcloudsProps.get("credential"), "credential");
-        
         result.put("brooklyn.external.creds", InPlaceExternalConfigSupplier.class.getName());
-        result.put("brooklyn.external.creds.test-identity", identity);
-        result.put("brooklyn.external.creds.test-credential", credential);
+        result.put("brooklyn.external.creds.test-identity", "myidentity");
+        result.put("brooklyn.external.creds.test-credential", "mycredential");
         
         return result;
     }
@@ -70,15 +62,9 @@ public class JcloudsRebindWithExternalConfigTest extends JcloudsRebindStubYamlTe
         
         String yaml = Joiner.on("\n").join(
                 "location:",
-                "  "+LOCATION_SPEC+":",
+                "  "+LOCATION_CATALOG_ID+":",
                 "    identity: $brooklyn:external(\"creds\", \"test-identity\")",
                 "    credential: $brooklyn:external(\"creds\", \"test-credential\")",
-                "    imageId: "+IMAGE_ID,
-                "    jclouds.computeServiceRegistry:",
-                "      $brooklyn:object:",
-                "        type: "+ByonComputeServiceStaticRef.class.getName(),
-                "    waitForSshable: false",
-                "    useJcloudsSshInit: false",
                 "services:\n"+
                 "- type: org.apache.brooklyn.entity.stock.BasicApplication");
         
@@ -87,6 +73,10 @@ public class JcloudsRebindWithExternalConfigTest extends JcloudsRebindStubYamlTe
         final Entity app = mgmt().getEntityManager().createEntity(spec);
         app.invoke(Startable.START, ImmutableMap.<String, Object>of()).get();
 
-        return (JcloudsLocation) Iterables.getOnlyElement(app.getLocations());
+        JcloudsLocation result = (JcloudsLocation) Iterables.getOnlyElement(app.getLocations());
+        assertEquals(result.getIdentity(), "myidentity");
+        assertEquals(result.getCredential(), "mycredential");
+        
+        return result;
     }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/70fd9bdf/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsRebindWithYamlDslTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsRebindWithYamlDslTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsRebindWithYamlDslTest.java
index 5864a9a..593595b 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsRebindWithYamlDslTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/JcloudsRebindWithYamlDslTest.java
@@ -25,6 +25,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.camp.brooklyn.AbstractJcloudsStubYamlTest.ByonComputeServiceStaticRef;
 import org.apache.brooklyn.camp.brooklyn.spi.creation.CampTypePlanTransformer;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.location.Machines;
@@ -33,8 +34,6 @@ import org.apache.brooklyn.entity.machine.MachineEntity;
 import org.apache.brooklyn.location.jclouds.ComputeServiceRegistry;
 import org.apache.brooklyn.location.jclouds.JcloudsLocation;
 import org.apache.brooklyn.location.jclouds.JcloudsMachineLocation;
-import org.apache.brooklyn.location.jclouds.JcloudsRebindStubTest;
-import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool;
 import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool.ExecCmd;
 import org.testng.annotations.Test;
@@ -47,9 +46,6 @@ import com.google.common.collect.Iterables;
  * This is primarily to test https://issues.apache.org/jira/browse/BROOKLYN-349.
  * It confirms that entity "provisioning.properties" get passed through to the machine.
  * 
- * As per the other {@link JcloudsRebindStubTest} tests, it will connect to SoftLayer to retrieve
- * image details (so needs real credentials), but it will then stub out the VM creation.
- * 
  * It could do with some cleanup at some point:
  * <ul>
  *   <li>There is an NPE at AddMachineMetrics$2.apply(AddMachineMetrics.java:111), despite having set
@@ -61,8 +57,8 @@ import com.google.common.collect.Iterables;
  *       Presumably we need to stub out that call as well somehow!
  * </ul>
  */
-@Test(groups={"Live", "Live-sanity"})
-public class JcloudsRebindWithYamlDslTest extends JcloudsRebindStubYamlTest {
+@Test
+public class JcloudsRebindWithYamlDslTest extends AbstractJcloudsRebindStubYamlTest {
 
     protected Entity origApp;
     
@@ -84,15 +80,7 @@ public class JcloudsRebindWithYamlDslTest extends JcloudsRebindStubYamlTest {
         mgmt().getCatalog().addItems(catalogYaml, true);
 
         String yaml = Joiner.on("\n").join(
-                "location:",
-                "  "+LOCATION_SPEC+":",
-                "    imageId: "+IMAGE_ID,
-                "    jclouds.computeServiceRegistry:",
-                "      $brooklyn:object:",
-                "        type: "+ByonComputeServiceStaticRef.class.getName(),
-                "    "+SshMachineLocation.SSH_TOOL_CLASS.getName() + ": " + RecordingSshTool.class.getName(),
-                "    waitForSshable: false",
-                "    useJcloudsSshInit: false",
+                "location: " + LOCATION_CATALOG_ID,
                 "services:\n"+
                 "- type: "+symbolicName,
                 "  brooklyn.config:",

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/70fd9bdf/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java
index 4e2e7cc..bf2fb8d 100644
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsLiveTest.java
@@ -109,6 +109,10 @@ public class AbstractJcloudsLiveTest {
         }
     }
 
+    protected LocalManagementContext mgmt() {
+        return managementContext;
+    }
+    
     protected LocalManagementContext newManagementContext() {
         // loads properties, by default, but not OSGi or anything else
         return LocalManagementContextForTests.builder(true).useDefaultProperties().build();

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/70fd9bdf/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsStubbedUnitTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsStubbedUnitTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsStubbedUnitTest.java
index 0fa0e94..6b6f790 100644
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsStubbedUnitTest.java
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsStubbedUnitTest.java
@@ -19,28 +19,21 @@
 package org.apache.brooklyn.location.jclouds;
 
 import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
 import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
-import org.apache.brooklyn.location.jclouds.StubbedComputeServiceRegistry.AbstractNodeCreator;
+import org.apache.brooklyn.location.jclouds.StubbedComputeServiceRegistry.BasicNodeCreator;
 import org.apache.brooklyn.location.jclouds.StubbedComputeServiceRegistry.NodeCreator;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
 import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool;
 import org.apache.brooklyn.util.core.internal.winrm.RecordingWinRmTool;
-import org.jclouds.compute.domain.NodeMetadata;
-import org.jclouds.compute.domain.NodeMetadata.Status;
-import org.jclouds.compute.domain.NodeMetadataBuilder;
-import org.jclouds.compute.domain.Template;
-import org.jclouds.domain.LoginCredentials;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 
 import com.google.common.base.Predicates;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 
 /**
@@ -81,10 +74,17 @@ public abstract class AbstractJcloudsStubbedUnitTest extends AbstractJcloudsLive
 
     @Override
     protected LocalManagementContext newManagementContext() {
-        return LocalManagementContextForTests.builder(true).build();
+        return LocalManagementContextForTests.builder(true).useAdditionalProperties(customBrooklynProperties()).build();
     }
     
     /**
+     * For overriding.
+     */
+    protected Map<String, ?> customBrooklynProperties() {
+        return ImmutableMap.of();
+    }
+
+    /**
      * Expect sub-classes to call this - either in their {@link BeforeMethod} or at the very 
      * start of the test method (to allow custom config per test).
      */
@@ -113,22 +113,7 @@ public abstract class AbstractJcloudsStubbedUnitTest extends AbstractJcloudsLive
         return LOCATION_SPEC;
     }
     
-    protected NodeCreator newVanillaNodeCreator() {
-        return new AbstractNodeCreator() {
-            private final AtomicInteger counter = new AtomicInteger(1);
-            @Override
-            protected NodeMetadata newNode(String group, Template template) {
-                int suffix = counter.getAndIncrement();
-                NodeMetadata result = new NodeMetadataBuilder()
-                        .id("mynodeid"+suffix)
-                        .credentials(LoginCredentials.builder().identity("myuser").credential("mypassword").build())
-                        .loginPort(22)
-                        .status(Status.RUNNING)
-                        .publicAddresses(ImmutableList.of("173.194.32."+suffix))
-                        .privateAddresses(ImmutableList.of("172.168.10."+suffix))
-                        .build();
-                return result;
-            }
-        };
+    protected NodeCreator newNodeCreator() {
+        return new BasicNodeCreator();
     }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/70fd9bdf/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationExtensionStubbedTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationExtensionStubbedTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationExtensionStubbedTest.java
index c192297..7c20d5b 100644
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationExtensionStubbedTest.java
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationExtensionStubbedTest.java
@@ -54,7 +54,7 @@ public class JcloudsLocationExtensionStubbedTest extends AbstractJcloudsStubbedU
 
     @Test
     public void testHasExtension() throws Exception {
-        initNodeCreatorAndJcloudsLocation(newVanillaNodeCreator(), ImmutableMap.of());
+        initNodeCreatorAndJcloudsLocation(newNodeCreator(), ImmutableMap.of());
         MachineLocation machine = jcloudsLocation.obtain();
         
         HttpExecutorFactory extension = machine.getExtension(HttpExecutorFactory.class);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/70fd9bdf/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsRebindStubUnitTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsRebindStubUnitTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsRebindStubUnitTest.java
new file mode 100644
index 0000000..e7bf4d8
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsRebindStubUnitTest.java
@@ -0,0 +1,212 @@
+/*
+ * 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 org.apache.brooklyn.location.jclouds;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.internal.BrooklynProperties;
+import org.apache.brooklyn.core.mgmt.rebind.RebindTestFixtureWithApp;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.location.jclouds.StubbedComputeServiceRegistry.BasicNodeCreator;
+import org.apache.brooklyn.location.jclouds.StubbedComputeServiceRegistry.NodeCreator;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
+import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool;
+import org.apache.brooklyn.util.core.internal.winrm.RecordingWinRmTool;
+import org.apache.brooklyn.util.exceptions.CompoundRuntimeException;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.Template;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Predicates;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+
+/**
+ * Tests rebind (i.e. restarting Brooklyn server) when there are JcloudsSshMachineLocation object(s).
+ * 
+ * It is just a unit test, because it uses the StubbedComputeServiceRegistry.
+ */
+public class JcloudsRebindStubUnitTest extends RebindTestFixtureWithApp {
+
+    // TODO Duplication of JcloudsRebindStubTest, and AbstractJcloudsStubbedUnitTest
+    
+    // TODO The ByonComputeServiceRegistry extends ComputeServiceRegistryImpl, which means when it  
+    // is serialized it will try to serialize the cachedComputeServices. That will try to serialize 
+    // threads and all sorts!
+
+    private static final Logger LOG = LoggerFactory.getLogger(JcloudsRebindStubUnitTest.class);
+
+    public static final String PROVIDER = AbstractJcloudsLiveTest.AWS_EC2_PROVIDER;
+    public static final String REGION = "us-east-1";
+    public static final String LOCATION_SPEC = "jclouds:" + PROVIDER + ":" + REGION;
+    public static final String IMAGE_ID = REGION + "/bogus-image"; // matches name in JcloudsStubTemplateBuilder
+    
+    protected List<ManagementContext> mgmts;
+    protected Multimap<ManagementContext, JcloudsSshMachineLocation> machines;
+    protected BrooklynProperties brooklynProperties;
+
+    // TODO These values are hard-coded into the JcloudsStubTemplateBuilder, so best not to mess!
+    
+    protected NodeCreator nodeCreator;
+    protected ComputeServiceRegistry computeServiceRegistry;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        super.setUp();
+        RecordingSshTool.clear();
+        RecordingWinRmTool.clear();
+        mgmts = Lists.newCopyOnWriteArrayList(ImmutableList.<ManagementContext>of(origManagementContext));
+        machines = Multimaps.synchronizedMultimap(ArrayListMultimap.<ManagementContext, JcloudsSshMachineLocation>create());
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        try {
+            List<Exception> exceptions = Lists.newArrayList();
+            for (ManagementContext mgmt : mgmts) {
+                try {
+                    if (mgmt.isRunning()) Entities.destroyAll(mgmt);
+                } catch (Exception e) {
+                    LOG.warn("Error destroying management context", e);
+                    exceptions.add(e);
+                }
+            }
+            
+            super.tearDown();
+            
+            if (exceptions.size() > 0) {
+                throw new CompoundRuntimeException("Error in tearDown of "+getClass(), exceptions);
+            }
+        } finally {
+            mgmts.clear();
+            origManagementContext = null;
+            newManagementContext = null;
+            origApp = null;
+            newApp = null;
+            RecordingSshTool.clear();
+            RecordingWinRmTool.clear();
+        }
+    }
+
+
+    @Override
+    protected BrooklynProperties createBrooklynProperties() {
+        // Don't let any defaults from brooklyn.properties (except credentials) interfere with test
+        BrooklynProperties result = super.createBrooklynProperties();
+        AbstractJcloudsLiveTest.stripBrooklynProperties(result);
+        return result;
+    }
+    
+    @Override
+    protected boolean useLiveManagementContext() {
+        return false;
+    }
+
+    @Override
+    protected TestApplication rebind() throws Exception {
+        TestApplication result = super.rebind();
+        mgmts.add(newManagementContext);
+        return result;
+    }
+
+    @Test
+    public void testRebind() throws Exception {
+        this.nodeCreator = newNodeCreator();
+        this.computeServiceRegistry = new StubbedComputeServiceRegistry(nodeCreator, false);
+
+        JcloudsLocation origJcloudsLoc = newJcloudsLocation(computeServiceRegistry);
+    
+        JcloudsSshMachineLocation origMachine = (JcloudsSshMachineLocation) obtainMachine(origJcloudsLoc, ImmutableMap.of("imageId", IMAGE_ID));
+        
+        String origHostname = origMachine.getHostname();
+        NodeMetadata origNode = origMachine.getNode();
+        Template origTemplate = origMachine.getTemplate();
+
+        rebind();
+        
+        // Check the machine is as before.
+        // Call to getOptionalNode() will cause it to try to resolve this node in Softlayer; but it won't find it.
+        JcloudsSshMachineLocation newMachine = (JcloudsSshMachineLocation) mgmt().getLocationManager().getLocation(origMachine.getId());
+        JcloudsLocation newJcloudsLoc = newMachine.getParent();
+        String newHostname = newMachine.getHostname();
+        String newNodeId = newMachine.getJcloudsId();
+        Optional<NodeMetadata> newNode = newMachine.getOptionalNode();
+        Optional<Template> newTemplate = newMachine.getOptionalTemplate();
+        
+        assertEquals(newHostname, origHostname);
+        assertEquals(origNode.getId(), newNodeId);
+        assertFalse(newNode.isPresent(), "newNode="+newNode);
+        assertFalse(newTemplate.isPresent(), "newTemplate="+newTemplate);
+        
+        assertEquals(newJcloudsLoc.getProvider(), origJcloudsLoc.getProvider());
+    }
+    
+    protected JcloudsMachineLocation obtainMachine(JcloudsLocation jcloudsLoc, Map<?,?> props) throws Exception {
+        return (JcloudsMachineLocation) jcloudsLoc.obtain(ImmutableMap.of("imageId", IMAGE_ID));
+    }
+
+    protected JcloudsLocation newJcloudsLocation(ComputeServiceRegistry computeServiceRegistry) throws Exception {
+        return newJcloudsLocation(computeServiceRegistry, ImmutableMap.of());
+    }
+    
+    protected JcloudsLocation newJcloudsLocation(ComputeServiceRegistry computeServiceRegistry, Map<?, ?> jcloudsLocationConfig) throws Exception {
+        return (JcloudsLocation) mgmt().getLocationRegistry().getLocationManaged(
+                getLocationSpec(),
+                ImmutableMap.builder()
+                        .put(JcloudsLocationConfig.COMPUTE_SERVICE_REGISTRY, computeServiceRegistry)
+                        .put(JcloudsLocationConfig.TEMPLATE_BUILDER, JcloudsStubTemplateBuilder.create())
+                        .put(JcloudsLocationConfig.ACCESS_IDENTITY, "stub-identity")
+                        .put(JcloudsLocationConfig.ACCESS_CREDENTIAL, "stub-credential")
+                        .put(SshMachineLocation.SSH_TOOL_CLASS, RecordingSshTool.class.getName())
+                        .put(WinRmMachineLocation.WINRM_TOOL_CLASS, RecordingWinRmTool.class.getName())
+                        .put(JcloudsLocation.POLL_FOR_FIRST_REACHABLE_ADDRESS_PREDICATE, Predicates.alwaysTrue())
+                        .putAll(jcloudsLocationConfig)
+                        .build());
+    }
+    
+    /**
+     * For overriding.
+     */
+    protected NodeCreator newNodeCreator() {
+        return new BasicNodeCreator();
+    }
+    
+    /**
+     * For overriding.
+     */
+    protected String getLocationSpec() {
+        return LOCATION_SPEC;
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/70fd9bdf/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsStubTemplateBuilder.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsStubTemplateBuilder.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsStubTemplateBuilder.java
index 149d0f4..bea98f3 100644
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsStubTemplateBuilder.java
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsStubTemplateBuilder.java
@@ -21,6 +21,7 @@ package org.apache.brooklyn.location.jclouds;
 import com.google.common.base.Functions;
 import com.google.common.base.Supplier;
 import com.google.common.base.Suppliers;
+import com.google.common.base.Objects.ToStringHelper;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
@@ -99,6 +100,10 @@ public class JcloudsStubTemplateBuilder {
 
         return new EC2TemplateBuilderImpl(locations, new ImageCacheSupplier(images, 60), sizes, Suppliers.ofInstance(jcloudsDomainLocation), optionsProvider,
                 templateBuilderProvider, getImageStrategy, imageCache) {
+            @Override
+            protected ToStringHelper string() {
+                return super.string().add("type", "Stubbed-TemplateBuilder");
+            }
         };
     }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/70fd9bdf/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/StubbedComputeServiceRegistry.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/StubbedComputeServiceRegistry.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/StubbedComputeServiceRegistry.java
index 99cd321..9dee5ef 100644
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/StubbedComputeServiceRegistry.java
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/StubbedComputeServiceRegistry.java
@@ -20,16 +20,21 @@ package org.apache.brooklyn.location.jclouds;
 
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.jclouds.compute.ComputeService;
 import org.jclouds.compute.RunNodesException;
 import org.jclouds.compute.domain.ComputeMetadata;
 import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.NodeMetadata.Status;
+import org.jclouds.compute.domain.NodeMetadataBuilder;
 import org.jclouds.compute.domain.Template;
 import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.domain.LoginCredentials;
 
 import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
@@ -78,6 +83,23 @@ public class StubbedComputeServiceRegistry implements ComputeServiceRegistry {
         }
     }
 
+    public static class BasicNodeCreator extends AbstractNodeCreator {
+        private final AtomicInteger counter = new AtomicInteger(1);
+        @Override
+        protected NodeMetadata newNode(String group, Template template) {
+            int suffix = counter.getAndIncrement();
+            NodeMetadata result = new NodeMetadataBuilder()
+                    .id("mynodeid"+suffix)
+                    .credentials(LoginCredentials.builder().identity("myuser").credential("mypassword").build())
+                    .loginPort(22)
+                    .status(Status.RUNNING)
+                    .publicAddresses(ImmutableList.of("173.194.32."+suffix))
+                    .privateAddresses(ImmutableList.of("172.168.10."+suffix))
+                    .build();
+            return result;
+        }
+    }
+
     static class MinimalComputeService extends DelegatingComputeService {
         private final NodeCreator nodeCreator;
         

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/70fd9bdf/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/JcloudsPortForwardingStubbedTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/JcloudsPortForwardingStubbedTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/JcloudsPortForwardingStubbedTest.java
index 22cea5a..737ebcf 100644
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/JcloudsPortForwardingStubbedTest.java
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/JcloudsPortForwardingStubbedTest.java
@@ -77,7 +77,7 @@ public class JcloudsPortForwardingStubbedTest extends AbstractJcloudsStubbedUnit
     @Override
     public void setUp() throws Exception {
         super.setUp();
-        initNodeCreatorAndJcloudsLocation(newVanillaNodeCreator(), ImmutableMap.of());
+        initNodeCreatorAndJcloudsLocation(newNodeCreator(), ImmutableMap.of());
     }
     
     protected AbstractNodeCreator getNodeCreator() {