From 428865d2433349b52e91519833b30c32a716fcbf Mon Sep 17 00:00:00 2001 From: Daniel Mohedano Date: Thu, 6 Feb 2025 11:00:43 +0100 Subject: [PATCH] request quarantined, disabled and attempt to fix tests list --- .../civisibility/config/ConfigurationApi.java | 9 ++ .../config/ConfigurationApiImpl.java | 147 ++++++++++++++++++ .../config/ExecutionSettings.java | 60 +++++-- .../config/ExecutionSettingsFactoryImpl.java | 40 ++++- .../config/ConfigurationApiImplTest.groovy | 40 +++++ .../config/ExecutionSettingsTest.groovy | 16 +- .../config/test-management-tests-request.ftl | 29 ++++ .../config/test-management-tests-response.ftl | 58 +++++++ .../CiVisibilityInstrumentationTest.groovy | 20 ++- .../telemetry/CiVisibilityCountMetric.java | 7 +- .../CiVisibilityDistributionMetric.java | 8 +- 11 files changed, 409 insertions(+), 25 deletions(-) create mode 100644 dd-java-agent/agent-ci-visibility/src/test/resources/datadog/trace/civisibility/config/test-management-tests-request.ftl create mode 100644 dd-java-agent/agent-ci-visibility/src/test/resources/datadog/trace/civisibility/config/test-management-tests-response.ftl diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ConfigurationApi.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ConfigurationApi.java index 69239fce6a6..34752c5fde7 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ConfigurationApi.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ConfigurationApi.java @@ -33,6 +33,12 @@ public Map> getKnownTestsByModule( return Collections.emptyMap(); } + @Override + public Map>> getTestManagementTestsByModule( + TracerEnvironment tracerEnvironment) { + return Collections.emptyMap(); + } + @Override public ChangedFiles getChangedFiles(TracerEnvironment tracerEnvironment) { return ChangedFiles.EMPTY; @@ -50,5 +56,8 @@ Map> getFlakyTestsByModule(TracerEnvironment Map> getKnownTestsByModule(TracerEnvironment tracerEnvironment) throws IOException; + Map>> getTestManagementTestsByModule( + TracerEnvironment tracerEnvironment) throws IOException; + ChangedFiles getChangedFiles(TracerEnvironment tracerEnvironment) throws IOException; } diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ConfigurationApiImpl.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ConfigurationApiImpl.java index c2330e584fd..ec488aaeb2b 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ConfigurationApiImpl.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ConfigurationApiImpl.java @@ -54,6 +54,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; @@ -63,6 +64,7 @@ public class ConfigurationApiImpl implements ConfigurationApi { private final JsonAdapter> settingsResponseAdapter; private final JsonAdapter> testIdentifiersResponseAdapter; private final JsonAdapter> testFullNamesResponseAdapter; + private final JsonAdapter> testManagementTestsResponseAdapter; private final JsonAdapter> changedFilesResponseAdapter; public ConfigurationApiImpl(BackendApi backendApi, CiVisibilityMetricCollector metricCollector) { @@ -105,6 +107,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); @@ -309,6 +316,90 @@ private Map> parseTestIdentifiers(KnownTestsD : null; } + @Override + public Map>> getTestManagementTestsByModule( + TracerEnvironment tracerEnvironment) throws IOException { + OkHttpUtils.CustomListener telemetryListener = + new TelemetryListener.Builder(metricCollector) + .requestCount(CiVisibilityCountMetric.TEST_MANAGEMENT_TESTS_DETECTION_REQUEST) + .requestErrors(CiVisibilityCountMetric.TEST_MANAGEMENT_TESTS_DETECTION_REQUEST_ERRORS) + .requestDuration(CiVisibilityDistributionMetric.TEST_MANAGEMENT_TESTS_REQUEST_MS) + .responseBytes(CiVisibilityDistributionMetric.TEST_MANAGEMENT_TESTS_RESPONSE_BYTES) + .build(); + + String uuid = uuidGenerator.get(); + EnvelopeDto 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>> parseTestManagementTests( + TestManagementTestsDto testsManagementTestsDto) { + int testManagementTestsCount = 0; + + Map> quarantinedTestsByModule = new HashMap<>(); + Map> disabledTestsByModule = new HashMap<>(); + Map> attemptToFixTestsByModule = new HashMap<>(); + + for (Map.Entry e : + testsManagementTestsDto.getModules().entrySet()) { + String moduleName = e.getKey(); + Map testsBySuiteName = e.getValue().getSuites(); + + for (Map.Entry se : testsBySuiteName.entrySet()) { + String suiteName = se.getKey(); + Map tests = se.getValue().getTests(); + + testManagementTestsCount += tests.size(); + + for (Map.Entry te : tests.entrySet()) { + String testName = te.getKey(); + TestManagementTestsDto.Properties properties = te.getValue(); + if (properties.isQuarantined()) { + quarantinedTestsByModule + .computeIfAbsent(moduleName, k -> new HashSet<>()) + .add(new TestIdentifier(suiteName, testName, null)); + } + if (properties.isDisabled()) { + disabledTestsByModule + .computeIfAbsent(moduleName, k -> new HashSet<>()) + .add(new TestIdentifier(suiteName, testName, null)); + } + if (properties.isAttemptToFix()) { + attemptToFixTestsByModule + .computeIfAbsent(moduleName, k -> new HashSet<>()) + .add(new TestIdentifier(suiteName, testName, null)); + } + } + } + } + + Map>> testsByTypeByModule = new HashMap<>(); + testsByTypeByModule.put("quarantined", quarantinedTestsByModule); + testsByTypeByModule.put("disabled", disabledTestsByModule); + testsByTypeByModule.put("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 = @@ -427,4 +518,60 @@ private KnownTestsDto(Map>> tests) { this.tests = tests; } } + + private static final class TestManagementTestsDto { + private static final class Properties { + private final Map properties; + + private Properties(Map properties) { + this.properties = properties; + } + + public Boolean isQuarantined() { + return properties != null ? properties.getOrDefault("quarantined", false) : false; + } + + public Boolean isDisabled() { + return properties != null ? properties.getOrDefault("disabled", false) : false; + } + + public Boolean isAttemptToFix() { + return properties != null ? properties.getOrDefault("attempt_to_fix", false) : false; + } + } + + private static final class Tests { + private final Map tests; + + private Tests(Map tests) { + this.tests = tests; + } + + public Map getTests() { + return tests != null ? tests : Collections.emptyMap(); + } + } + + private static final class Suites { + private final Map suites; + + private Suites(Map suites) { + this.suites = suites; + } + + public Map getSuites() { + return suites != null ? suites : Collections.emptyMap(); + } + } + + private final Map modules; + + private TestManagementTestsDto(Map modules) { + this.modules = modules; + } + + public Map getModules() { + return modules != null ? modules : Collections.emptyMap(); + } + } } diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ExecutionSettings.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ExecutionSettings.java index 70a9003b2a3..3480bd64d4a 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ExecutionSettings.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ExecutionSettings.java @@ -29,9 +29,11 @@ public class ExecutionSettings { null, Collections.emptyMap(), Collections.emptyMap(), - Collections.emptyList(), null, null, + Collections.emptyList(), + Collections.emptyList(), + Collections.emptyList(), LineDiff.EMPTY); private final boolean itrEnabled; @@ -44,9 +46,11 @@ public class ExecutionSettings { @Nullable private final String itrCorrelationId; @Nonnull private final Map skippableTests; @Nonnull private final Map skippableTestsCoverage; - @Nonnull private final Collection quarantinedTests; @Nullable private final Collection flakyTests; @Nullable private final Collection knownTests; + @Nonnull private final Collection quarantinedTests; + @Nonnull private final Collection disabledTests; + @Nonnull private final Collection attemptToFixTests; @Nonnull private final Diff pullRequestDiff; public ExecutionSettings( @@ -60,9 +64,11 @@ public ExecutionSettings( @Nullable String itrCorrelationId, @Nonnull Map skippableTests, @Nonnull Map skippableTestsCoverage, - @Nonnull Collection quarantinedTests, @Nullable Collection flakyTests, @Nullable Collection knownTests, + @Nonnull Collection quarantinedTests, + @Nonnull Collection disabledTests, + @Nonnull Collection attemptToFixTests, @Nonnull Diff pullRequestDiff) { this.itrEnabled = itrEnabled; this.codeCoverageEnabled = codeCoverageEnabled; @@ -74,9 +80,11 @@ public ExecutionSettings( this.itrCorrelationId = itrCorrelationId; this.skippableTests = skippableTests; this.skippableTestsCoverage = skippableTestsCoverage; - this.quarantinedTests = quarantinedTests; this.flakyTests = flakyTests; this.knownTests = knownTests; + this.quarantinedTests = quarantinedTests; + this.disabledTests = disabledTests; + this.attemptToFixTests = attemptToFixTests; this.pullRequestDiff = pullRequestDiff; } @@ -130,11 +138,6 @@ public Map getSkippableTests() { return skippableTests; } - @Nonnull - public Collection getQuarantinedTests() { - return quarantinedTests; - } - /** * @return the list of known tests for the given module (can be empty), or {@code null} if known * tests could not be obtained @@ -153,6 +156,21 @@ public Collection getFlakyTests() { return flakyTests; } + @Nonnull + public Collection getQuarantinedTests() { + return quarantinedTests; + } + + @Nonnull + public Collection getDisabledTests() { + return disabledTests; + } + + @Nonnull + public Collection getAttemptToFixTests() { + return attemptToFixTests; + } + @Nonnull public Diff getPullRequestDiff() { return pullRequestDiff; @@ -175,9 +193,11 @@ public boolean equals(Object o) { && Objects.equals(itrCorrelationId, that.itrCorrelationId) && Objects.equals(skippableTests, that.skippableTests) && Objects.equals(skippableTestsCoverage, that.skippableTestsCoverage) - && Objects.equals(quarantinedTests, that.quarantinedTests) && Objects.equals(flakyTests, that.flakyTests) && Objects.equals(knownTests, that.knownTests) + && Objects.equals(quarantinedTests, that.quarantinedTests) + && Objects.equals(disabledTests, that.disabledTests) + && Objects.equals(attemptToFixTests, that.attemptToFixTests) && Objects.equals(pullRequestDiff, that.pullRequestDiff); } @@ -192,9 +212,11 @@ public int hashCode() { itrCorrelationId, skippableTests, skippableTestsCoverage, - quarantinedTests, flakyTests, knownTests, + quarantinedTests, + disabledTests, + attemptToFixTests, pullRequestDiff); } @@ -231,9 +253,11 @@ public static ByteBuffer serialize(ExecutionSettings settings) { TestMetadataSerializer::serialize); s.write(settings.skippableTestsCoverage, Serializer::write, Serializer::write); - s.write(settings.quarantinedTests, TestIdentifierSerializer::serialize); s.write(settings.flakyTests, TestIdentifierSerializer::serialize); s.write(settings.knownTests, TestIdentifierSerializer::serialize); + s.write(settings.quarantinedTests, TestIdentifierSerializer::serialize); + s.write(settings.disabledTests, TestIdentifierSerializer::serialize); + s.write(settings.attemptToFixTests, TestIdentifierSerializer::serialize); Diff.SERIALIZER.serialize(settings.pullRequestDiff, s); @@ -262,12 +286,16 @@ public static ExecutionSettings deserialize(ByteBuffer buffer) { Map skippableTestsCoverage = Serializer.readMap(buffer, Serializer::readString, Serializer::readBitSet); - Collection quarantinedTests = - Serializer.readSet(buffer, TestIdentifierSerializer::deserialize); Collection flakyTests = Serializer.readSet(buffer, TestIdentifierSerializer::deserialize); Collection knownTests = Serializer.readSet(buffer, TestIdentifierSerializer::deserialize); + Collection quarantinedTests = + Serializer.readSet(buffer, TestIdentifierSerializer::deserialize); + Collection disabledTests = + Serializer.readSet(buffer, TestIdentifierSerializer::deserialize); + Collection attemptToFixTests = + Serializer.readSet(buffer, TestIdentifierSerializer::deserialize); Diff diff = Diff.SERIALIZER.deserialize(buffer); @@ -282,9 +310,11 @@ public static ExecutionSettings deserialize(ByteBuffer buffer) { itrCorrelationId, skippableTests, skippableTestsCoverage, - quarantinedTests, flakyTests, knownTests, + quarantinedTests, + disabledTests, + attemptToFixTests, diff); } } diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ExecutionSettingsFactoryImpl.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ExecutionSettingsFactoryImpl.java index 916661efa13..544d6df9538 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ExecutionSettingsFactoryImpl.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ExecutionSettingsFactoryImpl.java @@ -209,12 +209,33 @@ private Map doCreate( executor.submit(() -> getFlakyTestsByModule(tracerEnvironment, flakyTestRetriesEnabled)); Future>> knownTestsFuture = executor.submit(() -> getKnownTestsByModule(tracerEnvironment, knownTestsRequest)); + Future>>> testManagementTestsFuture = + executor.submit( + () -> + getTestManagementTestsByModule( + tracerEnvironment, testManagementSettings.isEnabled())); Future pullRequestDiffFuture = executor.submit(() -> getPullRequestDiff(tracerEnvironment, impactedTestsEnabled)); SkippableTests skippableTests = skippableTestsFuture.get(); Map> flakyTestsByModule = flakyTestsFuture.get(); Map> knownTestsByModule = knownTestsFuture.get(); + + Map>> testManagementTestsByModule = + testManagementTestsFuture.get(); + Map> quarantinedTestsByModule = + testManagementTestsByModule != null + ? testManagementTestsByModule.get("quarantined") + : Collections.emptyMap(); + Map> disabledTestsByModule = + testManagementTestsByModule != null + ? testManagementTestsByModule.get("disabled") + : Collections.emptyMap(); + Map> attemptToFixTestsByModule = + testManagementTestsByModule != null + ? testManagementTestsByModule.get("attempt_to_fix") + : Collections.emptyMap(); + Diff pullRequestDiff = pullRequestDiffFuture.get(); Map settingsByModule = new HashMap<>(); @@ -238,11 +259,13 @@ private Map doCreate( .getIdentifiersByModule() .getOrDefault(moduleName, Collections.emptyMap()), skippableTests.getCoveredLinesByRelativeSourcePath(), - Collections.emptyList(), // FIXME implement retrieving quarantined tests flakyTestsByModule != null ? flakyTestsByModule.getOrDefault(moduleName, Collections.emptyList()) : null, knownTestsByModule != null ? knownTestsByModule.get(moduleName) : null, + quarantinedTestsByModule.getOrDefault(moduleName, Collections.emptyList()), + disabledTestsByModule.getOrDefault(moduleName, Collections.emptyList()), + attemptToFixTestsByModule.getOrDefault(moduleName, Collections.emptyList()), pullRequestDiff)); } return settingsByModule; @@ -363,6 +386,21 @@ private Map> getKnownTestsByModule( } } + @Nullable + private Map>> getTestManagementTestsByModule( + TracerEnvironment tracerEnvironment, boolean testManagementTestsRequest) { + if (!testManagementTestsRequest) { + return null; + } + try { + return configurationApi.getTestManagementTestsByModule(tracerEnvironment); + + } catch (Exception e) { + LOGGER.error("Could not obtain list of test management tests", e); + return null; + } + } + @Nonnull private Diff getPullRequestDiff( TracerEnvironment tracerEnvironment, boolean impactedTestsDetectionEnabled) { diff --git a/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/config/ConfigurationApiImplTest.groovy b/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/config/ConfigurationApiImplTest.groovy index a7b2e50640c..74e03affd03 100644 --- a/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/config/ConfigurationApiImplTest.groovy +++ b/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/config/ConfigurationApiImplTest.groovy @@ -182,6 +182,46 @@ class ConfigurationApiImplTest extends Specification { intakeServer.close() } + def "test test management tests request"() { + given: + def tracerEnvironment = givenTracerEnvironment() + + def intakeServer = givenBackendEndpoint( + "/api/v2/test/libraries/test-management/tests", + "/datadog/trace/civisibility/config/test-management-tests-request.ftl", + [uid: REQUEST_UID, tracerEnvironment: tracerEnvironment], + "/datadog/trace/civisibility/config/test-management-tests-response.ftl", + [:] + ) + + def configurationApi = givenConfigurationApi(intakeServer) + + when: + def testManagementTests = configurationApi.getTestManagementTestsByModule(tracerEnvironment) + def quarantinedTests = testManagementTests.get("quarantined") + def disabledTests = testManagementTests.get("disabled") + def attemptToFixTests = testManagementTests.get("attempt_to_fix") + + then: + quarantinedTests == [ + "module-a": new HashSet<>([ + new TestIdentifier("suite-a", "test-a", null), + new TestIdentifier("suite-b", "test-c", null) + ]) + ] + disabledTests == [ + "module-a": new HashSet<>([new TestIdentifier("suite-a", "test-b", null)]), + "module-b": new HashSet<>([new TestIdentifier("suite-c", "test-d", null)]) + ] + attemptToFixTests == [ + "module-a": new HashSet<>([new TestIdentifier("suite-b", "test-c", null)]), + "module-b": new HashSet<>([new TestIdentifier("suite-c", "test-d", null)]) + ] + + cleanup: + intakeServer.close() + } + def "test changed files request"() { given: def tracerEnvironment = givenTracerEnvironment() diff --git a/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/config/ExecutionSettingsTest.groovy b/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/config/ExecutionSettingsTest.groovy index ccd3cc78ff8..850c0575977 100644 --- a/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/config/ExecutionSettingsTest.groovy +++ b/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/config/ExecutionSettingsTest.groovy @@ -30,9 +30,11 @@ class ExecutionSettingsTest extends Specification { null, [:], [:], - new HashSet<>([]), null, new HashSet<>([]), + new HashSet<>([]), + new HashSet<>([]), + new HashSet<>([]), LineDiff.EMPTY), new ExecutionSettings( @@ -46,9 +48,11 @@ class ExecutionSettingsTest extends Specification { "", [(new TestIdentifier("bc", "def", "g")): new TestMetadata(true), (new TestIdentifier("de", "f", null)): new TestMetadata(false)], [:], - new HashSet<>([new TestIdentifier("suite", "quarantined", null)]), new HashSet<>([new TestIdentifier("name", null, null)]), new HashSet<>([new TestIdentifier("b", "c", "g")]), + new HashSet<>([new TestIdentifier("suite", "quarantined", null)]), + new HashSet<>([new TestIdentifier("suite", "disabled", null)]), + new HashSet<>([new TestIdentifier("suite", "attemptToFix", null)]), new LineDiff(["path": lines()]) ), @@ -67,9 +71,11 @@ class ExecutionSettingsTest extends Specification { }), "cov2": BitSet.valueOf(new byte[]{ 4, 5, 6 })], - new HashSet<>([new TestIdentifier("suite", "quarantined", null), new TestIdentifier("another", "another-quarantined", null)]), new HashSet<>([new TestIdentifier("name", null, "g"), new TestIdentifier("b", "c", null)]), new HashSet<>([new TestIdentifier("b", "c", null), new TestIdentifier("bb", "cc", null)]), + new HashSet<>([new TestIdentifier("suite", "quarantined", null), new TestIdentifier("another", "another-quarantined", null)]), + new HashSet<>([new TestIdentifier("suite", "disabled", null), new TestIdentifier("another", "another-disabled", null)]), + new HashSet<>([new TestIdentifier("suite", "attemptToFix", null), new TestIdentifier("another", "another-attemptToFix", null)]), new LineDiff(["path": lines(1, 2, 3)]), ), @@ -88,9 +94,11 @@ class ExecutionSettingsTest extends Specification { }), "cov2": BitSet.valueOf(new byte[]{ 4, 5, 6 })], - new HashSet<>([new TestIdentifier("suite", "quarantined", null), new TestIdentifier("another", "another-quarantined", null)]), new HashSet<>([]), new HashSet<>([new TestIdentifier("b", "c", null), new TestIdentifier("bb", "cc", "g")]), + new HashSet<>([new TestIdentifier("suite", "quarantined", null), new TestIdentifier("another", "another-quarantined", null)]), + new HashSet<>([new TestIdentifier("suite", "disabled", null), new TestIdentifier("another", "another-disabled", null)]), + new HashSet<>([new TestIdentifier("suite", "attemptToFix", null), new TestIdentifier("another", "another-attemptToFix", null)]), new LineDiff(["path": lines(1, 2, 3), "path-b": lines(1, 2, 128, 257, 999)]), ), ] diff --git a/dd-java-agent/agent-ci-visibility/src/test/resources/datadog/trace/civisibility/config/test-management-tests-request.ftl b/dd-java-agent/agent-ci-visibility/src/test/resources/datadog/trace/civisibility/config/test-management-tests-request.ftl new file mode 100644 index 00000000000..4b9593e0a43 --- /dev/null +++ b/dd-java-agent/agent-ci-visibility/src/test/resources/datadog/trace/civisibility/config/test-management-tests-request.ftl @@ -0,0 +1,29 @@ +{ + "data": { + "type" : "ci_app_libraries_tests_request", + "id" : "${uid}", + "attributes": { + "service" : "${tracerEnvironment.service}", + "env" : "${tracerEnvironment.env}", + "repository_url": "${tracerEnvironment.repositoryUrl}", + "branch" : "${tracerEnvironment.branch}", + "sha" : "${tracerEnvironment.sha}", + "test_level" : "${tracerEnvironment.testLevel}", + "configurations": { + "os.platform" : "${tracerEnvironment.configurations.osPlatform}", + "os.architecture" : "${tracerEnvironment.configurations.osArchitecture}", + "os.arch" : "${tracerEnvironment.configurations.osArchitecture}", + "os.version" : "${tracerEnvironment.configurations.osVersion}", + "runtime.name" : "${tracerEnvironment.configurations.runtimeName}", + "runtime.version" : "${tracerEnvironment.configurations.runtimeVersion}", + "runtime.vendor" : "${tracerEnvironment.configurations.runtimeVendor}", + "runtime.architecture": "${tracerEnvironment.configurations.runtimeArchitecture}", + "custom" : { + <#list tracerEnvironment.configurations.custom as customTag, customValue> + "${customTag}": "${customValue}"<#if customTag?has_next>, + + } + } + } + } +} diff --git a/dd-java-agent/agent-ci-visibility/src/test/resources/datadog/trace/civisibility/config/test-management-tests-response.ftl b/dd-java-agent/agent-ci-visibility/src/test/resources/datadog/trace/civisibility/config/test-management-tests-response.ftl new file mode 100644 index 00000000000..00d4d986d72 --- /dev/null +++ b/dd-java-agent/agent-ci-visibility/src/test/resources/datadog/trace/civisibility/config/test-management-tests-response.ftl @@ -0,0 +1,58 @@ +{ + "data": { + "id": "9p1jTQLXB8g", + "type": "ci_app_libraries_tests", + "attributes": { + "modules": { + "module-a": { + "suites": { + "suite-a": { + "tests": { + "test-a": { + "properties": { + "quarantined": true, + "disabled": false, + "attempt_to_fix": false + } + }, + "test-b": { + "properties": { + "quarantined": false, + "disabled": true, + "attempt_to_fix": false + } + } + } + }, + "suite-b": { + "tests": { + "test-c": { + "properties": { + "quarantined": true, + "disabled": false, + "attempt_to_fix": true + } + } + } + } + } + }, + "module-b": { + "suites": { + "suite-c": { + "tests": { + "test-d": { + "properties": { + "quarantined": false, + "disabled": true, + "attempt_to_fix": true + } + } + } + } + } + } + } + } + } +} diff --git a/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilityInstrumentationTest.groovy b/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilityInstrumentationTest.groovy index 18247029797..73a8159c32d 100644 --- a/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilityInstrumentationTest.groovy +++ b/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilityInstrumentationTest.groovy @@ -71,9 +71,11 @@ abstract class CiVisibilityInstrumentationTest extends AgentTestRunner { private static Path agentKeyFile private static final List skippableTests = new ArrayList<>() - private static final List quarantinedTests = new ArrayList<>() private static final List flakyTests = new ArrayList<>() private static final List knownTests = new ArrayList<>() + private static final List quarantinedTests = new ArrayList<>() + private static final List disabledTests = new ArrayList<>() + private static final List attemptToFixTests = new ArrayList<>() private static volatile Diff diff = LineDiff.EMPTY private static volatile boolean itrEnabled = false @@ -137,9 +139,11 @@ abstract class CiVisibilityInstrumentationTest extends AgentTestRunner { itrEnabled ? "itrCorrelationId" : null, skippableTestsWithMetadata, [:], - quarantinedTests, flakyTests, earlyFlakinessDetectionEnabled || CIConstants.FAIL_FAST_TEST_ORDER.equalsIgnoreCase(Config.get().ciVisibilityTestOrder) ? knownTests : null, + quarantinedTests, + disabledTests, + attemptToFixTests, diff) } } @@ -259,9 +263,11 @@ abstract class CiVisibilityInstrumentationTest extends AgentTestRunner { @Override void setup() { skippableTests.clear() - quarantinedTests.clear() flakyTests.clear() knownTests.clear() + quarantinedTests.clear() + disabledTests.clear() + attemptToFixTests.clear() diff = LineDiff.EMPTY itrEnabled = false flakyRetryEnabled = false @@ -289,6 +295,14 @@ abstract class CiVisibilityInstrumentationTest extends AgentTestRunner { quarantinedTests.addAll(tests) } + def givenDisabledTests(List tests) { + disabledTests.addAll(tests) + } + + def givenAttemptToFixTests(List tests) { + attemptToFixTests.addAll(tests) + } + def givenDiff(Diff diff) { this.diff = diff } diff --git a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/CiVisibilityCountMetric.java b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/CiVisibilityCountMetric.java index f6b253d3177..5109c0d59d2 100644 --- a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/CiVisibilityCountMetric.java +++ b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/CiVisibilityCountMetric.java @@ -151,7 +151,12 @@ public enum CiVisibilityCountMetric { IMPACTED_TESTS_DETECTION_REQUEST("impacted_tests_detection.request", RequestCompressed.class), /** The number of tests requests sent to the changed files endpoint that errored */ IMPACTED_TESTS_DETECTION_REQUEST_ERRORS( - "impacted_tests_detection.request_errors", ErrorType.class, StatusCode.class); + "impacted_tests_detection.request_errors", ErrorType.class, StatusCode.class), + /** The number of requests sent to the test management tests endpoint */ + TEST_MANAGEMENT_TESTS_DETECTION_REQUEST("test_management.request", RequestCompressed.class), + /** The number of tests requests sent to the test management tests endpoint that errored */ + TEST_MANAGEMENT_TESTS_DETECTION_REQUEST_ERRORS( + "test_management.request_errors", ErrorType.class, StatusCode.class); // need a "holder" class, as accessing static fields from enum constructors is illegal static class IndexHolder { diff --git a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/CiVisibilityDistributionMetric.java b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/CiVisibilityDistributionMetric.java index a7e7de917dc..a50f2a2d61c 100644 --- a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/CiVisibilityDistributionMetric.java +++ b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/CiVisibilityDistributionMetric.java @@ -57,7 +57,13 @@ public enum CiVisibilityDistributionMetric { IMPACTED_TESTS_DETECTION_RESPONSE_BYTES( "impacted_tests_detection.response_bytes", ResponseCompressed.class), /** The number of files received by the changed files endpoint */ - IMPACTED_TESTS_DETECTION_RESPONSE_FILES("impacted_tests_detection.response_files"); + IMPACTED_TESTS_DETECTION_RESPONSE_FILES("impacted_tests_detection.response_files"), + /** The time it takes to get the response of the test management tests endpoint request in ms */ + TEST_MANAGEMENT_TESTS_REQUEST_MS("test_management.request_ms"), + /** The number of bytes received by the test management tests endpoint */ + TEST_MANAGEMENT_TESTS_RESPONSE_BYTES("test_management.response_bytes", ResponseCompressed.class), + /** The number of tests received by the test management tests endpoint */ + TEST_MANAGEMENT_TESTS_RESPONSE_TESTS("test_management.response_tests"); private static final String NAMESPACE = "civisibility";