/*
* Copyright 2011-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.glowroot.agent.plugin.servlet;
import java.io.IOException;
import java.util.Iterator;
import javax.annotation.Nullable;
import javax.servlet.FilterChain;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpSession;
import org.glowroot.agent.it.harness.AppUnderTest;
import org.glowroot.agent.it.harness.Container;
import org.glowroot.agent.it.harness.Containers;
import org.glowroot.wire.api.model.TraceOuterClass.Trace;
import static org.assertj.core.api.Assertions.assertThat;
public class ServletPluginIT {
private static Container container;
@BeforeClass
public static void setUp() throws Exception {
container = Containers.create();
}
@AfterClass
public static void tearDown() throws Exception {
container.close();
}
@After
public void afterEachTest() throws Exception {
container.checkAndReset();
}
@Test
public void testServlet() throws Exception {
// when
Trace trace = container.execute(ExecuteServlet.class);
// then
Trace.Header header = trace.getHeader();
assertThat(header.getHeadline()).isEqualTo("/testservlet");
assertThat(header.getTransactionName()).isEqualTo("/testservlet");
assertThat(getDetailValue(header, "Request http method")).isEqualTo("GET");
assertThat(header.getEntryCount()).isZero();
}
@Test
public void testFilter() throws Exception {
// when
Trace trace = container.execute(ExecuteFilter.class);
// then
Trace.Header header = trace.getHeader();
assertThat(header.getHeadline()).isEqualTo("/testfilter");
assertThat(header.getTransactionName()).isEqualTo("/testfilter");
assertThat(getDetailValue(header, "Request http method")).isEqualTo("GET");
assertThat(header.getEntryCount()).isZero();
}
@Test
public void testCombination() throws Exception {
// when
Trace trace = container.execute(ExecuteFilterWithNestedServlet.class);
// then
Trace.Header header = trace.getHeader();
assertThat(header.getHeadline()).isEqualTo("/testfilter");
assertThat(header.getTransactionName()).isEqualTo("/testfilter");
assertThat(getDetailValue(header, "Request http method")).isEqualTo("GET");
assertThat(header.getEntryCount()).isZero();
}
@Test
public void testNoQueryString() throws Exception {
// when
Trace trace = container.execute(TestNoQueryString.class);
// then
assertThat(getDetailValue(trace.getHeader(), "Request query string")).isNull();
assertThat(trace.getHeader().getEntryCount()).isZero();
}
@Test
public void testEmptyQueryString() throws Exception {
// when
Trace trace = container.execute(TestEmptyQueryString.class);
// then
assertThat(getDetailValue(trace.getHeader(), "Request query string")).isEqualTo("");
assertThat(trace.getHeader().getEntryCount()).isZero();
}
@Test
public void testNonEmptyQueryString() throws Exception {
// when
Trace trace = container.execute(TestNonEmptyQueryString.class);
// then
assertThat(getDetailValue(trace.getHeader(), "Request query string")).isEqualTo("a=b&c=d");
assertThat(trace.getHeader().getEntryCount()).isZero();
}
@Test
public void testServletThrowsException() throws Exception {
// when
Trace trace = container.execute(ServletThrowsException.class);
// then
Trace.Header header = trace.getHeader();
assertThat(header.getError().getMessage()).isNotEmpty();
assertThat(header.getError().hasException()).isTrue();
assertThat(header.getEntryCount()).isZero();
}
@Test
public void testFilterThrowsException() throws Exception {
// when
Trace trace = container.execute(FilterThrowsException.class);
// then
Trace.Header header = trace.getHeader();
assertThat(header.getError().getMessage()).isNotEmpty();
assertThat(header.getError().hasException()).isTrue();
assertThat(header.getEntryCount()).isZero();
}
@Test
public void testSend500Error() throws Exception {
// when
Trace trace = container.execute(Send500Error.class);
// then
assertThat(trace.getHeader().getError().getMessage())
.isEqualTo("sendError, HTTP status code 500");
assertThat(trace.getHeader().getError().hasException()).isFalse();
Iterator<Trace.Entry> i = trace.getEntryList().iterator();
Trace.Entry entry = i.next();
assertThat(entry.getError().getMessage()).isEqualTo("sendError, HTTP status code 500");
assertThat(entry.getError().hasException()).isFalse();
assertThat(entry.getLocationStackTraceElementList()).isNotEmpty();
assertThat(entry.getLocationStackTraceElementList().get(0).getMethodName())
.isEqualTo("sendError");
assertThat(i.hasNext()).isFalse();
}
@Test
public void testSetStatus500Error() throws Exception {
// when
Trace trace = container.execute(SetStatus500Error.class);
// then
assertThat(trace.getHeader().getError().getMessage())
.isEqualTo("setStatus, HTTP status code 500");
assertThat(trace.getHeader().getError().hasException()).isFalse();
Iterator<Trace.Entry> i = trace.getEntryList().iterator();
Trace.Entry entry = i.next();
assertThat(entry.getError().getMessage()).isEqualTo("setStatus, HTTP status code 500");
assertThat(entry.getError().hasException()).isFalse();
assertThat(entry.getLocationStackTraceElementList().get(0).getMethodName())
.isEqualTo("setStatus");
assertThat(i.hasNext()).isFalse();
}
@Test
public void testBizzareServletContainer() throws Exception {
// when
container.executeNoExpectedTrace(BizzareServletContainer.class);
// then
}
@Test
public void testBizzareThrowingServletContainer() throws Exception {
// when
container.executeNoExpectedTrace(BizzareThrowingServletContainer.class);
// then
}
private static @Nullable String getDetailValue(Trace.Header header, String name) {
for (Trace.DetailEntry detail : header.getDetailEntryList()) {
if (detail.getName().equals(name)) {
return detail.getValueList().get(0).getString();
}
}
return null;
}
@SuppressWarnings("serial")
public static class ExecuteServlet extends TestServlet {}
public static class ExecuteFilter extends TestFilter {}
public static class ExecuteFilterWithNestedServlet extends TestFilter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
new TestFilter().doFilter(request, response, chain);
}
}
@SuppressWarnings("serial")
public static class TestNoQueryString extends TestServlet {
@Override
protected void before(HttpServletRequest request, HttpServletResponse response) {
((MockHttpServletRequest) request).setQueryString(null);
}
}
@SuppressWarnings("serial")
public static class TestEmptyQueryString extends TestServlet {
@Override
protected void before(HttpServletRequest request, HttpServletResponse response) {
((MockHttpServletRequest) request).setQueryString("");
}
}
@SuppressWarnings("serial")
public static class TestNonEmptyQueryString extends TestServlet {
@Override
protected void before(HttpServletRequest request, HttpServletResponse response) {
((MockHttpServletRequest) request).setQueryString("a=b&c=d");
}
}
@SuppressWarnings("serial")
public static class InvalidateSession extends TestServlet {
@Override
protected void before(HttpServletRequest request, HttpServletResponse response) {
((MockHttpServletRequest) request).setSession(new MockHttpSession(null, "1234"));
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
request.getSession().invalidate();
}
}
@SuppressWarnings("serial")
public static class ServletThrowsException extends TestServlet {
private final RuntimeException exception = new RuntimeException("Something happened");
@Override
public void executeApp() throws Exception {
try {
super.executeApp();
} catch (RuntimeException e) {
// only suppress expected exception
if (e != exception) {
throw e;
}
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
throw exception;
}
}
public static class FilterThrowsException extends TestFilter {
private final RuntimeException exception = new RuntimeException("Something happened");
@Override
public void executeApp() throws Exception {
try {
super.executeApp();
} catch (RuntimeException e) {
// only suppress expected exception
if (e != exception) {
throw e;
}
}
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
throw exception;
}
}
@SuppressWarnings("serial")
public static class Send500Error extends TestServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
response.sendError(500);
}
}
@SuppressWarnings("serial")
public static class SetStatus500Error extends TestServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
response.setStatus(500);
}
}
public static class BizzareServletContainer implements AppUnderTest, Servlet {
@Override
public void executeApp() throws Exception {
service(null, null);
}
@Override
public void init(ServletConfig config) {}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest req, ServletResponse res) {}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {}
}
public static class BizzareThrowingServletContainer implements AppUnderTest, Servlet {
@Override
public void executeApp() throws Exception {
try {
service(null, null);
} catch (RuntimeException e) {
}
}
@Override
public void init(ServletConfig config) {}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest req, ServletResponse res) {
throw new RuntimeException();
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {}
}
public static class NestedTwo {
private final String two;
public NestedTwo(String two) {
this.two = two;
}
public String getTwo() {
return two;
}
}
}