Skip to content

Commit 4524f7b

Browse files
Fix NPE in logic that parses flaky tests list (#8070)
1 parent 88c9405 commit 4524f7b

File tree

2 files changed

+157
-5
lines changed

2 files changed

+157
-5
lines changed

dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ConfigurationApiImpl.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,8 @@ public SkippableTests getSkippableTests(TracerEnvironment tracerEnvironment) thr
168168
for (DataDto<TestIdentifierJson> dataDto : response.data) {
169169
TestIdentifierJson testIdentifierJson = dataDto.getAttributes();
170170
Configurations conf = testIdentifierJson.getConfigurations();
171-
String moduleName = (conf != null ? conf : requestConf).getTestBundle();
171+
String moduleName =
172+
(conf != null && conf.getTestBundle() != null ? conf : requestConf).getTestBundle();
172173
testIdentifiersByModule
173174
.computeIfAbsent(moduleName, k -> new HashMap<>())
174175
.put(testIdentifierJson.toTestIdentifier(), testIdentifierJson.toTestMetadata());
@@ -211,12 +212,15 @@ public Map<String, Collection<TestIdentifier>> getFlakyTestsByModule(
211212

212213
LOGGER.debug("Received {} flaky tests in total", response.size());
213214

215+
Configurations requestConf = tracerEnvironment.getConfigurations();
216+
214217
int flakyTestsCount = 0;
215218
Map<String, Collection<TestIdentifier>> testIdentifiers = new HashMap<>();
216219
for (DataDto<TestIdentifierJson> dataDto : response) {
217220
TestIdentifierJson testIdentifierJson = dataDto.getAttributes();
218-
Configurations configurations = testIdentifierJson.getConfigurations();
219-
String moduleName = configurations.getTestBundle();
221+
Configurations conf = testIdentifierJson.getConfigurations();
222+
String moduleName =
223+
(conf != null && conf.getTestBundle() != null ? conf : requestConf).getTestBundle();
220224
testIdentifiers
221225
.computeIfAbsent(moduleName, k -> new HashSet<>())
222226
.add(testIdentifierJson.toTestIdentifier());

dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/config/ConfigurationApiImplTest.groovy

Lines changed: 150 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,12 +142,14 @@ class ConfigurationApiImplTest extends Specification {
142142
return
143143
}
144144

145+
def testBundle = requestConfs['test.bundle']
146+
145147
def moduleATest = """{
146148
"id": "49968354e2091cdb",
147149
"type": "test",
148150
"attributes": {
149151
"configurations": {
150-
"test.bundle": "testBundle-a",
152+
${!testBundle ? '"test.bundle": "testBundle-a",' : ""}
151153
"custom": {
152154
"customTag": "customValue"
153155
}
@@ -164,7 +166,7 @@ class ConfigurationApiImplTest extends Specification {
164166
"type": "test",
165167
"attributes": {
166168
"configurations": {
167-
"test.bundle": "testBundle-b",
169+
${!testBundle ? '"test.bundle": "testBundle-b",' : ""}
168170
"custom": {
169171
"customTag": "customValue"
170172
}
@@ -175,8 +177,115 @@ class ConfigurationApiImplTest extends Specification {
175177
}
176178
}"""
177179

180+
def tests = []
181+
if (!testBundle || testBundle == 'testBundle-a') {
182+
tests << moduleATest
183+
}
184+
if (!testBundle || testBundle == 'testBundle-b') {
185+
tests << moduleBTest
186+
}
187+
188+
def response = response
189+
def requestBody = """
190+
{
191+
"data": [
192+
${tests.join(',')}
193+
],
194+
"meta": {
195+
"correlation_id": "11223344",
196+
"coverage": {
197+
"src/main/java/Calculator.java": "/8AA/w==",
198+
"src/main/java/utils/Math.java": "AAAAf+AA/A==",
199+
"src/test/java/CalculatorTest.java": "//AAeAAA/A=="
200+
}
201+
}
202+
}
203+
""".bytes
204+
205+
def header = request.getHeader("Accept-Encoding")
206+
def gzipSupported = header != null && header.contains("gzip")
207+
if (gzipSupported) {
208+
response.addHeader("Content-Encoding", "gzip")
209+
requestBody = gzip(requestBody)
210+
}
211+
212+
response.status(200).send(requestBody)
213+
}
214+
215+
prefix("/api/v2/ci/libraries/tests/flaky") {
216+
def requestJson = moshi.adapter(Map).fromJson(new String(request.body))
217+
218+
// assert request contents
219+
def requestData = requestJson['data']
220+
if (requestData['type'] != "flaky_test_from_libraries_params"
221+
|| requestData['id'] != "1234"
222+
) {
223+
response.status(400).send()
224+
return
225+
}
226+
227+
def requestAttrs = requestData['attributes']
228+
if (requestAttrs['service'] != "foo"
229+
|| requestAttrs['env'] != "foo_env"
230+
|| requestAttrs['repository_url'] != "https://github.com/DataDog/foo"
231+
|| requestAttrs['branch'] != "prod"
232+
|| requestAttrs['sha'] != "d64185e45d1722ab3a53c45be47accae"
233+
|| requestAttrs['test_level'] != "test"
234+
) {
235+
response.status(400).send()
236+
return
237+
}
238+
239+
def requestConfs = requestAttrs['configurations']
240+
if (requestConfs['os.platform'] != "linux"
241+
|| requestConfs['os.architecture'] != "amd64"
242+
|| requestConfs['os.arch'] != "amd64"
243+
|| requestConfs['os.version'] != "bionic"
244+
|| requestConfs['runtime.name'] != "runtimeName"
245+
|| requestConfs['runtime.version'] != "runtimeVersion"
246+
|| requestConfs['runtime.vendor'] != "vendor"
247+
|| requestConfs['runtime.architecture'] != "amd64"
248+
|| requestConfs['custom']['customTag'] != "customValue"
249+
) {
250+
response.status(400).send()
251+
return
252+
}
253+
178254
def testBundle = requestConfs['test.bundle']
179255

256+
def moduleATest = """{
257+
"id": "49968354e2091cdb",
258+
"type": "test",
259+
"attributes": {
260+
"configurations": {
261+
${!testBundle ? '"test.bundle": "testBundle-a",' : ""}
262+
"custom": {
263+
"customTag": "customValue"
264+
}
265+
},
266+
"suite": "suite-a",
267+
"name": "name-a",
268+
"parameters": "parameters-a",
269+
"_missing_line_code_coverage": true
270+
}
271+
}"""
272+
273+
def moduleBTest = """{
274+
"id": "49968354e2091cdc",
275+
"type": "test",
276+
"attributes": {
277+
"configurations": {
278+
${!testBundle ? '"test.bundle": "testBundle-b",' : ""}
279+
"custom": {
280+
"customTag": "customValue"
281+
}
282+
},
283+
"suite": "suite-b",
284+
"name": "name-b",
285+
"parameters": "parameters-b"
286+
}
287+
}"""
288+
180289
def tests = []
181290
if (!testBundle || testBundle == 'testBundle-a') {
182291
tests << moduleATest
@@ -372,6 +481,45 @@ class ConfigurationApiImplTest extends Specification {
372481
]
373482
}
374483

484+
def "test flaky tests request: #displayName"() {
485+
given:
486+
def tracerEnvironment = givenTracerEnvironment()
487+
def metricCollector = Stub(CiVisibilityMetricCollector)
488+
489+
when:
490+
def configurationApi = new ConfigurationApiImpl(api, metricCollector, () -> "1234")
491+
def flakyTests = configurationApi.getFlakyTestsByModule(tracerEnvironment)
492+
493+
then:
494+
flakyTests == [
495+
"testBundle-a": new HashSet<>([ new TestIdentifier("suite-a", "name-a", "parameters-a") ]),
496+
"testBundle-b": new HashSet<>([ new TestIdentifier("suite-b", "name-b", "parameters-b") ]),
497+
]
498+
499+
where:
500+
api | displayName
501+
givenEvpProxy(false) | "EVP proxy, compression disabled"
502+
givenEvpProxy(true) | "EVP proxy, compression enabled"
503+
givenIntakeApi(false) | "intake, compression disabled"
504+
givenIntakeApi(true) | "intake, compression enabled"
505+
}
506+
507+
def "test flaky tests request with module name"() {
508+
given:
509+
def tracerEnvironment = givenTracerEnvironment("testBundle-a")
510+
def metricCollector = Stub(CiVisibilityMetricCollector)
511+
def api = givenIntakeApi(false)
512+
513+
when:
514+
def configurationApi = new ConfigurationApiImpl(api, metricCollector, () -> "1234")
515+
def flakyTests = configurationApi.getFlakyTestsByModule(tracerEnvironment)
516+
517+
then:
518+
flakyTests == [
519+
"testBundle-a": new HashSet<>([ new TestIdentifier("suite-a", "name-a", "parameters-a") ])
520+
]
521+
}
522+
375523
private static BitSet bits(int... bits) {
376524
BitSet bitSet = new BitSet()
377525
for (int bit : bits) {

0 commit comments

Comments
 (0)