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 2015/08/12 17:55:21 UTC

[03/35] incubator-brooklyn git commit: [BROOKLYN-162] package rename to org.apache.brooklyn: software/webapp

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6ServerNonInheritingIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6ServerNonInheritingIntegrationTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6ServerNonInheritingIntegrationTest.java
new file mode 100644
index 0000000..48dbc5c
--- /dev/null
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6ServerNonInheritingIntegrationTest.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.webapp.jboss;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import java.net.URL;
+
+import org.apache.brooklyn.entity.webapp.jboss.JBoss6Server;
+import org.apache.brooklyn.test.HttpTestUtils;
+import org.apache.brooklyn.test.TestResourceUnavailableException;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.BrooklynAppLiveTestSupport;
+import brooklyn.entity.java.UsesJmx;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.location.basic.LocalhostMachineProvisioningLocation;
+import brooklyn.test.Asserts;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * TODO re-write this like WebAppIntegrationTest, rather than being jboss6 specific.
+ */
+public class JBoss6ServerNonInheritingIntegrationTest extends BrooklynAppLiveTestSupport {
+    
+    // FIXME Fails deploying hello-world.war
+    //     07:27:30,958 ERROR [AbstractKernelController] Error installing to Parse: name=vfs:///tmp/brooklyn-aled/apps/FJMcnSjO/entities/JBoss6Server_UZ2gA9HR/server/standard/deploy/ROOT.war state=PreParse mode=Manual requiredState=Parse: org.jboss.deployers.spi.DeploymentException: Error creating managed object for vfs:///tmp/brooklyn-aled/apps/FJMcnSjO/entities/JBoss6Server_UZ2gA9HR/server/standard/deploy/ROOT.war
+    //     ...
+    //     Caused by: org.xml.sax.SAXException: cvc-complex-type.2.4.d: Invalid content was found starting with element 'url-pattern'. No child element is expected at this point. @ vfs:///tmp/brooklyn-aled/apps/FJMcnSjO/entities/JBoss6Server_UZ2gA9HR/server/standard/deploy/ROOT.war/WEB-INF/web.xml[21,22]
+    //         at org.jboss.xb.binding.parser.sax.SaxJBossXBParser.error(SaxJBossXBParser.java:416) [jbossxb.jar:2.0.3.GA]
+    
+    // Port increment for JBoss 6.
+    public static final int PORT_INCREMENT = 400;
+
+    private LocalhostMachineProvisioningLocation localhostProvisioningLocation;
+    
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        super.setUp();
+
+        localhostProvisioningLocation = app.newLocalhostProvisioningLocation();
+    }
+
+    public String getTestWarWithNoMapping() {
+        TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), "/hello-world-no-mapping.war");
+        return "classpath://hello-world-no-mapping.war";
+    }
+
+    @Test(groups = "Integration")
+    public void testJmxmp() throws Exception {
+        runTest(UsesJmx.JmxAgentModes.JMXMP);
+    }
+
+    @Test(groups = "Integration")
+    public void testJmxRmi() throws Exception {
+        runTest(UsesJmx.JmxAgentModes.JMX_RMI_CUSTOM_AGENT);
+    }
+    
+    @Test(groups = "Integration")
+    public void testJmxAutodetect() throws Exception {
+        runTest(UsesJmx.JmxAgentModes.AUTODETECT);
+    }
+    
+    protected void runTest(UsesJmx.JmxAgentModes jmxAgentMode) throws Exception {
+        final JBoss6Server server = app.createAndManageChild(EntitySpec.create(JBoss6Server.class)
+                .configure(JBoss6Server.PORT_INCREMENT, PORT_INCREMENT)
+                .configure(UsesJmx.JMX_AGENT_MODE, jmxAgentMode)
+                .configure("war", getTestWarWithNoMapping()));
+
+        app.start(ImmutableList.of(localhostProvisioningLocation));
+        
+        String httpUrl = server.getAttribute(JBoss6Server.ROOT_URL);
+        
+        HttpTestUtils.assertHttpStatusCodeEventuallyEquals(httpUrl, 200);
+        HttpTestUtils.assertContentContainsText(httpUrl, "Hello");
+
+        Asserts.succeedsEventually(new Runnable() {
+            @Override public void run() {
+                // TODO Could test other attributes as well; see jboss7 test
+                assertNotNull(server.getAttribute(JBoss6Server.REQUEST_COUNT));
+                assertNotNull(server.getAttribute(JBoss6Server.ERROR_COUNT));
+                assertNotNull(server.getAttribute(JBoss6Server.TOTAL_PROCESSING_TIME));
+            }});
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7PasswordHashingTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7PasswordHashingTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7PasswordHashingTest.java
new file mode 100644
index 0000000..1a3d7b5
--- /dev/null
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7PasswordHashingTest.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.webapp.jboss;
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+import org.apache.brooklyn.entity.webapp.jboss.JBoss7SshDriver;
+
+/**
+ * Expected values in tests were generated by AS7's add-user.sh script and copied here.
+ */
+public class JBoss7PasswordHashingTest {
+
+    @Test
+    public void testPasswordForManagementRealm() {
+        assertEquals(
+                JBoss7SshDriver.hashPassword("username", "password", "ManagementRealm"),
+                "8959126dd54df47f694cd762a51a1a6f");
+        assertEquals(
+                JBoss7SshDriver.hashPassword("test", "123", "ManagementRealm"),
+                "090d846d31185e54a5e8811a2ccb43ee");
+    }
+
+    @Test
+    public void testPasswordForApplicationRealm() {
+        assertEquals(
+                JBoss7SshDriver.hashPassword("username", "password", "ApplicationRealm"),
+                "888a0504c559a34b1c3e919dcec6d941");
+        assertEquals(
+                JBoss7SshDriver.hashPassword("test", "321", "ApplicationRealm"),
+                "a0fdaa45e2d509ac2d390ff6820e2a10");
+    }
+
+    @Test
+    public void testPasswordForCustomRealm() {
+        assertEquals(
+                JBoss7SshDriver.hashPassword("abcdef", "ghijkl", "BrooklynRealm"),
+                "a65be1ba2eb88b9b9edc6a2a7105af72");
+        assertEquals(
+                JBoss7SshDriver.hashPassword("username", "password", "BrooklynRealm"),
+                "161124b73591a1483330f496311b0692");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerAwsEc2LiveTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerAwsEc2LiveTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerAwsEc2LiveTest.java
new file mode 100644
index 0000000..cc27f3c
--- /dev/null
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerAwsEc2LiveTest.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.webapp.jboss;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.testng.Assert.assertNotNull;
+
+import java.net.URL;
+
+import org.apache.brooklyn.entity.webapp.jboss.JBoss7Server;
+import org.apache.brooklyn.test.HttpTestUtils;
+import org.apache.brooklyn.test.TestResourceUnavailableException;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.AbstractEc2LiveTest;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.location.Location;
+import brooklyn.test.Asserts;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * A simple test of installing+running on AWS-EC2, using various OS distros and versions. 
+ */
+public class JBoss7ServerAwsEc2LiveTest extends AbstractEc2LiveTest {
+
+    public String getTestWar() {
+        TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), "/hello-world.war");
+        return "classpath://hello-world.war";
+    }
+
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        final JBoss7Server server = app.createAndManageChild(EntitySpec.create(JBoss7Server.class)
+                .configure("war", getTestWar()));
+        
+        app.start(ImmutableList.of(loc));
+        
+        String url = server.getAttribute(JBoss7Server.ROOT_URL);
+        
+        HttpTestUtils.assertHttpStatusCodeEventuallyEquals(url, 200);
+        HttpTestUtils.assertContentContainsText(url, "Hello");
+        
+        Asserts.succeedsEventually(new Runnable() {
+            @Override public void run() {
+                assertNotNull(server.getAttribute(JBoss7Server.REQUEST_COUNT));
+                assertNotNull(server.getAttribute(JBoss7Server.ERROR_COUNT));
+                assertNotNull(server.getAttribute(JBoss7Server.TOTAL_PROCESSING_TIME));
+                assertNotNull(server.getAttribute(JBoss7Server.MAX_PROCESSING_TIME));
+                assertNotNull(server.getAttribute(JBoss7Server.BYTES_RECEIVED));
+                assertNotNull(server.getAttribute(JBoss7Server.BYTES_SENT));
+            }});
+    }
+    
+    @Test(groups = {"Live", "Live-sanity"})
+    @Override
+    public void test_CentOS_6_3() throws Exception {
+        super.test_CentOS_6_3();
+    }
+
+    @Test(enabled=false)
+    public void testDummy() {} // Convince testng IDE integration that this really does have test methods  
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerDockerLiveTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerDockerLiveTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerDockerLiveTest.java
new file mode 100644
index 0000000..aa8299d
--- /dev/null
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerDockerLiveTest.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.webapp.jboss;
+
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.entity.software.AbstractDockerLiveTest;
+import brooklyn.location.Location;
+import brooklyn.test.Asserts;
+
+import org.apache.brooklyn.entity.webapp.jboss.JBoss7Server;
+import org.apache.brooklyn.test.HttpTestUtils;
+import org.apache.brooklyn.test.TestResourceUnavailableException;
+
+import com.google.common.collect.ImmutableList;
+
+import org.testng.annotations.Test;
+
+import java.net.URL;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.testng.Assert.assertNotNull;
+
+/**
+ * A simple test of installing+running on Docker, using various OS distros and versions.
+ */
+public class JBoss7ServerDockerLiveTest extends AbstractDockerLiveTest {
+
+   public String getTestWar() {
+      TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), "/hello-world.war");
+      return "classpath://hello-world.war";
+   }
+
+   @Override
+   protected void doTest(Location loc) throws Exception {
+      final JBoss7Server server = app.createAndManageChild(EntitySpec.create(JBoss7Server.class)
+              .configure("war", getTestWar()));
+
+      app.start(ImmutableList.of(loc));
+
+      String url = server.getAttribute(JBoss7Server.ROOT_URL);
+
+      HttpTestUtils.assertHttpStatusCodeEventuallyEquals(url, 200);
+      HttpTestUtils.assertContentContainsText(url, "Hello");
+
+      Asserts.succeedsEventually(new Runnable() {
+         @Override
+         public void run() {
+            assertNotNull(server.getAttribute(JBoss7Server.REQUEST_COUNT));
+            assertNotNull(server.getAttribute(JBoss7Server.ERROR_COUNT));
+            assertNotNull(server.getAttribute(JBoss7Server.TOTAL_PROCESSING_TIME));
+            assertNotNull(server.getAttribute(JBoss7Server.MAX_PROCESSING_TIME));
+            assertNotNull(server.getAttribute(JBoss7Server.BYTES_RECEIVED));
+            assertNotNull(server.getAttribute(JBoss7Server.BYTES_SENT));
+         }
+      });
+   }
+
+   @Test(enabled = false)
+   public void testDummy() {
+   } // Convince testng IDE integration that this really does have test methods
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerNonInheritingIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerNonInheritingIntegrationTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerNonInheritingIntegrationTest.java
new file mode 100644
index 0000000..8a4ab3e
--- /dev/null
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerNonInheritingIntegrationTest.java
@@ -0,0 +1,192 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.webapp.jboss;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import java.io.File;
+import java.net.URI;
+
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.BrooklynAppLiveTestSupport;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.location.basic.LocalhostMachineProvisioningLocation;
+import brooklyn.test.Asserts;
+
+import org.apache.brooklyn.entity.webapp.AbstractWebAppFixtureIntegrationTest;
+import org.apache.brooklyn.entity.webapp.HttpsSslConfig;
+import org.apache.brooklyn.entity.webapp.jboss.JBoss7Server;
+import org.apache.brooklyn.test.HttpTestUtils;
+import org.apache.brooklyn.test.TestResourceUnavailableException;
+
+import brooklyn.test.entity.TestApplication;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * TODO re-write this like WebAppIntegrationTest, inheriting, rather than being jboss7 specific.
+ */
+public class JBoss7ServerNonInheritingIntegrationTest extends BrooklynAppLiveTestSupport {
+    
+    private LocalhostMachineProvisioningLocation localhostProvisioningLocation;
+    private File keystoreFile;
+    
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        localhostProvisioningLocation = app.newLocalhostProvisioningLocation();
+        keystoreFile = AbstractWebAppFixtureIntegrationTest.createTemporaryKeyStore("myname", "mypass");
+    }
+
+    @AfterMethod(alwaysRun=true)
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+        if (keystoreFile != null) keystoreFile.delete();
+    }
+
+    public String getTestWar() {
+        TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), "/hello-world.war");
+        return "classpath://hello-world.war";
+    }
+
+    @Test(groups = "Integration")
+    public void testHttp() throws Exception {
+        final JBoss7Server server = app.createAndManageChild(EntitySpec.create(JBoss7Server.class)
+                .configure("war", getTestWar()));
+        
+        app.start(ImmutableList.of(localhostProvisioningLocation));
+        
+        // Don't rely on hostname; differs from URL when tests run on AWS VM
+        String httpUrl = server.getAttribute(JBoss7Server.ROOT_URL);
+        assertEquals(httpUrl.toLowerCase(), ("http://"+URI.create(httpUrl).getHost()+":"+server.getAttribute(JBoss7Server.HTTP_PORT)+"/").toLowerCase());
+        HttpTestUtils.assertHttpStatusCodeEventuallyEquals(httpUrl, 200);
+        HttpTestUtils.assertContentContainsText(httpUrl, "Hello");
+        
+        String httpsUrl = "https://"+URI.create(httpUrl).getHost()+":"+server.getAttribute(JBoss7Server.HTTPS_PORT)+"/";
+        HttpTestUtils.assertUrlUnreachable(httpsUrl);
+
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                assertNotNull(server.getAttribute(JBoss7Server.REQUEST_COUNT));
+                assertNotNull(server.getAttribute(JBoss7Server.ERROR_COUNT));
+                assertNotNull(server.getAttribute(JBoss7Server.TOTAL_PROCESSING_TIME));
+                assertNotNull(server.getAttribute(JBoss7Server.MAX_PROCESSING_TIME));
+                assertNotNull(server.getAttribute(JBoss7Server.BYTES_RECEIVED));
+                assertNotNull(server.getAttribute(JBoss7Server.BYTES_SENT));
+            }});
+    }
+
+    @Test(groups = {"Integration"})
+    public void testHttps() throws Exception {
+        final JBoss7Server server = app.createAndManageChild(EntitySpec.create(JBoss7Server.class)
+                .configure("war", getTestWar())
+                .configure(JBoss7Server.ENABLED_PROTOCOLS, ImmutableSet.of("https"))
+                .configure(JBoss7Server.HTTPS_SSL_CONFIG, new HttpsSslConfig().keyAlias("myname").keystorePassword("mypass").keystoreUrl(keystoreFile.getAbsolutePath())));
+        
+        app.start(ImmutableList.of(localhostProvisioningLocation));
+        
+        // Don't rely on hostname; differs from URL when tests run on AWS VM
+        String httpsUrl = server.getAttribute(JBoss7Server.ROOT_URL);
+        assertEquals(httpsUrl.toLowerCase(), ("https://"+URI.create(httpsUrl).getHost()+":"+server.getAttribute(JBoss7Server.HTTPS_PORT)+"/").toLowerCase());
+        
+        String httpUrl = "http://"+URI.create(httpsUrl).getHost()+":"+server.getAttribute(JBoss7Server.HTTP_PORT)+"/";
+        HttpTestUtils.assertUrlUnreachable(httpUrl);
+        
+        // FIXME HttpTestUtils isn't coping with https, giving
+        //     javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
+        // Uncomment this as soon as HttpTestUtils is fixed
+        // Manual inspection with breakpoint and web-browser confirmed this was working
+//        HttpTestUtils.assertHttpStatusCodeEventuallyEquals(httpsUrl, 200);
+//        HttpTestUtils.assertContentContainsText(httpsUrl, "Hello");
+        
+        // FIXME querying for http://localhost:9990/management/subsystem/web/connector/http/read-resource?include-runtime=true
+        // gives 500 when http is disabled, but if miss out "?include-runtime=true" then it works fine.
+        // So not getting these metrics!
+//        TestUtils.executeUntilSucceeds(new Runnable() {
+//            public void run() {
+//                assertNotNull(server.getAttribute(JBoss7Server.REQUEST_COUNT));
+//                assertNotNull(server.getAttribute(JBoss7Server.ERROR_COUNT));
+//                assertNotNull(server.getAttribute(JBoss7Server.TOTAL_PROCESSING_TIME));
+//                assertNotNull(server.getAttribute(JBoss7Server.MAX_PROCESSING_TIME));
+//                assertNotNull(server.getAttribute(JBoss7Server.BYTES_RECEIVED));
+//                assertNotNull(server.getAttribute(JBoss7Server.BYTES_SENT));
+//            }});
+    }
+    
+    @Test(groups = {"Integration"})
+    public void testHttpAndHttps() throws Exception {
+        final JBoss7Server server = app.createAndManageChild(EntitySpec.create(JBoss7Server.class)
+                .configure("war", getTestWar())
+                .configure(JBoss7Server.ENABLED_PROTOCOLS, ImmutableSet.of("http", "https"))
+                .configure(JBoss7Server.HTTPS_SSL_CONFIG, new HttpsSslConfig().keyAlias("myname").keystorePassword("mypass").keystoreUrl(keystoreFile.getAbsolutePath())));
+        
+        app.start(ImmutableList.of(localhostProvisioningLocation));
+
+        // Don't rely on hostname; differs from URL when tests run on AWS VM
+        String httpsUrl = server.getAttribute(JBoss7Server.ROOT_URL);
+        String httpUrl = "http://"+URI.create(httpsUrl).getHost()+":"+server.getAttribute(JBoss7Server.HTTP_PORT)+"/";
+        
+        assertEquals(httpsUrl.toLowerCase(), ("https://"+URI.create(httpsUrl).getHost()+":"+server.getAttribute(JBoss7Server.HTTPS_PORT)+"/").toLowerCase());
+
+        HttpTestUtils.assertHttpStatusCodeEventuallyEquals(httpUrl, 200);
+        HttpTestUtils.assertContentContainsText(httpUrl, "Hello");
+        
+        // FIXME HttpTestUtils isn't coping with https, giving
+        //     javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
+        // Uncomment this as soon as HttpTestUtils is fixed
+        // Manual inspection with breakpoint and web-browser confirmed this was working
+        //HttpTestUtils.assertHttpStatusCodeEventuallyEquals(httpsUrl, 200);
+        //HttpTestUtils.assertContentContainsText(httpsUrl, "Hello");
+        
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                assertNotNull(server.getAttribute(JBoss7Server.REQUEST_COUNT));
+                assertNotNull(server.getAttribute(JBoss7Server.ERROR_COUNT));
+                assertNotNull(server.getAttribute(JBoss7Server.TOTAL_PROCESSING_TIME));
+                assertNotNull(server.getAttribute(JBoss7Server.MAX_PROCESSING_TIME));
+                assertNotNull(server.getAttribute(JBoss7Server.BYTES_RECEIVED));
+                assertNotNull(server.getAttribute(JBoss7Server.BYTES_SENT));
+            }});
+    }
+
+    @Test(groups = {"Integration"})
+    public void testUsingPortOffsets() throws Exception {
+        final JBoss7Server serverA = app.createAndManageChild(EntitySpec.create(JBoss7Server.class)
+                .configure("portIncrement", 100));
+        final JBoss7Server serverB = app.createAndManageChild(EntitySpec.create(JBoss7Server.class)
+                .configure("portIncrement", 200));
+        app.start(ImmutableList.of(localhostProvisioningLocation));
+
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                assertNotNull(serverA.getAttribute(JBoss7Server.BYTES_SENT));
+                assertNotNull(serverB.getAttribute(JBoss7Server.BYTES_SENT));
+            }});
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerRebindingIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerRebindingIntegrationTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerRebindingIntegrationTest.java
new file mode 100644
index 0000000..93b19fe
--- /dev/null
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss7ServerRebindingIntegrationTest.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.webapp.jboss;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.apache.brooklyn.entity.webapp.jboss.JBoss7Server;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.test.HttpTestUtils;
+import org.apache.brooklyn.test.TestResourceUnavailableException;
+import org.apache.brooklyn.test.WebAppMonitor;
+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.SoftwareProcess;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.entity.rebind.RebindOptions;
+import brooklyn.entity.rebind.RebindTestFixtureWithApp;
+import brooklyn.location.basic.LocalhostMachineProvisioningLocation;
+import brooklyn.test.entity.TestApplication;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+public class JBoss7ServerRebindingIntegrationTest extends RebindTestFixtureWithApp {
+    private static final Logger LOG = LoggerFactory.getLogger(JBoss7ServerRebindingIntegrationTest.class);
+    
+    private LocalhostMachineProvisioningLocation localhostProvisioningLocation;
+    private TestApplication newApp;
+    private List<WebAppMonitor> webAppMonitors = new CopyOnWriteArrayList<WebAppMonitor>();
+    private ExecutorService executor;
+    
+    @BeforeMethod(groups = "Integration")
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        executor = Executors.newCachedThreadPool();
+        localhostProvisioningLocation = (LocalhostMachineProvisioningLocation) origManagementContext.getLocationRegistry().resolve("localhost");
+    }
+
+    @Override
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        for (WebAppMonitor monitor : webAppMonitors) {
+            monitor.terminate();
+        }
+        if (executor != null) executor.shutdownNow();
+        super.tearDown();
+    }
+
+    public String getTestWar() {
+        TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), "/hello-world.war");
+        return "classpath://hello-world.war";
+    }
+
+    private WebAppMonitor newWebAppMonitor(String url) {
+        WebAppMonitor monitor = new WebAppMonitor(url)
+//                .delayMillis(0)
+                .logFailures(LOG);
+        webAppMonitors.add(monitor);
+        executor.execute(monitor);
+        return monitor;
+    }
+    
+    @Test(groups = "Integration")
+    public void testRebindsToRunningServer() throws Exception {
+        // Start an app-server, and wait for it to be fully up
+        JBoss7Server origServer = origApp.createAndManageChild(EntitySpec.create(JBoss7Server.class)
+                    .configure("war", getTestWar()));
+        
+        origApp.start(ImmutableList.of(localhostProvisioningLocation));
+        
+        HttpTestUtils.assertHttpStatusCodeEventuallyEquals(origServer.getAttribute(JBoss7Server.ROOT_URL), 200);
+        WebAppMonitor monitor = newWebAppMonitor(origServer.getAttribute(JBoss7Server.ROOT_URL));
+        
+        // Rebind
+        newApp = rebind(RebindOptions.create().terminateOrigManagementContext(true));
+        JBoss7Server newServer = (JBoss7Server) Iterables.find(newApp.getChildren(), Predicates.instanceOf(JBoss7Server.class));
+        String newRootUrl = newServer.getAttribute(JBoss7Server.ROOT_URL);
+        
+        assertEquals(newRootUrl, origServer.getAttribute(JBoss7Server.ROOT_URL));
+        assertEquals(newServer.getAttribute(JBoss7Server.MANAGEMENT_HTTP_PORT), origServer.getAttribute(JBoss7Server.MANAGEMENT_HTTP_PORT));
+        assertEquals(newServer.getAttribute(JBoss7Server.DEPLOYED_WARS), origServer.getAttribute(JBoss7Server.DEPLOYED_WARS));
+        
+        EntityTestUtils.assertAttributeEqualsEventually(newServer, SoftwareProcess.SERVICE_UP, true);
+        HttpTestUtils.assertHttpStatusCodeEventuallyEquals(newRootUrl, 200);
+
+        // confirm that deploy() effector affects the correct jboss server 
+        newServer.deploy(getTestWar(), "myhello.war");
+        HttpTestUtils.assertHttpStatusCodeEventuallyEquals(newRootUrl+"myhello", 200);
+        
+        // check we see evidence of the enrichers and sensor-feeds having an effect.
+        // Relying on WebAppMonitor to cause these to change.
+        EntityTestUtils.assertAttributeChangesEventually(newServer, JBoss7Server.REQUEST_COUNT);
+        EntityTestUtils.assertAttributeChangesEventually(newServer, JBoss7Server.REQUESTS_PER_SECOND_IN_WINDOW);
+        EntityTestUtils.assertAttributeChangesEventually(newServer, JBoss7Server.REQUESTS_PER_SECOND_IN_WINDOW);
+        EntityTestUtils.assertAttributeChangesEventually(newServer, JBoss7Server.PROCESSING_TIME_FRACTION_IN_WINDOW);
+        
+        assertEquals(monitor.getFailures(), 0);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBossServersMultiVersionWebAppFixtureIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBossServersMultiVersionWebAppFixtureIntegrationTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBossServersMultiVersionWebAppFixtureIntegrationTest.java
new file mode 100644
index 0000000..2de395e
--- /dev/null
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBossServersMultiVersionWebAppFixtureIntegrationTest.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.webapp.jboss;
+
+import org.apache.brooklyn.entity.webapp.AbstractWebAppFixtureIntegrationTest;
+import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcess;
+import org.apache.brooklyn.entity.webapp.jboss.JBoss6Server;
+import org.apache.brooklyn.entity.webapp.jboss.JBoss7Server;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.basic.SoftwareProcess;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.location.basic.PortRanges;
+import brooklyn.test.entity.TestApplication;
+
+public class JBossServersMultiVersionWebAppFixtureIntegrationTest extends AbstractWebAppFixtureIntegrationTest {
+
+    @Test(groups = "Integration", dataProvider = "basicEntities")
+    public void testReportsServiceDownWhenKilled(final SoftwareProcess entity) throws Exception {
+        super.testReportsServiceDownWhenKilled(entity);
+    }
+    
+    @DataProvider(name = "basicEntities")
+    public Object[][] basicEntities() {
+        TestApplication jboss6App = newTestApplication();
+        JBoss6Server jboss6 = jboss6App.createAndManageChild(EntitySpec.create(JBoss6Server.class)
+                .configure(JBoss6Server.PORT_INCREMENT, PORT_INCREMENT));
+        
+        TestApplication jboss7App = newTestApplication();
+        JBoss7Server jboss7 = jboss7App.createAndManageChild(EntitySpec.create(JBoss7Server.class)
+                .configure(JBoss7Server.HTTP_PORT, PortRanges.fromString(DEFAULT_HTTP_PORT)));
+        
+        return new JavaWebAppSoftwareProcess[][] {
+                new JavaWebAppSoftwareProcess[] {jboss6}, 
+                new JavaWebAppSoftwareProcess[] {jboss7}
+                
+        };
+    }
+
+    // to be able to test on this class in Eclipse IDE
+    @Test(groups = "Integration", dataProvider = "basicEntities")
+    public void canStartAndStop(final SoftwareProcess entity) {
+        super.canStartAndStop(entity);
+    }
+
+//    @Override
+//    // TODO override parent and add seam-booking-as{6,7}
+//    @DataProvider(name = "entitiesWithWarAndURL")
+//    public Object[][] entitiesWithWar() {
+//        List<Object[]> result = Lists.newArrayList();
+//        
+//        for (Object[] entity : basicEntities()) {
+//            result.add(new Object[] {
+//                    entity[0],
+//                    "hello-world.war",
+//                    "hello-world/",
+//                    "" // no sub-page path
+//                    });
+//        }
+//        
+//        TestApplication tomcatApp = newTestApplication();
+//        TomcatServer tomcat = tomcatApp.createAndManageChild(EntitySpec.create(TomcatServer.class)
+//                .configure(TomcatServer.HTTP_PORT, PortRanges.fromString(DEFAULT_HTTP_PORT)));
+//        result.add(new Object[] {
+//                tomcat,
+//                "swf-booking-mvc.war",
+//                "swf-booking-mvc/",
+//                "spring/intro",
+//               });
+//            // FIXME seam-booking does not work
+////            [   new JBoss6ServerImpl(parent:application, portIncrement:PORT_INCREMENT),
+////              "seam-booking-as6.war",
+////                "seam-booking-as6/",
+////            ],
+////            [   new JBoss7ServerImpl(parent:application, httpPort:DEFAULT_HTTP_PORT),
+////                "seam-booking-as7.war",
+////                "seam-booking-as7/",
+////            ],
+//        
+//        return result.toArray(new Object[][] {});
+//    }
+
+    public static void main(String ...args) throws Exception {
+        JBossServersMultiVersionWebAppFixtureIntegrationTest t = new JBossServersMultiVersionWebAppFixtureIntegrationTest();
+        t.setUp();
+        t.testReportsServiceDownWhenKilled((SoftwareProcess) t.basicEntities()[0][0]);
+        t.shutdownApp();
+        t.shutdownMgmt();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/Jboss7ServerGoogleComputeLiveTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/Jboss7ServerGoogleComputeLiveTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/Jboss7ServerGoogleComputeLiveTest.java
new file mode 100644
index 0000000..343ec03
--- /dev/null
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/Jboss7ServerGoogleComputeLiveTest.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.webapp.jboss;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.testng.Assert.assertNotNull;
+
+import java.net.URL;
+
+import org.apache.brooklyn.entity.webapp.jboss.JBoss7Server;
+import org.apache.brooklyn.test.HttpTestUtils;
+import org.apache.brooklyn.test.TestResourceUnavailableException;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.AbstractGoogleComputeLiveTest;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.location.Location;
+import brooklyn.test.Asserts;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * A simple test of installing+running on AWS-EC2, using various OS distros and versions. 
+ */
+public class Jboss7ServerGoogleComputeLiveTest extends AbstractGoogleComputeLiveTest {
+
+    public String getTestWar() {
+        TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), "/hello-world.war");
+        return "classpath://hello-world.war";
+    }
+
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        final JBoss7Server server = app.createAndManageChild(EntitySpec.create(JBoss7Server.class)
+                .configure("war", getTestWar()));
+        
+        app.start(ImmutableList.of(loc));
+        
+        String url = server.getAttribute(JBoss7Server.ROOT_URL);
+        
+        HttpTestUtils.assertHttpStatusCodeEventuallyEquals(url, 200);
+        HttpTestUtils.assertContentContainsText(url, "Hello");
+        
+        Asserts.succeedsEventually(new Runnable() {
+            @Override public void run() {
+                assertNotNull(server.getAttribute(JBoss7Server.REQUEST_COUNT));
+                assertNotNull(server.getAttribute(JBoss7Server.ERROR_COUNT));
+                assertNotNull(server.getAttribute(JBoss7Server.TOTAL_PROCESSING_TIME));
+                assertNotNull(server.getAttribute(JBoss7Server.MAX_PROCESSING_TIME));
+                assertNotNull(server.getAttribute(JBoss7Server.BYTES_RECEIVED));
+                assertNotNull(server.getAttribute(JBoss7Server.BYTES_SENT));
+            }});
+    }
+    
+    @Test(groups = {"Live"})
+    @Override
+    public void test_DefaultImage() throws Exception {
+        super.test_DefaultImage();
+    }
+
+    @Test(enabled=false)
+    public void testDummy() {} // Convince testng IDE integration that this really does have test methods  
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jetty/JettyWebAppFixtureIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jetty/JettyWebAppFixtureIntegrationTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jetty/JettyWebAppFixtureIntegrationTest.java
new file mode 100644
index 0000000..a5bd7a8
--- /dev/null
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jetty/JettyWebAppFixtureIntegrationTest.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.webapp.jetty;
+
+import org.apache.brooklyn.entity.webapp.AbstractWebAppFixtureIntegrationTest;
+import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcess;
+import org.apache.brooklyn.entity.webapp.jetty.Jetty6Server;
+import org.apache.brooklyn.entity.webapp.jetty.JettyWebAppFixtureIntegrationTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.basic.SoftwareProcess;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.location.basic.PortRanges;
+import brooklyn.test.entity.TestApplication;
+
+public class JettyWebAppFixtureIntegrationTest extends AbstractWebAppFixtureIntegrationTest {
+
+    // FIXME Fails with this is in the jetty log:
+    //     Caused by: java.lang.ClassNotFoundException: mx4j.tools.adaptor.http.HttpAdaptor
+
+    @Test(groups = "Integration", dataProvider = "basicEntities")
+    public void canStartAndStop(final SoftwareProcess entity) {
+        super.canStartAndStop(entity);
+    }
+    
+    @DataProvider(name = "basicEntities")
+    public Object[][] basicEntities() {
+        TestApplication jettyApp = newTestApplication();
+        Jetty6Server jetty = jettyApp.createAndManageChild(EntitySpec.create(Jetty6Server.class)
+                .configure(Jetty6Server.HTTP_PORT, PortRanges.fromString(DEFAULT_HTTP_PORT)));
+        
+        return new JavaWebAppSoftwareProcess[][] {
+                new JavaWebAppSoftwareProcess[] {jetty}
+        };
+    }
+
+    // to be able to test on this class in Eclipse IDE
+    @Override
+    @Test(groups = "Integration", dataProvider = "entitiesWithWarAndURL")
+    public void testWarDeployAndUndeploy(JavaWebAppSoftwareProcess entity, String war, String urlSubPathToWebApp,
+            String urlSubPathToPageToQuery) {
+        super.testWarDeployAndUndeploy(entity, war, urlSubPathToWebApp, urlSubPathToPageToQuery);
+    }
+    
+    public static void main(String ...args) throws Exception {
+        JettyWebAppFixtureIntegrationTest t = new JettyWebAppFixtureIntegrationTest();
+        t.setUp();
+        t.canStartAndStop((SoftwareProcess) t.basicEntities()[0][0]);
+        t.shutdownApp();
+        t.shutdownMgmt();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppEc2LiveTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppEc2LiveTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppEc2LiveTest.java
new file mode 100644
index 0000000..d3f0dae
--- /dev/null
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppEc2LiveTest.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.webapp.nodejs;
+
+import static org.apache.brooklyn.entity.webapp.nodejs.NodeJsWebAppFixtureIntegrationTest.APP_FILE;
+import static org.apache.brooklyn.entity.webapp.nodejs.NodeJsWebAppFixtureIntegrationTest.APP_NAME;
+import static org.apache.brooklyn.entity.webapp.nodejs.NodeJsWebAppFixtureIntegrationTest.GIT_REPO_URL;
+
+import org.apache.brooklyn.entity.webapp.nodejs.NodeJsWebAppService;
+import org.apache.brooklyn.test.HttpTestUtils;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.AbstractEc2LiveTest;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.location.Location;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * A simple test of installing+running on AWS-EC2, using various OS distros and versions.
+ */
+public class NodeJsWebAppEc2LiveTest extends AbstractEc2LiveTest {
+
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        final NodeJsWebAppService server = app.createAndManageChild(EntitySpec.create(NodeJsWebAppService.class)
+                .configure("gitRepoUrl", GIT_REPO_URL)
+                .configure("appFileName", APP_FILE)
+                .configure("appName", APP_NAME));
+
+        app.start(ImmutableList.of(loc));
+
+        String url = server.getAttribute(NodeJsWebAppService.ROOT_URL);
+
+        HttpTestUtils.assertHttpStatusCodeEventuallyEquals(url, 200);
+        HttpTestUtils.assertContentContainsText(url, "Hello");
+    }
+
+    @Test(groups = {"Live", "Live-sanity"})
+    @Override
+    public void test_Ubuntu_12_0() throws Exception {
+        super.test_Ubuntu_12_0();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppFixtureIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppFixtureIntegrationTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppFixtureIntegrationTest.java
new file mode 100644
index 0000000..c85efc1
--- /dev/null
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppFixtureIntegrationTest.java
@@ -0,0 +1,172 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.webapp.nodejs;
+
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.SoftwareProcessDriver;
+import brooklyn.entity.drivers.DriverDependentEntity;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.entity.trait.Startable;
+import brooklyn.location.Location;
+import brooklyn.location.basic.PortRanges;
+import brooklyn.test.Asserts;
+import brooklyn.test.entity.TestApplication;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.net.Urls;
+import brooklyn.util.time.Duration;
+
+import com.google.common.collect.ImmutableList;
+
+import org.apache.brooklyn.entity.webapp.WebAppService;
+import org.apache.brooklyn.entity.webapp.nodejs.NodeJsWebAppService;
+import org.apache.brooklyn.management.ManagementContext;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.test.HttpTestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Integration tests for NodeJS.
+ * 
+ * Only works on Linux (including Ubuntu and CentOS); not on OS X
+ */
+public class NodeJsWebAppFixtureIntegrationTest {
+
+    // TODO Remove duplication from AbstractWebAppFixtureIntegrationTest. Those tests are geared towards Java-based
+    // tests (e.g. deploying WAR), so not extending it.
+
+    // TODO Test deploy and undeploy; see AbstractWebAppFixtureIntegrationTest#testWarDeployAndUndeploy
+
+    // TODO Does not set WebAppService.REQUEST_COUNT, WebAppService.ERROR_COUNT, REQUESTS_PER_SECOND_IN_WINDOW etc
+    // See AbstractWebAppFixtureIntegrationTest#testPublishesRequestAndErrorCountMetrics and
+    // testPublishesRequestsPerSecondMetric for example tests.
+    
+
+    private static final Logger LOG = LoggerFactory.getLogger(NodeJsWebAppFixtureIntegrationTest.class);
+    
+    // Don't use 8080 since that is commonly used by testing software
+    public static final String DEFAULT_HTTP_PORT = "7880+";
+    
+    public static final String GIT_REPO_URL = "https://github.com/grkvlt/node-hello-world.git";
+    public static final String APP_FILE = "app.js";
+    public static final String APP_NAME = "node-hello-world";
+
+    // The parent application entity for these tests
+    private ManagementContext mgmt;
+    private TestApplication app;
+    private Location loc;
+    private NodeJsWebAppService entity;
+    
+    public static void main(String ...args) throws Exception {
+        NodeJsWebAppFixtureIntegrationTest t = new NodeJsWebAppFixtureIntegrationTest();
+        try {
+            t.setUp();
+            t.testReportsServiceDownWhenKilled();
+        } finally {
+            t.tearDown();
+        }
+    }
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        app = TestApplication.Factory.newManagedInstanceForTests();
+        mgmt = app.getManagementContext();
+        loc = app.newLocalhostProvisioningLocation();
+
+        entity = app.createAndManageChild(EntitySpec.create(NodeJsWebAppService.class)
+                .configure(NodeJsWebAppService.HTTP_PORT, PortRanges.fromString(DEFAULT_HTTP_PORT))
+                .configure("gitRepoUrl", GIT_REPO_URL)
+                .configure("appFileName", APP_FILE)
+                .configure("appName", APP_NAME));
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() {
+        if (mgmt != null) Entities.destroyAll(mgmt);
+        mgmt = null;
+    }
+
+    /**
+     * Checks an entity can start, set SERVICE_UP to true and shutdown again.
+     */
+    @Test(groups = "Integration")
+    public void testCanStartAndStop() {
+        LOG.info("test=canStartAndStop; entity="+entity+"; app="+entity.getApplication());
+
+        Entities.start(entity.getApplication(), ImmutableList.of(loc));
+        Asserts.succeedsEventually(MutableMap.of("timeout", 120*1000), new Runnable() {
+            public void run() {
+                assertTrue(entity.getAttribute(Startable.SERVICE_UP));
+            }});
+        
+        entity.stop();
+        assertFalse(entity.getAttribute(Startable.SERVICE_UP));
+    }
+
+    /**
+     * Checks an entity can start, set SERVICE_UP to true and shutdown again.
+     */
+    @Test(groups = "Integration")
+    public void testReportsServiceDownWhenKilled() throws Exception {
+        LOG.info("test=testReportsServiceDownWithKilled; entity="+entity+"; app="+entity.getApplication());
+        
+        Entities.start(entity.getApplication(), ImmutableList.of(loc));
+        EntityTestUtils.assertAttributeEqualsEventually(MutableMap.of("timeout", Duration.minutes(2)), entity, Startable.SERVICE_UP, true);
+
+        // Stop the underlying entity, but without our entity instance being told!
+        killEntityBehindBack(entity);
+        LOG.info("Killed {} behind mgmt's back, waiting for service up false in mgmt context", entity);
+        
+        EntityTestUtils.assertAttributeEqualsEventually(entity, Startable.SERVICE_UP, false);
+        
+        LOG.info("success getting service up false in primary mgmt universe");
+    }
+
+    /**
+     * Stop the given underlying entity, but without our entity instance being told!
+     */
+    protected void killEntityBehindBack(Entity tokill) throws Exception {
+        ((SoftwareProcessDriver)((DriverDependentEntity<?>) Entities.deproxy(tokill)).getDriver()).stop();
+        // old method of doing this did some dodgy legacy rebind and failed due to too many dangling refs; above is better in any case
+        // but TODO we should have some rebind tests for these!
+    }
+
+    @Test(groups = "Integration")
+    public void testInitialNamedDeployments() {
+        final String urlSubPathToWebApp = APP_NAME;
+        final String urlSubPathToPageToQuery = "";
+        LOG.info("test=testInitialNamedDeployments; entity="+entity+"; app="+entity.getApplication());
+        
+        Entities.start(entity.getApplication(), ImmutableList.of(loc));
+
+        Asserts.succeedsEventually(MutableMap.of("timeout", Duration.minutes(1)), new Runnable() {
+            public void run() {
+                // TODO get this URL from a web-app entity of some kind?
+                String url = Urls.mergePaths(entity.getAttribute(WebAppService.ROOT_URL), urlSubPathToWebApp, urlSubPathToPageToQuery);
+                HttpTestUtils.assertHttpStatusCodeEquals(url, 200);
+            }});
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppSimpleIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppSimpleIntegrationTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppSimpleIntegrationTest.java
new file mode 100644
index 0000000..f5bb7c9
--- /dev/null
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppSimpleIntegrationTest.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.webapp.nodejs;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.fail;
+
+import java.net.ServerSocket;
+import java.util.Iterator;
+
+import org.apache.brooklyn.entity.webapp.nodejs.NodeJsWebAppService;
+import org.apache.brooklyn.entity.webapp.nodejs.NodeJsWebAppServiceImpl;
+import org.jclouds.util.Throwables2;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.BrooklynAppLiveTestSupport;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.location.PortRange;
+import brooklyn.location.basic.LocalhostMachineProvisioningLocation;
+import brooklyn.location.basic.PortRanges;
+import brooklyn.util.net.Networking;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * This tests the operation of the {@link NodeJsWebAppService} entity.
+ */
+public class NodeJsWebAppSimpleIntegrationTest extends BrooklynAppLiveTestSupport {
+
+    private static PortRange DEFAULT_PORT_RANGE = PortRanges.fromString("3000-3099");
+
+    private int httpPort;
+
+    @BeforeMethod(alwaysRun=true)
+    public void pickFreePort() {
+        for (Iterator<Integer> iter = DEFAULT_PORT_RANGE.iterator(); iter.hasNext();) {
+            Integer port = iter.next();
+            if (Networking.isPortAvailable(port)) {
+                httpPort = port;
+                return;
+            }
+        }
+        fail("someone is already listening on ports "+DEFAULT_PORT_RANGE+"; tests assume that port is free on localhost");
+    }
+
+    @Test(groups="Integration")
+    public void detectFailureIfNodeJsBindToPort() throws Exception {
+        ServerSocket listener = new ServerSocket(httpPort);
+        try {
+            LocalhostMachineProvisioningLocation loc = app.newLocalhostProvisioningLocation();
+            NodeJsWebAppService nodejs = app.createAndManageChild(EntitySpec.create(NodeJsWebAppService.class).configure("httpPort", httpPort));
+            try {
+                nodejs.start(ImmutableList.of(loc));
+                fail("Should have thrown start-exception");
+            } catch (Exception e) {
+                // LocalhostMachineProvisioningLocation does NetworkUtils.isPortAvailable, so get -1
+                IllegalArgumentException iae = Throwables2.getFirstThrowableOfType(e, IllegalArgumentException.class);
+                if (iae == null || iae.getMessage() == null || !iae.getMessage().equals("port for http is null")) throw e;
+            } finally {
+                nodejs.stop();
+            }
+            assertFalse(nodejs.getAttribute(NodeJsWebAppServiceImpl.SERVICE_UP));
+        } finally {
+            listener.close();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppSoftlayerLiveTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppSoftlayerLiveTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppSoftlayerLiveTest.java
new file mode 100644
index 0000000..163e232
--- /dev/null
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppSoftlayerLiveTest.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.webapp.nodejs;
+
+import static org.apache.brooklyn.entity.webapp.nodejs.NodeJsWebAppFixtureIntegrationTest.APP_FILE;
+import static org.apache.brooklyn.entity.webapp.nodejs.NodeJsWebAppFixtureIntegrationTest.APP_NAME;
+import static org.apache.brooklyn.entity.webapp.nodejs.NodeJsWebAppFixtureIntegrationTest.GIT_REPO_URL;
+
+import org.apache.brooklyn.entity.webapp.nodejs.NodeJsWebAppService;
+import org.apache.brooklyn.test.HttpTestUtils;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.AbstractSoftlayerLiveTest;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.location.Location;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * A simple test of installing+running on Softlayer, using various OS distros and versions.
+ */
+public class NodeJsWebAppSoftlayerLiveTest extends AbstractSoftlayerLiveTest {
+
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        final NodeJsWebAppService server = app.createAndManageChild(EntitySpec.create(NodeJsWebAppService.class)
+                .configure("gitRepoUrl", GIT_REPO_URL)
+                .configure("appFileName", APP_FILE)
+                .configure("appName", APP_NAME));
+
+        app.start(ImmutableList.of(loc));
+
+        String url = server.getAttribute(NodeJsWebAppService.ROOT_URL);
+
+        HttpTestUtils.assertHttpStatusCodeEventuallyEquals(url, 200);
+        HttpTestUtils.assertContentContainsText(url, "Hello");
+    }
+
+    @Test(groups = {"Live", "Live-sanity"})
+    @Override
+    public void test_Ubuntu_12_0_4() throws Exception {
+        super.test_Ubuntu_12_0_4();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/tomcat/Tomcat8ServerEc2LiveTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/tomcat/Tomcat8ServerEc2LiveTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/tomcat/Tomcat8ServerEc2LiveTest.java
new file mode 100644
index 0000000..ad1aca3
--- /dev/null
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/tomcat/Tomcat8ServerEc2LiveTest.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.webapp.tomcat;
+
+import static org.testng.Assert.assertNotNull;
+
+import org.testng.annotations.Test;
+
+import brooklyn.entity.AbstractEc2LiveTest;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.location.Location;
+import brooklyn.test.Asserts;
+
+import org.apache.brooklyn.entity.webapp.tomcat.Tomcat8Server;
+import org.apache.brooklyn.test.HttpTestUtils;
+import org.apache.brooklyn.test.TestResourceUnavailableException;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * A simple test of installing+running on AWS-EC2, using various OS distros and versions. 
+ */
+public class Tomcat8ServerEc2LiveTest extends AbstractEc2LiveTest {
+
+    public String getTestWar() {
+        TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), "/hello-world.war");
+        return "classpath://hello-world.war";
+    }
+
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        final Tomcat8Server server = app.createAndManageChild(EntitySpec.create(Tomcat8Server.class)
+                .configure("war", getTestWar()));
+        
+        app.start(ImmutableList.of(loc));
+        
+        String url = server.getAttribute(Tomcat8Server.ROOT_URL);
+        
+        HttpTestUtils.assertHttpStatusCodeEventuallyEquals(url, 200);
+        HttpTestUtils.assertContentContainsText(url, "Hello");
+        
+        Asserts.succeedsEventually(new Runnable() {
+            @Override public void run() {
+                assertNotNull(server.getAttribute(Tomcat8Server.REQUEST_COUNT));
+                assertNotNull(server.getAttribute(Tomcat8Server.ERROR_COUNT));
+                assertNotNull(server.getAttribute(Tomcat8Server.TOTAL_PROCESSING_TIME));
+            }});
+    }
+    
+    @Test(enabled=false)
+    public void testDummy() {} // Convince testng IDE integration that this really does have test methods  
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/tomcat/Tomcat8ServerRestartIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/tomcat/Tomcat8ServerRestartIntegrationTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/tomcat/Tomcat8ServerRestartIntegrationTest.java
new file mode 100644
index 0000000..53eb739
--- /dev/null
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/tomcat/Tomcat8ServerRestartIntegrationTest.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.webapp.tomcat;
+
+import org.apache.brooklyn.entity.webapp.tomcat.Tomcat8Server;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.basic.AbstractSoftwareProcessRestartIntegrationTest;
+import brooklyn.entity.basic.SoftwareProcess;
+import brooklyn.entity.proxying.EntitySpec;
+
+/**
+ * Tests restart of the software *process* (as opposed to the VM).
+ */
+@Test(groups="Integration")
+public class Tomcat8ServerRestartIntegrationTest extends AbstractSoftwareProcessRestartIntegrationTest {
+    
+    // TODO Remove duplication from MySqlRestartIntegrationTest
+    
+    @SuppressWarnings("unused")
+    private static final Logger LOG = LoggerFactory.getLogger(Tomcat8ServerRestartIntegrationTest.class);
+
+    @Override
+    protected EntitySpec<? extends SoftwareProcess> newEntitySpec() {
+        return EntitySpec.create(Tomcat8Server.class);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/tomcat/Tomcat8ServerSoftlayerLiveTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/tomcat/Tomcat8ServerSoftlayerLiveTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/tomcat/Tomcat8ServerSoftlayerLiveTest.java
new file mode 100644
index 0000000..2e37974
--- /dev/null
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/tomcat/Tomcat8ServerSoftlayerLiveTest.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.webapp.tomcat;
+
+import static org.testng.Assert.assertNotNull;
+
+import org.testng.annotations.Test;
+
+import brooklyn.entity.AbstractSoftlayerLiveTest;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.location.Location;
+import brooklyn.test.Asserts;
+
+import org.apache.brooklyn.entity.webapp.tomcat.Tomcat8Server;
+import org.apache.brooklyn.test.HttpTestUtils;
+import org.apache.brooklyn.test.TestResourceUnavailableException;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * A simple test of installing+running on Softlayer, using various OS distros and versions. 
+ */
+public class Tomcat8ServerSoftlayerLiveTest extends AbstractSoftlayerLiveTest {
+
+    public String getTestWar() {
+        TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), "/hello-world.war");
+        return "classpath://hello-world.war";
+    }
+
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        final Tomcat8Server server = app.createAndManageChild(EntitySpec.create(Tomcat8Server.class)
+                .configure("war", getTestWar()));
+        
+        app.start(ImmutableList.of(loc));
+        
+        String url = server.getAttribute(Tomcat8Server.ROOT_URL);
+        
+        HttpTestUtils.assertHttpStatusCodeEventuallyEquals(url, 200);
+        HttpTestUtils.assertContentContainsText(url, "Hello");
+        
+        Asserts.succeedsEventually(new Runnable() {
+            @Override public void run() {
+                assertNotNull(server.getAttribute(Tomcat8Server.REQUEST_COUNT));
+                assertNotNull(server.getAttribute(Tomcat8Server.ERROR_COUNT));
+                assertNotNull(server.getAttribute(Tomcat8Server.TOTAL_PROCESSING_TIME));
+                
+                // TODO These appear not to be set in TomcatServerImpl.connectSensors
+                //      See TomcatServerEc2LiveTest, where these are also not included.
+//                assertNotNull(server.getAttribute(TomcatServer.MAX_PROCESSING_TIME));
+//                assertNotNull(server.getAttribute(TomcatServer.BYTES_RECEIVED));
+//                assertNotNull(server.getAttribute(TomcatServer.BYTES_SENT));
+            }});
+    }
+
+    @Test(groups = {"Live", "Live-sanity"})
+    @Override
+    public void test_Ubuntu_12_0_4() throws Exception {
+        super.test_Ubuntu_12_0_4();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/tomcat/Tomcat8ServerWebAppFixtureIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/tomcat/Tomcat8ServerWebAppFixtureIntegrationTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/tomcat/Tomcat8ServerWebAppFixtureIntegrationTest.java
new file mode 100644
index 0000000..acf2e85
--- /dev/null
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/tomcat/Tomcat8ServerWebAppFixtureIntegrationTest.java
@@ -0,0 +1,177 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.webapp.tomcat;
+
+import java.io.File;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketException;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.basic.SoftwareProcess;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.location.basic.PortRanges;
+
+import org.apache.brooklyn.entity.webapp.AbstractWebAppFixtureIntegrationTest;
+import org.apache.brooklyn.entity.webapp.HttpsSslConfig;
+import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcess;
+import org.apache.brooklyn.entity.webapp.tomcat.Tomcat8Server;
+import org.apache.brooklyn.test.TestResourceUnavailableException;
+import brooklyn.test.entity.TestApplication;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.repeat.Repeater;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+
+public class Tomcat8ServerWebAppFixtureIntegrationTest extends AbstractWebAppFixtureIntegrationTest {
+
+    @SuppressWarnings("unused")
+    private static final Logger log = LoggerFactory.getLogger(Tomcat8ServerWebAppFixtureIntegrationTest.class);
+    
+    @DataProvider(name = "basicEntities")
+    public Object[][] basicEntities() {
+        TestApplication tomcatApp = newTestApplication();
+        Tomcat8Server tomcat = tomcatApp.createAndManageChild(EntitySpec.create(Tomcat8Server.class)
+                .configure(Tomcat8Server.HTTP_PORT, PortRanges.fromString(DEFAULT_HTTP_PORT)));
+
+
+        File keystoreFile;
+        try {
+            keystoreFile = createTemporaryKeyStore("myname", "mypass");
+            keystoreFile.deleteOnExit();
+        } catch (Exception e) {
+            throw Exceptions.propagate(e);
+        }
+
+        TestApplication tomcatHttpsApp = newTestApplication();
+        Tomcat8Server httpsTomcat = tomcatHttpsApp.createAndManageChild(EntitySpec.create(Tomcat8Server.class)
+                .configure(Tomcat8Server.ENABLED_PROTOCOLS, ImmutableSet.of("https"))
+                .configure(Tomcat8Server.HTTPS_SSL_CONFIG,
+                        new HttpsSslConfig().keyAlias("myname").keystorePassword("mypass").keystoreUrl(keystoreFile.getAbsolutePath())));
+
+        return new JavaWebAppSoftwareProcess[][] {
+                new JavaWebAppSoftwareProcess[] { tomcat },
+                new JavaWebAppSoftwareProcess[] { httpsTomcat }
+        };
+    }
+
+    // exists to be able to test on this class from GUI in Eclipse IDE
+    @Test(groups = "Integration", dataProvider = "basicEntities")
+    public void canStartAndStop(final SoftwareProcess entity) {
+        super.canStartAndStop(entity);
+    }
+    @Test(groups = "Integration", dataProvider = "basicEntities")
+    public void testReportsServiceDownWhenKilled(final SoftwareProcess entity) throws Exception {
+        super.testReportsServiceDownWhenKilled(entity);
+    }
+
+    @Override
+    // as parent, but with spring travel
+    @DataProvider(name = "entitiesWithWarAndURL")
+    public Object[][] entitiesWithWar() {
+        TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), "/hello-world.war");
+        List<Object[]> result = Lists.newArrayList();
+        
+        for (Object[] entity : basicEntities()) {
+            result.add(new Object[] {
+                    entity[0],
+                    "hello-world.war",
+                    "hello-world/",
+                    "" // no sub-page path
+                    });
+        }
+
+        // TODO would be nice to test against spring web framework stock booking example
+        // but we'd need an external URL for that (we removed the binary from here for apache compliance reasons)
+//        TestApplication tomcatApp = newTestApplication();
+//        TomcatServer tomcat = tomcatApp.createAndManageChild(EntitySpec.create(TomcatServer.class)
+//                .configure(TomcatServer.HTTP_PORT, PortRanges.fromString(DEFAULT_HTTP_PORT)));
+//        result.add(new Object[] {
+//                tomcat,
+//                "swf-booking-mvc.war",
+//                "swf-booking-mvc/",
+//                "spring/intro",
+//               });
+        
+        return result.toArray(new Object[][] {});
+    }
+
+    @AfterMethod(alwaysRun=true, dependsOnMethods="shutdownApp")
+    public void ensureIsShutDown() throws Exception {
+        final AtomicReference<Socket> shutdownSocket = new AtomicReference<Socket>();
+        final AtomicReference<SocketException> gotException = new AtomicReference<SocketException>();
+        final Integer shutdownPort = (entity != null) ? entity.getAttribute(Tomcat8Server.SHUTDOWN_PORT) : null;
+        
+        if (shutdownPort != null) {
+            boolean socketClosed = Repeater.create("Checking WebApp has shut down")
+                    .repeat(new Callable<Void>() {
+                            public Void call() throws Exception {
+                                if (shutdownSocket.get() != null) shutdownSocket.get().close();
+                                try {
+                                    shutdownSocket.set(new Socket(InetAddress.getLocalHost(), shutdownPort));
+                                    gotException.set(null);
+                                } catch (SocketException e) {
+                                    gotException.set(e);
+                                }
+                                return null;
+                            }})
+                    .every(100, TimeUnit.MILLISECONDS)
+                    .until(new Callable<Boolean>() {
+                            public Boolean call() {
+                                return (gotException.get() != null);
+                            }})
+                    .limitIterationsTo(25)
+                    .run();
+            
+            if (socketClosed == false) {
+//                log.error("WebApp did not shut down - this is a failure of the last test run");
+//                log.warn("I'm sending a message to the shutdown port {}", shutdownPort);
+//                OutputStreamWriter writer = new OutputStreamWriter(shutdownSocket.getOutputStream());
+//                writer.write("SHUTDOWN\r\n");
+//                writer.flush();
+//                writer.close();
+//                shutdownSocket.close();
+                throw new Exception("Last test run did not shut down WebApp entity "+entity+" (port "+shutdownPort+")");
+            }
+        } else {
+            Assert.fail("Cannot shutdown, because shutdown-port not set for "+entity);
+        }
+    }
+
+    public static void main(String ...args) throws Exception {
+        Tomcat8ServerWebAppFixtureIntegrationTest t = new Tomcat8ServerWebAppFixtureIntegrationTest();
+        t.setUp();
+        t.testReportsServiceDownWhenKilled((SoftwareProcess) t.basicEntities()[0][0]);
+        t.shutdownApp();
+        t.ensureIsShutDown();
+        t.shutdownMgmt();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/tomcat/TomcatServerDisableRetrieveUsageMetricsIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/tomcat/TomcatServerDisableRetrieveUsageMetricsIntegrationTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/tomcat/TomcatServerDisableRetrieveUsageMetricsIntegrationTest.java
new file mode 100644
index 0000000..03d1492
--- /dev/null
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/tomcat/TomcatServerDisableRetrieveUsageMetricsIntegrationTest.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.webapp.tomcat;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+
+import org.apache.brooklyn.entity.webapp.tomcat.TomcatServer;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.BrooklynAppLiveTestSupport;
+import brooklyn.entity.basic.SoftwareProcess;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.location.basic.LocalhostMachineProvisioningLocation;
+import brooklyn.test.Asserts;
+
+import com.google.common.collect.ImmutableList;
+
+public class TomcatServerDisableRetrieveUsageMetricsIntegrationTest extends BrooklynAppLiveTestSupport {
+    
+    // Note we test the default and the disabled with two entities, in the same method.
+    // This piggie-backs off the necessary length of time required for the default entity
+    // to have its metrics set; we then assert that the other entity does not have its set.
+    @Test(groups="Integration")
+    public void testDisableRetrievalOfUsageMetrics() throws Exception {
+        LocalhostMachineProvisioningLocation loc = app.newLocalhostProvisioningLocation();
+        final TomcatServer tc1 = app.createAndManageChild(EntitySpec.create(TomcatServer.class)
+                .configure(SoftwareProcess.RETRIEVE_USAGE_METRICS, false));
+        final TomcatServer tc2 = app.createAndManageChild(EntitySpec.create(TomcatServer.class));
+        
+        tc1.start(ImmutableList.of(loc));
+        tc2.start(ImmutableList.of(loc));
+
+        // tc2 uses defaults, so will include usage metrics
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                assertNotNull(tc2.getAttribute(TomcatServer.CONNECTOR_STATUS));
+                assertNotNull(tc2.getAttribute(TomcatServer.ERROR_COUNT));
+                assertNotNull(tc2.getAttribute(TomcatServer.REQUEST_COUNT));
+                assertNotNull(tc2.getAttribute(TomcatServer.TOTAL_PROCESSING_TIME));
+            }});
+
+        // tc1 should have status info, but not usage metrics
+        EntityTestUtils.assertAttributeEventuallyNonNull(tc1, TomcatServer.CONNECTOR_STATUS);
+        EntityTestUtils.assertAttributeEqualsContinually(tc1, TomcatServer.ERROR_COUNT, null);
+        assertNull(tc1.getAttribute(TomcatServer.REQUEST_COUNT));
+        assertNull(tc1.getAttribute(TomcatServer.TOTAL_PROCESSING_TIME));
+    }
+}