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/10/04 14:43:52 UTC

[4/5] brooklyn-server git commit: JcloudsReachableAddressStubbedTest is now a unit test

JcloudsReachableAddressStubbedTest is now a unit test

- verify it chooses first Public address when
  POLL_FOR_FIRST_REACHABLE_ADDRESS, is false


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

Branch: refs/heads/master
Commit: 1adc2187fb47bc2af16ddcd553aef7d6b5eddeff
Parents: b8c4b39
Author: Valentin Aitken <bo...@gmail.com>
Authored: Mon Oct 3 17:54:24 2016 +0300
Committer: Valentin Aitken <bo...@gmail.com>
Committed: Tue Oct 4 17:12:32 2016 +0300

----------------------------------------------------------------------
 .../location/ssh/SshMachineLocationTest.java    |   2 +-
 .../location/jclouds/JcloudsLocation.java       |   5 +
 .../jclouds/JcloudsStubTemplateBuilder.java     | 104 ++++++
 .../JcloudsReachableAddressStubbedLiveTest.java | 337 -----------------
 .../JcloudsReachableAddressStubbedTest.java     | 369 +++++++++++++++++++
 5 files changed, 479 insertions(+), 338 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/1adc2187/core/src/test/java/org/apache/brooklyn/location/ssh/SshMachineLocationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/location/ssh/SshMachineLocationTest.java b/core/src/test/java/org/apache/brooklyn/location/ssh/SshMachineLocationTest.java
index c9d8ef7..82d9001 100644
--- a/core/src/test/java/org/apache/brooklyn/location/ssh/SshMachineLocationTest.java
+++ b/core/src/test/java/org/apache/brooklyn/location/ssh/SshMachineLocationTest.java
@@ -175,7 +175,7 @@ public class SshMachineLocationTest extends BrooklynAppUnitTestSupport {
         assertNull(details);
     }
     public static class FailingSshTool extends RecordingSshTool {
-        public FailingSshTool(Map<?, ?> props) {
+        public FailingSshTool(Map<String, ?> props) {
             super(props);
         }
         @Override public int execScript(Map<String, ?> props, List<String> commands, Map<String, ?> env) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/1adc2187/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
index 0fd1697..2fd12a8 100644
--- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
@@ -3354,6 +3354,11 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
 
     private Maybe<String> getHostnameAws(NodeMetadata node, Optional<HostAndPort> sshHostAndPort, Supplier<? extends LoginCredentials> userCredentials, ConfigBag setup) {
         HostAndPort inferredHostAndPort = null;
+        boolean waitForSshable = !"false".equalsIgnoreCase(setup.get(WAIT_FOR_SSHABLE));
+        if (!waitForSshable) {
+            return Maybe.absent();
+        }
+
         if (!sshHostAndPort.isPresent()) {
             try {
                 String vmIp = getFirstReachableAddress(node, setup);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/1adc2187/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
new file mode 100644
index 0000000..149d0f4
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsStubTemplateBuilder.java
@@ -0,0 +1,104 @@
+/*
+ * 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 com.google.common.base.Functions;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import org.jclouds.compute.domain.*;
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.compute.strategy.GetImageStrategy;
+import org.jclouds.compute.suppliers.ImageCacheSupplier;
+import org.jclouds.domain.Location;
+import org.jclouds.domain.LocationBuilder;
+import org.jclouds.domain.LocationScope;
+import org.jclouds.domain.LoginCredentials;
+import org.jclouds.ec2.compute.domain.RegionAndName;
+import org.jclouds.ec2.compute.functions.ImagesToRegionAndIdMap;
+import org.jclouds.ec2.compute.internal.EC2TemplateBuilderImpl;
+import org.jclouds.ec2.domain.RootDeviceType;
+import org.jclouds.ec2.domain.VirtualizationType;
+
+import javax.inject.Provider;
+import java.util.Set;
+
+import static org.jclouds.ec2.compute.domain.EC2HardwareBuilder.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class JcloudsStubTemplateBuilder {
+    protected final Location provider = new LocationBuilder().scope(LocationScope.PROVIDER).id("aws-ec2").description("aws-ec2").build();
+    protected final Location jcloudsDomainLocation = new LocationBuilder().scope(LocationScope.REGION).id("us-east-1").description("us-east-1")
+            .parent(provider).build();
+
+    protected final Hardware HARDWARE_SUPPORTING_BOGUS = t2_micro().id("supporting-bogus")
+            .supportsImageIds(ImmutableSet.of("us-east-1/bogus-image"))
+            .virtualizationType(VirtualizationType.PARAVIRTUAL)
+            .rootDeviceType(RootDeviceType.EBS)
+            .build();
+
+    public static TemplateBuilder create() {
+        return new JcloudsStubTemplateBuilder().createTemplateBuilder();
+    }
+
+    public TemplateBuilder createTemplateBuilder() {
+        final Supplier<Set<? extends Image>> images = Suppliers.<Set<? extends Image>> ofInstance(ImmutableSet.of(
+                new ImageBuilder().providerId("ebs-image-provider").name("image")
+                        .id("us-east-1/bogus-image").location(jcloudsDomainLocation)
+                        .userMetadata(ImmutableMap.of("rootDeviceType", RootDeviceType.EBS.value()))
+                        .operatingSystem(new OperatingSystem(OsFamily.UBUNTU, null, "1.0", VirtualizationType.PARAVIRTUAL.value(), "ubuntu", true))
+                        .description("description").version("1.0").defaultCredentials(LoginCredentials.builder().user("root").build())
+                        .status(Image.Status.AVAILABLE)
+                        .build()));
+        ImmutableMap<RegionAndName, Image> imageMap = (ImmutableMap<RegionAndName, Image>) ImagesToRegionAndIdMap.imagesToMap(images.get());
+        Supplier<LoadingCache<RegionAndName, ? extends Image>> imageCache = Suppliers.<LoadingCache<RegionAndName, ? extends Image>> ofInstance(
+                CacheBuilder.newBuilder().<RegionAndName, Image>build(CacheLoader.from(Functions.forMap(imageMap))));
+        JcloudsStubTemplateBuilder jcloudsStubTemplateBuilder = new JcloudsStubTemplateBuilder();
+        return jcloudsStubTemplateBuilder.newTemplateBuilder(images, imageCache);
+    }
+
+    /**
+     * Used source from jclouds project.
+     * {@link org.jclouds.ec2.compute.EC2TemplateBuilderTest#newTemplateBuilder}
+     */
+    @SuppressWarnings("unchecked")
+    protected TemplateBuilder newTemplateBuilder(Supplier<Set<? extends Image>> images, Supplier<LoadingCache<RegionAndName, ? extends Image>> imageCache) {
+
+        Provider<TemplateOptions> optionsProvider = mock(Provider.class);
+        Provider<TemplateBuilder> templateBuilderProvider = mock(Provider.class);
+        TemplateOptions defaultOptions = mock(TemplateOptions.class);
+        GetImageStrategy getImageStrategy = mock(GetImageStrategy.class);
+
+        when(optionsProvider.get()).thenReturn(defaultOptions);
+
+        Supplier<Set<? extends Location>> locations = Suppliers.<Set<? extends Location>> ofInstance(ImmutableSet
+                .of(jcloudsDomainLocation));
+        Supplier<Set<? extends Hardware>> sizes = Suppliers.<Set<? extends Hardware>> ofInstance(ImmutableSet
+                .of(HARDWARE_SUPPORTING_BOGUS));
+
+        return new EC2TemplateBuilderImpl(locations, new ImageCacheSupplier(images, 60), sizes, Suppliers.ofInstance(jcloudsDomainLocation), optionsProvider,
+                templateBuilderProvider, getImageStrategy, imageCache) {
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/1adc2187/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/JcloudsReachableAddressStubbedLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/JcloudsReachableAddressStubbedLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/JcloudsReachableAddressStubbedLiveTest.java
deleted file mode 100644
index 65829e4..0000000
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/JcloudsReachableAddressStubbedLiveTest.java
+++ /dev/null
@@ -1,337 +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.location.jclouds.networking;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.location.access.PortForwardManager;
-import org.apache.brooklyn.core.location.access.PortForwardManagerImpl;
-import org.apache.brooklyn.location.jclouds.AbstractJcloudsStubbedLiveTest;
-import org.apache.brooklyn.location.jclouds.JcloudsLocation;
-import org.apache.brooklyn.location.jclouds.JcloudsLocationConfig;
-import org.apache.brooklyn.location.jclouds.JcloudsSshMachineLocation;
-import org.apache.brooklyn.location.jclouds.StubbedComputeServiceRegistry.AbstractNodeCreator;
-import org.apache.brooklyn.location.jclouds.networking.JcloudsPortForwardingStubbedLiveTest.RecordingJcloudsPortForwarderExtension;
-import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.test.Asserts;
-import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool;
-import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool.CustomResponse;
-import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool.CustomResponseGenerator;
-import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool.ExecParams;
-import org.apache.brooklyn.util.net.Cidr;
-import org.apache.brooklyn.util.net.Protocol;
-import org.apache.brooklyn.util.core.internal.ssh.SshTool;
-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 org.testng.annotations.Test;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-import com.google.common.net.HostAndPort;
-
-/**
- * The VM creation is stubbed out, but it still requires live access (i.e. real account credentials)
- * to generate the template etc.
- * 
- * Simulates the creation of a VM that has multiple IPs. Checks that we choose the right address.
- * 
- */
-public class JcloudsReachableAddressStubbedLiveTest extends AbstractJcloudsStubbedLiveTest {
-
-    // TODO Aim is to test the various situations/permutations, where we pass in different config.
-    // More tests still need to be added.
-
-    @SuppressWarnings("unused")
-    private static final Logger LOG = LoggerFactory.getLogger(JcloudsReachableAddressStubbedLiveTest.class);
-
-    protected String reachableIp;
-    protected List<String> publicAddresses;
-    protected List<String> privateAddresses;
-    protected AddressChooser addressChooser;
-    protected CustomResponseGeneratorImpl customResponseGenerator;
-
-    
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        reachableIp = null; // expect test method to set this
-        publicAddresses = null; // expect test method to set this
-        privateAddresses = null; // expect test method to set this
-        addressChooser = new AddressChooser();
-        customResponseGenerator = new CustomResponseGeneratorImpl();
-        RecordingSshTool.clear();
-        super.setUp();
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    @Override
-    public void tearDown() throws Exception {
-        try {
-            super.tearDown();
-        } finally {
-            RecordingSshTool.clear();
-        }
-    }
-    
-    @Override
-    protected AbstractNodeCreator newNodeCreator() {
-        return new AbstractNodeCreator() {
-            int nextIpSuffix = 2;
-            @Override
-            protected NodeMetadata newNode(String group, Template template) {
-                int ipSuffix = nextIpSuffix++;
-                NodeMetadata result = new NodeMetadataBuilder()
-                        .id("myid-"+ipSuffix)
-                        .credentials(LoginCredentials.builder().identity("myuser").credential("mypassword").build())
-                        .loginPort(22)
-                        .status(Status.RUNNING)
-                        .publicAddresses(publicAddresses)
-                        .privateAddresses(privateAddresses)
-                        .build();
-                return result;
-            }
-        };
-    }
-
-    protected AbstractNodeCreator getNodeCreator() {
-        return (AbstractNodeCreator) nodeCreator;
-    }
-    
-    /**
-     * Only one public and one private; public is reachable;
-     * With waitForSshable=true; pollForFirstReachableAddress=true; and custom reachable-predicate
-     */
-    @Test(groups = {"Live", "Live-sanity"})
-    protected void testMachineUsesVanillaPublicAddress() throws Exception {
-        publicAddresses = ImmutableList.of("1.1.1.1");
-        privateAddresses = ImmutableList.<String>of("2.1.1.1");
-        reachableIp = "1.1.1.1";
-
-        JcloudsSshMachineLocation machine = newMachine(ImmutableMap.<ConfigKey<?>,Object>builder()
-                .put(JcloudsLocationConfig.WAIT_FOR_SSHABLE, Asserts.DEFAULT_LONG_TIMEOUT.toString())
-                .put(JcloudsLocation.POLL_FOR_FIRST_REACHABLE_ADDRESS, Asserts.DEFAULT_LONG_TIMEOUT.toString())
-                .build());
-        
-        addressChooser.assertCalled();
-        assertEquals(RecordingSshTool.getLastExecCmd().constructorProps.get(SshTool.PROP_HOST.getName()), reachableIp);
-
-        assertEquals(machine.getAddress().getHostAddress(), reachableIp);
-        assertEquals(machine.getHostname(), reachableIp);
-        assertEquals(machine.getSubnetIp(), "2.1.1.1");
-    }
-
-    /**
-     * Only one public and one private; private is reachable;
-     * With waitForSshable=true; pollForFirstReachableAddress=true; and custom reachable-predicate
-     */
-    @Test(groups = {"Live", "Live-sanity"})
-    protected void testMachineUsesVanillaPrivateAddress() throws Exception {
-        publicAddresses = ImmutableList.of("1.1.1.1");
-        privateAddresses = ImmutableList.<String>of("2.1.1.1");
-        reachableIp = "2.1.1.1";
-
-        JcloudsSshMachineLocation machine = newMachine(ImmutableMap.<ConfigKey<?>,Object>builder()
-                .put(JcloudsLocationConfig.WAIT_FOR_SSHABLE, Asserts.DEFAULT_LONG_TIMEOUT.toString())
-                .put(JcloudsLocation.POLL_FOR_FIRST_REACHABLE_ADDRESS, Asserts.DEFAULT_LONG_TIMEOUT.toString())
-                .build());
-        
-        addressChooser.assertCalled();
-        assertEquals(RecordingSshTool.getLastExecCmd().constructorProps.get(SshTool.PROP_HOST.getName()), reachableIp);
-
-        assertEquals(machine.getAddress().getHostAddress(), reachableIp);
-        assertEquals(machine.getHostname(), reachableIp);
-        assertEquals(machine.getSubnetIp(), reachableIp);
-    }
-
-    /**
-     * Multiple public addresses; chooses the reachable one;
-     * With waitForSshable=true; pollForFirstReachableAddress=true; and custom reachable-predicate
-     */
-    @Test(enabled=false, groups = {"Live", "Live-sanity"})
-    protected void testMachineUsesReachablePublicAddress() throws Exception {
-        publicAddresses = ImmutableList.of("1.1.1.1", "1.1.1.2", "1.1.1.2");
-        privateAddresses = ImmutableList.<String>of("2.1.1.1");
-        reachableIp = "1.1.1.2";
-
-        JcloudsSshMachineLocation machine = newMachine(ImmutableMap.<ConfigKey<?>,Object>builder()
-                .put(JcloudsLocationConfig.WAIT_FOR_SSHABLE, Asserts.DEFAULT_LONG_TIMEOUT.toString())
-                .put(JcloudsLocation.POLL_FOR_FIRST_REACHABLE_ADDRESS, Asserts.DEFAULT_LONG_TIMEOUT.toString())
-                .build());
-        
-        addressChooser.assertCalled();
-        assertEquals(RecordingSshTool.getLastExecCmd().constructorProps.get(SshTool.PROP_HOST.getName()), reachableIp);
-
-        assertEquals(machine.getAddress().getHostAddress(), reachableIp);
-        assertEquals(machine.getHostname(), reachableIp);
-        assertEquals(machine.getSubnetIp(), "2.1.1.1");
-    }
-
-    /**
-     * Multiple private addresses; chooses the reachable one;
-     * With waitForSshable=true; pollForFirstReachableAddress=true; and custom reachable-predicate
-     */
-    @Test(enabled=false, groups = {"Live", "Live-sanity"})
-    protected void testMachineUsesReachablePrivateAddress() throws Exception {
-        publicAddresses = ImmutableList.<String>of("1.1.1.1");
-        privateAddresses = ImmutableList.of("2.1.1.1", "2.1.1.2", "2.1.1.2");
-        reachableIp = "2.1.1.2";
-
-        JcloudsSshMachineLocation machine = newMachine(ImmutableMap.<ConfigKey<?>,Object>builder()
-                .put(JcloudsLocationConfig.WAIT_FOR_SSHABLE, Asserts.DEFAULT_LONG_TIMEOUT.toString())
-                .put(JcloudsLocation.POLL_FOR_FIRST_REACHABLE_ADDRESS, Asserts.DEFAULT_LONG_TIMEOUT.toString())
-                .build());
-        
-        addressChooser.assertCalled();
-        assertEquals(RecordingSshTool.getLastExecCmd().constructorProps.get(SshTool.PROP_HOST.getName()), reachableIp);
-
-        assertEquals(machine.getAddress().getHostAddress(), reachableIp);
-        assertEquals(machine.getHostname(), reachableIp);
-        assertEquals(machine.getSubnetIp(), reachableIp);
-    }
-
-    /**
-     * No waitForSshable: should not try to ssh.
-     * Therefore will also not search for reachable address (as that expects loginPort to be reachable).
-     */
-    @Test(groups = {"Live", "Live-sanity"})
-    protected void testNoWaitFroSshable() throws Exception {
-        publicAddresses = ImmutableList.of("1.1.1.1", "1.1.1.2", "1.1.1.2");
-        privateAddresses = ImmutableList.<String>of("2.1.1.1");
-        reachableIp = "1.1.1.2";
-
-        JcloudsSshMachineLocation machine = newMachine(ImmutableMap.<ConfigKey<?>,Object>builder()
-                .put(JcloudsLocationConfig.WAIT_FOR_SSHABLE, "false")
-                .put(JcloudsLocation.POLL_FOR_FIRST_REACHABLE_ADDRESS, Asserts.DEFAULT_LONG_TIMEOUT.toString())
-                .build());
-        
-        addressChooser.assertNotCalled();
-        assertTrue(RecordingSshTool.getExecCmds().isEmpty());
-
-        assertEquals(machine.getAddress().getHostAddress(), reachableIp);
-        assertEquals(machine.getHostname(), reachableIp);
-        assertEquals(machine.getSubnetIp(), "2.1.1.1");
-    }
-
-    /**
-     * No pollForFirstReachableAddress: should use first public IP.
-     */
-    @Test(groups = {"Live", "Live-sanity"})
-    protected void testNoPollForFirstReachable() throws Exception {
-        publicAddresses = ImmutableList.of("1.1.1.1", "1.1.1.2", "1.1.1.2");
-        privateAddresses = ImmutableList.<String>of("2.1.1.1");
-        reachableIp = null;
-
-        JcloudsSshMachineLocation machine = newMachine(ImmutableMap.<ConfigKey<?>,Object>builder()
-                .put(JcloudsLocationConfig.WAIT_FOR_SSHABLE, "false")
-                .put(JcloudsLocation.POLL_FOR_FIRST_REACHABLE_ADDRESS, "false")
-                .build());
-        
-        addressChooser.assertNotCalled();
-        assertTrue(RecordingSshTool.getExecCmds().isEmpty());
-
-        assertEquals(machine.getAddress().getHostAddress(), "1.1.1.1");
-        assertEquals(machine.getHostname(), "1.1.1.1");
-        assertEquals(machine.getSubnetIp(), "2.1.1.1");
-    }
-
-    // TODO What is the right behaviour for getHostname?
-    @Test(groups = {"Live", "Live-sanity"})
-    protected void testReachabilityChecksWithPortForwarding() throws Exception {
-        publicAddresses = ImmutableList.of("1.1.1.1");
-        privateAddresses = ImmutableList.<String>of("2.1.1.1");
-        reachableIp = "1.2.3.4";
-                
-        PortForwardManager pfm = new PortForwardManagerImpl();
-        RecordingJcloudsPortForwarderExtension portForwarder = new RecordingJcloudsPortForwarderExtension(pfm);
-        
-        JcloudsSshMachineLocation machine = newMachine(ImmutableMap.<ConfigKey<?>,Object>builder()
-                .put(JcloudsLocationConfig.WAIT_FOR_SSHABLE, Asserts.DEFAULT_LONG_TIMEOUT.toString())
-                .put(JcloudsLocation.POLL_FOR_FIRST_REACHABLE_ADDRESS, Asserts.DEFAULT_LONG_TIMEOUT.toString())
-                .put(JcloudsLocation.USE_PORT_FORWARDING, true)
-                .put(JcloudsLocation.PORT_FORWARDER, portForwarder)
-                .build());
-        
-        addressChooser.assertNotCalled();
-        assertEquals(RecordingSshTool.getLastExecCmd().constructorProps.get(SshTool.PROP_HOST.getName()), reachableIp);
-        assertEquals(RecordingSshTool.getLastExecCmd().constructorProps.get(SshTool.PROP_PORT.getName()), 12345);
-
-        assertEquals(machine.getAddress().getHostAddress(), "1.2.3.4");
-        assertEquals(machine.getPort(), 12345);
-        assertEquals(machine.getSshHostAndPort(), HostAndPort.fromParts("1.2.3.4", 12345));
-        assertEquals(machine.getHostname(), "1.1.1.1");
-        assertEquals(machine.getSubnetIp(), "2.1.1.1");
-    }
-    
-    protected JcloudsSshMachineLocation newMachine() throws Exception {
-        return newMachine(ImmutableMap.<ConfigKey<?>, Object>of());
-    }
-    
-    protected JcloudsSshMachineLocation newMachine(Map<? extends ConfigKey<?>, ?> additionalConfig) throws Exception {
-        return obtainMachine(ImmutableMap.<ConfigKey<?>,Object>builder()
-                .put(SshMachineLocation.SSH_TOOL_CLASS, RecordingSshTool.class.getName())
-                .put(JcloudsLocation.POLL_FOR_FIRST_REACHABLE_ADDRESS_PREDICATE, addressChooser)
-                .putAll(additionalConfig)
-                .build());
-    }
-    
-    protected class AddressChooser implements Predicate<HostAndPort> {
-        final List<HostAndPort> calls = Lists.newCopyOnWriteArrayList();
-        
-        @Override public boolean apply(HostAndPort input) {
-            calls.add(input);
-            return reachableIp != null && reachableIp.equals(input.getHostText());
-        }
-        
-        public void assertCalled() {
-            assertTrue(calls.size() > 0, "no calls to "+this);
-        }
-        
-        public void assertNotCalled() {
-            assertTrue(calls.isEmpty(), "unexpected calls to "+this+": "+calls);
-        }
-    }
-    
-    protected class CustomResponseGeneratorImpl implements CustomResponseGenerator {
-        @Override public CustomResponse generate(ExecParams execParams) throws Exception {
-            System.out.println("ssh call: "+execParams);
-            Object host = execParams.constructorProps.get(SshTool.PROP_HOST.getName());
-            if (reachableIp != null && reachableIp.equals(host)) {
-                return new CustomResponse(0, "", "");
-            } else {
-                throw new IOException("Simulate VM not reachable for host '"+host+"'");
-            }
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/1adc2187/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/JcloudsReachableAddressStubbedTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/JcloudsReachableAddressStubbedTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/JcloudsReachableAddressStubbedTest.java
new file mode 100644
index 0000000..2ba966b
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/networking/JcloudsReachableAddressStubbedTest.java
@@ -0,0 +1,369 @@
+/*
+ * 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.networking;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.location.access.PortForwardManager;
+import org.apache.brooklyn.core.location.access.PortForwardManagerImpl;
+import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
+import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
+import org.apache.brooklyn.location.jclouds.AbstractJcloudsLiveTest;
+import org.apache.brooklyn.location.jclouds.ComputeServiceRegistry;
+import org.apache.brooklyn.location.jclouds.JcloudsLocation;
+import org.apache.brooklyn.location.jclouds.JcloudsLocationConfig;
+import org.apache.brooklyn.location.jclouds.JcloudsSshMachineLocation;
+import org.apache.brooklyn.location.jclouds.JcloudsStubTemplateBuilder;
+import org.apache.brooklyn.location.jclouds.StubbedComputeServiceRegistry;
+import org.apache.brooklyn.location.jclouds.StubbedComputeServiceRegistry.AbstractNodeCreator;
+import org.apache.brooklyn.location.jclouds.networking.JcloudsPortForwardingStubbedLiveTest.RecordingJcloudsPortForwarderExtension;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool;
+import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool.CustomResponse;
+import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool.CustomResponseGenerator;
+import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool.ExecParams;
+import org.apache.brooklyn.util.core.internal.ssh.SshTool;
+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 org.testng.annotations.Test;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.net.HostAndPort;
+
+/**
+ * The VM creation is stubbed out, but it still requires live access (i.e. real account credentials)
+ * to generate the template etc.
+ * 
+ * Simulates the creation of a VM that has multiple IPs. Checks that we choose the right address.
+ * 
+ */
+public class JcloudsReachableAddressStubbedTest extends AbstractJcloudsLiveTest {
+
+    // TODO Aim is to test the various situations/permutations, where we pass in different config.
+    // More tests still need to be added.
+
+    @SuppressWarnings("unused")
+    private static final Logger LOG = LoggerFactory.getLogger(JcloudsReachableAddressStubbedTest.class);
+
+    protected StubbedComputeServiceRegistry.NodeCreator nodeCreator;
+    protected ComputeServiceRegistry computeServiceRegistry;
+    
+    protected String reachableIp;
+    protected AddressChooser addressChooser;
+    protected CustomResponseGeneratorImpl customResponseGenerator;
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        reachableIp = null; // expect test method to set this
+        addressChooser = new AddressChooser();
+        customResponseGenerator = new CustomResponseGeneratorImpl();
+        RecordingSshTool.clear();
+        super.setUp();
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    @Override
+    public void tearDown() throws Exception {
+        try {
+            super.tearDown();
+        } finally {
+            RecordingSshTool.clear();
+        }
+    }
+
+    @Override
+    protected LocalManagementContext newManagementContext() {
+        return LocalManagementContextForTests.builder(true).build();
+    }
+
+    protected AbstractNodeCreator newNodeCreator(final List<String> publicAddresses, final List<String> privateAddresses) {
+        return new AbstractNodeCreator() {
+            int nextIpSuffix = 2;
+            @Override
+            protected NodeMetadata newNode(String group, Template template) {
+                int ipSuffix = nextIpSuffix++;
+                NodeMetadata result = new NodeMetadataBuilder()
+                        .id("myid-"+ipSuffix)
+                        .credentials(LoginCredentials.builder().identity("myuser").credential("mypassword").build())
+                        .loginPort(22)
+                        .status(Status.RUNNING)
+                        .publicAddresses(publicAddresses)
+                        .privateAddresses(privateAddresses)
+                        .build();
+                return result;
+            }
+        };
+    }
+
+    public String getLocationSpec() {
+        return "jclouds:aws-ec2";
+    }
+
+    protected void initNodeCreatorAndJcloudsLocation(List<String> publicAddresses, List<String> privateAddresses, Map<Object, Object> jcloudsLocationConfig) throws Exception {
+        nodeCreator = newNodeCreator(publicAddresses, privateAddresses);
+        computeServiceRegistry = new StubbedComputeServiceRegistry(nodeCreator);
+
+        jcloudsLocation = (JcloudsLocation)managementContext.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")
+                        .putAll(jcloudsLocationConfig)
+                        .build());
+    }
+
+    protected JcloudsSshMachineLocation obtainMachine(Map<?, ?> conf) throws Exception {
+        assertNotNull(jcloudsLocation);
+        JcloudsSshMachineLocation result = (JcloudsSshMachineLocation)jcloudsLocation.obtain(conf);
+        machines.add(checkNotNull(result, "result"));
+        return result;
+    }
+    
+    /**
+     * Only one public and one private; public is reachable;
+     * With waitForSshable=true; pollForFirstReachableAddress=true; and custom reachable-predicate
+     */
+    @Test(groups = {"Live", "Live-sanity"})
+    public void testMachineUsesVanillaPublicAddress() throws Exception {
+        initNodeCreatorAndJcloudsLocation(ImmutableList.of("1.1.1.1"), ImmutableList.of("2.1.1.1"), ImmutableMap.of());
+        reachableIp = "1.1.1.1";
+
+        JcloudsSshMachineLocation machine = newMachine(ImmutableMap.<ConfigKey<?>,Object>builder()
+                .put(JcloudsLocationConfig.WAIT_FOR_SSHABLE, Asserts.DEFAULT_LONG_TIMEOUT.toString())
+                .put(JcloudsLocation.POLL_FOR_FIRST_REACHABLE_ADDRESS, Asserts.DEFAULT_LONG_TIMEOUT.toString())
+                .build());
+        
+        addressChooser.assertCalled();
+        assertEquals(RecordingSshTool.getLastExecCmd().constructorProps.get(SshTool.PROP_HOST.getName()), reachableIp);
+
+        assertEquals(machine.getAddress().getHostAddress(), reachableIp);
+        assertEquals(machine.getHostname(), reachableIp);
+        assertEquals(machine.getSubnetIp(), "2.1.1.1");
+    }
+
+    /**
+     * Only one public and one private; private is reachable;
+     * With waitForSshable=true; pollForFirstReachableAddress=true; and custom reachable-predicate
+     */
+    @Test(enabled = false, groups = "WIP")
+    public void testMachineUsesVanillaPrivateAddress() throws Exception {
+        initNodeCreatorAndJcloudsLocation(ImmutableList.of("1.1.1.1"), ImmutableList.of("2.1.1.1"), ImmutableMap.of());
+        reachableIp = "2.1.1.1";
+
+        JcloudsSshMachineLocation machine = newMachine(ImmutableMap.<ConfigKey<?>,Object>builder()
+                .put(JcloudsLocationConfig.WAIT_FOR_SSHABLE, Asserts.DEFAULT_LONG_TIMEOUT.toString())
+                .put(JcloudsLocation.POLL_FOR_FIRST_REACHABLE_ADDRESS, Asserts.DEFAULT_LONG_TIMEOUT.toString())
+                .build());
+        
+        addressChooser.assertCalled();
+        assertEquals(RecordingSshTool.getLastExecCmd().constructorProps.get(SshTool.PROP_HOST.getName()), reachableIp);
+
+        assertEquals(machine.getAddress().getHostAddress(), reachableIp);
+        assertEquals(machine.getHostname(), reachableIp);
+        assertEquals(machine.getSubnetIp(), reachableIp);
+    }
+
+    /**
+     * Multiple public addresses; chooses the reachable one;
+     * With waitForSshable=true; pollForFirstReachableAddress=true; and custom reachable-predicate
+     */
+    @Test(enabled = false, groups = "WIP")
+    public void testMachineUsesReachablePublicAddress() throws Exception {
+        initNodeCreatorAndJcloudsLocation(ImmutableList.of("1.1.1.1", "1.1.1.2", "1.1.1.2"), ImmutableList.of("2.1.1.1"), ImmutableMap.of());
+        reachableIp = "1.1.1.2";
+
+        JcloudsSshMachineLocation machine = newMachine(ImmutableMap.<ConfigKey<?>,Object>builder()
+                .put(JcloudsLocationConfig.WAIT_FOR_SSHABLE, Asserts.DEFAULT_LONG_TIMEOUT.toString())
+                .put(JcloudsLocation.POLL_FOR_FIRST_REACHABLE_ADDRESS, Asserts.DEFAULT_LONG_TIMEOUT.toString())
+                .build());
+        
+        addressChooser.assertCalled();
+        assertEquals(RecordingSshTool.getLastExecCmd().constructorProps.get(SshTool.PROP_HOST.getName()), reachableIp);
+
+        assertEquals(machine.getAddress().getHostAddress(), reachableIp);
+        assertEquals(machine.getHostname(), reachableIp);
+        assertEquals(machine.getSubnetIp(), "2.1.1.1");
+    }
+
+    /**
+     * Multiple private addresses; chooses the reachable one;
+     * With waitForSshable=true; pollForFirstReachableAddress=true; and custom reachable-predicate
+     */
+    @Test(enabled = false, groups = "WIP")
+    public void testMachineUsesReachablePrivateAddress() throws Exception {
+        initNodeCreatorAndJcloudsLocation(ImmutableList.of("1.1.1.1"), ImmutableList.of("2.1.1.1", "2.1.1.2", "2.1.1.2"), ImmutableMap.of());
+        reachableIp = "2.1.1.2";
+
+        JcloudsSshMachineLocation machine = newMachine(ImmutableMap.<ConfigKey<?>,Object>builder()
+                .put(JcloudsLocationConfig.WAIT_FOR_SSHABLE, Asserts.DEFAULT_LONG_TIMEOUT.toString())
+                .put(JcloudsLocation.POLL_FOR_FIRST_REACHABLE_ADDRESS, Asserts.DEFAULT_LONG_TIMEOUT.toString())
+                .build());
+        
+        addressChooser.assertCalled();
+        assertEquals(RecordingSshTool.getLastExecCmd().constructorProps.get(SshTool.PROP_HOST.getName()), reachableIp);
+
+        assertEquals(machine.getAddress().getHostAddress(), reachableIp);
+        assertEquals(machine.getHostname(), reachableIp);
+        assertEquals(machine.getSubnetIp(), reachableIp);
+    }
+
+    /**
+     * No waitForSshable: should not try to ssh.
+     * Therefore will also not search for reachable address (as that expects loginPort to be reachable).
+     */
+    @Test
+    public void testNoWaitFroSshable() throws Exception {
+        initNodeCreatorAndJcloudsLocation(ImmutableList.of("1.1.1.1", "1.1.1.2", "1.1.1.2"), ImmutableList.of("2.1.1.1"), ImmutableMap.of());
+        reachableIp = null;
+
+        JcloudsSshMachineLocation machine = newMachine(ImmutableMap.<ConfigKey<?>,Object>builder()
+                .put(JcloudsLocationConfig.WAIT_FOR_SSHABLE, "false")
+                .put(JcloudsLocation.POLL_FOR_FIRST_REACHABLE_ADDRESS, Asserts.DEFAULT_LONG_TIMEOUT.toString())
+                .build());
+        
+        addressChooser.assertNotCalled();
+        assertTrue(RecordingSshTool.getExecCmds().isEmpty());
+
+        assertEquals(machine.getAddress().getHostAddress(), "1.1.1.1");
+        assertEquals(machine.getHostname(), "1.1.1.1");
+        assertEquals(machine.getSubnetIp(), "2.1.1.1");
+    }
+
+    /**
+     * No pollForFirstReachableAddress: should use first public IP.
+     */
+    @Test
+    public void testNoPollForFirstReachable() throws Exception {
+        initNodeCreatorAndJcloudsLocation(ImmutableList.of("1.1.1.1", "1.1.1.2", "1.1.1.2"), ImmutableList.of("2.1.1.1"), ImmutableMap.of());
+        reachableIp = null;
+
+        JcloudsSshMachineLocation machine = newMachine(ImmutableMap.<ConfigKey<?>,Object>builder()
+                .put(JcloudsLocationConfig.WAIT_FOR_SSHABLE, Asserts.DEFAULT_LONG_TIMEOUT.toString())
+                .put(JcloudsLocation.POLL_FOR_FIRST_REACHABLE_ADDRESS, "false")
+                .build());
+        
+        addressChooser.assertNotCalled();
+
+        assertEquals(machine.getAddress().getHostAddress(), "1.1.1.1");
+        assertEquals(machine.getHostname(), "1.1.1.1");
+        assertEquals(machine.getSubnetIp(), "2.1.1.1");
+    }
+
+    @Test
+    public void testReachabilityChecksWithPortForwarding() throws Exception {
+        initNodeCreatorAndJcloudsLocation(ImmutableList.of("1.1.1.1"), ImmutableList.of("2.1.1.1"), ImmutableMap.of());
+        reachableIp = "1.2.3.4";
+                
+        PortForwardManager pfm = new PortForwardManagerImpl();
+        RecordingJcloudsPortForwarderExtension portForwarder = new RecordingJcloudsPortForwarderExtension(pfm);
+        
+        JcloudsSshMachineLocation machine = newMachine(ImmutableMap.<ConfigKey<?>,Object>builder()
+                .put(JcloudsLocationConfig.WAIT_FOR_SSHABLE, Asserts.DEFAULT_LONG_TIMEOUT.toString())
+                .put(JcloudsLocation.POLL_FOR_FIRST_REACHABLE_ADDRESS, Asserts.DEFAULT_LONG_TIMEOUT.toString())
+                .put(JcloudsLocation.USE_PORT_FORWARDING, true)
+                .put(JcloudsLocation.PORT_FORWARDER, portForwarder)
+                .build());
+        
+        addressChooser.assertNotCalled();
+        assertEquals(RecordingSshTool.getLastExecCmd().constructorProps.get(SshTool.PROP_HOST.getName()), reachableIp);
+        assertEquals(RecordingSshTool.getLastExecCmd().constructorProps.get(SshTool.PROP_PORT.getName()), 12345);
+
+        assertEquals(machine.getAddress().getHostAddress(), "1.2.3.4");
+        assertEquals(machine.getPort(), 12345);
+        assertEquals(machine.getSshHostAndPort(), HostAndPort.fromParts("1.2.3.4", 12345));
+        assertEquals(machine.getHostname(), "1.1.1.1");
+        assertEquals(machine.getSubnetIp(), "2.1.1.1");
+    }
+    
+    @Test
+    public void testMachineUsesFirstPublicAddress() throws Exception {
+        initNodeCreatorAndJcloudsLocation(ImmutableList.of("10.10.10.1", "10.10.10.2"), ImmutableList.of("1.1.1.1", "1.1.1.2", "1.1.1.2"), ImmutableMap.of());
+        reachableIp = "10.10.10.1";
+
+        JcloudsSshMachineLocation machine = newMachine(ImmutableMap.<ConfigKey<?>,Object>builder()
+                .put(JcloudsLocationConfig.WAIT_FOR_SSHABLE, Asserts.DEFAULT_LONG_TIMEOUT.toString())
+                .put(JcloudsLocation.POLL_FOR_FIRST_REACHABLE_ADDRESS, false)
+                .build());
+
+        assertEquals(machine.getAddress().getHostAddress(), reachableIp);
+    }
+    
+    protected JcloudsSshMachineLocation newMachine() throws Exception {
+        return newMachine(ImmutableMap.<ConfigKey<?>, Object>of());
+    }
+    
+    protected JcloudsSshMachineLocation newMachine(Map<? extends ConfigKey<?>, ?> additionalConfig) throws Exception {
+        return obtainMachine(ImmutableMap.<ConfigKey<?>,Object>builder()
+                .put(SshMachineLocation.SSH_TOOL_CLASS, RecordingSshTool.class.getName())
+                .put(JcloudsLocation.POLL_FOR_FIRST_REACHABLE_ADDRESS_PREDICATE, addressChooser)
+                .putAll(additionalConfig)
+                .build());
+    }
+    
+    protected class AddressChooser implements Predicate<HostAndPort> {
+        final List<HostAndPort> calls = Lists.newCopyOnWriteArrayList();
+        
+        @Override public boolean apply(HostAndPort input) {
+            calls.add(input);
+            return reachableIp != null && reachableIp.equals(input.getHostText());
+        }
+        
+        public void assertCalled() {
+            assertTrue(calls.size() > 0, "no calls to "+this);
+        }
+        
+        public void assertNotCalled() {
+            assertTrue(calls.isEmpty(), "unexpected calls to "+this+": "+calls);
+        }
+    }
+    
+    protected class CustomResponseGeneratorImpl implements CustomResponseGenerator {
+        @Override public CustomResponse generate(ExecParams execParams) throws Exception {
+            System.out.println("ssh call: "+execParams);
+            Object host = execParams.constructorProps.get(SshTool.PROP_HOST.getName());
+            if (reachableIp != null && reachableIp.equals(host)) {
+                return new CustomResponse(0, "", "");
+            } else {
+                throw new IOException("Simulate VM not reachable for host '"+host+"'");
+            }
+        }
+    }
+}