Convert jsp 2.3 tests from groovy to java (#11827)

This commit is contained in:
Jay DeLuca 2024-07-31 06:17:57 -04:00 committed by GitHub
parent 14d87e7323
commit e7a6398c71
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 1268 additions and 1029 deletions

View File

@ -1,539 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
import io.opentelemetry.instrumentation.test.utils.PortUtils
import io.opentelemetry.semconv.ExceptionAttributes
import io.opentelemetry.semconv.ServerAttributes
import io.opentelemetry.semconv.ClientAttributes
import io.opentelemetry.semconv.UserAgentAttributes
import io.opentelemetry.semconv.ErrorAttributes
import io.opentelemetry.semconv.HttpAttributes
import io.opentelemetry.semconv.NetworkAttributes
import io.opentelemetry.semconv.UrlAttributes
import io.opentelemetry.testing.internal.armeria.client.WebClient
import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse
import io.opentelemetry.testing.internal.armeria.common.HttpMethod
import io.opentelemetry.testing.internal.armeria.common.MediaType
import io.opentelemetry.testing.internal.armeria.common.RequestHeaders
import org.apache.catalina.Context
import org.apache.catalina.startup.Tomcat
import org.apache.jasper.JasperException
import spock.lang.Shared
import spock.lang.Unroll
import java.nio.file.Files
import static io.opentelemetry.api.trace.SpanKind.SERVER
import static io.opentelemetry.api.trace.StatusCode.ERROR
//TODO should this be HttpServerTest?
class JspInstrumentationBasicTests extends AgentInstrumentationSpecification {
@Shared
int port
@Shared
Tomcat tomcatServer
@Shared
Context appContext
@Shared
String jspWebappContext = "jsptest-context"
@Shared
File baseDir
@Shared
String baseUrl
@Shared
WebClient client
def setupSpec() {
baseDir = Files.createTempDirectory("jsp").toFile()
baseDir.deleteOnExit()
port = PortUtils.findOpenPort()
tomcatServer = new Tomcat()
tomcatServer.setBaseDir(baseDir.getAbsolutePath())
tomcatServer.setPort(port)
tomcatServer.getConnector()
// comment to debug
tomcatServer.setSilent(true)
// this is needed in tomcat 9, this triggers the creation of a connector, will not
// affect tomcat 7 and 8
// https://stackoverflow.com/questions/48998387/code-works-with-embedded-apache-tomcat-8-but-not-with-9-whats-changed
tomcatServer.getConnector()
baseUrl = "http://localhost:$port/$jspWebappContext"
client = WebClient.of(baseUrl)
appContext = tomcatServer.addWebapp("/$jspWebappContext",
JspInstrumentationBasicTests.getResource("/webapps/jsptest").getPath())
tomcatServer.start()
System.out.println(
"Tomcat server: http://" + tomcatServer.getHost().getName() + ":" + port + "/")
}
def cleanupSpec() {
tomcatServer.stop()
tomcatServer.destroy()
}
@Unroll
def "non-erroneous GET #test test"() {
when:
AggregatedHttpResponse res = client.get("/${jspFileName}").aggregate().join()
then:
assertTraces(1) {
trace(0, 3) {
span(0) {
def route = "/$jspWebappContext/$jspFileName"
hasNoParent()
name "GET $route"
kind SERVER
attributes {
"$UrlAttributes.URL_SCHEME" "http"
"$UrlAttributes.URL_PATH" route
"$HttpAttributes.HTTP_REQUEST_METHOD" "GET"
"$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200
"$UserAgentAttributes.USER_AGENT_ORIGINAL" String
"$HttpAttributes.HTTP_ROUTE" route
"$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
"$ServerAttributes.SERVER_ADDRESS" "localhost"
"$ServerAttributes.SERVER_PORT" port
"$ClientAttributes.CLIENT_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_PORT" Long
}
}
span(1) {
childOf span(0)
name "Compile /$jspFileName"
attributes {
"jsp.classFQCN" "org.apache.jsp.$jspClassNamePrefix$jspClassName"
"jsp.compiler" "org.apache.jasper.compiler.JDTCompiler"
}
}
span(2) {
childOf span(0)
name "Render /$jspFileName"
attributes {
"jsp.requestURL" "${baseUrl}/${jspFileName}"
}
}
}
}
res.status().code() == 200
where:
test | jspFileName | jspClassName | jspClassNamePrefix
"no java jsp" | "nojava.jsp" | "nojava_jsp" | ""
"basic loop jsp" | "common/loop.jsp" | "loop_jsp" | "common."
"invalid HTML markup" | "invalidMarkup.jsp" | "invalidMarkup_jsp" | ""
}
def "non-erroneous GET with query string"() {
setup:
String queryString = "HELLO"
when:
AggregatedHttpResponse res = client.get("/getQuery.jsp?${queryString}").aggregate().join()
then:
assertTraces(1) {
trace(0, 3) {
span(0) {
def route = "/$jspWebappContext/getQuery.jsp"
hasNoParent()
name "GET $route"
kind SERVER
attributes {
"$UrlAttributes.URL_SCHEME" "http"
"$UrlAttributes.URL_PATH" route
"$UrlAttributes.URL_QUERY" queryString
"$HttpAttributes.HTTP_REQUEST_METHOD" "GET"
"$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200
"$UserAgentAttributes.USER_AGENT_ORIGINAL" String
"$HttpAttributes.HTTP_ROUTE" route
"$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
"$ServerAttributes.SERVER_ADDRESS" "localhost"
"$ServerAttributes.SERVER_PORT" port
"$ClientAttributes.CLIENT_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_PORT" Long
}
}
span(1) {
childOf span(0)
name "Compile /getQuery.jsp"
attributes {
"jsp.classFQCN" "org.apache.jsp.getQuery_jsp"
"jsp.compiler" "org.apache.jasper.compiler.JDTCompiler"
}
}
span(2) {
childOf span(0)
name "Render /getQuery.jsp"
attributes {
"jsp.requestURL" "${baseUrl}/getQuery.jsp"
}
}
}
}
res.status().code() == 200
}
def "non-erroneous POST"() {
setup:
RequestHeaders headers = RequestHeaders.builder(HttpMethod.POST, "/post.jsp")
.contentType(MediaType.FORM_DATA)
.build()
when:
AggregatedHttpResponse res = client.execute(headers, "name=world").aggregate().join()
then:
assertTraces(1) {
trace(0, 3) {
span(0) {
def route = "/$jspWebappContext/post.jsp"
hasNoParent()
name "POST $route"
kind SERVER
attributes {
"$UrlAttributes.URL_SCHEME" "http"
"$UrlAttributes.URL_PATH" route
"$HttpAttributes.HTTP_REQUEST_METHOD" "POST"
"$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200
"$UserAgentAttributes.USER_AGENT_ORIGINAL" String
"$HttpAttributes.HTTP_ROUTE" route
"$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
"$ServerAttributes.SERVER_ADDRESS" "localhost"
"$ServerAttributes.SERVER_PORT" port
"$ClientAttributes.CLIENT_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_PORT" Long
}
}
span(1) {
childOf span(0)
name "Compile /post.jsp"
attributes {
"jsp.classFQCN" "org.apache.jsp.post_jsp"
"jsp.compiler" "org.apache.jasper.compiler.JDTCompiler"
}
}
span(2) {
childOf span(0)
name "Render /post.jsp"
attributes {
"jsp.requestURL" "${baseUrl}/post.jsp"
}
}
}
}
res.status().code() == 200
}
@Unroll
def "erroneous runtime errors GET jsp with #test test"() {
when:
AggregatedHttpResponse res = client.get("/${jspFileName}").aggregate().join()
then:
assertTraces(1) {
trace(0, 3) {
span(0) {
def route = "/$jspWebappContext/$jspFileName"
hasNoParent()
name "GET $route"
kind SERVER
status ERROR
event(0) {
eventName("exception")
attributes {
"$ExceptionAttributes.EXCEPTION_TYPE" { String tagExceptionType ->
return tagExceptionType == exceptionClass.getName() || tagExceptionType.contains(exceptionClass.getSimpleName())
}
"$ExceptionAttributes.EXCEPTION_MESSAGE" { String tagErrorMsg ->
return errorMessageOptional || tagErrorMsg instanceof String
}
"$ExceptionAttributes.EXCEPTION_STACKTRACE" String
}
}
attributes {
"$UrlAttributes.URL_SCHEME" "http"
"$UrlAttributes.URL_PATH" route
"$HttpAttributes.HTTP_REQUEST_METHOD" "GET"
"$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 500
"$UserAgentAttributes.USER_AGENT_ORIGINAL" String
"$HttpAttributes.HTTP_ROUTE" route
"$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
"$ServerAttributes.SERVER_ADDRESS" "localhost"
"$ServerAttributes.SERVER_PORT" port
"$ClientAttributes.CLIENT_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_PORT" Long
"$ErrorAttributes.ERROR_TYPE" "500"
}
}
span(1) {
childOf span(0)
name "Compile /$jspFileName"
attributes {
"jsp.classFQCN" "org.apache.jsp.$jspClassName"
"jsp.compiler" "org.apache.jasper.compiler.JDTCompiler"
}
}
span(2) {
childOf span(0)
name "Render /$jspFileName"
status ERROR
event(0) {
eventName("exception")
attributes {
"$ExceptionAttributes.EXCEPTION_TYPE" { String tagExceptionType ->
return tagExceptionType == exceptionClass.getName() || tagExceptionType.contains(exceptionClass.getSimpleName())
}
"$ExceptionAttributes.EXCEPTION_MESSAGE" { String tagErrorMsg ->
return errorMessageOptional || tagErrorMsg instanceof String
}
"$ExceptionAttributes.EXCEPTION_STACKTRACE" String
}
}
attributes {
"jsp.requestURL" "${baseUrl}/${jspFileName}"
}
}
}
}
res.status().code() == 500
where:
test | jspFileName | jspClassName | exceptionClass | errorMessageOptional
"java runtime error" | "runtimeError.jsp" | "runtimeError_jsp" | ArithmeticException | false
"invalid write" | "invalidWrite.jsp" | "invalidWrite_jsp" | IndexOutOfBoundsException | true
"missing query gives null" | "getQuery.jsp" | "getQuery_jsp" | NullPointerException | true
}
def "non-erroneous include plain HTML GET"() {
when:
AggregatedHttpResponse res = client.get("/includes/includeHtml.jsp").aggregate().join()
then:
assertTraces(1) {
trace(0, 3) {
span(0) {
def route = "/$jspWebappContext/includes/includeHtml.jsp"
hasNoParent()
name "GET $route"
kind SERVER
attributes {
"$UrlAttributes.URL_SCHEME" "http"
"$UrlAttributes.URL_PATH" route
"$HttpAttributes.HTTP_REQUEST_METHOD" "GET"
"$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200
"$UserAgentAttributes.USER_AGENT_ORIGINAL" String
"$HttpAttributes.HTTP_ROUTE" route
"$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
"$ServerAttributes.SERVER_ADDRESS" "localhost"
"$ServerAttributes.SERVER_PORT" port
"$ClientAttributes.CLIENT_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_PORT" Long
}
}
span(1) {
childOf span(0)
name "Compile /includes/includeHtml.jsp"
attributes {
"jsp.classFQCN" "org.apache.jsp.includes.includeHtml_jsp"
"jsp.compiler" "org.apache.jasper.compiler.JDTCompiler"
}
}
span(2) {
childOf span(0)
name "Render /includes/includeHtml.jsp"
attributes {
"jsp.requestURL" "${baseUrl}/includes/includeHtml.jsp"
}
}
}
}
res.status().code() == 200
}
def "non-erroneous multi GET"() {
when:
AggregatedHttpResponse res = client.get("/includes/includeMulti.jsp").aggregate().join()
then:
assertTraces(1) {
trace(0, 7) {
span(0) {
def route = "/$jspWebappContext/includes/includeMulti.jsp"
hasNoParent()
name "GET $route"
kind SERVER
attributes {
"$UrlAttributes.URL_SCHEME" "http"
"$UrlAttributes.URL_PATH" route
"$HttpAttributes.HTTP_REQUEST_METHOD" "GET"
"$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200
"$UserAgentAttributes.USER_AGENT_ORIGINAL" String
"$HttpAttributes.HTTP_ROUTE" route
"$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
"$ServerAttributes.SERVER_ADDRESS" "localhost"
"$ServerAttributes.SERVER_PORT" port
"$ClientAttributes.CLIENT_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_PORT" Long
}
}
span(1) {
childOf span(0)
name "Compile /includes/includeMulti.jsp"
attributes {
"jsp.classFQCN" "org.apache.jsp.includes.includeMulti_jsp"
"jsp.compiler" "org.apache.jasper.compiler.JDTCompiler"
}
}
span(2) {
childOf span(0)
name "Render /includes/includeMulti.jsp"
attributes {
"jsp.requestURL" "${baseUrl}/includes/includeMulti.jsp"
}
}
span(3) {
childOf span(2)
name "Compile /common/javaLoopH2.jsp"
attributes {
"jsp.classFQCN" "org.apache.jsp.common.javaLoopH2_jsp"
"jsp.compiler" "org.apache.jasper.compiler.JDTCompiler"
}
}
span(4) {
childOf span(2)
name "Render /common/javaLoopH2.jsp"
attributes {
"jsp.requestURL" "${baseUrl}/includes/includeMulti.jsp"
}
}
span(5) {
childOf span(2)
name "Compile /common/javaLoopH2.jsp"
attributes {
"jsp.classFQCN" "org.apache.jsp.common.javaLoopH2_jsp"
"jsp.compiler" "org.apache.jasper.compiler.JDTCompiler"
}
}
span(6) {
childOf span(2)
name "Render /common/javaLoopH2.jsp"
attributes {
"jsp.requestURL" "${baseUrl}/includes/includeMulti.jsp"
}
}
}
}
res.status().code() == 200
}
def "#test compile error should not produce render traces and spans"() {
when:
AggregatedHttpResponse res = client.get("/${jspFileName}").aggregate().join()
then:
assertTraces(1) {
trace(0, 2) {
span(0) {
def route = "/$jspWebappContext/$jspFileName"
hasNoParent()
name "GET $route"
kind SERVER
status ERROR
errorEvent(JasperException, String)
attributes {
"$UrlAttributes.URL_SCHEME" "http"
"$UrlAttributes.URL_PATH" route
"$HttpAttributes.HTTP_REQUEST_METHOD" "GET"
"$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 500
"$UserAgentAttributes.USER_AGENT_ORIGINAL" String
"$HttpAttributes.HTTP_ROUTE" route
"$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
"$ServerAttributes.SERVER_ADDRESS" "localhost"
"$ServerAttributes.SERVER_PORT" port
"$ClientAttributes.CLIENT_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_PORT" Long
"$ErrorAttributes.ERROR_TYPE" "500"
}
}
span(1) {
childOf span(0)
name "Compile /$jspFileName"
status ERROR
errorEvent(JasperException, String)
attributes {
"jsp.classFQCN" "org.apache.jsp.$jspClassNamePrefix$jspClassName"
"jsp.compiler" "org.apache.jasper.compiler.JDTCompiler"
}
}
}
}
res.status().code() == 500
where:
test | jspFileName | jspClassName | jspClassNamePrefix
"normal" | "compileError.jsp" | "compileError_jsp" | ""
"forward" | "forwards/forwardWithCompileError.jsp" | "forwardWithCompileError_jsp" | "forwards."
}
def "direct static file reference"() {
when:
AggregatedHttpResponse res = client.get("/${staticFile}").aggregate().join()
then:
res.status().code() == 200
assertTraces(1) {
trace(0, 1) {
span(0) {
def route = "/$jspWebappContext/*"
hasNoParent()
name "GET $route"
kind SERVER
attributes {
"$UrlAttributes.URL_SCHEME" "http"
"$UrlAttributes.URL_PATH" "/$jspWebappContext/$staticFile"
"$HttpAttributes.HTTP_REQUEST_METHOD" "GET"
"$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200
"$UserAgentAttributes.USER_AGENT_ORIGINAL" String
"$HttpAttributes.HTTP_ROUTE" route
"$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
"$ServerAttributes.SERVER_ADDRESS" "localhost"
"$ServerAttributes.SERVER_PORT" port
"$ClientAttributes.CLIENT_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_PORT" Long
}
}
}
}
where:
staticFile = "common/hello.html"
}
}

View File

@ -1,490 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
import io.opentelemetry.instrumentation.test.utils.PortUtils
import io.opentelemetry.semconv.ServerAttributes
import io.opentelemetry.semconv.ClientAttributes
import io.opentelemetry.semconv.UserAgentAttributes
import io.opentelemetry.semconv.ErrorAttributes
import io.opentelemetry.semconv.HttpAttributes
import io.opentelemetry.semconv.NetworkAttributes
import io.opentelemetry.semconv.UrlAttributes
import io.opentelemetry.testing.internal.armeria.client.WebClient
import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse
import org.apache.catalina.Context
import org.apache.catalina.startup.Tomcat
import org.apache.jasper.JasperException
import spock.lang.Shared
import spock.lang.Unroll
import java.nio.file.Files
import static io.opentelemetry.api.trace.SpanKind.SERVER
import static io.opentelemetry.api.trace.StatusCode.ERROR
import static io.opentelemetry.api.trace.StatusCode.UNSET
class JspInstrumentationForwardTests extends AgentInstrumentationSpecification {
@Shared
int port
@Shared
Tomcat tomcatServer
@Shared
Context appContext
@Shared
String jspWebappContext = "jsptest-context"
@Shared
File baseDir
@Shared
String baseUrl
@Shared
WebClient client
def setupSpec() {
baseDir = Files.createTempDirectory("jsp").toFile()
baseDir.deleteOnExit()
port = PortUtils.findOpenPort()
tomcatServer = new Tomcat()
tomcatServer.setBaseDir(baseDir.getAbsolutePath())
tomcatServer.setPort(port)
tomcatServer.getConnector()
// comment to debug
tomcatServer.setSilent(true)
// this is needed in tomcat 9, this triggers the creation of a connector, will not
// affect tomcat 7 and 8
// https://stackoverflow.com/questions/48998387/code-works-with-embedded-apache-tomcat-8-but-not-with-9-whats-changed
tomcatServer.getConnector()
baseUrl = "http://localhost:$port/$jspWebappContext"
client = WebClient.of(baseUrl)
appContext = tomcatServer.addWebapp("/$jspWebappContext",
JspInstrumentationForwardTests.getResource("/webapps/jsptest").getPath())
tomcatServer.start()
System.out.println(
"Tomcat server: http://" + tomcatServer.getHost().getName() + ":" + port + "/")
}
def cleanupSpec() {
tomcatServer.stop()
tomcatServer.destroy()
}
@Unroll
def "non-erroneous GET forward to #forwardTo"() {
when:
AggregatedHttpResponse res = client.get("/$forwardFromFileName").aggregate().join()
then:
assertTraces(1) {
trace(0, 5) {
span(0) {
def route = "/$jspWebappContext/$forwardFromFileName"
hasNoParent()
name "GET $route"
kind SERVER
attributes {
"$UrlAttributes.URL_SCHEME" "http"
"$UrlAttributes.URL_PATH" route
"$HttpAttributes.HTTP_REQUEST_METHOD" "GET"
"$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200
"$UserAgentAttributes.USER_AGENT_ORIGINAL" String
"$HttpAttributes.HTTP_ROUTE" route
"$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
"$ServerAttributes.SERVER_ADDRESS" "localhost"
"$ServerAttributes.SERVER_PORT" port
"$ClientAttributes.CLIENT_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_PORT" Long
}
}
span(1) {
childOf span(0)
name "Compile /$forwardFromFileName"
attributes {
"jsp.classFQCN" "org.apache.jsp.$jspForwardFromClassPrefix$jspForwardFromClassName"
"jsp.compiler" "org.apache.jasper.compiler.JDTCompiler"
}
}
span(2) {
childOf span(0)
name "Render /$forwardFromFileName"
attributes {
"jsp.requestURL" "${baseUrl}/$forwardFromFileName"
}
}
span(3) {
childOf span(2)
name "Compile /$forwardDestFileName"
attributes {
"jsp.classFQCN" "org.apache.jsp.$jspForwardDestClassPrefix$jspForwardDestClassName"
"jsp.compiler" "org.apache.jasper.compiler.JDTCompiler"
}
}
span(4) {
childOf span(2)
name "Render /$forwardDestFileName"
attributes {
"jsp.forwardOrigin" "/$forwardFromFileName"
"jsp.requestURL" "${baseUrl}/$forwardDestFileName"
}
}
}
}
res.status().code() == 200
where:
forwardTo | forwardFromFileName | forwardDestFileName | jspForwardFromClassName | jspForwardFromClassPrefix | jspForwardDestClassName | jspForwardDestClassPrefix
"no java jsp" | "forwards/forwardToNoJavaJsp.jsp" | "nojava.jsp" | "forwardToNoJavaJsp_jsp" | "forwards." | "nojava_jsp" | ""
"normal java jsp" | "forwards/forwardToSimpleJava.jsp" | "common/loop.jsp" | "forwardToSimpleJava_jsp" | "forwards." | "loop_jsp" | "common."
}
def "non-erroneous GET forward to plain HTML"() {
when:
AggregatedHttpResponse res = client.get("/forwards/forwardToHtml.jsp").aggregate().join()
then:
assertTraces(1) {
trace(0, 3) {
span(0) {
def route = "/$jspWebappContext/forwards/forwardToHtml.jsp"
hasNoParent()
name "GET $route"
kind SERVER
attributes {
"$UrlAttributes.URL_SCHEME" "http"
"$UrlAttributes.URL_PATH" route
"$HttpAttributes.HTTP_REQUEST_METHOD" "GET"
"$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200
"$UserAgentAttributes.USER_AGENT_ORIGINAL" String
"$HttpAttributes.HTTP_ROUTE" route
"$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
"$ServerAttributes.SERVER_ADDRESS" "localhost"
"$ServerAttributes.SERVER_PORT" port
"$ClientAttributes.CLIENT_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_PORT" Long
}
}
span(1) {
childOf span(0)
name "Compile /forwards/forwardToHtml.jsp"
attributes {
"jsp.classFQCN" "org.apache.jsp.forwards.forwardToHtml_jsp"
"jsp.compiler" "org.apache.jasper.compiler.JDTCompiler"
}
}
span(2) {
childOf span(0)
name "Render /forwards/forwardToHtml.jsp"
attributes {
"jsp.requestURL" "${baseUrl}/forwards/forwardToHtml.jsp"
}
}
}
}
res.status().code() == 200
}
def "non-erroneous GET forwarded to jsp with multiple includes"() {
when:
AggregatedHttpResponse res = client.get("/forwards/forwardToIncludeMulti.jsp").aggregate().join()
then:
assertTraces(1) {
trace(0, 9) {
span(0) {
def route = "/$jspWebappContext/forwards/forwardToIncludeMulti.jsp"
hasNoParent()
name "GET $route"
kind SERVER
attributes {
"$UrlAttributes.URL_SCHEME" "http"
"$UrlAttributes.URL_PATH" route
"$HttpAttributes.HTTP_REQUEST_METHOD" "GET"
"$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200
"$UserAgentAttributes.USER_AGENT_ORIGINAL" String
"$HttpAttributes.HTTP_ROUTE" route
"$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
"$ServerAttributes.SERVER_ADDRESS" "localhost"
"$ServerAttributes.SERVER_PORT" port
"$ClientAttributes.CLIENT_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_PORT" Long
}
}
span(1) {
childOf span(0)
name "Compile /forwards/forwardToIncludeMulti.jsp"
attributes {
"jsp.classFQCN" "org.apache.jsp.forwards.forwardToIncludeMulti_jsp"
"jsp.compiler" "org.apache.jasper.compiler.JDTCompiler"
}
}
span(2) {
childOf span(0)
name "Render /forwards/forwardToIncludeMulti.jsp"
attributes {
"jsp.requestURL" "${baseUrl}/forwards/forwardToIncludeMulti.jsp"
}
}
span(3) {
childOf span(2)
name "Compile /includes/includeMulti.jsp"
attributes {
"jsp.classFQCN" "org.apache.jsp.includes.includeMulti_jsp"
"jsp.compiler" "org.apache.jasper.compiler.JDTCompiler"
}
}
span(4) {
childOf span(2)
name "Render /includes/includeMulti.jsp"
attributes {
"jsp.forwardOrigin" "/forwards/forwardToIncludeMulti.jsp"
"jsp.requestURL" "${baseUrl}/includes/includeMulti.jsp"
}
}
span(5) {
childOf span(4)
name "Compile /common/javaLoopH2.jsp"
attributes {
"jsp.classFQCN" "org.apache.jsp.common.javaLoopH2_jsp"
"jsp.compiler" "org.apache.jasper.compiler.JDTCompiler"
}
}
span(6) {
childOf span(4)
name "Render /common/javaLoopH2.jsp"
attributes {
"jsp.forwardOrigin" "/forwards/forwardToIncludeMulti.jsp"
"jsp.requestURL" "${baseUrl}/includes/includeMulti.jsp"
}
}
span(7) {
childOf span(4)
name "Compile /common/javaLoopH2.jsp"
attributes {
"jsp.classFQCN" "org.apache.jsp.common.javaLoopH2_jsp"
"jsp.compiler" "org.apache.jasper.compiler.JDTCompiler"
}
}
span(8) {
childOf span(4)
name "Render /common/javaLoopH2.jsp"
attributes {
"jsp.forwardOrigin" "/forwards/forwardToIncludeMulti.jsp"
"jsp.requestURL" "${baseUrl}/includes/includeMulti.jsp"
}
}
}
}
res.status().code() == 200
}
def "non-erroneous GET forward to another forward (2 forwards)"() {
when:
AggregatedHttpResponse res = client.get("/forwards/forwardToJspForward.jsp").aggregate().join()
then:
assertTraces(1) {
trace(0, 7) {
span(0) {
def route = "/$jspWebappContext/forwards/forwardToJspForward.jsp"
hasNoParent()
name "GET $route"
kind SERVER
attributes {
"$UrlAttributes.URL_SCHEME" "http"
"$UrlAttributes.URL_PATH" route
"$HttpAttributes.HTTP_REQUEST_METHOD" "GET"
"$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200
"$UserAgentAttributes.USER_AGENT_ORIGINAL" String
"$HttpAttributes.HTTP_ROUTE" route
"$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
"$ServerAttributes.SERVER_ADDRESS" "localhost"
"$ServerAttributes.SERVER_PORT" port
"$ClientAttributes.CLIENT_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_PORT" Long
}
}
span(1) {
childOf span(0)
name "Compile /forwards/forwardToJspForward.jsp"
attributes {
"jsp.classFQCN" "org.apache.jsp.forwards.forwardToJspForward_jsp"
"jsp.compiler" "org.apache.jasper.compiler.JDTCompiler"
}
}
span(2) {
childOf span(0)
name "Render /forwards/forwardToJspForward.jsp"
attributes {
"jsp.requestURL" "${baseUrl}/forwards/forwardToJspForward.jsp"
}
}
span(3) {
childOf span(2)
name "Compile /forwards/forwardToSimpleJava.jsp"
attributes {
"jsp.classFQCN" "org.apache.jsp.forwards.forwardToSimpleJava_jsp"
"jsp.compiler" "org.apache.jasper.compiler.JDTCompiler"
}
}
span(4) {
childOf span(2)
name "Render /forwards/forwardToSimpleJava.jsp"
attributes {
"jsp.forwardOrigin" "/forwards/forwardToJspForward.jsp"
"jsp.requestURL" "${baseUrl}/forwards/forwardToSimpleJava.jsp"
}
}
span(5) {
childOf span(4)
name "Compile /common/loop.jsp"
attributes {
"jsp.classFQCN" "org.apache.jsp.common.loop_jsp"
"jsp.compiler" "org.apache.jasper.compiler.JDTCompiler"
}
}
span(6) {
childOf span(4)
name "Render /common/loop.jsp"
attributes {
"jsp.forwardOrigin" "/forwards/forwardToJspForward.jsp"
"jsp.requestURL" "${baseUrl}/common/loop.jsp"
}
}
}
}
res.status().code() == 200
}
def "forward to jsp with compile error should not produce a 2nd render span"() {
when:
AggregatedHttpResponse res = client.get("/forwards/forwardToCompileError.jsp").aggregate().join()
then:
assertTraces(1) {
trace(0, 4) {
span(0) {
def route = "/$jspWebappContext/forwards/forwardToCompileError.jsp"
hasNoParent()
name "GET $route"
kind SERVER
status ERROR
errorEvent(JasperException, String)
attributes {
"$UrlAttributes.URL_SCHEME" "http"
"$UrlAttributes.URL_PATH" route
"$HttpAttributes.HTTP_REQUEST_METHOD" "GET"
"$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 500
"$UserAgentAttributes.USER_AGENT_ORIGINAL" String
"$HttpAttributes.HTTP_ROUTE" route
"$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
"$ServerAttributes.SERVER_ADDRESS" "localhost"
"$ServerAttributes.SERVER_PORT" port
"$ClientAttributes.CLIENT_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_PORT" Long
"$ErrorAttributes.ERROR_TYPE" "500"
}
}
span(1) {
childOf span(0)
name "Compile /forwards/forwardToCompileError.jsp"
attributes {
"jsp.classFQCN" "org.apache.jsp.forwards.forwardToCompileError_jsp"
"jsp.compiler" "org.apache.jasper.compiler.JDTCompiler"
}
}
span(2) {
childOf span(0)
name "Render /forwards/forwardToCompileError.jsp"
status ERROR
errorEvent(JasperException, String)
attributes {
"jsp.requestURL" "${baseUrl}/forwards/forwardToCompileError.jsp"
}
}
span(3) {
childOf span(2)
name "Compile /compileError.jsp"
status ERROR
errorEvent(JasperException, String)
attributes {
"jsp.classFQCN" "org.apache.jsp.compileError_jsp"
"jsp.compiler" "org.apache.jasper.compiler.JDTCompiler"
}
}
}
}
res.status().code() == 500
}
def "forward to non existent jsp should be 404"() {
when:
AggregatedHttpResponse res = client.get("/forwards/forwardToNonExistent.jsp").aggregate().join()
then:
assertTraces(1) {
trace(0, 4) {
span(0) {
def route = "/$jspWebappContext/forwards/forwardToNonExistent.jsp"
hasNoParent()
name "GET $route"
kind SERVER
status UNSET
attributes {
"$UrlAttributes.URL_SCHEME" "http"
"$UrlAttributes.URL_PATH" route
"$HttpAttributes.HTTP_REQUEST_METHOD" "GET"
"$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 404
"$UserAgentAttributes.USER_AGENT_ORIGINAL" String
"$HttpAttributes.HTTP_ROUTE" route
"$NetworkAttributes.NETWORK_PROTOCOL_VERSION" "1.1"
"$ServerAttributes.SERVER_ADDRESS" "localhost"
"$ServerAttributes.SERVER_PORT" port
"$ClientAttributes.CLIENT_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_ADDRESS" "127.0.0.1"
"$NetworkAttributes.NETWORK_PEER_PORT" Long
}
}
span(1) {
childOf span(0)
name "Compile /forwards/forwardToNonExistent.jsp"
attributes {
"jsp.classFQCN" "org.apache.jsp.forwards.forwardToNonExistent_jsp"
"jsp.compiler" "org.apache.jasper.compiler.JDTCompiler"
}
}
span(2) {
childOf span(0)
name "Render /forwards/forwardToNonExistent.jsp"
attributes {
"jsp.requestURL" "${baseUrl}/forwards/forwardToNonExistent.jsp"
}
}
span(3) {
childOf span(2)
name "ResponseFacade.sendError"
}
}
}
res.status().code() == 404
}
}

View File

@ -0,0 +1,488 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.jsp;
import static io.opentelemetry.api.common.AttributeKey.stringKey;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerUsingTest;
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerInstrumentationExtension;
import io.opentelemetry.sdk.trace.data.StatusData;
import io.opentelemetry.semconv.ClientAttributes;
import io.opentelemetry.semconv.ExceptionAttributes;
import io.opentelemetry.semconv.HttpAttributes;
import io.opentelemetry.semconv.NetworkAttributes;
import io.opentelemetry.semconv.ServerAttributes;
import io.opentelemetry.semconv.UrlAttributes;
import io.opentelemetry.semconv.UserAgentAttributes;
import io.opentelemetry.testing.internal.armeria.client.WebClient;
import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse;
import io.opentelemetry.testing.internal.armeria.common.HttpMethod;
import io.opentelemetry.testing.internal.armeria.common.MediaType;
import io.opentelemetry.testing.internal.armeria.common.RequestHeaders;
import java.io.File;
import java.nio.file.Files;
import java.util.stream.Stream;
import org.apache.catalina.startup.Tomcat;
import org.apache.jasper.JasperException;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
import org.junit.jupiter.params.provider.ArgumentsSource;
import org.junit.jupiter.params.provider.ValueSource;
class JspInstrumentationBasicTests extends AbstractHttpServerUsingTest<Tomcat> {
@RegisterExtension
public static final InstrumentationExtension testing =
HttpServerInstrumentationExtension.forAgent();
private static JspSpanAssertions spanAsserts;
@Override
protected Tomcat setupServer() throws Exception {
File baseDir = Files.createTempDirectory("jsp").toFile();
baseDir.deleteOnExit();
Tomcat tomcatServer = new Tomcat();
tomcatServer.setBaseDir(baseDir.getAbsolutePath());
tomcatServer.setPort(port);
tomcatServer.getConnector();
// comment to debug
tomcatServer.setSilent(true);
// this is needed in tomcat 9, this triggers the creation of a connector, will not
// affect tomcat 7 and 8
// https://stackoverflow.com/questions/48998387/code-works-with-embedded-apache-tomcat-8-but-not-with-9-whats-changed
tomcatServer.getConnector();
String baseUrl = "http://localhost:" + port + "/" + getContextPath();
spanAsserts = new JspSpanAssertions(baseUrl, port);
client = WebClient.of(baseUrl);
tomcatServer.addWebapp(
"/" + getContextPath(),
JspInstrumentationBasicTests.class.getResource("/webapps/jsptest").getPath());
tomcatServer.start();
return tomcatServer;
}
@Override
protected void stopServer(Tomcat tomcat) throws Exception {
tomcat.stop();
tomcat.destroy();
}
@Override
protected String getContextPath() {
return "jsptest-context";
}
@BeforeAll
protected void setUp() {
startServer();
}
@AfterAll
protected void cleanUp() {
cleanupServer();
}
@ParameterizedTest(name = "GET {0}")
@ArgumentsSource(NonErroneousArgs.class)
void testNonErroneousGet(
String testName, String jspFileName, String jspClassName, String jspClassNamePrefix) {
AggregatedHttpResponse res = client.get(jspFileName).aggregate().join();
assertThat(res.status().code()).isEqualTo(200);
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
spanAsserts.assertServerSpan(
span,
new JspSpanAssertionBuilder()
.withMethod("GET")
.withRoute("/" + getContextPath() + jspFileName)
.withResponseStatus(200)
.build()),
span ->
spanAsserts.assertCompileSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute(jspFileName)
.withClassName(jspClassNamePrefix + jspClassName)
.build()),
span ->
spanAsserts.assertRenderSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute(jspFileName)
.build())));
}
static class NonErroneousArgs implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return Stream.of(
Arguments.of("no java jsp", "/nojava.jsp", "nojava_jsp", ""),
Arguments.of("basic loop jsp", "/common/loop.jsp", "loop_jsp", "common."),
Arguments.of("invalid HTML markup", "/invalidMarkup.jsp", "invalidMarkup_jsp", ""));
}
}
@Test
void testNonErroneousGetWithQueryString() {
String queryString = "HELLO";
String route = "/" + getContextPath() + "/getQuery.jsp";
AggregatedHttpResponse res = client.get("/getQuery.jsp?" + queryString).aggregate().join();
assertThat(res.status().code()).isEqualTo(200);
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
span.hasName("GET " + route)
.hasNoParent()
.hasKind(SpanKind.SERVER)
.hasAttributesSatisfyingExactly(
equalTo(UrlAttributes.URL_SCHEME, "http"),
equalTo(UrlAttributes.URL_PATH, route),
equalTo(UrlAttributes.URL_QUERY, queryString),
equalTo(HttpAttributes.HTTP_REQUEST_METHOD, "GET"),
equalTo(HttpAttributes.HTTP_RESPONSE_STATUS_CODE, 200),
satisfies(
UserAgentAttributes.USER_AGENT_ORIGINAL,
val -> val.isInstanceOf(String.class)),
equalTo(HttpAttributes.HTTP_ROUTE, route),
equalTo(NetworkAttributes.NETWORK_PROTOCOL_VERSION, "1.1"),
equalTo(ServerAttributes.SERVER_ADDRESS, "localhost"),
equalTo(ServerAttributes.SERVER_PORT, port),
equalTo(ClientAttributes.CLIENT_ADDRESS, "127.0.0.1"),
equalTo(NetworkAttributes.NETWORK_PEER_ADDRESS, "127.0.0.1"),
satisfies(
NetworkAttributes.NETWORK_PEER_PORT,
val -> val.isInstanceOf(Long.class))),
span ->
spanAsserts.assertCompileSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute("/getQuery.jsp")
.withClassName("getQuery_jsp")
.build()),
span ->
spanAsserts.assertRenderSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute("/getQuery.jsp")
.build())));
}
@Test
void testNonErroneousPost() {
RequestHeaders headers =
RequestHeaders.builder(HttpMethod.POST, "/post.jsp")
.contentType(MediaType.FORM_DATA)
.build();
AggregatedHttpResponse res = client.execute(headers, "name=world").aggregate().join();
assertThat(res.status().code()).isEqualTo(200);
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
spanAsserts.assertServerSpan(
span,
new JspSpanAssertionBuilder()
.withMethod("POST")
.withRoute("/" + getContextPath() + "/post.jsp")
.withResponseStatus(200)
.build()),
span ->
spanAsserts.assertCompileSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute("/post.jsp")
.withClassName("post_jsp")
.build()),
span ->
spanAsserts.assertRenderSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute("/post.jsp")
.build())));
}
@ParameterizedTest(name = "GET jsp with {0}")
@ArgumentsSource(ErroneousRuntimeErrorsArgs.class)
void testErroneousRuntimeErrorsGet(
String testName,
String jspFileName,
String jspClassName,
Class<?> exceptionClass,
boolean errorMessageOptional) {
AggregatedHttpResponse res = client.get(jspFileName).aggregate().join();
assertThat(res.status().code()).isEqualTo(500);
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
spanAsserts.assertServerSpan(
span,
new JspSpanAssertionBuilder()
.withMethod("GET")
.withRoute("/" + getContextPath() + jspFileName)
.withResponseStatus(500)
.withExceptionClass(exceptionClass)
.withErrorMessageOptional(errorMessageOptional)
.build()),
span ->
spanAsserts.assertCompileSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute(jspFileName)
.withClassName(jspClassName)
.build()),
span ->
spanAsserts.assertRenderSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute(jspFileName)
.withErrorMessageOptional(errorMessageOptional)
.build())));
}
static class ErroneousRuntimeErrorsArgs implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return Stream.of(
Arguments.of(
"java runtime error",
"/runtimeError.jsp",
"runtimeError_jsp",
ArithmeticException.class,
false),
Arguments.of(
"invalid write",
"/invalidWrite.jsp",
"invalidWrite_jsp",
IndexOutOfBoundsException.class,
true),
Arguments.of(
"invalid write", "/getQuery.jsp", "getQuery_jsp", NullPointerException.class, true));
}
}
@Test
void testNonErroneousIncludePlainHtmlGet() {
AggregatedHttpResponse res = client.get("/includes/includeHtml.jsp").aggregate().join();
assertThat(res.status().code()).isEqualTo(200);
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
spanAsserts.assertServerSpan(
span,
new JspSpanAssertionBuilder()
.withMethod("GET")
.withRoute("/" + getContextPath() + "/includes/includeHtml.jsp")
.withResponseStatus(200)
.build()),
span ->
spanAsserts.assertCompileSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute("/includes/includeHtml.jsp")
.withClassName("includes.includeHtml_jsp")
.build()),
span ->
spanAsserts.assertRenderSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute("/includes/includeHtml.jsp")
.build())));
}
@Test
void testNonErroneousMultiGet() {
AggregatedHttpResponse res = client.get("/includes/includeMulti.jsp").aggregate().join();
assertThat(res.status().code()).isEqualTo(200);
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
spanAsserts.assertServerSpan(
span,
new JspSpanAssertionBuilder()
.withMethod("GET")
.withRoute("/" + getContextPath() + "/includes/includeMulti.jsp")
.withResponseStatus(200)
.build()),
span ->
spanAsserts.assertCompileSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute("/includes/includeMulti.jsp")
.withClassName("includes.includeMulti_jsp")
.build()),
span ->
spanAsserts.assertRenderSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute("/includes/includeMulti.jsp")
.build()),
span ->
spanAsserts.assertCompileSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(2))
.withRoute("/common/javaLoopH2.jsp")
.withClassName("common.javaLoopH2_jsp")
.build()),
span ->
spanAsserts.assertRenderSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(2))
.withRoute("/common/javaLoopH2.jsp")
.withRequestUrlOverride("/includes/includeMulti.jsp")
.build()),
span ->
spanAsserts.assertCompileSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(2))
.withRoute("/common/javaLoopH2.jsp")
.withClassName("common.javaLoopH2_jsp")
.build()),
span ->
spanAsserts.assertRenderSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(2))
.withRoute("/common/javaLoopH2.jsp")
.withRequestUrlOverride("/includes/includeMulti.jsp")
.build())));
}
@ParameterizedTest
@ArgumentsSource(CompileErrorsArgs.class)
void testCompileErrorShouldNotProduceRenderTracesAndSpans(
String jspFileName, String jspClassName, String jspClassNamePrefix) {
AggregatedHttpResponse res = client.get(jspFileName).aggregate().join();
assertThat(res.status().code()).isEqualTo(500);
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
spanAsserts.assertServerSpan(
span,
new JspSpanAssertionBuilder()
.withMethod("GET")
.withRoute("/" + getContextPath() + jspFileName)
.withResponseStatus(500)
.withExceptionClass(JasperException.class)
.build()),
span ->
span.hasName("Compile " + jspFileName)
.hasParent(trace.getSpan(0))
.hasStatus(StatusData.error())
.hasEventsSatisfyingExactly(
event ->
event
.hasName("exception")
.hasAttributesSatisfyingExactly(
equalTo(
ExceptionAttributes.EXCEPTION_TYPE,
JasperException.class.getCanonicalName()),
satisfies(
ExceptionAttributes.EXCEPTION_STACKTRACE,
val -> val.isInstanceOf(String.class)),
satisfies(
ExceptionAttributes.EXCEPTION_MESSAGE,
val -> val.isInstanceOf(String.class))))
.hasAttributesSatisfyingExactly(
equalTo(
stringKey("jsp.classFQCN"),
"org.apache.jsp." + jspClassNamePrefix + jspClassName),
equalTo(
stringKey("jsp.compiler"),
"org.apache.jasper.compiler.JDTCompiler"))));
}
static class CompileErrorsArgs implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return Stream.of(
Arguments.of("/compileError.jsp", "compileError_jsp", ""),
Arguments.of(
"/forwards/forwardWithCompileError.jsp", "forwardWithCompileError_jsp", "forwards."));
}
}
@ParameterizedTest
@ValueSource(strings = {"/common/hello.html"})
void testDirectStaticFileReference(String staticFile) {
String route = "/" + getContextPath() + "/*";
AggregatedHttpResponse res = client.get(staticFile).aggregate().join();
assertThat(res.status().code()).isEqualTo(200);
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
span.hasName("GET " + route)
.hasNoParent()
.hasKind(SpanKind.SERVER)
.hasAttributesSatisfyingExactly(
equalTo(UrlAttributes.URL_SCHEME, "http"),
equalTo(UrlAttributes.URL_PATH, "/" + getContextPath() + staticFile),
equalTo(HttpAttributes.HTTP_REQUEST_METHOD, "GET"),
equalTo(HttpAttributes.HTTP_RESPONSE_STATUS_CODE, 200),
satisfies(
UserAgentAttributes.USER_AGENT_ORIGINAL,
val -> val.isInstanceOf(String.class)),
equalTo(HttpAttributes.HTTP_ROUTE, route),
equalTo(NetworkAttributes.NETWORK_PROTOCOL_VERSION, "1.1"),
equalTo(ServerAttributes.SERVER_ADDRESS, "localhost"),
equalTo(ServerAttributes.SERVER_PORT, port),
equalTo(ClientAttributes.CLIENT_ADDRESS, "127.0.0.1"),
equalTo(NetworkAttributes.NETWORK_PEER_ADDRESS, "127.0.0.1"),
satisfies(
NetworkAttributes.NETWORK_PEER_PORT,
val -> val.isInstanceOf(Long.class)))));
}
}

View File

@ -0,0 +1,454 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.jsp;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerUsingTest;
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerInstrumentationExtension;
import io.opentelemetry.sdk.trace.data.StatusData;
import io.opentelemetry.semconv.ClientAttributes;
import io.opentelemetry.semconv.HttpAttributes;
import io.opentelemetry.semconv.NetworkAttributes;
import io.opentelemetry.semconv.ServerAttributes;
import io.opentelemetry.semconv.UrlAttributes;
import io.opentelemetry.semconv.UserAgentAttributes;
import io.opentelemetry.testing.internal.armeria.client.WebClient;
import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse;
import java.io.File;
import java.nio.file.Files;
import java.util.stream.Stream;
import org.apache.catalina.startup.Tomcat;
import org.apache.jasper.JasperException;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
import org.junit.jupiter.params.provider.ArgumentsSource;
class JspInstrumentationForwardTests extends AbstractHttpServerUsingTest<Tomcat> {
@RegisterExtension
public static final InstrumentationExtension testing =
HttpServerInstrumentationExtension.forAgent();
private static JspSpanAssertions spanAsserts;
@Override
protected Tomcat setupServer() throws Exception {
File baseDir = Files.createTempDirectory("jsp").toFile();
baseDir.deleteOnExit();
Tomcat tomcatServer = new Tomcat();
tomcatServer.setBaseDir(baseDir.getAbsolutePath());
tomcatServer.setPort(port);
tomcatServer.getConnector();
// comment to debug
tomcatServer.setSilent(true);
// this is needed in tomcat 9, this triggers the creation of a connector, will not
// affect tomcat 7 and 8
// https://stackoverflow.com/questions/48998387/code-works-with-embedded-apache-tomcat-8-but-not-with-9-whats-changed
tomcatServer.getConnector();
String baseUrl = "http://localhost:" + port + "/" + getContextPath();
spanAsserts = new JspSpanAssertions(baseUrl, port);
client = WebClient.of(baseUrl);
tomcatServer.addWebapp(
"/" + getContextPath(),
JspInstrumentationForwardTests.class.getResource("/webapps/jsptest").getPath());
tomcatServer.start();
return tomcatServer;
}
@Override
protected void stopServer(Tomcat tomcat) throws Exception {
tomcat.stop();
tomcat.destroy();
}
@Override
protected String getContextPath() {
return "jsptest-context";
}
@BeforeAll
protected void setUp() {
startServer();
}
@AfterAll
protected void cleanUp() {
cleanupServer();
}
@ParameterizedTest(name = "Forward to {0}")
@ArgumentsSource(NonErroneousGetForwardArgs.class)
void testNonErroneousGetForwardTo(
String name,
String forwardFromFileName,
String forwardDestFileName,
String jspForwardFromClassName,
String jspForwardFromClassPrefix,
String jspForwardDestClassName,
String jspForwardDestClassPrefix) {
AggregatedHttpResponse res = client.get(forwardFromFileName).aggregate().join();
assertThat(res.status().code()).isEqualTo(200);
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
spanAsserts.assertServerSpan(
span,
new JspSpanAssertionBuilder()
.withMethod("GET")
.withRoute("/" + getContextPath() + forwardFromFileName)
.withResponseStatus(200)
.build()),
span ->
spanAsserts.assertCompileSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute(forwardFromFileName)
.withClassName(jspForwardFromClassPrefix + jspForwardFromClassName)
.build()),
span ->
spanAsserts.assertRenderSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute(forwardFromFileName)
.build()),
span ->
spanAsserts.assertCompileSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(2))
.withRoute(forwardDestFileName)
.withClassName(jspForwardDestClassPrefix + jspForwardDestClassName)
.build()),
span ->
spanAsserts.assertRenderSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(2))
.withRoute(forwardDestFileName)
.build())));
}
static class NonErroneousGetForwardArgs implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return Stream.of(
Arguments.of(
"no java jsp",
"/forwards/forwardToNoJavaJsp.jsp",
"/nojava.jsp",
"forwardToNoJavaJsp_jsp",
"forwards.",
"nojava_jsp",
""),
Arguments.of(
"normal java jsp",
"/forwards/forwardToSimpleJava.jsp",
"/common/loop.jsp",
"forwardToSimpleJava_jsp",
"forwards.",
"loop_jsp",
"common."));
}
}
@Test
void testNonErroneousGetForwardToPlainHtml() {
AggregatedHttpResponse res = client.get("/forwards/forwardToHtml.jsp").aggregate().join();
assertThat(res.status().code()).isEqualTo(200);
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
spanAsserts.assertServerSpan(
span,
new JspSpanAssertionBuilder()
.withMethod("GET")
.withRoute("/" + getContextPath() + "/forwards/forwardToHtml.jsp")
.withResponseStatus(200)
.build()),
span ->
spanAsserts.assertCompileSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute("/forwards/forwardToHtml.jsp")
.withClassName("forwards.forwardToHtml_jsp")
.build()),
span ->
spanAsserts.assertRenderSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute("/forwards/forwardToHtml.jsp")
.build())));
}
@Test
void testNonErroneousGetForwardedToJspWithMultipleIncludes() {
AggregatedHttpResponse res =
client.get("/forwards/forwardToIncludeMulti.jsp").aggregate().join();
assertThat(res.status().code()).isEqualTo(200);
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
spanAsserts.assertServerSpan(
span,
new JspSpanAssertionBuilder()
.withMethod("GET")
.withRoute(
"/" + getContextPath() + "/forwards/forwardToIncludeMulti.jsp")
.withResponseStatus(200)
.build()),
span ->
spanAsserts.assertCompileSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute("/forwards/forwardToIncludeMulti.jsp")
.withClassName("forwards.forwardToIncludeMulti_jsp")
.build()),
span ->
spanAsserts.assertRenderSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute("/forwards/forwardToIncludeMulti.jsp")
.build()),
span ->
spanAsserts.assertCompileSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(2))
.withRoute("/includes/includeMulti.jsp")
.withClassName("includes.includeMulti_jsp")
.build()),
span ->
spanAsserts.assertRenderSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(2))
.withRoute("/includes/includeMulti.jsp")
.build()),
span ->
spanAsserts.assertCompileSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(4))
.withRoute("/common/javaLoopH2.jsp")
.withClassName("common.javaLoopH2_jsp")
.build()),
span ->
spanAsserts.assertRenderSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(4))
.withRoute("/common/javaLoopH2.jsp")
.withRequestUrlOverride("/includes/includeMulti.jsp")
.withForwardOrigin("/forwards/forwardToIncludeMulti.jsp")
.build()),
span ->
spanAsserts.assertCompileSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(4))
.withRoute("/common/javaLoopH2.jsp")
.withClassName("common.javaLoopH2_jsp")
.build()),
span ->
spanAsserts.assertRenderSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(4))
.withRoute("/common/javaLoopH2.jsp")
.withRequestUrlOverride("/includes/includeMulti.jsp")
.withForwardOrigin("/forwards/forwardToIncludeMulti.jsp")
.build())));
}
@Test
void testNonErroneousGetForwardToAnotherForward() {
AggregatedHttpResponse res = client.get("/forwards/forwardToJspForward.jsp").aggregate().join();
assertThat(res.status().code()).isEqualTo(200);
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
spanAsserts.assertServerSpan(
span,
new JspSpanAssertionBuilder()
.withMethod("GET")
.withRoute("/" + getContextPath() + "/forwards/forwardToJspForward.jsp")
.withResponseStatus(200)
.build()),
span ->
spanAsserts.assertCompileSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute("/forwards/forwardToJspForward.jsp")
.withClassName("forwards.forwardToJspForward_jsp")
.build()),
span ->
spanAsserts.assertRenderSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute("/forwards/forwardToJspForward.jsp")
.build()),
span ->
spanAsserts.assertCompileSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(2))
.withRoute("/forwards/forwardToSimpleJava.jsp")
.withClassName("forwards.forwardToSimpleJava_jsp")
.build()),
span ->
spanAsserts.assertRenderSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(2))
.withRoute("/forwards/forwardToSimpleJava.jsp")
.build()),
span ->
spanAsserts.assertCompileSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(4))
.withRoute("/common/loop.jsp")
.withClassName("common.loop_jsp")
.build()),
span ->
spanAsserts.assertRenderSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(4))
.withRoute("/common/loop.jsp")
.build())));
}
@Test
void testForwardToJspWithCompileErrorShouldNotProduceSecondRenderSpan() {
AggregatedHttpResponse res =
client.get("/forwards/forwardToCompileError.jsp").aggregate().join();
assertThat(res.status().code()).isEqualTo(500);
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
spanAsserts.assertServerSpan(
span,
new JspSpanAssertionBuilder()
.withMethod("GET")
.withRoute(
"/" + getContextPath() + "/forwards/forwardToCompileError.jsp")
.withResponseStatus(500)
.withExceptionClass(JasperException.class)
.build()),
span ->
spanAsserts.assertCompileSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute("/forwards/forwardToCompileError.jsp")
.withClassName("forwards.forwardToCompileError_jsp")
.build()),
span ->
spanAsserts.assertRenderSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute("/forwards/forwardToCompileError.jsp")
.withExceptionClass(JasperException.class)
.build()),
span ->
spanAsserts.assertCompileSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(2))
.withRoute("/compileError.jsp")
.withClassName("compileError_jsp")
.withExceptionClass(JasperException.class)
.build())));
}
@Test
void testForwardToNonExistentJspShouldBe404() {
String route = "/" + getContextPath() + "/forwards/forwardToNonExistent.jsp";
AggregatedHttpResponse res =
client.get("/forwards/forwardToNonExistent.jsp").aggregate().join();
assertThat(res.status().code()).isEqualTo(404);
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
span.hasName("GET " + route)
.hasNoParent()
.hasKind(SpanKind.SERVER)
.hasStatus(StatusData.unset())
.hasAttributesSatisfyingExactly(
equalTo(UrlAttributes.URL_SCHEME, "http"),
equalTo(UrlAttributes.URL_PATH, route),
equalTo(HttpAttributes.HTTP_REQUEST_METHOD, "GET"),
equalTo(HttpAttributes.HTTP_RESPONSE_STATUS_CODE, 404),
satisfies(
UserAgentAttributes.USER_AGENT_ORIGINAL,
val -> val.isInstanceOf(String.class)),
equalTo(HttpAttributes.HTTP_ROUTE, route),
equalTo(NetworkAttributes.NETWORK_PROTOCOL_VERSION, "1.1"),
equalTo(ServerAttributes.SERVER_ADDRESS, "localhost"),
equalTo(ServerAttributes.SERVER_PORT, port),
equalTo(ClientAttributes.CLIENT_ADDRESS, "127.0.0.1"),
equalTo(NetworkAttributes.NETWORK_PEER_ADDRESS, "127.0.0.1"),
satisfies(
NetworkAttributes.NETWORK_PEER_PORT,
val -> val.isInstanceOf(Long.class))),
span ->
spanAsserts.assertCompileSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute("/forwards/forwardToNonExistent.jsp")
.withClassName("forwards.forwardToNonExistent_jsp")
.build()),
span ->
spanAsserts.assertRenderSpan(
span,
new JspSpanAssertionBuilder()
.withParent(trace.getSpan(0))
.withRoute("/forwards/forwardToNonExistent.jsp")
.build()),
span -> span.hasName("ResponseFacade.sendError").hasParent(trace.getSpan(2))));
}
}

View File

@ -0,0 +1,92 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.jsp;
import io.opentelemetry.sdk.trace.data.SpanData;
class JspSpan {
private SpanData parent;
private String method;
private String className;
private String requestUrlOverride;
private String forwardOrigin;
private String route;
private int responseStatus;
private Class<?> exceptionClass;
private boolean errorMessageOptional;
public SpanData getParent() {
return parent;
}
public void setParent(SpanData parent) {
this.parent = parent;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getRequestUrlOverride() {
return requestUrlOverride;
}
public void setRequestUrlOverride(String requestUrlOverride) {
this.requestUrlOverride = requestUrlOverride;
}
public String getForwardOrigin() {
return forwardOrigin;
}
public void setForwardOrigin(String forwardOrigin) {
this.forwardOrigin = forwardOrigin;
}
public String getRoute() {
return route;
}
public void setRoute(String route) {
this.route = route;
}
public int getResponseStatus() {
return responseStatus;
}
public void setResponseStatus(int responseStatus) {
this.responseStatus = responseStatus;
}
public Class<?> getExceptionClass() {
return exceptionClass;
}
public void setExceptionClass(Class<?> exceptionClass) {
this.exceptionClass = exceptionClass;
}
public boolean getErrorMessageOptional() {
return errorMessageOptional;
}
public void setErrorMessageOptional(boolean errorMessageOptional) {
this.errorMessageOptional = errorMessageOptional;
}
}

View File

@ -0,0 +1,79 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.jsp;
import io.opentelemetry.sdk.trace.data.SpanData;
class JspSpanAssertionBuilder {
private SpanData parent;
private String method;
private String route;
private String className;
private String requestUrlOverride;
private String forwardOrigin;
private int responseStatus;
private Class<?> exceptionClass;
private boolean errorMessageOptional;
public JspSpanAssertionBuilder withParent(SpanData parent) {
this.parent = parent;
return this;
}
public JspSpanAssertionBuilder withMethod(String method) {
this.method = method;
return this;
}
public JspSpanAssertionBuilder withRoute(String route) {
this.route = route;
return this;
}
public JspSpanAssertionBuilder withClassName(String className) {
this.className = className;
return this;
}
public JspSpanAssertionBuilder withRequestUrlOverride(String requestUrlOverride) {
this.requestUrlOverride = requestUrlOverride;
return this;
}
public JspSpanAssertionBuilder withForwardOrigin(String forwardOrigin) {
this.forwardOrigin = forwardOrigin;
return this;
}
public JspSpanAssertionBuilder withResponseStatus(int responseStatus) {
this.responseStatus = responseStatus;
return this;
}
public JspSpanAssertionBuilder withExceptionClass(Class<?> exceptionClass) {
this.exceptionClass = exceptionClass;
return this;
}
public JspSpanAssertionBuilder withErrorMessageOptional(boolean errorMessageOptional) {
this.errorMessageOptional = errorMessageOptional;
return this;
}
public JspSpan build() {
JspSpan serverSpan = new JspSpan();
serverSpan.setParent(this.parent);
serverSpan.setMethod(this.method);
serverSpan.setRoute(this.route);
serverSpan.setClassName(this.className);
serverSpan.setRequestUrlOverride(this.requestUrlOverride);
serverSpan.setForwardOrigin(this.forwardOrigin);
serverSpan.setResponseStatus(this.responseStatus);
serverSpan.setExceptionClass(this.exceptionClass);
serverSpan.setErrorMessageOptional(this.errorMessageOptional);
return serverSpan;
}
}

View File

@ -0,0 +1,155 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.jsp;
import static io.opentelemetry.api.common.AttributeKey.stringKey;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.sdk.testing.assertj.SpanDataAssert;
import io.opentelemetry.sdk.trace.data.StatusData;
import io.opentelemetry.semconv.ClientAttributes;
import io.opentelemetry.semconv.ErrorAttributes;
import io.opentelemetry.semconv.ExceptionAttributes;
import io.opentelemetry.semconv.HttpAttributes;
import io.opentelemetry.semconv.NetworkAttributes;
import io.opentelemetry.semconv.ServerAttributes;
import io.opentelemetry.semconv.UrlAttributes;
import io.opentelemetry.semconv.UserAgentAttributes;
class JspSpanAssertions {
private final String baseUrl;
private final int port;
JspSpanAssertions(String baseUrl, int port) {
this.baseUrl = baseUrl;
this.port = port;
}
SpanDataAssert assertServerSpan(SpanDataAssert span, JspSpan spanData) {
if (spanData.getExceptionClass() != null) {
span.hasStatus(StatusData.error())
.hasEventsSatisfyingExactly(
event ->
event
.hasName("exception")
.hasAttributesSatisfyingExactly(
satisfies(
ExceptionAttributes.EXCEPTION_TYPE,
val ->
val.satisfiesAnyOf(
v -> val.isEqualTo(spanData.getExceptionClass().getName()),
v ->
val.contains(
spanData.getExceptionClass().getSimpleName()))),
satisfies(
ExceptionAttributes.EXCEPTION_MESSAGE,
val ->
val.satisfiesAnyOf(
v -> assertThat(spanData.getErrorMessageOptional()).isTrue(),
v -> val.isInstanceOf(String.class))),
satisfies(
ExceptionAttributes.EXCEPTION_STACKTRACE,
val -> val.isInstanceOf(String.class))));
}
return span.hasName(spanData.getMethod() + " " + spanData.getRoute())
.hasNoParent()
.hasKind(SpanKind.SERVER)
.hasAttributesSatisfyingExactly(
equalTo(UrlAttributes.URL_SCHEME, "http"),
equalTo(UrlAttributes.URL_PATH, spanData.getRoute()),
equalTo(HttpAttributes.HTTP_REQUEST_METHOD, spanData.getMethod()),
equalTo(HttpAttributes.HTTP_RESPONSE_STATUS_CODE, spanData.getResponseStatus()),
satisfies(
UserAgentAttributes.USER_AGENT_ORIGINAL, val -> val.isInstanceOf(String.class)),
equalTo(HttpAttributes.HTTP_ROUTE, spanData.getRoute()),
equalTo(NetworkAttributes.NETWORK_PROTOCOL_VERSION, "1.1"),
equalTo(ServerAttributes.SERVER_ADDRESS, "localhost"),
equalTo(ServerAttributes.SERVER_PORT, port),
equalTo(ClientAttributes.CLIENT_ADDRESS, "127.0.0.1"),
equalTo(NetworkAttributes.NETWORK_PEER_ADDRESS, "127.0.0.1"),
satisfies(NetworkAttributes.NETWORK_PEER_PORT, val -> val.isInstanceOf(Long.class)),
satisfies(
ErrorAttributes.ERROR_TYPE,
val ->
val.satisfiesAnyOf(
v -> assertThat(spanData.getExceptionClass()).isNull(),
v -> assertThat(v).isEqualTo("500"))));
}
SpanDataAssert assertCompileSpan(SpanDataAssert span, JspSpan spanData) {
if (spanData.getExceptionClass() != null) {
span.hasStatus(StatusData.error())
.hasEventsSatisfyingExactly(
event ->
event
.hasName("exception")
.hasAttributesSatisfyingExactly(
equalTo(
ExceptionAttributes.EXCEPTION_TYPE,
spanData.getExceptionClass().getCanonicalName()),
satisfies(
ExceptionAttributes.EXCEPTION_STACKTRACE,
val -> val.isInstanceOf(String.class)),
satisfies(
ExceptionAttributes.EXCEPTION_MESSAGE,
val -> val.isInstanceOf(String.class))));
}
return span.hasName("Compile " + spanData.getRoute())
.hasParent(spanData.getParent())
.hasAttributesSatisfyingExactly(
equalTo(stringKey("jsp.classFQCN"), "org.apache.jsp." + spanData.getClassName()),
equalTo(stringKey("jsp.compiler"), "org.apache.jasper.compiler.JDTCompiler"));
}
SpanDataAssert assertRenderSpan(SpanDataAssert span, JspSpan spanData) {
String requestUrl = spanData.getRoute();
if (spanData.getRequestUrlOverride() != null) {
requestUrl = spanData.getRequestUrlOverride();
}
if (spanData.getExceptionClass() != null) {
span.hasStatus(StatusData.error())
.hasEventsSatisfyingExactly(
event ->
event
.hasName("exception")
.hasAttributesSatisfyingExactly(
satisfies(
ExceptionAttributes.EXCEPTION_TYPE,
val ->
val.satisfiesAnyOf(
v -> val.isEqualTo(spanData.getExceptionClass().getName()),
v ->
val.contains(
spanData.getExceptionClass().getSimpleName()))),
satisfies(
ExceptionAttributes.EXCEPTION_MESSAGE,
val ->
val.satisfiesAnyOf(
v -> assertThat(spanData.getErrorMessageOptional()).isTrue(),
v -> val.isInstanceOf(String.class))),
satisfies(
ExceptionAttributes.EXCEPTION_STACKTRACE,
val -> val.isInstanceOf(String.class))));
}
return span.hasName("Render " + spanData.getRoute())
.hasParent(spanData.getParent())
.hasAttributesSatisfyingExactly(
equalTo(stringKey("jsp.requestURL"), baseUrl + requestUrl),
satisfies(
stringKey("jsp.forwardOrigin"),
val ->
val.satisfiesAnyOf(
v -> assertThat(spanData.getForwardOrigin()).isNull(),
v -> assertThat(v).isEqualTo(spanData.getForwardOrigin()))));
}
}