From 583c41bfac1d1ff911e798d55f8a2879a0fd3235 Mon Sep 17 00:00:00 2001 From: Steve Loughran Date: Wed, 23 Dec 2009 12:02:04 +0000 Subject: [PATCH] HADOOP-6434 Make HttpServer slightly easier to manage/diagnose faults with git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@893485 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/hadoop/http/HttpServer.java | 28 +++- .../hadoop/http/TestHttpServerLifecycle.java | 145 ++++++++++++++++++ 2 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 src/test/core/org/apache/hadoop/http/TestHttpServerLifecycle.java diff --git a/src/java/org/apache/hadoop/http/HttpServer.java b/src/java/org/apache/hadoop/http/HttpServer.java index 4123923abb3..ce525910e76 100644 --- a/src/java/org/apache/hadoop/http/HttpServer.java +++ b/src/java/org/apache/hadoop/http/HttpServer.java @@ -85,6 +85,8 @@ public class HttpServer implements FilterContainer { new HashMap(); protected final List filterNames = new ArrayList(); private static final int MAX_RETRIES = 10; + static final String STATE_DESCRIPTION_ALIVE = " - alive"; + static final String STATE_DESCRIPTION_NOT_LIVE = " - not live"; /** Same as this(name, bindAddress, port, findPort, null); */ public HttpServer(String name, String bindAddress, int port, boolean findPort @@ -502,7 +504,11 @@ public void start() throws IOException { // then try the next port number. if (ex instanceof BindException) { if (!findPort) { - throw (BindException) ex; + BindException be = new BindException( + "Port in use: " + listener.getHost() + + ":" + listener.getPort()); + be.initCause(ex); + throw be; } } else { LOG.info("HttpServer.start() threw a non Bind IOException"); @@ -533,6 +539,26 @@ public void join() throws InterruptedException { webServer.join(); } + /** + * Test for the availability of the web server + * @return true if the web server is started, false otherwise + */ + public boolean isAlive() { + return webServer != null && webServer.isStarted(); + } + + /** + * Return the host and port of the HttpServer, if live + * @return the classname and any HTTP URL + */ + @Override + public String toString() { + return listener != null ? + ("HttpServer at http://" + listener.getHost() + ":" + listener.getLocalPort() + "/" + + (isAlive() ? STATE_DESCRIPTION_ALIVE : STATE_DESCRIPTION_NOT_LIVE)) + : "Inactive HttpServer"; + } + /** * A very simple servlet to serve up a text representation of the current * stack traces. It both returns the stacks to the caller and logs them. diff --git a/src/test/core/org/apache/hadoop/http/TestHttpServerLifecycle.java b/src/test/core/org/apache/hadoop/http/TestHttpServerLifecycle.java new file mode 100644 index 00000000000..861f44ed8b2 --- /dev/null +++ b/src/test/core/org/apache/hadoop/http/TestHttpServerLifecycle.java @@ -0,0 +1,145 @@ +/** + * 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.hadoop.http; + +import static org.junit.Assert.assertTrue; +import org.junit.Test; + +import java.io.File; + +public class TestHttpServerLifecycle { + + + /** + * Create but do not start the server + * @return the server instance in the member variable "server" + * @throws Exception on any failure + */ + private HttpServer createServer() throws Exception { + new File(System.getProperty("build.webapps", "build/webapps") + "/test" + ).mkdirs(); + HttpServer server = new HttpServer("test", "0.0.0.0", 0, true); + return server; + } + + /** + * Create and start the server + * @return the newly started server + * @throws Exception on any failure + */ + private HttpServer createAndStartServer() throws Exception { + HttpServer server = createServer(); + server.start(); + return server; + } + + /** + * If the server is non null, stop it + * @throws Exception on any failure + */ + private void stop(HttpServer server) throws Exception { + if (server != null) { + server.stop(); + } + } + + /** + * Check that a server is alive by probing the {@link HttpServer#isAlive()} method + * and the text of its toString() description + * @param server server + */ + private void assertAlive(HttpServer server) { + assertTrue("Server is not alive", server.isAlive()); + assertToStringContains(server, HttpServer.STATE_DESCRIPTION_ALIVE); + } + + private void assertNotLive(HttpServer server) { + assertTrue("Server should not be live", !server.isAlive()); + assertToStringContains(server, HttpServer.STATE_DESCRIPTION_NOT_LIVE); + } + + /** + * Test that the server is alive once started + * + * @throws Throwable on failure + */ + @Test public void testCreatedServerIsNotAlive() throws Throwable { + HttpServer server = createServer(); + assertNotLive(server); + } + + @Test public void testStopUnstartedServer() throws Throwable { + HttpServer server = createServer(); + stop(server); + } + + /** + * Test that the server is alive once started + * + * @throws Throwable on failure + */ + @Test public void testStartedServerIsAlive() throws Throwable { + HttpServer server = null; + try { + server = createServer(); + assertNotLive(server); + server.start(); + assertAlive(server); + } finally { + stop(server); + } + } + + /** + * Assert that the result of {@link HttpServer#toString()} contains the specific text + * @param server server to examine + * @param text text to search for + */ + private void assertToStringContains(HttpServer server, String text) { + String description = server.toString(); + assertTrue("Did not find \"" + text + "\" in \"" + description + "\"", + description.contains(text)); + } + + /** + * Test that the server is not alive once stopped + * + * @throws Throwable on failure + */ + @Test public void testStoppedServerIsNotAlive() throws Throwable { + HttpServer server = createAndStartServer(); + assertAlive(server); + stop(server); + assertNotLive(server); + } + + /** + * Test that the server is not alive once stopped + * + * @throws Throwable on failure + */ + @Test public void testStoppingTwiceServerIsAllowed() throws Throwable { + HttpServer server = createAndStartServer(); + assertAlive(server); + stop(server); + assertNotLive(server); + stop(server); + assertNotLive(server); + } + +}