PageRenderTime 42ms CodeModel.GetById 21ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 0ms

/http-server/src/test/java/io/airlift/http/server/TestHttpServerModule.java

https://gitlab.com/vectorci/airlift
Java | 379 lines | 313 code | 47 blank | 19 comment | 3 complexity | 803180c58aa809426ab471c0d8fce7c2 MD5 | raw file
  1/*
  2 * Copyright 2010 Proofpoint, Inc.
  3 *
  4 * Licensed under the Apache License, Version 2.0 (the "License");
  5 * you may not use this file except in compliance with the License.
  6 * You may obtain a copy of the License at
  7 *
  8 *     http://www.apache.org/licenses/LICENSE-2.0
  9 *
 10 * Unless required by applicable law or agreed to in writing, software
 11 * distributed under the License is distributed on an "AS IS" BASIS,
 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13 * See the License for the specific language governing permissions and
 14 * limitations under the License.
 15 */
 16package io.airlift.http.server;
 17
 18import com.google.common.base.Charsets;
 19import com.google.common.base.Joiner;
 20import com.google.common.collect.ArrayListMultimap;
 21import com.google.common.collect.ImmutableMap;
 22import com.google.common.collect.ListMultimap;
 23import com.google.common.io.ByteStreams;
 24import com.google.common.io.Files;
 25import com.google.common.net.HttpHeaders;
 26import com.google.common.net.MediaType;
 27import com.google.inject.Binder;
 28import com.google.inject.Guice;
 29import com.google.inject.Injector;
 30import com.google.inject.Key;
 31import com.google.inject.Module;
 32import com.google.inject.Scopes;
 33import com.google.inject.multibindings.Multibinder;
 34import io.airlift.configuration.ConfigurationFactory;
 35import io.airlift.configuration.ConfigurationModule;
 36import io.airlift.event.client.EventModule;
 37import io.airlift.event.client.InMemoryEventClient;
 38import io.airlift.event.client.InMemoryEventModule;
 39import io.airlift.http.client.HttpClient;
 40import io.airlift.http.client.HttpStatus;
 41import io.airlift.http.client.HttpUriBuilder;
 42import io.airlift.http.client.StatusResponseHandler.StatusResponse;
 43import io.airlift.http.client.StringResponseHandler.StringResponse;
 44import io.airlift.http.client.jetty.JettyHttpClient;
 45import io.airlift.log.Logging;
 46import io.airlift.node.NodeInfo;
 47import io.airlift.node.NodeModule;
 48import io.airlift.testing.FileUtils;
 49import io.airlift.tracetoken.TraceTokenModule;
 50import org.testng.Assert;
 51import org.testng.annotations.AfterMethod;
 52import org.testng.annotations.BeforeMethod;
 53import org.testng.annotations.BeforeSuite;
 54import org.testng.annotations.Test;
 55
 56import javax.servlet.Filter;
 57import javax.servlet.Servlet;
 58import javax.servlet.ServletException;
 59import javax.servlet.http.HttpServlet;
 60import javax.servlet.http.HttpServletRequest;
 61import javax.servlet.http.HttpServletResponse;
 62
 63import java.io.File;
 64import java.io.IOException;
 65import java.net.URI;
 66import java.util.List;
 67import java.util.Map;
 68import java.util.Map.Entry;
 69
 70import static com.google.common.net.HttpHeaders.CONTENT_TYPE;
 71import static com.google.common.net.HttpHeaders.REFERER;
 72import static com.google.common.net.HttpHeaders.USER_AGENT;
 73import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
 74import static io.airlift.http.client.HttpUriBuilder.uriBuilderFrom;
 75import static io.airlift.http.client.Request.Builder.prepareGet;
 76import static io.airlift.http.client.Request.Builder.preparePost;
 77import static io.airlift.http.client.StaticBodyGenerator.createStaticBodyGenerator;
 78import static io.airlift.http.client.StatusResponseHandler.createStatusResponseHandler;
 79import static io.airlift.http.client.StringResponseHandler.createStringResponseHandler;
 80import static io.airlift.http.server.HttpServerBinder.httpServerBinder;
 81import static java.util.Collections.nCopies;
 82import static org.testng.Assert.assertEquals;
 83import static org.testng.Assert.assertNotNull;
 84import static org.testng.Assert.assertNull;
 85import static org.testng.Assert.assertTrue;
 86
 87public class TestHttpServerModule
 88{
 89    private File tempDir;
 90
 91    @BeforeSuite
 92    public void setupSuite()
 93    {
 94        Logging.initialize();
 95    }
 96
 97    @BeforeMethod
 98    public void setup()
 99            throws IOException
100    {
101        tempDir = Files.createTempDir().getCanonicalFile(); // getCanonicalFile needed to get around Issue 365 (http://code.google.com/p/guava-libraries/issues/detail?id=365)
102    }
103
104    @AfterMethod
105    public void tearDown()
106            throws IOException
107    {
108        FileUtils.deleteRecursively(tempDir);
109    }
110
111    @Test
112    public void testCanConstructServer()
113            throws Exception
114    {
115        Map<String, String> properties = new ImmutableMap.Builder<String, String>()
116                .put("node.environment", "test")
117                .put("http-server.http.port", "0")
118                .put("http-server.log.path", new File(tempDir, "http-request.log").getAbsolutePath())
119                .build();
120
121        ConfigurationFactory configFactory = new ConfigurationFactory(properties);
122        Injector injector = Guice.createInjector(new HttpServerModule(),
123                new NodeModule(),
124                new ConfigurationModule(configFactory),
125                new EventModule(),
126                new Module()
127                {
128                    @Override
129                    public void configure(Binder binder)
130                    {
131                        binder.bind(Servlet.class).annotatedWith(TheServlet.class).to(DummyServlet.class);
132                    }
133                });
134
135        HttpServer server = injector.getInstance(HttpServer.class);
136        assertNotNull(server);
137    }
138
139    @Test
140    public void testHttpServerUri()
141            throws Exception
142    {
143        Map<String, String> properties = new ImmutableMap.Builder<String, String>()
144                .put("node.environment", "test")
145                .put("http-server.http.port", "0")
146                .put("http-server.log.path", new File(tempDir, "http-request.log").getAbsolutePath())
147                .build();
148
149        ConfigurationFactory configFactory = new ConfigurationFactory(properties);
150        Injector injector = Guice.createInjector(new HttpServerModule(),
151                new NodeModule(),
152                new ConfigurationModule(configFactory),
153                new EventModule(),
154                new Module()
155                {
156                    @Override
157                    public void configure(Binder binder)
158                    {
159                        binder.bind(Servlet.class).annotatedWith(TheServlet.class).to(DummyServlet.class);
160                    }
161                });
162
163        NodeInfo nodeInfo = injector.getInstance(NodeInfo.class);
164        HttpServer server = injector.getInstance(HttpServer.class);
165        assertNotNull(server);
166        server.start();
167        try {
168            HttpServerInfo httpServerInfo = injector.getInstance(HttpServerInfo.class);
169            assertNotNull(httpServerInfo);
170            assertNotNull(httpServerInfo.getHttpUri());
171            assertEquals(httpServerInfo.getHttpUri().getScheme(), "http");
172            assertEquals(httpServerInfo.getHttpUri().getHost(), nodeInfo.getInternalIp().getHostAddress());
173            assertNull(httpServerInfo.getHttpsUri());
174        }
175        catch (Exception e) {
176            server.stop();
177        }
178    }
179
180    @Test
181    public void testServer()
182            throws Exception
183    {
184        Map<String, String> properties = new ImmutableMap.Builder<String, String>()
185                .put("node.environment", "test")
186                .put("http-server.http.port", "0")
187                .put("http-server.log.path", new File(tempDir, "http-request.log").getAbsolutePath())
188                .build();
189
190        ConfigurationFactory configFactory = new ConfigurationFactory(properties);
191        Injector injector = Guice.createInjector(new HttpServerModule(),
192                new NodeModule(),
193                new ConfigurationModule(configFactory),
194                new EventModule(),
195                new Module()
196                {
197                    @Override
198                    public void configure(Binder binder)
199                    {
200                        binder.bind(Servlet.class).annotatedWith(TheServlet.class).to(DummyServlet.class);
201                        Multibinder.newSetBinder(binder, Filter.class, TheServlet.class).addBinding().to(DummyFilter.class).in(Scopes.SINGLETON);
202                        httpServerBinder(binder).bindResource("/", "webapp/user").withWelcomeFile("user-welcome.txt");
203                        httpServerBinder(binder).bindResource("/", "webapp/user2");
204                        httpServerBinder(binder).bindResource("path", "webapp/user").withWelcomeFile("user-welcome.txt");
205                        httpServerBinder(binder).bindResource("path", "webapp/user2");
206                    }
207                });
208
209        HttpServerInfo httpServerInfo = injector.getInstance(HttpServerInfo.class);
210
211        HttpServer server = injector.getInstance(HttpServer.class);
212        server.start();
213
214        try (HttpClient client = new JettyHttpClient()) {
215
216            // test servlet bound correctly
217            URI httpUri = httpServerInfo.getHttpUri();
218            StatusResponse response = client.execute(prepareGet().setUri(httpUri).build(), createStatusResponseHandler());
219
220            assertEquals(response.getStatusCode(), HttpServletResponse.SC_OK);
221
222            // test filter bound correctly
223            response = client.execute(prepareGet().setUri(httpUri.resolve("/filter")).build(), createStatusResponseHandler());
224
225            assertEquals(response.getStatusCode(), HttpServletResponse.SC_PAYMENT_REQUIRED);
226            assertEquals(response.getStatusMessage(), "filtered");
227
228            // test http resources
229            assertResource(httpUri, client, "", "welcome user!");
230            assertResource(httpUri, client, "user-welcome.txt", "welcome user!");
231            assertResource(httpUri, client, "user.txt", "user");
232            assertResource(httpUri, client, "user2.txt", "user2");
233            assertResource(httpUri, client, "path", "welcome user!");
234            assertResource(httpUri, client, "path/", "welcome user!");
235            assertResource(httpUri, client, "path/user-welcome.txt", "welcome user!");
236            assertResource(httpUri, client, "path/user.txt", "user");
237            assertResource(httpUri, client, "path/user2.txt", "user2");
238        }
239        finally {
240            server.stop();
241        }
242    }
243
244    private void assertResource(URI baseUri, HttpClient client, String path, String contents)
245    {
246        HttpUriBuilder uriBuilder = uriBuilderFrom(baseUri);
247        StringResponse data = client.execute(prepareGet().setUri(uriBuilder.appendPath(path).build()).build(), createStringResponseHandler());
248        assertEquals(data.getStatusCode(), HttpStatus.OK.code());
249        MediaType contentType = MediaType.parse(data.getHeader(HttpHeaders.CONTENT_TYPE));
250        assertTrue(PLAIN_TEXT_UTF_8.is(contentType), "Expected text/plain but got " + contentType);
251        assertEquals(data.getBody().trim(), contents);
252    }
253
254    @Test
255    public void testHttpRequestEvent()
256            throws Exception
257    {
258        Map<String, String> properties = new ImmutableMap.Builder<String, String>()
259                .put("node.environment", "test")
260                .put("http-server.http.port", "0")
261                .put("http-server.log.path", new File(tempDir, "http-request.log").getAbsolutePath())
262                .build();
263
264        ConfigurationFactory configFactory = new ConfigurationFactory(properties);
265        Injector injector = Guice.createInjector(new HttpServerModule(),
266                new NodeModule(),
267                new ConfigurationModule(configFactory),
268                new InMemoryEventModule(),
269                new TraceTokenModule(),
270                new Module()
271                {
272                    @Override
273                    public void configure(Binder binder)
274                    {
275                        binder.bind(Servlet.class).annotatedWith(TheServlet.class).to(EchoServlet.class).in(Scopes.SINGLETON);
276                    }
277                });
278
279        HttpServerInfo httpServerInfo = injector.getInstance(HttpServerInfo.class);
280        InMemoryEventClient eventClient = injector.getInstance(InMemoryEventClient.class);
281        EchoServlet echoServlet = (EchoServlet) injector.getInstance(Key.get(Servlet.class, TheServlet.class));
282
283        HttpServer server = injector.getInstance(HttpServer.class);
284        server.start();
285
286        URI requestUri = httpServerInfo.getHttpUri().resolve("/my/path");
287        String userAgent = "my-user-agent";
288        String referrer = "http://www.google.com";
289        String token = "this is a trace token";
290        String requestBody = Joiner.on(" ").join(nCopies(50, "request"));
291        String requestContentType = "request/type";
292
293        int responseCode = 555;
294        String responseBody = Joiner.on(" ").join(nCopies(100, "response"));
295        String responseContentType = "response/type";
296
297        echoServlet.responseBody = responseBody;
298        echoServlet.responseStatusCode = responseCode;
299        echoServlet.responseHeaders.put("Content-Type", responseContentType);
300
301        long beforeRequest = System.currentTimeMillis();
302        long afterRequest;
303        try (JettyHttpClient client = new JettyHttpClient()) {
304
305            // test servlet bound correctly
306            StringResponse response = client.execute(
307                    preparePost().setUri(requestUri)
308                            .addHeader(USER_AGENT, userAgent)
309                            .addHeader(CONTENT_TYPE, requestContentType)
310                            .addHeader(REFERER, referrer)
311                            .addHeader("X-Airlift-TraceToken", token)
312                            .setBodyGenerator(createStaticBodyGenerator(requestBody, Charsets.UTF_8))
313                            .build(),
314                    createStringResponseHandler());
315
316            afterRequest = System.currentTimeMillis();
317
318            assertEquals(response.getStatusCode(), responseCode);
319            assertEquals(response.getBody(), responseBody);
320            assertEquals(response.getHeader("Content-Type"), responseContentType);
321        }
322        finally {
323            server.stop();
324        }
325
326        List<Object> events = eventClient.getEvents();
327        Assert.assertEquals(events.size(), 1);
328        HttpRequestEvent event = (HttpRequestEvent) events.get(0);
329
330
331        Assert.assertEquals(event.getClientAddress(), echoServlet.remoteAddress);
332        Assert.assertEquals(event.getProtocol(), "http");
333        Assert.assertEquals(event.getMethod(), "POST");
334        Assert.assertEquals(event.getRequestUri(), requestUri.getPath());
335        Assert.assertNull(event.getUser());
336        Assert.assertEquals(event.getAgent(), userAgent);
337        Assert.assertEquals(event.getReferrer(), referrer);
338        Assert.assertEquals(event.getTraceToken(), token);
339
340        Assert.assertEquals(event.getRequestSize(), requestBody.length());
341        Assert.assertEquals(event.getRequestContentType(), requestContentType);
342
343        Assert.assertEquals(event.getResponseSize(), responseBody.length());
344        Assert.assertEquals(event.getResponseCode(), responseCode);
345        Assert.assertEquals(event.getResponseContentType(), responseContentType);
346
347        Assert.assertTrue(event.getTimeStamp().getMillis() >= beforeRequest);
348        Assert.assertTrue(event.getTimeToLastByte() <= afterRequest - beforeRequest);
349        Assert.assertNotNull(event.getTimeToFirstByte());
350        Assert.assertTrue(event.getTimeToDispatch() <= event.getTimeToFirstByte());
351        Assert.assertTrue(event.getTimeToFirstByte() <= event.getTimeToLastByte());
352    }
353
354    private static final class EchoServlet extends HttpServlet
355    {
356        private int responseStatusCode = 300;
357        private final ListMultimap<String, String> responseHeaders = ArrayListMultimap.create();
358        public String responseBody;
359        private String remoteAddress;
360
361        @Override
362        protected void service(HttpServletRequest request, HttpServletResponse response)
363                throws ServletException, IOException
364        {
365            ByteStreams.copy(request.getInputStream(), ByteStreams.nullOutputStream());
366
367            remoteAddress = request.getRemoteAddr();
368            for (Entry<String, String> entry : responseHeaders.entries()) {
369                response.addHeader(entry.getKey(), entry.getValue());
370            }
371
372            response.setStatus(responseStatusCode);
373
374            if (responseBody != null) {
375                response.getOutputStream().write(responseBody.getBytes(Charsets.UTF_8));
376            }
377        }
378    }
379}