View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18   
19  package org.apache.hadoop.hbase.http;
20  
21  import org.apache.hadoop.net.NetUtils;
22  import org.apache.hadoop.security.authorize.AccessControlList;
23  import org.junit.Assert;
24  import org.apache.hadoop.conf.Configuration;
25  import org.apache.hadoop.hbase.http.HttpServer.Builder;
26  
27  import java.io.File;
28  import java.io.IOException;
29  import java.io.InputStream;
30  import java.net.ServerSocket;
31  import java.net.URI;
32  import java.net.URL;
33  import java.net.MalformedURLException;
34  
35  /**
36   * This is a base class for functional tests of the {@link HttpServer}.
37   * The methods are static for other classes to import statically.
38   */
39  public class HttpServerFunctionalTest extends Assert {
40    /** JVM property for the webapp test dir : {@value} */
41    public static final String TEST_BUILD_WEBAPPS = "test.build.webapps";
42    /** expected location of the test.build.webapps dir: {@value} */
43    private static final String BUILD_WEBAPPS_DIR = "build/test/webapps";
44    
45    /** name of the test webapp: {@value} */
46    private static final String TEST = "test";
47  
48    /**
49     * Create but do not start the test webapp server. The test webapp dir is
50     * prepared/checked in advance.
51     *
52     * @return the server instance
53     *
54     * @throws IOException if a problem occurs
55     * @throws AssertionError if a condition was not met
56     */
57    public static HttpServer createTestServer() throws IOException {
58      prepareTestWebapp();
59      return createServer(TEST);
60    }
61  
62    /**
63     * Create but do not start the test webapp server. The test webapp dir is
64     * prepared/checked in advance.
65     * @param conf the server configuration to use
66     * @return the server instance
67     *
68     * @throws IOException if a problem occurs
69     * @throws AssertionError if a condition was not met
70     */
71    public static HttpServer createTestServer(Configuration conf)
72        throws IOException {
73      prepareTestWebapp();
74      return createServer(TEST, conf);
75    }
76  
77    public static HttpServer createTestServer(Configuration conf, AccessControlList adminsAcl)
78        throws IOException {
79      prepareTestWebapp();
80      return createServer(TEST, conf, adminsAcl);
81    }
82  
83    /**
84     * Create but do not start the test webapp server. The test webapp dir is
85     * prepared/checked in advance.
86     * @param conf the server configuration to use
87     * @return the server instance
88     *
89     * @throws IOException if a problem occurs
90     * @throws AssertionError if a condition was not met
91     */
92    public static HttpServer createTestServer(Configuration conf, 
93        String[] pathSpecs) throws IOException {
94      prepareTestWebapp();
95      return createServer(TEST, conf, pathSpecs);
96    }
97  
98    public static HttpServer createTestServerWithSecurity(Configuration conf) throws IOException {
99      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(d);
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 }