001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019package org.apache.hadoop.hbase.http; 020 021import org.apache.hadoop.net.NetUtils; 022import org.apache.hadoop.security.authorize.AccessControlList; 023import org.junit.Assert; 024import org.apache.hadoop.conf.Configuration; 025import org.apache.hadoop.hbase.http.HttpServer.Builder; 026 027import java.io.File; 028import java.io.IOException; 029import java.io.InputStream; 030import java.net.ServerSocket; 031import java.net.URI; 032import java.net.URL; 033import java.net.MalformedURLException; 034 035/** 036 * This is a base class for functional tests of the {@link HttpServer}. 037 * The methods are static for other classes to import statically. 038 */ 039public class HttpServerFunctionalTest extends Assert { 040 /** JVM property for the webapp test dir : {@value} */ 041 public static final String TEST_BUILD_WEBAPPS = "test.build.webapps"; 042 /** expected location of the test.build.webapps dir: {@value} */ 043 private static final String BUILD_WEBAPPS_DIR = "src/main/resources/hbase-webapps"; 044 045 /** name of the test webapp: {@value} */ 046 private static final String TEST = "test"; 047 048 /** 049 * Create but do not start the test webapp server. The test webapp dir is 050 * prepared/checked in advance. 051 * 052 * @return the server instance 053 * 054 * @throws IOException if a problem occurs 055 * @throws AssertionError if a condition was not met 056 */ 057 public static HttpServer createTestServer() throws IOException { 058 prepareTestWebapp(); 059 return createServer(TEST); 060 } 061 062 /** 063 * Create but do not start the test webapp server. The test webapp dir is 064 * prepared/checked in advance. 065 * @param conf the server configuration to use 066 * @return the server instance 067 * 068 * @throws IOException if a problem occurs 069 * @throws AssertionError if a condition was not met 070 */ 071 public static HttpServer createTestServer(Configuration conf) 072 throws IOException { 073 prepareTestWebapp(); 074 return createServer(TEST, conf); 075 } 076 077 public static HttpServer createTestServer(Configuration conf, AccessControlList adminsAcl) 078 throws IOException { 079 prepareTestWebapp(); 080 return createServer(TEST, conf, adminsAcl); 081 } 082 083 /** 084 * Create but do not start the test webapp server. The test webapp dir is 085 * prepared/checked in advance. 086 * @param conf the server configuration to use 087 * @return the server instance 088 * 089 * @throws IOException if a problem occurs 090 * @throws AssertionError if a condition was not met 091 */ 092 public static HttpServer createTestServer(Configuration conf, 093 String[] pathSpecs) throws IOException { 094 prepareTestWebapp(); 095 return createServer(TEST, conf, pathSpecs); 096 } 097 098 public static HttpServer createTestServerWithSecurity(Configuration conf) throws IOException { 099 prepareTestWebapp(); 100 return localServerBuilder(TEST).setFindPort(true).setConf(conf).setSecurityEnabled(true) 101 // InfoServer normally sets these for us 102 .setUsernameConfKey(HttpServer.HTTP_SPNEGO_AUTHENTICATION_PRINCIPAL_KEY) 103 .setKeytabConfKey(HttpServer.HTTP_SPNEGO_AUTHENTICATION_KEYTAB_KEY) 104 .build(); 105 } 106 107 /** 108 * Prepare the test webapp by creating the directory from the test properties 109 * fail if the directory cannot be created. 110 * @throws AssertionError if a condition was not met 111 */ 112 protected static void prepareTestWebapp() { 113 String webapps = System.getProperty(TEST_BUILD_WEBAPPS, BUILD_WEBAPPS_DIR); 114 File testWebappDir = new File(webapps + 115 File.separatorChar + TEST); 116 try { 117 if (!testWebappDir.exists()) { 118 fail("Test webapp dir " + testWebappDir.getCanonicalPath() + " missing"); 119 } 120 } 121 catch (IOException e) { 122 } 123 } 124 125 /** 126 * Create an HttpServer instance on the given address for the given webapp 127 * @param host to bind 128 * @param port to bind 129 * @return the server 130 * @throws IOException if it could not be created 131 */ 132 public static HttpServer createServer(String host, int port) 133 throws IOException { 134 prepareTestWebapp(); 135 return new HttpServer.Builder().setName(TEST) 136 .addEndpoint(URI.create("http://" + host + ":" + port)) 137 .setFindPort(true).build(); 138 } 139 140 /** 141 * Create an HttpServer instance for the given webapp 142 * @param webapp the webapp to work with 143 * @return the server 144 * @throws IOException if it could not be created 145 */ 146 public static HttpServer createServer(String webapp) throws IOException { 147 return localServerBuilder(webapp).setFindPort(true).build(); 148 } 149 /** 150 * Create an HttpServer instance for the given webapp 151 * @param webapp the webapp to work with 152 * @param conf the configuration to use for the server 153 * @return the server 154 * @throws IOException if it could not be created 155 */ 156 public static HttpServer createServer(String webapp, Configuration conf) 157 throws IOException { 158 return localServerBuilder(webapp).setFindPort(true).setConf(conf).build(); 159 } 160 161 public static HttpServer createServer(String webapp, Configuration conf, AccessControlList adminsAcl) 162 throws IOException { 163 return localServerBuilder(webapp).setFindPort(true).setConf(conf).setACL(adminsAcl).build(); 164 } 165 166 private static Builder localServerBuilder(String webapp) { 167 return new HttpServer.Builder().setName(webapp).addEndpoint( 168 URI.create("http://localhost:0")); 169 } 170 171 /** 172 * Create an HttpServer instance for the given webapp 173 * @param webapp the webapp to work with 174 * @param conf the configuration to use for the server 175 * @param pathSpecs the paths specifications the server will service 176 * @return the server 177 * @throws IOException if it could not be created 178 */ 179 public static HttpServer createServer(String webapp, Configuration conf, 180 String[] pathSpecs) throws IOException { 181 return localServerBuilder(webapp).setFindPort(true).setConf(conf).setPathSpec(pathSpecs).build(); 182 } 183 184 /** 185 * Create and start a server with the test webapp 186 * 187 * @return the newly started server 188 * 189 * @throws IOException on any failure 190 * @throws AssertionError if a condition was not met 191 */ 192 public static HttpServer createAndStartTestServer() throws IOException { 193 HttpServer server = createTestServer(); 194 server.start(); 195 return server; 196 } 197 198 /** 199 * If the server is non null, stop it 200 * @param server to stop 201 * @throws Exception on any failure 202 */ 203 public static void stop(HttpServer server) throws Exception { 204 if (server != null) { 205 server.stop(); 206 } 207 } 208 209 /** 210 * Pass in a server, return a URL bound to localhost and its port 211 * @param server server 212 * @return a URL bonded to the base of the server 213 * @throws MalformedURLException if the URL cannot be created. 214 */ 215 public static URL getServerURL(HttpServer server) 216 throws MalformedURLException { 217 assertNotNull("No server", server); 218 return new URL("http://" 219 + NetUtils.getHostPortString(server.getConnectorAddress(0))); 220 } 221 222 /** 223 * Read in the content from a URL 224 * @param url URL To read 225 * @return the text from the output 226 * @throws IOException if something went wrong 227 */ 228 protected static String readOutput(URL url) throws IOException { 229 StringBuilder out = new StringBuilder(); 230 InputStream in = url.openConnection().getInputStream(); 231 byte[] buffer = new byte[64 * 1024]; 232 int len = in.read(buffer); 233 while (len > 0) { 234 out.append(new String(buffer, 0, len)); 235 len = in.read(buffer); 236 } 237 return out.toString(); 238 } 239 240 /** 241 * Recursively deletes a {@link File}. 242 */ 243 protected static void deleteRecursively(File d) { 244 if (d.isDirectory()) { 245 for (String name : d.list()) { 246 File child = new File(d, name); 247 if (child.isFile()) { 248 child.delete(); 249 } else { 250 deleteRecursively(child); 251 } 252 } 253 } 254 d.delete(); 255 } 256 257 /** 258 * Picks a free port on the host by binding a Socket to '0'. 259 */ 260 protected static int getFreePort() throws IOException { 261 ServerSocket s = new ServerSocket(0); 262 try { 263 s.setReuseAddress(true); 264 int port = s.getLocalPort(); 265 return port; 266 } finally { 267 if (null != s) { 268 s.close(); 269 } 270 } 271 } 272}