Skip to content

Commit 3728466

Browse files
Added test to check that we do not generate spans for initial telemetry forwarder sub-process any more.
1 parent 296c9b2 commit 3728466

3 files changed

Lines changed: 121 additions & 43 deletions

File tree

dd-java-agent/src/test/groovy/datadog/trace/agent/InitializationTelemetryTest.groovy

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package datadog.trace.agent
22

3-
import spock.lang.Specification
4-
import spock.lang.Timeout
5-
import spock.lang.IgnoreIf
3+
import datadog.test.SimpleAgentMock
64
import datadog.trace.api.Platform
7-
85
import jvmbootstraptest.InitializationTelemetryCheck
6+
import spock.lang.IgnoreIf
7+
import spock.lang.Specification
8+
import spock.lang.Timeout
99

1010
@Timeout(30)
1111
@IgnoreIf(reason = "SecurityManager is permanently disabled as of JDK 24", value = {
@@ -26,19 +26,39 @@ class InitializationTelemetryTest extends Specification {
2626

2727
def "normal start-up"() {
2828
when:
29-
def result = InitializationTelemetryCheck.runTestJvm(null, false, "sleep")
29+
def result = InitializationTelemetryCheck.runTestJvm(null)
30+
31+
then:
32+
result.exitCode == 0
33+
result.telemetryJson.contains('library_entrypoint.complete')
34+
}
35+
36+
def "test initial telemetry forwarder trace muted"() {
37+
when:
38+
def agent = new SimpleAgentMock().start()
39+
def result = InitializationTelemetryCheck.runTestJvm(null, agent.port)
3040

3141
then:
3242
result.exitCode == 0
3343
result.telemetryJson.contains('library_entrypoint.complete')
44+
45+
// Check that we have only one span related to sub-process execution,
46+
// and it is not initial telemetry forwarder.
47+
agent.spans.size() == 1
48+
def span = agent.spans.get(0)
49+
span.name == 'command_execution'
50+
span.resource == 'echo'
51+
52+
cleanup:
53+
agent.close()
3454
}
3555

3656
def "incomplete agent start-up"() {
3757
// In this case, the SecurityManager blocks a custom permission that is checked by bytebuddy causing
3858
// agent initialization to fail. However, we should catch the exception allowing the application
3959
// to run normally.
4060
when:
41-
def result = InitializationTelemetryCheck.runTestJvm(InitializationTelemetryCheck.BlockByteBuddy, false, "sleep")
61+
def result = InitializationTelemetryCheck.runTestJvm(InitializationTelemetryCheck.BlockByteBuddy)
4262

4363
then:
4464
result.exitCode == 0
@@ -50,7 +70,7 @@ class InitializationTelemetryTest extends Specification {
5070
// In this case, the SecurityManager blocks access to the forwarder environment variable,
5171
// so the tracer is unable to report initialization telemetry
5272
when:
53-
def result = InitializationTelemetryCheck.runTestJvm(InitializationTelemetryCheck.BlockForwarderEnvVar, true)
73+
def result = InitializationTelemetryCheck.runTestJvm(InitializationTelemetryCheck.BlockForwarderEnvVar)
5474

5575
then:
5676
result.exitCode == 0
@@ -62,7 +82,7 @@ class InitializationTelemetryTest extends Specification {
6282
// In this case, the SecurityManager blocks access to process execution, so the tracer is
6383
// unable to invoke the forwarder executable
6484
when:
65-
def result = InitializationTelemetryCheck.runTestJvm(InitializationTelemetryCheck.BlockForwarderExecution, true)
85+
def result = InitializationTelemetryCheck.runTestJvm(InitializationTelemetryCheck.BlockForwarderExecution)
6686

6787
then:
6888
result.exitCode == 0
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package datadog.test;
2+
3+
import datadog.trace.test.agent.decoder.DecodedMessage;
4+
import datadog.trace.test.agent.decoder.DecodedSpan;
5+
import datadog.trace.test.agent.decoder.DecodedTrace;
6+
import datadog.trace.test.agent.decoder.Decoder;
7+
import java.io.Closeable;
8+
import java.io.IOException;
9+
import java.util.List;
10+
import java.util.concurrent.CopyOnWriteArrayList;
11+
import okhttp3.mockwebserver.Dispatcher;
12+
import okhttp3.mockwebserver.MockResponse;
13+
import okhttp3.mockwebserver.MockWebServer;
14+
import okhttp3.mockwebserver.RecordedRequest;
15+
16+
/**
17+
* Simple web server to mock responses from agent and collect spans. We can not use `TestHttpServer`
18+
* from `:dd-java-agent:testing` because it will bring unwanted dependencies into classpath and were
19+
* are trying to make sure that we expose as little as possible into the bootstrap and system class
20+
* loaders.
21+
*/
22+
public class SimpleAgentMock implements Closeable {
23+
private static final MockResponse EMPTY_200_RESPONSE = new MockResponse().setResponseCode(200);
24+
25+
private final MockWebServer server;
26+
private final List<DecodedSpan> spans = new CopyOnWriteArrayList<>();
27+
28+
public SimpleAgentMock() {
29+
server = new MockWebServer();
30+
31+
server.setDispatcher(
32+
new Dispatcher() {
33+
@Override
34+
public MockResponse dispatch(final RecordedRequest request) {
35+
if ("/v0.4/traces".equals(request.getPath())) {
36+
byte[] body = request.getBody().readByteArray();
37+
38+
DecodedMessage message = Decoder.decodeV04(body);
39+
for (DecodedTrace trace : message.getTraces()) {
40+
spans.addAll(trace.getSpans());
41+
}
42+
}
43+
44+
return EMPTY_200_RESPONSE;
45+
}
46+
});
47+
}
48+
49+
public SimpleAgentMock start() throws IOException {
50+
server.start();
51+
52+
return this;
53+
}
54+
55+
public int getPort() {
56+
return server.getPort();
57+
}
58+
59+
public List<DecodedSpan> getSpans() {
60+
return spans;
61+
}
62+
63+
@Override
64+
public void close() throws IOException {
65+
server.shutdown();
66+
}
67+
}

dd-java-agent/src/test/java/jvmbootstraptest/InitializationTelemetryCheck.java

Lines changed: 26 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package jvmbootstraptest;
22

3+
import static datadog.trace.api.ConfigDefaults.DEFAULT_TRACE_AGENT_PORT;
4+
35
import datadog.trace.agent.test.IntegrationTestUtils;
46
import java.io.File;
57
import java.io.FilePermission;
@@ -9,25 +11,34 @@
911
import java.nio.file.Path;
1012
import java.nio.file.attribute.PosixFilePermission;
1113
import java.nio.file.attribute.PosixFilePermissions;
14+
import java.util.ArrayList;
1215
import java.util.Arrays;
1316
import java.util.Collections;
1417
import java.util.HashMap;
1518
import java.util.List;
1619
import java.util.Map;
1720
import java.util.Set;
21+
import java.util.concurrent.TimeUnit;
1822

1923
/**
2024
* Basic sanity check that InitializationTelemetry is functioning
2125
*
2226
* <p>Checks edge cases where InitializationTelemetry is blocked by SecurityManagers
2327
*/
2428
public class InitializationTelemetryCheck {
25-
public static void main(String[] args) throws InterruptedException {
29+
public static void main(String[] args) throws Exception {
2630
// Emulates the real application performing work in main().
27-
// That should give enough time to send initial telemetry from daemon thread.
28-
if (args.length > 0 && "sleep".equals(args[0])) {
29-
Thread.sleep(5000);
31+
// Start sub-process to generate one trace.
32+
try {
33+
ProcessBuilder builder = new ProcessBuilder("echo");
34+
Process process = builder.start();
35+
process.waitFor(5, TimeUnit.SECONDS);
36+
} catch (SecurityException se) {
37+
// Ignore security exceptions, as it can be part of strict security manager test.
3038
}
39+
40+
// That should give enough time to send initial telemetry and traces.
41+
Thread.sleep(2000);
3142
}
3243

3344
/** Blocks the loading of the agent bootstrap */
@@ -79,20 +90,11 @@ protected boolean checkFileExecutePermission(FilePermission perm, Object ctx, St
7990

8091
public static final Result runTestJvm(Class<? extends TestSecurityManager> securityManagerClass)
8192
throws Exception {
82-
return runTestJvm(securityManagerClass, false, null);
83-
}
84-
85-
public static final Result runTestJvm(
86-
Class<? extends TestSecurityManager> securityManagerClass, boolean printStreams)
87-
throws Exception {
88-
return runTestJvm(securityManagerClass, printStreams, null);
93+
return runTestJvm(securityManagerClass, DEFAULT_TRACE_AGENT_PORT);
8994
}
9095

9196
public static final Result runTestJvm(
92-
Class<? extends TestSecurityManager> securityManagerClass,
93-
boolean printStreams,
94-
String mainArgs)
95-
throws Exception {
97+
Class<? extends TestSecurityManager> securityManagerClass, int port) throws Exception {
9698

9799
File jarFile =
98100
IntegrationTestUtils.createJarFileWithClasses(requiredClasses(securityManagerClass));
@@ -101,6 +103,12 @@ public static final Result runTestJvm(
101103
createTempFile("forwarder", "sh", PosixFilePermissions.fromString("rwxr--r--"));
102104
File outputFile = new File(forwarderFile.getAbsoluteFile() + ".out");
103105

106+
List<String> jvmArgs = new ArrayList<>();
107+
jvmArgs.add("-Ddd.trace.agent.port=" + port);
108+
if (securityManagerClass != null) {
109+
jvmArgs.add("-Djava.security.manager=" + securityManagerClass.getName());
110+
}
111+
104112
write(
105113
forwarderFile,
106114
"#!/usr/bin/env bash\n",
@@ -110,11 +118,11 @@ public static final Result runTestJvm(
110118
int exitCode =
111119
IntegrationTestUtils.runOnSeparateJvm(
112120
InitializationTelemetryCheck.class.getName(),
113-
InitializationTelemetryCheck.jvmArgs(securityManagerClass),
114-
InitializationTelemetryCheck.mainArgs(mainArgs),
121+
jvmArgs,
122+
Collections.emptyList(),
115123
InitializationTelemetryCheck.envVars(forwarderFile),
116124
jarFile,
117-
printStreams);
125+
true);
118126

119127
return new Result(exitCode, read(outputFile));
120128
} finally {
@@ -170,23 +178,6 @@ public static final Class<?>[] requiredClasses(
170178
}
171179
}
172180

173-
public static final List<String> jvmArgs(
174-
Class<? extends TestSecurityManager> securityManagerClass) {
175-
if (securityManagerClass == null) {
176-
return Collections.emptyList();
177-
} else {
178-
return Collections.singletonList("-Djava.security.manager=" + securityManagerClass.getName());
179-
}
180-
}
181-
182-
public static final List<String> mainArgs(String args) {
183-
if (args == null) {
184-
return Collections.emptyList();
185-
} else {
186-
return Arrays.asList(args.split(","));
187-
}
188-
}
189-
190181
public static final Map<String, String> envVars(File forwarderFile) {
191182
Map<String, String> envVars = new HashMap<>();
192183
envVars.put("DD_TELEMETRY_FORWARDER_PATH", forwarderFile.getAbsolutePath());

0 commit comments

Comments
 (0)