diff --git a/CHANGELOG.md b/CHANGELOG.md index a62eb50dd2..6c09897674 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,11 +16,14 @@ * Introduces a new configuration option `disable_metrics` which disables the collection of metrics via a wildcard expression. * Support for HttpUrlConnection * Adds `subtype` and `action` to spans. This replaces former typing mechanism where type, subtype and action were all set through - the type in an hierarchical dotted-syntax. In order to support existing API usages, dotted types are parsed into subtype and action, - however `Span.createSpan` and `Span.setType` are deprecated starting this version. Instead, type-less spans can be created using the new - `Span.startSpan` API and typed spans can be created using the new `Span.startSpan(String type, String subtype, String action)` API - * Add support for JBoss EAP - * Improving startup times + the type in an hierarchical dotted-syntax. In order to support existing API usages, dotted types are parsed into subtype and action, + however `Span.createSpan` and `Span.setType` are deprecated starting this version. Instead, type-less spans can be created using the new + `Span.startSpan` API and typed spans can be created using the new `Span.startSpan(String type, String subtype, String action)` API + * Support for JBoss EAP 6.4, 7.0, 7.1 and 7.2 + * Improved startup times + * Support for SOAP (JAX-WS). + SOAP client create spans and propagate context. + Transactions are created for `@WebService` classes and `@WebMethod` methods. ## Bug Fixes * Fixes a failure in BitBucket when agent deployed ([#349](https://github.com/elastic/apm-agent-java/issues/349)) diff --git a/apm-agent-plugins/apm-jaxrs-plugin/src/main/java/co/elastic/apm/agent/jaxrs/JaxRsTransactionNameInstrumentation.java b/apm-agent-plugins/apm-jaxrs-plugin/src/main/java/co/elastic/apm/agent/jaxrs/JaxRsTransactionNameInstrumentation.java index 208fd3e1c6..7c2a6c3fef 100644 --- a/apm-agent-plugins/apm-jaxrs-plugin/src/main/java/co/elastic/apm/agent/jaxrs/JaxRsTransactionNameInstrumentation.java +++ b/apm-agent-plugins/apm-jaxrs-plugin/src/main/java/co/elastic/apm/agent/jaxrs/JaxRsTransactionNameInstrumentation.java @@ -31,7 +31,6 @@ import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatchers; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -103,6 +102,6 @@ public ElementMatcher getMethodMatcher() { @Override public Collection getInstrumentationGroupNames() { - return Arrays.asList("jax-rs", "jax-rs-annotations"); + return Collections.singletonList("jax-rs"); } } diff --git a/apm-agent-plugins/apm-jaxws-plugin/pom.xml b/apm-agent-plugins/apm-jaxws-plugin/pom.xml new file mode 100644 index 0000000000..e7d09a718a --- /dev/null +++ b/apm-agent-plugins/apm-jaxws-plugin/pom.xml @@ -0,0 +1,24 @@ + + + + apm-agent-plugins + co.elastic.apm + 1.3.1-SNAPSHOT + + 4.0.0 + + apm-jaxws-plugin + + + + javax + javaee-api + 7.0 + test + + + + + diff --git a/apm-agent-plugins/apm-jaxws-plugin/src/main/java/co/elastic/apm/agent/jaxws/JaxWsTransactionNameInstrumentation.java b/apm-agent-plugins/apm-jaxws-plugin/src/main/java/co/elastic/apm/agent/jaxws/JaxWsTransactionNameInstrumentation.java new file mode 100644 index 0000000000..465d7f4b9a --- /dev/null +++ b/apm-agent-plugins/apm-jaxws-plugin/src/main/java/co/elastic/apm/agent/jaxws/JaxWsTransactionNameInstrumentation.java @@ -0,0 +1,98 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2019 Elastic and contributors + * %% + * 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. + * #L% + */ +package co.elastic.apm.agent.jaxws; + +import co.elastic.apm.agent.bci.ElasticApmInstrumentation; +import co.elastic.apm.agent.bci.bytebuddy.SimpleMethodSignatureOffsetMappingFactory.SimpleMethodSignature; +import co.elastic.apm.agent.impl.ElasticApmTracer; +import co.elastic.apm.agent.impl.stacktrace.StacktraceConfiguration; +import co.elastic.apm.agent.impl.transaction.Transaction; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.NamedElement; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import net.bytebuddy.matcher.ElementMatchers; + +import java.util.Collection; +import java.util.Collections; + +import static co.elastic.apm.agent.bci.bytebuddy.CustomElementMatchers.classLoaderCanLoadClass; +import static co.elastic.apm.agent.bci.bytebuddy.CustomElementMatchers.isInAnyPackage; +import static co.elastic.apm.agent.bci.bytebuddy.CustomElementMatchers.overridesOrImplementsMethodThat; +import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith; +import static net.bytebuddy.matcher.ElementMatchers.isBootstrapClassLoader; +import static net.bytebuddy.matcher.ElementMatchers.isInterface; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.not; + +public class JaxWsTransactionNameInstrumentation extends ElasticApmInstrumentation { + + private Collection applicationPackages = Collections.emptyList(); + + @Advice.OnMethodEnter(suppress = Throwable.class) + private static void setTransactionName(@SimpleMethodSignature String signature) { + if (tracer != null) { + final Transaction transaction = tracer.currentTransaction(); + if (transaction != null && transaction.getName().length() == 0) { + transaction.withName(signature); + } + } + } + + @Override + public void init(ElasticApmTracer tracer) { + applicationPackages = tracer.getConfig(StacktraceConfiguration.class).getApplicationPackages(); + } + + @Override + public ElementMatcher getTypeMatcherPreFilter() { + // setting application_packages makes this matcher more performant but is not required + // could lead to false negative matches when importing a 3rd party library whose JAX-WS resources are exposed + return isInAnyPackage(applicationPackages, ElementMatchers.any()); + } + + @Override + public ElementMatcher getTypeMatcher() { + // the implementations have to be annotated as well + // quote from javadoc: + // "Marks a Java class as implementing a Web Service, or a Java interface as defining a Web Service interface." + return isAnnotatedWith(named("javax.jws.WebService")).and(not(isInterface())); + } + + @Override + public ElementMatcher.Junction getClassLoaderMatcher() { + return not(isBootstrapClassLoader()) + .and(classLoaderCanLoadClass("javax.jws.WebService")); + } + + @Override + public ElementMatcher getMethodMatcher() { + return overridesOrImplementsMethodThat( + isAnnotatedWith( + named("javax.jws.WebMethod"))) + .onSuperClassesThat(isInAnyPackage(applicationPackages, ElementMatchers.any())); + } + + @Override + public Collection getInstrumentationGroupNames() { + return Collections.singletonList("jax-ws"); + } +} diff --git a/apm-agent-plugins/apm-jaxws-plugin/src/main/java/co/elastic/apm/agent/jaxws/package-info.java b/apm-agent-plugins/apm-jaxws-plugin/src/main/java/co/elastic/apm/agent/jaxws/package-info.java new file mode 100644 index 0000000000..84770a7083 --- /dev/null +++ b/apm-agent-plugins/apm-jaxws-plugin/src/main/java/co/elastic/apm/agent/jaxws/package-info.java @@ -0,0 +1,23 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2019 Elastic and contributors + * %% + * 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. + * #L% + */ +@NonnullApi +package co.elastic.apm.agent.jaxws; + +import co.elastic.apm.agent.annotation.NonnullApi; diff --git a/apm-agent-plugins/apm-jaxws-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.bci.ElasticApmInstrumentation b/apm-agent-plugins/apm-jaxws-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.bci.ElasticApmInstrumentation new file mode 100644 index 0000000000..bb99974ad1 --- /dev/null +++ b/apm-agent-plugins/apm-jaxws-plugin/src/main/resources/META-INF/services/co.elastic.apm.agent.bci.ElasticApmInstrumentation @@ -0,0 +1 @@ +co.elastic.apm.agent.jaxws.JaxWsTransactionNameInstrumentation diff --git a/apm-agent-plugins/apm-jaxws-plugin/src/test/java/co/elastic/apm/agent/jaxws/JaxWsTransactionNameInstrumentationTest.java b/apm-agent-plugins/apm-jaxws-plugin/src/test/java/co/elastic/apm/agent/jaxws/JaxWsTransactionNameInstrumentationTest.java new file mode 100644 index 0000000000..7d4ec8326f --- /dev/null +++ b/apm-agent-plugins/apm-jaxws-plugin/src/test/java/co/elastic/apm/agent/jaxws/JaxWsTransactionNameInstrumentationTest.java @@ -0,0 +1,71 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2019 Elastic and contributors + * %% + * 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. + * #L% + */ +package co.elastic.apm.agent.jaxws; + +import co.elastic.apm.agent.AbstractInstrumentationTest; +import co.elastic.apm.agent.impl.Scope; +import co.elastic.apm.agent.impl.transaction.Transaction; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import javax.jws.WebMethod; +import javax.jws.WebService; +import javax.jws.soap.SOAPBinding; + +import static org.assertj.core.api.Assertions.assertThat; + +class JaxWsTransactionNameInstrumentationTest extends AbstractInstrumentationTest { + + private HelloWorldService helloWorldService; + + @BeforeEach + void setUp() { + helloWorldService = new HelloWorldServiceImpl(); + } + + @Test + void testTransactionName() { + final Transaction transaction = tracer.startTransaction(); + try (Scope scope = transaction.activateInScope()) { + helloWorldService.sayHello(); + } finally { + transaction.end(); + } + assertThat(transaction.getName().toString()).isEqualTo("HelloWorldServiceImpl#sayHello"); + } + + @SOAPBinding(style = SOAPBinding.Style.RPC) + @WebService(targetNamespace = "elastic") + public interface HelloWorldService { + @WebMethod + String sayHello(); + } + + @WebService(serviceName = "HelloWorldService", portName = "HelloWorld", name = "HelloWorld", + endpointInterface = "co.elastic.apm.agent.jaxws.JaxWsTransactionNameInstrumentationTest.HelloWorldService", + targetNamespace = "elastic") + public static class HelloWorldServiceImpl implements HelloWorldService { + @Override + public String sayHello() { + return "Hello World"; + } + } + +} diff --git a/apm-agent-plugins/pom.xml b/apm-agent-plugins/pom.xml index 811820a35b..ad35e33650 100644 --- a/apm-agent-plugins/pom.xml +++ b/apm-agent-plugins/pom.xml @@ -24,6 +24,7 @@ apm-okhttp-plugin apm-java-concurrent-plugin apm-urlconnection-plugin + apm-jaxws-plugin diff --git a/docs/supported-technologies.asciidoc b/docs/supported-technologies.asciidoc index 9be1ee31e9..732230430a 100644 --- a/docs/supported-technologies.asciidoc +++ b/docs/supported-technologies.asciidoc @@ -45,26 +45,30 @@ the agent does not capture transactions. [[supported-web-frameworks]] === Web Frameworks |=== -|Framework |Supported versions | Description +|Framework |Supported versions | Description | Since |Servlet API |3+ |A transaction will be created for all incoming HTTP requests to your Servlet API-based application. See also <> +|1.0.0 |Spring Web MVC |4.x, 5.x |If you are using Spring MVC (for example with Spring Boot), the transactions are named based on your controllers (`ControllerClass#controllerMethod`). +|1.0.0 |JavaServer Faces |2.2.x, 2.3.x |If you are using JSF, transactions are named based on the requested Facelets and spans are captured for visibility into execution and rendering +|1.0.0 |Spring Boot |1.5+, 2.x |Supports embedded Tomcat, Jetty and Undertow +|1.0.0 |JAX-RS |2.x @@ -75,6 +79,18 @@ rendering This comes at the cost of increased startup times, however. Note: JAX-RS is only supported when running on a supported <>. +|1.0.0 + +|JAX-WS +| +|The transactions are named based on your `@javax.jws.WebService` annotated classes and `@javax.jws.WebMethod` annotated method names (`WebServiceClass#webMethod`). + Note that only the packages configured in <> are scanned for JAX-WS resources. + If you don't set this option, + all classes are scanned. + This comes at the cost of increased startup times, however. + + Note: JAX-WS is only supported when running on a supported <> and when using the HTTP binding. +|1.4.0 |=== @@ -168,6 +184,12 @@ The spans are named after the schema ` `, for example `GET elastic | | 1.4.0 +|JAX-WS client +| +|JAX-WS clients created via link:https://docs.oracle.com/javaee/7/api/javax/xml/ws/Service.html[`javax.xml.ws.Service`] + inherently support context propagation as they are using `HttpUrlConnection` underneath. +|1.4.0 + |=== @@ -193,10 +215,10 @@ This section lists all supported asynchronous frameworks. [float] [[supported-technologies-caveats]] === Caveats -* Tracing of asynchronous invocations (for example `java.util.concurrent.ExecutorService`) is currently not supported. * Certain OSGi containers need the following configuration setting in case you see exceptions like `java.lang.NoClassDefFoundError: co/elastic/apm/jdbc/StatementInstrumentation`: `org.osgi.framework.bootdelegation=co.elastic.apm.agent.*` * Other JVM languages, like Scala, Kotlin and Groovy have not been tested yet. * The agent does currently not support running on JVMs with an enabled `SecurityManager`. - You may see exceptions like this: `java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "getProtectionDomain")` + You may see exceptions like this: `java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "getProtectionDomain")`. + Try to grant `java.security.AllPermission` to the agent. diff --git a/elastic-apm-agent/pom.xml b/elastic-apm-agent/pom.xml index c9ada6d992..2f28c501aa 100644 --- a/elastic-apm-agent/pom.xml +++ b/elastic-apm-agent/pom.xml @@ -162,6 +162,11 @@ apm-jaxrs-plugin ${project.version} + + ${project.groupId} + apm-jaxws-plugin + ${project.version} + ${project.groupId} apm-jdbc-plugin diff --git a/integration-tests/simple-webapp-integration-test/README.md b/integration-tests/application-server-integration-tests/README.md similarity index 100% rename from integration-tests/simple-webapp-integration-test/README.md rename to integration-tests/application-server-integration-tests/README.md diff --git a/integration-tests/simple-webapp-integration-test/pom.xml b/integration-tests/application-server-integration-tests/pom.xml similarity index 98% rename from integration-tests/simple-webapp-integration-test/pom.xml rename to integration-tests/application-server-integration-tests/pom.xml index a01baf69b1..8be1bb75a3 100644 --- a/integration-tests/simple-webapp-integration-test/pom.xml +++ b/integration-tests/application-server-integration-tests/pom.xml @@ -8,7 +8,7 @@ 4.0.0 - simple-webapp-integration-test + application-server-integration-tests ${project.groupId}:${project.artifactId} diff --git a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/AbstractServletContainerIntegrationTest.java b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/AbstractServletContainerIntegrationTest.java similarity index 93% rename from integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/AbstractServletContainerIntegrationTest.java rename to integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/AbstractServletContainerIntegrationTest.java index 62fa398c3a..c62bd8bb0d 100644 --- a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/AbstractServletContainerIntegrationTest.java +++ b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/AbstractServletContainerIntegrationTest.java @@ -20,6 +20,7 @@ package co.elastic.apm.servlet; import co.elastic.apm.agent.MockReporter; +import co.elastic.apm.servlet.tests.TestApp; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import okhttp3.OkHttpClient; @@ -211,11 +212,11 @@ public void testAllScenarios() throws Exception { } } - void clearMockServerLog() { + public void clearMockServerLog() { mockServerContainer.getClient().clear(HttpRequest.request(), ClearType.LOG); } - JsonNode assertTransactionReported(String pathToTest, int expectedResponseCode) { + public JsonNode assertTransactionReported(String pathToTest, int expectedResponseCode) { final List reportedTransactions = getAllReported(500, this::getReportedTransactions, 1); JsonNode transaction = reportedTransactions.iterator().next(); assertThat(transaction.get("context").get("request").get("url").get("pathname").textValue()).isEqualTo(pathToTest); @@ -223,7 +224,7 @@ JsonNode assertTransactionReported(String pathToTest, int expectedResponseCode) return transaction; } - void executeAndValidateRequest(String pathToTest, String expectedContent, Integer expectedResponseCode) throws IOException, InterruptedException { + public void executeAndValidateRequest(String pathToTest, String expectedContent, Integer expectedResponseCode) throws IOException, InterruptedException { Response response = executeRequest(pathToTest); if (expectedResponseCode != null) { assertThat(response.code()).withFailMessage(response.toString() + getServerLogs()).isEqualTo(expectedResponseCode); @@ -235,7 +236,7 @@ void executeAndValidateRequest(String pathToTest, String expectedContent, Intege } } - Response executeRequest(String pathToTest) throws IOException { + public Response executeRequest(String pathToTest) throws IOException { return httpClient.newCall(new Request.Builder() .get() .url(getBaseUrl() + pathToTest) @@ -244,7 +245,7 @@ Response executeRequest(String pathToTest) throws IOException { } @Nonnull - List getAllReported(int timeoutMs, Supplier> supplier, int expected) { + public List getAllReported(int timeoutMs, Supplier> supplier, int expected) { long start = System.currentTimeMillis(); List reportedTransactions; do { @@ -255,7 +256,7 @@ List getAllReported(int timeoutMs, Supplier> supplier, } @Nonnull - List assertSpansTransactionId(int timeoutMs, Supplier> supplier, String transactionId) { + public List assertSpansTransactionId(int timeoutMs, Supplier> supplier, String transactionId) { long start = System.currentTimeMillis(); List reportedSpans; do { @@ -269,7 +270,7 @@ List assertSpansTransactionId(int timeoutMs, Supplier> } @Nonnull - List assertErrorContent(int timeoutMs, Supplier> supplier, String transactionId, String errorMessage) { + public List assertErrorContent(int timeoutMs, Supplier> supplier, String transactionId, String errorMessage) { long start = System.currentTimeMillis(); List reportedErrors; do { @@ -301,16 +302,16 @@ protected String getServerLogsPath() { } @NotNull - protected List getPathsToTest() { + public List getPathsToTest() { return Arrays.asList("/index.jsp", "/servlet", "/async-dispatch-servlet", "/async-start-servlet"); } @NotNull - protected List getPathsToTestErrors() { + public List getPathsToTestErrors() { return Arrays.asList("/index.jsp", "/servlet", "/async-dispatch-servlet", "/async-start-servlet"); } - protected boolean isExpectedStacktrace(String path) { + public boolean isExpectedStacktrace(String path) { return !path.equals("/async-start-servlet"); } @@ -318,19 +319,19 @@ private String getBaseUrl() { return "http://" + servletContainer.getContainerIpAddress() + ":" + servletContainer.getMappedPort(webPort); } - List getReportedTransactions() { + public List getReportedTransactions() { final List transactions = getEvents("transaction"); transactions.forEach(mockReporter::verifyTransactionSchema); return transactions; } - List getReportedSpans() { + public List getReportedSpans() { final List transactions = getEvents("span"); transactions.forEach(mockReporter::verifySpanSchema); return transactions; } - List getReportedErrors() { + public List getReportedErrors() { final List transactions = getEvents("error"); transactions.forEach(mockReporter::verifyErrorSchema); return transactions; @@ -354,7 +355,7 @@ private List getEvents(String eventType) { } } - void validateMetadata() { + public void validateMetadata() { try { final ObjectMapper objectMapper = new ObjectMapper(); final JsonNode payload; diff --git a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/JBossIT.java b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/JBossIT.java similarity index 92% rename from integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/JBossIT.java rename to integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/JBossIT.java index 9bf8c121e3..91c9da3844 100644 --- a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/JBossIT.java +++ b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/JBossIT.java @@ -19,6 +19,10 @@ */ package co.elastic.apm.servlet; +import co.elastic.apm.servlet.tests.JsfApplicationServerTestApp; +import co.elastic.apm.servlet.tests.ServletApiTestApp; +import co.elastic.apm.servlet.tests.SoapTestApp; +import co.elastic.apm.servlet.tests.TestApp; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.testcontainers.containers.GenericContainer; diff --git a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/JettyIT.java b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/JettyIT.java similarity index 90% rename from integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/JettyIT.java rename to integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/JettyIT.java index ac832e98f7..aa9e8d070e 100644 --- a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/JettyIT.java +++ b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/JettyIT.java @@ -19,6 +19,9 @@ */ package co.elastic.apm.servlet; +import co.elastic.apm.servlet.tests.JsfServletContainerTestApp; +import co.elastic.apm.servlet.tests.ServletApiTestApp; +import co.elastic.apm.servlet.tests.TestApp; import org.jetbrains.annotations.NotNull; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -59,12 +62,12 @@ protected void enableDebugging(GenericContainer servletContainer) { } @NotNull - protected List getPathsToTestErrors() { + public List getPathsToTestErrors() { return Arrays.asList("/index.jsp", "/servlet", "/async-dispatch-servlet"); } @Override - protected boolean isExpectedStacktrace(String path) { + public boolean isExpectedStacktrace(String path) { // only from version 9.4 Jetty includes a valid Throwable instance and only in the onComplete return version.equals("9.4") || !path.equals("/async-dispatch-servlet"); } diff --git a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/MockServerContainer.java b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/MockServerContainer.java similarity index 100% rename from integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/MockServerContainer.java rename to integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/MockServerContainer.java diff --git a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/PayaraIT.java b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/PayaraIT.java similarity index 94% rename from integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/PayaraIT.java rename to integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/PayaraIT.java index 6451fb559b..f4ed8c2fee 100644 --- a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/PayaraIT.java +++ b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/PayaraIT.java @@ -19,6 +19,9 @@ */ package co.elastic.apm.servlet; +import co.elastic.apm.servlet.tests.JsfApplicationServerTestApp; +import co.elastic.apm.servlet.tests.ServletApiTestApp; +import co.elastic.apm.servlet.tests.TestApp; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.testcontainers.containers.GenericContainer; diff --git a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/StandardOutLogConsumer.java b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/StandardOutLogConsumer.java similarity index 100% rename from integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/StandardOutLogConsumer.java rename to integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/StandardOutLogConsumer.java diff --git a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/TomcatIT.java b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/TomcatIT.java similarity index 92% rename from integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/TomcatIT.java rename to integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/TomcatIT.java index d6e315ec4c..7c39a406c2 100644 --- a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/TomcatIT.java +++ b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/TomcatIT.java @@ -19,6 +19,9 @@ */ package co.elastic.apm.servlet; +import co.elastic.apm.servlet.tests.JsfServletContainerTestApp; +import co.elastic.apm.servlet.tests.ServletApiTestApp; +import co.elastic.apm.servlet.tests.TestApp; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.testcontainers.containers.GenericContainer; diff --git a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/WebSphereIT.java b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/WebSphereIT.java similarity index 91% rename from integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/WebSphereIT.java rename to integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/WebSphereIT.java index 85b565ae5e..6a169bea47 100644 --- a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/WebSphereIT.java +++ b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/WebSphereIT.java @@ -19,6 +19,9 @@ */ package co.elastic.apm.servlet; +import co.elastic.apm.servlet.tests.JsfApplicationServerTestApp; +import co.elastic.apm.servlet.tests.ServletApiTestApp; +import co.elastic.apm.servlet.tests.TestApp; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.testcontainers.containers.GenericContainer; @@ -54,7 +57,7 @@ protected void enableDebugging(GenericContainer servletContainer) { } @Override - protected boolean isExpectedStacktrace(String path) { + public boolean isExpectedStacktrace(String path) { return true; } diff --git a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/WildFlyIT.java b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/WildFlyIT.java similarity index 91% rename from integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/WildFlyIT.java rename to integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/WildFlyIT.java index 09c0c4e6c4..df7e4d78cb 100644 --- a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/WildFlyIT.java +++ b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/WildFlyIT.java @@ -19,6 +19,10 @@ */ package co.elastic.apm.servlet; +import co.elastic.apm.servlet.tests.JsfApplicationServerTestApp; +import co.elastic.apm.servlet.tests.ServletApiTestApp; +import co.elastic.apm.servlet.tests.SoapTestApp; +import co.elastic.apm.servlet.tests.TestApp; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.testcontainers.containers.GenericContainer; diff --git a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/JsfApplicationServerTestApp.java b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/tests/JsfApplicationServerTestApp.java similarity index 67% rename from integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/JsfApplicationServerTestApp.java rename to integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/tests/JsfApplicationServerTestApp.java index 2bce097372..72a6a0dcd0 100644 --- a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/JsfApplicationServerTestApp.java +++ b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/tests/JsfApplicationServerTestApp.java @@ -1,5 +1,25 @@ -package co.elastic.apm.servlet; +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2019 Elastic and contributors + * %% + * 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. + * #L% + */ +package co.elastic.apm.servlet.tests; +import co.elastic.apm.servlet.AbstractServletContainerIntegrationTest; import com.fasterxml.jackson.databind.JsonNode; import java.io.IOException; @@ -8,14 +28,14 @@ import static org.assertj.core.api.Assertions.assertThat; -class JsfApplicationServerTestApp extends TestApp { +public class JsfApplicationServerTestApp extends TestApp { public JsfApplicationServerTestApp() { super("../jsf-app/jsf-app-dependent", "jsf-http-get.war", "/jsf-http-get/status.html"); } @Override - void test(AbstractServletContainerIntegrationTest test) throws Exception { + public void test(AbstractServletContainerIntegrationTest test) throws Exception { testJsfRequest(test, "/faces/index.xhtml", ""); testJsfRequest(test, "/faces/login.xhtml", "?name=Jack"); } diff --git a/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/tests/JsfServletContainerTestApp.java b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/tests/JsfServletContainerTestApp.java new file mode 100644 index 0000000000..c4a350dab7 --- /dev/null +++ b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/tests/JsfServletContainerTestApp.java @@ -0,0 +1,33 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2019 Elastic and contributors + * %% + * 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. + * #L% + */ +package co.elastic.apm.servlet.tests; + +import co.elastic.apm.servlet.AbstractServletContainerIntegrationTest; + +public class JsfServletContainerTestApp extends TestApp { + public JsfServletContainerTestApp() { + super("../jsf-app/jsf-app-standalone", "jsf-http-get.war", "/jsf-http-get/status.html"); + } + + @Override + public void test(AbstractServletContainerIntegrationTest test) throws Exception { + new JsfApplicationServerTestApp().test(test); + } +} diff --git a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/ServletApiTestApp.java b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/tests/ServletApiTestApp.java similarity index 95% rename from integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/ServletApiTestApp.java rename to integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/tests/ServletApiTestApp.java index bc32d881e4..ab20a5a714 100644 --- a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/ServletApiTestApp.java +++ b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/tests/ServletApiTestApp.java @@ -17,8 +17,9 @@ * limitations under the License. * #L% */ -package co.elastic.apm.servlet; +package co.elastic.apm.servlet.tests; +import co.elastic.apm.servlet.AbstractServletContainerIntegrationTest; import com.fasterxml.jackson.databind.JsonNode; import java.io.IOException; @@ -26,14 +27,14 @@ import static org.assertj.core.api.Assertions.assertThat; -class ServletApiTestApp extends TestApp { +public class ServletApiTestApp extends TestApp { public ServletApiTestApp() { super("../simple-webapp", "simple-webapp.war", "/simple-webapp/status.jsp"); } @Override - void test(AbstractServletContainerIntegrationTest test) throws Exception { + public void test(AbstractServletContainerIntegrationTest test) throws Exception { testTransactionReporting(test); testTransactionErrorReporting(test); testSpanErrorReporting(test); diff --git a/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/tests/SoapTestApp.java b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/tests/SoapTestApp.java new file mode 100644 index 0000000000..312f2d0fdc --- /dev/null +++ b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/tests/SoapTestApp.java @@ -0,0 +1,54 @@ +/*- + * #%L + * Elastic APM Java agent + * %% + * Copyright (C) 2018 - 2019 Elastic and contributors + * %% + * 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. + * #L% + */ +package co.elastic.apm.servlet.tests; + +import co.elastic.apm.servlet.AbstractServletContainerIntegrationTest; +import com.fasterxml.jackson.databind.JsonNode; +import okhttp3.Response; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class SoapTestApp extends TestApp { + public SoapTestApp() { + super("../soap-test", "soap-test.war", "/soap-test/status.html"); + } + + @Override + public void test(AbstractServletContainerIntegrationTest test) throws Exception { + final Response response = test.executeRequest("/soap-test/execute-soap-request"); + assertThat(response.code()).isEqualTo(200); + assertThat(response.body().string()).isNotEmpty(); + + final List reportedTransactions = test.getReportedTransactions(); + // there will also be another transaction for getting the WSDL but we don't need to assert on that + assertThat(reportedTransactions.stream().map(node -> node.get("name").textValue())).contains("HelloWorldServiceImpl#sayHello", "SoapClientServlet#doGet"); + final Set traceIds = reportedTransactions.stream().map(node -> node.get("trace_id").textValue()).collect(Collectors.toSet()); + assertThat(traceIds).hasSize(1); + + final List spans = test.getReportedSpans(); + // there will also be another span for getting the WSDL but we don't need to assert on that + assertThat(spans.stream().map(node -> node.get("trace_id").textValue()).collect(Collectors.toSet())).isEqualTo(traceIds); + assertThat(spans.stream().filter(span -> span.get("context").get("http").get("url").textValue().endsWith("/soap-test/HelloWorldService"))).isNotEmpty(); + } +} diff --git a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/TestApp.java b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/tests/TestApp.java similarity index 74% rename from integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/TestApp.java rename to integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/tests/TestApp.java index 06c98b3d0b..a0904bccd2 100644 --- a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/TestApp.java +++ b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/tests/TestApp.java @@ -17,14 +17,11 @@ * limitations under the License. * #L% */ -package co.elastic.apm.servlet; +package co.elastic.apm.servlet.tests; -import static org.assertj.core.api.Assertions.assertThat; +import co.elastic.apm.servlet.AbstractServletContainerIntegrationTest; public abstract class TestApp { - public static final TestApp JSF = new JsfApplicationServerTestApp(); - public static final TestApp JSF_STANDALONE = new JsfServletContainerTestApp(); - public static final TestApp SOAP = new SoapTestApp(); private final String modulePath; private final String appFileName; @@ -36,7 +33,7 @@ public abstract class TestApp { this.statusEndpoint = statusEndpoint; } - String getAppFilePath() { + public String getAppFilePath() { return modulePath + "/target/" + getAppFileName(); } @@ -48,6 +45,6 @@ public String getStatusEndpoint() { return statusEndpoint; } - abstract void test(AbstractServletContainerIntegrationTest test) throws Exception; + public abstract void test(AbstractServletContainerIntegrationTest test) throws Exception; } diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 2099d93eab..829d4bf658 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -13,7 +13,7 @@ simple-webapp jsf-app - simple-webapp-integration-test + application-server-integration-tests spring-boot-1-5 spring-boot-2 soap-test diff --git a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/JsfServletContainerTestApp.java b/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/JsfServletContainerTestApp.java deleted file mode 100644 index 90a0d172d8..0000000000 --- a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/JsfServletContainerTestApp.java +++ /dev/null @@ -1,12 +0,0 @@ -package co.elastic.apm.servlet; - -class JsfServletContainerTestApp extends TestApp { - public JsfServletContainerTestApp() { - super("../jsf-app/jsf-app-standalone", "jsf-http-get.war", "/jsf-http-get/status.html"); - } - - @Override - void test(AbstractServletContainerIntegrationTest test) throws Exception { - new JsfApplicationServerTestApp().test(test); - } -} diff --git a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/SoapTestApp.java b/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/SoapTestApp.java deleted file mode 100644 index 547b79055b..0000000000 --- a/integration-tests/simple-webapp-integration-test/src/test/java/co/elastic/apm/servlet/SoapTestApp.java +++ /dev/null @@ -1,18 +0,0 @@ -package co.elastic.apm.servlet; - -import okhttp3.Response; - -import static org.assertj.core.api.Assertions.assertThat; - -class SoapTestApp extends TestApp { - public SoapTestApp() { - super("../soap-test", "soap-test.war", "/soap-test/status.html"); - } - - @Override - void test(AbstractServletContainerIntegrationTest test) throws Exception { - final Response response = test.executeRequest("/soap-test/execute-soap-request"); - assertThat(response.code()).isEqualTo(200); - assertThat(response.body().string()).isNotEmpty(); - } -}