/*
* The MIT License (MIT)
* Copyright © 2013 Englishtown <opensource@englishtown.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the “Software”), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.englishtown.vertx.jersey.impl;
import com.englishtown.vertx.jersey.ApplicationHandlerDelegate;
import com.englishtown.vertx.jersey.JerseyOptions;
import com.englishtown.vertx.jersey.VertxContainer;
import com.englishtown.vertx.jersey.inject.ContainerResponseWriterProvider;
import com.englishtown.vertx.jersey.inject.VertxRequestProcessor;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.vertx.core.Handler;
import io.vertx.core.MultiMap;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.http.impl.HeadersAdaptor;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.core.logging.Logger;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.api.TypeLiteral;
import org.glassfish.jersey.internal.util.collection.Ref;
import org.glassfish.jersey.server.ContainerRequest;
import org.glassfish.jersey.server.spi.Container;
import org.glassfish.jersey.server.spi.ContainerResponseWriter;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*;
/**
* {@link DefaultJerseyHandler} unit tests
*/
@RunWith(MockitoJUnitRunner.class)
public class DefaultJerseyHandlerTest {
DefaultJerseyHandler jerseyHandler;
JsonObject config = new JsonObject();
List<VertxRequestProcessor> requestProcessors = new ArrayList<>();
@Mock
VertxContainer container;
@Mock
JerseyOptions options;
@Mock
ApplicationHandlerDelegate applicationHandlerDelegate;
@Mock
HttpServerRequest request;
@Mock
HttpServerResponse response;
@Mock
ServiceLocator serviceLocator;
@Mock
Vertx vertx;
@Mock
Logger logger;
@Mock
Ref<Vertx> vertxRef;
@Mock
Ref<Container> containerRef;
@Mock
MultiMap headers;
@Captor
ArgumentCaptor<Handler<Buffer>> dataHandlerCaptor;
@Captor
ArgumentCaptor<Handler<Void>> endHandlerCaptor;
@Before
public void setUp() {
when(container.getOptions()).thenReturn(options);
when(container.getVertx()).thenReturn(vertx);
when(container.getApplicationHandlerDelegate()).thenReturn(applicationHandlerDelegate);
when(applicationHandlerDelegate.getServiceLocator()).thenReturn(serviceLocator);
when(options.getMaxBodySize()).thenReturn(1024);
when(options.getBaseUri()).thenReturn(URI.create("/test"));
when(request.absoluteURI()).thenReturn(URI.create("http://test.englishtown.com/test").toString());
when(request.response()).thenReturn(response);
when(request.headers()).thenReturn(headers);
JsonArray resources = new JsonArray().add("com.englishtown.vertx.jersey.resources");
config.put(DefaultJerseyOptions.CONFIG_RESOURCES, resources);
ContainerResponseWriterProvider provider = mock(ContainerResponseWriterProvider.class);
when(provider.get(any(HttpServerRequest.class), any(ContainerRequest.class))).thenReturn(mock(ContainerResponseWriter.class));
when(serviceLocator.<Ref<Vertx>>getService((new TypeLiteral<Ref<Vertx>>() {
}).getType())).thenReturn(vertxRef);
when(serviceLocator.<Ref<Container>>getService((new TypeLiteral<Ref<Container>>() {
}).getType())).thenReturn(containerRef);
jerseyHandler = new DefaultJerseyHandler(() -> container, provider, requestProcessors);
}
@Test
public void testHandle() throws Exception {
when(request.method()).thenReturn(HttpMethod.GET);
when(request.headers()).thenReturn(mock(MultiMap.class));
jerseyHandler.handle(request);
verify(applicationHandlerDelegate).handle(any(ContainerRequest.class));
}
@Test
public void testHandle_JSON_POST() throws Exception {
DefaultHttpHeaders headers = new DefaultHttpHeaders();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
when(request.method()).thenReturn(HttpMethod.POST);
when(request.headers()).thenReturn(new HeadersAdaptor(headers));
jerseyHandler.handle(request);
verify(request).handler(dataHandlerCaptor.capture());
verify(request).endHandler(endHandlerCaptor.capture());
Buffer data = Buffer.buffer("{}");
dataHandlerCaptor.getValue().handle(data);
endHandlerCaptor.getValue().handle(null);
verify(applicationHandlerDelegate).handle(any(ContainerRequest.class));
}
@Test
public void testHandle_RequestProcessors() throws Exception {
when(request.headers()).thenReturn(mock(MultiMap.class));
when(request.method()).thenReturn(HttpMethod.GET);
InputStream inputStream = null;
VertxRequestProcessor rp1 = mock(VertxRequestProcessor.class);
VertxRequestProcessor rp2 = mock(VertxRequestProcessor.class);
requestProcessors.add(rp1);
requestProcessors.add(rp2);
jerseyHandler.handle(request, inputStream);
verify(rp1).process(any(HttpServerRequest.class), any(ContainerRequest.class), endHandlerCaptor.capture());
endHandlerCaptor.getValue().handle(null);
verify(rp2).process(any(HttpServerRequest.class), any(ContainerRequest.class), endHandlerCaptor.capture());
endHandlerCaptor.getValue().handle(null);
verify(applicationHandlerDelegate).handle(any(ContainerRequest.class));
}
@Test
public void testHandle_RequestProcessors_Throw() throws Exception {
when(request.headers()).thenReturn(mock(MultiMap.class));
when(request.method()).thenReturn(HttpMethod.GET);
InputStream inputStream = null;
VertxRequestProcessor rp1 = mock(VertxRequestProcessor.class);
VertxRequestProcessor rp2 = mock(VertxRequestProcessor.class);
when(response.setStatusCode(anyInt())).thenReturn(response);
doThrow(RuntimeException.class).when(rp2).process(any(), any(), any());
requestProcessors.add(rp1);
requestProcessors.add(rp2);
jerseyHandler.handle(request, inputStream);
verify(rp1).process(any(), any(), endHandlerCaptor.capture());
endHandlerCaptor.getValue().handle(null);
verify(rp2).process(any(), any(), any());
verify(response).setStatusCode(eq(HttpResponseStatus.INTERNAL_SERVER_ERROR.code()));
verify(response).end();
}
@Test
public void testShouldReadData() throws Exception {
boolean result;
DefaultHttpHeaders headers = new DefaultHttpHeaders();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM);
when(request.method()).thenReturn(HttpMethod.GET).thenReturn(HttpMethod.PUT);
when(request.headers()).thenReturn(new HeadersAdaptor(headers));
result = jerseyHandler.shouldReadData(request);
assertFalse(result);
result = jerseyHandler.shouldReadData(request);
assertFalse(result);
headers.clear();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN);
result = jerseyHandler.shouldReadData(request);
assertTrue(result);
headers.clear();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
result = jerseyHandler.shouldReadData(request);
assertTrue(result);
headers.clear();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED);
when(request.method()).thenReturn(HttpMethod.POST);
result = jerseyHandler.shouldReadData(request);
assertTrue(result);
headers.clear();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML);
result = jerseyHandler.shouldReadData(request);
assertTrue(result);
headers.clear();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED + "; charset=UTF-8");
result = jerseyHandler.shouldReadData(request);
assertTrue(result);
}
@Test
public void testGetAbsoluteURI() throws Exception {
URI uri;
String absoluteUri = "http://0.0.0.0:80/test";
String host = "test.englishtown.com";
String badUrl = "http://test.englishtown.com/test?a=b=c|d=e";
HttpServerRequest request = mock(HttpServerRequest.class);
when(request.absoluteURI()).thenReturn(absoluteUri).thenThrow(new IllegalArgumentException());
when(request.uri()).thenReturn(badUrl);
when(request.headers()).thenReturn(headers);
when(headers.get(eq(HttpHeaders.HOST))).thenReturn(host);
uri = jerseyHandler.getAbsoluteURI(request);
assertEquals("http://test.englishtown.com/test", uri.toString());
uri = jerseyHandler.getAbsoluteURI(request);
assertEquals("http://test.englishtown.com/test?a=b%3Dc%7Cd%3De", uri.toString());
}
@Test
public void testGetBaseURI() throws Exception {
URI baseUri = URI.create("/test");
when(options.getBaseUri()).thenReturn(baseUri);
URI result = jerseyHandler.getBaseUri();
assertEquals(baseUri, result);
}
}