Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request Test Management tests list #8345

Merged
merged 6 commits into from
Feb 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading