/**
*
*/
package org.minnal.core;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import java.io.OutputStream;
import java.net.URI;
import java.util.Arrays;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import org.glassfish.jersey.server.ApplicationHandler;
import org.glassfish.jersey.server.ContainerRequest;
import org.glassfish.jersey.server.ContainerResponse;
import org.glassfish.jersey.server.ResourceConfig;
import org.minnal.core.config.ApplicationConfiguration;
import org.minnal.core.server.MessageContext;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
/**
* @author ganeshs
*
*/
public class RouterTest {
private Router router;
private MessageContext context;
private Application<ApplicationConfiguration> application;
private ApplicationMapping applicationMapping;
private FullHttpRequest request;
private FullHttpResponse response;
@BeforeMethod
public void setup() {
applicationMapping = mock(ApplicationMapping.class);
request = mock(FullHttpRequest.class);
response = mock(FullHttpResponse.class);
when(request.getMethod()).thenReturn(HttpMethod.GET);
when(request.getUri()).thenReturn("/test");
when(request.headers()).thenReturn(new DefaultHttpHeaders());
when(request.content()).thenReturn(mock(ByteBuf.class));
when(request.getProtocolVersion()).thenReturn(HttpVersion.HTTP_1_1);
when(response.getStatus()).thenReturn(HttpResponseStatus.PROCESSING);
application = mock(Application.class);
context = mock(MessageContext.class);
router = spy(new Router(applicationMapping));
doReturn(new ApplicationHandler()).when(router).getApplicationHandler(application);
when(application.getPath()).thenReturn(URI.create("/app"));
when(context.getRequest()).thenReturn(request);
when(context.getResponse()).thenReturn(response);
when(context.getApplication()).thenReturn(application);
when(context.getBaseUri()).thenReturn(URI.create("http://localhost:8080"));
when(applicationMapping.resolve(request)).thenReturn(application);
}
@Test
public void shouldNotSetResponseCodeIfAlreadySet() {
when(response.getStatus()).thenReturn(HttpResponseStatus.NOT_FOUND);
router.route(context);
verify(response, never()).setStatus(any(HttpResponseStatus.class));
}
@Test
public void shouldPopulateContextWithApplication() {
router.route(context);
verify(context).setApplication(application);
}
@Test(expectedExceptions=NotFoundException.class)
public void shouldReturnNotFoundIfApplicationDoesntMatch() {
RouterListener listener = mock(RouterListener.class);
router.registerListener(listener);
when(applicationMapping.resolve(context.getRequest())).thenReturn(null);
router.route(context);
verify(listener, never()).onApplicationResolved(context);
}
@Test
public void shouldInvokeListenerWhenApplicationIsResolved() {
RouterListener listener = mock(RouterListener.class);
router.registerListener(listener);
router.route(context);
verify(listener).onApplicationResolved(context);
}
@Test
public void shouldInvokeApplicationHandlerOnRoute() {
ApplicationHandler handler = new ApplicationHandler();
doReturn(handler).when(router).getApplicationHandler(application);
router.route(context);
// FIXME: ApplicationHandler cant be mocked. How to test this ???
}
@Test
public void shouldCreateContainerRequestFromHttpRequestWithBaseAndRequestUri() {
ContainerRequest containerRequest = router.createContainerRequest(context);
assertEquals(containerRequest.getBaseUri(), URI.create("http://localhost:8080/app/"));
assertEquals(containerRequest.getRequestUri(), URI.create("/test"));
}
@Test
public void shouldCreateContainerRequestFromHttpRequestWithHeaders() {
request.headers().add("header1", "value1");
request.headers().add("header2", Arrays.asList("value2", "value3"));
ContainerRequest containerRequest = router.createContainerRequest(context);
assertEquals(containerRequest.getHeaders().getFirst("header1"), "value1");
assertEquals(containerRequest.getHeaders().get("header2"), Arrays.asList("value2", "value3"));
}
@Test
public void shouldCreateContainerRequestFromHttpRequestWithContent() {
ByteBuf content = mock(ByteBuf.class);
when(request.content()).thenReturn(content);
ContainerRequest containerRequest = router.createContainerRequest(context);
assertTrue(containerRequest.getEntityStream() instanceof ByteBufInputStream);
}
@Test
public void shouldCreateApplicationHandlerFirstTime() {
router = spy(new Router(applicationMapping));
ResourceConfig config = mock(ResourceConfig.class);
when(application.getResourceConfig()).thenReturn(config);
ApplicationHandler handler = new ApplicationHandler();
doReturn(handler).when(router).createApplicationHandler(config);
assertNotNull(router.getApplicationHandler(application));
}
@Test
public void shouldNotCreateApplicationHandlerSecondTime() {
router = spy(new Router(applicationMapping));
ResourceConfig config = mock(ResourceConfig.class);
when(application.getResourceConfig()).thenReturn(config);
ApplicationHandler handler = new ApplicationHandler();
doReturn(handler).when(router).createApplicationHandler(config);
handler = router.getApplicationHandler(application);
assertEquals(router.getApplicationHandler(application), handler);
}
@Test
public void shouldCreateHttpResponseFromContainerResponseWithStatus() {
MultivaluedMap<String, Object> headers = mock(MultivaluedMap.class);
ContainerResponse response = mock(ContainerResponse.class);
when(response.getHeaders()).thenReturn(headers);
when(response.getStatus()).thenReturn(200);
ByteBuf buffer = mock(ByteBuf.class);
FullHttpResponse httpResponse = router.createHttpResponse(context, response, buffer);
assertEquals(httpResponse.getStatus(), HttpResponseStatus.OK);
}
@Test
public void shouldCreateHttpResponseFromContainerResponseWithContent() {
MultivaluedMap<String, Object> headers = mock(MultivaluedMap.class);
ContainerResponse response = mock(ContainerResponse.class);
when(response.getHeaders()).thenReturn(headers);
when(response.getStatus()).thenReturn(200);
when(response.getLength()).thenReturn(10);
when(response.getEntityStream()).thenReturn(mock(OutputStream.class));
ByteBuf buffer = mock(ByteBuf.class);
FullHttpResponse httpResponse = router.createHttpResponse(context, response, buffer);
assertTrue(httpResponse.content() instanceof ByteBuf);
assertEquals(HttpHeaders.getContentLength(httpResponse), 10);
}
@Test
public void shouldCreateHttpResponseFromContainerResponseWithHeaders() {
MultivaluedMap<String, Object> headers = new MultivaluedHashMap<String, Object>();
headers.add("header1", "value1");
headers.addAll("header2", Arrays.<Object>asList("value2", "value3"));
ContainerResponse response = mock(ContainerResponse.class);
when(response.getHeaders()).thenReturn(headers);
when(response.getStatus()).thenReturn(200);
ByteBuf buffer = mock(ByteBuf.class);
FullHttpResponse httpResponse = router.createHttpResponse(context, response, buffer);
assertEquals(HttpHeaders.getHeader(httpResponse, "header1"), "value1");
assertEquals(HttpHeaders.getHeader(httpResponse, "header2"), "value2, value3");
}
}