Skip to content

Commit 0b12d08

Browse files
committed
Add smoke tests for telemetry
1 parent 9e8d0dc commit 0b12d08

File tree

3 files changed

+105
-1
lines changed

3 files changed

+105
-1
lines changed

dd-smoke-tests/spring-boot-2.3-webmvc-jetty/src/test/groovy/SpringBootWebmvcIntegrationTest.groovy

+5
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,9 @@ class SpringBootWebmvcIntegrationTest extends AbstractServerSmokeTest {
8686
response.code() == 404
8787
waitForTraceCount(1)
8888
}
89+
90+
@Override
91+
List<String> expectedTelemetryDependencies() {
92+
['org.eclipse.jetty:jetty-client']
93+
}
8994
}

dd-smoke-tests/src/main/groovy/datadog/smoketest/AbstractServerSmokeTest.groovy

+45
Original file line numberDiff line numberDiff line change
@@ -116,4 +116,49 @@ abstract class AbstractServerSmokeTest extends AbstractSmokeTest {
116116
}
117117
return remaining
118118
}
119+
120+
void 'receive telemetry app-started'() {
121+
when:
122+
waitForTelemetryCount(1)
123+
124+
then:
125+
telemetryMessages.size() >= 1
126+
Object msg = telemetryMessages.get(0)
127+
msg['request_type'] == 'app-started'
128+
}
129+
130+
List<String> expectedTelemetryDependencies() {
131+
[]
132+
}
133+
134+
void 'receive telemetry app-dependencies-loaded'() {
135+
when:
136+
// app-started + 3 message-batch
137+
waitForTelemetryCount(4)
138+
waitForTelemetryFlat { it.get('request_type') == 'app-dependencies-loaded' }
139+
140+
then: 'received some dependencies'
141+
def dependenciesLoaded = telemetryFlatMessages.findAll { it.get('request_type') == 'app-dependencies-loaded' }
142+
def dependencies = []
143+
dependenciesLoaded.each {
144+
def payload = it.get('payload') as Map<String, Object>
145+
dependencies.addAll(payload.get('dependencies')) }
146+
dependencies.size() > 0
147+
148+
Set<String> dependencyNames = dependencies.collect {
149+
def dependency = it as Map<String, Object>
150+
dependency.get('name') as String
151+
}.toSet()
152+
153+
and: 'received tracer dependencies'
154+
// Not exhaustive list of tracer dependencies.
155+
Set<String> missingDependencyNames = ['com.github.jnr:jnr-ffi', 'net.bytebuddy:byte-buddy-agent',].toSet()
156+
missingDependencyNames.removeAll(dependencyNames) || true
157+
missingDependencyNames.isEmpty()
158+
159+
and: 'received application dependencies'
160+
Set<String> missingExtraDependencyNames = expectedTelemetryDependencies().toSet()
161+
missingExtraDependencyNames.removeAll(dependencyNames) || true
162+
missingExtraDependencyNames.isEmpty()
163+
}
119164
}

dd-smoke-tests/src/main/groovy/datadog/smoketest/AbstractSmokeTest.groovy

+55-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import datadog.trace.test.agent.decoder.Decoder
77
import datadog.trace.test.agent.decoder.DecodedMessage
88
import datadog.trace.test.agent.decoder.DecodedTrace
99
import datadog.trace.util.Strings
10+
import groovy.json.JsonSlurper
1011

1112
import java.nio.charset.StandardCharsets
1213
import java.util.concurrent.CopyOnWriteArrayList
@@ -28,6 +29,12 @@ abstract class AbstractSmokeTest extends ProcessManager {
2829
@Shared
2930
protected CopyOnWriteArrayList<DecodedTrace> decodeTraces = new CopyOnWriteArrayList()
3031

32+
@Shared
33+
protected CopyOnWriteArrayList<Map<String, Object>> telemetryMessages = new CopyOnWriteArrayList()
34+
35+
@Shared
36+
protected CopyOnWriteArrayList<Map<String, Object>> telemetryFlatMessages = new CopyOnWriteArrayList()
37+
3138
@Shared
3239
private Closure decode = decodedTracesCallback()
3340

@@ -37,6 +44,9 @@ abstract class AbstractSmokeTest extends ProcessManager {
3744
@Shared
3845
private Throwable traceDecodingFailure = null
3946

47+
@Shared
48+
private Throwable telemetryDecodingFailure = null
49+
4050
@Shared
4151
@AutoCleanup
4252
protected TestHttpServer server = httpServer {
@@ -111,6 +121,24 @@ abstract class AbstractSmokeTest extends ProcessManager {
111121
response.status(200).send(remoteConfigResponse)
112122
}
113123
prefix("/telemetry/proxy/api/v2/apmtelemetry") {
124+
def body = request.getBody()
125+
if (body != null) {
126+
Map<String, Object> msg = null
127+
try {
128+
msg = new JsonSlurper().parseText(new String(body, StandardCharsets.UTF_8)) as Map<String, Object>
129+
} catch (Throwable t) {
130+
println("=== Failure during telemetry decoding ===")
131+
t.printStackTrace(System.out)
132+
telemetryDecodingFailure = t
133+
throw t
134+
}
135+
telemetryMessages.add(msg)
136+
if (msg.get("request_type") == "message-batch") {
137+
msg.get("payload")?.each { telemetryFlatMessages.add(it as Map<String, Object>) }
138+
} else {
139+
telemetryFlatMessages.add(msg)
140+
}
141+
}
114142
response.status(202).send()
115143
}
116144
}
@@ -147,7 +175,8 @@ abstract class AbstractSmokeTest extends ProcessManager {
147175
"-Ddd.profiling.ddprof.alloc.enabled=${isDdprofSafe()}",
148176
"-Ddatadog.slf4j.simpleLogger.defaultLogLevel=${logLevel()}",
149177
"-Dorg.slf4j.simpleLogger.defaultLogLevel=${logLevel()}",
150-
"-Ddd.site="
178+
"-Ddd.site=",
179+
"-Ddd.telemetry.heartbeat.interval=2",
151180
]
152181
if (inferServiceName()) {
153182
ret += "-Ddd.service.name=${SERVICE_NAME}"
@@ -268,6 +297,31 @@ abstract class AbstractSmokeTest extends ProcessManager {
268297
decodeTraces
269298
}
270299

300+
void waitForTelemetryCount(final int count) {
301+
def conditions = new PollingConditions(timeout: 30, initialDelay: 0, delay: 1, factor: 1)
302+
waitForTelemetryCount(conditions, count)
303+
}
304+
305+
void waitForTelemetryCount(final PollingConditions poll, final int count) {
306+
poll.eventually {
307+
telemetryMessages.size() >= count
308+
}
309+
}
310+
311+
void waitForTelemetryFlat(final Function<Map<String, Object>, Boolean> predicate) {
312+
def conditions = new PollingConditions(timeout: 30, initialDelay: 0, delay: 1, factor: 1)
313+
waitForTelemetryFlat(conditions, predicate)
314+
}
315+
316+
void waitForTelemetryFlat(final PollingConditions poll, final Function<Map<String, Object>, Boolean> predicate) {
317+
poll.eventually {
318+
if (telemetryDecodingFailure != null) {
319+
throw telemetryDecodingFailure
320+
}
321+
assert telemetryFlatMessages.find { predicate.apply(it) } != null
322+
}
323+
}
324+
271325
def logLevel() {
272326
return "info"
273327
}

0 commit comments

Comments
 (0)