Skip to content

Commit

Permalink
Request Test Management tests list (#8345)
Browse files Browse the repository at this point in the history
  • Loading branch information
daniel-mohedano authored Feb 11, 2025
1 parent added74 commit 2964589
Show file tree
Hide file tree
Showing 31 changed files with 976 additions and 253 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package datadog.trace.civisibility.config;

import datadog.trace.api.civisibility.config.TestIdentifier;
import datadog.trace.api.civisibility.config.TestFQN;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
Expand All @@ -22,13 +22,19 @@ public SkippableTests getSkippableTests(TracerEnvironment tracerEnvironment) {
}

@Override
public Map<String, Collection<TestIdentifier>> getFlakyTestsByModule(
public Map<String, Collection<TestFQN>> getFlakyTestsByModule(
TracerEnvironment tracerEnvironment) {
return Collections.emptyMap();
}

@Override
public Map<String, Collection<TestIdentifier>> getKnownTestsByModule(
public Map<String, Collection<TestFQN>> getKnownTestsByModule(
TracerEnvironment tracerEnvironment) {
return Collections.emptyMap();
}

@Override
public Map<TestSetting, Map<String, Collection<TestFQN>>> getTestManagementTestsByModule(
TracerEnvironment tracerEnvironment) {
return Collections.emptyMap();
}
Expand All @@ -43,12 +49,15 @@ public ChangedFiles getChangedFiles(TracerEnvironment tracerEnvironment) {

SkippableTests getSkippableTests(TracerEnvironment tracerEnvironment) throws IOException;

Map<String, Collection<TestIdentifier>> getFlakyTestsByModule(TracerEnvironment tracerEnvironment)
Map<String, Collection<TestFQN>> getFlakyTestsByModule(TracerEnvironment tracerEnvironment)
throws IOException;

@Nullable
Map<String, Collection<TestIdentifier>> getKnownTestsByModule(TracerEnvironment tracerEnvironment)
Map<String, Collection<TestFQN>> getKnownTestsByModule(TracerEnvironment tracerEnvironment)
throws IOException;

Map<TestSetting, Map<String, Collection<TestFQN>>> getTestManagementTestsByModule(
TracerEnvironment tracerEnvironment) throws IOException;

ChangedFiles getChangedFiles(TracerEnvironment tracerEnvironment) throws IOException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import datadog.communication.BackendApi;
import datadog.communication.http.OkHttpUtils;
import datadog.trace.api.civisibility.config.Configurations;
import datadog.trace.api.civisibility.config.TestFQN;
import datadog.trace.api.civisibility.config.TestIdentifier;
import datadog.trace.api.civisibility.config.TestMetadata;
import datadog.trace.api.civisibility.telemetry.CiVisibilityCountMetric;
Expand Down Expand Up @@ -54,6 +55,7 @@ public class ConfigurationApiImpl implements ConfigurationApi {
private static final String CHANGED_FILES_URI = "ci/tests/diffs";
private static final String FLAKY_TESTS_URI = "ci/libraries/tests/flaky";
private static final String KNOWN_TESTS_URI = "ci/libraries/tests";
private static final String TEST_MANAGEMENT_TESTS_URI = "test/libraries/test-management/tests";

private final BackendApi backendApi;
private final CiVisibilityMetricCollector metricCollector;
Expand All @@ -63,6 +65,7 @@ public class ConfigurationApiImpl implements ConfigurationApi {
private final JsonAdapter<EnvelopeDto<CiVisibilitySettings>> settingsResponseAdapter;
private final JsonAdapter<MultiEnvelopeDto<TestIdentifierJson>> testIdentifiersResponseAdapter;
private final JsonAdapter<EnvelopeDto<KnownTestsDto>> testFullNamesResponseAdapter;
private final JsonAdapter<EnvelopeDto<TestManagementTestsDto>> testManagementTestsResponseAdapter;
private final JsonAdapter<EnvelopeDto<ChangedFiles>> changedFilesResponseAdapter;

public ConfigurationApiImpl(BackendApi backendApi, CiVisibilityMetricCollector metricCollector) {
Expand Down Expand Up @@ -105,6 +108,11 @@ public ConfigurationApiImpl(BackendApi backendApi, CiVisibilityMetricCollector m
ConfigurationApiImpl.class, EnvelopeDto.class, KnownTestsDto.class);
testFullNamesResponseAdapter = moshi.adapter(testFullNamesResponseType);

ParameterizedType testManagementTestsResponseType =
Types.newParameterizedTypeWithOwner(
ConfigurationApiImpl.class, EnvelopeDto.class, TestManagementTestsDto.class);
testManagementTestsResponseAdapter = moshi.adapter(testManagementTestsResponseType);

ParameterizedType changedFilesResponseAdapterType =
Types.newParameterizedTypeWithOwner(
ConfigurationApiImpl.class, EnvelopeDto.class, ChangedFiles.class);
Expand Down Expand Up @@ -202,8 +210,8 @@ public SkippableTests getSkippableTests(TracerEnvironment tracerEnvironment) thr
}

@Override
public Map<String, Collection<TestIdentifier>> getFlakyTestsByModule(
TracerEnvironment tracerEnvironment) throws IOException {
public Map<String, Collection<TestFQN>> getFlakyTestsByModule(TracerEnvironment tracerEnvironment)
throws IOException {
OkHttpUtils.CustomListener telemetryListener =
new TelemetryListener.Builder(metricCollector)
.requestCount(CiVisibilityCountMetric.FLAKY_TESTS_REQUEST)
Expand Down Expand Up @@ -231,15 +239,15 @@ public Map<String, Collection<TestIdentifier>> getFlakyTestsByModule(
Configurations requestConf = tracerEnvironment.getConfigurations();

int flakyTestsCount = 0;
Map<String, Collection<TestIdentifier>> testIdentifiers = new HashMap<>();
Map<String, Collection<TestFQN>> testIdentifiers = new HashMap<>();
for (DataDto<TestIdentifierJson> dataDto : response) {
TestIdentifierJson testIdentifierJson = dataDto.getAttributes();
Configurations conf = testIdentifierJson.getConfigurations();
String moduleName =
(conf != null && conf.getTestBundle() != null ? conf : requestConf).getTestBundle();
testIdentifiers
.computeIfAbsent(moduleName, k -> new HashSet<>())
.add(testIdentifierJson.toTestIdentifier());
.add(testIdentifierJson.toTestIdentifier().toFQN());
flakyTestsCount++;
}

Expand All @@ -249,8 +257,8 @@ public Map<String, Collection<TestIdentifier>> getFlakyTestsByModule(

@Nullable
@Override
public Map<String, Collection<TestIdentifier>> getKnownTestsByModule(
TracerEnvironment tracerEnvironment) throws IOException {
public Map<String, Collection<TestFQN>> getKnownTestsByModule(TracerEnvironment tracerEnvironment)
throws IOException {
OkHttpUtils.CustomListener telemetryListener =
new TelemetryListener.Builder(metricCollector)
.requestCount(CiVisibilityCountMetric.KNOWN_TESTS_REQUEST)
Expand All @@ -276,10 +284,10 @@ public Map<String, Collection<TestIdentifier>> getKnownTestsByModule(
return parseTestIdentifiers(knownTests);
}

private Map<String, Collection<TestIdentifier>> parseTestIdentifiers(KnownTestsDto knownTests) {
private Map<String, Collection<TestFQN>> parseTestIdentifiers(KnownTestsDto knownTests) {
int knownTestsCount = 0;

Map<String, Collection<TestIdentifier>> testIdentifiers = new HashMap<>();
Map<String, Collection<TestFQN>> testIdentifiers = new HashMap<>();
for (Map.Entry<String, Map<String, List<String>>> e : knownTests.tests.entrySet()) {
String moduleName = e.getKey();
Map<String, List<String>> testsBySuiteName = e.getValue();
Expand All @@ -292,7 +300,7 @@ private Map<String, Collection<TestIdentifier>> parseTestIdentifiers(KnownTestsD
for (String testName : testNames) {
testIdentifiers
.computeIfAbsent(moduleName, k -> new HashSet<>())
.add(new TestIdentifier(suiteName, testName, null));
.add(new TestFQN(suiteName, testName));
}
}
}
Expand All @@ -309,6 +317,90 @@ private Map<String, Collection<TestIdentifier>> parseTestIdentifiers(KnownTestsD
: null;
}

@Override
public Map<TestSetting, Map<String, Collection<TestFQN>>> getTestManagementTestsByModule(
TracerEnvironment tracerEnvironment) throws IOException {
OkHttpUtils.CustomListener telemetryListener =
new TelemetryListener.Builder(metricCollector)
.requestCount(CiVisibilityCountMetric.TEST_MANAGEMENT_TESTS_REQUEST)
.requestErrors(CiVisibilityCountMetric.TEST_MANAGEMENT_TESTS_REQUEST_ERRORS)
.requestDuration(CiVisibilityDistributionMetric.TEST_MANAGEMENT_TESTS_REQUEST_MS)
.responseBytes(CiVisibilityDistributionMetric.TEST_MANAGEMENT_TESTS_RESPONSE_BYTES)
.build();

String uuid = uuidGenerator.get();
EnvelopeDto<TracerEnvironment> request =
new EnvelopeDto<>(new DataDto<>(uuid, "ci_app_libraries_tests_request", tracerEnvironment));
String json = requestAdapter.toJson(request);
RequestBody requestBody = RequestBody.create(JSON, json);
TestManagementTestsDto testManagementTestsDto =
backendApi.post(
TEST_MANAGEMENT_TESTS_URI,
requestBody,
is ->
testManagementTestsResponseAdapter.fromJson(Okio.buffer(Okio.source(is)))
.data
.attributes,
telemetryListener,
false);

return parseTestManagementTests(testManagementTestsDto);
}

private Map<TestSetting, Map<String, Collection<TestFQN>>> parseTestManagementTests(
TestManagementTestsDto testsManagementTestsDto) {
int testManagementTestsCount = 0;

Map<String, Collection<TestFQN>> quarantinedTestsByModule = new HashMap<>();
Map<String, Collection<TestFQN>> disabledTestsByModule = new HashMap<>();
Map<String, Collection<TestFQN>> attemptToFixTestsByModule = new HashMap<>();

for (Map.Entry<String, TestManagementTestsDto.Suites> e :
testsManagementTestsDto.getModules().entrySet()) {
String moduleName = e.getKey();
Map<String, TestManagementTestsDto.Tests> testsBySuiteName = e.getValue().getSuites();

for (Map.Entry<String, TestManagementTestsDto.Tests> se : testsBySuiteName.entrySet()) {
String suiteName = se.getKey();
Map<String, TestManagementTestsDto.Properties> tests = se.getValue().getTests();

testManagementTestsCount += tests.size();

for (Map.Entry<String, TestManagementTestsDto.Properties> te : tests.entrySet()) {
String testName = te.getKey();
TestManagementTestsDto.Properties properties = te.getValue();
if (properties.isQuarantined()) {
quarantinedTestsByModule
.computeIfAbsent(moduleName, k -> new HashSet<>())
.add(new TestFQN(suiteName, testName));
}
if (properties.isDisabled()) {
disabledTestsByModule
.computeIfAbsent(moduleName, k -> new HashSet<>())
.add(new TestFQN(suiteName, testName));
}
if (properties.isAttemptToFix()) {
attemptToFixTestsByModule
.computeIfAbsent(moduleName, k -> new HashSet<>())
.add(new TestFQN(suiteName, testName));
}
}
}
}

Map<TestSetting, Map<String, Collection<TestFQN>>> testsByTypeByModule = new HashMap<>();
testsByTypeByModule.put(TestSetting.QUARANTINED, quarantinedTestsByModule);
testsByTypeByModule.put(TestSetting.DISABLED, disabledTestsByModule);
testsByTypeByModule.put(TestSetting.ATTEMPT_TO_FIX, attemptToFixTestsByModule);

LOGGER.debug("Received {} test management tests in total", testManagementTestsCount);
metricCollector.add(
CiVisibilityDistributionMetric.TEST_MANAGEMENT_TESTS_RESPONSE_TESTS,
testManagementTestsCount);

return testsByTypeByModule;
}

@Override
public ChangedFiles getChangedFiles(TracerEnvironment tracerEnvironment) throws IOException {
OkHttpUtils.CustomListener telemetryListener =
Expand Down Expand Up @@ -427,4 +519,66 @@ private KnownTestsDto(Map<String, Map<String, List<String>>> tests) {
this.tests = tests;
}
}

private static final class TestManagementTestsDto {
private static final class Properties {
private final Map<String, Boolean> properties;

private Properties(Map<String, Boolean> properties) {
this.properties = properties;
}

public Boolean isQuarantined() {
return properties != null
? properties.getOrDefault(TestSetting.QUARANTINED.asString(), false)
: false;
}

public Boolean isDisabled() {
return properties != null
? properties.getOrDefault(TestSetting.DISABLED.asString(), false)
: false;
}

public Boolean isAttemptToFix() {
return properties != null
? properties.getOrDefault(TestSetting.ATTEMPT_TO_FIX.asString(), false)
: false;
}
}

private static final class Tests {
private final Map<String, Properties> tests;

private Tests(Map<String, Properties> tests) {
this.tests = tests;
}

public Map<String, Properties> getTests() {
return tests != null ? tests : Collections.emptyMap();
}
}

private static final class Suites {
private final Map<String, Tests> suites;

private Suites(Map<String, Tests> suites) {
this.suites = suites;
}

public Map<String, Tests> getSuites() {
return suites != null ? suites : Collections.emptyMap();
}
}

private final Map<String, Suites> modules;

private TestManagementTestsDto(Map<String, Suites> modules) {
this.modules = modules;
}

public Map<String, Suites> getModules() {
return modules != null ? modules : Collections.emptyMap();
}
}
}
Loading

0 comments on commit 2964589

Please sign in to comment.