blob: c533b8de805af9886b0dc11ae9283de15751398d [file] [log] [blame]
/*
* 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.proxy.nginx;
import static org.apache.brooklyn.test.HttpTestUtils.assertHttpStatusCodeEquals;
import static org.apache.brooklyn.test.HttpTestUtils.assertHttpStatusCodeEventuallyEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotEquals;
import static org.testng.Assert.assertTrue;
import java.util.Map;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.entity.EntitySpec;
import org.apache.brooklyn.api.location.Location;
import org.apache.brooklyn.core.entity.EntityAsserts;
import org.apache.brooklyn.core.test.BrooklynAppLiveTestSupport;
import org.apache.brooklyn.core.test.entity.TestEntity;
import org.apache.brooklyn.entity.group.DynamicCluster;
import org.apache.brooklyn.entity.software.base.SoftwareProcess;
import org.apache.brooklyn.entity.webapp.JavaWebAppService;
import org.apache.brooklyn.entity.webapp.WebAppService;
import org.apache.brooklyn.entity.webapp.jboss.JBoss7Server;
import org.apache.brooklyn.test.Asserts;
import org.apache.brooklyn.test.HttpTestUtils;
import org.apache.brooklyn.test.WebAppMonitor;
import org.apache.brooklyn.test.support.TestResourceUnavailableException;
import org.apache.brooklyn.util.time.Duration;
import org.apache.brooklyn.util.time.Time;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
/**
* Test the operation of the {@link NginxController} class.
*/
public class NginxIntegrationTest extends BrooklynAppLiveTestSupport {
private static final Logger log = LoggerFactory.getLogger(NginxIntegrationTest.class);
private NginxController nginx;
private DynamicCluster serverPool;
private Location localLoc;
@BeforeMethod(alwaysRun=true)
@Override
public void setUp() throws Exception {
super.setUp();
localLoc = mgmt.getLocationRegistry().getLocationManaged("localhost");
}
public String getTestWar() {
TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), "/hello-world.war");
return "classpath://hello-world.war";
}
/**
* Test that the Nginx proxy starts up and sets SERVICE_UP correctly.
*/
@Test(groups = "Integration")
public void testWhenNoServersReturns404() {
serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
.configure("initialSize", 0)
.configure("memberSpec", EntitySpec.create(TestEntity.class)));
nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
.configure("serverPool", serverPool)
.configure("domain", "localhost"));
app.start(ImmutableList.of(localLoc));
EntityAsserts.assertAttributeEqualsEventually(nginx, SoftwareProcess.SERVICE_UP, true);
assertHttpStatusCodeEventuallyEquals(nginx.getAttribute(NginxController.ROOT_URL), 404);
}
@Test(groups = "Integration")
public void testRestart() {
serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
.configure("initialSize", 0)
.configure("memberSpec", EntitySpec.create(TestEntity.class)));
nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
.configure("serverPool", serverPool)
.configure("domain", "localhost"));
app.start(ImmutableList.of(localLoc));
nginx.restart();
EntityAsserts.assertAttributeEqualsEventually(nginx, SoftwareProcess.SERVICE_UP, true);
assertHttpStatusCodeEventuallyEquals(nginx.getAttribute(NginxController.ROOT_URL), 404);
}
/**
* Test that the Nginx proxy starts up and sets SERVICE_UP correctly.
*/
@Test(groups = "Integration")
public void testCanStartupAndShutdown() {
serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
.configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class))
.configure("initialSize", 1)
.configure(JavaWebAppService.ROOT_WAR, getTestWar()));
nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
.configure("serverPool", serverPool)
.configure("domain", "localhost")
.configure("portNumberSensor", WebAppService.HTTP_PORT));
app.start(ImmutableList.of(localLoc));
// App-servers and nginx has started
Asserts.succeedsEventually(new Runnable() {
public void run() {
for (Entity member : serverPool.getMembers()) {
assertTrue(member.getAttribute(SoftwareProcess.SERVICE_UP));
}
assertTrue(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
}});
// URLs reachable
assertHttpStatusCodeEventuallyEquals(nginx.getAttribute(NginxController.ROOT_URL), 200);
for (Entity member : serverPool.getMembers()) {
assertHttpStatusCodeEventuallyEquals(member.getAttribute(WebAppService.ROOT_URL), 200);
}
app.stop();
// Services have stopped
assertFalse(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
assertFalse(serverPool.getAttribute(SoftwareProcess.SERVICE_UP));
for (Entity member : serverPool.getMembers()) {
assertFalse(member.getAttribute(SoftwareProcess.SERVICE_UP));
}
}
/**
* Test that the Nginx proxy starts up and sets SERVICE_UP correctly using the config file template.
*/
@Test(groups = "Integration")
public void testCanStartupAndShutdownUsingTemplate() {
serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
.configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class))
.configure("initialSize", 1)
.configure(JavaWebAppService.ROOT_WAR, getTestWar()));
nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
.configure("serverPool", serverPool)
.configure("domain", "localhost")
.configure("portNumberSensor", WebAppService.HTTP_PORT)
.configure("configTemplate", "classpath://org/apache/brooklyn/entity/proxy/nginx/server.conf"));
app.start(ImmutableList.of(localLoc));
// App-servers and nginx has started
Asserts.succeedsEventually(new Runnable() {
public void run() {
for (Entity member : serverPool.getMembers()) {
assertTrue(member.getAttribute(SoftwareProcess.SERVICE_UP));
}
assertTrue(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
}});
// URLs reachable
assertHttpStatusCodeEventuallyEquals(nginx.getAttribute(NginxController.ROOT_URL), 200);
for (Entity member : serverPool.getMembers()) {
assertHttpStatusCodeEventuallyEquals(member.getAttribute(WebAppService.ROOT_URL), 200);
}
app.stop();
// Services have stopped
assertFalse(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
assertFalse(serverPool.getAttribute(SoftwareProcess.SERVICE_UP));
for (Entity member : serverPool.getMembers()) {
assertFalse(member.getAttribute(SoftwareProcess.SERVICE_UP));
}
}
/**
* Test that the Nginx proxy works, serving all domains, if no domain is set
*/
@Test(groups = "Integration")
public void testDomainless() {
serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
.configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class))
.configure("initialSize", 1)
.configure(JavaWebAppService.ROOT_WAR, getTestWar()));
nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
.configure("serverPool", serverPool)
.configure("domain", "localhost")
.configure("portNumberSensor", WebAppService.HTTP_PORT));
app.start(ImmutableList.of(localLoc));
// App-servers and nginx has started
EntityAsserts.assertAttributeEqualsEventually(serverPool, SoftwareProcess.SERVICE_UP, true);
for (Entity member : serverPool.getMembers()) {
EntityAsserts.assertAttributeEqualsEventually(member, SoftwareProcess.SERVICE_UP, true);
}
EntityAsserts.assertAttributeEqualsEventually(nginx, SoftwareProcess.SERVICE_UP, true);
// URLs reachable
assertHttpStatusCodeEventuallyEquals(nginx.getAttribute(NginxController.ROOT_URL), 200);
for (Entity member : serverPool.getMembers()) {
assertHttpStatusCodeEventuallyEquals(member.getAttribute(WebAppService.ROOT_URL), 200);
}
app.stop();
// Services have stopped
assertFalse(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
assertFalse(serverPool.getAttribute(SoftwareProcess.SERVICE_UP));
for (Entity member : serverPool.getMembers()) {
assertFalse(member.getAttribute(SoftwareProcess.SERVICE_UP));
}
}
@Test(groups = "Integration")
public void testTwoNginxesGetDifferentPorts() {
serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
.configure("initialSize", 0)
.configure("memberSpec", EntitySpec.create(TestEntity.class)));
NginxController nginx1 = app.createAndManageChild(EntitySpec.create(NginxController.class)
.configure("serverPool", serverPool)
.configure("domain", "localhost")
.configure("port", "14000+"));
NginxController nginx2 = app.createAndManageChild(EntitySpec.create(NginxController.class)
.configure("serverPool", serverPool)
.configure("domain", "localhost")
.configure("port", "14000+"));
app.start(ImmutableList.of(localLoc));
String url1 = nginx1.getAttribute(NginxController.ROOT_URL);
String url2 = nginx2.getAttribute(NginxController.ROOT_URL);
assertTrue(url1.contains(":1400"), url1);
assertTrue(url2.contains(":1400"), url2);
assertNotEquals(url1, url2, "Two nginxs should listen on different ports, not both on "+url1);
// Nginx has started
EntityAsserts.assertAttributeEqualsEventually(nginx1, SoftwareProcess.SERVICE_UP, true);
EntityAsserts.assertAttributeEqualsEventually(nginx2, SoftwareProcess.SERVICE_UP, true);
// Nginx reachable (returning default 404)
assertHttpStatusCodeEventuallyEquals(url1, 404);
assertHttpStatusCodeEventuallyEquals(url2, 404);
}
/** Test that site access does not fail even while nginx is reloaded */
// FIXME test disabled -- reload isn't a problem, but #365 is
@Test(enabled = false, groups = "Integration")
public void testServiceContinuity() throws Exception {
serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
.configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class))
.configure("initialSize", 1)
.configure(JavaWebAppService.ROOT_WAR, getTestWar()));
nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
.configure("serverPool", serverPool));
app.start(ImmutableList.of(localLoc));
Asserts.succeedsEventually(new Runnable() {
public void run() {
for (Entity member : serverPool.getMembers()) {
assertHttpStatusCodeEquals(member.getAttribute(WebAppService.ROOT_URL), 200);
}
assertHttpStatusCodeEquals(nginx.getAttribute(WebAppService.ROOT_URL), 200);
}});
WebAppMonitor monitor = new WebAppMonitor(nginx.getAttribute(WebAppService.ROOT_URL))
.logFailures(log)
.delayMillis(0);
Thread t = new Thread(monitor);
t.start();
try {
Thread.sleep(1*1000);
log.info("service continuity test, startup, "+monitor.getAttempts()+" requests made");
monitor.assertAttemptsMade(10, "startup").assertNoFailures("startup").resetCounts();
for (int i=0; i<20; i++) {
nginx.reload();
Thread.sleep(500);
log.info("service continuity test, iteration "+i+", "+monitor.getAttempts()+" requests made");
monitor.assertAttemptsMade(10, "reloaded").assertNoFailures("reloaded").resetCounts();
}
} finally {
t.interrupt();
}
app.stop();
// Services have stopped
assertFalse(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
assertFalse(serverPool.getAttribute(SoftwareProcess.SERVICE_UP));
for (Entity member : serverPool.getMembers()) {
assertFalse(member.getAttribute(SoftwareProcess.SERVICE_UP));
}
}
// FIXME test disabled -- issue #365
/*
* This currently makes no assertions, but writes out the number of sequential reqs per sec
* supported with nginx and jboss.
* <p>
* jboss is (now) steady, at 6k+, since we close the connections in HttpTestUtils.getHttpStatusCode.
* but nginx still hits problems, after about 15k reqs, something is getting starved in nginx.
*/
@Test(enabled=false, groups = "Integration")
public void testContinuityNginxAndJboss() throws Exception {
serverPool = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
.configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class))
.configure("initialSize", 1)
.configure(JavaWebAppService.ROOT_WAR, getTestWar()));
nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
.configure("serverPool", serverPool));
app.start(ImmutableList.of(localLoc));
final String nginxUrl = nginx.getAttribute(WebAppService.ROOT_URL);
Asserts.succeedsEventually(new Runnable() {
public void run() {
for (Entity member : serverPool.getMembers()) {
String jbossUrl = member.getAttribute(WebAppService.ROOT_URL);
assertHttpStatusCodeEquals(jbossUrl, 200);
}
assertHttpStatusCodeEquals(nginxUrl, 200);
}});
final String jbossUrl = Iterables.get(serverPool.getMembers(), 0).getAttribute(WebAppService.ROOT_URL);
Thread t = new Thread(new Runnable() {
public void run() {
long lastReportTime = System.currentTimeMillis();
int num = 0;
while (true) {
try {
num++;
int code = HttpTestUtils.getHttpStatusCode(nginxUrl);
if (code!=200) log.info("NGINX GOT: "+code);
else log.debug("NGINX GOT: "+code);
if (System.currentTimeMillis()>=lastReportTime+1000) {
log.info("NGINX DID "+num+" requests in last "+(System.currentTimeMillis()-lastReportTime)+"ms");
num=0;
lastReportTime = System.currentTimeMillis();
}
} catch (Exception e) {
log.info("NGINX GOT: "+e);
}
}
}});
t.start();
Thread t2 = new Thread(new Runnable() {
public void run() {
long lastReportTime = System.currentTimeMillis();
int num = 0;
while (true) {
try {
num++;
int code = HttpTestUtils.getHttpStatusCode(jbossUrl);
if (code!=200) log.info("JBOSS GOT: "+code);
else log.debug("JBOSS GOT: "+code);
if (System.currentTimeMillis()>=1000+lastReportTime) {
log.info("JBOSS DID "+num+" requests in last "+(System.currentTimeMillis()-lastReportTime)+"ms");
num=0;
lastReportTime = System.currentTimeMillis();
}
} catch (Exception e) {
log.info("JBOSS GOT: "+e);
}
}
}});
t2.start();
t2.join();
}
/**
* Test that the Nginx proxy starts up and sets SERVICE_UP correctly.
*/
@Test(groups = "Integration")
public void testCanRestart() {
nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
.configure("serverPool", serverPool)
.configure("domain", "localhost")
.configure("portNumberSensor", WebAppService.HTTP_PORT));
app.start(ImmutableList.of(localLoc));
// App-servers and nginx has started
Asserts.succeedsEventually(new Runnable() {
public void run() {
assertTrue(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
}});
log.info("started, will restart soon");
Time.sleep(Duration.ONE_SECOND);
nginx.restart();
Time.sleep(Duration.ONE_SECOND);
Asserts.succeedsEventually(new Runnable() {
public void run() {
assertTrue(nginx.getAttribute(SoftwareProcess.SERVICE_UP));
}});
log.info("restarted and got service up");
}
// public static void main(String[] args) {
// NginxIntegrationTest t = new NginxIntegrationTest();
// t.setup();
// t.testCanRestart();
// t.shutdown();
// }
}