Convert tomcat 7 tests from groovy to java (#11402)
This commit is contained in:
parent
64bbbc801a
commit
b36d2845b3
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.tomcat.v7_0
|
||||
|
||||
import io.opentelemetry.instrumentation.test.base.HttpServerTest
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint
|
||||
import javax.servlet.ServletException
|
||||
import javax.servlet.annotation.WebServlet
|
||||
import javax.servlet.http.HttpServlet
|
||||
import javax.servlet.http.HttpServletRequest
|
||||
import javax.servlet.http.HttpServletResponse
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.CAPTURE_HEADERS
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.ERROR
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.INDEXED_CHILD
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.QUERY_PARAM
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.REDIRECT
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.SUCCESS
|
||||
|
||||
@WebServlet(asyncSupported = true)
|
||||
class AsyncServlet extends HttpServlet {
|
||||
@Override
|
||||
protected void service(HttpServletRequest req, HttpServletResponse resp) {
|
||||
ServerEndpoint endpoint = ServerEndpoint.forPath(req.servletPath)
|
||||
def latch = new CountDownLatch(1)
|
||||
def context = req.startAsync()
|
||||
if (endpoint == EXCEPTION) {
|
||||
context.setTimeout(5000)
|
||||
}
|
||||
context.start {
|
||||
try {
|
||||
HttpServerTest.controller(endpoint) {
|
||||
resp.contentType = "text/plain"
|
||||
switch (endpoint) {
|
||||
case SUCCESS:
|
||||
resp.status = endpoint.status
|
||||
resp.writer.print(endpoint.body)
|
||||
break
|
||||
case INDEXED_CHILD:
|
||||
endpoint.collectSpanAttributes { req.getParameter(it) }
|
||||
resp.status = endpoint.status
|
||||
break
|
||||
case QUERY_PARAM:
|
||||
resp.status = endpoint.status
|
||||
resp.writer.print(req.queryString)
|
||||
break
|
||||
case REDIRECT:
|
||||
resp.sendRedirect(endpoint.body)
|
||||
break
|
||||
case CAPTURE_HEADERS:
|
||||
resp.setHeader("X-Test-Response", req.getHeader("X-Test-Request"))
|
||||
resp.status = endpoint.status
|
||||
resp.writer.print(endpoint.body)
|
||||
break
|
||||
case ERROR:
|
||||
resp.status = endpoint.status
|
||||
resp.writer.print(endpoint.body)
|
||||
break
|
||||
case EXCEPTION:
|
||||
resp.status = endpoint.status
|
||||
def writer = resp.writer
|
||||
writer.print(endpoint.body)
|
||||
writer.close()
|
||||
throw new ServletException(endpoint.body)
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// complete at the end so the server span will end after the controller span
|
||||
if (endpoint != EXCEPTION) {
|
||||
context.complete()
|
||||
}
|
||||
latch.countDown()
|
||||
}
|
||||
}
|
||||
latch.await()
|
||||
}
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.tomcat.v7_0
|
||||
|
||||
import io.opentelemetry.api.trace.SpanKind
|
||||
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
|
||||
import org.apache.tomcat.util.threads.TaskQueue
|
||||
import org.apache.tomcat.util.threads.ThreadPoolExecutor
|
||||
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
class ThreadPoolExecutorTest extends AgentInstrumentationSpecification {
|
||||
|
||||
// Test that PropagatedContext isn't cleared when ThreadPoolExecutor.execute fails with
|
||||
// RejectedExecutionException
|
||||
def "test tomcat thread pool"() {
|
||||
setup:
|
||||
def reject = new AtomicBoolean()
|
||||
def queue = new TaskQueue() {
|
||||
@Override
|
||||
boolean offer(Runnable o) {
|
||||
// TaskQueue.offer returns false when parent.getPoolSize() < parent.getMaximumPoolSize()
|
||||
// here we simulate the same condition to trigger RejectedExecutionException handling in
|
||||
// tomcat ThreadPoolExecutor
|
||||
if (reject.get()) {
|
||||
reject.set(false)
|
||||
return false
|
||||
}
|
||||
return super.offer(o)
|
||||
}
|
||||
}
|
||||
def pool = new ThreadPoolExecutor(1, 1, 0, TimeUnit.MILLISECONDS, queue)
|
||||
queue.setParent(pool)
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1)
|
||||
|
||||
runWithSpan("parent") {
|
||||
pool.execute(new Runnable() {
|
||||
@Override
|
||||
void run() {
|
||||
runWithSpan("child1") {
|
||||
latch.await()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
reject.set(true)
|
||||
pool.execute(new Runnable() {
|
||||
@Override
|
||||
void run() {
|
||||
runWithSpan("child2") {
|
||||
latch.await()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
latch.countDown()
|
||||
|
||||
expect:
|
||||
assertTraces(1) {
|
||||
trace(0, 3) {
|
||||
span(0) {
|
||||
name "parent"
|
||||
kind SpanKind.INTERNAL
|
||||
hasNoParent()
|
||||
}
|
||||
span(1) {
|
||||
name "child1"
|
||||
kind SpanKind.INTERNAL
|
||||
childOf span(0)
|
||||
}
|
||||
span(2) {
|
||||
name "child2"
|
||||
kind SpanKind.INTERNAL
|
||||
childOf span(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
pool.shutdown()
|
||||
pool.awaitTermination(10, TimeUnit.SECONDS)
|
||||
}
|
||||
}
|
|
@ -1,143 +0,0 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.tomcat.v7_0
|
||||
|
||||
import io.opentelemetry.instrumentation.api.internal.HttpConstants
|
||||
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
||||
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
||||
import io.opentelemetry.instrumentation.test.base.HttpServerTest
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint
|
||||
import org.apache.catalina.Context
|
||||
import org.apache.catalina.startup.Tomcat
|
||||
import org.apache.tomcat.JarScanFilter
|
||||
import org.apache.tomcat.JarScanType
|
||||
import spock.lang.Unroll
|
||||
|
||||
import javax.servlet.Servlet
|
||||
import javax.servlet.ServletException
|
||||
import java.nio.file.Files
|
||||
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.AUTH_REQUIRED
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.CAPTURE_HEADERS
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.ERROR
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.INDEXED_CHILD
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.NOT_FOUND
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.QUERY_PARAM
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.REDIRECT
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.SUCCESS
|
||||
|
||||
@Unroll
|
||||
class TomcatAsyncTest extends HttpServerTest<Tomcat> implements AgentTestTrait {
|
||||
|
||||
@Override
|
||||
Tomcat startServer(int port) {
|
||||
def tomcatServer = new Tomcat()
|
||||
|
||||
def baseDir = Files.createTempDirectory("tomcat").toFile()
|
||||
baseDir.deleteOnExit()
|
||||
tomcatServer.setBaseDir(baseDir.getAbsolutePath())
|
||||
|
||||
tomcatServer.setPort(port)
|
||||
tomcatServer.getConnector().enableLookups = true // get localhost instead of 127.0.0.1
|
||||
|
||||
File applicationDir = new File(baseDir, "/webapps/ROOT")
|
||||
if (!applicationDir.exists()) {
|
||||
applicationDir.mkdirs()
|
||||
applicationDir.deleteOnExit()
|
||||
}
|
||||
Context servletContext = tomcatServer.addWebapp(contextPath, applicationDir.getAbsolutePath())
|
||||
// Speed up startup by disabling jar scanning:
|
||||
servletContext.getJarScanner().setJarScanFilter(new JarScanFilter() {
|
||||
@Override
|
||||
boolean check(JarScanType jarScanType, String jarName) {
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
||||
setupServlets(servletContext)
|
||||
|
||||
tomcatServer.start()
|
||||
|
||||
return tomcatServer
|
||||
}
|
||||
|
||||
@Override
|
||||
void stopServer(Tomcat server) {
|
||||
server.stop()
|
||||
server.destroy()
|
||||
}
|
||||
|
||||
@Override
|
||||
String getContextPath() {
|
||||
return "/tomcat-context"
|
||||
}
|
||||
|
||||
@Override
|
||||
String getMetricsInstrumentationName() {
|
||||
// with async requests the span is started in one instrumentation (server instrumentation)
|
||||
// but ended from another (servlet instrumentation)
|
||||
"io.opentelemetry.servlet-3.0"
|
||||
}
|
||||
|
||||
protected void setupServlets(Context context) {
|
||||
def servlet = servlet()
|
||||
|
||||
addServlet(context, SUCCESS.path, servlet)
|
||||
addServlet(context, QUERY_PARAM.path, servlet)
|
||||
addServlet(context, ERROR.path, servlet)
|
||||
addServlet(context, EXCEPTION.path, servlet)
|
||||
addServlet(context, REDIRECT.path, servlet)
|
||||
addServlet(context, AUTH_REQUIRED.path, servlet)
|
||||
addServlet(context, CAPTURE_HEADERS.path, servlet)
|
||||
addServlet(context, INDEXED_CHILD.path, servlet)
|
||||
}
|
||||
|
||||
void addServlet(Context servletContext, String path, Class<Servlet> servlet) {
|
||||
String name = UUID.randomUUID()
|
||||
Tomcat.addServlet(servletContext, name, servlet.newInstance())
|
||||
servletContext.addServletMappingDecoded(path, name)
|
||||
}
|
||||
|
||||
Class<Servlet> servlet() {
|
||||
AsyncServlet
|
||||
}
|
||||
|
||||
@Override
|
||||
String expectedHttpRoute(ServerEndpoint endpoint, String method) {
|
||||
if (method == HttpConstants._OTHER) {
|
||||
return getContextPath() + endpoint.path
|
||||
}
|
||||
switch (endpoint) {
|
||||
case NOT_FOUND:
|
||||
return getContextPath() + "/*"
|
||||
default:
|
||||
return super.expectedHttpRoute(endpoint, method)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Throwable expectedException() {
|
||||
new ServletException(EXCEPTION.body)
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean hasResponseSpan(ServerEndpoint endpoint) {
|
||||
endpoint == NOT_FOUND || endpoint == REDIRECT
|
||||
}
|
||||
|
||||
@Override
|
||||
void responseSpan(TraceAssert trace, int index, Object parent, String method, ServerEndpoint endpoint) {
|
||||
switch (endpoint) {
|
||||
case REDIRECT:
|
||||
redirectSpan(trace, index, parent)
|
||||
break
|
||||
case NOT_FOUND:
|
||||
sendErrorSpan(trace, index, parent)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,128 +0,0 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.tomcat.v7_0
|
||||
|
||||
import io.opentelemetry.instrumentation.api.internal.HttpConstants
|
||||
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
||||
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
||||
import io.opentelemetry.instrumentation.test.base.HttpServerTest
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint
|
||||
import org.apache.catalina.Context
|
||||
import org.apache.catalina.connector.Request
|
||||
import org.apache.catalina.connector.Response
|
||||
import org.apache.catalina.core.StandardHost
|
||||
import org.apache.catalina.startup.Tomcat
|
||||
import org.apache.catalina.valves.ErrorReportValve
|
||||
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.AUTH_ERROR
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.AUTH_REQUIRED
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.CAPTURE_HEADERS
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.CAPTURE_PARAMETERS
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.ERROR
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.INDEXED_CHILD
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.LOGIN
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.NOT_FOUND
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.PATH_PARAM
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.QUERY_PARAM
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.REDIRECT
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.SUCCESS
|
||||
|
||||
class TomcatHandlerTest extends HttpServerTest<Tomcat> implements AgentTestTrait {
|
||||
|
||||
private static final List<ServerEndpoint> serverEndpointsList = Arrays.asList(SUCCESS, REDIRECT, ERROR, EXCEPTION, NOT_FOUND, CAPTURE_HEADERS, CAPTURE_PARAMETERS, QUERY_PARAM, PATH_PARAM, AUTH_REQUIRED, LOGIN, AUTH_ERROR, INDEXED_CHILD)
|
||||
|
||||
def "Tomcat starts"() {
|
||||
expect:
|
||||
getServer() != null
|
||||
}
|
||||
|
||||
@Override
|
||||
String getContextPath() {
|
||||
return "/app"
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean hasResponseCustomizer(ServerEndpoint endpoint) {
|
||||
true
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean testCapturedRequestParameters() {
|
||||
true
|
||||
}
|
||||
|
||||
@Override
|
||||
String expectedHttpRoute(ServerEndpoint endpoint, String method) {
|
||||
if (method == HttpConstants._OTHER) {
|
||||
return getContextPath() + endpoint.path
|
||||
}
|
||||
return super.expectedHttpRoute(endpoint, method)
|
||||
}
|
||||
|
||||
@Override
|
||||
Tomcat startServer(int port) {
|
||||
Tomcat tomcat = new Tomcat()
|
||||
tomcat.setBaseDir(File.createTempDir().absolutePath)
|
||||
tomcat.setPort(port)
|
||||
tomcat.getConnector()
|
||||
|
||||
Context ctx = tomcat.addContext(getContextPath(), new File(".").getAbsolutePath())
|
||||
|
||||
Tomcat.addServlet(ctx, "testServlet", new TestServlet())
|
||||
|
||||
// Mapping servlet to /* will result in all requests have a name of just a context.
|
||||
serverEndpointsList.stream()
|
||||
.filter { it != NOT_FOUND }
|
||||
.forEach {
|
||||
ctx.addServletMappingDecoded(it.path, "testServlet")
|
||||
}
|
||||
|
||||
(tomcat.host as StandardHost).errorReportValveClass = ErrorHandlerValve.name
|
||||
|
||||
tomcat.start()
|
||||
|
||||
return tomcat
|
||||
}
|
||||
|
||||
@Override
|
||||
void stopServer(Tomcat tomcat) {
|
||||
tomcat.getServer().stop()
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean hasResponseSpan(ServerEndpoint endpoint) {
|
||||
endpoint == REDIRECT || endpoint == ERROR || endpoint == NOT_FOUND
|
||||
}
|
||||
|
||||
@Override
|
||||
void responseSpan(TraceAssert trace, int index, Object parent, String method, ServerEndpoint endpoint) {
|
||||
switch (endpoint) {
|
||||
case REDIRECT:
|
||||
redirectSpan(trace, index, parent)
|
||||
break
|
||||
case ERROR:
|
||||
case NOT_FOUND:
|
||||
sendErrorSpan(trace, index, parent)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ErrorHandlerValve extends ErrorReportValve {
|
||||
@Override
|
||||
protected void report(Request request, Response response, Throwable t) {
|
||||
if (response.getStatus() < 400 || response.getContentWritten() > 0 || !response.isError()) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
response.writer.print(t ? t.cause.message : response.message)
|
||||
} catch (IOException ignored) {
|
||||
// Ignore exception when writing exception message to response fails on IO - same as is done
|
||||
// by the superclass itself and by other built-in ErrorReportValve implementations.
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.tomcat.v7_0;
|
||||
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.CAPTURE_HEADERS;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.ERROR;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.INDEXED_CHILD;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.QUERY_PARAM;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.REDIRECT;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.SUCCESS;
|
||||
|
||||
import io.opentelemetry.instrumentation.test.base.HttpServerTest;
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@WebServlet(asyncSupported = true)
|
||||
class AsyncServlet extends HttpServlet {
|
||||
@Override
|
||||
protected void service(HttpServletRequest req, HttpServletResponse resp) {
|
||||
ServerEndpoint endpoint = ServerEndpoint.forPath(req.getServletPath());
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
AsyncContext context = req.startAsync();
|
||||
if (endpoint == EXCEPTION) {
|
||||
context.setTimeout(5000);
|
||||
}
|
||||
context.start(
|
||||
() -> {
|
||||
try {
|
||||
HttpServerTest.controller(
|
||||
endpoint,
|
||||
() -> {
|
||||
resp.setContentType("text/plain");
|
||||
if (endpoint.equals(SUCCESS) || endpoint.equals(ERROR)) {
|
||||
resp.setStatus(endpoint.getStatus());
|
||||
resp.getWriter().print(endpoint.getBody());
|
||||
} else if (endpoint.equals(INDEXED_CHILD)) {
|
||||
endpoint.collectSpanAttributes(x -> req.getParameter(x));
|
||||
resp.setStatus(endpoint.getStatus());
|
||||
} else if (endpoint.equals(QUERY_PARAM)) {
|
||||
resp.setStatus(endpoint.getStatus());
|
||||
resp.getWriter().print(req.getQueryString());
|
||||
} else if (endpoint.equals(REDIRECT)) {
|
||||
resp.sendRedirect(endpoint.getBody());
|
||||
} else if (endpoint.equals(CAPTURE_HEADERS)) {
|
||||
resp.setHeader("X-Test-Response", req.getHeader("X-Test-Request"));
|
||||
resp.setStatus(endpoint.getStatus());
|
||||
resp.getWriter().print(endpoint.getBody());
|
||||
} else if (endpoint.equals(EXCEPTION)) {
|
||||
resp.setStatus(endpoint.getStatus());
|
||||
PrintWriter writer = resp.getWriter();
|
||||
writer.print(endpoint.getBody());
|
||||
writer.close();
|
||||
throw new ServletException(endpoint.getBody());
|
||||
}
|
||||
return null;
|
||||
});
|
||||
} finally {
|
||||
// complete at the end so the server span will end after the controller span
|
||||
if (endpoint != EXCEPTION) {
|
||||
context.complete();
|
||||
}
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
try {
|
||||
latch.await();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.tomcat.v7_0;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.apache.catalina.connector.Response;
|
||||
import org.apache.catalina.valves.ErrorReportValve;
|
||||
|
||||
class ErrorHandlerValve extends ErrorReportValve {
|
||||
@Override
|
||||
protected void report(Request request, Response response, Throwable t) {
|
||||
if (response.getStatus() < 400 || response.getContentWritten() > 0 || !response.isError()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
response.getWriter().print(t != null ? t.getCause().getMessage() : response.getMessage());
|
||||
} catch (IOException ignored) {
|
||||
// Ignore exception when writing exception message to response fails on IO - same as is done
|
||||
// by the superclass itself and by other built-in ErrorReportValve implementations.
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ import javax.servlet.http.HttpServlet;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
public class TestServlet extends HttpServlet {
|
||||
class TestServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.tomcat.v7_0;
|
||||
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
|
||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import org.apache.tomcat.util.threads.TaskQueue;
|
||||
import org.apache.tomcat.util.threads.ThreadPoolExecutor;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
class ThreadPoolExecutorTest {
|
||||
|
||||
@RegisterExtension
|
||||
static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
|
||||
|
||||
// Test that PropagatedContext isn't cleared when ThreadPoolExecutor.execute fails with
|
||||
// RejectedExecutionException
|
||||
@Test
|
||||
void testTomcatThreadPool() throws InterruptedException {
|
||||
AtomicBoolean reject = new AtomicBoolean();
|
||||
TaskQueue queue =
|
||||
new TaskQueue() {
|
||||
@Override
|
||||
public boolean offer(Runnable o) {
|
||||
// TaskQueue.offer returns false when parent.getPoolSize() < parent.getMaximumPoolSize()
|
||||
// here we simulate the same condition to trigger RejectedExecutionException handling in
|
||||
// tomcat ThreadPoolExecutor
|
||||
if (reject.get()) {
|
||||
reject.set(false);
|
||||
return false;
|
||||
}
|
||||
return super.offer(o);
|
||||
}
|
||||
};
|
||||
|
||||
ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 1, 0, TimeUnit.MILLISECONDS, queue);
|
||||
queue.setParent(pool);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
testing.runWithSpan(
|
||||
"parent",
|
||||
() -> {
|
||||
pool.execute(
|
||||
() -> {
|
||||
try {
|
||||
testing.runWithSpan("child1", () -> latch.await());
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
|
||||
reject.set(true);
|
||||
pool.execute(
|
||||
() -> {
|
||||
try {
|
||||
testing.runWithSpan("child2", () -> latch.await());
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
latch.countDown();
|
||||
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
||||
span ->
|
||||
span.hasName("child1").hasKind(SpanKind.INTERNAL).hasParent(trace.getSpan(0)),
|
||||
span ->
|
||||
span.hasName("child2").hasKind(SpanKind.INTERNAL).hasParent(trace.getSpan(0))));
|
||||
|
||||
pool.shutdown();
|
||||
pool.awaitTermination(10, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.tomcat.v7_0;
|
||||
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.AUTH_REQUIRED;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.CAPTURE_HEADERS;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.ERROR;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.INDEXED_CHILD;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.NOT_FOUND;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.QUERY_PARAM;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.REDIRECT;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.SUCCESS;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.instrumentation.api.internal.HttpConstants;
|
||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest;
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerInstrumentationExtension;
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerTestOptions;
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint;
|
||||
import io.opentelemetry.sdk.testing.assertj.SpanDataAssert;
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.util.UUID;
|
||||
import javax.servlet.ServletException;
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
class TomcatAsyncTest extends AbstractHttpServerTest<Tomcat> {
|
||||
|
||||
@RegisterExtension
|
||||
static final InstrumentationExtension testing = HttpServerInstrumentationExtension.forAgent();
|
||||
|
||||
@Override
|
||||
public Tomcat setupServer() throws Exception {
|
||||
Tomcat tomcatServer = new Tomcat();
|
||||
File baseDir = Files.createTempDirectory("tomcat").toFile();
|
||||
baseDir.deleteOnExit();
|
||||
tomcatServer.setBaseDir(baseDir.getAbsolutePath());
|
||||
tomcatServer.setPort(port);
|
||||
tomcatServer.getConnector().setEnableLookups(true); // get localhost instead of 127.0.0.1
|
||||
|
||||
File applicationDir = new File(baseDir, "/webapps/ROOT");
|
||||
if (!applicationDir.exists()) {
|
||||
applicationDir.mkdirs();
|
||||
applicationDir.deleteOnExit();
|
||||
}
|
||||
|
||||
Context servletContext =
|
||||
tomcatServer.addWebapp(getContextPath(), applicationDir.getAbsolutePath());
|
||||
// Speed up startup by disabling jar scanning:
|
||||
servletContext.getJarScanner().setJarScanFilter((jarScanType, jarName) -> false);
|
||||
|
||||
setupServlets(servletContext);
|
||||
tomcatServer.start();
|
||||
return tomcatServer;
|
||||
}
|
||||
|
||||
protected void setupServlets(Context context) throws Exception {
|
||||
Class<AsyncServlet> servlet = AsyncServlet.class;
|
||||
|
||||
addServlet(context, SUCCESS.getPath(), servlet);
|
||||
addServlet(context, QUERY_PARAM.getPath(), servlet);
|
||||
addServlet(context, ERROR.getPath(), servlet);
|
||||
addServlet(context, EXCEPTION.getPath(), servlet);
|
||||
addServlet(context, REDIRECT.getPath(), servlet);
|
||||
addServlet(context, AUTH_REQUIRED.getPath(), servlet);
|
||||
addServlet(context, CAPTURE_HEADERS.getPath(), servlet);
|
||||
addServlet(context, INDEXED_CHILD.getPath(), servlet);
|
||||
}
|
||||
|
||||
void addServlet(Context servletContext, String path, Class<AsyncServlet> servlet)
|
||||
throws Exception {
|
||||
String name = UUID.randomUUID().toString();
|
||||
Tomcat.addServlet(servletContext, name, servlet.getDeclaredConstructor().newInstance());
|
||||
servletContext.addServletMappingDecoded(path, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopServer(Tomcat server) throws LifecycleException {
|
||||
server.stop();
|
||||
server.destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpServerTestOptions options) {
|
||||
options.setContextPath("/tomcat-context");
|
||||
|
||||
options.setExpectedHttpRoute(
|
||||
(ServerEndpoint endpoint, String method) -> {
|
||||
if (method.equals(HttpConstants._OTHER)) {
|
||||
return getContextPath() + endpoint.getPath();
|
||||
}
|
||||
if (endpoint.equals(NOT_FOUND)) {
|
||||
return getContextPath() + "/*";
|
||||
}
|
||||
return super.expectedHttpRoute(endpoint, method);
|
||||
});
|
||||
|
||||
options.setExpectedException(new ServletException(EXCEPTION.getBody()));
|
||||
|
||||
options.setHasResponseSpan(endpoint -> endpoint == NOT_FOUND || endpoint == REDIRECT);
|
||||
|
||||
// with async requests the span is started in one instrumentation (server instrumentation)
|
||||
// but ended from another (servlet instrumentation)
|
||||
options.setMetricsInstrumentationName(() -> "io.opentelemetry.servlet-3.0");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SpanDataAssert assertResponseSpan(
|
||||
SpanDataAssert span, String method, ServerEndpoint endpoint) {
|
||||
if (endpoint.equals(REDIRECT)) {
|
||||
span.satisfies(spanData -> assertThat(spanData.getName()).endsWith(".sendRedirect"));
|
||||
} else if (endpoint.equals(NOT_FOUND)) {
|
||||
span.satisfies(spanData -> assertThat(spanData.getName()).endsWith(".sendError"));
|
||||
}
|
||||
span.hasKind(SpanKind.INTERNAL).hasAttributesSatisfying(Attributes::isEmpty);
|
||||
return span;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.tomcat.v7_0;
|
||||
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.AUTH_ERROR;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.AUTH_REQUIRED;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.CAPTURE_HEADERS;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.CAPTURE_PARAMETERS;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.ERROR;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.INDEXED_CHILD;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.LOGIN;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.NOT_FOUND;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.PATH_PARAM;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.QUERY_PARAM;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.REDIRECT;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.SUCCESS;
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.instrumentation.api.internal.HttpConstants;
|
||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest;
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerInstrumentationExtension;
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerTestOptions;
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint;
|
||||
import io.opentelemetry.sdk.testing.assertj.SpanDataAssert;
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.util.List;
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.core.StandardHost;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
class TomcatHandlerTest extends AbstractHttpServerTest<Tomcat> {
|
||||
|
||||
@RegisterExtension
|
||||
static final InstrumentationExtension testing = HttpServerInstrumentationExtension.forAgent();
|
||||
|
||||
private static final List<ServerEndpoint> serverEndpointsList =
|
||||
asList(
|
||||
SUCCESS,
|
||||
REDIRECT,
|
||||
ERROR,
|
||||
EXCEPTION,
|
||||
NOT_FOUND,
|
||||
CAPTURE_HEADERS,
|
||||
CAPTURE_PARAMETERS,
|
||||
QUERY_PARAM,
|
||||
PATH_PARAM,
|
||||
AUTH_REQUIRED,
|
||||
LOGIN,
|
||||
AUTH_ERROR,
|
||||
INDEXED_CHILD);
|
||||
|
||||
@Override
|
||||
public Tomcat setupServer() throws Exception {
|
||||
Tomcat tomcatServer = new Tomcat();
|
||||
File baseDir = Files.createTempDirectory("tomcat").toFile();
|
||||
baseDir.deleteOnExit();
|
||||
tomcatServer.setBaseDir(baseDir.getAbsolutePath());
|
||||
tomcatServer.setPort(port);
|
||||
tomcatServer.getConnector();
|
||||
|
||||
Context servletContext =
|
||||
tomcatServer.addContext(getContextPath(), new File(".").getAbsolutePath());
|
||||
|
||||
Tomcat.addServlet(servletContext, "testServlet", new TestServlet());
|
||||
|
||||
// Mapping servlet to /* will result in all requests have a name of just a context.
|
||||
serverEndpointsList.stream()
|
||||
.filter(endpoint -> !endpoint.equals(NOT_FOUND))
|
||||
.forEach(
|
||||
endpoint -> servletContext.addServletMappingDecoded(endpoint.getPath(), "testServlet"));
|
||||
|
||||
StandardHost host = (StandardHost) tomcatServer.getHost();
|
||||
host.setErrorReportValveClass(ErrorHandlerValve.class.getName());
|
||||
|
||||
tomcatServer.start();
|
||||
return tomcatServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopServer(Tomcat server) throws LifecycleException {
|
||||
server.stop();
|
||||
server.destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpServerTestOptions options) {
|
||||
options.setContextPath("/app");
|
||||
options.setHasResponseCustomizer(serverEndpoint -> true);
|
||||
options.setTestCaptureRequestParameters(true);
|
||||
options.setTestErrorBody(false);
|
||||
|
||||
options.setHasResponseSpan(
|
||||
endpoint -> endpoint == REDIRECT || endpoint == ERROR || endpoint == NOT_FOUND);
|
||||
|
||||
options.setExpectedHttpRoute(
|
||||
(ServerEndpoint endpoint, String method) -> {
|
||||
if (method.equals(HttpConstants._OTHER)) {
|
||||
return getContextPath() + endpoint.getPath();
|
||||
}
|
||||
return super.expectedHttpRoute(endpoint, method);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SpanDataAssert assertResponseSpan(
|
||||
SpanDataAssert span, String method, ServerEndpoint endpoint) {
|
||||
if (endpoint.equals(REDIRECT)) {
|
||||
span.satisfies(spanData -> assertThat(spanData.getName()).endsWith(".sendRedirect"));
|
||||
} else if (endpoint.equals(NOT_FOUND)) {
|
||||
span.satisfies(spanData -> assertThat(spanData.getName()).endsWith(".sendError"));
|
||||
}
|
||||
span.hasKind(SpanKind.INTERNAL).hasAttributesSatisfying(Attributes::isEmpty);
|
||||
return span;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue