Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ dependencies {
testRuntimeOnly project(':dd-java-agent:instrumentation:websocket:jakarta-websocket-2.0')

testImplementation testFixtures(project(':dd-java-agent:instrumentation:servlet:jakarta-servlet-5.0'))
testImplementation libs.bundles.junit5

tomcat9TestImplementation group: 'org.apache.tomcat.embed', name: 'tomcat-embed-core', version: '9.+'
tomcat9TestImplementation group: 'org.apache.tomcat.embed', name: 'tomcat-embed-websocket', version: '9.+'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,12 @@ public static void extractParent(

@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void closeScope(@Advice.Local("parentScope") ContextScope scope) {
scope.close();
// scope can be null if extractParent() above threw before assigning it (the throwable is
// swallowed by suppress = Throwable.class), which would otherwise NPE here and mask the
// real failure.
if (scope != null) {
scope.close();
}
}
}

Expand Down Expand Up @@ -167,7 +172,12 @@ public static void onService(

@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void closeScope(@Advice.Local("serverScope") ContextScope serverScope) {
serverScope.close();
// serverScope can be null if onService() above threw before assigning it (the throwable is
// swallowed by suppress = Throwable.class), which would otherwise NPE here and mask the
// real failure.
if (serverScope != null) {
serverScope.close();
}
}

private void muzzleCheck(CoyoteAdapter adapter, Request request, Response response)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package datadog.trace.instrumentation.tomcat;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertTrue;

import datadog.context.Context;
import datadog.context.ContextScope;
import org.junit.jupiter.api.Test;

class TomcatServerInstrumentationTest {

private static final class RecordingScope implements ContextScope {
private boolean closed;

@Override
public Context context() {
return null;
}

@Override
public void close() {
closed = true;
}
}

@Test
void contextTrackingAdviceCloseScopeToleratesNullScope() {
assertDoesNotThrow(() -> TomcatServerInstrumentation.ContextTrackingAdvice.closeScope(null));
}

@Test
void contextTrackingAdviceCloseScopeClosesNonNullScope() {
RecordingScope scope = new RecordingScope();
TomcatServerInstrumentation.ContextTrackingAdvice.closeScope(scope);
assertTrue(scope.closed);
}

@Test
void serviceAdviceCloseScopeToleratesNullScope() {
assertDoesNotThrow(() -> TomcatServerInstrumentation.ServiceAdvice.closeScope(null));
}

@Test
void serviceAdviceCloseScopeClosesNonNullScope() {
RecordingScope scope = new RecordingScope();
TomcatServerInstrumentation.ServiceAdvice.closeScope(scope);
assertTrue(scope.closed);
}
}
Loading