Skip to content

Commit 685be55

Browse files
authored
Add Exception Replay smoke test (#8388)
refactor smoke test to be able to add JVM options/properties ad smoke test for max captured frames
1 parent d57a858 commit 685be55

File tree

5 files changed

+134
-34
lines changed

5 files changed

+134
-34
lines changed

dd-smoke-tests/debugger-integration-tests/src/test/java/datadog/smoketest/CodeOriginIntegrationTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ protected ProcessBuilder createProcessBuilder(Path logFilePath, String... params
3333
@Test
3434
@DisplayName("testCodeOriginTraceAnnotation")
3535
void testCodeOriginTraceAnnotation() throws Exception {
36+
appUrl = startAppAndAndGetUrl();
3637
execute(appUrl, TRACED_METHOD_NAME);
3738
waitForInstrumentation(appUrl);
3839
execute(appUrl, TRACED_METHOD_NAME);

dd-smoke-tests/debugger-integration-tests/src/test/java/datadog/smoketest/ExceptionDebuggerIntegrationTest.java

Lines changed: 112 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
import static org.junit.jupiter.api.Assertions.assertEquals;
44
import static org.junit.jupiter.api.Assertions.assertFalse;
55
import static org.junit.jupiter.api.Assertions.assertNotNull;
6-
import static org.junit.jupiter.api.Assertions.assertNull;
6+
import static org.junit.jupiter.api.Assertions.assertTrue;
77

88
import com.datadog.debugger.sink.Snapshot;
99
import datadog.trace.api.Platform;
1010
import datadog.trace.bootstrap.debugger.CapturedContext;
1111
import datadog.trace.test.agent.decoder.DecodedSpan;
1212
import datadog.trace.test.agent.decoder.DecodedTrace;
1313
import java.nio.file.Path;
14+
import java.util.ArrayList;
1415
import java.util.HashMap;
1516
import java.util.List;
1617
import java.util.Map;
@@ -20,12 +21,11 @@
2021

2122
public class ExceptionDebuggerIntegrationTest extends ServerAppDebuggerIntegrationTest {
2223

23-
private String snapshotId0;
24-
private String snapshotId1;
25-
private String snapshotId2;
24+
private List<String> snapshotIdTags = new ArrayList<>();
2625
private boolean traceReceived;
2726
private boolean snapshotReceived;
2827
private Map<String, Snapshot> snapshots = new HashMap<>();
28+
private List<String> additionalJvmArgs = new ArrayList<>();
2929

3030
@Override
3131
protected ProcessBuilder createProcessBuilder(Path logFilePath, String... params) {
@@ -36,6 +36,7 @@ protected ProcessBuilder createProcessBuilder(Path logFilePath, String... params
3636
commandParams.add("-Ddd.third.party.excludes=datadog.smoketest");
3737
// disable DI to make sure exception debugger works alone
3838
commandParams.remove("-Ddd.dynamic.instrumentation.enabled=true");
39+
commandParams.addAll(additionalJvmArgs);
3940
return ProcessBuilderHelper.createProcessBuilder(
4041
commandParams, logFilePath, getAppClass(), params);
4142
}
@@ -46,13 +47,18 @@ protected ProcessBuilder createProcessBuilder(Path logFilePath, String... params
4647
value = "datadog.trace.api.Platform#isJ9",
4748
disabledReason = "we cannot get local variable debug info")
4849
void testSimpleSingleFrameException() throws Exception {
50+
appUrl = startAppAndAndGetUrl();
4951
execute(appUrl, TRACED_METHOD_NAME, "oops"); // instrumenting first exception
5052
waitForInstrumentation(appUrl);
5153
execute(appUrl, TRACED_METHOD_NAME, "oops"); // collecting snapshots and sending them
5254
registerTraceListener(this::receiveExceptionReplayTrace);
5355
registerSnapshotListener(this::receiveSnapshot);
5456
processRequests(
5557
() -> {
58+
if (snapshotIdTags.isEmpty()) {
59+
return false;
60+
}
61+
String snapshotId0 = snapshotIdTags.get(0);
5662
if (traceReceived && snapshotReceived && snapshots.containsKey(snapshotId0)) {
5763
Snapshot snapshot = snapshots.get(snapshotId0);
5864
assertNotNull(snapshot);
@@ -71,6 +77,7 @@ void testSimpleSingleFrameException() throws Exception {
7177
value = "datadog.trace.api.Platform#isJ9",
7278
disabledReason = "we cannot get local variable debug info")
7379
void testNoSubsequentCaptureAfterFirst() throws Exception {
80+
appUrl = startAppAndAndGetUrl();
7481
testSimpleSingleFrameException();
7582
resetSnapshotsAndTraces();
7683
// we should not receive any more snapshots after the first one
@@ -88,39 +95,40 @@ void testNoSubsequentCaptureAfterFirst() throws Exception {
8895
processRequests(() -> traceReceived && !snapshotReceived);
8996
}
9097

98+
// DeepOops exception stacktrace:
99+
// java.lang.RuntimeException: oops
100+
// datadog.smoketest.debugger.ServerDebuggerTestApplication.tracedMethodWithException(ServerDebuggerTestApplication.java:190)
101+
// datadog.smoketest.debugger.ServerDebuggerTestApplication.tracedMethodWithDeepException5(ServerDebuggerTestApplication.java:210)
102+
// datadog.smoketest.debugger.ServerDebuggerTestApplication.tracedMethodWithDeepException4(ServerDebuggerTestApplication.java:206)
103+
// datadog.smoketest.debugger.ServerDebuggerTestApplication.tracedMethodWithDeepException3(ServerDebuggerTestApplication.java:202)
104+
// datadog.smoketest.debugger.ServerDebuggerTestApplication.tracedMethodWithDeepException2(ServerDebuggerTestApplication.java:198)
105+
// datadog.smoketest.debugger.ServerDebuggerTestApplication.tracedMethodWithDeepException1(ServerDebuggerTestApplication.java:194)
106+
// datadog.smoketest.debugger.ServerDebuggerTestApplication.runTracedMethod(ServerDebuggerTestApplication.java:140)
91107
@Test
92108
@DisplayName("test3CapturedFrames")
93109
@DisabledIf(
94110
value = "datadog.trace.api.Platform#isJ9",
95111
disabledReason = "we cannot get local variable debug info")
96112
void test3CapturedFrames() throws Exception {
113+
appUrl = startAppAndAndGetUrl();
97114
execute(appUrl, TRACED_METHOD_NAME, "deepOops"); // instrumenting first exception
98115
waitForInstrumentation(appUrl);
99116
execute(appUrl, TRACED_METHOD_NAME, "deepOops"); // collecting snapshots and sending them
100117
registerTraceListener(this::receiveExceptionReplayTrace);
101118
registerSnapshotListener(this::receiveSnapshot);
102119
processRequests(
103120
() -> {
121+
if (snapshotIdTags.isEmpty()) {
122+
return false;
123+
}
124+
String snapshotId0 = snapshotIdTags.get(0);
125+
String snapshotId1 = snapshotIdTags.get(1);
126+
String snapshotId2 = snapshotIdTags.get(2);
104127
if (traceReceived
105128
&& snapshotReceived
106129
&& snapshots.containsKey(snapshotId0)
107130
&& snapshots.containsKey(snapshotId1)
108131
&& snapshots.containsKey(snapshotId2)) {
109-
// java.lang.RuntimeException: oops
110-
// at
111-
// datadog.smoketest.debugger.ServerDebuggerTestApplication.tracedMethodWithException(ServerDebuggerTestApplication.java:190)
112-
// at
113-
// datadog.smoketest.debugger.ServerDebuggerTestApplication.tracedMethodWithDeepException5(ServerDebuggerTestApplication.java:210)
114-
// at
115-
// datadog.smoketest.debugger.ServerDebuggerTestApplication.tracedMethodWithDeepException4(ServerDebuggerTestApplication.java:206)
116-
// at
117-
// datadog.smoketest.debugger.ServerDebuggerTestApplication.tracedMethodWithDeepException3(ServerDebuggerTestApplication.java:202)
118-
// at
119-
// datadog.smoketest.debugger.ServerDebuggerTestApplication.tracedMethodWithDeepException2(ServerDebuggerTestApplication.java:198)
120-
// at
121-
// datadog.smoketest.debugger.ServerDebuggerTestApplication.tracedMethodWithDeepException1(ServerDebuggerTestApplication.java:194)
122-
// at
123-
// datadog.smoketest.debugger.ServerDebuggerTestApplication.runTracedMethod(ServerDebuggerTestApplication.java:140)
124132
// snapshot 0
125133
Snapshot snapshot = snapshots.get(snapshotId0);
126134
assertNotNull(snapshot);
@@ -152,14 +160,89 @@ void test3CapturedFrames() throws Exception {
152160
});
153161
}
154162

163+
@Test
164+
@DisplayName("test5CapturedFrames")
165+
@DisabledIf(
166+
value = "datadog.trace.api.Platform#isJ9",
167+
disabledReason = "we cannot get local variable debug info")
168+
void test5CapturedFrames() throws Exception {
169+
additionalJvmArgs.add("-Ddd.exception.replay.capture.max.frames=5");
170+
appUrl = startAppAndAndGetUrl();
171+
execute(appUrl, TRACED_METHOD_NAME, "deepOops"); // instrumenting first exception
172+
waitForInstrumentation(appUrl);
173+
execute(appUrl, TRACED_METHOD_NAME, "deepOops"); // collecting snapshots and sending them
174+
registerTraceListener(this::receiveExceptionReplayTrace);
175+
registerSnapshotListener(this::receiveSnapshot);
176+
processRequests(
177+
() -> {
178+
if (snapshotIdTags.isEmpty()) {
179+
return false;
180+
}
181+
String snapshotId0 = snapshotIdTags.get(0);
182+
String snapshotId1 = snapshotIdTags.get(1);
183+
String snapshotId2 = snapshotIdTags.get(2);
184+
String snapshotId3 = snapshotIdTags.get(3);
185+
String snapshotId4 = snapshotIdTags.get(4);
186+
if (traceReceived
187+
&& snapshotReceived
188+
&& snapshots.containsKey(snapshotId0)
189+
&& snapshots.containsKey(snapshotId1)
190+
&& snapshots.containsKey(snapshotId2)
191+
&& snapshots.containsKey(snapshotId3)
192+
&& snapshots.containsKey(snapshotId4)) {
193+
// snapshot 0
194+
Snapshot snapshot = snapshots.get(snapshotId0);
195+
assertNotNull(snapshot);
196+
assertEquals(
197+
"oops", snapshot.getCaptures().getReturn().getCapturedThrowable().getMessage());
198+
assertEquals(
199+
"datadog.smoketest.debugger.ServerDebuggerTestApplication.tracedMethodWithException",
200+
snapshot.getStack().get(0).getFunction());
201+
assertFullMethodCaptureArgs(snapshot.getCaptures().getReturn());
202+
// snapshot 1
203+
snapshot = snapshots.get(snapshotId1);
204+
assertEquals(
205+
"oops", snapshot.getCaptures().getReturn().getCapturedThrowable().getMessage());
206+
assertEquals(
207+
"datadog.smoketest.debugger.ServerDebuggerTestApplication.tracedMethodWithDeepException5",
208+
snapshot.getStack().get(0).getFunction());
209+
assertFullMethodCaptureArgs(snapshot.getCaptures().getReturn());
210+
// snapshot 2
211+
snapshot = snapshots.get(snapshotId2);
212+
assertEquals(
213+
"oops", snapshot.getCaptures().getReturn().getCapturedThrowable().getMessage());
214+
assertEquals(
215+
"datadog.smoketest.debugger.ServerDebuggerTestApplication.tracedMethodWithDeepException4",
216+
snapshot.getStack().get(0).getFunction());
217+
assertFullMethodCaptureArgs(snapshot.getCaptures().getReturn());
218+
// snapshot 3
219+
snapshot = snapshots.get(snapshotId3);
220+
assertEquals(
221+
"oops", snapshot.getCaptures().getReturn().getCapturedThrowable().getMessage());
222+
assertEquals(
223+
"datadog.smoketest.debugger.ServerDebuggerTestApplication.tracedMethodWithDeepException3",
224+
snapshot.getStack().get(0).getFunction());
225+
assertFullMethodCaptureArgs(snapshot.getCaptures().getReturn());
226+
// snapshot 4
227+
snapshot = snapshots.get(snapshotId4);
228+
assertEquals(
229+
"oops", snapshot.getCaptures().getReturn().getCapturedThrowable().getMessage());
230+
assertEquals(
231+
"datadog.smoketest.debugger.ServerDebuggerTestApplication.tracedMethodWithDeepException2",
232+
snapshot.getStack().get(0).getFunction());
233+
assertFullMethodCaptureArgs(snapshot.getCaptures().getReturn());
234+
return true;
235+
}
236+
return false;
237+
});
238+
}
239+
155240
private void resetSnapshotsAndTraces() {
156241
resetTraceListener();
157242
traceReceived = false;
158243
snapshotReceived = false;
159244
snapshots.clear();
160-
snapshotId0 = null;
161-
snapshotId1 = null;
162-
snapshotId2 = null;
245+
snapshotIdTags.clear();
163246
}
164247

165248
private void assertFullMethodCaptureArgs(CapturedContext context) {
@@ -178,10 +261,13 @@ private void receiveExceptionReplayTrace(DecodedTrace decodedTrace) {
178261
for (DecodedSpan span : decodedTrace.getSpans()) {
179262
if (isTracedFullMethodSpan(span) && span.getMeta().containsKey("error.debug_info_captured")) {
180263
// assert that we have received the trace with ER tags only once
181-
assertNull(snapshotId0);
182-
snapshotId0 = span.getMeta().get("_dd.debug.error.0.snapshot_id");
183-
snapshotId1 = span.getMeta().get("_dd.debug.error.1.snapshot_id");
184-
snapshotId2 = span.getMeta().get("_dd.debug.error.2.snapshot_id");
264+
assertTrue(snapshotIdTags.isEmpty());
265+
for (int i = 0; i < 5; i++) {
266+
String snapshotId = span.getMeta().get("_dd.debug.error." + i + ".snapshot_id");
267+
if (snapshotId != null) {
268+
snapshotIdTags.add(snapshotId);
269+
}
270+
}
185271
assertFalse(traceReceived);
186272
traceReceived = true;
187273
}

dd-smoke-tests/debugger-integration-tests/src/test/java/datadog/smoketest/ProbeStateIntegrationTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,22 @@
1010
import java.util.Collections;
1111
import java.util.List;
1212
import java.util.concurrent.atomic.AtomicBoolean;
13+
import org.junit.jupiter.api.BeforeEach;
1314
import org.junit.jupiter.api.Disabled;
1415
import org.junit.jupiter.api.DisplayName;
1516
import org.junit.jupiter.api.Test;
17+
import org.junit.jupiter.api.TestInfo;
1618
import org.junit.jupiter.api.condition.DisabledIf;
1719

1820
public class ProbeStateIntegrationTest extends ServerAppDebuggerIntegrationTest {
21+
22+
@BeforeEach
23+
@Override
24+
void setup(TestInfo testInfo) throws Exception {
25+
super.setup(testInfo);
26+
appUrl = startAppAndAndGetUrl();
27+
}
28+
1929
@Test
2030
@DisplayName("testAddRemoveProbes")
2131
@DisabledIf(value = "datadog.trace.api.Platform#isJ9", disabledReason = "Flaky on J9 JVMs")

dd-smoke-tests/debugger-integration-tests/src/test/java/datadog/smoketest/ServerAppDebuggerIntegrationTest.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import datadog.trace.bootstrap.debugger.ProbeId;
1212
import datadog.trace.test.agent.decoder.DecodedSpan;
1313
import datadog.trace.util.TagsHelper;
14-
import java.io.EOFException;
1514
import java.io.IOException;
1615
import java.util.List;
1716
import java.util.concurrent.TimeUnit;
@@ -42,17 +41,15 @@ public class ServerAppDebuggerIntegrationTest extends BaseIntegrationTest {
4241
private OkHttpClient httpClient = new OkHttpClient();
4342
protected String appUrl;
4443

45-
@Override
4644
@BeforeEach
45+
@Override
4746
void setup(TestInfo testInfo) throws Exception {
4847
super.setup(testInfo);
4948
controlServer = new MockWebServer();
5049
// controlServer.setDispatcher(new ControlDispatcher());
5150
controlServer.start();
5251
LOG.info("ControlServer on {}", controlServer.getPort());
5352
controlUrl = controlServer.url(CONTROL_URL);
54-
startApp();
55-
appUrl = waitForAppStartedAndGetUrl();
5653
}
5754

5855
@Override
@@ -146,12 +143,9 @@ protected void waitForReTransformation(String appUrl) throws IOException {
146143
LOG.info("re-transformation done");
147144
}
148145

149-
protected void startApp() throws IOException {
146+
protected String startAppAndAndGetUrl() throws InterruptedException, IOException {
150147
controlServer.enqueue(EMPTY_200_RESPONSE); // ack response
151148
targetProcess = createProcessBuilder(logFilePath, controlUrl.toString()).start();
152-
}
153-
154-
protected String waitForAppStartedAndGetUrl() throws InterruptedException, EOFException {
155149
RecordedRequest recordedRequest = controlServer.takeRequest(30, TimeUnit.SECONDS);
156150
assertNotNull(recordedRequest);
157151
String appUrl = recordedRequest.getBody().readUtf8Line();

dd-smoke-tests/debugger-integration-tests/src/test/java/datadog/smoketest/SpanDecorationProbesIntegrationTests.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,21 @@
2323
import java.util.List;
2424
import java.util.concurrent.atomic.AtomicBoolean;
2525
import java.util.concurrent.atomic.AtomicInteger;
26+
import org.junit.jupiter.api.BeforeEach;
2627
import org.junit.jupiter.api.DisplayName;
2728
import org.junit.jupiter.api.Test;
29+
import org.junit.jupiter.api.TestInfo;
2830
import org.junit.jupiter.api.condition.DisabledIf;
2931

3032
public class SpanDecorationProbesIntegrationTests extends ServerAppDebuggerIntegrationTest {
3133

34+
@BeforeEach
35+
@Override
36+
void setup(TestInfo testInfo) throws Exception {
37+
super.setup(testInfo);
38+
appUrl = startAppAndAndGetUrl();
39+
}
40+
3241
@Override
3342
protected ProcessBuilder createProcessBuilder(Path logFilePath, String... params) {
3443
List<String> commandParams = getDebuggerCommandParams();

0 commit comments

Comments
 (0)