Skip to content

Commit 439604a

Browse files
authored
Fix DebuggerAgent tests (#9951)
Inject a config instance to DebuggerAgent and stop rely on Config.get() to be able to provide clean config at any time. add some reset method for reseting static fields Fix readFromFile test that wasn't at all executed
1 parent a011ae4 commit 439604a

File tree

6 files changed

+94
-59
lines changed

6 files changed

+94
-59
lines changed

dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1396,8 +1396,8 @@ private static synchronized void startDebuggerAgent(
13961396
final Class<?> debuggerAgentClass =
13971397
AGENT_CLASSLOADER.loadClass("com.datadog.debugger.agent.DebuggerAgent");
13981398
final Method debuggerInstallerMethod =
1399-
debuggerAgentClass.getMethod("run", Instrumentation.class, scoClass);
1400-
debuggerInstallerMethod.invoke(null, inst, sco);
1399+
debuggerAgentClass.getMethod("run", Config.class, Instrumentation.class, scoClass);
1400+
debuggerInstallerMethod.invoke(null, Config.get(), inst, sco);
14011401
} catch (final Throwable ex) {
14021402
log.error("Throwable thrown while starting debugger agent", ex);
14031403
} finally {

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerAgent.java

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -72,23 +72,23 @@ public class DebuggerAgent {
7272
static final AtomicBoolean distributedDebuggerEnabled = new AtomicBoolean();
7373
private static ClassesToRetransformFinder classesToRetransformFinder;
7474

75-
public static synchronized void run(Instrumentation inst, SharedCommunicationObjects sco) {
75+
public static synchronized void run(
76+
Config config, Instrumentation inst, SharedCommunicationObjects sco) {
7677
instrumentation = inst;
7778
sharedCommunicationObjects = sco;
78-
Config config = Config.get();
7979
classesToRetransformFinder = new ClassesToRetransformFinder();
8080
setupSourceFileTracking(instrumentation, classesToRetransformFinder);
8181
// set config updater after setup is done, as some deferred updates might be immediately called
82-
DebuggerConfigBridge.setUpdater(new DefaultDebuggerConfigUpdater());
82+
DebuggerConfigBridge.setUpdater(new DefaultDebuggerConfigUpdater(config));
8383
if (config.isDebuggerCodeOriginEnabled()) {
84-
startCodeOriginForSpans();
84+
startCodeOriginForSpans(config);
8585
}
8686
if (config.isDebuggerExceptionEnabled()) {
87-
startExceptionReplay();
87+
startExceptionReplay(config);
8888
}
8989
if (config.isDynamicInstrumentationEnabled()) {
90-
startDynamicInstrumentation();
91-
startCodeOriginForSpans();
90+
startDynamicInstrumentation(config);
91+
startCodeOriginForSpans(config);
9292
if (config.getDynamicInstrumentationInstrumentTheWorld() != null) {
9393
setupInstrumentTheWorldTransformer(config, instrumentation, sink);
9494
}
@@ -145,12 +145,11 @@ private static void initClassNameFilter() {
145145
}
146146
}
147147

148-
public static void startDynamicInstrumentation() {
148+
public static void startDynamicInstrumentation(Config config) {
149149
if (!dynamicInstrumentationEnabled.compareAndSet(false, true)) {
150150
return;
151151
}
152152
LOGGER.info("Starting Dynamic Instrumentation");
153-
Config config = Config.get();
154153
commonInit(config);
155154
String probeFileLocation = config.getDynamicInstrumentationProbeFile();
156155
if (probeFileLocation != null) {
@@ -206,12 +205,11 @@ public static void stopDynamicInstrumentation() {
206205
}
207206
}
208207

209-
public static void startExceptionReplay() {
208+
public static void startExceptionReplay(Config config) {
210209
if (!exceptionReplayEnabled.compareAndSet(false, true)) {
211210
return;
212211
}
213212
LOGGER.info("Starting Exception Replay");
214-
Config config = Config.get();
215213
commonInit(config);
216214
initClassNameFilter();
217215
if (config.isCiVisibilityEnabled()) {
@@ -238,12 +236,11 @@ public static void stopExceptionReplay() {
238236
DebuggerContext.initExceptionDebugger(null);
239237
}
240238

241-
public static void startCodeOriginForSpans() {
239+
public static void startCodeOriginForSpans(Config config) {
242240
if (!codeOriginEnabled.compareAndSet(false, true)) {
243241
return;
244242
}
245243
LOGGER.debug("Starting Code Origin for spans");
246-
Config config = Config.get();
247244
commonInit(config);
248245
initClassNameFilter();
249246
DebuggerContext.initClassNameFilter(classNameFilter);
@@ -263,7 +260,7 @@ public static void stopCodeOriginForSpans() {
263260
DebuggerContext.initCodeOrigin(null);
264261
}
265262

266-
public static void startDistributedDebugger() {
263+
public static void startDistributedDebugger(Config config) {
267264
if (!distributedDebuggerEnabled.compareAndSet(false, true)) {
268265
return;
269266
}
@@ -441,6 +438,26 @@ public static JsonSnapshotSerializer getSnapshotSerializer() {
441438
return DebuggerAgent.snapshotSerializer;
442439
}
443440

441+
// only used for tests
442+
static void reset() {
443+
instrumentation = null;
444+
sharedCommunicationObjects = null;
445+
configurationPoller = null;
446+
sink = null;
447+
agentVersion = null;
448+
snapshotSerializer = null;
449+
classNameFilter = null;
450+
symDBEnablement = null;
451+
configurationUpdater = null;
452+
exceptionDebugger = null;
453+
commonInitDone.set(false);
454+
dynamicInstrumentationEnabled.set(false);
455+
exceptionReplayEnabled.set(false);
456+
codeOriginEnabled.set(false);
457+
distributedDebuggerEnabled.set(false);
458+
classesToRetransformFinder = null;
459+
}
460+
444461
private static class ShutdownHook extends Thread {
445462

446463
private final WeakReference<ConfigurationPoller> pollerRef;

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerTransformer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,7 @@ private List<ToInstrumentInfo> filterAndSortDefinitions(
697697
// Log and span decoration probe shared the same instrumentor: CaptureContextInstrumentor
698698
// and therefore need to be instrumented once
699699
// note: exception probes are log probes and are handled the same way
700-
if (!Config.get().isDistributedDebuggerEnabled() && definition instanceof TriggerProbe) {
700+
if (!config.isDistributedDebuggerEnabled() && definition instanceof TriggerProbe) {
701701
LOGGER.debug(
702702
"The distributed debugger feature is disabled. Trigger probes will not be installed.");
703703
} else if (isCapturedContextProbe(definition)) {

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DefaultDebuggerConfigUpdater.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,42 @@
55
import datadog.trace.api.config.TraceInstrumentationConfig;
66
import datadog.trace.api.debugger.DebuggerConfigUpdate;
77
import datadog.trace.api.debugger.DebuggerConfigUpdater;
8+
import java.util.function.Consumer;
89
import org.slf4j.Logger;
910
import org.slf4j.LoggerFactory;
1011

1112
class DefaultDebuggerConfigUpdater implements DebuggerConfigUpdater {
1213

1314
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultDebuggerConfigUpdater.class);
1415

16+
private final Config config;
17+
18+
public DefaultDebuggerConfigUpdater(Config config) {
19+
this.config = config;
20+
}
21+
1522
@Override
1623
public void updateConfig(DebuggerConfigUpdate update) {
1724
startOrStopFeature(
25+
config,
1826
DebuggerConfig.DYNAMIC_INSTRUMENTATION_ENABLED,
1927
update.getDynamicInstrumentationEnabled(),
2028
DebuggerAgent::startDynamicInstrumentation,
2129
DebuggerAgent::stopDynamicInstrumentation);
2230
startOrStopFeature(
31+
config,
2332
DebuggerConfig.EXCEPTION_REPLAY_ENABLED,
2433
update.getExceptionReplayEnabled(),
2534
DebuggerAgent::startExceptionReplay,
2635
DebuggerAgent::stopExceptionReplay);
2736
startOrStopFeature(
37+
config,
2838
TraceInstrumentationConfig.CODE_ORIGIN_FOR_SPANS_ENABLED,
2939
update.getCodeOriginEnabled(),
3040
DebuggerAgent::startCodeOriginForSpans,
3141
DebuggerAgent::stopCodeOriginForSpans);
3242
startOrStopFeature(
43+
config,
3344
DebuggerConfig.DISTRIBUTED_DEBUGGER_ENABLED,
3445
update.getDistributedDebuggerEnabled(),
3546
DebuggerAgent::startDistributedDebugger,
@@ -62,14 +73,18 @@ private static boolean isExplicitlyDisabled(String booleanKey) {
6273
}
6374

6475
private static void startOrStopFeature(
65-
String booleanKey, Boolean currentStatus, Runnable start, Runnable stop) {
76+
Config config,
77+
String booleanKey,
78+
Boolean currentStatus,
79+
Consumer<Config> start,
80+
Runnable stop) {
6681
if (isExplicitlyDisabled(booleanKey)) {
6782
LOGGER.debug("Feature {} is explicitly disabled", booleanKey);
6883
return;
6984
}
7085
if (currentStatus != null) {
7186
if (currentStatus) {
72-
start.run();
87+
start.accept(config);
7388
} else {
7489
stop.run();
7590
}

dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/DebuggerAgentTest.java

Lines changed: 39 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import static org.junit.jupiter.api.Assertions.assertEquals;
44
import static org.junit.jupiter.api.Assertions.assertNotNull;
5-
import static org.junit.jupiter.api.Assumptions.assumeTrue;
5+
import static org.junit.jupiter.api.Assertions.assertTrue;
66
import static org.junit.jupiter.api.condition.JRE.JAVA_11;
77
import static org.junit.jupiter.api.condition.JRE.JAVA_8;
88
import static org.mockito.ArgumentMatchers.any;
@@ -12,7 +12,6 @@
1212
import static org.mockito.Mockito.never;
1313
import static org.mockito.Mockito.verify;
1414
import static org.mockito.Mockito.when;
15-
import static utils.TestHelper.setFieldInConfig;
1615

1716
import com.datadog.debugger.util.RemoteConfigHelper;
1817
import datadog.common.container.ContainerInfo;
@@ -22,7 +21,6 @@
2221
import datadog.trace.api.git.GitInfoProvider;
2322
import datadog.trace.bootstrap.instrumentation.api.Tags;
2423
import datadog.trace.test.util.ControllableEnvironmentVariables;
25-
import datadog.trace.test.util.Flaky;
2624
import java.io.BufferedReader;
2725
import java.io.IOException;
2826
import java.io.InputStreamReader;
@@ -51,10 +49,10 @@
5149
public class DebuggerAgentTest {
5250

5351
public static final String URL_PATH = "/foo";
52+
@Mock Config config;
5453
@Mock Instrumentation inst;
5554
final MockWebServer server = new MockWebServer();
5655
HttpUrl url;
57-
5856
private ControllableEnvironmentVariables env = ControllableEnvironmentVariables.setup();
5957

6058
private static void setFieldInContainerInfo(
@@ -76,6 +74,7 @@ public void setUp() {
7674

7775
@AfterEach
7876
public void tearDown() throws IOException {
77+
DebuggerAgent.reset();
7978
try {
8079
server.shutdown();
8180
} catch (final IOException e) {
@@ -86,64 +85,66 @@ public void tearDown() throws IOException {
8685
@Test
8786
@EnabledOnJre({JAVA_8, JAVA_11})
8887
public void runDisabled() {
89-
setFieldInConfig(Config.get(), "dynamicInstrumentationEnabled", false);
90-
DebuggerAgent.run(inst, new SharedCommunicationObjects());
88+
when(config.isDynamicInstrumentationEnabled()).thenReturn(false);
89+
DebuggerAgent.run(config, inst, new SharedCommunicationObjects());
9190
verify(inst, never()).addTransformer(any(), eq(true));
9291
}
9392

94-
@Flaky
9593
@Test
9694
@EnabledOnJre({JAVA_8, JAVA_11})
9795
public void runEnabledWithDatadogAgent() throws InterruptedException, IOException {
98-
MockWebServer datadogAgentServer = new MockWebServer();
99-
HttpUrl datadogAgentUrl = datadogAgentServer.url(URL_PATH);
100-
setFieldInConfig(Config.get(), "dynamicInstrumentationEnabled", true);
101-
setFieldInConfig(Config.get(), "remoteConfigEnabled", true);
102-
setFieldInConfig(Config.get(), "dynamicInstrumentationSnapshotUrl", datadogAgentUrl.toString());
103-
setFieldInConfig(Config.get(), "agentUrl", datadogAgentUrl.toString());
104-
setFieldInConfig(Config.get(), "agentHost", "localhost");
105-
setFieldInConfig(Config.get(), "agentPort", datadogAgentServer.getPort());
106-
setFieldInConfig(Config.get(), "dynamicInstrumentationMaxPayloadSize", 4096L);
96+
when(config.isDynamicInstrumentationEnabled()).thenReturn(true);
97+
when(config.isRemoteConfigEnabled()).thenReturn(true);
98+
when(config.getAgentUrl()).thenReturn(url.toString());
99+
when(config.getDynamicInstrumentationUploadBatchSize()).thenReturn(100);
100+
when(config.getRemoteConfigTargetsKeyId())
101+
.thenReturn(Config.get().getRemoteConfigTargetsKeyId());
102+
when(config.getRemoteConfigTargetsKey()).thenReturn(Config.get().getRemoteConfigTargetsKey());
103+
when(config.getFinalDebuggerSymDBUrl()).thenReturn("http://localhost:8126/symdb/v1/input");
104+
when(config.getRemoteConfigMaxPayloadSizeBytes())
105+
.thenReturn(Config.get().getRemoteConfigMaxPayloadSizeBytes());
106+
assertTrue(config.isDynamicInstrumentationEnabled());
107107
setFieldInContainerInfo(ContainerInfo.get(), "containerId", "");
108108
String infoContent =
109109
"{\"endpoints\": [\"v0.4/traces\", \"debugger/v1/input\", \"debugger/v1/diagnostics\", \"v0.7/config\"] }";
110-
datadogAgentServer.enqueue(new MockResponse().setResponseCode(200).setBody(infoContent));
111-
datadogAgentServer.enqueue(new MockResponse().setResponseCode(200).setBody(infoContent));
110+
server.enqueue(new MockResponse().setResponseCode(200).setBody(infoContent));
111+
server.enqueue(new MockResponse().setResponseCode(200).setBody(infoContent));
112112
try (BufferedReader reader =
113113
new BufferedReader(
114114
new InputStreamReader(
115115
DebuggerAgentTest.class.getResourceAsStream("/test_probe.json")))) {
116116
String content = reader.lines().collect(Collectors.joining("\n"));
117117
String rcContent = RemoteConfigHelper.encode(content, "petclinic");
118-
datadogAgentServer.enqueue(new MockResponse().setResponseCode(200).setBody(rcContent));
118+
server.enqueue(new MockResponse().setResponseCode(200).setBody(rcContent));
119119
} catch (IOException e) {
120120
e.printStackTrace();
121121
}
122122
SharedCommunicationObjects sharedCommunicationObjects = new SharedCommunicationObjects();
123-
DebuggerAgent.run(inst, sharedCommunicationObjects);
123+
DebuggerAgent.run(config, inst, sharedCommunicationObjects);
124124
ConfigurationPoller configurationPoller =
125-
(ConfigurationPoller) sharedCommunicationObjects.configurationPoller(Config.get());
125+
sharedCommunicationObjects.configurationPoller(config);
126126
configurationPoller.start();
127127
RecordedRequest request;
128128
do {
129-
request = datadogAgentServer.takeRequest(5, TimeUnit.SECONDS);
129+
request = server.takeRequest(5, TimeUnit.SECONDS);
130130
assertNotNull(request);
131131
} while ("/info".equals(request.getPath()));
132132
assertEquals("/v0.7/config", request.getPath());
133133
DebuggerAgent.stop();
134-
datadogAgentServer.shutdown();
135134
}
136135

137136
@Test
138137
@EnabledOnJre({JAVA_8, JAVA_11})
139138
public void runEnabledWithUnsupportedDatadogAgent() throws InterruptedException {
140-
setFieldInConfig(Config.get(), "dynamicInstrumentationEnabled", true);
141-
setFieldInConfig(Config.get(), "dynamicInstrumentationSnapshotUrl", url.toString());
142-
setFieldInConfig(Config.get(), "agentUrl", url.toString());
143-
setFieldInConfig(Config.get(), "dynamicInstrumentationMaxPayloadSize", 1024L);
139+
when(config.isDynamicInstrumentationEnabled()).thenReturn(true);
140+
when(config.getAgentUrl()).thenReturn(url.toString());
141+
when(config.getFinalDebuggerSnapshotUrl())
142+
.thenReturn("http://localhost:8126/debugger/v1/input");
143+
when(config.getDynamicInstrumentationUploadBatchSize()).thenReturn(100);
144+
when(config.getFinalDebuggerSymDBUrl()).thenReturn("http://localhost:8126/symdb/v1/input");
144145
String infoContent = "{\"endpoints\": [\"v0.4/traces\"]}";
145146
server.enqueue(new MockResponse().setResponseCode(200).setBody(infoContent));
146-
DebuggerAgent.run(inst, new SharedCommunicationObjects());
147+
DebuggerAgent.run(config, inst, new SharedCommunicationObjects());
147148
verify(inst, never()).addTransformer(any(), eq(true));
148149
}
149150

@@ -152,18 +153,18 @@ public void runEnabledWithUnsupportedDatadogAgent() throws InterruptedException
152153
public void readFromFile() throws URISyntaxException {
153154
URL res = getClass().getClassLoader().getResource("test_probe_file.json");
154155
String probeDefinitionPath = Paths.get(res.toURI()).toFile().getAbsolutePath();
155-
setFieldInConfig(Config.get(), "serviceName", "petclinic");
156-
setFieldInConfig(Config.get(), "dynamicInstrumentationEnabled", true);
157-
setFieldInConfig(Config.get(), "dynamicInstrumentationSnapshotUrl", url.toString());
158-
setFieldInConfig(Config.get(), "agentUrl", url.toString());
159-
setFieldInConfig(Config.get(), "dynamicInstrumentationMaxPayloadSize", 4096L);
160-
setFieldInConfig(Config.get(), "dynamicInstrumentationProbeFile", probeDefinitionPath);
156+
when(config.getServiceName()).thenReturn("petclinic");
157+
when(config.isDynamicInstrumentationEnabled()).thenReturn(true);
158+
when(config.getAgentUrl()).thenReturn(url.toString());
159+
when(config.getDynamicInstrumentationMaxPayloadSize()).thenReturn(4096L);
160+
when(config.getDynamicInstrumentationProbeFile()).thenReturn(probeDefinitionPath);
161+
when(config.getDynamicInstrumentationUploadBatchSize()).thenReturn(100);
162+
when(config.getFinalDebuggerSymDBUrl()).thenReturn("http://localhost:8126/symdb/v1/input");
161163
String infoContent =
162-
"{\"endpoints\": [\"v0.4/traces\", \"debugger/v1/input\", \"v0.7/config\"] }";
164+
"{\"endpoints\": [\"v0.4/traces\", \"debugger/v1/input\", \"debugger/v1/diagnostics\", \"v0.7/config\"] }";
163165
server.enqueue(new MockResponse().setResponseCode(200).setBody(infoContent));
164-
// sometimes this test fails because getAllLoadedClasses returns null
165-
assumeTrue(inst.getAllLoadedClasses() != null);
166-
DebuggerAgent.run(inst, new SharedCommunicationObjects());
166+
when(inst.getAllLoadedClasses()).thenReturn(new Class[0]);
167+
DebuggerAgent.run(config, inst, new SharedCommunicationObjects());
167168
verify(inst, atLeastOnce()).addTransformer(any(), eq(true));
168169
}
169170

dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/DefaultDebuggerConfigUpdaterTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import datadog.communication.ddagent.DDAgentFeaturesDiscovery;
99
import datadog.communication.ddagent.SharedCommunicationObjects;
10+
import datadog.trace.api.Config;
1011
import datadog.trace.api.debugger.DebuggerConfigUpdate;
1112
import java.lang.instrument.Instrumentation;
1213
import org.junit.jupiter.api.Test;
@@ -17,8 +18,9 @@ class DefaultDebuggerConfigUpdaterTest {
1718
public void enableDisable() {
1819
SharedCommunicationObjects sco = mock(SharedCommunicationObjects.class);
1920
when(sco.featuresDiscovery(any())).thenReturn(mock(DDAgentFeaturesDiscovery.class));
20-
DebuggerAgent.run(mock(Instrumentation.class), sco);
21-
DefaultDebuggerConfigUpdater productConfigUpdater = new DefaultDebuggerConfigUpdater();
21+
DebuggerAgent.run(Config.get(), mock(Instrumentation.class), sco);
22+
DefaultDebuggerConfigUpdater productConfigUpdater =
23+
new DefaultDebuggerConfigUpdater(Config.get());
2224
productConfigUpdater.updateConfig(new DebuggerConfigUpdate());
2325
productConfigUpdater.updateConfig(new DebuggerConfigUpdate(true, true, true, true));
2426
assertTrue(productConfigUpdater.isDynamicInstrumentationEnabled());

0 commit comments

Comments
 (0)