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 2014/08/21 18:02:44 UTC

[1/5] git commit: NginxUrlMapping test: remove some incorrect asserts

Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master cc1915aaa -> 8257a4fff


NginxUrlMapping test: remove some incorrect asserts


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

Branch: refs/heads/master
Commit: 2f2792318a8f44b86d4a31da74495acd66951a19
Parents: 42ba635
Author: Aled Sage <al...@gmail.com>
Authored: Wed Aug 6 13:24:09 2014 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Thu Aug 21 16:49:43 2014 +0100

----------------------------------------------------------------------
 .../nginx/NginxUrlMappingIntegrationTest.java   |  10 +-
 .../main/java/brooklyn/test/HttpTestUtils.java  | 108 +++++++++++++++----
 2 files changed, 92 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2f279231/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxUrlMappingIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxUrlMappingIntegrationTest.java b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxUrlMappingIntegrationTest.java
index b8103d9..d6918a5 100644
--- a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxUrlMappingIntegrationTest.java
+++ b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxUrlMappingIntegrationTest.java
@@ -196,10 +196,12 @@ public class NginxUrlMappingIntegrationTest extends BrooklynAppLiveTestSupport {
         HttpTestUtils.assertHttpStatusCodeEquals("http://localhost2:"+port+"/hello-world/notexists", 404);
         HttpTestUtils.assertHttpStatusCodeEquals("http://localhost3:"+port+"/", 404);
         
-        //make sure nginx default welcome page isn't displayed
-        HttpTestUtils.assertContentNotContainsText("http://localhost:"+port+"/", "ginx");
-        HttpTestUtils.assertContentNotContainsText("http://localhost2:"+port+"/", "ginx");
-        HttpTestUtils.assertContentNotContainsText("http://localhost3:"+port+"/", "ginx");
+        // TODO previously said "make sure nginx default welcome page isn't displayed",
+        // but the assertion only worked because threw exception on 404 trying to read
+        // stdin of http connection. If reading stderr of http connection, we do see
+        // "ginx" in the output. Why were we asserting this? Can we just delete it?
+        // Previous code was:
+        //     Asserts.assertFails { HttpTestUtils.assertContentContainsText([timeout:1], "http://localhost:${port}/", "ginx"); }
     }
 
     @Test(groups = "Integration")

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2f279231/usage/test-support/src/main/java/brooklyn/test/HttpTestUtils.java
----------------------------------------------------------------------
diff --git a/usage/test-support/src/main/java/brooklyn/test/HttpTestUtils.java b/usage/test-support/src/main/java/brooklyn/test/HttpTestUtils.java
index bc238bf..8f96dcf 100644
--- a/usage/test-support/src/main/java/brooklyn/test/HttpTestUtils.java
+++ b/usage/test-support/src/main/java/brooklyn/test/HttpTestUtils.java
@@ -18,19 +18,16 @@
  */
 package brooklyn.test;
 
-import static com.google.common.base.Predicates.instanceOf;
-import static com.google.common.base.Throwables.getCausalChain;
-import static com.google.common.collect.Iterables.find;
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.HttpURLConnection;
 import java.net.URL;
 import java.net.URLConnection;
 import java.util.List;
 import java.util.Map;
-import java.util.NoSuchElementException;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -48,6 +45,9 @@ import org.slf4j.LoggerFactory;
 import org.testng.Assert;
 
 import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.stream.Streams;
+import brooklyn.util.time.Time;
 
 import com.google.common.base.Throwables;
 import com.google.common.collect.Lists;
@@ -132,11 +132,7 @@ public class HttpTestUtils {
         int status = ((HttpURLConnection) connection).getResponseCode();
         
         // read fully if possible, then close everything, trying to prevent cached threads at server
-        try { DefaultGroovyMethods.getText( connection.getInputStream() ); } catch (Exception e) {}
-        try { ((HttpURLConnection) connection).disconnect(); } catch (Exception e) {}
-        try { connection.getInputStream().close(); } catch (Exception e) {}
-        try { connection.getOutputStream().close(); } catch (Exception e) {}
-        try { ((HttpURLConnection) connection).getErrorStream().close(); } catch (Exception e) {}
+        consumeAndCloseQuietly((HttpURLConnection) connection);
         
         if (LOG.isDebugEnabled())
             LOG.debug("connection to {} ({}ms) gives {}", new Object[] { url, (System.currentTimeMillis()-startTime), status });
@@ -166,7 +162,7 @@ public class HttpTestUtils {
             Thread.currentThread().interrupt();
             throw new RuntimeException("Interrupted for "+url+" (in assertion that unreachable)", e);
         } catch (Exception e) {
-            IOException cause = getFirstThrowableOfType(e, IOException.class);
+            IOException cause = Exceptions.getFirstThrowableOfType(e, IOException.class);
             if (cause != null) {
                 // success; clean shutdown transitioning from 400 to error
             } else {
@@ -180,7 +176,7 @@ public class HttpTestUtils {
     }
     
     public static void assertUrlUnreachableEventually(Map flags, final String url) {
-        TestUtils.executeUntilSucceeds(flags, new Runnable() {
+        Asserts.succeedsEventually(flags, new Runnable() {
             public void run() {
                 assertUrlUnreachable(url);
             }
@@ -209,7 +205,7 @@ public class HttpTestUtils {
     }
 
     public static void assertHttpStatusCodeEventuallyEquals(Map flags, final String url, final int expectedCode) {
-        TestUtils.executeUntilSucceeds(flags, new Runnable() {
+        Asserts.succeedsEventually(flags, new Runnable() {
             public void run() {
                 assertHttpStatusCodeEquals(url, expectedCode);
             }
@@ -219,7 +215,7 @@ public class HttpTestUtils {
     public static void assertContentContainsText(final String url, final String phrase, final String ...additionalPhrases) {
         try {
             String contents = getContent(url);
-            Assert.assertTrue(contents!=null && contents.length()>0);
+            Assert.assertTrue(contents != null && contents.length() > 0);
             for (String text: Lists.asList(phrase, additionalPhrases)) {
                 if (!contents.contains(text)) {
                     LOG.warn("CONTENTS OF URL "+url+" MISSING TEXT: "+text+"\n"+contents);
@@ -246,12 +242,43 @@ public class HttpTestUtils {
         }
     }
 
+    public static void assertErrorContentContainsText(final String url, final String phrase, final String ...additionalPhrases) {
+        try {
+            String contents = getErrorContent(url);
+            Assert.assertTrue(contents != null && contents.length() > 0);
+            for (String text: Lists.asList(phrase, additionalPhrases)) {
+                if (!contents.contains(text)) {
+                    LOG.warn("CONTENTS OF URL "+url+" MISSING TEXT: "+text+"\n"+contents);
+                    Assert.fail("URL "+url+" does not contain text: "+text);
+                }
+            }
+        } catch (Exception e) {
+            throw Throwables.propagate(e);
+        }
+    }
+
+
+    public static void assertErrorContentNotContainsText(final String url, final String phrase, final String ...additionalPhrases) {
+        try {
+            String err = getErrorContent(url);
+            Assert.assertTrue(err != null);
+            for (String text: Lists.asList(phrase, additionalPhrases)) {
+                if (err.contains(text)) {
+                    LOG.warn("CONTENTS OF URL "+url+" HAS TEXT: "+text+"\n"+err);
+                    Assert.fail("URL "+url+" contain text: "+text);
+                }
+            }
+        } catch (Exception e) {
+            throw Throwables.propagate(e);
+        }
+    }
+    
     public static void assertContentEventuallyContainsText(final String url, final String phrase, final String ...additionalPhrases) {
         assertContentEventuallyContainsText(MutableMap.of(), url, phrase, additionalPhrases);
     }
     
     public static void assertContentEventuallyContainsText(Map flags, final String url, final String phrase, final String ...additionalPhrases) {
-        TestUtils.executeUntilSucceeds(new Runnable() {
+        Asserts.succeedsEventually(flags, new Runnable() {
             public void run() {
                 assertContentContainsText(url, phrase, additionalPhrases);
             }
@@ -273,6 +300,30 @@ public class HttpTestUtils {
         });
     }
     
+    public static String getErrorContent(String url) {
+        try {
+            HttpURLConnection connection = (HttpURLConnection) connectToUrl(url);
+            long startTime = System.currentTimeMillis();
+            
+            String err;
+            int status;
+            try {
+                InputStream errStream = connection.getErrorStream();
+                err = Streams.readFullyString(errStream);
+                status = connection.getResponseCode();
+            } finally {
+                closeQuietly(connection);
+            }
+            
+            if (LOG.isDebugEnabled())
+                LOG.debug("read of err {} ({}ms) complete; http code {}", new Object[] { url, Time.makeTimeStringRounded(System.currentTimeMillis()-startTime), status});
+            return err;
+
+        } catch (Exception e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+    
     public static String getContent(String url) {
         try {
             return DefaultGroovyMethods.getText(new URL(url).openStream());
@@ -315,13 +366,26 @@ public class HttpTestUtils {
         });
     }
     
-    // TODO Part-duplicated from jclouds Throwables2
-    @SuppressWarnings("unchecked")
-    private static <T extends Throwable> T getFirstThrowableOfType(Throwable from, Class<T> clazz) {
-        try {
-            return (T) find(getCausalChain(from), instanceOf(clazz));
-        } catch (NoSuchElementException e) {
-            return null;
-        }
+    /**
+     * Consumes the input stream entirely and then cleanly closes the connection.
+     * Ignores all exceptions completely, not even logging them!
+     * 
+     * Consuming the stream fully is useful for preventing idle TCP connections. 
+     * See {@linkplain http://docs.oracle.com/javase/8/docs/technotes/guides/net/http-keepalive.html}.
+     */
+    public static void consumeAndCloseQuietly(HttpURLConnection connection) {
+        try { Streams.readFully(connection.getInputStream()); } catch (Exception e) {}
+        closeQuietly(connection);
+    }
+    
+    /**
+     * Closes all streams of the connection, and disconnects it. Ignores all exceptions completely,
+     * not even logging them!
+     */
+    public static void closeQuietly(HttpURLConnection connection) {
+        try { connection.disconnect(); } catch (Exception e) {}
+        try { connection.getInputStream().close(); } catch (Exception e) {}
+        try { connection.getOutputStream().close(); } catch (Exception e) {}
+        try { connection.getErrorStream().close(); } catch (Exception e) {}
     }
 }


[2/5] git commit: NginxRebindIntegrationTest: use live brooklyn.properties

Posted by al...@apache.org.
NginxRebindIntegrationTest: use live brooklyn.properties


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

Branch: refs/heads/master
Commit: 42ba635b59c8f77f9df7185e7ccba198f049ad8a
Parents: 4d86f06
Author: Aled Sage <al...@gmail.com>
Authored: Wed Aug 6 13:22:54 2014 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Thu Aug 21 16:49:43 2014 +0100

----------------------------------------------------------------------
 .../entity/rebind/RebindTestFixture.java        | 20 +++++--
 .../brooklyn/entity/rebind/RebindTestUtils.java | 18 ++++++-
 .../proxy/nginx/NginxRebindIntegrationTest.java | 55 +++++++-------------
 3 files changed, 50 insertions(+), 43 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/42ba635b/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java b/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java
index 605f32d..9a33e73 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java
@@ -30,7 +30,6 @@ import brooklyn.entity.basic.StartableApplication;
 import brooklyn.entity.rebind.persister.BrooklynMementoPersisterToObjectStore;
 import brooklyn.entity.rebind.persister.FileBasedObjectStore;
 import brooklyn.entity.rebind.persister.PersistMode;
-import brooklyn.internal.BrooklynFeatureEnablement;
 import brooklyn.management.ManagementContext;
 import brooklyn.management.ha.HighAvailabilityMode;
 import brooklyn.management.internal.LocalManagementContext;
@@ -64,7 +63,14 @@ public abstract class RebindTestFixture<T extends StartableApplication> {
     }
 
     protected LocalManagementContext createOrigManagementContext() {
-        return RebindTestUtils.newPersistingManagementContext(mementoDir, classLoader, getPersistPeriodMillis());
+        return RebindTestUtils.managementContextBuilder(mementoDir, classLoader)
+                .persistPeriodMillis(getPersistPeriodMillis())
+                .forLive(useLiveManagementContext())
+                .buildStarted();
+    }
+    
+    protected boolean useLiveManagementContext() {
+        return false;
     }
     
     protected int getPersistPeriodMillis() {
@@ -110,19 +116,23 @@ public abstract class RebindTestFixture<T extends StartableApplication> {
         if (terminateOrigManagementContext) {
             origManagementContext.terminate();
         }
-        return (T) RebindTestUtils.rebind(mementoDir, getClass().getClassLoader());
+        LocalManagementContext newManagementContext = RebindTestUtils.managementContextBuilder(mementoDir, classLoader)
+                .forLive(useLiveManagementContext())
+                .buildUnstarted();
+
+        return (T) RebindTestUtils.rebind(newManagementContext, classLoader);
     }
 
     @SuppressWarnings("unchecked")
     protected T rebind(RebindExceptionHandler exceptionHandler) throws Exception {
         RebindTestUtils.waitForPersisted(origApp);
-        return (T) RebindTestUtils.rebind(mementoDir, getClass().getClassLoader(), exceptionHandler);
+        return (T) RebindTestUtils.rebind(mementoDir, classLoader, exceptionHandler);
     }
 
     @SuppressWarnings("unchecked")
     protected T rebind(ManagementContext newManagementContext, RebindExceptionHandler exceptionHandler) throws Exception {
         RebindTestUtils.waitForPersisted(origApp);
-        return (T) RebindTestUtils.rebind(newManagementContext, mementoDir, getClass().getClassLoader(), exceptionHandler);
+        return (T) RebindTestUtils.rebind(newManagementContext, mementoDir, classLoader, exceptionHandler);
     }
     
     protected BrooklynMementoManifest loadMementoManifest() throws Exception {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/42ba635b/core/src/test/java/brooklyn/entity/rebind/RebindTestUtils.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindTestUtils.java b/core/src/test/java/brooklyn/entity/rebind/RebindTestUtils.java
index 018e4d8..5e739c5 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindTestUtils.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindTestUtils.java
@@ -211,8 +211,18 @@ public class RebindTestUtils {
         return rebind(mementoDir, classLoader, null);
     }
 
+    public static Application rebind(LocalManagementContext newManagementContext, ClassLoader classLoader) throws Exception {
+        return rebind(newManagementContext, classLoader, null);
+    }
+
+    public static Application rebind(LocalManagementContext newManagementContext, ClassLoader classLoader, RebindExceptionHandler exceptionHandler) throws Exception {
+        Collection<Application> newApps = rebindAll(newManagementContext, classLoader, exceptionHandler);
+        if (newApps.isEmpty()) throw new IllegalStateException("Application could not be rebinded; serialization probably failed");
+        return Iterables.getFirst(newApps, null);
+    }
+
     public static Application rebind(File mementoDir, ClassLoader classLoader, RebindExceptionHandler exceptionHandler) throws Exception {
-        Collection<Application> newApps = rebindAll(mementoDir, classLoader);
+        Collection<Application> newApps = rebindAll(mementoDir, classLoader, exceptionHandler);
         if (newApps.isEmpty()) throw new IllegalStateException("Application could not be rebinded; serialization probably failed");
         return Iterables.getFirst(newApps, null);
     }
@@ -223,8 +233,12 @@ public class RebindTestUtils {
 
     public static Collection<Application> rebindAll(File mementoDir, ClassLoader classLoader, RebindExceptionHandler exceptionHandler) throws Exception {
         LOG.info("Rebinding app, using directory "+mementoDir);
+        return rebindAll(newPersistingManagementContextUnstarted(mementoDir, classLoader), classLoader, exceptionHandler);
+    }
+    
+    public static Collection<Application> rebindAll(LocalManagementContext newManagementContext, ClassLoader classLoader, RebindExceptionHandler exceptionHandler) throws Exception {
+        LOG.info("Rebinding app");
 
-        LocalManagementContext newManagementContext = newPersistingManagementContextUnstarted(mementoDir, classLoader);
         List<Application> newApps;
         if (exceptionHandler == null) {
             newApps = newManagementContext.getRebindManager().rebind(classLoader);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/42ba635b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxRebindIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxRebindIntegrationTest.java b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxRebindIntegrationTest.java
index a119130..74e23b5 100644
--- a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxRebindIntegrationTest.java
+++ b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxRebindIntegrationTest.java
@@ -23,7 +23,6 @@ import static brooklyn.test.HttpTestUtils.assertHttpStatusCodeEquals;
 import static brooklyn.test.HttpTestUtils.assertHttpStatusCodeEventuallyEquals;
 import static org.testng.Assert.assertEquals;
 
-import java.io.File;
 import java.net.URL;
 import java.util.List;
 import java.util.Map;
@@ -39,55 +38,50 @@ import org.testng.annotations.Test;
 
 import brooklyn.entity.Entity;
 import brooklyn.entity.Group;
-import brooklyn.entity.basic.ApplicationBuilder;
 import brooklyn.entity.basic.BasicGroup;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.Lifecycle;
 import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.entity.group.DynamicCluster;
 import brooklyn.entity.proxying.EntitySpec;
-import brooklyn.entity.rebind.RebindTestUtils;
+import brooklyn.entity.rebind.RebindTestFixtureWithApp;
 import brooklyn.entity.webapp.jboss.JBoss7Server;
+import brooklyn.location.LocationSpec;
 import brooklyn.location.basic.LocalhostMachineProvisioningLocation;
 import brooklyn.management.ManagementContext;
-import brooklyn.management.internal.LocalManagementContext;
 import brooklyn.test.Asserts;
 import brooklyn.test.WebAppMonitor;
-import brooklyn.test.entity.TestApplication;
 
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
-import com.google.common.io.Files;
 
 /**
  * Test the operation of the {@link NginxController} class.
  */
-public class NginxRebindIntegrationTest {
+public class NginxRebindIntegrationTest extends RebindTestFixtureWithApp {
+
     private static final Logger LOG = LoggerFactory.getLogger(NginxRebindIntegrationTest.class);
 
     private URL warUrl;
     private LocalhostMachineProvisioningLocation localhostProvisioningLocation;
-    private ClassLoader classLoader = getClass().getClassLoader();
-    private LocalManagementContext origManagementContext;
-    private File mementoDir;
-    private TestApplication origApp;
-    private TestApplication newApp;
     private List<WebAppMonitor> webAppMonitors = new CopyOnWriteArrayList<WebAppMonitor>();
 	private ExecutorService executor;
     
-    
+	@Override
+	protected boolean useLiveManagementContext() {
+	    // For Aled, the test failed without own ~/.brooklyn/brooklyn.properties.
+	    // Suspect that was caused by local environment, with custom brooklyn.ssh.config.scriptHeader
+	    // to set things like correct Java on path.
+	    return true;
+	}
+	
     @BeforeMethod(groups = "Integration")
-    public void setUp() {
+    public void setUp() throws Exception {
+        super.setUp();
         warUrl = getClass().getClassLoader().getResource("hello-world.war");
-
-        mementoDir = Files.createTempDir();
-        origManagementContext = RebindTestUtils.newPersistingManagementContext(mementoDir, classLoader);
-        origApp = ApplicationBuilder.newManagedApp(TestApplication.class, origManagementContext);
-
-    	localhostProvisioningLocation = new LocalhostMachineProvisioningLocation();
-
+    	localhostProvisioningLocation = origManagementContext.getLocationManager().createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class));
         executor = Executors.newCachedThreadPool();
     }
 
@@ -97,18 +91,7 @@ public class NginxRebindIntegrationTest {
         	monitor.terminate();
         }
         if (executor != null) executor.shutdownNow();
-        if (newApp != null) Entities.destroyAll(newApp.getManagementContext());
-        if (origApp != null && origManagementContext.isRunning()) Entities.destroyAll(origApp.getManagementContext());
-        if (mementoDir != null) RebindTestUtils.deleteMementoDir(mementoDir);
-    }
-
-    private TestApplication rebind() throws Exception {
-        RebindTestUtils.waitForPersisted(origApp);
-        
-        // Stop the old management context, so original nginx won't interfere
-        origManagementContext.terminate();
-        
-        return (TestApplication) RebindTestUtils.rebind(mementoDir, getClass().getClassLoader());
+        super.tearDown();
     }
 
     private WebAppMonitor newWebAppMonitor(String url, int expectedResponseCode) {
@@ -146,7 +129,7 @@ public class NginxRebindIntegrationTest {
         WebAppMonitor monitor = newWebAppMonitor(rootUrl, 404);
         final String origConfigFile = origNginx.getConfigFile();
         
-        newApp = rebind();
+        newApp = rebind(false, true);
         final NginxController newNginx = (NginxController) Iterables.find(newApp.getChildren(), Predicates.instanceOf(NginxController.class));
 
         assertEquals(newNginx.getConfigFile(), origConfigFile);
@@ -190,7 +173,7 @@ public class NginxRebindIntegrationTest {
         final String origConfigFile = origNginx.getConfigFile();
         
         // Rebind
-        newApp = rebind();
+        newApp = rebind(false, true);
         ManagementContext newManagementContext = newApp.getManagementContext();
         final NginxController newNginx = (NginxController) Iterables.find(newApp.getChildren(), Predicates.instanceOf(NginxController.class));
         final DynamicCluster newServerPool = (DynamicCluster) newManagementContext.getEntityManager().getEntity(origServerPool.getId());
@@ -268,7 +251,7 @@ public class NginxRebindIntegrationTest {
         final String origConfigFile = origNginx.getConfigFile();
         
         // Create a rebinding
-        newApp = rebind();
+        newApp = rebind(false, true);
         ManagementContext newManagementContext = newApp.getManagementContext();
         final NginxController newNginx = (NginxController) Iterables.find(newApp.getChildren(), Predicates.instanceOf(NginxController.class));
         DynamicCluster newServerPool = (DynamicCluster) newManagementContext.getEntityManager().getEntity(origServerPool.getId());


[3/5] Convert nginx tests from groovy to java

Posted by al...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4d86f06c/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxUrlMappingIntegrationTest.groovy
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxUrlMappingIntegrationTest.groovy b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxUrlMappingIntegrationTest.groovy
deleted file mode 100644
index b7b186e..0000000
--- a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxUrlMappingIntegrationTest.groovy
+++ /dev/null
@@ -1,503 +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 brooklyn.entity.proxy.nginx;
-
-import static brooklyn.test.TestUtils.*
-import static java.util.concurrent.TimeUnit.*
-import static org.testng.Assert.*
-
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import org.testng.annotations.AfterMethod
-import org.testng.annotations.BeforeMethod
-import org.testng.annotations.Test
-
-import brooklyn.entity.Entity
-import brooklyn.entity.Group
-import brooklyn.entity.basic.ApplicationBuilder
-import brooklyn.entity.basic.Attributes
-import brooklyn.entity.basic.BasicGroup
-import brooklyn.entity.basic.Entities
-import brooklyn.entity.group.DynamicCluster
-import brooklyn.entity.proxying.EntitySpec
-import brooklyn.entity.webapp.JavaWebAppService
-import brooklyn.entity.webapp.WebAppService
-import brooklyn.entity.webapp.jboss.JBoss7Server
-import brooklyn.location.basic.LocalhostMachineProvisioningLocation
-import brooklyn.management.EntityManager
-import brooklyn.test.Asserts;
-import brooklyn.test.HttpTestUtils
-import brooklyn.test.TestUtils;
-import brooklyn.test.entity.TestApplication
-import brooklyn.util.internal.TimeExtras
-
-import com.google.common.collect.Iterables
-
-/**
- * Test the operation of the {@link NginxController} class, for URL mapped groups (two different pools).
- * 
- * These tests require that /etc/hosts contains some extra entries, such as:
- *     127.0.0.1       localhost localhost1 localhost2 localhost3 localhost4
- */
-public class NginxUrlMappingIntegrationTest {
-    
-    // TODO Make JBoss7Server.deploy wait for the web-app to actually be deployed.
-    // That may simplify some of the tests, because we can assert some things immediately rather than in a succeedsEventually.
-    
-    private static final Logger log = LoggerFactory.getLogger(NginxUrlMappingIntegrationTest.class)
-
-    static { TimeExtras.init() }
-
-    private TestApplication app
-    private NginxController nginx
-    private DynamicCluster cluster
-    private Group urlMappingsGroup;
-    private EntityManager entityManager;
-    
-    private URL war;
-    private static String WAR_URL = "classpath://hello-world.war";
-    
-    @BeforeMethod(alwaysRun=true)
-    public void setup() {
-        war = getClass().getClassLoader().getResource("hello-world.war")
-        assertNotNull(war, "Unable to locate hello-world.war resource");
-        
-        app = ApplicationBuilder.newManagedApp(TestApplication.class);
-        urlMappingsGroup = app.createAndManageChild(EntitySpec.create(BasicGroup.class)
-                .configure("childrenAsMembers", true));
-        entityManager = app.getManagementContext().getEntityManager();
-    }
-
-    @AfterMethod(alwaysRun=true)
-    public void shutdown() {
-        if (app != null) Entities.destroy(app);
-    }
-
-    protected void checkExtraLocalhosts() {
-        Set failedHosts = []
-        ["localhost", "localhost1", "localhost2", "localhost3", "localhost4"].each { String host ->
-            try {
-                InetAddress i = InetAddress.getByName(host);
-                byte[] b = ((Inet4Address)i).getAddress();
-                if (b[0]!=127 || b[1]!=0 || b[2]!=0 || b[3]!=1) {
-                    log.warn "Failed to resolve "+host+" (test will subsequently fail, but looking for more errors first; see subsequent failure for more info): wrong IP "+Arrays.asList(b)
-                    failedHosts += host;
-                }
-            } catch (Exception e) {
-                log.warn "Failed to resolve "+host+" (test will subsequently fail, but looking for more errors first; see subsequent failure for more info): "+e, e
-                failedHosts += host;
-            }
-        }
-        if (!failedHosts.isEmpty()) {
-            fail("These tests (in "+this+") require special hostnames to map to 127.0.0.1, in /etc/hosts: "+failedHosts);
-        }
-    }
-    
-    @Test(groups = "Integration")
-    public void testUrlMappingServerNameAndPath() {
-        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
-                .configure("urlMappings", urlMappingsGroup));
-        
-        //cluster 0 mounted at localhost1 /
-        DynamicCluster c0 = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-                .configure("initialSize", 1)
-                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+"))
-                .configure(JavaWebAppService.ROOT_WAR, WAR_URL));
-        UrlMapping u0 = entityManager.createEntity(EntitySpec.create(UrlMapping.class)
-                .configure("domain", "localhost1")
-                .configure("target", c0)
-                .parent(urlMappingsGroup));
-        Entities.manage(u0);
-        
-        //cluster 1 at localhost2 /hello-world/
-        DynamicCluster c1 = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-                .configure("initialSize", 1)
-                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+"))
-                .configure(JavaWebAppService.NAMED_WARS, [WAR_URL]));
-        UrlMapping u1 = entityManager.createEntity(EntitySpec.create(UrlMapping.class)
-                .configure("domain", "localhost2")
-                .configure("path", '/hello-world($|/.*)')
-                .configure("target", c1)
-                .parent(urlMappingsGroup));
-        Entities.manage(u1);
-
-        // cluster 2 at localhost3 /c2/  and mapping /hello/xxx to /hello/new xxx
-        DynamicCluster c2 = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-                .configure("initialSize", 1)
-                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+")));
-        UrlMapping u2 = entityManager.createEntity(EntitySpec.create(UrlMapping.class)
-                .configure("domain", "localhost3")
-                .configure("path", '/c2($|/.*)')
-                .configure("target", c2)
-                .configure("rewrites", [new UrlRewriteRule('(.*/|)(hello/)(.*)', '$1$2new $3').setBreak()])
-                .parent(urlMappingsGroup));
-        Entities.manage(u2);
-        // FIXME rewrite not a config
-        
-        app.start([ new LocalhostMachineProvisioningLocation() ])
-        int port = nginx.getAttribute(NginxController.PROXY_HTTP_PORT)
-        c2.getMembers().each { it.deploy(war.toString(), "c2.war") }
-    
-        Entities.dumpInfo(app);
-        
-        // Confirm routes requests to the correct cluster
-        // Do more than one request for each in-case just lucky with round-robin...
-        executeUntilSucceeds {
-            //cluster 0
-            for (int i = 0; i < 2; i++) {
-                HttpTestUtils.assertContentContainsText("http://localhost1:${port}", "Hello");
-                HttpTestUtils.assertContentContainsText("http://localhost1:${port}/", "Hello");
-                HttpTestUtils.assertContentContainsText("http://localhost1:${port}/hello/frank", "http://localhost1:${port}/hello/frank");
-            }
-            //cluster 1
-            for (int i = 0; i < 2; i++) {
-                HttpTestUtils.assertContentContainsText("http://localhost2:${port}/hello-world", "Hello");
-                HttpTestUtils.assertContentContainsText("http://localhost2:${port}/hello-world/", "Hello");
-                HttpTestUtils.assertContentContainsText("http://localhost2:${port}/hello-world/hello/bob", "http://localhost2:${port}/hello-world/hello/bob");
-            }
-            //cluster 2
-            for (int i = 0; i < 2; i++) {
-                HttpTestUtils.assertContentContainsText("http://localhost3:${port}/c2", "Hello");
-                HttpTestUtils.assertContentContainsText("http://localhost3:${port}/c2/", "Hello");
-                HttpTestUtils.assertContentContainsText("http://localhost3:${port}/c2/hello/joe", "http://localhost3:${port}/c2/hello/new%20joe");
-            }
-        }
-        
-        //these should *not* be available
-        HttpTestUtils.assertHttpStatusCodeEquals("http://localhost:${port}/", 404);
-        HttpTestUtils.assertHttpStatusCodeEquals("http://localhost1:${port}/hello-world", 404);
-        HttpTestUtils.assertHttpStatusCodeEquals("http://localhost2:${port}/", 404);
-        HttpTestUtils.assertHttpStatusCodeEquals("http://localhost2:${port}/hello-world/notexists", 404);
-        HttpTestUtils.assertHttpStatusCodeEquals("http://localhost3:${port}/", 404);
-        
-        //make sure nginx default welcome page isn't displayed
-        Asserts.assertFails { HttpTestUtils.assertContentContainsText([timeout:1], "http://localhost:${port}/", "ginx"); }
-        Asserts.assertFails { HttpTestUtils.assertContentContainsText([timeout:1], "http://localhost2:${port}/", "ginx"); }
-        Asserts.assertFails { HttpTestUtils.assertContentContainsText([timeout:1], "http://localhost3:${port}/", "ginx"); }
-    }
-
-    @Test(groups = "Integration")
-    public void testUrlMappingRoutesRequestByPathToCorrectGroup() {
-        DynamicCluster c0 = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-                .configure("initialSize", 1)
-                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+")));
-        UrlMapping u0 = entityManager.createEntity(EntitySpec.create(UrlMapping.class)
-                .configure("domain", "localhost")
-                .configure("path", '/atC0($|/.*)')
-                .configure("target", c0)
-                .parent(urlMappingsGroup));
-        Entities.manage(u0);
-
-        DynamicCluster c1 = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-                .configure("initialSize", 1)
-                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+")));
-        UrlMapping u1 = entityManager.createEntity(EntitySpec.create(UrlMapping.class)
-                .configure("domain", "localhost")
-                .configure("path", '/atC1($|/.*)')
-                .configure("target", c1)
-                .parent(urlMappingsGroup));
-        Entities.manage(u1);
-
-        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
-                .configure("domain", "localhost")
-                .configure("port", "8000+")
-                .configure("portNumberSensor", WebAppService.HTTP_PORT)
-                .configure("urlMappings", urlMappingsGroup));
-        
-        app.start([ new LocalhostMachineProvisioningLocation() ])
-        int port = nginx.getAttribute(NginxController.PROXY_HTTP_PORT)
-        
-        for (Entity child : c0.getMembers()) {
-            ((JBoss7Server)child).deploy(war.toString(), "atC0.war")
-        }
-        for (Entity child : c1.getMembers()) {
-            ((JBoss7Server)child).deploy(war.toString(), "atC1.war")
-        }
-
-        // Confirm routes requests to the correct cluster
-        // Do more than one request for each in-case just lucky with round-robin...
-        executeUntilSucceeds {
-            for (int i = 0; i < 2; i++) {
-                HttpTestUtils.assertContentContainsText("http://localhost:${port}/atC0", "Hello");
-                HttpTestUtils.assertContentContainsText("http://localhost:${port}/atC0/", "Hello");
-            }
-            for (int i = 0; i < 2; i++) {
-                HttpTestUtils.assertContentContainsText("http://localhost:${port}/atC1", "Hello");
-                HttpTestUtils.assertContentContainsText("http://localhost:${port}/atC1/", "Hello");
-            }
-        }
-    }
-    
-    @Test(groups = "Integration")
-    public void testUrlMappingRemovedWhenMappingEntityRemoved() {
-        DynamicCluster c0 = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-                .configure("initialSize", 1)
-                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+"))
-                .configure(JavaWebAppService.ROOT_WAR, war.toString()));
-        UrlMapping u0 = entityManager.createEntity(EntitySpec.create(UrlMapping.class)
-                .configure("domain", "localhost2")
-                .configure("target", c0)
-                .parent(urlMappingsGroup));
-        Entities.manage(u0);
-        
-        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
-                .configure("domain", "localhost")
-                .configure("port", "8000+")
-                .configure("portNumberSensor", WebAppService.HTTP_PORT)
-                .configure("urlMappings", urlMappingsGroup));
-        
-        app.start([ new LocalhostMachineProvisioningLocation() ])
-        int port = nginx.getAttribute(NginxController.PROXY_HTTP_PORT)
-        
-        // Wait for deployment to be successful
-        HttpTestUtils.assertHttpStatusCodeEventuallyEquals("http://localhost2:${port}/", 200);
-        
-        // Now remove mapping; will no longer route requests
-        Entities.unmanage(u0);
-        HttpTestUtils.assertHttpStatusCodeEventuallyEquals("http://localhost2:${port}/", 404);
-    }
-    
-    @Test(groups = "Integration")
-    public void testWithCoreClusterAndUrlMappedGroup() {
-        // TODO Should use different wars, so can confirm content from each cluster
-        // TODO Could also assert on: nginx.getConfigFile()
-        
-        checkExtraLocalhosts();
-        
-        DynamicCluster coreCluster = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-                .configure("initialSize", 1)
-                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+"))
-                .configure(JavaWebAppService.ROOT_WAR, war.toString()));
-        
-        DynamicCluster c1 = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-                .configure("initialSize", 1)
-                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+"))
-                .configure(JavaWebAppService.NAMED_WARS, [war.toString()]));
-        UrlMapping u1 = entityManager.createEntity(EntitySpec.create(UrlMapping.class)
-                .configure("domain", "localhost1")
-                .configure("target", c1)
-                .parent(urlMappingsGroup));
-        Entities.manage(u1);
-        
-        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
-                .configure("serverPool", coreCluster)
-                .configure("domain", "localhost")
-                .configure("port", "8000+")
-                .configure("portNumberSensor", WebAppService.HTTP_PORT)
-                .configure("urlMappings", urlMappingsGroup));
-                
-        app.start([ new LocalhostMachineProvisioningLocation() ])
-        int port = nginx.getAttribute(NginxController.PROXY_HTTP_PORT)
-        
-        // check nginx forwards localhost1 to c1, and localhost to core group 
-        executeUntilSucceeds {
-            HttpTestUtils.assertContentContainsText("http://localhost1:${port}/hello-world", "Hello");
-            HttpTestUtils.assertHttpStatusCodeEquals("http://localhost1:${port}", 404);
-            
-            HttpTestUtils.assertContentContainsText("http://localhost:${port}", "Hello");
-            HttpTestUtils.assertHttpStatusCodeEquals("http://localhost:${port}/hello-world", 404);
-        }
-    }
-    
-    @Test(groups = "Integration")
-    public void testUrlMappingMultipleRewrites() {
-        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
-                .configure("urlMappings", urlMappingsGroup));
-    
-        //cluster 0 mounted at localhost1 /
-        DynamicCluster c0 = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-                .configure("initialSize", 1)
-                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+"))
-                .configure(JavaWebAppService.ROOT_WAR, WAR_URL));
-        UrlMapping u0 = entityManager.createEntity(EntitySpec.create(UrlMapping.class)
-                .configure("domain", "localhost1")
-                .configure("target", c0)
-                .parent(urlMappingsGroup));
-        u0.addRewrite("/goodbye/al(.*)", '/hello/al$1');
-        u0.addRewrite(new UrlRewriteRule('/goodbye(|/.*)$', '/hello$1').setBreak());
-        u0.addRewrite("(.*)/hello/al(.*)", '$1/hello/Big Al$2');
-        u0.addRewrite('/hello/an(.*)', '/hello/Sir An$1');
-        Entities.manage(u0);
-
-        app.start([ new LocalhostMachineProvisioningLocation() ])
-        int port = nginx.getAttribute(NginxController.PROXY_HTTP_PORT)
-        
-        // Confirm routes requests to the correct cluster
-        executeUntilSucceeds {
-            // health check
-            HttpTestUtils.assertContentContainsText("http://localhost1:${port}", "Hello");
-            HttpTestUtils.assertContentContainsText("http://localhost1:${port}/hello/frank", "http://localhost1:${port}/hello/frank");
-            
-            // goodbye rewritten to hello
-            HttpTestUtils.assertContentContainsText("http://localhost1:${port}/goodbye/frank", "http://localhost1:${port}/hello/frank");
-            // hello al rewritten to hello Big Al
-            HttpTestUtils.assertContentContainsText("http://localhost1:${port}/hello/aled", "http://localhost1:${port}/hello/Big%20Aled");
-            // hello andrew rewritten to hello Sir Andrew
-            HttpTestUtils.assertContentContainsText("http://localhost1:${port}/hello/andrew", "http://localhost1:${port}/hello/Sir%20Andrew");
-            
-            // goodbye alex rewritten to hello Big Alex (two rewrites)
-            HttpTestUtils.assertContentContainsText("http://localhost1:${port}/goodbye/alex", "http://localhost1:${port}/hello/Big%20Alex");
-            // but goodbye andrew rewritten only to hello Andrew -- test the "break" logic above (won't continue rewriting)
-            HttpTestUtils.assertContentContainsText("http://localhost1:${port}/goodbye/andrew", "http://localhost1:${port}/hello/andrew");
-            
-            // al rewrite can be anywhere
-            HttpTestUtils.assertContentContainsText("http://localhost1:${port}/hello/hello/alex", "http://localhost1:${port}/hello/hello/Big%20Alex");
-            // but an rewrite must be at beginning
-            HttpTestUtils.assertContentContainsText("http://localhost1:${port}/hello/hello/andrew", "http://localhost1:${port}/hello/hello/andrew");
-        }
-    }
-    
-    @Test(groups = "Integration")
-    public void testUrlMappingGroupRespondsToScaleOut() {
-        checkExtraLocalhosts();
-        
-        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
-                .configure("domain" : "localhost")
-                .configure("port" : "8000+")
-                .configure("portNumberSensor" : WebAppService.HTTP_PORT)
-                .configure("urlMappings" : urlMappingsGroup));
-        
-        DynamicCluster c1 = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-                .configure("initialSize", 1)
-                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+"))
-                .configure(JavaWebAppService.ROOT_WAR, war.toString()));
-        UrlMapping u1 = entityManager.createEntity(EntitySpec.create(UrlMapping.class)
-                .configure("domain", "localhost1")
-                .configure("target", c1)
-                .parent(urlMappingsGroup));
-        Entities.manage(u1);
-        
-        app.start([ new LocalhostMachineProvisioningLocation() ])
-        int port = nginx.getAttribute(NginxController.PROXY_HTTP_PORT)
-        
-        Entity c1jboss = Iterables.getOnlyElement(c1.getMembers());
-        
-        // Wait for app-server to be responsive, and url-mapping to update its TARGET_ADDRESSES (through async subscription)
-        executeUntilSucceeds {
-            // Entities.dumpInfo(app);
-            assertEquals(u1.getAttribute(UrlMapping.TARGET_ADDRESSES).size(), 1);
-        }
-
-        // check nginx forwards localhost1 to c1
-        HttpTestUtils.assertContentEventuallyContainsText("http://localhost1:${port}", "Hello");
-        
-        // Resize target cluster of url-mapping
-        c1.resize(2);
-        List c1jbosses = new ArrayList(c1.getMembers());
-        c1jbosses.remove(c1jboss);
-        Entity c1jboss2 = Iterables.getOnlyElement(c1jbosses);
-
-        // TODO Have to wait for new app-server; should fix app-servers to block
-        // Also wait for TARGET_ADDRESSES to update
-        assertAppServerRespondsEventually(c1jboss2);
-        executeUntilSucceeds {
-            assertEquals(u1.getAttribute(UrlMapping.TARGET_ADDRESSES).size(), 2);
-        }
-
-        // check jboss2 is included in nginx rules
-        // TODO Should getConfigFile return the current config file, rather than recalculate?
-        //      This assertion isn't good enough to tell if it's been deployed.
-        String c1jboss2addr = c1jboss2.getAttribute(Attributes.HOSTNAME)+":"+c1jboss2.getAttribute(Attributes.HTTP_PORT);
-        assertEventually { 
-            String conf = nginx.getConfigFile();
-            assertTrue(conf.contains(c1jboss2addr), "could not find "+c1jboss2addr+" in:\n"+conf);
-        }
-        
-        // and check forwarding to c1 by nginx still works
-        for (int i = 0; i < 2; i++) {
-            HttpTestUtils.assertContentContainsText("http://localhost1:${port}", "Hello");
-        }
-    }
-    
-    @Test(groups = "Integration")
-    public void testUrlMappingWithEmptyCoreCluster() {
-        DynamicCluster nullCluster = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-            .configure("initialSize", 0)
-            .configure("factory", { throw new UnsupportedOperationException(); }));
-
-        DynamicCluster c0 = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-                .configure("initialSize", 1)
-                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+")));
-        UrlMapping u0 = entityManager.createEntity(EntitySpec.create(UrlMapping.class)
-                .configure("domain", "localhost")
-                .configure("path", '/atC0($|/.*)')
-                .configure("target", c0)
-                .parent(urlMappingsGroup));
-        Entities.manage(u0);
-
-        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
-                .configure("cluster" : nullCluster)
-                .configure("domain" : "localhost")
-                .configure("port" : "8000+")
-                .configure("portNumberSensor" : WebAppService.HTTP_PORT)
-                .configure("urlMappings" : urlMappingsGroup));
-        
-        app.start([ new LocalhostMachineProvisioningLocation() ])
-        int port = nginx.getAttribute(NginxController.PROXY_HTTP_PORT)
-        
-        for (Entity child : c0.getMembers()) {
-            ((JBoss7Server)child).deploy(war.toString(), "atC0.war")
-        }
-
-        // Confirm routes requests to the correct cluster
-        // Do more than one request for each in-case just lucky with round-robin...
-        executeUntilSucceeds {
-            for (int i = 0; i < 2; i++) {
-                HttpTestUtils.assertContentContainsText("http://localhost:${port}/atC0/", "Hello");
-                HttpTestUtils.assertContentContainsText("http://localhost:${port}/atC0", "Hello");
-            }
-        }
-
-        // And empty-core should return 404
-        HttpTestUtils.assertHttpStatusCodeEquals("http://localhost:${port}", 404);
-    }
-    
-    @Test(groups = "Integration")
-    public void testDiscardUrlMapping() {
-        //cluster 0 mounted at localhost1 /
-        DynamicCluster c0 = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-                .configure("initialSize", 1)
-                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+"))
-                .configure(JavaWebAppService.ROOT_WAR, WAR_URL));
-        UrlMapping u0 = entityManager.createEntity(EntitySpec.create(UrlMapping.class)
-                .configure("domain", "localhost1")
-                .configure("target", c0)
-                .parent(urlMappingsGroup));
-        Entities.manage(u0);
-
-        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
-                .configure("urlMappings" : urlMappingsGroup));
-        
-        app.start([ new LocalhostMachineProvisioningLocation() ])
-        int port = nginx.getAttribute(NginxController.PROXY_HTTP_PORT)
-        
-        HttpTestUtils.assertHttpStatusCodeEventuallyEquals("http://localhost1:${port}", 200);
-
-        // Discard, and confirm that subsequently get a 404 instead
-        u0.discard();
-        
-        HttpTestUtils.assertHttpStatusCodeEventuallyEquals("http://localhost1:${port}", 404);
-    }
-
-    private void assertAppServerRespondsEventually(final JBoss7Server server) {
-        String hostname = server.getAttribute(Attributes.HOSTNAME);
-        int port = server.getAttribute(Attributes.HTTP_PORT);
-        HttpTestUtils.assertHttpStatusCodeEventuallyEquals("http://"+hostname+":"+port, 200);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4d86f06c/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxUrlMappingIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxUrlMappingIntegrationTest.java b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxUrlMappingIntegrationTest.java
new file mode 100644
index 0000000..b8103d9
--- /dev/null
+++ b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxUrlMappingIntegrationTest.java
@@ -0,0 +1,523 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.entity.proxy.nginx;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.BrooklynAppLiveTestSupport;
+import brooklyn.entity.Entity;
+import brooklyn.entity.Group;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.BasicGroup;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.EntityFactory;
+import brooklyn.entity.group.DynamicCluster;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.entity.webapp.JavaWebAppService;
+import brooklyn.entity.webapp.WebAppService;
+import brooklyn.entity.webapp.jboss.JBoss7Server;
+import brooklyn.location.basic.LocalhostMachineProvisioningLocation;
+import brooklyn.management.EntityManager;
+import brooklyn.test.Asserts;
+import brooklyn.test.HttpTestUtils;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+
+/**
+ * Test the operation of the {@link NginxController} class, for URL mapped groups (two different pools).
+ * 
+ * These tests require that /etc/hosts contains some extra entries, such as:
+ *     127.0.0.1       localhost localhost1 localhost2 localhost3 localhost4
+ */
+public class NginxUrlMappingIntegrationTest extends BrooklynAppLiveTestSupport {
+    
+    // TODO Make JBoss7Server.deploy wait for the web-app to actually be deployed.
+    // That may simplify some of the tests, because we can assert some things immediately rather than in a succeedsEventually.
+    
+    private static final Logger log = LoggerFactory.getLogger(NginxUrlMappingIntegrationTest.class);
+
+    private static final String WAR_URL = "classpath://hello-world.war";
+    
+    private NginxController nginx;
+    private DynamicCluster cluster;
+    private Group urlMappingsGroup;
+    private EntityManager entityManager;
+    private LocalhostMachineProvisioningLocation localLoc;
+    
+    private URL war;
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        war = getClass().getClassLoader().getResource("hello-world.war");
+        assertNotNull(war, "Unable to locate hello-world.war resource");
+        
+        urlMappingsGroup = app.createAndManageChild(EntitySpec.create(BasicGroup.class)
+                .configure("childrenAsMembers", true));
+        entityManager = app.getManagementContext().getEntityManager();
+        
+        localLoc = new LocalhostMachineProvisioningLocation();
+    }
+
+    protected void checkExtraLocalhosts() throws Exception {
+        Set<String> failedHosts = Sets.newLinkedHashSet();
+        List<String> allHosts = ImmutableList.of("localhost", "localhost1", "localhost2", "localhost3", "localhost4");
+        for (String host : allHosts) {
+            try {
+                InetAddress i = InetAddress.getByName(host);
+                byte[] b = ((Inet4Address)i).getAddress();
+                if (b[0]!=127 || b[1]!=0 || b[2]!=0 || b[3]!=1) {
+                    log.warn("Failed to resolve "+host+" (test will subsequently fail, but looking for more errors first; see subsequent failure for more info): wrong IP "+Arrays.asList(b));
+                    failedHosts.add(host);
+                }
+            } catch (Exception e) {
+                log.warn("Failed to resolve "+host+" (test will subsequently fail, but looking for more errors first; see subsequent failure for more info): "+e, e);
+                failedHosts.add(host);
+            }
+        }
+        if (!failedHosts.isEmpty()) {
+            fail("These tests (in "+this+") require special hostnames to map to 127.0.0.1, in /etc/hosts: "+failedHosts);
+        }
+    }
+    
+    @Test(groups = "Integration")
+    public void testUrlMappingServerNameAndPath() throws Exception {
+        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
+                .configure("urlMappings", urlMappingsGroup));
+        
+        //cluster 0 mounted at localhost1 /
+        DynamicCluster c0 = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+                .configure("initialSize", 1)
+                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+"))
+                .configure(JavaWebAppService.ROOT_WAR, WAR_URL));
+        UrlMapping u0 = entityManager.createEntity(EntitySpec.create(UrlMapping.class)
+                .configure("domain", "localhost1")
+                .configure("target", c0)
+                .parent(urlMappingsGroup));
+        Entities.manage(u0);
+        
+        //cluster 1 at localhost2 /hello-world/
+        DynamicCluster c1 = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+                .configure("initialSize", 1)
+                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+"))
+                .configure(JavaWebAppService.NAMED_WARS, ImmutableList.of(WAR_URL)));
+        UrlMapping u1 = entityManager.createEntity(EntitySpec.create(UrlMapping.class)
+                .configure("domain", "localhost2")
+                .configure("path", "/hello-world($|/.*)")
+                .configure("target", c1)
+                .parent(urlMappingsGroup));
+        Entities.manage(u1);
+
+        // cluster 2 at localhost3 /c2/  and mapping /hello/xxx to /hello/new xxx
+        DynamicCluster c2 = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+                .configure("initialSize", 1)
+                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+")));
+        UrlMapping u2 = entityManager.createEntity(EntitySpec.create(UrlMapping.class)
+                .configure("domain", "localhost3")
+                .configure("path", "/c2($|/.*)")
+                .configure("target", c2)
+                .configure("rewrites", ImmutableList.of(new UrlRewriteRule("(.*/|)(hello/)(.*)", "$1$2new $3").setBreak()))
+                .parent(urlMappingsGroup));
+        Entities.manage(u2);
+        // FIXME rewrite not a config
+        
+        app.start(ImmutableList.of(localLoc));
+        final int port = nginx.getAttribute(NginxController.PROXY_HTTP_PORT);
+        for (Entity member : c2.getMembers()) {
+            ((JBoss7Server)member).deploy(war.toString(), "c2.war");
+        }
+    
+        Entities.dumpInfo(app);
+        
+        // Confirm routes requests to the correct cluster
+        // Do more than one request for each in-case just lucky with round-robin...
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                //cluster 0
+                for (int i = 0; i < 2; i++) {
+                    HttpTestUtils.assertContentContainsText("http://localhost1:"+port, "Hello");
+                    HttpTestUtils.assertContentContainsText("http://localhost1:"+port+"/", "Hello");
+                    HttpTestUtils.assertContentContainsText("http://localhost1:"+port+"/hello/frank", "http://localhost1:"+port+"/hello/frank");
+                }
+                //cluster 1
+                for (int i = 0; i < 2; i++) {
+                    HttpTestUtils.assertContentContainsText("http://localhost2:"+port+"/hello-world", "Hello");
+                    HttpTestUtils.assertContentContainsText("http://localhost2:"+port+"/hello-world/", "Hello");
+                    HttpTestUtils.assertContentContainsText("http://localhost2:"+port+"/hello-world/hello/bob", "http://localhost2:"+port+"/hello-world/hello/bob");
+                }
+                //cluster 2
+                for (int i = 0; i < 2; i++) {
+                    HttpTestUtils.assertContentContainsText("http://localhost3:"+port+"/c2", "Hello");
+                    HttpTestUtils.assertContentContainsText("http://localhost3:"+port+"/c2/", "Hello");
+                    HttpTestUtils.assertContentContainsText("http://localhost3:"+port+"/c2/hello/joe", "http://localhost3:"+port+"/c2/hello/new%20joe");
+                }
+            }});
+        
+        //these should *not* be available
+        HttpTestUtils.assertHttpStatusCodeEquals("http://localhost:"+port+"/", 404);
+        HttpTestUtils.assertHttpStatusCodeEquals("http://localhost1:"+port+"/hello-world", 404);
+        HttpTestUtils.assertHttpStatusCodeEquals("http://localhost2:"+port+"/", 404);
+        HttpTestUtils.assertHttpStatusCodeEquals("http://localhost2:"+port+"/hello-world/notexists", 404);
+        HttpTestUtils.assertHttpStatusCodeEquals("http://localhost3:"+port+"/", 404);
+        
+        //make sure nginx default welcome page isn't displayed
+        HttpTestUtils.assertContentNotContainsText("http://localhost:"+port+"/", "ginx");
+        HttpTestUtils.assertContentNotContainsText("http://localhost2:"+port+"/", "ginx");
+        HttpTestUtils.assertContentNotContainsText("http://localhost3:"+port+"/", "ginx");
+    }
+
+    @Test(groups = "Integration")
+    public void testUrlMappingRoutesRequestByPathToCorrectGroup() throws Exception {
+        DynamicCluster c0 = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+                .configure("initialSize", 1)
+                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+")));
+        UrlMapping u0 = entityManager.createEntity(EntitySpec.create(UrlMapping.class)
+                .configure("domain", "localhost")
+                .configure("path", "/atC0($|/.*)")
+                .configure("target", c0)
+                .parent(urlMappingsGroup));
+        Entities.manage(u0);
+
+        DynamicCluster c1 = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+                .configure("initialSize", 1)
+                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+")));
+        UrlMapping u1 = entityManager.createEntity(EntitySpec.create(UrlMapping.class)
+                .configure("domain", "localhost")
+                .configure("path", "/atC1($|/.*)")
+                .configure("target", c1)
+                .parent(urlMappingsGroup));
+        Entities.manage(u1);
+
+        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
+                .configure("domain", "localhost")
+                .configure("port", "8000+")
+                .configure("portNumberSensor", WebAppService.HTTP_PORT)
+                .configure("urlMappings", urlMappingsGroup));
+        
+        app.start(ImmutableList.of(localLoc));
+        final int port = nginx.getAttribute(NginxController.PROXY_HTTP_PORT);
+        
+        for (Entity child : c0.getMembers()) {
+            ((JBoss7Server)child).deploy(war.toString(), "atC0.war");
+        }
+        for (Entity child : c1.getMembers()) {
+            ((JBoss7Server)child).deploy(war.toString(), "atC1.war");
+        }
+
+        // Confirm routes requests to the correct cluster
+        // Do more than one request for each in-case just lucky with round-robin...
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                for (int i = 0; i < 2; i++) {
+                    HttpTestUtils.assertContentContainsText("http://localhost:"+port+"/atC0", "Hello");
+                    HttpTestUtils.assertContentContainsText("http://localhost:"+port+"/atC0/", "Hello");
+                }
+                for (int i = 0; i < 2; i++) {
+                    HttpTestUtils.assertContentContainsText("http://localhost:"+port+"/atC1", "Hello");
+                    HttpTestUtils.assertContentContainsText("http://localhost:"+port+"/atC1/", "Hello");
+                }
+            }});
+    }
+    
+    @Test(groups = "Integration")
+    public void testUrlMappingRemovedWhenMappingEntityRemoved() throws Exception {
+        DynamicCluster c0 = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+                .configure("initialSize", 1)
+                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+"))
+                .configure(JavaWebAppService.ROOT_WAR, war.toString()));
+        UrlMapping u0 = entityManager.createEntity(EntitySpec.create(UrlMapping.class)
+                .configure("domain", "localhost2")
+                .configure("target", c0)
+                .parent(urlMappingsGroup));
+        Entities.manage(u0);
+        
+        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
+                .configure("domain", "localhost")
+                .configure("port", "8000+")
+                .configure("portNumberSensor", WebAppService.HTTP_PORT)
+                .configure("urlMappings", urlMappingsGroup));
+        
+        app.start(ImmutableList.of(localLoc));
+        int port = nginx.getAttribute(NginxController.PROXY_HTTP_PORT);
+        
+        // Wait for deployment to be successful
+        HttpTestUtils.assertHttpStatusCodeEventuallyEquals("http://localhost2:"+port+"/", 200);
+        
+        // Now remove mapping; will no longer route requests
+        Entities.unmanage(u0);
+        HttpTestUtils.assertHttpStatusCodeEventuallyEquals("http://localhost2:"+port+"/", 404);
+    }
+    
+    @Test(groups = "Integration")
+    public void testWithCoreClusterAndUrlMappedGroup() throws Exception {
+        // TODO Should use different wars, so can confirm content from each cluster
+        // TODO Could also assert on: nginx.getConfigFile()
+        
+        checkExtraLocalhosts();
+        
+        DynamicCluster coreCluster = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+                .configure("initialSize", 1)
+                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+"))
+                .configure(JavaWebAppService.ROOT_WAR, war.toString()));
+        
+        DynamicCluster c1 = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+                .configure("initialSize", 1)
+                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+"))
+                .configure(JavaWebAppService.NAMED_WARS, ImmutableList.of(war.toString())));
+        UrlMapping u1 = entityManager.createEntity(EntitySpec.create(UrlMapping.class)
+                .configure("domain", "localhost1")
+                .configure("target", c1)
+                .parent(urlMappingsGroup));
+        Entities.manage(u1);
+        
+        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
+                .configure("serverPool", coreCluster)
+                .configure("domain", "localhost")
+                .configure("port", "8000+")
+                .configure("portNumberSensor", WebAppService.HTTP_PORT)
+                .configure("urlMappings", urlMappingsGroup));
+                
+        app.start(ImmutableList.of(localLoc));
+        final int port = nginx.getAttribute(NginxController.PROXY_HTTP_PORT);
+        
+        // check nginx forwards localhost1 to c1, and localhost to core group 
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                HttpTestUtils.assertContentContainsText("http://localhost1:"+port+"/hello-world", "Hello");
+                HttpTestUtils.assertHttpStatusCodeEquals("http://localhost1:"+port+"", 404);
+                
+                HttpTestUtils.assertContentContainsText("http://localhost:"+port+"", "Hello");
+                HttpTestUtils.assertHttpStatusCodeEquals("http://localhost:"+port+"/hello-world", 404);
+            }});
+    }
+    
+    @Test(groups = "Integration")
+    public void testUrlMappingMultipleRewrites() throws Exception {
+        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
+                .configure("urlMappings", urlMappingsGroup));
+    
+        //cluster 0 mounted at localhost1 /
+        DynamicCluster c0 = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+                .configure("initialSize", 1)
+                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+"))
+                .configure(JavaWebAppService.ROOT_WAR, WAR_URL));
+        UrlMapping u0 = entityManager.createEntity(EntitySpec.create(UrlMapping.class)
+                .configure("domain", "localhost1")
+                .configure("target", c0)
+                .parent(urlMappingsGroup));
+        u0.addRewrite("/goodbye/al(.*)", "/hello/al$1");
+        u0.addRewrite(new UrlRewriteRule("/goodbye(|/.*)$", "/hello$1").setBreak());
+        u0.addRewrite("(.*)/hello/al(.*)", "$1/hello/Big Al$2");
+        u0.addRewrite("/hello/an(.*)", "/hello/Sir An$1");
+        Entities.manage(u0);
+
+        app.start(ImmutableList.of(localLoc));
+        final int port = nginx.getAttribute(NginxController.PROXY_HTTP_PORT);
+        
+        // Confirm routes requests to the correct cluster
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                // health check
+                HttpTestUtils.assertContentContainsText("http://localhost1:"+port+"", "Hello");
+                HttpTestUtils.assertContentContainsText("http://localhost1:"+port+"/hello/frank", "http://localhost1:"+port+"/hello/frank");
+                
+                // goodbye rewritten to hello
+                HttpTestUtils.assertContentContainsText("http://localhost1:"+port+"/goodbye/frank", "http://localhost1:"+port+"/hello/frank");
+                // hello al rewritten to hello Big Al
+                HttpTestUtils.assertContentContainsText("http://localhost1:"+port+"/hello/aled", "http://localhost1:"+port+"/hello/Big%20Aled");
+                // hello andrew rewritten to hello Sir Andrew
+                HttpTestUtils.assertContentContainsText("http://localhost1:"+port+"/hello/andrew", "http://localhost1:"+port+"/hello/Sir%20Andrew");
+                
+                // goodbye alex rewritten to hello Big Alex (two rewrites)
+                HttpTestUtils.assertContentContainsText("http://localhost1:"+port+"/goodbye/alex", "http://localhost1:"+port+"/hello/Big%20Alex");
+                // but goodbye andrew rewritten only to hello Andrew -- test the "break" logic above (won't continue rewriting)
+                HttpTestUtils.assertContentContainsText("http://localhost1:"+port+"/goodbye/andrew", "http://localhost1:"+port+"/hello/andrew");
+                
+                // al rewrite can be anywhere
+                HttpTestUtils.assertContentContainsText("http://localhost1:"+port+"/hello/hello/alex", "http://localhost1:"+port+"/hello/hello/Big%20Alex");
+                // but an rewrite must be at beginning
+                HttpTestUtils.assertContentContainsText("http://localhost1:"+port+"/hello/hello/andrew", "http://localhost1:"+port+"/hello/hello/andrew");
+            }});
+    }
+    
+    @Test(groups = "Integration")
+    public void testUrlMappingGroupRespondsToScaleOut() throws Exception {
+        checkExtraLocalhosts();
+        
+        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
+                .configure("domain", "localhost")
+                .configure("port", "8000+")
+                .configure("portNumberSensor", WebAppService.HTTP_PORT)
+                .configure("urlMappings", urlMappingsGroup));
+        
+        final DynamicCluster c1 = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+                .configure("initialSize", 1)
+                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+"))
+                .configure(JavaWebAppService.ROOT_WAR, war.toString()));
+        final UrlMapping u1 = entityManager.createEntity(EntitySpec.create(UrlMapping.class)
+                .configure("domain", "localhost1")
+                .configure("target", c1)
+                .parent(urlMappingsGroup));
+        Entities.manage(u1);
+        
+        app.start(ImmutableList.of(localLoc));
+        int port = nginx.getAttribute(NginxController.PROXY_HTTP_PORT);
+        
+        Entity c1jboss = Iterables.getOnlyElement(c1.getMembers());
+        
+        // Wait for app-server to be responsive, and url-mapping to update its TARGET_ADDRESSES (through async subscription)
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                // Entities.dumpInfo(app);
+                assertEquals(u1.getAttribute(UrlMapping.TARGET_ADDRESSES).size(), 1);
+            }});
+
+        // check nginx forwards localhost1 to c1
+        HttpTestUtils.assertContentEventuallyContainsText("http://localhost1:"+port+"", "Hello");
+        
+        // Resize target cluster of url-mapping
+        c1.resize(2);
+        List c1jbosses = new ArrayList(c1.getMembers());
+        c1jbosses.remove(c1jboss);
+        Entity c1jboss2 = Iterables.getOnlyElement(c1jbosses);
+
+        // TODO Have to wait for new app-server; should fix app-servers to block
+        // Also wait for TARGET_ADDRESSES to update
+        assertAppServerRespondsEventually(c1jboss2);
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                assertEquals(u1.getAttribute(UrlMapping.TARGET_ADDRESSES).size(), 2);
+            }});
+
+        // check jboss2 is included in nginx rules
+        // TODO Should getConfigFile return the current config file, rather than recalculate?
+        //      This assertion isn't good enough to tell if it's been deployed.
+        final String c1jboss2addr = c1jboss2.getAttribute(Attributes.HOSTNAME)+":"+c1jboss2.getAttribute(Attributes.HTTP_PORT);
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                String conf = nginx.getConfigFile();
+                assertTrue(conf.contains(c1jboss2addr), "could not find "+c1jboss2addr+" in:\n"+conf);
+            }});
+        
+        // and check forwarding to c1 by nginx still works
+        for (int i = 0; i < 2; i++) {
+            HttpTestUtils.assertContentContainsText("http://localhost1:"+port+"", "Hello");
+        }
+    }
+    
+    @Test(groups = "Integration")
+    public void testUrlMappingWithEmptyCoreCluster() throws Exception {
+        DynamicCluster nullCluster = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+            .configure("initialSize", 0)
+            .configure("factory", new EntityFactory<Entity>() {
+                public Entity newEntity(Map flags, Entity parent) {
+                    throw new UnsupportedOperationException();
+                }}));
+
+        DynamicCluster c0 = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+                .configure("initialSize", 1)
+                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+")));
+        UrlMapping u0 = entityManager.createEntity(EntitySpec.create(UrlMapping.class)
+                .configure("domain", "localhost")
+                .configure("path", "/atC0($|/.*)")
+                .configure("target", c0)
+                .parent(urlMappingsGroup));
+        Entities.manage(u0);
+
+        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
+                .configure("cluster", nullCluster)
+                .configure("domain", "localhost")
+                .configure("port", "8000+")
+                .configure("portNumberSensor", WebAppService.HTTP_PORT)
+                .configure("urlMappings", urlMappingsGroup));
+        
+        app.start(ImmutableList.of(localLoc));
+        final int port = nginx.getAttribute(NginxController.PROXY_HTTP_PORT);
+        
+        for (Entity child : c0.getMembers()) {
+            ((JBoss7Server)child).deploy(war.toString(), "atC0.war");
+        }
+
+        // Confirm routes requests to the correct cluster
+        // Do more than one request for each in-case just lucky with round-robin...
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                for (int i = 0; i < 2; i++) {
+                    HttpTestUtils.assertContentContainsText("http://localhost:"+port+"/atC0/", "Hello");
+                    HttpTestUtils.assertContentContainsText("http://localhost:"+port+"/atC0", "Hello");
+                }
+            }});
+
+        // And empty-core should return 404
+        HttpTestUtils.assertHttpStatusCodeEquals("http://localhost:"+port+"", 404);
+    }
+    
+    @Test(groups = "Integration")
+    public void testDiscardUrlMapping() throws Exception {
+        //cluster 0 mounted at localhost1 /
+        DynamicCluster c0 = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+                .configure("initialSize", 1)
+                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class).configure("httpPort", "8100+"))
+                .configure(JavaWebAppService.ROOT_WAR, WAR_URL));
+        UrlMapping u0 = entityManager.createEntity(EntitySpec.create(UrlMapping.class)
+                .configure("domain", "localhost1")
+                .configure("target", c0)
+                .parent(urlMappingsGroup));
+        Entities.manage(u0);
+
+        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
+                .configure("urlMappings", urlMappingsGroup));
+        
+        app.start(ImmutableList.of(localLoc));
+        int port = nginx.getAttribute(NginxController.PROXY_HTTP_PORT);
+        
+        HttpTestUtils.assertHttpStatusCodeEventuallyEquals("http://localhost1:"+port+"", 200);
+
+        // Discard, and confirm that subsequently get a 404 instead
+        u0.discard();
+        
+        HttpTestUtils.assertHttpStatusCodeEventuallyEquals("http://localhost1:"+port+"", 404);
+    }
+
+    private void assertAppServerRespondsEventually(Entity server) {
+        String hostname = server.getAttribute(Attributes.HOSTNAME);
+        int port = server.getAttribute(Attributes.HTTP_PORT);
+        HttpTestUtils.assertHttpStatusCodeEventuallyEquals("http://"+hostname+":"+port, 200);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4d86f06c/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxWebClusterEc2LiveTest.groovy
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxWebClusterEc2LiveTest.groovy b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxWebClusterEc2LiveTest.groovy
deleted file mode 100644
index 49de9c5..0000000
--- a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxWebClusterEc2LiveTest.groovy
+++ /dev/null
@@ -1,107 +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 brooklyn.entity.proxy.nginx
-
-import static brooklyn.test.TestUtils.*
-import static org.testng.Assert.*
-
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import org.testng.annotations.AfterMethod
-import org.testng.annotations.BeforeMethod
-import org.testng.annotations.Test
-
-import brooklyn.entity.basic.ApplicationBuilder
-import brooklyn.entity.basic.Entities
-import brooklyn.entity.group.DynamicCluster
-import brooklyn.entity.proxying.EntitySpec
-import brooklyn.entity.webapp.JavaWebAppService
-import brooklyn.entity.webapp.WebAppService
-import brooklyn.entity.webapp.jboss.JBoss7Server
-import brooklyn.location.Location
-import brooklyn.location.MachineLocation
-import brooklyn.management.ManagementContext
-import brooklyn.test.HttpTestUtils
-import brooklyn.test.entity.TestApplication
-
-import com.google.common.collect.ImmutableMap
-
-/**
- * Test Nginx proxying a cluster of JBoss7Server entities on AWS for ENGR-1689.
- *
- * This test is a proof-of-concept for the Brooklyn demo application, with each
- * service running on a separate Amazon EC2 instance.
- */
-public class NginxWebClusterEc2LiveTest {
-    private static final Logger LOG = LoggerFactory.getLogger(NginxWebClusterEc2LiveTest.class)
-    
-    private TestApplication app
-    private NginxController nginx
-    private DynamicCluster cluster
-    private Location loc
-
-    @BeforeMethod(alwaysRun = true)
-    public void setUp() {
-        ManagementContext managementContext = Entities.newManagementContext(
-                ImmutableMap.of("brooklyn.location.jclouds.aws-ec2.image-id", "us-east-1/ami-2342a94a"));
-        
-        loc = managementContext.getLocationRegistry().resolve("aws-ec2:us-east-1")
-        app = ApplicationBuilder.newManagedApp(TestApplication.class);
-        Entities.startManagement(app, managementContext)
-    }
-
-    @AfterMethod(alwaysRun = true)
-    public void shutdown() {
-        if (app != null) Entities.destroyAll(app.getManagementContext());
-    }
-    
-    @Test(groups = "Live")
-    public void testProvisionAwsCluster() {
-        URL war = getClass().getClassLoader().getResource("swf-booking-mvc.war")
-        assertNotNull war, "Unable to locate resource $war"
-        
-        cluster = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class))
-                .configure("initialSize", 2)
-                .configure("httpPort", 8080)
-                .configure(JavaWebAppService.ROOT_WAR, war.path));
-        
-        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
-                .configure("cluster", cluster)
-                .configure("domain", "localhost")
-                .configure("port", 8000)
-                .configure("portNumberSensor", WebAppService.HTTP_PORT));
-
-        app.start([ loc ])
-        
-        executeUntilSucceeds {
-            // Nginx URL is available
-            MachineLocation machine = nginx.locations.find { true }
-            String url = "http://" + machine.address.hostName + ":" + nginx.getAttribute(NginxController.PROXY_HTTP_PORT) + "/swf-booking-mvc"
-            HttpTestUtils.assertHttpStatusCodeEquals(url, 200)
-
-            // Web-app URL is available
-            cluster.members.each {
-                HttpTestUtils.assertHttpStatusCodeEquals(it.getAttribute(JavaWebAppService.ROOT_URL) + "swf-booking-mvc", 200)
-            }
-        }
-
-		nginx.stop()
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4d86f06c/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxWebClusterEc2LiveTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxWebClusterEc2LiveTest.java b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxWebClusterEc2LiveTest.java
new file mode 100644
index 0000000..589e13e
--- /dev/null
+++ b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxWebClusterEc2LiveTest.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.entity.proxy.nginx;
+
+import static org.testng.Assert.assertNotNull;
+
+import java.net.URL;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.ApplicationBuilder;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.group.DynamicCluster;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.entity.webapp.JavaWebAppService;
+import brooklyn.entity.webapp.WebAppService;
+import brooklyn.entity.webapp.jboss.JBoss7Server;
+import brooklyn.location.Location;
+import brooklyn.location.MachineLocation;
+import brooklyn.location.basic.Machines;
+import brooklyn.management.ManagementContext;
+import brooklyn.test.Asserts;
+import brooklyn.test.HttpTestUtils;
+import brooklyn.test.entity.TestApplication;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Test Nginx proxying a cluster of JBoss7Server entities on AWS for ENGR-1689.
+ *
+ * This test is a proof-of-concept for the Brooklyn demo application, with each
+ * service running on a separate Amazon EC2 instance.
+ */
+public class NginxWebClusterEc2LiveTest {
+    private static final Logger LOG = LoggerFactory.getLogger(NginxWebClusterEc2LiveTest.class);
+    
+    private TestApplication app;
+    private NginxController nginx;
+    private DynamicCluster cluster;
+    private Location loc;
+
+    @BeforeMethod(alwaysRun = true)
+    public void setUp() {
+        ManagementContext managementContext = Entities.newManagementContext(
+                ImmutableMap.of("brooklyn.location.jclouds.aws-ec2.image-id", "us-east-1/ami-2342a94a"));
+        
+        loc = managementContext.getLocationRegistry().resolve("aws-ec2:us-east-1");
+        app = ApplicationBuilder.newManagedApp(TestApplication.class, managementContext);
+    }
+
+    @AfterMethod(alwaysRun = true)
+    public void shutdown() {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+    
+    @Test(groups = "Live")
+    public void testProvisionAwsCluster() {
+        String warName = "swf-booking-mvc.war";
+        URL war = getClass().getClassLoader().getResource(warName);
+        assertNotNull(war, "Unable to locate resource "+warName);
+        
+        cluster = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class))
+                .configure("initialSize", 2)
+                .configure("httpPort", 8080)
+                .configure(JavaWebAppService.ROOT_WAR, war.getPath()));
+        
+        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
+                .configure("cluster", cluster)
+                .configure("domain", "localhost")
+                .configure("port", 8000)
+                .configure("portNumberSensor", WebAppService.HTTP_PORT));
+
+        app.start(ImmutableList.of(loc));
+        
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                // Nginx URL is available
+                MachineLocation machine = Machines.findUniqueMachineLocation(nginx.getLocations()).get();
+                String url = "http://" + machine.getAddress().getHostName() + ":" + nginx.getAttribute(NginxController.PROXY_HTTP_PORT) + "/swf-booking-mvc";
+                HttpTestUtils.assertHttpStatusCodeEquals(url, 200);
+    
+                // Web-app URL is available
+                for (Entity member : cluster.getMembers()) {
+                    HttpTestUtils.assertHttpStatusCodeEquals(member.getAttribute(JavaWebAppService.ROOT_URL) + "swf-booking-mvc", 200);
+                }
+            }});
+
+		nginx.stop();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4d86f06c/usage/test-support/src/main/java/brooklyn/test/HttpTestUtils.java
----------------------------------------------------------------------
diff --git a/usage/test-support/src/main/java/brooklyn/test/HttpTestUtils.java b/usage/test-support/src/main/java/brooklyn/test/HttpTestUtils.java
index 097b16e..bc238bf 100644
--- a/usage/test-support/src/main/java/brooklyn/test/HttpTestUtils.java
+++ b/usage/test-support/src/main/java/brooklyn/test/HttpTestUtils.java
@@ -231,6 +231,21 @@ public class HttpTestUtils {
         }
     }
 
+    public static void assertContentNotContainsText(final String url, final String phrase, final String ...additionalPhrases) {
+        try {
+            String contents = getContent(url);
+            Assert.assertTrue(contents != null);
+            for (String text: Lists.asList(phrase, additionalPhrases)) {
+                if (contents.contains(text)) {
+                    LOG.warn("CONTENTS OF URL "+url+" HAS TEXT: "+text+"\n"+contents);
+                    Assert.fail("URL "+url+" contain text: "+text);
+                }
+            }
+        } catch (Exception e) {
+            throw Throwables.propagate(e);
+        }
+    }
+
     public static void assertContentEventuallyContainsText(final String url, final String phrase, final String ...additionalPhrases) {
         assertContentEventuallyContainsText(MutableMap.of(), url, phrase, additionalPhrases);
     }


[4/5] git commit: Convert nginx tests from groovy to java

Posted by al...@apache.org.
Convert nginx tests from groovy to java


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

Branch: refs/heads/master
Commit: 4d86f06c873697cdaed7424be8d5c236f195fa95
Parents: 8643fbc
Author: Aled Sage <al...@gmail.com>
Authored: Wed Jul 16 15:20:51 2014 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Thu Aug 21 16:49:43 2014 +0100

----------------------------------------------------------------------
 .../brooklyn/entity/proxy/ProxySslConfig.java   |  79 +++
 .../nginx/NginxClusterIntegrationTest.java      |  49 +-
 .../nginx/NginxHttpsSslIntegrationTest.groovy   | 171 ------
 .../nginx/NginxHttpsSslIntegrationTest.java     | 182 +++++++
 .../proxy/nginx/NginxIntegrationTest.groovy     | 432 ---------------
 .../proxy/nginx/NginxIntegrationTest.java       | 449 ++++++++++++++++
 .../proxy/nginx/NginxLightIntegrationTest.java  |  21 +-
 .../proxy/nginx/NginxRebindIntegrationTest.java |   3 -
 .../nginx/NginxUrlMappingIntegrationTest.groovy | 503 ------------------
 .../nginx/NginxUrlMappingIntegrationTest.java   | 523 +++++++++++++++++++
 .../nginx/NginxWebClusterEc2LiveTest.groovy     | 107 ----
 .../proxy/nginx/NginxWebClusterEc2LiveTest.java | 113 ++++
 .../main/java/brooklyn/test/HttpTestUtils.java  |  15 +
 13 files changed, 1383 insertions(+), 1264 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4d86f06c/software/webapp/src/main/java/brooklyn/entity/proxy/ProxySslConfig.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/proxy/ProxySslConfig.java b/software/webapp/src/main/java/brooklyn/entity/proxy/ProxySslConfig.java
index 28dddd5..0d1be84 100644
--- a/software/webapp/src/main/java/brooklyn/entity/proxy/ProxySslConfig.java
+++ b/software/webapp/src/main/java/brooklyn/entity/proxy/ProxySslConfig.java
@@ -34,7 +34,10 @@ import com.google.common.base.Objects;
 
 public class ProxySslConfig implements Serializable {
 
+    private static final long serialVersionUID = -2692754611458939617L;
+    
     private static final Logger LOG = LoggerFactory.getLogger(ProxySslConfig.class);
+    
     private static final AtomicBoolean initialized = new AtomicBoolean(false);
 
     /** Setup type coercion. */
@@ -72,6 +75,42 @@ public class ProxySslConfig implements Serializable {
         init();
     }
 
+    public static Builder builder() {
+        return new Builder();
+    }
+    
+    public static class Builder {
+        protected String certificateSourceUrl;
+        protected String keySourceUrl;
+        protected String certificateDestination;
+        protected String keyDestination;
+        protected boolean targetIsSsl = false;
+        protected boolean reuseSessions = false;
+        
+        public Builder certificateSourceUrl(String val) {
+            certificateSourceUrl = val; return this;
+        }
+        public Builder keySourceUrl(String val) {
+            keySourceUrl = val; return this;
+        }
+        public Builder certificateDestination(String val) {
+            certificateDestination = val; return this;
+        }
+        public Builder keyDestination(String val) {
+            keyDestination = val; return this;
+        }
+        public Builder targetIsSsl(boolean val) {
+            targetIsSsl = val; return this;
+        }
+        public Builder reuseSessions(boolean val) {
+            reuseSessions = val; return this;
+        }
+        public ProxySslConfig build() {
+            ProxySslConfig result = new ProxySslConfig(this);
+            return result;
+        }
+    }
+    
     /** 
      * url's for the SSL certificates required at the server
      * <p>
@@ -121,10 +160,30 @@ public class ProxySslConfig implements Serializable {
      * corresponds to nginx setting: proxy_ssl_session_reuse on|off */
     boolean reuseSessions = false;
 
+    /**
+     * @deprecated since 0.7.0; use {@link ProxySslConfig#builder()}
+     */
+    @Deprecated
+    public ProxySslConfig() {
+    }
+    
+    protected ProxySslConfig(Builder builder) {
+        certificateSourceUrl = builder.certificateSourceUrl;
+        keySourceUrl = builder.keySourceUrl;
+        certificateDestination = builder.certificateDestination;
+        keyDestination = builder.keyDestination;
+        targetIsSsl = builder.targetIsSsl;
+        reuseSessions = builder.reuseSessions;
+    }
+    
     public String getCertificateSourceUrl() {
         return certificateSourceUrl;
     }
 
+    /**
+     * @deprecated since 0.7.0; use {@link ProxySslConfig#builder()}
+     */
+    @Deprecated
     public void setCertificateSourceUrl(String certificateSourceUrl) {
         this.certificateSourceUrl = certificateSourceUrl;
     }
@@ -133,6 +192,10 @@ public class ProxySslConfig implements Serializable {
         return keySourceUrl;
     }
 
+    /**
+     * @deprecated since 0.7.0; use {@link ProxySslConfig#builder()}
+     */
+    @Deprecated
     public void setKeySourceUrl(String keySourceUrl) {
         this.keySourceUrl = keySourceUrl;
     }
@@ -141,6 +204,10 @@ public class ProxySslConfig implements Serializable {
         return certificateDestination;
     }
 
+    /**
+     * @deprecated since 0.7.0; use {@link ProxySslConfig#builder()}
+     */
+    @Deprecated
     public void setCertificateDestination(String certificateDestination) {
         this.certificateDestination = certificateDestination;
     }
@@ -149,6 +216,10 @@ public class ProxySslConfig implements Serializable {
         return keyDestination;
     }
 
+    /**
+     * @deprecated since 0.7.0; use {@link ProxySslConfig#builder()}
+     */
+    @Deprecated
     public void setKeyDestination(String keyDestination) {
         this.keyDestination = keyDestination;
     }
@@ -157,6 +228,10 @@ public class ProxySslConfig implements Serializable {
         return targetIsSsl;
     }
 
+    /**
+     * @deprecated since 0.7.0; use {@link ProxySslConfig#builder()}
+     */
+    @Deprecated
     public void setTargetIsSsl(boolean targetIsSsl) {
         this.targetIsSsl = targetIsSsl;
     }
@@ -165,6 +240,10 @@ public class ProxySslConfig implements Serializable {
         return reuseSessions;
     }
 
+    /**
+     * @deprecated since 0.7.0; use {@link ProxySslConfig#builder()}
+     */
+    @Deprecated
     public void setReuseSessions(boolean reuseSessions) {
         this.reuseSessions = reuseSessions;
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4d86f06c/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxClusterIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxClusterIntegrationTest.java b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxClusterIntegrationTest.java
index 24660d7..5c6b115 100644
--- a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxClusterIntegrationTest.java
+++ b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxClusterIntegrationTest.java
@@ -18,7 +18,6 @@
  */
 package brooklyn.entity.proxy.nginx;
 
-import static brooklyn.test.TestUtils.urlRespondsStatusCode;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertTrue;
@@ -29,12 +28,11 @@ import java.util.List;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
+import brooklyn.entity.BrooklynAppLiveTestSupport;
 import brooklyn.entity.Group;
-import brooklyn.entity.basic.ApplicationBuilder;
 import brooklyn.entity.basic.BasicGroup;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.group.DynamicCluster;
@@ -43,11 +41,12 @@ import brooklyn.entity.proxying.EntitySpec;
 import brooklyn.entity.trait.Startable;
 import brooklyn.entity.webapp.JavaWebAppService;
 import brooklyn.entity.webapp.jboss.JBoss7Server;
-import brooklyn.location.basic.LocalhostMachineProvisioningLocation;
+import brooklyn.location.Location;
 import brooklyn.location.basic.PortRanges;
 import brooklyn.management.EntityManager;
-import brooklyn.test.TestUtils;
-import brooklyn.test.entity.TestApplication;
+import brooklyn.test.Asserts;
+import brooklyn.test.EntityTestUtils;
+import brooklyn.test.HttpTestUtils;
 import brooklyn.util.collections.MutableMap;
 
 import com.google.common.base.Predicates;
@@ -59,27 +58,26 @@ import com.google.common.collect.Lists;
 /**
  * Test the operation of the {@link NginxController} class.
  */
-public class NginxClusterIntegrationTest {
+public class NginxClusterIntegrationTest extends BrooklynAppLiveTestSupport {
+    @SuppressWarnings("unused")
     private static final Logger log = LoggerFactory.getLogger(NginxClusterIntegrationTest.class);
 
     private static final long TIMEOUT_MS = 60*1000;
     
     private URL war;
-    private LocalhostMachineProvisioningLocation localhostProvisioningLoc;
-    private TestApplication app;
+    private Location localhostProvisioningLoc;
     private EntityManager entityManager;
     private LoadBalancerCluster loadBalancerCluster;
     private EntitySpec<NginxController> nginxSpec;
     private Group urlMappings;
 
-
-    
-    @BeforeMethod(groups = "Integration")
-    public void setup() throws Exception {
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
         war = checkNotNull(getClass().getClassLoader().getResource("hello-world.war"), "hello-world.war not on classpath");
-        localhostProvisioningLoc = new LocalhostMachineProvisioningLocation(MutableMap.of("address", "localhost"));
+        localhostProvisioningLoc = mgmt.getLocationRegistry().resolve("localhost");
         
-        app = ApplicationBuilder.newManagedApp(TestApplication.class);
         urlMappings = app.createAndManageChild(EntitySpec.create(BasicGroup.class)
                 .configure("childrenAsMembers", true));
         entityManager = app.getManagementContext().getEntityManager();
@@ -87,11 +85,6 @@ public class NginxClusterIntegrationTest {
         nginxSpec = EntitySpec.create(NginxController.class);
     }
 
-    @AfterMethod(groups = "Integration", alwaysRun=true)
-    public void shutdown() {
-        if (app != null) Entities.destroyAll(app.getManagementContext());
-    }
-
     @Test(groups = "Integration")
     public void testCreatesNginxInstancesAndResizes() {
         loadBalancerCluster = app.createAndManageChild(EntitySpec.create(LoadBalancerCluster.class)
@@ -169,13 +162,13 @@ public class NginxClusterIntegrationTest {
                 .configure(NginxController.DOMAIN_NAME, "localhost"));
         
         app.start(ImmutableList.of(localhostProvisioningLoc));
-        TestUtils.assertAttributeContinually(loadBalancerCluster, Startable.SERVICE_UP, false);
+        EntityTestUtils.assertAttributeEqualsContinually(loadBalancerCluster, Startable.SERVICE_UP, false);
         
         loadBalancerCluster.resize(1);
-        TestUtils.assertAttributeEventually(loadBalancerCluster, Startable.SERVICE_UP, true);
+        EntityTestUtils.assertAttributeEqualsEventually(loadBalancerCluster, Startable.SERVICE_UP, true);
 
         loadBalancerCluster.resize(0);
-        TestUtils.assertAttributeEventually(loadBalancerCluster, Startable.SERVICE_UP, false);
+        EntityTestUtils.assertAttributeEqualsEventually(loadBalancerCluster, Startable.SERVICE_UP, false);
     }
     
     // Warning: test is a little brittle for if a previous run leaves something on these required ports
@@ -217,12 +210,8 @@ public class NginxClusterIntegrationTest {
         assertNginxsResponsiveEvenutally(nginxs, null, Collections.<String>emptyList());
     }
 
-    private void assertNginxsResponsiveEvenutally(final Iterable<NginxController> nginxs, final List<String> pathsFor200) {
-        assertNginxsResponsiveEvenutally(nginxs, null, pathsFor200);
-    }
-    
     private void assertNginxsResponsiveEvenutally(final Iterable<NginxController> nginxs, final String hostname, final List<String> pathsFor200) {
-        TestUtils.executeUntilSucceeds(MutableMap.of("timeout", TIMEOUT_MS), new Runnable() {
+        Asserts.succeedsEventually(MutableMap.of("timeout", TIMEOUT_MS), new Runnable() {
             public void run() {
                 for (NginxController nginx : nginxs) {
                     assertTrue(nginx.getAttribute(NginxController.SERVICE_UP));
@@ -232,11 +221,11 @@ public class NginxClusterIntegrationTest {
                     String rootUrl = (hostname != null) ? ("http://"+hostname+":"+port+"/") : normalRootUrl;
                     
                     String wrongUrl = rootUrl+"doesnotexist";
-                    assertEquals(urlRespondsStatusCode(wrongUrl), 404, "url="+wrongUrl);
+                    HttpTestUtils.assertHttpStatusCodeEquals(wrongUrl, 404);
                     
                     for (String pathFor200 : pathsFor200) {
                         String url = rootUrl+pathFor200;
-                        assertEquals(urlRespondsStatusCode(url), 200, "url="+url);
+                        HttpTestUtils.assertHttpStatusCodeEquals(url, 200);
                     }
                 }
             }});

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4d86f06c/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxHttpsSslIntegrationTest.groovy
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxHttpsSslIntegrationTest.groovy b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxHttpsSslIntegrationTest.groovy
deleted file mode 100644
index 7cb0423..0000000
--- a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxHttpsSslIntegrationTest.groovy
+++ /dev/null
@@ -1,171 +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 brooklyn.entity.proxy.nginx;
-
-import static brooklyn.test.TestUtils.*
-import static org.testng.Assert.*
-
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import org.testng.Assert
-import org.testng.annotations.AfterMethod
-import org.testng.annotations.BeforeMethod
-import org.testng.annotations.Test
-
-import brooklyn.entity.basic.ApplicationBuilder
-import brooklyn.entity.basic.Entities
-import brooklyn.entity.basic.SoftwareProcess
-import brooklyn.entity.group.DynamicCluster
-import brooklyn.entity.proxy.ProxySslConfig
-import brooklyn.entity.proxying.EntitySpec
-import brooklyn.entity.webapp.JavaWebAppService
-import brooklyn.entity.webapp.WebAppService
-import brooklyn.entity.webapp.jboss.JBoss7Server
-import brooklyn.location.basic.LocalhostMachineProvisioningLocation
-import brooklyn.test.HttpTestUtils
-import brooklyn.test.entity.TestApplication
-import brooklyn.util.internal.TimeExtras
-
-/**
- * Test the operation of the {@link NginxController} class.
- */
-public class NginxHttpsSslIntegrationTest {
-    private static final Logger log = LoggerFactory.getLogger(NginxHttpsSslIntegrationTest.class)
-
-    static { TimeExtras.init() }
-
-    private TestApplication app
-    private NginxController nginx
-    private DynamicCluster cluster
-
-    private static final String WAR_URL = "classpath://hello-world.war";
-    private static final String CERTIFICATE_URL = "classpath://ssl/certs/localhost/server.crt";
-    private static final String KEY_URL = "classpath://ssl/certs/localhost/server.key";
-    
-    @BeforeMethod(alwaysRun=true)
-    public void setup() {
-        app = ApplicationBuilder.newManagedApp(TestApplication.class);
-    }
-
-    @AfterMethod(alwaysRun=true)
-    public void shutdown() {
-        if (app != null) Entities.destroyAll(app.getManagementContext());
-    }
-
-    /**
-     * Test that the Nginx proxy starts up and sets SERVICE_UP correctly.
-     */
-    @Test(groups = "Integration")
-    public void testStartsWithGlobalSsl_withCertificateAndKeyCopy() {
-        cluster = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-            .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class))
-            .configure("initialSize", 1)
-            .configure(JavaWebAppService.ROOT_WAR, WAR_URL));
-        
-        ProxySslConfig ssl = new ProxySslConfig(
-                certificateSourceUrl:CERTIFICATE_URL,
-                keySourceUrl:KEY_URL);
-        
-        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
-                .configure("sticky", false)
-                .configure("serverPool", cluster)
-                .configure("domain", "localhost")
-                .configure("port", "8443+")
-                .configure("ssl", ssl));
-        
-        app.start([ new LocalhostMachineProvisioningLocation() ])
-
-        String url = nginx.getAttribute(WebAppService.ROOT_URL);
-        if (!url.startsWith("https://")) Assert.fail("URL should be https: "+url);
-        
-        executeUntilSucceeds() {
-            // Services are running
-            assertTrue cluster.getAttribute(SoftwareProcess.SERVICE_UP)
-            cluster.members.each { assertTrue it.getAttribute(SoftwareProcess.SERVICE_UP) }
-            
-            assertTrue nginx.getAttribute(SoftwareProcess.SERVICE_UP)
-
-            // Nginx URL is available
-            HttpTestUtils.assertHttpStatusCodeEquals(url, 200);
-
-            // Web-server URL is available
-            cluster.members.each {
-                HttpTestUtils.assertHttpStatusCodeEquals(it.getAttribute(WebAppService.ROOT_URL), 200);
-            }
-        }
-        
-        app.stop()
-
-        // Services have stopped
-        assertFalse nginx.getAttribute(SoftwareProcess.SERVICE_UP)
-        assertFalse cluster.getAttribute(SoftwareProcess.SERVICE_UP)
-        cluster.members.each { assertFalse it.getAttribute(SoftwareProcess.SERVICE_UP) }
-    }
-
-    private String getFile(String file) {
-           return new File(getClass().getResource("/" + file).getFile()).getAbsolutePath();
-       }
-
-    @Test(groups = "Integration")
-    public void testStartsWithGlobalSsl_withPreinstalledCertificateAndKey() {
-        cluster = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-            .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class))
-            .configure("initialSize", 1)
-            .configure(JavaWebAppService.ROOT_WAR, WAR_URL));
-        
-        ProxySslConfig ssl = new ProxySslConfig(
-                certificateDestination: getFile("ssl/certs/localhost/server.crt"),
-                keyDestination: getFile("ssl/certs/localhost/server.key"));
-        
-        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
-                .configure("sticky", false)
-                .configure("serverPool", cluster)
-                .configure("domain", "localhost")
-                .configure("port", "8443+")
-                .configure("ssl", ssl));
-
-        app.start([ new LocalhostMachineProvisioningLocation() ])
-
-        String url = nginx.getAttribute(WebAppService.ROOT_URL);
-        if (!url.startsWith("https://")) Assert.fail("URL should be https: "+url);
-
-        executeUntilSucceeds() {
-            // Services are running
-            assertTrue cluster.getAttribute(SoftwareProcess.SERVICE_UP)
-            cluster.members.each { assertTrue it.getAttribute(SoftwareProcess.SERVICE_UP) }
-
-            assertTrue nginx.getAttribute(SoftwareProcess.SERVICE_UP)
-
-            // Nginx URL is available
-            HttpTestUtils.assertHttpStatusCodeEquals(url, 200);
-
-            // Web-server URL is available
-            cluster.members.each {
-                HttpTestUtils.assertHttpStatusCodeEquals(it.getAttribute(WebAppService.ROOT_URL), 200)
-            }
-        }
-
-        app.stop()
-
-        // Services have stopped
-        assertFalse nginx.getAttribute(SoftwareProcess.SERVICE_UP)
-        assertFalse cluster.getAttribute(SoftwareProcess.SERVICE_UP)
-        cluster.members.each { assertFalse it.getAttribute(SoftwareProcess.SERVICE_UP) }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4d86f06c/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxHttpsSslIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxHttpsSslIntegrationTest.java b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxHttpsSslIntegrationTest.java
new file mode 100644
index 0000000..826bd0f
--- /dev/null
+++ b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxHttpsSslIntegrationTest.java
@@ -0,0 +1,182 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.entity.proxy.nginx;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.io.File;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.BrooklynAppLiveTestSupport;
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.SoftwareProcess;
+import brooklyn.entity.group.DynamicCluster;
+import brooklyn.entity.proxy.ProxySslConfig;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.entity.webapp.JavaWebAppService;
+import brooklyn.entity.webapp.WebAppService;
+import brooklyn.entity.webapp.jboss.JBoss7Server;
+import brooklyn.location.Location;
+import brooklyn.test.Asserts;
+import brooklyn.test.HttpTestUtils;
+import brooklyn.test.entity.TestApplication;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Test the operation of the {@link NginxController} class.
+ */
+public class NginxHttpsSslIntegrationTest extends BrooklynAppLiveTestSupport {
+    @SuppressWarnings("unused")
+    private static final Logger log = LoggerFactory.getLogger(NginxHttpsSslIntegrationTest.class);
+
+    private NginxController nginx;
+    private DynamicCluster cluster;
+    private Location localLoc;
+
+    private static final String WAR_URL = "classpath://hello-world.war";
+    private static final String CERTIFICATE_URL = "classpath://ssl/certs/localhost/server.crt";
+    private static final String KEY_URL = "classpath://ssl/certs/localhost/server.key";
+    
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        localLoc = mgmt.getLocationRegistry().resolve("localhost");
+    }
+
+    /**
+     * Test that the Nginx proxy starts up and sets SERVICE_UP correctly.
+     */
+    @Test(groups = "Integration")
+    public void testStartsWithGlobalSsl_withCertificateAndKeyCopy() {
+        cluster = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+            .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class))
+            .configure("initialSize", 1)
+            .configure(JavaWebAppService.ROOT_WAR, WAR_URL));
+        
+        ProxySslConfig ssl = ProxySslConfig.builder()
+                .certificateSourceUrl(CERTIFICATE_URL)
+                .keySourceUrl(KEY_URL)
+                .build();
+        
+        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
+                .configure("sticky", false)
+                .configure("serverPool", cluster)
+                .configure("domain", "localhost")
+                .configure("port", "8443+")
+                .configure("ssl", ssl));
+        
+        app.start(ImmutableList.of(localLoc));
+
+        final String url = nginx.getAttribute(WebAppService.ROOT_URL);
+        if (!url.startsWith("https://")) Assert.fail("URL should be https: "+url);
+        
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                // Services are running
+                assertTrue(cluster.getAttribute(SoftwareProcess.SERVICE_UP));
+                for (Entity member : cluster.getMembers()) {
+                    assertTrue(member.getAttribute(SoftwareProcess.SERVICE_UP));
+                }
+                
+                assertTrue(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
+    
+                // Nginx URL is available
+                HttpTestUtils.assertHttpStatusCodeEquals(url, 200);
+    
+                // Web-server URL is available
+                for (Entity member : cluster.getMembers()) {
+                    HttpTestUtils.assertHttpStatusCodeEquals(member.getAttribute(WebAppService.ROOT_URL), 200);
+                }
+            }});
+        
+        app.stop();
+
+        // Services have stopped
+        assertFalse(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
+        assertFalse(cluster.getAttribute(SoftwareProcess.SERVICE_UP));
+        for (Entity member : cluster.getMembers()) {
+            assertFalse(member.getAttribute(SoftwareProcess.SERVICE_UP));
+        }
+    }
+
+    private String getFile(String file) {
+           return new File(getClass().getResource("/" + file).getFile()).getAbsolutePath();
+       }
+
+    @Test(groups = "Integration")
+    public void testStartsWithGlobalSsl_withPreinstalledCertificateAndKey() {
+        cluster = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+            .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class))
+            .configure("initialSize", 1)
+            .configure(JavaWebAppService.ROOT_WAR, WAR_URL));
+        
+        ProxySslConfig ssl = ProxySslConfig.builder()
+                .certificateDestination(getFile("ssl/certs/localhost/server.crt"))
+                .keyDestination(getFile("ssl/certs/localhost/server.key"))
+                .build();
+        
+        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
+                .configure("sticky", false)
+                .configure("serverPool", cluster)
+                .configure("domain", "localhost")
+                .configure("port", "8443+")
+                .configure("ssl", ssl));
+
+        app.start(ImmutableList.of(localLoc));
+
+        final String url = nginx.getAttribute(WebAppService.ROOT_URL);
+        if (!url.startsWith("https://")) Assert.fail("URL should be https: "+url);
+
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                // Services are running
+                assertTrue(cluster.getAttribute(SoftwareProcess.SERVICE_UP));
+                for (Entity member : cluster.getMembers()) {
+                    assertTrue(member.getAttribute(SoftwareProcess.SERVICE_UP));
+                }
+    
+                assertTrue(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
+    
+                // Nginx URL is available
+                HttpTestUtils.assertHttpStatusCodeEquals(url, 200);
+    
+                // Web-server URL is available
+                for (Entity member : cluster.getMembers()) {
+                    HttpTestUtils.assertHttpStatusCodeEquals(member.getAttribute(WebAppService.ROOT_URL), 200);
+                }
+            }});
+
+        app.stop();
+
+        // Services have stopped
+        assertFalse(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
+        assertFalse(cluster.getAttribute(SoftwareProcess.SERVICE_UP));
+        for (Entity member : cluster.getMembers()) {
+            assertFalse(member.getAttribute(SoftwareProcess.SERVICE_UP));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4d86f06c/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxIntegrationTest.groovy
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxIntegrationTest.groovy b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxIntegrationTest.groovy
deleted file mode 100644
index 9249548..0000000
--- a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxIntegrationTest.groovy
+++ /dev/null
@@ -1,432 +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 brooklyn.entity.proxy.nginx;
-
-import static brooklyn.test.HttpTestUtils.*
-import static brooklyn.test.TestUtils.*
-import static java.util.concurrent.TimeUnit.*
-import static org.testng.Assert.*
-
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import org.testng.annotations.AfterMethod
-import org.testng.annotations.BeforeMethod
-import org.testng.annotations.Test
-
-import brooklyn.entity.basic.ApplicationBuilder
-import brooklyn.entity.basic.Entities
-import brooklyn.entity.basic.SoftwareProcess
-import brooklyn.entity.group.DynamicCluster
-import brooklyn.entity.proxying.EntitySpec
-import brooklyn.entity.webapp.JavaWebAppService
-import brooklyn.entity.webapp.WebAppService
-import brooklyn.entity.webapp.jboss.JBoss7Server
-import brooklyn.location.basic.LocalhostMachineProvisioningLocation
-import brooklyn.test.HttpTestUtils
-import brooklyn.test.WebAppMonitor
-import brooklyn.test.entity.TestApplication
-import brooklyn.util.internal.TimeExtras
-import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
-/**
- * Test the operation of the {@link NginxController} class.
- */
-public class NginxIntegrationTest {
-    private static final Logger log = LoggerFactory.getLogger(NginxIntegrationTest.class)
-
-    static final String HELLO_WAR_URL = "classpath://hello-world.war";
-    static { TimeExtras.init() }
-
-    private TestApplication app
-    private NginxController nginx
-    private DynamicCluster serverPool
-
-    @BeforeMethod(alwaysRun=true)
-    public void setup() {
-        app = ApplicationBuilder.newManagedApp(TestApplication.class);
-    }
-
-    @AfterMethod(alwaysRun=true)
-    public void shutdown() {
-        if (app != null) Entities.destroyAll(app.getManagementContext());
-    }
-
-    /**
-     * Test that the Nginx proxy starts up and sets SERVICE_UP correctly.
-     */
-    @Test(groups = "Integration")
-    public void testWhenNoServersReturns404() {
-        serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-                .configure(DynamicCluster.FACTORY, { throw new UnsupportedOperationException(); })
-                .configure("initialSize", 0));
-        
-        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
-                .configure("serverPool", serverPool)
-                .configure("domain", "localhost"));
-        
-        app.start([ new LocalhostMachineProvisioningLocation() ])
-        
-        assertAttributeEventually(nginx, SoftwareProcess.SERVICE_UP, true);
-        assertUrlStatusCodeEventually(nginx.getAttribute(NginxController.ROOT_URL), 404);
-    }
-
-    @Test(groups = "Integration")
-    public void testRestart() {
-        serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-                .configure(DynamicCluster.FACTORY, { throw new UnsupportedOperationException(); })
-                .configure("initialSize", 0));
-        
-        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
-                .configure("serverPool", serverPool)
-                .configure("domain", "localhost"));
-        
-        app.start([ new LocalhostMachineProvisioningLocation() ])
-
-        nginx.restart();
-        
-        assertAttributeEventually(nginx, SoftwareProcess.SERVICE_UP, true);
-        assertUrlStatusCodeEventually(nginx.getAttribute(NginxController.ROOT_URL), 404);
-    }
-
-    /**
-     * Test that the Nginx proxy starts up and sets SERVICE_UP correctly.
-     */
-    @Test(groups = "Integration")
-    public void testCanStartupAndShutdown() {
-        serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class))
-                .configure("initialSize", 1)
-                .configure(JavaWebAppService.ROOT_WAR, HELLO_WAR_URL));
-        
-        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
-                .configure("serverPool", serverPool)
-                .configure("domain", "localhost")
-                .configure("portNumberSensor", WebAppService.HTTP_PORT));
-        
-        app.start([ new LocalhostMachineProvisioningLocation() ])
-        
-        // App-servers and nginx has started
-        assertEventually {        
-            serverPool.members.each { 
-                assertTrue it.getAttribute(SoftwareProcess.SERVICE_UP);
-            }
-            assertTrue nginx.getAttribute(SoftwareProcess.SERVICE_UP);
-        }
-
-        // URLs reachable        
-        assertUrlStatusCodeEventually(nginx.getAttribute(NginxController.ROOT_URL), 200);
-        serverPool.members.each {
-            assertUrlStatusCodeEventually(it.getAttribute(WebAppService.ROOT_URL), 200);
-        }
-
-        app.stop();
-
-        // Services have stopped
-        assertFalse(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
-        assertFalse(serverPool.getAttribute(SoftwareProcess.SERVICE_UP));
-        serverPool.members.each {
-            assertFalse(it.getAttribute(SoftwareProcess.SERVICE_UP));
-        }
-    }
-
-    /**
-     * Test that the Nginx proxy starts up and sets SERVICE_UP correctly using the config file template.
-     */
-    @Test(groups = "Integration")
-    public void testCanStartupAndShutdownUsingTemplate() {
-        serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class))
-                .configure("initialSize", 1)
-                .configure(JavaWebAppService.ROOT_WAR, HELLO_WAR_URL));
-
-        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
-                .configure("serverPool", serverPool)
-                .configure("domain", "localhost")
-                .configure("portNumberSensor", WebAppService.HTTP_PORT)
-                .configure("configTemplate", "classpath://brooklyn/entity/proxy/nginx/server.conf"));
-
-        app.start([ new LocalhostMachineProvisioningLocation() ])
-
-        // App-servers and nginx has started
-        assertEventually {
-            serverPool.members.each {
-                assertTrue it.getAttribute(SoftwareProcess.SERVICE_UP);
-            }
-            assertTrue nginx.getAttribute(SoftwareProcess.SERVICE_UP);
-        }
-
-        // URLs reachable
-        assertUrlStatusCodeEventually(nginx.getAttribute(NginxController.ROOT_URL), 200);
-        serverPool.members.each {
-            assertUrlStatusCodeEventually(it.getAttribute(WebAppService.ROOT_URL), 200);
-        }
-
-        app.stop();
-
-        // Services have stopped
-        assertFalse(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
-        assertFalse(serverPool.getAttribute(SoftwareProcess.SERVICE_UP));
-        serverPool.members.each {
-            assertFalse(it.getAttribute(SoftwareProcess.SERVICE_UP));
-        }
-    }
-
-    /**
-     * Test that the Nginx proxy works, serving all domains, if no domain is set
-     */
-    @Test(groups = "Integration")
-    public void testDomainless() {
-        serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class))
-                .configure("initialSize", 1)
-                .configure(JavaWebAppService.ROOT_WAR, HELLO_WAR_URL));
-        
-        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
-                .configure("serverPool", serverPool)
-                .configure("domain", "localhost")
-                .configure("portNumberSensor", WebAppService.HTTP_PORT));
-        
-        app.start([ new LocalhostMachineProvisioningLocation() ])
-        
-        // App-servers and nginx has started
-        assertAttributeEventually(serverPool, SoftwareProcess.SERVICE_UP, true);
-        serverPool.members.each {
-            assertAttributeEventually(it, SoftwareProcess.SERVICE_UP, true);
-        }
-        assertAttributeEventually(nginx, SoftwareProcess.SERVICE_UP, true);
-
-        // URLs reachable
-        assertUrlStatusCodeEventually(nginx.getAttribute(NginxController.ROOT_URL), 200);
-        serverPool.members.each {
-            assertUrlStatusCodeEventually(it.getAttribute(WebAppService.ROOT_URL), 200);
-        }
-
-        app.stop();
-
-        // Services have stopped
-        assertFalse(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
-        assertFalse(serverPool.getAttribute(SoftwareProcess.SERVICE_UP));
-        serverPool.members.each {
-            assertFalse(it.getAttribute(SoftwareProcess.SERVICE_UP));
-        }
-    }
-    
-    @Test(groups = "Integration")
-    public void testTwoNginxesGetDifferentPorts() {
-        serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-                .configure(DynamicCluster.FACTORY, { throw new UnsupportedOperationException(); })
-                .configure("initialSize", 0));
-        
-        NginxController nginx1 = app.createAndManageChild(EntitySpec.create(NginxController.class)
-                .configure("serverPool", serverPool)
-                .configure("domain", "localhost")
-                .configure("port", "14000+"));
-        
-        NginxController nginx2 = app.createAndManageChild(EntitySpec.create(NginxController.class)
-                .configure("serverPool", serverPool)
-                .configure("domain", "localhost")
-                .configure("port", "14000+"));
-        
-        app.start([ new LocalhostMachineProvisioningLocation() ])
-
-        String url1 = nginx1.getAttribute(NginxController.ROOT_URL)
-        String url2 = nginx2.getAttribute(NginxController.ROOT_URL)
-
-        assertTrue(url1.contains(":1400"), url1);
-        assertTrue(url2.contains(":1400"), url2);
-        assertNotEquals(url1, url2, "Two nginxs should listen on different ports, not both on "+url1);
-        
-        // Nginx has started
-        assertAttributeEventually(nginx1, SoftwareProcess.SERVICE_UP, true);
-        assertAttributeEventually(nginx2, SoftwareProcess.SERVICE_UP, true);
-
-        // Nginx reachable (returning default 404)
-        assertUrlStatusCodeEventually(url1, 404);
-        assertUrlStatusCodeEventually(url2, 404);
-    }
-    
-    /** Test that site access does not fail even while nginx is reloaded */
-    // FIXME test disabled -- reload isn't a problem, but #365 is
-    @Test(enabled = false, groups = "Integration")
-    public void testServiceContinuity() {
-        serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class))
-                .configure("initialSize", 1)
-                .configure(JavaWebAppService.ROOT_WAR, HELLO_WAR_URL));
-        
-        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
-                .configure("serverPool", serverPool));
-        
-        app.start([ new LocalhostMachineProvisioningLocation() ])
-
-        assertEventually {        
-            serverPool.members.each { 
-                assertHttpStatusCodeEquals it.getAttribute(WebAppService.ROOT_URL), 200;
-            }
-            assertHttpStatusCodeEquals nginx.getAttribute(WebAppService.ROOT_URL), 200;
-        }
-
-        WebAppMonitor monitor = new WebAppMonitor(nginx.getAttribute(WebAppService.ROOT_URL)).
-            logFailures(LOG).
-            delayMillis(0);
-        Thread t = new Thread(monitor);
-        t.start();
-
-        try {
-            Thread.sleep(1*1000);
-            LOG.info("service continuity test, startup, "+monitor.getAttempts()+" requests made");
-            monitor.assertAttemptsMade(10, "startup").assertNoFailures("startup").resetCounts();
-            
-            for (int i=0; i<20; i++) {
-                nginx.reload();
-                Thread.sleep(500);
-                LOG.info("service continuity test, iteration "+i+", "+monitor.getAttempts()+" requests made");
-                monitor.assertAttemptsMade(10, "reloaded").assertNoFailures("reloaded").resetCounts();
-            }
-            
-        } finally {
-            t.interrupt();
-        }
-        
-        app.stop();
-
-        // Services have stopped
-        assertFalse(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
-        assertFalse(serverPool.getAttribute(SoftwareProcess.SERVICE_UP));
-        serverPool.members.each {
-            assertFalse(it.getAttribute(SoftwareProcess.SERVICE_UP));
-        }
-    }
-
-    // FIXME test disabled -- issue #365
-    /*
-     * This currently makes no assertions, but writes out the number of sequential reqs per sec
-     * supported with nginx and jboss.
-     * <p>
-     * jboss is (now) steady, at 6k+, since we close the connections in HttpTestUtils.getHttpStatusCode.
-     * but nginx still hits problems, after about 15k reqs, something is getting starved in nginx.
-     */
-    @Test(enabled=false, groups = "Integration")
-    public void testContinuityNginxAndJboss() {
-        serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
-                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class))
-                .configure("initialSize", 1)
-                .configure(JavaWebAppService.ROOT_WAR, HELLO_WAR_URL));
-        
-        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
-                .configure("serverPool", serverPool));
-        
-        app.start([ new LocalhostMachineProvisioningLocation() ])
-
-        String nginxUrl = nginx.getAttribute(WebAppService.ROOT_URL);
-        String jbossUrl;
-        assertEventually {
-            serverPool.members.each {
-                jbossUrl = it.getAttribute(WebAppService.ROOT_URL);
-                assertHttpStatusCodeEquals jbossUrl, 200;
-            }
-            assertHttpStatusCodeEquals nginxUrl, 200;
-        }
-
-        Thread t = new Thread() {
-            public void run() {
-                long lastReportTime = System.currentTimeMillis();
-                int num = 0;
-                while (true) {
-                    try {
-                        num++;
-                        int code = HttpTestUtils.getHttpStatusCode(nginxUrl);
-                        if (code!=200) LOG.info("NGINX GOT: "+code);
-                        else LOG.debug("NGINX GOT: "+code);
-                        if (System.currentTimeMillis()>=lastReportTime+1000) {
-                            LOG.info("NGINX DID "+num+" requests in last "+(System.currentTimeMillis()-lastReportTime)+"ms");
-                            num=0;
-                            lastReportTime = System.currentTimeMillis();
-                        }
-                    } catch (Exception e) {
-                        LOG.info("NGINX GOT: "+e);
-                    }
-                }
-            }
-        };
-        t.start();
-        
-        Thread t2 = new Thread() {
-            public void run() {
-                long lastReportTime = System.currentTimeMillis();
-                int num = 0;
-        while (true) {
-            try {
-                num++;
-                int code = HttpTestUtils.getHttpStatusCode(jbossUrl);
-                if (code!=200) LOG.info("JBOSS GOT: "+code);
-                else LOG.debug("JBOSS GOT: "+code);
-                if (System.currentTimeMillis()>=1000+lastReportTime) {
-                    LOG.info("JBOSS DID "+num+" requests in last "+(System.currentTimeMillis()-lastReportTime)+"ms");
-                    num=0;
-                    lastReportTime = System.currentTimeMillis();
-                }
-            } catch (Exception e) {
-                LOG.info("JBOSS GOT: "+e);
-            }
-        }
-            }
-        };
-        t2.start();
-        
-        t2.join();
-    }
-
-    /**
-     * Test that the Nginx proxy starts up and sets SERVICE_UP correctly.
-     */
-    @Test(groups = "Integration")
-    public void testCanRestart() {
-        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
-                .configure("serverPool", serverPool)
-                .configure("domain", "localhost")
-                .configure("portNumberSensor", WebAppService.HTTP_PORT));
-        
-        app.start([ new LocalhostMachineProvisioningLocation() ])
-        
-        // App-servers and nginx has started
-        assertEventually {
-            assertTrue nginx.getAttribute(SoftwareProcess.SERVICE_UP);
-        }
-
-        log.info("started, will restart soon");
-        Time.sleep(Duration.ONE_SECOND);
-        
-        nginx.restart()
-
-        Time.sleep(Duration.ONE_SECOND);
-        assertEventually {
-            assertTrue nginx.getAttribute(SoftwareProcess.SERVICE_UP);
-        }
-        log.info("restarted and got service up");
-    }
-    
-//    public static void main(String[] args) {
-//        NginxIntegrationTest t = new NginxIntegrationTest();
-//        t.setup();
-//        t.testCanRestart();
-//        t.shutdown();        
-//    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4d86f06c/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxIntegrationTest.java b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxIntegrationTest.java
new file mode 100644
index 0000000..2dd5567
--- /dev/null
+++ b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxIntegrationTest.java
@@ -0,0 +1,449 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.entity.proxy.nginx;
+
+import static brooklyn.test.EntityTestUtils.assertAttributeEqualsEventually;
+import static brooklyn.test.HttpTestUtils.assertHttpStatusCodeEquals;
+import static brooklyn.test.HttpTestUtils.assertHttpStatusCodeEventuallyEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.BrooklynAppLiveTestSupport;
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.EntityFactory;
+import brooklyn.entity.basic.SoftwareProcess;
+import brooklyn.entity.group.DynamicCluster;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.entity.webapp.JavaWebAppService;
+import brooklyn.entity.webapp.WebAppService;
+import brooklyn.entity.webapp.jboss.JBoss7Server;
+import brooklyn.location.Location;
+import brooklyn.test.Asserts;
+import brooklyn.test.HttpTestUtils;
+import brooklyn.test.WebAppMonitor;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+/**
+ * Test the operation of the {@link NginxController} class.
+ */
+public class NginxIntegrationTest extends BrooklynAppLiveTestSupport {
+    private static final Logger log = LoggerFactory.getLogger(NginxIntegrationTest.class);
+
+    static final String HELLO_WAR_URL = "classpath://hello-world.war";
+
+    private NginxController nginx;
+    private DynamicCluster serverPool;
+    private Location localLoc;
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        localLoc = mgmt.getLocationRegistry().resolve("localhost");
+    }
+
+    /**
+     * Test that the Nginx proxy starts up and sets SERVICE_UP correctly.
+     */
+    @Test(groups = "Integration")
+    public void testWhenNoServersReturns404() {
+        serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+                .configure("initialSize", 0)
+                .configure(DynamicCluster.FACTORY, new EntityFactory<Entity>() {
+                    @Override public Entity newEntity(Map flags, Entity parent) {
+                        throw new UnsupportedOperationException();
+                    }}));
+        
+        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
+                .configure("serverPool", serverPool)
+                .configure("domain", "localhost"));
+        
+        app.start(ImmutableList.of(localLoc));
+        
+        assertAttributeEqualsEventually(nginx, SoftwareProcess.SERVICE_UP, true);
+        assertHttpStatusCodeEventuallyEquals(nginx.getAttribute(NginxController.ROOT_URL), 404);
+    }
+
+    @Test(groups = "Integration")
+    public void testRestart() {
+        serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+                .configure("initialSize", 0)
+                .configure(DynamicCluster.FACTORY, new EntityFactory<Entity>() {
+                    @Override public Entity newEntity(Map flags, Entity parent) {
+                        throw new UnsupportedOperationException();
+                    }}));
+        
+        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
+                .configure("serverPool", serverPool)
+                .configure("domain", "localhost"));
+        
+        app.start(ImmutableList.of(localLoc));
+
+        nginx.restart();
+        
+        assertAttributeEqualsEventually(nginx, SoftwareProcess.SERVICE_UP, true);
+        assertHttpStatusCodeEventuallyEquals(nginx.getAttribute(NginxController.ROOT_URL), 404);
+    }
+
+    /**
+     * Test that the Nginx proxy starts up and sets SERVICE_UP correctly.
+     */
+    @Test(groups = "Integration")
+    public void testCanStartupAndShutdown() {
+        serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class))
+                .configure("initialSize", 1)
+                .configure(JavaWebAppService.ROOT_WAR, HELLO_WAR_URL));
+        
+        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
+                .configure("serverPool", serverPool)
+                .configure("domain", "localhost")
+                .configure("portNumberSensor", WebAppService.HTTP_PORT));
+        
+        app.start(ImmutableList.of(localLoc));
+        
+        // App-servers and nginx has started
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                for (Entity member : serverPool.getMembers()) {
+                    assertTrue(member.getAttribute(SoftwareProcess.SERVICE_UP));
+                }
+                assertTrue(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
+            }});
+
+        // URLs reachable
+        assertHttpStatusCodeEventuallyEquals(nginx.getAttribute(NginxController.ROOT_URL), 200);
+        for (Entity member : serverPool.getMembers()) {
+            assertHttpStatusCodeEventuallyEquals(member.getAttribute(WebAppService.ROOT_URL), 200);
+        }
+
+        app.stop();
+
+        // Services have stopped
+        assertFalse(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
+        assertFalse(serverPool.getAttribute(SoftwareProcess.SERVICE_UP));
+        for (Entity member : serverPool.getMembers()) {
+            assertFalse(member.getAttribute(SoftwareProcess.SERVICE_UP));
+        }
+    }
+
+    /**
+     * Test that the Nginx proxy starts up and sets SERVICE_UP correctly using the config file template.
+     */
+    @Test(groups = "Integration")
+    public void testCanStartupAndShutdownUsingTemplate() {
+        serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class))
+                .configure("initialSize", 1)
+                .configure(JavaWebAppService.ROOT_WAR, HELLO_WAR_URL));
+
+        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
+                .configure("serverPool", serverPool)
+                .configure("domain", "localhost")
+                .configure("portNumberSensor", WebAppService.HTTP_PORT)
+                .configure("configTemplate", "classpath://brooklyn/entity/proxy/nginx/server.conf"));
+
+        app.start(ImmutableList.of(localLoc));
+
+        // App-servers and nginx has started
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                for (Entity member : serverPool.getMembers()) {
+                    assertTrue(member.getAttribute(SoftwareProcess.SERVICE_UP));
+                }
+                assertTrue(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
+            }});
+
+        // URLs reachable
+        assertHttpStatusCodeEventuallyEquals(nginx.getAttribute(NginxController.ROOT_URL), 200);
+        for (Entity member : serverPool.getMembers()) {
+            assertHttpStatusCodeEventuallyEquals(member.getAttribute(WebAppService.ROOT_URL), 200);
+        }
+
+        app.stop();
+
+        // Services have stopped
+        assertFalse(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
+        assertFalse(serverPool.getAttribute(SoftwareProcess.SERVICE_UP));
+        for (Entity member : serverPool.getMembers()) {
+            assertFalse(member.getAttribute(SoftwareProcess.SERVICE_UP));
+        }
+    }
+
+    /**
+     * Test that the Nginx proxy works, serving all domains, if no domain is set
+     */
+    @Test(groups = "Integration")
+    public void testDomainless() {
+        serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class))
+                .configure("initialSize", 1)
+                .configure(JavaWebAppService.ROOT_WAR, HELLO_WAR_URL));
+        
+        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
+                .configure("serverPool", serverPool)
+                .configure("domain", "localhost")
+                .configure("portNumberSensor", WebAppService.HTTP_PORT));
+        
+        app.start(ImmutableList.of(localLoc));
+        
+        // App-servers and nginx has started
+        assertAttributeEqualsEventually(serverPool, SoftwareProcess.SERVICE_UP, true);
+        for (Entity member : serverPool.getMembers()) {
+            assertAttributeEqualsEventually(member, SoftwareProcess.SERVICE_UP, true);
+        }
+        assertAttributeEqualsEventually(nginx, SoftwareProcess.SERVICE_UP, true);
+
+        // URLs reachable
+        assertHttpStatusCodeEventuallyEquals(nginx.getAttribute(NginxController.ROOT_URL), 200);
+        for (Entity member : serverPool.getMembers()) {
+            assertHttpStatusCodeEventuallyEquals(member.getAttribute(WebAppService.ROOT_URL), 200);
+        }
+
+        app.stop();
+
+        // Services have stopped
+        assertFalse(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
+        assertFalse(serverPool.getAttribute(SoftwareProcess.SERVICE_UP));
+        for (Entity member : serverPool.getMembers()) {
+            assertFalse(member.getAttribute(SoftwareProcess.SERVICE_UP));
+        }
+    }
+    
+    @Test(groups = "Integration")
+    public void testTwoNginxesGetDifferentPorts() {
+        serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+                .configure("initialSize", 0)
+                .configure(DynamicCluster.FACTORY, new EntityFactory<Entity>() {
+                    @Override public Entity newEntity(Map flags, Entity parent) {
+                        throw new UnsupportedOperationException();
+                    }}));
+        
+        NginxController nginx1 = app.createAndManageChild(EntitySpec.create(NginxController.class)
+                .configure("serverPool", serverPool)
+                .configure("domain", "localhost")
+                .configure("port", "14000+"));
+        
+        NginxController nginx2 = app.createAndManageChild(EntitySpec.create(NginxController.class)
+                .configure("serverPool", serverPool)
+                .configure("domain", "localhost")
+                .configure("port", "14000+"));
+        
+        app.start(ImmutableList.of(localLoc));
+
+        String url1 = nginx1.getAttribute(NginxController.ROOT_URL);
+        String url2 = nginx2.getAttribute(NginxController.ROOT_URL);
+
+        assertTrue(url1.contains(":1400"), url1);
+        assertTrue(url2.contains(":1400"), url2);
+        assertNotEquals(url1, url2, "Two nginxs should listen on different ports, not both on "+url1);
+        
+        // Nginx has started
+        assertAttributeEqualsEventually(nginx1, SoftwareProcess.SERVICE_UP, true);
+        assertAttributeEqualsEventually(nginx2, SoftwareProcess.SERVICE_UP, true);
+
+        // Nginx reachable (returning default 404)
+        assertHttpStatusCodeEventuallyEquals(url1, 404);
+        assertHttpStatusCodeEventuallyEquals(url2, 404);
+    }
+    
+    /** Test that site access does not fail even while nginx is reloaded */
+    // FIXME test disabled -- reload isn't a problem, but #365 is
+    @Test(enabled = false, groups = "Integration")
+    public void testServiceContinuity() throws Exception {
+        serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class))
+                .configure("initialSize", 1)
+                .configure(JavaWebAppService.ROOT_WAR, HELLO_WAR_URL));
+        
+        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
+                .configure("serverPool", serverPool));
+        
+        app.start(ImmutableList.of(localLoc));
+
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                for (Entity member : serverPool.getMembers()) {
+                    assertHttpStatusCodeEquals(member.getAttribute(WebAppService.ROOT_URL), 200);
+                }
+                assertHttpStatusCodeEquals(nginx.getAttribute(WebAppService.ROOT_URL), 200);
+            }});
+
+        WebAppMonitor monitor = new WebAppMonitor(nginx.getAttribute(WebAppService.ROOT_URL))
+            .logFailures(log)
+            .delayMillis(0);
+        Thread t = new Thread(monitor);
+        t.start();
+
+        try {
+            Thread.sleep(1*1000);
+            log.info("service continuity test, startup, "+monitor.getAttempts()+" requests made");
+            monitor.assertAttemptsMade(10, "startup").assertNoFailures("startup").resetCounts();
+            
+            for (int i=0; i<20; i++) {
+                nginx.reload();
+                Thread.sleep(500);
+                log.info("service continuity test, iteration "+i+", "+monitor.getAttempts()+" requests made");
+                monitor.assertAttemptsMade(10, "reloaded").assertNoFailures("reloaded").resetCounts();
+            }
+            
+        } finally {
+            t.interrupt();
+        }
+        
+        app.stop();
+
+        // Services have stopped
+        assertFalse(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
+        assertFalse(serverPool.getAttribute(SoftwareProcess.SERVICE_UP));
+        for (Entity member : serverPool.getMembers()) {
+            assertFalse(member.getAttribute(SoftwareProcess.SERVICE_UP));
+        }
+    }
+
+    // FIXME test disabled -- issue #365
+    /*
+     * This currently makes no assertions, but writes out the number of sequential reqs per sec
+     * supported with nginx and jboss.
+     * <p>
+     * jboss is (now) steady, at 6k+, since we close the connections in HttpTestUtils.getHttpStatusCode.
+     * but nginx still hits problems, after about 15k reqs, something is getting starved in nginx.
+     */
+    @Test(enabled=false, groups = "Integration")
+    public void testContinuityNginxAndJboss() throws Exception {
+        serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class))
+                .configure("initialSize", 1)
+                .configure(JavaWebAppService.ROOT_WAR, HELLO_WAR_URL));
+        
+        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
+                .configure("serverPool", serverPool));
+        
+        app.start(ImmutableList.of(localLoc));
+
+        final String nginxUrl = nginx.getAttribute(WebAppService.ROOT_URL);
+
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                for (Entity member : serverPool.getMembers()) {
+                    String jbossUrl = member.getAttribute(WebAppService.ROOT_URL);
+                    assertHttpStatusCodeEquals(jbossUrl, 200);
+                }
+                assertHttpStatusCodeEquals(nginxUrl, 200);
+            }});
+
+        final String jbossUrl = Iterables.get(serverPool.getMembers(), 0).getAttribute(WebAppService.ROOT_URL);
+        
+        Thread t = new Thread(new Runnable() {
+            public void run() {
+                long lastReportTime = System.currentTimeMillis();
+                int num = 0;
+                while (true) {
+                    try {
+                        num++;
+                        int code = HttpTestUtils.getHttpStatusCode(nginxUrl);
+                        if (code!=200) log.info("NGINX GOT: "+code);
+                        else log.debug("NGINX GOT: "+code);
+                        if (System.currentTimeMillis()>=lastReportTime+1000) {
+                            log.info("NGINX DID "+num+" requests in last "+(System.currentTimeMillis()-lastReportTime)+"ms");
+                            num=0;
+                            lastReportTime = System.currentTimeMillis();
+                        }
+                    } catch (Exception e) {
+                        log.info("NGINX GOT: "+e);
+                    }
+                }
+            }});
+        t.start();
+        
+        Thread t2 = new Thread(new Runnable() {
+            public void run() {
+                long lastReportTime = System.currentTimeMillis();
+                int num = 0;
+                while (true) {
+                    try {
+                        num++;
+                        int code = HttpTestUtils.getHttpStatusCode(jbossUrl);
+                        if (code!=200) log.info("JBOSS GOT: "+code);
+                        else log.debug("JBOSS GOT: "+code);
+                        if (System.currentTimeMillis()>=1000+lastReportTime) {
+                            log.info("JBOSS DID "+num+" requests in last "+(System.currentTimeMillis()-lastReportTime)+"ms");
+                            num=0;
+                            lastReportTime = System.currentTimeMillis();
+                        }
+                    } catch (Exception e) {
+                        log.info("JBOSS GOT: "+e);
+                    }
+                }
+            }});
+        t2.start();
+        
+        t2.join();
+    }
+
+    /**
+     * Test that the Nginx proxy starts up and sets SERVICE_UP correctly.
+     */
+    @Test(groups = "Integration")
+    public void testCanRestart() {
+        nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
+                .configure("serverPool", serverPool)
+                .configure("domain", "localhost")
+                .configure("portNumberSensor", WebAppService.HTTP_PORT));
+        
+        app.start(ImmutableList.of(localLoc));
+        
+        // App-servers and nginx has started
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                assertTrue(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
+            }});
+
+        log.info("started, will restart soon");
+        Time.sleep(Duration.ONE_SECOND);
+        
+        nginx.restart();
+
+        Time.sleep(Duration.ONE_SECOND);
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                assertTrue(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
+            }});
+        log.info("restarted and got service up");
+    }
+    
+//    public static void main(String[] args) {
+//        NginxIntegrationTest t = new NginxIntegrationTest();
+//        t.setup();
+//        t.testCanRestart();
+//        t.shutdown();        
+//    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4d86f06c/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxLightIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxLightIntegrationTest.java b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxLightIntegrationTest.java
index b12bfa8..4605735 100644
--- a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxLightIntegrationTest.java
+++ b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxLightIntegrationTest.java
@@ -23,45 +23,30 @@ import static org.testng.Assert.assertEquals;
 import java.net.URL;
 import java.util.Map;
 
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
+import brooklyn.entity.BrooklynAppUnitTestSupport;
 import brooklyn.entity.Entity;
-import brooklyn.entity.basic.ApplicationBuilder;
 import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.BasicConfigurableEntityFactory;
-import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityFactory;
 import brooklyn.entity.group.DynamicCluster;
 import brooklyn.entity.proxy.StubAppServer;
 import brooklyn.entity.proxying.EntitySpec;
 import brooklyn.location.basic.LocalhostMachineProvisioningLocation;
 import brooklyn.test.Asserts;
-import brooklyn.test.entity.TestApplication;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Maps;
 
-public class NginxLightIntegrationTest {
+public class NginxLightIntegrationTest extends BrooklynAppUnitTestSupport {
 
-    private TestApplication app;
     private NginxController nginx;
     private DynamicCluster cluster;
 
     private URL war;
-    private static String WAR_URL = "classpath://hello-world.war";
+    private static final String WAR_URL = "classpath://hello-world.war";
     
-    @BeforeMethod
-    public void setup() {
-        app = ApplicationBuilder.newManagedApp(TestApplication.class);
-    }
-
-    @AfterMethod(alwaysRun=true)
-    public void shutdown() {
-        if (app != null) Entities.destroyAll(app.getManagementContext());
-    }
-
     // FIXME Fails because getting addEntity callback for group members while nginx is still starting,
     // so important nginx fields are still null. Therefore get NPE for cluster members, and thus targets
     // is of size zero.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4d86f06c/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxRebindIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxRebindIntegrationTest.java b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxRebindIntegrationTest.java
index 9bf4244..a119130 100644
--- a/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxRebindIntegrationTest.java
+++ b/software/webapp/src/test/java/brooklyn/entity/proxy/nginx/NginxRebindIntegrationTest.java
@@ -54,7 +54,6 @@ import brooklyn.management.internal.LocalManagementContext;
 import brooklyn.test.Asserts;
 import brooklyn.test.WebAppMonitor;
 import brooklyn.test.entity.TestApplication;
-import brooklyn.util.internal.TimeExtras;
 
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
@@ -68,8 +67,6 @@ import com.google.common.io.Files;
 public class NginxRebindIntegrationTest {
     private static final Logger LOG = LoggerFactory.getLogger(NginxRebindIntegrationTest.class);
 
-    static { TimeExtras.init(); }
-
     private URL warUrl;
     private LocalhostMachineProvisioningLocation localhostProvisioningLocation;
     private ClassLoader classLoader = getClass().getClassLoader();


[5/5] git commit: This closes #121

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


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

Branch: refs/heads/master
Commit: 8257a4fffa55d50b03a19e22b910ce60afce259c
Parents: cc1915a 2f27923
Author: Aled Sage <al...@gmail.com>
Authored: Thu Aug 21 17:02:07 2014 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Thu Aug 21 17:02:07 2014 +0100

----------------------------------------------------------------------
 .../entity/rebind/RebindTestFixture.java        |  20 +-
 .../brooklyn/entity/rebind/RebindTestUtils.java |  18 +-
 .../brooklyn/entity/proxy/ProxySslConfig.java   |  79 +++
 .../nginx/NginxClusterIntegrationTest.java      |  49 +-
 .../nginx/NginxHttpsSslIntegrationTest.groovy   | 171 ------
 .../nginx/NginxHttpsSslIntegrationTest.java     | 182 +++++++
 .../proxy/nginx/NginxIntegrationTest.groovy     | 432 ---------------
 .../proxy/nginx/NginxIntegrationTest.java       | 449 ++++++++++++++++
 .../proxy/nginx/NginxLightIntegrationTest.java  |  21 +-
 .../proxy/nginx/NginxRebindIntegrationTest.java |  58 +-
 .../nginx/NginxUrlMappingIntegrationTest.groovy | 503 ------------------
 .../nginx/NginxUrlMappingIntegrationTest.java   | 525 +++++++++++++++++++
 .../nginx/NginxWebClusterEc2LiveTest.groovy     | 107 ----
 .../proxy/nginx/NginxWebClusterEc2LiveTest.java | 113 ++++
 .../main/java/brooklyn/test/HttpTestUtils.java  | 123 ++++-
 15 files changed, 1521 insertions(+), 1329 deletions(-)
----------------------------------------------------------------------