http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppClusterIntegrationTest.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppClusterIntegrationTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppClusterIntegrationTest.java new file mode 100644 index 0000000..b004a8c --- /dev/null +++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppClusterIntegrationTest.java @@ -0,0 +1,184 @@ +/* + * 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; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import java.util.List; +import java.util.concurrent.Callable; + +import org.apache.brooklyn.test.EntityTestUtils; +import org.apache.brooklyn.test.HttpTestUtils; +import org.apache.brooklyn.test.TestResourceUnavailableException; +import org.apache.brooklyn.test.entity.TestJavaWebAppEntity; +import org.apache.brooklyn.entity.basic.RecordingSensorEventListener; +import org.apache.brooklyn.entity.proxy.AbstractController; +import org.apache.brooklyn.entity.proxy.LoadBalancer; +import org.apache.brooklyn.entity.proxy.nginx.NginxController; +import org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster; +import org.apache.brooklyn.entity.webapp.DynamicWebAppCluster; +import org.apache.brooklyn.entity.webapp.tomcat.TomcatServer; +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.Attributes; +import brooklyn.entity.basic.Lifecycle; +import brooklyn.entity.proxying.EntitySpec; +import brooklyn.location.basic.LocalhostMachineProvisioningLocation; +import brooklyn.test.Asserts; +import brooklyn.util.collections.CollectionFunctionals; +import brooklyn.util.collections.MutableMap; + +import com.google.common.base.Suppliers; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; + +public class ControlledDynamicWebAppClusterIntegrationTest extends BrooklynAppLiveTestSupport { + private static final Logger log = LoggerFactory.getLogger(ControlledDynamicWebAppClusterIntegrationTest.class); + + private static final int TIMEOUT_MS = 10*1000; + + private LocalhostMachineProvisioningLocation loc; + private List<LocalhostMachineProvisioningLocation> locs; + + @BeforeMethod(alwaysRun=true) + public void setUp() throws Exception { + super.setUp(); + + loc = app.newLocalhostProvisioningLocation(); + locs = ImmutableList.of(loc); + } + + public String getTestWar() { + TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), "/hello-world.war"); + return "classpath://hello-world.war"; + } + + @Test(groups="Integration") + public void testPropogateHttpPorts() { + ControlledDynamicWebAppCluster cluster = app.createAndManageChild(EntitySpec.create(ControlledDynamicWebAppCluster.class) + .configure("initialSize", 1)); + app.start(locs); + + EntityTestUtils.assertAttributeEventuallyNonNull(cluster, LoadBalancer.PROXY_HTTP_PORT); + EntityTestUtils.assertAttributeEventuallyNonNull(cluster, LoadBalancer.PROXY_HTTPS_PORT); + } + + @Test(groups="Integration") + public void testConfiguresController() { + ControlledDynamicWebAppCluster cluster = app.createAndManageChild(EntitySpec.create(ControlledDynamicWebAppCluster.class) + .configure("initialSize", 1) + .configure("memberSpec", EntitySpec.create(TomcatServer.class).configure("war", getTestWar()))); + app.start(locs); + + String url = cluster.getController().getAttribute(NginxController.ROOT_URL); + HttpTestUtils.assertHttpStatusCodeEventuallyEquals(url, 200); + HttpTestUtils.assertContentEventuallyContainsText(url, "Hello"); + } + + @Test(groups="Integration") + public void testSetsToplevelHostnameFromController() { + ControlledDynamicWebAppCluster cluster = app.createAndManageChild(EntitySpec.create(ControlledDynamicWebAppCluster.class) + .configure("initialSize", 1) + .configure("memberSpec", EntitySpec.create(TomcatServer.class).configure("war", getTestWar()))); + app.start(locs); + + String expectedHostname = cluster.getController().getAttribute(LoadBalancer.HOSTNAME); + String expectedRootUrl = cluster.getController().getAttribute(LoadBalancer.ROOT_URL); + boolean expectedServiceUp = true; + + assertNotNull(expectedHostname); + assertNotNull(expectedRootUrl); + + EntityTestUtils.assertAttributeEqualsEventually(MutableMap.of("timeout", TIMEOUT_MS), cluster, ControlledDynamicWebAppCluster.HOSTNAME, expectedHostname); + EntityTestUtils.assertAttributeEqualsEventually(MutableMap.of("timeout", TIMEOUT_MS), cluster, ControlledDynamicWebAppCluster.ROOT_URL, expectedRootUrl); + EntityTestUtils.assertAttributeEqualsEventually(MutableMap.of("timeout", TIMEOUT_MS), cluster, ControlledDynamicWebAppCluster.SERVICE_UP, expectedServiceUp); + } + + @Test(groups="Integration") + public void testCustomWebClusterSpecGetsMemberSpec() { + ControlledDynamicWebAppCluster cluster = app.createAndManageChild(EntitySpec.create(ControlledDynamicWebAppCluster.class) + .configure("initialSize", 1) + .configure(ControlledDynamicWebAppCluster.MEMBER_SPEC, EntitySpec.create(TomcatServer.class) + .configure(TomcatServer.ROOT_WAR, getTestWar())) + .configure(ControlledDynamicWebAppCluster.WEB_CLUSTER_SPEC, EntitySpec.create(DynamicWebAppCluster.class) + .displayName("mydisplayname"))); + app.start(locs); + + String url = cluster.getController().getAttribute(NginxController.ROOT_URL); + HttpTestUtils.assertContentEventuallyContainsText(url, "Hello"); + + // and make sure it really was using our custom spec + assertEquals(cluster.getCluster().getDisplayName(), "mydisplayname"); + } + + // Needs to be integration test because still using nginx controller; could pass in mock controller + @Test(groups="Integration") + public void testSetsServiceLifecycle() { + ControlledDynamicWebAppCluster cluster = app.createAndManageChild( EntitySpec.create(ControlledDynamicWebAppCluster.class) + .configure("initialSize", 1) + .configure(ControlledDynamicWebAppCluster.MEMBER_SPEC, EntitySpec.create(TestJavaWebAppEntity.class)) ); + + EntityTestUtils.assertAttributeEqualsEventually(cluster, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.STOPPED); + + RecordingSensorEventListener<Lifecycle> listener = new RecordingSensorEventListener<Lifecycle>(true); + app.subscribe(cluster, Attributes.SERVICE_STATE_ACTUAL, listener); + app.start(locs); + + Asserts.eventually(Suppliers.ofInstance(listener.getEventValues()), CollectionFunctionals.sizeEquals(2)); + assertEquals(listener.getEventValues(), ImmutableList.of(Lifecycle.STARTING, Lifecycle.RUNNING), "vals="+listener.getEventValues()); + listener.clearEvents(); + + app.stop(); + EntityTestUtils.assertAttributeEqualsEventually(cluster, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.STOPPED); + Asserts.eventually(Suppliers.ofInstance(listener), CollectionFunctionals.sizeEquals(2)); + assertEquals(listener.getEventValues(), ImmutableList.of(Lifecycle.STOPPING, Lifecycle.STOPPED), "vals="+listener.getEventValues()); + } + + @Test(groups="Integration") + public void testTomcatAbsoluteRedirect() { + final ControlledDynamicWebAppCluster cluster = app.createAndManageChild(EntitySpec.create(ControlledDynamicWebAppCluster.class) + .configure(ControlledDynamicWebAppCluster.MEMBER_SPEC, EntitySpec.create(TomcatServer.class) + .configure(TomcatServer.ROOT_WAR, getTestWar())) + .configure("initialSize", 1) + .configure(AbstractController.SERVICE_UP_URL_PATH, "hello/redirectAbsolute") + ); + app.start(locs); + + final NginxController nginxController = (NginxController) cluster.getController(); + Asserts.succeedsEventually(new Callable<Boolean>() { + @Override + public Boolean call() throws Exception { + return nginxController.getServerPoolAddresses().size() == 1; + } + }); + + Entity tomcatServer = Iterables.getOnlyElement(cluster.getCluster().getMembers()); + EntityTestUtils.assertAttributeEqualsEventually(tomcatServer, Attributes.SERVICE_UP, true); + + EntityTestUtils.assertAttributeEqualsContinually(nginxController, Attributes.SERVICE_UP, true); + + app.stop(); + } +}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppClusterTest.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppClusterTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppClusterTest.java new file mode 100644 index 0000000..30b66ba --- /dev/null +++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/ControlledDynamicWebAppClusterTest.java @@ -0,0 +1,213 @@ +/* + * 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; + +import static org.testng.Assert.assertEquals; + +import java.util.List; + +import org.apache.brooklyn.entity.proxy.AbstractController; +import org.apache.brooklyn.entity.proxy.LoadBalancer; +import org.apache.brooklyn.entity.proxy.TrackingAbstractController; +import org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster; +import org.apache.brooklyn.entity.webapp.DynamicWebAppCluster; +import org.apache.brooklyn.entity.webapp.jboss.JBoss7Server; +import org.apache.brooklyn.test.EntityTestUtils; +import org.apache.brooklyn.test.TestResourceUnavailableException; +import org.apache.brooklyn.test.entity.TestJavaWebAppEntity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import brooklyn.entity.BrooklynAppUnitTestSupport; +import brooklyn.entity.Group; +import brooklyn.entity.basic.Attributes; +import brooklyn.entity.basic.BasicGroup; +import brooklyn.entity.basic.Entities; +import brooklyn.entity.basic.Lifecycle; +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; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; + +public class ControlledDynamicWebAppClusterTest extends BrooklynAppUnitTestSupport { + private static final Logger log = LoggerFactory.getLogger(ControlledDynamicWebAppClusterTest.class); + + private LocalhostMachineProvisioningLocation loc; + private List<LocalhostMachineProvisioningLocation> locs; + + @BeforeMethod(alwaysRun=true) + public void setUp() throws Exception { + super.setUp(); + + loc = app.newLocalhostProvisioningLocation(); + locs = ImmutableList.of(loc); + } + + public String getTestWar() { + TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), "/hello-world.war"); + return "classpath://hello-world.war"; + } + + @Test + public void testUsesCustomController() { + AbstractController controller = app.createAndManageChild(EntitySpec.create(TrackingAbstractController.class).displayName("mycustom")); + + ControlledDynamicWebAppCluster cluster = app.createAndManageChild(EntitySpec.create(ControlledDynamicWebAppCluster.class) + .configure("initialSize", 0) + .configure(ControlledDynamicWebAppCluster.CONTROLLER, controller) + .configure("memberSpec", EntitySpec.create(JBoss7Server.class).configure("war", getTestWar()))); + app.start(locs); + + EntityTestUtils.assertAttributeEqualsEventually(controller, AbstractController.SERVICE_UP, true); + assertEquals(cluster.getController(), controller); + + // Stopping cluster should not stop controller (because it didn't create it) + cluster.stop(); + EntityTestUtils.assertAttributeEquals(controller, AbstractController.SERVICE_UP, true); + } + + @Test + public void testUsesCustomControlledGroup() { + TestJavaWebAppEntity webServer = app.createAndManageChild(EntitySpec.create(TestJavaWebAppEntity.class)); + webServer.setAttribute(Attributes.SUBNET_HOSTNAME, "myhostname"); + webServer.setAttribute(Attributes.HTTP_PORT, 1234); + + TrackingAbstractController controller = app.createAndManageChild(EntitySpec.create(TrackingAbstractController.class)); + Group controlledGroup = app.createAndManageChild(EntitySpec.create(BasicGroup.class)); + controlledGroup.addMember(webServer); + + ControlledDynamicWebAppCluster cluster = app.createAndManageChild(EntitySpec.create(ControlledDynamicWebAppCluster.class) + .configure("initialSize", 0) + .configure(ControlledDynamicWebAppCluster.CONTROLLER, controller) + .configure(ControlledDynamicWebAppCluster.CONTROLLED_GROUP, controlledGroup) + .configure("memberSpec", EntitySpec.create(JBoss7Server.class).configure("war", getTestWar()))); + app.start(locs); + + assertEquals(controller.getUpdates(), ImmutableList.of(ImmutableSet.of("myhostname:1234"))); + } + + @Test + public void testUsesCustomControllerSpec() { + EntitySpec<TrackingAbstractController> controllerSpec = EntitySpec.create(TrackingAbstractController.class).displayName("mycustom"); + ControlledDynamicWebAppCluster cluster = app.createAndManageChild(EntitySpec.create(ControlledDynamicWebAppCluster.class) + .configure("initialSize", 0) + .configure(ControlledDynamicWebAppCluster.CONTROLLER_SPEC, controllerSpec) + .configure("memberSpec", EntitySpec.create(JBoss7Server.class).configure("war", getTestWar()))); + app.start(locs); + LoadBalancer controller = cluster.getController(); + + EntityTestUtils.assertAttributeEqualsEventually(controller, AbstractController.SERVICE_UP, true); + assertEquals(controller.getDisplayName(), "mycustom"); + + // Stopping cluster should stop the controller (because it created it) + cluster.stop(); + EntityTestUtils.assertAttributeEquals(controller, AbstractController.SERVICE_UP, false); + } + + @Test + public void testTheTestJavaWebApp() { + SoftwareProcess n = app.createAndManageChild(EntitySpec.create(TestJavaWebAppEntity.class)); + app.start(locs); + + EntityTestUtils.assertAttributeEqualsEventually(n, AbstractController.SERVICE_UP, true); + + app.stop(); + EntityTestUtils.assertAttributeEqualsEventually(n, AbstractController.SERVICE_UP, false); + } + + @Test + public void testSetsInitialSize() { + ControlledDynamicWebAppCluster cluster = app.createAndManageChild(EntitySpec.create(ControlledDynamicWebAppCluster.class) + .configure("initialSize", 2) + .configure(ControlledDynamicWebAppCluster.CONTROLLER_SPEC, EntitySpec.create(TrackingAbstractController.class)) + .configure(ControlledDynamicWebAppCluster.MEMBER_SPEC, EntitySpec.create(TestJavaWebAppEntity.class)) ); + app.start(locs); + + Iterable<TestJavaWebAppEntity> webservers = Iterables.filter(cluster.getCluster().getMembers(), TestJavaWebAppEntity.class); + assertEquals(Iterables.size(webservers), 2, "webservers="+webservers); + } + + @Test + public void testUsesCustomWebClusterSpec() { + ControlledDynamicWebAppCluster cluster = app.createAndManageChild(EntitySpec.create(ControlledDynamicWebAppCluster.class) + .configure("initialSize", 0) + .configure(ControlledDynamicWebAppCluster.CONTROLLER_SPEC, EntitySpec.create(TrackingAbstractController.class)) + .configure(ControlledDynamicWebAppCluster.WEB_CLUSTER_SPEC, EntitySpec.create(DynamicWebAppCluster.class) + .displayName("mydisplayname"))); + app.start(locs); + + assertEquals(cluster.getCluster().getDisplayName(), "mydisplayname"); + } + + @Test + public void testMembersReflectChildClusterMembers() { + final ControlledDynamicWebAppCluster cluster = app.createAndManageChild(EntitySpec.create(ControlledDynamicWebAppCluster.class) + .configure("initialSize", 1) + .configure(ControlledDynamicWebAppCluster.CONTROLLER_SPEC, EntitySpec.create(TrackingAbstractController.class)) + .configure(ControlledDynamicWebAppCluster.MEMBER_SPEC, EntitySpec.create(TestJavaWebAppEntity.class)) ); + app.start(locs); + final DynamicWebAppCluster childCluster = cluster.getCluster(); + + // Expect initial member(s) to be the same + assertEquals(childCluster.getMembers().size(), 1); + Asserts.succeedsEventually(new Runnable() { + @Override public void run() { + Asserts.assertEqualsIgnoringOrder(childCluster.getMembers(), cluster.getMembers()); + }}); + + // After resize up, same members + cluster.resize(2); + assertEquals(childCluster.getMembers().size(), 2); + Asserts.succeedsEventually(new Runnable() { + @Override public void run() { + Asserts.assertEqualsIgnoringOrder(childCluster.getMembers(), cluster.getMembers()); + }}); + + // After resize down, same members + cluster.resize(1); + assertEquals(childCluster.getMembers().size(), 1); + Asserts.succeedsEventually(new Runnable() { + @Override public void run() { + Asserts.assertEqualsIgnoringOrder(childCluster.getMembers(), cluster.getMembers()); + }}); + } + + @Test + public void testStopOnChildUnmanaged() { + final ControlledDynamicWebAppCluster cluster = app.createAndManageChild(EntitySpec.create(ControlledDynamicWebAppCluster.class) + .configure("initialSize", 1) + .configure(ControlledDynamicWebAppCluster.CONTROLLER_SPEC, EntitySpec.create(TrackingAbstractController.class)) + .configure(ControlledDynamicWebAppCluster.MEMBER_SPEC, EntitySpec.create(TestJavaWebAppEntity.class)) ); + app.start(locs); + final DynamicWebAppCluster childCluster = cluster.getCluster(); + LoadBalancer controller = cluster.getController(); + + Entities.unmanage(childCluster); + Entities.unmanage(controller); + + cluster.stop(); + EntityTestUtils.assertAttributeEquals(cluster, ControlledDynamicWebAppCluster.SERVICE_STATE_ACTUAL, Lifecycle.STOPPED); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/DynamicWebAppClusterTest.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/DynamicWebAppClusterTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/DynamicWebAppClusterTest.java new file mode 100644 index 0000000..ec063f4 --- /dev/null +++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/DynamicWebAppClusterTest.java @@ -0,0 +1,133 @@ +/* + * 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; + +import static org.testng.Assert.assertEquals; + +import org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster; +import org.apache.brooklyn.entity.webapp.DynamicWebAppCluster; +import org.apache.brooklyn.test.EntityTestUtils; +import org.apache.brooklyn.test.entity.TestJavaWebAppEntity; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import brooklyn.entity.Entity; +import brooklyn.entity.basic.Attributes; +import brooklyn.entity.basic.Entities; +import brooklyn.entity.basic.EntityLocal; +import brooklyn.entity.proxying.EntitySpec; +import brooklyn.entity.trait.Startable; +import brooklyn.location.basic.SimulatedLocation; +import brooklyn.test.entity.TestApplication; +import brooklyn.util.collections.MutableMap; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; + +public class DynamicWebAppClusterTest { + + private static final int SHORT_WAIT_MS = 250; + + private TestApplication app; + private SimulatedLocation loc; + + @BeforeMethod(alwaysRun=true) + public void setUp() throws Exception { + app = TestApplication.Factory.newManagedInstanceForTests(); + loc = app.newSimulatedLocation(); + } + + @AfterMethod(alwaysRun=true) + public void tearDown() throws Exception { + if (app != null) Entities.destroyAll(app.getManagementContext()); + } + + @Test + public void testTestJavaWebAppEntityStarts() throws Exception { + Entity test = app.createAndManageChild(EntitySpec.create(TestJavaWebAppEntity.class)); + test.invoke(Startable.START, ImmutableMap.of("locations", ImmutableList.of(loc))).get(); + + EntityTestUtils.assertAttributeEqualsEventually(test, Attributes.SERVICE_UP, true); + } + + @Test + public void testRequestCountAggregation() throws Exception { + final DynamicWebAppCluster cluster = app.createAndManageChild(EntitySpec.create(DynamicWebAppCluster.class) + .configure("initialSize", 2) + .configure(ControlledDynamicWebAppCluster.MEMBER_SPEC, EntitySpec.create(TestJavaWebAppEntity.class)) ); + + app.start(ImmutableList.of(loc)); + + for (Entity member : cluster.getMembers()) { + ((TestJavaWebAppEntity)member).spoofRequest(); + } + EntityTestUtils.assertAttributeEqualsEventually(cluster, DynamicWebAppCluster.REQUEST_COUNT, 2); + + for (Entity member : cluster.getMembers()) { + for (int i = 0; i < 2; i++) { + ((TestJavaWebAppEntity)member).spoofRequest(); + } + } + EntityTestUtils.assertAttributeEqualsEventually(cluster, DynamicWebAppCluster.REQUEST_COUNT_PER_NODE, 3d); + } + + @Test + public void testSetsServiceUpIfMemberIsUp() throws Exception { + DynamicWebAppCluster cluster = app.createAndManageChild(EntitySpec.create(DynamicWebAppCluster.class) + .configure("initialSize", 1) + .configure(ControlledDynamicWebAppCluster.MEMBER_SPEC, EntitySpec.create(TestJavaWebAppEntity.class)) ); + + app.start(ImmutableList.of(loc)); + + // Should initially be true (now that TestJavaWebAppEntity sets true) + EntityTestUtils.assertAttributeEqualsEventually(cluster, DynamicWebAppCluster.SERVICE_UP, true); + + // When child is !service_up, should report false + ((EntityLocal)Iterables.get(cluster.getMembers(), 0)).setAttribute(Startable.SERVICE_UP, false); + EntityTestUtils.assertAttributeEqualsEventually(cluster, DynamicWebAppCluster.SERVICE_UP, false); + EntityTestUtils.assertAttributeEqualsContinually(MutableMap.of("timeout", SHORT_WAIT_MS), cluster, DynamicWebAppCluster.SERVICE_UP, false); + + cluster.resize(2); + + // When one of the two children is service_up, should report true + EntityTestUtils.assertAttributeEqualsEventually(cluster, DynamicWebAppCluster.SERVICE_UP, true); + + // And if that serviceUp child goes away, should again report false + Entities.unmanage(Iterables.get(cluster.getMembers(), 1)); + ((EntityLocal)Iterables.get(cluster.getMembers(), 0)).setAttribute(Startable.SERVICE_UP, false); + + EntityTestUtils.assertAttributeEqualsEventually(cluster, DynamicWebAppCluster.SERVICE_UP, false); + } + + @Test + public void testPropertiesToChildren() throws Exception { + DynamicWebAppCluster cluster = app.createAndManageChild(EntitySpec.create(DynamicWebAppCluster.class) + .configure(ControlledDynamicWebAppCluster.MEMBER_SPEC, EntitySpec.create(TestJavaWebAppEntity.class) + .configure("a", 1)) + .configure(DynamicWebAppCluster.CUSTOM_CHILD_FLAGS, ImmutableMap.of("b", 2))); + + app.start(ImmutableList.of(loc)); + + TestJavaWebAppEntity we = (TestJavaWebAppEntity) Iterables.getOnlyElement(cluster.getMembers()); + assertEquals(we.getA(), 1); + assertEquals(we.getB(), 2); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/DynamicWebAppFabricTest.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/DynamicWebAppFabricTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/DynamicWebAppFabricTest.java new file mode 100644 index 0000000..63954e8 --- /dev/null +++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/DynamicWebAppFabricTest.java @@ -0,0 +1,127 @@ +/* + * 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; + +import java.util.List; + +import org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster; +import org.apache.brooklyn.entity.webapp.DynamicWebAppCluster; +import org.apache.brooklyn.entity.webapp.DynamicWebAppFabric; +import org.apache.brooklyn.test.EntityTestUtils; +import org.apache.brooklyn.test.entity.TestJavaWebAppEntity; +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.DynamicGroup; +import brooklyn.entity.basic.Entities; +import brooklyn.entity.basic.EntityInternal; +import brooklyn.entity.basic.EntityLocal; +import brooklyn.entity.proxying.EntitySpec; +import brooklyn.entity.trait.Changeable; +import brooklyn.location.basic.SimulatedLocation; +import brooklyn.test.entity.TestApplication; +import brooklyn.util.collections.MutableMap; + +import com.google.common.collect.ImmutableList; + +/** + * TODO clarify test purpose + */ +public class DynamicWebAppFabricTest { + private static final Logger log = LoggerFactory.getLogger(DynamicWebAppFabricTest.class); + + private static final long TIMEOUT_MS = 10*1000; + + private TestApplication app; + private SimulatedLocation loc1; + private SimulatedLocation loc2; + private List<SimulatedLocation> locs; + + @BeforeMethod(alwaysRun=true) + public void setUp() throws Exception { + app = TestApplication.Factory.newManagedInstanceForTests(); + loc1 = app.newSimulatedLocation(); + loc2 = app.newSimulatedLocation(); + locs = ImmutableList.of(loc1, loc2); + } + + @AfterMethod(alwaysRun=true) + public void tearDown() throws Exception { + if (app != null) Entities.destroyAll(app.getManagementContext()); + } + + @Test + public void testRequestCountAggregation() { + DynamicWebAppFabric fabric = app.createAndManageChild(EntitySpec.create(DynamicWebAppFabric.class) + .configure(DynamicWebAppFabric.MEMBER_SPEC, EntitySpec.create(TestJavaWebAppEntity.class)) ); + + app.start(locs); + for (Entity member : fabric.getChildren()) { + ((EntityLocal)member).setAttribute(Changeable.GROUP_SIZE, 1); + } + + for (Entity member : fabric.getChildren()) { + ((EntityInternal)member).setAttribute(DynamicGroup.GROUP_SIZE, 1); + ((TestJavaWebAppEntity)member).spoofRequest(); + } + EntityTestUtils.assertAttributeEqualsEventually(MutableMap.of("timeout", TIMEOUT_MS), fabric, DynamicWebAppFabric.REQUEST_COUNT, 2); + + // Note this is time-sensitive: need to do the next two sends before the previous one has dropped out + // of the time-window. + for (Entity member : fabric.getChildren()) { + for (int i = 0; i < 2; i++) { + ((TestJavaWebAppEntity)member).spoofRequest(); + } + } + EntityTestUtils.assertAttributeEqualsEventually(MutableMap.of("timeout", TIMEOUT_MS), fabric, DynamicWebAppFabric.REQUEST_COUNT_PER_NODE, 3d); + } + + @Test + public void testRequestCountAggregationOverClusters() { + DynamicWebAppFabric fabric = app.createAndManageChild(EntitySpec.create(DynamicWebAppFabric.class) + .configure(DynamicWebAppFabric.MEMBER_SPEC, + EntitySpec.create(DynamicWebAppCluster.class) + .configure("initialSize", 2) + .configure(ControlledDynamicWebAppCluster.MEMBER_SPEC, EntitySpec.create(TestJavaWebAppEntity.class)) )); + + app.start(locs); + + for (Entity cluster : fabric.getChildren()) { + for (Entity node : ((DynamicWebAppCluster)cluster).getMembers()) { + ((TestJavaWebAppEntity)node).spoofRequest(); + } + } + EntityTestUtils.assertAttributeEqualsEventually(MutableMap.of("timeout", TIMEOUT_MS), fabric, DynamicWebAppFabric.REQUEST_COUNT, 4); + + // Note this is time-sensitive: need to do the next two sends before the previous one has dropped out + // of the time-window. + for (Entity cluster : fabric.getChildren()) { + for (Entity node : ((DynamicWebAppCluster)cluster).getMembers()) { + for (int i = 0; i < 2; i++) { + ((TestJavaWebAppEntity)node).spoofRequest(); + } + } + } + EntityTestUtils.assertAttributeEqualsEventually(MutableMap.of("timeout", TIMEOUT_MS), fabric, DynamicWebAppFabric.REQUEST_COUNT_PER_NODE, 3d); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/ElasticCustomLocationTest.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/ElasticCustomLocationTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/ElasticCustomLocationTest.java new file mode 100644 index 0000000..7a13ac2 --- /dev/null +++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/ElasticCustomLocationTest.java @@ -0,0 +1,91 @@ +/* + * 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; + +import java.util.Map; + +import org.apache.brooklyn.entity.webapp.ElasticJavaWebAppService; +import org.apache.brooklyn.entity.webapp.ElasticJavaWebAppService.ElasticJavaWebAppServiceAwareLocation; +import org.testng.Assert; +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.BasicConfigurableEntityFactory; +import brooklyn.entity.basic.ConfigurableEntityFactory; +import brooklyn.entity.basic.Entities; +import brooklyn.location.basic.SimulatedLocation; +import brooklyn.test.entity.TestApplication; +import brooklyn.test.entity.TestEntityImpl; +import brooklyn.util.collections.MutableMap; + +import com.google.common.collect.ImmutableList; + +public class ElasticCustomLocationTest { + + public static class MockWebServiceLocation extends SimulatedLocation implements ElasticJavaWebAppServiceAwareLocation { + public MockWebServiceLocation() { + } + + @Override + public ConfigurableEntityFactory<ElasticJavaWebAppService> newWebClusterFactory() { + return new BasicConfigurableEntityFactory(MockWebService.class); + } + } + + public static class MockWebService extends TestEntityImpl implements ElasticJavaWebAppService { + public MockWebService() { + } + // TODO Used by asicConfigurableEntityFactory.newEntity2, via MockWebServiceLocation.newWebClusterFactory + public MockWebService(Map flags, Entity parent) { + super(flags, parent); + } + } + + private TestApplication app; + + @BeforeMethod(alwaysRun=true) + public void setUp() throws Exception { + app = ApplicationBuilder.newManagedApp(TestApplication.class); + } + + @AfterMethod(alwaysRun=true) + public void tearDown() throws Exception { + if (app != null) Entities.destroyAll(app.getManagementContext()); + } + + @Test + public void testElasticClusterCreatesTestEntity() { + MockWebServiceLocation l = new MockWebServiceLocation(); + app.setConfig(MockWebService.ROOT_WAR, "WAR0"); + app.setConfig(MockWebService.NAMED_WARS, ImmutableList.of("ignore://WARn")); + + ElasticJavaWebAppService svc = + new ElasticJavaWebAppService.Factory().newFactoryForLocation(l).newEntity(MutableMap.of("war", "WAR1"), app); + Entities.manage(svc); + + Assert.assertTrue(svc instanceof MockWebService, "expected MockWebService, got "+svc); + //check config has been set correctly, where overridden, and where inherited + Assert.assertEquals(svc.getConfig(MockWebService.ROOT_WAR), "WAR1"); + Assert.assertEquals(svc.getConfig(MockWebService.NAMED_WARS), ImmutableList.of("ignore://WARn")); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/ElasticJavaWebAppServiceIntegrationTest.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/ElasticJavaWebAppServiceIntegrationTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/ElasticJavaWebAppServiceIntegrationTest.java new file mode 100644 index 0000000..93859a2 --- /dev/null +++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/ElasticJavaWebAppServiceIntegrationTest.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; + +import org.apache.brooklyn.entity.webapp.ElasticJavaWebAppService; +import org.apache.brooklyn.test.HttpTestUtils; +import org.apache.brooklyn.test.TestResourceUnavailableException; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import brooklyn.entity.basic.Entities; +import brooklyn.location.basic.LocalhostMachineProvisioningLocation; +import brooklyn.test.entity.TestApplication; +import brooklyn.util.collections.MutableMap; + +import com.google.common.collect.ImmutableList; + +public class ElasticJavaWebAppServiceIntegrationTest { + + private LocalhostMachineProvisioningLocation loc; + private TestApplication app; + + @BeforeMethod(alwaysRun=true) + public void setUp() throws Exception { + app = TestApplication.Factory.newManagedInstanceForTests(); + loc = app.newLocalhostProvisioningLocation(); + } + + @AfterMethod(alwaysRun=true) + public void tearDown() throws Exception { + if (app != null) Entities.destroyAll(app.getManagementContext()); + } + + public String getTestWar() { + TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), "/hello-world.war"); + return "classpath://hello-world.war"; + } + + @SuppressWarnings("deprecation") + @Test(groups = "Integration") + // TODO a new approach to what ElasticJavaWebAppService.Factory does, giving a different entity depending on location! + public void testLegacyFactory() { + ElasticJavaWebAppService svc = + new ElasticJavaWebAppService.Factory().newEntity(MutableMap.of("war", getTestWar()), app); + Entities.manage(svc); + app.start(ImmutableList.of(loc)); + + String url = svc.getAttribute(ElasticJavaWebAppService.ROOT_URL); + Assert.assertNotNull(url); + HttpTestUtils.assertContentEventuallyContainsText(url, "Hello"); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/FilenameToWebContextMapperTest.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/FilenameToWebContextMapperTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/FilenameToWebContextMapperTest.java new file mode 100644 index 0000000..e49cf12 --- /dev/null +++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/FilenameToWebContextMapperTest.java @@ -0,0 +1,86 @@ +/* + * 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; + +import org.apache.brooklyn.entity.webapp.FilenameToWebContextMapper; +import org.testng.Assert; +import org.testng.annotations.Test; + +@Test +public class FilenameToWebContextMapperTest { + +// * either ROOT.WAR or / denotes root context +// * <p> +// * anything of form FOO.?AR (ending .?AR) is copied with that name (unless copying not necessary) +// * and is expected to be served from /FOO +// * <p> +// * anything of form /FOO (with leading slash) is expected to be served from /FOO +// * (and is copied as FOO.WAR) +// * <p> +// * anything of form FOO (without a dot) is expected to be served from /FOO +// * (and is copied as FOO.WAR) +// * <p> +// * otherwise <i>please note</i> behaviour may vary on different appservers; +// * e.g. FOO.FOO would probably be ignored on appservers which expect a file copied across (usually), +// * but served as /FOO.FOO on systems that take a deployment context. + + FilenameToWebContextMapper m = new FilenameToWebContextMapper(); + + private void assertMapping(String input, String context, String filename) { + Assert.assertEquals(m.convertDeploymentTargetNameToContext(input), context); + Assert.assertEquals(m.convertDeploymentTargetNameToFilename(input), filename); + } + + public void testRootNames() { + assertMapping("/", "/", "ROOT.war"); + assertMapping("ROOT.war", "/", "ROOT.war"); + + //bad ones -- some of these aren't invertible + assertMapping("/ROOT.war", "/ROOT.war", "ROOT.war.war"); + assertMapping("/ROOT", "/ROOT", "ROOT.war"); + + //and leave empty string alone (will cause subsequent error) + assertMapping("", "", ""); + } + + public void testOtherNames() { + assertMapping("/foo", "/foo", "foo.war"); + assertMapping("/foo.foo", "/foo.foo", "foo.foo.war"); + assertMapping("foo.war", "/foo", "foo.war"); + assertMapping("foo.Ear", "/foo", "foo.Ear"); + assertMapping("foo", "/foo", "foo.war"); + + //bad ones -- some of these aren't invertible + assertMapping("foo.foo", "/foo.foo", "foo.foo"); + } + + public void testInferFromUrl() { + Assert.assertEquals(m.findArchiveNameFromUrl("http//localhost/simple.war", false), "simple.war"); + Assert.assertEquals(m.findArchiveNameFromUrl("http//localhost/simple.Ear?type=raw", false), "simple.Ear"); + Assert.assertEquals(m.findArchiveNameFromUrl("http//localhost/simple.war?type=raw*other=sample.war", false), "simple.war"); + Assert.assertEquals(m.findArchiveNameFromUrl("http//localhost/get?file=simple.war", false), "simple.war"); + Assert.assertEquals(m.findArchiveNameFromUrl("http//localhost/get?file=simple.war&other=ignore", false), "simple.war"); + //takes the first (but logs warning in verbose mode) + Assert.assertEquals(m.findArchiveNameFromUrl("http//localhost/get?file=simple.war&other=sample.war", false), "simple.war"); + //allows hyphen + Assert.assertEquals(m.findArchiveNameFromUrl("http//localhost/get?file=simple-simon.war&other=sample", false), "simple-simon.war"); + Assert.assertEquals(m.findArchiveNameFromUrl("http//localhost/get?file=simple\\simon.war&other=sample", false), "simon.war"); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/HttpsSslConfigTest.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/HttpsSslConfigTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/HttpsSslConfigTest.java new file mode 100644 index 0000000..d21c0d9 --- /dev/null +++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/HttpsSslConfigTest.java @@ -0,0 +1,39 @@ +/* + * 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; + +import org.apache.brooklyn.entity.webapp.HttpsSslConfig; +import org.testng.Assert; +import org.testng.annotations.Test; + +import brooklyn.util.collections.MutableMap; +import brooklyn.util.flags.TypeCoercions; + +public class HttpsSslConfigTest { + + @Test + public void testCoerce() { + HttpsSslConfig config = TypeCoercions.coerce(MutableMap.of("keystoreUrl", "http://foo", "keystorePassword", "b4r", "keyAlias", "baz"), + HttpsSslConfig.class); + Assert.assertEquals(config.getKeystoreUrl(), "http://foo"); + Assert.assertEquals(config.getKeystorePassword(), "b4r"); + Assert.assertEquals(config.getKeyAlias(), "baz"); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/TomcatAutoScalerPolicyTest.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/TomcatAutoScalerPolicyTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/TomcatAutoScalerPolicyTest.java new file mode 100644 index 0000000..2158d2d --- /dev/null +++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/TomcatAutoScalerPolicyTest.java @@ -0,0 +1,125 @@ +/* + * 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; + +import static org.apache.brooklyn.test.HttpTestUtils.connectToUrl; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import org.apache.brooklyn.entity.webapp.DynamicWebAppCluster; +import org.apache.brooklyn.entity.webapp.tomcat.TomcatServer; +import org.apache.brooklyn.entity.webapp.tomcat.TomcatServerImpl; +import org.apache.brooklyn.management.ManagementContext; +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.Entities; +import brooklyn.entity.proxying.EntitySpec; +import brooklyn.location.LocationSpec; +import brooklyn.location.basic.LocalhostMachineProvisioningLocation; +import brooklyn.policy.autoscaling.AutoScalerPolicy; +import brooklyn.test.Asserts; +import brooklyn.test.entity.TestApplication; +import brooklyn.util.collections.MutableMap; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; + +public class TomcatAutoScalerPolicyTest { + + @SuppressWarnings("unused") + private static final Logger LOG = LoggerFactory.getLogger(TomcatAutoScalerPolicyTest.class); + + // TODO Test is time-sensitive: we send two web-requests in rapid succession, and expect the average workrate to + // be 2 msgs/sec; we then expect resizing to kick-in. + // P speculate that... if for some reason things are running slow (e.g. GC during that one second), then brooklyn + // may not report the 2 msgs/sec. + + private LocalhostMachineProvisioningLocation loc; + private TestApplication app; + private ManagementContext managementContext; + + @BeforeMethod(alwaysRun=true) + public void setUp() throws Exception { + app = TestApplication.Factory.newManagedInstanceForTests(); + managementContext = app.getManagementContext(); + loc = managementContext.getLocationManager().createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class) + .configure("name", "london")); + } + + @AfterMethod(alwaysRun=true) + public void tearDown() throws Exception { + if (app != null) Entities.destroyAll(app.getManagementContext()); + } + + @Test(groups="Integration") + public void testWithTomcatServers() throws Exception { + /* + * One DynamicWebAppClster with auto-scaler policy + * AutoScaler listening to DynamicWebAppCluster.TOTAL_REQS + * AutoScaler minSize 1 + * AutoScaler upper metric 1 + * AutoScaler lower metric 0 + * .. send one request + * wait til auto-scaling complete + * assert cluster size 2 + */ + + final DynamicWebAppCluster cluster = app.createAndManageChild(EntitySpec.create(DynamicWebAppCluster.class) + .configure(DynamicWebAppCluster.INITIAL_SIZE, 1) + .configure(DynamicWebAppCluster.MEMBER_SPEC, EntitySpec.create(TomcatServer.class))); + + final AutoScalerPolicy policy = AutoScalerPolicy.builder() + .metric(DynamicWebAppCluster.REQUEST_COUNT_PER_NODE) + .metricRange(0, 1) + .minPoolSize(1) + .build(); + cluster.addPolicy(policy); + + app.start(ImmutableList.of(loc)); + + assertEquals(cluster.getCurrentSize(), (Integer)1); + + // Scaling based on *total requests* processed, rather than the requests per second. + // So just hit it with 2 requests. + // Alternatively could hit each tomcat server's URL twice per second; but that's less deterministic. + TomcatServer tc = (TomcatServer) Iterables.getOnlyElement(cluster.getMembers()); + for (int i = 0; i < 2; i++) { + connectToUrl(tc.getAttribute(TomcatServerImpl.ROOT_URL)); + } + + // We'll scale to two members as soon as the policy detects it. + // But the second member won't count in the requests-per-node until it has started up. + // Expect to see (if we polled at convenient times): + // - zero requests per node (because haven't yet retrieved over JMX the metric) + // - two requests per node, with one member + // - two requests per node, with two members (one of whom is still starting up, so doesn't count) + // - one request per node (i.e. two divided across the two active members) + Asserts.succeedsEventually(MutableMap.of("timeout", 5*60*1000), new Runnable() { + @Override public void run() { + String err = "policy="+policy.isRunning()+"; size="+cluster.getCurrentSize()+"; reqCountPerNode="+cluster.getAttribute(DynamicWebAppCluster.REQUEST_COUNT_PER_NODE); + assertTrue(policy.isRunning(), "err="+err); + assertEquals(cluster.getCurrentSize(), (Integer)2, "err="+err); + assertEquals(cluster.getAttribute(DynamicWebAppCluster.REQUEST_COUNT_PER_NODE), 1.0d, "err="+err); + }}); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppConcurrentDeployTest.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppConcurrentDeployTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppConcurrentDeployTest.java new file mode 100644 index 0000000..5b64cb6 --- /dev/null +++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppConcurrentDeployTest.java @@ -0,0 +1,106 @@ +/* + * 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; + +import static org.testng.Assert.assertEquals; + +import java.net.URI; +import java.util.Collection; + +import org.apache.http.client.HttpClient; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import brooklyn.entity.BrooklynAppUnitTestSupport; +import brooklyn.entity.basic.Attributes; +import brooklyn.entity.basic.BrooklynConfigKeys; +import brooklyn.entity.proxying.EntitySpec; +import brooklyn.location.Location; +import brooklyn.location.LocationSpec; +import brooklyn.location.basic.LocalhostMachineProvisioningLocation; +import brooklyn.test.Asserts; + +import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcess; +import org.apache.brooklyn.entity.webapp.jboss.JBoss7Server; +import org.apache.brooklyn.entity.webapp.tomcat.TomcatServer; +import org.apache.brooklyn.management.Task; +import org.apache.brooklyn.test.EntityTestUtils; +import org.apache.brooklyn.test.TestResourceUnavailableException; + +import brooklyn.util.collections.MutableList; +import brooklyn.util.collections.MutableMap; +import brooklyn.util.http.HttpTool; +import brooklyn.util.http.HttpToolResponse; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +public class WebAppConcurrentDeployTest extends BrooklynAppUnitTestSupport { + private Location loc; + + @Override + @BeforeMethod(alwaysRun=true) + public void setUp() throws Exception { + super.setUp(); + app.config().set(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, false); +// tested on loc = mgmt.getLocationRegistry().resolve("byon:(hosts=\"hostname\")"); + loc = mgmt.getLocationManager().createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class)); + } + + @DataProvider(name = "basicEntities") + public Object[][] basicEntities() { + return new Object[][]{ + {EntitySpec.create(TomcatServer.class)}, + // Hot Deploy not enabled? + // {EntitySpec.create(JBoss6Server.class)}, + {EntitySpec.create(JBoss7Server.class)}, + }; + } + + @Test(groups = "Live", dataProvider="basicEntities") + public void testConcurrentDeploys(EntitySpec<? extends JavaWebAppSoftwareProcess> webServerSpec) throws Exception { + JavaWebAppSoftwareProcess server = app.createAndManageChild(webServerSpec); + app.start(ImmutableList.of(loc)); + EntityTestUtils.assertAttributeEqualsEventually(server, Attributes.SERVICE_UP, Boolean.TRUE); + Collection<Task<Void>> deploys = MutableList.of(); + for (int i = 0; i < 5; i++) { + deploys.add(server.invoke(TomcatServer.DEPLOY, MutableMap.of("url", getTestWar(), "targetName", "/"))); + } + for(Task<Void> t : deploys) { + t.getUnchecked(); + } + + final HttpClient client = HttpTool.httpClientBuilder().build(); + final URI warUrl = URI.create(server.getAttribute(JavaWebAppSoftwareProcess.ROOT_URL)); + Asserts.succeedsEventually(new Runnable() { + @Override + public void run() { + HttpToolResponse resp = HttpTool.httpGet(client, warUrl, ImmutableMap.<String,String>of()); + assertEquals(resp.getResponseCode(), 200); + } + }); + } + + public String getTestWar() { + TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), "/hello-world.war"); + return "classpath://hello-world.war"; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppLiveIntegrationTest.groovy ---------------------------------------------------------------------- diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppLiveIntegrationTest.groovy b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppLiveIntegrationTest.groovy new file mode 100644 index 0000000..db16cbd --- /dev/null +++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppLiveIntegrationTest.groovy @@ -0,0 +1,115 @@ +/* + * 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 + +import static brooklyn.entity.basic.ConfigKeys.* +import static org.apache.brooklyn.entity.webapp.jboss.JBoss6Server.* +import static org.apache.brooklyn.test.TestUtils.* +import static java.util.concurrent.TimeUnit.* +import static org.testng.Assert.* + +import java.util.concurrent.TimeUnit + +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import org.testng.annotations.AfterMethod +import org.testng.annotations.BeforeMethod +import org.testng.annotations.DataProvider +import org.testng.annotations.Test + +import brooklyn.config.BrooklynProperties +import brooklyn.entity.Application +import brooklyn.entity.basic.SoftwareProcess +import brooklyn.entity.basic.Entities +import brooklyn.entity.trait.Startable +import org.apache.brooklyn.entity.webapp.jboss.JBoss6Server +import org.apache.brooklyn.entity.webapp.jboss.JBoss6ServerImpl +import org.apache.brooklyn.entity.webapp.jboss.JBoss7Server +import org.apache.brooklyn.entity.webapp.jboss.JBoss7ServerImpl +import org.apache.brooklyn.entity.webapp.tomcat.TomcatServer +import org.apache.brooklyn.entity.webapp.tomcat.TomcatServerImpl +import brooklyn.location.Location +import brooklyn.location.basic.BasicLocationRegistry +import org.apache.brooklyn.test.TestUtils +import brooklyn.test.entity.TestApplicationImpl +import brooklyn.util.internal.TimeExtras + +/** + * This tests that we can run jboss entity on AWS. + */ +public class WebAppLiveIntegrationTest { + private static final Logger logger = LoggerFactory.getLogger(WebAppLiveIntegrationTest.class) + + static { TimeExtras.init() } + + public static final int DEFAULT_HTTP_PORT = 8080 + public static final int DEFAULT_JMX_PORT = 32199 + + // Port increment for JBoss 6. + public static final int PORT_INCREMENT = 400 + + // The parent application entity for these tests + Application application = new TestApplicationImpl() + + Location loc + + /** + * Provides instances of {@link TomcatServer}, {@link JBoss6Server} and {@link JBoss7Server} to the tests below. + * + * TODO combine the data provider here with the integration tests + * + * @see WebAppIntegrationTest#basicEntities() + */ + @DataProvider(name = "basicEntities") + public Object[][] basicEntities() { + TomcatServer tomcat = new TomcatServerImpl(parent:application, httpPort:DEFAULT_HTTP_PORT, jmxPort:DEFAULT_JMX_PORT) + JBoss6Server jboss6 = new JBoss6ServerImpl(parent:application, portIncrement:PORT_INCREMENT, jmxPort:DEFAULT_JMX_PORT) + JBoss7Server jboss7 = new JBoss7ServerImpl(parent:application, httpPort:DEFAULT_HTTP_PORT, jmxPort:DEFAULT_JMX_PORT) + return [ [ tomcat ], [ jboss6 ], [ jboss7 ] ] + } + + private File getResource(String path) { + return TestUtils.getResource(path, getClass().getClassLoader()); + } + + @BeforeMethod(alwaysRun = true) + public void setUp() { + Entities.manage(application) + + BrooklynProperties props = BrooklynProperties.Factory.newDefault() + props.put("brooklyn.location.jclouds.aws-ec2.imagel-id", "us-east-1/ami-2342a94a") + props.put("brooklyn.location.jclouds.aws-ec2.image-owner", "411009282317") + + loc = new BasicLocationRegistry(props).resolve("aws-ec2:us-east-1") + } + + @AfterMethod(alwaysRun = true) + public void shutdown() { + if (application != null) Entities.destroyAll(application.getManagementContext()); + } + + @Test(groups = "Live", dataProvider="basicEntities") + public void testStartsWebAppInAws(final SoftwareProcess entity) { + entity.start([ loc ]) + executeUntilSucceedsWithShutdown(entity, abortOnError:false, timeout:75*SECONDS, useGroovyTruth:true) { + assertTrue(entity.getAttribute(Startable.SERVICE_UP)) + true + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/ControlledDynamicWebAppClusterRebindIntegrationTest.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/ControlledDynamicWebAppClusterRebindIntegrationTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/ControlledDynamicWebAppClusterRebindIntegrationTest.java new file mode 100644 index 0000000..59232e6 --- /dev/null +++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/ControlledDynamicWebAppClusterRebindIntegrationTest.java @@ -0,0 +1,163 @@ +/* + * 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.apache.brooklyn.test.EntityTestUtils.assertAttributeEqualsEventually; +import static org.apache.brooklyn.test.HttpTestUtils.assertHttpStatusCodeEquals; +import static org.apache.brooklyn.test.HttpTestUtils.assertHttpStatusCodeEventuallyEquals; +import static org.testng.Assert.assertEquals; + +import java.io.File; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import org.apache.brooklyn.entity.proxy.nginx.NginxController; +import org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster; +import org.apache.brooklyn.entity.webapp.jboss.JBoss7Server; +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.Entity; +import brooklyn.entity.basic.ApplicationBuilder; +import brooklyn.entity.basic.Entities; +import brooklyn.entity.basic.SoftwareProcess; +import brooklyn.entity.proxying.EntitySpec; +import brooklyn.entity.rebind.RebindTestUtils; +import brooklyn.location.basic.LocalhostMachineProvisioningLocation; +import brooklyn.management.internal.LocalManagementContext; +import brooklyn.test.entity.TestApplication; +import brooklyn.util.internal.TimeExtras; + +import com.google.common.base.Predicates; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import com.google.common.io.Files; + +public class ControlledDynamicWebAppClusterRebindIntegrationTest { + private static final Logger LOG = LoggerFactory.getLogger(ControlledDynamicWebAppClusterRebindIntegrationTest.class); + + static { TimeExtras.init(); } + + private LocalhostMachineProvisioningLocation localhostProvisioningLocation; + private TestApplication origApp; + private TestApplication newApp; + private List<WebAppMonitor> webAppMonitors = new CopyOnWriteArrayList<WebAppMonitor>(); + private ExecutorService executor; + + private ClassLoader classLoader = getClass().getClassLoader(); + private LocalManagementContext origManagementContext; + private File mementoDir; + + @BeforeMethod(alwaysRun=true) + public void setUp() { + executor = Executors.newCachedThreadPool(); + + mementoDir = Files.createTempDir(); + LOG.info("Test persisting to "+mementoDir); + origManagementContext = RebindTestUtils.newPersistingManagementContext(mementoDir, classLoader); + + localhostProvisioningLocation = new LocalhostMachineProvisioningLocation(); + origApp = ApplicationBuilder.newManagedApp(TestApplication.class, origManagementContext); + } + + @AfterMethod(alwaysRun=true) + public void tearDown() throws Exception { + for (WebAppMonitor monitor : webAppMonitors) { + monitor.terminate(); + } + if (executor != null) executor.shutdownNow(); + if (newApp != null) Entities.destroyAll(newApp.getManagementContext()); + if (origApp != null) Entities.destroyAll(origApp.getManagementContext()); + if (mementoDir != null) RebindTestUtils.deleteMementoDir(mementoDir); + } + + public String getTestWar() { + TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), "/hello-world.war"); + return "classpath://hello-world.war"; + } + + 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()); + } + + 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 testRebindsToRunningCluster() throws Exception { + NginxController origNginx = origApp.createAndManageChild(EntitySpec.create(NginxController.class).configure("domain", "localhost")); + + origApp.createAndManageChild(EntitySpec.create(ControlledDynamicWebAppCluster.class) + .configure("memberSpec", EntitySpec.create(JBoss7Server.class).configure("war", getTestWar())) + .configure("initialSize", 1) + .configure("controller", origNginx)); + + origApp.start(ImmutableList.of(localhostProvisioningLocation)); + String rootUrl = origNginx.getAttribute(JBoss7Server.ROOT_URL); + + assertHttpStatusCodeEventuallyEquals(rootUrl, 200); + WebAppMonitor monitor = newWebAppMonitor(rootUrl); + + // Rebind + newApp = rebind(); + NginxController newNginx = (NginxController) Iterables.find(newApp.getChildren(), Predicates.instanceOf(NginxController.class)); + ControlledDynamicWebAppCluster newCluster = (ControlledDynamicWebAppCluster) Iterables.find(newApp.getChildren(), Predicates.instanceOf(ControlledDynamicWebAppCluster.class)); + + assertAttributeEqualsEventually(newNginx, SoftwareProcess.SERVICE_UP, true); + assertHttpStatusCodeEquals(rootUrl, 200); + + // Confirm the cluster is usable: we can scale-up + assertEquals(newCluster.getCurrentSize(), (Integer)1); + newCluster.resize(2); + + Iterable<Entity> newJbosses = Iterables.filter(newCluster.getCluster().getChildren(), Predicates.instanceOf(JBoss7Server.class)); + assertEquals(Iterables.size(newJbosses), 2); + + Thread.sleep(1000); + for (int i = 0; i < 10; i++) { + assertHttpStatusCodeEquals(rootUrl, 200); + } + + // Ensure while doing all of this the original jboss server remained reachable + assertEquals(monitor.getFailures(), 0); + + // Ensure cluster is usable: we can scale back to stop the original jboss server + newCluster.resize(0); + + assertHttpStatusCodeEventuallyEquals(rootUrl, 404); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/DynamicWebAppClusterRebindIntegrationTest.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/DynamicWebAppClusterRebindIntegrationTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/DynamicWebAppClusterRebindIntegrationTest.java new file mode 100644 index 0000000..30c0068 --- /dev/null +++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/DynamicWebAppClusterRebindIntegrationTest.java @@ -0,0 +1,153 @@ +/* + * 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.apache.brooklyn.test.HttpTestUtils.assertHttpStatusCodeEquals; +import static org.apache.brooklyn.test.HttpTestUtils.assertHttpStatusCodeEventuallyEquals; +import static org.apache.brooklyn.test.HttpTestUtils.assertUrlUnreachableEventually; +import static org.testng.Assert.assertEquals; + +import java.io.File; +import java.net.URL; +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.DynamicWebAppCluster; +import org.apache.brooklyn.entity.webapp.jboss.JBoss7Server; +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.Entity; +import brooklyn.entity.basic.ApplicationBuilder; +import brooklyn.entity.basic.Entities; +import brooklyn.entity.proxying.EntitySpec; +import brooklyn.entity.rebind.RebindTestUtils; +import brooklyn.location.basic.LocalhostMachineProvisioningLocation; +import brooklyn.management.internal.LocalManagementContext; +import brooklyn.test.entity.TestApplication; +import brooklyn.util.collections.MutableMap; + +import com.google.common.base.Predicates; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import com.google.common.io.Files; + +public class DynamicWebAppClusterRebindIntegrationTest { + private static final Logger LOG = LoggerFactory.getLogger(DynamicWebAppClusterRebindIntegrationTest.class); + + private LocalhostMachineProvisioningLocation localhostProvisioningLocation; + private TestApplication origApp; + private TestApplication newApp; + private List<WebAppMonitor> webAppMonitors = new CopyOnWriteArrayList<WebAppMonitor>(); + private ExecutorService executor; + + private ClassLoader classLoader = getClass().getClassLoader(); + private LocalManagementContext origManagementContext; + private File mementoDir; + + @BeforeMethod(groups = "Integration") + public void setUp() { + executor = Executors.newCachedThreadPool(); + + mementoDir = Files.createTempDir(); + origManagementContext = RebindTestUtils.newPersistingManagementContext(mementoDir, classLoader); + + localhostProvisioningLocation = new LocalhostMachineProvisioningLocation(); + origApp = ApplicationBuilder.newManagedApp(TestApplication.class, origManagementContext); + } + + @AfterMethod(groups = "Integration", alwaysRun=true) + public void tearDown() throws Exception { + for (WebAppMonitor monitor : webAppMonitors) { + monitor.terminate(); + } + if (executor != null) executor.shutdownNow(); + if (newApp != null) Entities.destroyAll(newApp.getManagementContext()); + if (origApp != null) Entities.destroyAll(origApp.getManagementContext()); + if (mementoDir != null) RebindTestUtils.deleteMementoDir(mementoDir); + } + + public String getTestWar() { + TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), "/hello-world.war"); + return "classpath://hello-world.war"; + } + + 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()); + } + + 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 testRebindsToRunningCluster() throws Exception { + DynamicWebAppCluster origCluster = origApp.createAndManageChild(EntitySpec.create(DynamicWebAppCluster.class) + .configure("memberSpec", EntitySpec.create(JBoss7Server.class).configure("war", getTestWar())) + .configure("initialSize", 1)); + + origApp.start(ImmutableList.of(localhostProvisioningLocation)); + JBoss7Server origJboss = (JBoss7Server) Iterables.find(origCluster.getChildren(), Predicates.instanceOf(JBoss7Server.class)); + String jbossUrl = origJboss.getAttribute(JBoss7Server.ROOT_URL); + + assertHttpStatusCodeEventuallyEquals(jbossUrl, 200); + WebAppMonitor monitor = newWebAppMonitor(jbossUrl); + + // Rebind + newApp = rebind(); + DynamicWebAppCluster newCluster = (DynamicWebAppCluster) Iterables.find(newApp.getChildren(), Predicates.instanceOf(DynamicWebAppCluster.class)); + + assertHttpStatusCodeEquals(jbossUrl, 200); + + // Confirm the cluster is usable: we can scale-up + assertEquals(newCluster.getCurrentSize(), (Integer)1); + newCluster.resize(2); + + Iterable<Entity> newJbosses = Iterables.filter(newCluster.getChildren(), Predicates.instanceOf(JBoss7Server.class)); + assertEquals(Iterables.size(newJbosses), 2); + for (Entity j : newJbosses) { + assertHttpStatusCodeEventuallyEquals(j.getAttribute(JBoss7Server.ROOT_URL), 200); + } + + // Ensure while doing all of this the original jboss server remained reachable + assertEquals(monitor.getFailures(), 0); + + // Ensure cluster is usable: we can scale back to stop the original jboss server + newCluster.resize(0); + + assertUrlUnreachableEventually(jbossUrl); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6ServerAwsEc2LiveTest.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6ServerAwsEc2LiveTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6ServerAwsEc2LiveTest.java new file mode 100644 index 0000000..1262765 --- /dev/null +++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/JBoss6ServerAwsEc2LiveTest.java @@ -0,0 +1,73 @@ +/* + * 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.JBoss6Server; +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 JBoss6ServerAwsEc2LiveTest extends AbstractEc2LiveTest { + + public String getTestWar() { + TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), "/hello-world-no-mapping.war"); + return "classpath://hello-world-no-mapping.war"; + } + + @Override + protected void doTest(Location loc) throws Exception { + final JBoss6Server server = app.createAndManageChild(EntitySpec.create(JBoss6Server.class) + .configure("war", getTestWar())); + + app.start(ImmutableList.of(loc)); + + String url = server.getAttribute(JBoss6Server.ROOT_URL); + + HttpTestUtils.assertHttpStatusCodeEventuallyEquals(url, 200); + HttpTestUtils.assertContentContainsText(url, "Hello"); + + Asserts.succeedsEventually(new Runnable() { + @Override public void run() { + assertNotNull(server.getAttribute(JBoss6Server.REQUEST_COUNT)); + assertNotNull(server.getAttribute(JBoss6Server.ERROR_COUNT)); + assertNotNull(server.getAttribute(JBoss6Server.TOTAL_PROCESSING_TIME)); + assertNotNull(server.getAttribute(JBoss6Server.MAX_PROCESSING_TIME)); + assertNotNull(server.getAttribute(JBoss6Server.BYTES_RECEIVED)); + assertNotNull(server.getAttribute(JBoss6Server.BYTES_SENT)); + }}); + } + + @Test(enabled=false) + public void testDummy() {} // Convince testng IDE integration that this really does have test methods +}
