diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/CiVisibilitySystem.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/CiVisibilitySystem.java index ac467e6500a..5bc7e85c587 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/CiVisibilitySystem.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/CiVisibilitySystem.java @@ -7,6 +7,7 @@ import datadog.trace.api.civisibility.DDTest; import datadog.trace.api.civisibility.DDTestSuite; import datadog.trace.api.civisibility.InstrumentationBridge; +import datadog.trace.api.civisibility.config.LibraryCapability; import datadog.trace.api.civisibility.coverage.CoveragePerTestBridge; import datadog.trace.api.civisibility.events.BuildEventsHandler; import datadog.trace.api.civisibility.events.TestEventsHandler; @@ -39,6 +40,7 @@ import java.lang.instrument.Instrumentation; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Collection; import java.util.function.Predicate; import javax.annotation.Nullable; import org.slf4j.Logger; @@ -167,9 +169,10 @@ private TestEventsHandlerFactory( public TestEventsHandler create( String component, @Nullable ContextStore suiteStore, - @Nullable ContextStore testStore) { + @Nullable ContextStore testStore, + Collection capabilities) { TestFrameworkSession testSession = - sessionFactory.startSession(repoServices.moduleName, component, null); + sessionFactory.startSession(repoServices.moduleName, component, null, capabilities); TestFrameworkModule testModule = testSession.testModuleStart(repoServices.moduleName, null); return new TestEventsHandlerImpl<>( services.metricCollector, @@ -231,7 +234,10 @@ private static TestFrameworkSession.Factory childTestFrameworkSessionFactory( CiVisibilityRepoServices repoServices, CiVisibilityCoverageServices.Child coverageServices, ExecutionSettings executionSettings) { - return (String projectName, String component, Long startTime) -> { + return (String projectName, + String component, + Long startTime, + Collection capabilities) -> { String sessionName = services.config.getCiVisibilitySessionName(); String testCommand = services.config.getCiVisibilityTestCommand(); TestDecorator testDecorator = @@ -255,7 +261,8 @@ private static TestFrameworkSession.Factory childTestFrameworkSessionFactory( coverageServices.coverageStoreFactory, coverageServices.coverageReporter, services.signalClientFactory, - executionStrategy); + executionStrategy, + capabilities); }; } @@ -264,7 +271,10 @@ private static TestFrameworkSession.Factory headlessTestFrameworkSessionFactory( CiVisibilityRepoServices repoServices, CiVisibilityCoverageServices.Child coverageServices, ExecutionSettings executionSettings) { - return (String projectName, String component, Long startTime) -> { + return (String projectName, + String component, + Long startTime, + Collection capabilities) -> { repoServices.gitDataUploader.startOrObserveGitDataUpload(); String sessionName = services.config.getCiVisibilitySessionName(); @@ -288,7 +298,8 @@ private static TestFrameworkSession.Factory headlessTestFrameworkSessionFactory( repoServices.codeowners, services.linesResolver, coverageServices.coverageStoreFactory, - executionStrategy); + executionStrategy, + capabilities); }; } 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 4d93dcf5d38..cdca5314c6e 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 @@ -1,5 +1,8 @@ package datadog.trace.civisibility.config; +import datadog.trace.api.Config; +import datadog.trace.api.civisibility.CIConstants; +import datadog.trace.api.civisibility.config.LibraryCapability; import datadog.trace.api.civisibility.config.TestFQN; import datadog.trace.api.civisibility.config.TestIdentifier; import datadog.trace.api.civisibility.config.TestMetadata; @@ -229,6 +232,44 @@ public Diff getPullRequestDiff() { return pullRequestDiff; } + @Nonnull + public Map getCapabilitiesStatus( + Collection capabilities) { + Map status = new EnumMap<>(LibraryCapability.class); + + for (LibraryCapability c : capabilities) { + switch (c) { + case TIA: + status.put(c, isTestSkippingEnabled()); + break; + case EFD: + EarlyFlakeDetectionSettings efdSettings = getEarlyFlakeDetectionSettings(); + status.put(c, efdSettings.isEnabled()); + break; + case ATR: + status.put(c, isFlakyTestRetriesEnabled()); + break; + case IMPACTED: + status.put(c, isImpactedTestsDetectionEnabled()); + break; + case FAIL_FAST: + String testOrder = Config.get().getCiVisibilityTestOrder(); + status.put(c, CIConstants.FAIL_FAST_TEST_ORDER.equalsIgnoreCase(testOrder)); + break; + case QUARANTINE: + case DISABLED: + case ATTEMPT_TO_FIX: + TestManagementSettings testManagementSettings = getTestManagementSettings(); + status.put(c, testManagementSettings.isEnabled()); + break; + default: + break; + } + } + + return status; + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/TestFrameworkSession.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/TestFrameworkSession.java index 0e7ec2d1737..c7391f945b6 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/TestFrameworkSession.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/TestFrameworkSession.java @@ -1,5 +1,7 @@ package datadog.trace.civisibility.domain; +import datadog.trace.api.civisibility.config.LibraryCapability; +import java.util.Collection; import javax.annotation.Nullable; /** Test session abstraction that is used by test framework instrumentations (e.g. JUnit, TestNG) */ @@ -9,6 +11,10 @@ public interface TestFrameworkSession { TestFrameworkModule testModuleStart(String moduleName, @Nullable Long startTime); interface Factory { - TestFrameworkSession startSession(String projectName, String component, Long startTime); + TestFrameworkSession startSession( + String projectName, + String component, + Long startTime, + Collection capabilities); } } diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/TestImpl.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/TestImpl.java index 679b3c46894..0cd56757009 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/TestImpl.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/TestImpl.java @@ -9,6 +9,7 @@ import datadog.trace.api.civisibility.CIConstants; import datadog.trace.api.civisibility.DDTest; import datadog.trace.api.civisibility.InstrumentationTestBridge; +import datadog.trace.api.civisibility.config.LibraryCapability; import datadog.trace.api.civisibility.config.TestIdentifier; import datadog.trace.api.civisibility.coverage.CoveragePerTestBridge; import datadog.trace.api.civisibility.coverage.CoverageStore; @@ -45,6 +46,7 @@ import java.lang.reflect.Method; import java.util.Collection; import java.util.Collections; +import java.util.Map; import java.util.function.Consumer; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -86,6 +88,7 @@ public TestImpl( Codeowners codeowners, CoverageStore.Factory coverageStoreFactory, ExecutionResults executionResults, + @Nonnull Map libraryCapabilities, Consumer onSpanFinish) { this.instrumentation = instrumentation; this.metricCollector = metricCollector; @@ -144,6 +147,10 @@ public TestImpl( span.setTag(Tags.ITR_CORRELATION_ID, itrCorrelationId); } + for (Map.Entry entry : libraryCapabilities.entrySet()) { + span.setTag(entry.getKey().asTag(), entry.getValue()); + } + testDecorator.afterStart(span); metricCollector.add(CiVisibilityCountMetric.EVENT_CREATED, 1, instrumentation, EventType.TEST); diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/TestSuiteImpl.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/TestSuiteImpl.java index 024f77f0b4d..bf154912f11 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/TestSuiteImpl.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/TestSuiteImpl.java @@ -6,6 +6,7 @@ import datadog.trace.api.Config; import datadog.trace.api.civisibility.DDTestSuite; +import datadog.trace.api.civisibility.config.LibraryCapability; import datadog.trace.api.civisibility.coverage.CoverageStore; import datadog.trace.api.civisibility.telemetry.CiVisibilityCountMetric; import datadog.trace.api.civisibility.telemetry.CiVisibilityMetricCollector; @@ -26,7 +27,9 @@ import datadog.trace.civisibility.utils.SpanUtils; import java.lang.reflect.Method; import java.util.Collection; +import java.util.Map; import java.util.function.Consumer; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,6 +55,7 @@ public class TestSuiteImpl implements DDTestSuite { private final CoverageStore.Factory coverageStoreFactory; private final ExecutionResults executionResults; private final boolean parallelized; + private final Map libraryCapabilities; private final Consumer onSpanFinish; public TestSuiteImpl( @@ -72,6 +76,7 @@ public TestSuiteImpl( LinesResolver linesResolver, CoverageStore.Factory coverageStoreFactory, ExecutionResults executionResults, + @Nonnull Map libraryCapabilities, Consumer onSpanFinish) { this.moduleSpanContext = moduleSpanContext; this.moduleName = moduleName; @@ -88,6 +93,7 @@ public TestSuiteImpl( this.linesResolver = linesResolver; this.coverageStoreFactory = coverageStoreFactory; this.executionResults = executionResults; + this.libraryCapabilities = libraryCapabilities; this.onSpanFinish = onSpanFinish; AgentTracer.SpanBuilder spanBuilder = @@ -259,6 +265,7 @@ public TestImpl testStart( codeowners, coverageStoreFactory, executionResults, + libraryCapabilities, SpanUtils.propagateCiVisibilityTagsTo(span)); } } diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/buildsystem/ProxyTestModule.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/buildsystem/ProxyTestModule.java index d51dee9a34f..0b77d2b0824 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/buildsystem/ProxyTestModule.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/buildsystem/ProxyTestModule.java @@ -2,6 +2,7 @@ import datadog.trace.api.Config; import datadog.trace.api.DDTraceId; +import datadog.trace.api.civisibility.config.LibraryCapability; import datadog.trace.api.civisibility.config.TestIdentifier; import datadog.trace.api.civisibility.config.TestSourceData; import datadog.trace.api.civisibility.coverage.CoverageStore; @@ -30,6 +31,7 @@ import datadog.trace.civisibility.test.ExecutionResults; import datadog.trace.civisibility.test.ExecutionStrategy; import java.util.Collection; +import java.util.Map; import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import javax.annotation.Nonnull; @@ -60,6 +62,7 @@ public class ProxyTestModule implements TestFrameworkModule { private final LinesResolver linesResolver; private final CoverageStore.Factory coverageStoreFactory; private final Collection testFrameworks = ConcurrentHashMap.newKeySet(); + private final Map libraryCapabilities; public ProxyTestModule( AgentSpanContext parentProcessModuleContext, @@ -73,7 +76,8 @@ public ProxyTestModule( LinesResolver linesResolver, CoverageStore.Factory coverageStoreFactory, ChildProcessCoverageReporter childProcessCoverageReporter, - SignalClient.Factory signalClientFactory) { + SignalClient.Factory signalClientFactory, + Map libraryCapabilities) { this.parentProcessModuleContext = parentProcessModuleContext; this.moduleName = moduleName; this.executionStrategy = executionStrategy; @@ -87,6 +91,7 @@ public ProxyTestModule( this.codeowners = codeowners; this.linesResolver = linesResolver; this.coverageStoreFactory = coverageStoreFactory; + this.libraryCapabilities = libraryCapabilities; } @Override @@ -211,6 +216,7 @@ public TestSuiteImpl testSuiteStart( linesResolver, coverageStoreFactory, executionResults, + libraryCapabilities, this::propagateTestFrameworkData); } diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/buildsystem/ProxyTestSession.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/buildsystem/ProxyTestSession.java index 25a7f86b119..a44dc030bbf 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/buildsystem/ProxyTestSession.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/buildsystem/ProxyTestSession.java @@ -1,6 +1,7 @@ package datadog.trace.civisibility.domain.buildsystem; import datadog.trace.api.Config; +import datadog.trace.api.civisibility.config.LibraryCapability; import datadog.trace.api.civisibility.coverage.CoverageStore; import datadog.trace.api.civisibility.telemetry.CiVisibilityMetricCollector; import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext; @@ -14,6 +15,9 @@ import datadog.trace.civisibility.source.LinesResolver; import datadog.trace.civisibility.source.SourcePathResolver; import datadog.trace.civisibility.test.ExecutionStrategy; +import java.util.Collection; +import java.util.Map; +import javax.annotation.Nonnull; import javax.annotation.Nullable; /** @@ -34,6 +38,7 @@ public class ProxyTestSession implements TestFrameworkSession { private final ChildProcessCoverageReporter childProcessCoverageReporter; private final SignalClient.Factory signalClientFactory; private final ExecutionStrategy executionStrategy; + private final Map libraryCapabilities; public ProxyTestSession( AgentSpanContext parentProcessModuleContext, @@ -46,7 +51,8 @@ public ProxyTestSession( CoverageStore.Factory coverageStoreFactory, ChildProcessCoverageReporter childProcessCoverageReporter, SignalClient.Factory signalClientFactory, - ExecutionStrategy executionStrategy) { + ExecutionStrategy executionStrategy, + @Nonnull Collection capabilities) { this.parentProcessModuleContext = parentProcessModuleContext; this.config = config; this.metricCollector = metricCollector; @@ -58,6 +64,8 @@ public ProxyTestSession( this.childProcessCoverageReporter = childProcessCoverageReporter; this.signalClientFactory = signalClientFactory; this.executionStrategy = executionStrategy; + this.libraryCapabilities = + executionStrategy.getExecutionSettings().getCapabilitiesStatus(capabilities); } @Override @@ -82,6 +90,7 @@ public TestFrameworkModule testModuleStart(String moduleName, @Nullable Long sta linesResolver, coverageStoreFactory, childProcessCoverageReporter, - signalClientFactory); + signalClientFactory, + libraryCapabilities); } } diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/headless/HeadlessTestModule.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/headless/HeadlessTestModule.java index 4e8b98403e5..96c182990fd 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/headless/HeadlessTestModule.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/headless/HeadlessTestModule.java @@ -3,6 +3,7 @@ import datadog.trace.api.Config; import datadog.trace.api.DDTags; import datadog.trace.api.civisibility.CIConstants; +import datadog.trace.api.civisibility.config.LibraryCapability; import datadog.trace.api.civisibility.config.TestIdentifier; import datadog.trace.api.civisibility.config.TestSourceData; import datadog.trace.api.civisibility.coverage.CoverageStore; @@ -28,6 +29,7 @@ import datadog.trace.civisibility.test.ExecutionStrategy; import datadog.trace.civisibility.utils.SpanUtils; import java.util.Collection; +import java.util.Map; import java.util.function.Consumer; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -44,6 +46,7 @@ public class HeadlessTestModule extends AbstractTestModule implements TestFramew private final CoverageStore.Factory coverageStoreFactory; private final ExecutionStrategy executionStrategy; private final ExecutionResults executionResults; + private final Map libraryCapabilities; public HeadlessTestModule( AgentSpanContext sessionSpanContext, @@ -57,6 +60,7 @@ public HeadlessTestModule( LinesResolver linesResolver, CoverageStore.Factory coverageStoreFactory, ExecutionStrategy executionStrategy, + Map libraryCapabilities, Consumer onSpanFinish) { super( sessionSpanContext, @@ -73,6 +77,7 @@ public HeadlessTestModule( this.coverageStoreFactory = coverageStoreFactory; this.executionStrategy = executionStrategy; this.executionResults = new ExecutionResults(); + this.libraryCapabilities = libraryCapabilities; } @Override @@ -183,6 +188,7 @@ public TestSuiteImpl testSuiteStart( linesResolver, coverageStoreFactory, executionResults, + libraryCapabilities, SpanUtils.propagateCiVisibilityTagsTo(span)); } } diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/headless/HeadlessTestSession.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/headless/HeadlessTestSession.java index 1bed53b8344..7d43d8db71c 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/headless/HeadlessTestSession.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/headless/HeadlessTestSession.java @@ -3,6 +3,7 @@ import datadog.trace.api.Config; import datadog.trace.api.DDTags; import datadog.trace.api.civisibility.CIConstants; +import datadog.trace.api.civisibility.config.LibraryCapability; import datadog.trace.api.civisibility.coverage.CoverageStore; import datadog.trace.api.civisibility.telemetry.CiVisibilityMetricCollector; import datadog.trace.api.civisibility.telemetry.TagValue; @@ -21,6 +22,8 @@ import datadog.trace.civisibility.utils.SpanUtils; import java.util.Collection; import java.util.Collections; +import java.util.Map; +import javax.annotation.Nonnull; import javax.annotation.Nullable; /** @@ -34,6 +37,7 @@ public class HeadlessTestSession extends AbstractTestSession implements TestFram private final ExecutionStrategy executionStrategy; private final CoverageStore.Factory coverageStoreFactory; + private final Map libraryCapabilities; public HeadlessTestSession( String projectName, @@ -46,7 +50,8 @@ public HeadlessTestSession( Codeowners codeowners, LinesResolver linesResolver, CoverageStore.Factory coverageStoreFactory, - ExecutionStrategy executionStrategy) { + ExecutionStrategy executionStrategy, + @Nonnull Collection capabilities) { super( projectName, startTime, @@ -60,6 +65,8 @@ public HeadlessTestSession( linesResolver); this.executionStrategy = executionStrategy; this.coverageStoreFactory = coverageStoreFactory; + this.libraryCapabilities = + executionStrategy.getExecutionSettings().getCapabilitiesStatus(capabilities); } @Override @@ -76,6 +83,7 @@ public HeadlessTestModule testModuleStart(String moduleName, @Nullable Long star linesResolver, coverageStoreFactory, executionStrategy, + libraryCapabilities, this::propagateModuleTags); } diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/manualapi/ManualApiTestModule.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/manualapi/ManualApiTestModule.java index 4d9d3f54e68..627edd654c4 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/manualapi/ManualApiTestModule.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/manualapi/ManualApiTestModule.java @@ -16,6 +16,7 @@ import datadog.trace.civisibility.source.SourcePathResolver; import datadog.trace.civisibility.test.ExecutionResults; import datadog.trace.civisibility.utils.SpanUtils; +import java.util.Collections; import java.util.function.Consumer; import javax.annotation.Nullable; @@ -79,6 +80,7 @@ public TestSuiteImpl testSuiteStart( linesResolver, coverageStoreFactory, executionResults, + Collections.emptyMap(), SpanUtils.propagateCiVisibilityTagsTo(span)); } } diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/events/NoOpTestEventsHandler.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/events/NoOpTestEventsHandler.java index 9052e1b5a50..cd7d292aab6 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/events/NoOpTestEventsHandler.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/events/NoOpTestEventsHandler.java @@ -2,6 +2,7 @@ import datadog.trace.api.civisibility.DDTest; import datadog.trace.api.civisibility.DDTestSuite; +import datadog.trace.api.civisibility.config.LibraryCapability; import datadog.trace.api.civisibility.config.TestIdentifier; import datadog.trace.api.civisibility.config.TestSourceData; import datadog.trace.api.civisibility.events.TestEventsHandler; @@ -131,7 +132,8 @@ public static final class Factory implements TestEventsHandler.Factory { public TestEventsHandler create( String component, @Nullable ContextStore suiteStore, - @Nullable ContextStore testStore) { + @Nullable ContextStore testStore, + Collection capabilities) { return new NoOpTestEventsHandler<>(); } } 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 2bcbf3f8177..495767cf336 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 @@ -1,14 +1,19 @@ package datadog.trace.civisibility.config +import datadog.trace.api.civisibility.CIConstants +import datadog.trace.api.civisibility.config.LibraryCapability 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.config.CiVisibilityConfig import datadog.trace.civisibility.diff.LineDiff -import spock.lang.Specification +import datadog.trace.test.util.DDSpecification + +import java.util.stream.Collectors import static datadog.trace.civisibility.TestUtils.lines -class ExecutionSettingsTest extends Specification { +class ExecutionSettingsTest extends DDSpecification { def "test serialization: #settings"() { when: @@ -104,4 +109,52 @@ class ExecutionSettingsTest extends Specification { ), ] } + + def "test capabilities status: #testcaseName"() { + when: + def executionSettings = givenExecutionSettings(settingsEnabled) + + def capabilitiesStatus = executionSettings.getCapabilitiesStatus(capabilities) + def expectedStatus = capabilities.stream().collect(Collectors.toMap(item -> item, item -> settingsEnabled)) + + then: + capabilitiesStatus == expectedStatus + + where: + testcaseName | settingsEnabled | capabilities + "capabilities-disabled" | false | LibraryCapability.values().toList() + "capabilities-enabled" | true | LibraryCapability.values().toList() + "capabilities-filtering" | true | [LibraryCapability.TIA, LibraryCapability.ATR, LibraryCapability.IMPACTED, LibraryCapability.QUARANTINE] + } + + private ExecutionSettings givenExecutionSettings(boolean settingsEnabled) { + if (settingsEnabled) { + injectSysConfig(CiVisibilityConfig.CIVISIBILITY_TEST_ORDER, CIConstants.FAIL_FAST_TEST_ORDER) + } + + def testManagementSettings = Stub(TestManagementSettings) + testManagementSettings.isEnabled() >> settingsEnabled + + def earlyFlakeDetectionSettings = Stub(EarlyFlakeDetectionSettings) + earlyFlakeDetectionSettings.isEnabled() >> settingsEnabled + + return new ExecutionSettings( + settingsEnabled, + settingsEnabled, + settingsEnabled, + settingsEnabled, + settingsEnabled, + earlyFlakeDetectionSettings, + testManagementSettings, + null, + [:], + [:], + [], + [], + [], + [], + [], + LineDiff.EMPTY + ) + } } diff --git a/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/domain/TestImplTest.groovy b/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/domain/TestImplTest.groovy index eed93706371..e1e659010f9 100644 --- a/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/domain/TestImplTest.groovy +++ b/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/domain/TestImplTest.groovy @@ -4,6 +4,7 @@ import datadog.trace.agent.test.asserts.ListWriterAssert import datadog.trace.api.Config import datadog.trace.api.DDSpanTypes import datadog.trace.api.DDTraceId +import datadog.trace.api.civisibility.config.LibraryCapability import datadog.trace.api.civisibility.config.TestIdentifier import datadog.trace.api.civisibility.coverage.CoverageProbes import datadog.trace.api.civisibility.coverage.CoverageStore @@ -20,7 +21,7 @@ import datadog.trace.civisibility.test.ExecutionResults import datadog.trace.civisibility.utils.SpanUtils class TestImplTest extends SpanWriterTest { - def "test span is generated"() { + def "test span is generated and tags populated"() { setup: def test = givenATest() @@ -33,6 +34,13 @@ class TestImplTest extends SpanWriterTest { span(0) { parent() spanType DDSpanTypes.TEST + tags(false) { + "${LibraryCapability.TIA.asTag()}" true + "${LibraryCapability.EFD.asTag()}" false + "${LibraryCapability.QUARANTINE.asTag()}" true + "${LibraryCapability.DISABLED.asTag()}" false + "${LibraryCapability.ATTEMPT_TO_FIX.asTag()}" true + } } } }) @@ -105,6 +113,13 @@ class TestImplTest extends SpanWriterTest { linesResolver.getMethodLines(_) >> LinesResolver.Lines.EMPTY def codeowners = NoCodeowners.INSTANCE + def libraryCapabilities = [ + (LibraryCapability.TIA) : true, + (LibraryCapability.EFD) : false, + (LibraryCapability.QUARANTINE) : true, + (LibraryCapability.DISABLED) : false, + (LibraryCapability.ATTEMPT_TO_FIX): true] + new TestImpl( moduleSpanContext, suiteId, @@ -126,6 +141,7 @@ class TestImplTest extends SpanWriterTest { codeowners, coverageStoreFactory, executionResults, + libraryCapabilities, SpanUtils.DO_NOT_PROPAGATE_CI_VISIBILITY_TAGS ) } diff --git a/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/domain/TestSuiteImplTest.groovy b/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/domain/TestSuiteImplTest.groovy index 2acfcc0dc79..f51f8df278f 100644 --- a/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/domain/TestSuiteImplTest.groovy +++ b/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/domain/TestSuiteImplTest.groovy @@ -85,6 +85,7 @@ class TestSuiteImplTest extends SpanWriterTest { linesResolver, coverageStoreFactory, executionResults, + [:], SpanUtils.DO_NOT_PROPAGATE_CI_VISIBILITY_TAGS ) } diff --git a/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/domain/buildsystem/ProxyTestModuleTest.groovy b/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/domain/buildsystem/ProxyTestModuleTest.groovy index 086699b155d..006fe2b9c66 100644 --- a/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/domain/buildsystem/ProxyTestModuleTest.groovy +++ b/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/domain/buildsystem/ProxyTestModuleTest.groovy @@ -51,7 +51,8 @@ class ProxyTestModuleTest extends DDSpecification { Stub(LinesResolver), Stub(CoverageStore.Factory), Stub(ChildProcessCoverageReporter), - GroovyMock(SignalClient.Factory) + GroovyMock(SignalClient.Factory), + [:] ) when: diff --git a/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/domain/headless/HeadlessTestModuleTest.groovy b/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/domain/headless/HeadlessTestModuleTest.groovy index cea3e91cad6..57924803cd3 100644 --- a/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/domain/headless/HeadlessTestModuleTest.groovy +++ b/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/domain/headless/HeadlessTestModuleTest.groovy @@ -66,6 +66,7 @@ class HeadlessTestModuleTest extends SpanWriterTest { Stub(LinesResolver), Stub(CoverageStore.Factory), executionStrategy, + [:], (span) -> { } ) } diff --git a/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/domain/headless/HeadlessTestSessionTest.groovy b/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/domain/headless/HeadlessTestSessionTest.groovy index 1cf2e858e31..2b0ddfeeadb 100644 --- a/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/domain/headless/HeadlessTestSessionTest.groovy +++ b/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/domain/headless/HeadlessTestSessionTest.groovy @@ -18,7 +18,7 @@ import datadog.trace.civisibility.test.ExecutionStrategy class HeadlessTestSessionTest extends SpanWriterTest { - def "test tags are populated correctly in span"() { + def "test tags are propagated correctly"() { setup: def session = givenAHeadlessTestSession() def module = session.testModuleStart("module-name", null) @@ -36,7 +36,7 @@ class HeadlessTestSessionTest extends SpanWriterTest { "$Tags.TEST_TEST_MANAGEMENT_ENABLED" true } } - span (1) { + span(1) { spanType DDSpanTypes.TEST_MODULE_END } } @@ -60,7 +60,8 @@ class HeadlessTestSessionTest extends SpanWriterTest { Stub(Codeowners), Stub(LinesResolver), Stub(CoverageStore.Factory), - executionStrategy + executionStrategy, + [] ) } } 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 c4055519759..65d75d1507c 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 @@ -4,11 +4,14 @@ import com.fasterxml.jackson.databind.ObjectMapper import datadog.communication.serialization.GrowableBuffer import datadog.communication.serialization.msgpack.MsgPackWriter import datadog.trace.agent.test.AgentTestRunner +import datadog.trace.agent.test.asserts.ListWriterAssert import datadog.trace.api.Config +import datadog.trace.api.DDSpanTypes import datadog.trace.api.civisibility.CIConstants import datadog.trace.api.civisibility.DDTest import datadog.trace.api.civisibility.DDTestSuite import datadog.trace.api.civisibility.InstrumentationBridge +import datadog.trace.api.civisibility.config.LibraryCapability import datadog.trace.api.civisibility.config.TestFQN import datadog.trace.api.civisibility.config.TestIdentifier import datadog.trace.api.civisibility.config.TestMetadata @@ -56,6 +59,7 @@ import java.nio.file.Path import java.nio.file.Paths import java.util.concurrent.TimeUnit import java.util.function.Predicate +import java.util.stream.Collectors abstract class CiVisibilityInstrumentationTest extends AgentTestRunner { @@ -136,7 +140,7 @@ abstract class CiVisibilityInstrumentationTest extends AgentTestRunner { def executionSettingsFactory = new MockExecutionSettingsFactory(settings) def coverageStoreFactory = new FileCoverageStore.Factory(metricCollector, sourcePathResolver) - TestFrameworkSession.Factory testFrameworkSessionFactory = (String projectName, String component, Long startTime) -> { + TestFrameworkSession.Factory testFrameworkSessionFactory = (String projectName, String component, Long startTime, Collection capabilities) -> { def config = Config.get() def ciTags = [(DUMMY_CI_TAG): DUMMY_CI_TAG_VALUE] TestDecorator testDecorator = new TestDecoratorImpl(component, "session-name", "test-command", ciTags) @@ -155,7 +159,8 @@ abstract class CiVisibilityInstrumentationTest extends AgentTestRunner { config, executionSettingsFactory.create(JvmInfo.CURRENT_JVM, ""), sourcePathResolver, - linesResolver) + linesResolver), + capabilities ) } @@ -254,8 +259,8 @@ abstract class CiVisibilityInstrumentationTest extends AgentTestRunner { } @Override - TestEventsHandler create(String component, ContextStore suiteStore, ContextStore testStore) { - TestFrameworkSession testSession = testFrameworkSessionFactory.startSession(moduleName, component, null) + TestEventsHandler create(String component, ContextStore suiteStore, ContextStore testStore, Collection capabilities) { + TestFrameworkSession testSession = testFrameworkSessionFactory.startSession(moduleName, component, null, capabilities) TestFrameworkModule testModule = testSession.testModuleStart(moduleName, null) new TestEventsHandlerImpl(metricCollector, testSession, testModule, suiteStore != null ? suiteStore : new ConcurrentHashMapContextStore<>(), @@ -341,7 +346,7 @@ abstract class CiVisibilityInstrumentationTest extends AgentTestRunner { settings.impactedTestsDetectionEnabled = impactedTestsDetectionEnabled } - def assertSpansData(String testcaseName, Map replacements = [:]) { + def assertSpansData(String testcaseName, Map replacements = [:], List ignoredTags = []) { Predicate sessionSpan = span -> span.spanType == "test_session_end" spanFilter.waitForSpan(sessionSpan, TimeUnit.SECONDS.toMillis(20)) @@ -354,14 +359,16 @@ abstract class CiVisibilityInstrumentationTest extends AgentTestRunner { "content.meta.['test.toolchain']" : "${instrumentedLibraryName()}:${instrumentedLibraryVersion()}" ] + replacements + def additionalIgnoredTags = CiVisibilityTestUtils.IGNORED_TAGS + ignoredTags + if (System.getenv().get("GENERATE_TEST_FIXTURES") != null) { - return generateTestFixtures(testcaseName, events, coverages, additionalReplacements) + return generateTestFixtures(testcaseName, events, coverages, additionalReplacements, additionalIgnoredTags) } else { - return CiVisibilityTestUtils.assertData(testcaseName, events, coverages, additionalReplacements) + return CiVisibilityTestUtils.assertData(testcaseName, events, coverages, additionalReplacements, additionalIgnoredTags) } } - def generateTestFixtures(testcaseName, events, coverages, additionalReplacements) { + def generateTestFixtures(testcaseName, events, coverages, additionalReplacements, additionalIgnoredTags) { def clazz = this.getClass() def resourceName = "/" + clazz.name.replace('.', '/') + ".class" def classfilePath = clazz.getResource(resourceName).toURI().schemeSpecificPart @@ -373,7 +380,7 @@ abstract class CiVisibilityInstrumentationTest extends AgentTestRunner { submoduleName = "test" } def baseTemplatesPath = modulePath + "/src/" + submoduleName + "/resources/" + testcaseName - CiVisibilityTestUtils.generateTemplates(baseTemplatesPath, events, coverages, additionalReplacements) + CiVisibilityTestUtils.generateTemplates(baseTemplatesPath, events, coverages, additionalReplacements, additionalIgnoredTags) return [:] } @@ -388,6 +395,22 @@ abstract class CiVisibilityInstrumentationTest extends AgentTestRunner { return true } + def assertCapabilities(Collection capabilities, int expectedTraceCount) { + ListWriterAssert.assertTraces(TEST_WRITER, expectedTraceCount, true, new CiVisibilityTestUtils.SortTracesByType(), { + trace(1) { + span(0) { + spanType DDSpanTypes.TEST + tags(false) { + arePresent(capabilities.stream().map(LibraryCapability::asTag).collect(Collectors.toList())) + areNotPresent(LibraryCapability.values().stream().filter(capability -> !capabilities.contains(capability)).map(LibraryCapability::asTag).collect(Collectors.toList())) + } + } + } + }) + + return true + } + def getTestIdentifiers(List events) { events.sort(Comparator.comparing { it['content']['start'] as Long }) def testIdentifiers = [] diff --git a/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilitySmokeTest.groovy b/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilitySmokeTest.groovy index c4120d8649b..86eceed7f64 100644 --- a/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilitySmokeTest.groovy +++ b/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilitySmokeTest.groovy @@ -12,7 +12,7 @@ abstract class CiVisibilitySmokeTest extends Specification { def baseTemplatesPath = CiVisibilitySmokeTest.classLoader.getResource(projectName).toURI().schemeSpecificPart.replace('build/resources/test', 'src/test/resources') CiVisibilityTestUtils.generateTemplates(baseTemplatesPath, events, coverages, additionalReplacements) } else { - CiVisibilityTestUtils.assertData(projectName, events, coverages, additionalReplacements) + CiVisibilityTestUtils.assertData(projectName, events, coverages, additionalReplacements, []) } } diff --git a/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilityTestUtils.groovy b/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilityTestUtils.groovy index 5e4c61cbffd..b07295bc4c4 100644 --- a/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilityTestUtils.groovy +++ b/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilityTestUtils.groovy @@ -7,12 +7,9 @@ import com.jayway.jsonpath.JsonPath import com.jayway.jsonpath.Option import com.jayway.jsonpath.ReadContext import com.jayway.jsonpath.WriteContext -import datadog.trace.api.Config -import datadog.trace.civisibility.ci.CIProviderInfoFactory -import datadog.trace.civisibility.ci.GitLabInfo -import datadog.trace.civisibility.ci.GithubActionsInfo -import datadog.trace.civisibility.ci.env.CiEnvironment -import datadog.trace.civisibility.ci.env.CiEnvironmentImpl +import datadog.trace.api.DDSpanTypes +import datadog.trace.api.civisibility.config.LibraryCapability +import datadog.trace.core.DDSpan import freemarker.core.Environment import freemarker.core.InvalidReferenceException import freemarker.template.Template @@ -24,6 +21,7 @@ import org.skyscreamer.jsonassert.JSONCompareMode import java.nio.file.Files import java.nio.file.Paths import java.util.regex.Pattern +import java.util.stream.Collectors abstract class CiVisibilityTestUtils { @@ -55,6 +53,9 @@ abstract class CiVisibilityTestUtils { path("content.meta.['error.stack']", false), ] + // ignored tags on assertion and fixture build + static final List IGNORED_TAGS = LibraryCapability.values().toList().stream().map(c -> "content.meta.['${c.asTag()}']").collect(Collectors.toList()) + static final List COVERAGE_DYNAMIC_PATHS = [path("test_session_id"), path("test_suite_id"), path("span_id"),] private static final Comparator> EVENT_RESOURCE_COMPARATOR = Comparator., String> comparing((Map m) -> { @@ -68,7 +69,10 @@ abstract class CiVisibilityTestUtils { /** * Use this method to generate expected data templates */ - static void generateTemplates(String baseTemplatesPath, List> events, List> coverages, Map additionalReplacements) { + static void generateTemplates(String baseTemplatesPath, List> events, List> coverages, Map additionalReplacements, List ignoredTags = []) { + if (!ignoredTags.empty) { + events = removeTags(events, ignoredTags) + } events.sort(EVENT_RESOURCE_COMPARATOR) def templateGenerator = new TemplateGenerator(new LabelGenerator()) @@ -79,7 +83,7 @@ abstract class CiVisibilityTestUtils { Files.write(Paths.get(baseTemplatesPath, "coverages.ftl"), templateGenerator.generateTemplate(coverages, COVERAGE_DYNAMIC_PATHS + compiledAdditionalReplacements).bytes) } - static Map assertData(String baseTemplatesPath, List> events, List> coverages, Map additionalReplacements) { + static Map assertData(String baseTemplatesPath, List> events, List> coverages, Map additionalReplacements, List ignoredTags) { events.sort(EVENT_RESOURCE_COMPARATOR) def labelGenerator = new LabelGenerator() @@ -93,6 +97,9 @@ abstract class CiVisibilityTestUtils { replacementMap.put(labelGenerator.forKey(e.key), "\"$e.value\"") } + // ignore provided tags + events = removeTags(events, ignoredTags) + def environment = System.getenv() def ciRun = environment.get("GITHUB_ACTION") != null || environment.get("GITLAB_CI") != null def comparisonMode = ciRun ? JSONCompareMode.LENIENT : JSONCompareMode.NON_EXTENSIBLE @@ -129,6 +136,45 @@ abstract class CiVisibilityTestUtils { return replacementMap } + static List> removeTags(List> events, List tags) { + def filteredEvents = [] + + for (Map event : events) { + ReadContext ctx = JsonPath.parse(event, JSON_PATH_CONFIG) + for (String tag : tags) { + ctx.delete(path(tag).path) + } + filteredEvents.add(ctx.json()) + } + + return filteredEvents + } + + // Will sort traces in the following order: TEST -> SUITE -> MODULE -> SESSION + static class SortTracesByType implements Comparator> { + @Override + int compare(List o1, List o2) { + return Integer.compare(rootSpanTypeToVal(o1), rootSpanTypeToVal(o2)) + } + + int rootSpanTypeToVal(List trace) { + assert !trace.isEmpty() + def spanType = trace.get(0).getSpanType() + switch (spanType) { + case DDSpanTypes.TEST: + return 0 + case DDSpanTypes.TEST_SUITE_END: + return 1 + case DDSpanTypes.TEST_MODULE_END: + return 2 + case DDSpanTypes.TEST_SESSION_END: + return 3 + default: + return 4 + } + } + } + static final Configuration JSON_PATH_CONFIG = Configuration.builder() .options(Option.SUPPRESS_EXCEPTIONS) .build() diff --git a/dd-java-agent/instrumentation/junit-4.10/cucumber-junit-4/src/main/java/datadog/trace/instrumentation/junit4/CucumberUtils.java b/dd-java-agent/instrumentation/junit-4.10/cucumber-junit-4/src/main/java/datadog/trace/instrumentation/junit4/CucumberUtils.java index 985f777ff13..d3014374988 100644 --- a/dd-java-agent/instrumentation/junit-4.10/cucumber-junit-4/src/main/java/datadog/trace/instrumentation/junit4/CucumberUtils.java +++ b/dd-java-agent/instrumentation/junit-4.10/cucumber-junit-4/src/main/java/datadog/trace/instrumentation/junit4/CucumberUtils.java @@ -1,6 +1,7 @@ package datadog.trace.instrumentation.junit4; import datadog.trace.agent.tooling.muzzle.Reference; +import datadog.trace.api.civisibility.config.LibraryCapability; import datadog.trace.api.civisibility.config.TestIdentifier; import datadog.trace.api.civisibility.events.TestDescriptor; import datadog.trace.api.civisibility.events.TestSuiteDescriptor; @@ -13,6 +14,7 @@ import java.lang.invoke.MethodHandle; import java.net.URI; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; @@ -66,12 +68,21 @@ public static String getVersion() { private static final MethodHandle PICKLE_RUNNER_WITH_STEP_GET_PICKLE = REFLECTION.privateFieldGetter(WITH_STEP_PICKLE_RUNNER_CLASSNAME, "pickle"); + public static final List CAPABILITIES = + Arrays.asList( + LibraryCapability.TIA, + LibraryCapability.ATR, + LibraryCapability.EFD, + LibraryCapability.QUARANTINE, + LibraryCapability.DISABLED, + LibraryCapability.ATTEMPT_TO_FIX); + private CucumberUtils() {} public static Map getPicklesById(List> featureRunners) { Map pickleById = new HashMap<>(); for (ParentRunner featureRunner : featureRunners) { - Feature feature = (Feature) REFLECTION.invoke(FEATURE_GETTER, featureRunner); + Feature feature = REFLECTION.invoke(FEATURE_GETTER, featureRunner); for (Pickle pickle : feature.getPickles()) { Object pickleId = REFLECTION.invoke(PICKLE_ID_CONSTRUCTOR, pickle); pickleById.put(pickleId, pickle); @@ -129,7 +140,7 @@ public static String getTestNameForScenario(Description scenarioDescription) { Integer pickleLine = getPickleLine(scenarioDescription); if (pickleLine != null) { - return "LINE:" + pickleLine + ""; + return "LINE:" + pickleLine; } return "EMPTY_NAME"; diff --git a/dd-java-agent/instrumentation/junit-4.10/cucumber-junit-4/src/main/java/datadog/trace/instrumentation/junit4/JUnit4CucumberInstrumentation.java b/dd-java-agent/instrumentation/junit-4.10/cucumber-junit-4/src/main/java/datadog/trace/instrumentation/junit4/JUnit4CucumberInstrumentation.java index 0ba9205314c..9237af9e6a7 100644 --- a/dd-java-agent/instrumentation/junit-4.10/cucumber-junit-4/src/main/java/datadog/trace/instrumentation/junit4/JUnit4CucumberInstrumentation.java +++ b/dd-java-agent/instrumentation/junit-4.10/cucumber-junit-4/src/main/java/datadog/trace/instrumentation/junit4/JUnit4CucumberInstrumentation.java @@ -83,7 +83,8 @@ public static void addTracingListener( } } - TestEventsHandlerHolder.start(TestFrameworkInstrumentation.CUCUMBER); + TestEventsHandlerHolder.start( + TestFrameworkInstrumentation.CUCUMBER, CucumberUtils.CAPABILITIES); replacedNotifier.addListener( new CucumberTracingListener( diff --git a/dd-java-agent/instrumentation/junit-4.10/cucumber-junit-4/src/test/groovy/CucumberTest.groovy b/dd-java-agent/instrumentation/junit-4.10/cucumber-junit-4/src/test/groovy/CucumberTest.groovy index 89023b1abaf..491bfb3bd48 100644 --- a/dd-java-agent/instrumentation/junit-4.10/cucumber-junit-4/src/test/groovy/CucumberTest.groovy +++ b/dd-java-agent/instrumentation/junit-4.10/cucumber-junit-4/src/test/groovy/CucumberTest.groovy @@ -4,6 +4,7 @@ import datadog.trace.api.civisibility.config.TestIdentifier import datadog.trace.api.civisibility.telemetry.tag.TestFrameworkInstrumentation import datadog.trace.civisibility.CiVisibilityInstrumentationTest import datadog.trace.instrumentation.junit4.CucumberTracingListener +import datadog.trace.instrumentation.junit4.CucumberUtils import datadog.trace.instrumentation.junit4.TestEventsHandlerHolder import io.cucumber.core.options.Constants import org.example.cucumber.TestSucceedCucumber @@ -202,6 +203,14 @@ class CucumberTest extends CiVisibilityInstrumentationTest { ] } + def "test capabilities tagging #testcaseName"() { + setup: + runFeatures(["org/example/cucumber/calculator/basic_arithmetic.feature"], true) + + expect: + assertCapabilities(CucumberUtils.CAPABILITIES, 4) + } + private String version() { return CucumberTracingListener.FRAMEWORK_VERSION < "7" ? CucumberTracingListener.FRAMEWORK_VERSION : "latest" } @@ -213,7 +222,7 @@ class CucumberTest extends CiVisibilityInstrumentationTest { .map(f -> "classpath:" + f). collect(Collectors.joining(","))) - TestEventsHandlerHolder.start(TestFrameworkInstrumentation.CUCUMBER) + TestEventsHandlerHolder.start(TestFrameworkInstrumentation.CUCUMBER, CucumberUtils.CAPABILITIES) try { def result = runner.run(TestSucceedCucumber) if (expectSuccess) { diff --git a/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/groovy/JUnit413Test.groovy b/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/groovy/JUnit413Test.groovy index 5f400d721ff..ed5a06b4ab9 100644 --- a/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/groovy/JUnit413Test.groovy +++ b/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/groovy/JUnit413Test.groovy @@ -1,6 +1,7 @@ import datadog.trace.api.DisableTestTrace import datadog.trace.api.civisibility.telemetry.tag.TestFrameworkInstrumentation import datadog.trace.civisibility.CiVisibilityInstrumentationTest +import datadog.trace.instrumentation.junit4.JUnit4Utils import datadog.trace.instrumentation.junit4.TestEventsHandlerHolder import junit.runner.Version import org.example.TestFailedAfter @@ -38,7 +39,7 @@ class JUnit413Test extends CiVisibilityInstrumentationTest { } private void runTests(Collection> tests, boolean expectSuccess = true) { - TestEventsHandlerHolder.start(TestFrameworkInstrumentation.JUNIT4) + TestEventsHandlerHolder.start(TestFrameworkInstrumentation.JUNIT4, JUnit4Utils.CAPABILITIES) try { Class[] array = tests.toArray(new Class[0]) def result = runner.run(array) diff --git a/dd-java-agent/instrumentation/junit-4.10/munit-junit-4/src/main/java/datadog/trace/instrumentation/junit4/MUnitInstrumentation.java b/dd-java-agent/instrumentation/junit-4.10/munit-junit-4/src/main/java/datadog/trace/instrumentation/junit4/MUnitInstrumentation.java index 9fe051f3c56..2ef32f48d12 100644 --- a/dd-java-agent/instrumentation/junit-4.10/munit-junit-4/src/main/java/datadog/trace/instrumentation/junit4/MUnitInstrumentation.java +++ b/dd-java-agent/instrumentation/junit-4.10/munit-junit-4/src/main/java/datadog/trace/instrumentation/junit4/MUnitInstrumentation.java @@ -74,7 +74,7 @@ public static void addTracingListener( } } - TestEventsHandlerHolder.start(TestFrameworkInstrumentation.MUNIT); + TestEventsHandlerHolder.start(TestFrameworkInstrumentation.MUNIT, MUnitUtils.CAPABILITIES); replacedNotifier.addListener( new MUnitTracingListener( diff --git a/dd-java-agent/instrumentation/junit-4.10/munit-junit-4/src/main/java/datadog/trace/instrumentation/junit4/MUnitUtils.java b/dd-java-agent/instrumentation/junit-4.10/munit-junit-4/src/main/java/datadog/trace/instrumentation/junit4/MUnitUtils.java index 09b952f0bdb..cb0755ffe0d 100644 --- a/dd-java-agent/instrumentation/junit-4.10/munit-junit-4/src/main/java/datadog/trace/instrumentation/junit4/MUnitUtils.java +++ b/dd-java-agent/instrumentation/junit-4.10/munit-junit-4/src/main/java/datadog/trace/instrumentation/junit4/MUnitUtils.java @@ -1,11 +1,13 @@ package datadog.trace.instrumentation.junit4; +import datadog.trace.api.civisibility.config.LibraryCapability; import datadog.trace.api.civisibility.events.TestDescriptor; import datadog.trace.api.civisibility.events.TestSuiteDescriptor; import datadog.trace.util.MethodHandles; import java.lang.annotation.Annotation; import java.lang.invoke.MethodHandle; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import munit.MUnitRunner; import munit.Tag; @@ -20,6 +22,14 @@ public abstract class MUnitUtils { MUnitRunner.class, m -> "createTestDescription".equals(m.getName()) && m.getParameterCount() == 1); + public static final List CAPABILITIES = + Arrays.asList( + LibraryCapability.ATR, + LibraryCapability.EFD, + LibraryCapability.IMPACTED, + LibraryCapability.QUARANTINE, + LibraryCapability.ATTEMPT_TO_FIX); + private MUnitUtils() {} public static Description createDescription(MUnitRunner runner, Object test) { diff --git a/dd-java-agent/instrumentation/junit-4.10/munit-junit-4/src/test/groovy/MUnitTest.groovy b/dd-java-agent/instrumentation/junit-4.10/munit-junit-4/src/test/groovy/MUnitTest.groovy index 4a2427a7b76..5df618caa3c 100644 --- a/dd-java-agent/instrumentation/junit-4.10/munit-junit-4/src/test/groovy/MUnitTest.groovy +++ b/dd-java-agent/instrumentation/junit-4.10/munit-junit-4/src/test/groovy/MUnitTest.groovy @@ -5,6 +5,7 @@ import datadog.trace.civisibility.CiVisibilityInstrumentationTest import datadog.trace.civisibility.diff.FileDiff import datadog.trace.civisibility.diff.LineDiff import datadog.trace.instrumentation.junit4.MUnitTracingListener +import datadog.trace.instrumentation.junit4.MUnitUtils import datadog.trace.instrumentation.junit4.TestEventsHandlerHolder import org.example.TestFailedAssumptionMUnit import org.example.TestFailedMUnit @@ -146,8 +147,16 @@ class MUnitTest extends CiVisibilityInstrumentationTest { "test-attempt-to-fix-disabled-succeeded" | true | [TestSucceedMUnit] | [new TestFQN("org.example.TestSucceedMUnit", "Calculator.add")] | [] | [new TestFQN("org.example.TestSucceedMUnit", "Calculator.add")] } + def "test capabilities tagging #testcaseName"() { + setup: + runTests([TestSucceedMUnit], true) + + expect: + assertCapabilities(MUnitUtils.CAPABILITIES, 4) + } + private void runTests(Collection> tests, boolean expectSuccess = true) { - TestEventsHandlerHolder.start(TestFrameworkInstrumentation.MUNIT) + TestEventsHandlerHolder.start(TestFrameworkInstrumentation.MUNIT, MUnitUtils.CAPABILITIES) try { Class[] array = tests.toArray(new Class[0]) def result = runner.run(array) diff --git a/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/JUnit4Instrumentation.java b/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/JUnit4Instrumentation.java index 99c07805562..02786479793 100644 --- a/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/JUnit4Instrumentation.java +++ b/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/JUnit4Instrumentation.java @@ -115,7 +115,7 @@ public static void addTracingListener( } } - TestEventsHandlerHolder.start(TestFrameworkInstrumentation.JUNIT4); + TestEventsHandlerHolder.start(TestFrameworkInstrumentation.JUNIT4, JUnit4Utils.CAPABILITIES); final TracingListener tracingListener = new JUnit4TracingListener( diff --git a/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/JUnit4Utils.java b/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/JUnit4Utils.java index b8a88a464db..c2213e2fa13 100644 --- a/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/JUnit4Utils.java +++ b/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/JUnit4Utils.java @@ -2,6 +2,7 @@ import static datadog.json.JsonMapper.toJson; +import datadog.trace.api.civisibility.config.LibraryCapability; import datadog.trace.api.civisibility.config.TestIdentifier; import datadog.trace.api.civisibility.config.TestSourceData; import datadog.trace.api.civisibility.events.TestDescriptor; @@ -12,6 +13,7 @@ import java.lang.invoke.MethodHandle; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.regex.Matcher; @@ -51,6 +53,16 @@ public abstract class JUnit4Utils { private static final MethodHandle DESCRIPTION_UNIQUE_ID = METHOD_HANDLES.privateFieldGetter(Description.class, "fUniqueId"); + public static final List CAPABILITIES = + Arrays.asList( + LibraryCapability.TIA, + LibraryCapability.ATR, + LibraryCapability.EFD, + LibraryCapability.IMPACTED, + LibraryCapability.QUARANTINE, + LibraryCapability.DISABLED, + LibraryCapability.ATTEMPT_TO_FIX); + private static MethodHandle accessListenersFieldInRunNotifier() { MethodHandle listeners = METHOD_HANDLES.privateFieldGetter(RunNotifier.class, "listeners"); if (listeners != null) { diff --git a/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/TestEventsHandlerHolder.java b/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/TestEventsHandlerHolder.java index db5b9de2b3c..fa3eacdf225 100644 --- a/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/TestEventsHandlerHolder.java +++ b/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/TestEventsHandlerHolder.java @@ -1,12 +1,14 @@ package datadog.trace.instrumentation.junit4; import datadog.trace.api.civisibility.InstrumentationBridge; +import datadog.trace.api.civisibility.config.LibraryCapability; import datadog.trace.api.civisibility.events.TestDescriptor; import datadog.trace.api.civisibility.events.TestEventsHandler; import datadog.trace.api.civisibility.events.TestSuiteDescriptor; import datadog.trace.api.civisibility.telemetry.tag.TestFrameworkInstrumentation; import datadog.trace.util.AgentThreadFactory; import datadog.trace.util.ConcurrentEnumMap; +import java.util.Collection; import java.util.Map; public abstract class TestEventsHandlerHolder { @@ -25,13 +27,14 @@ public abstract class TestEventsHandlerHolder { false)); } - public static synchronized void start(TestFrameworkInstrumentation framework) { + public static synchronized void start( + TestFrameworkInstrumentation framework, Collection capabilities) { TestEventsHandler handler = HANDLERS.get(framework); if (handler == null) { HANDLERS.put( framework, InstrumentationBridge.createTestEventsHandler( - framework.name().toLowerCase(), null, null)); + framework.name().toLowerCase(), null, null, capabilities)); } } diff --git a/dd-java-agent/instrumentation/junit-4.10/src/test/groovy/JUnit4Test.groovy b/dd-java-agent/instrumentation/junit-4.10/src/test/groovy/JUnit4Test.groovy index 4789ca302f5..44fb66f6ffc 100644 --- a/dd-java-agent/instrumentation/junit-4.10/src/test/groovy/JUnit4Test.groovy +++ b/dd-java-agent/instrumentation/junit-4.10/src/test/groovy/JUnit4Test.groovy @@ -5,6 +5,7 @@ import datadog.trace.api.civisibility.telemetry.tag.TestFrameworkInstrumentation import datadog.trace.civisibility.CiVisibilityInstrumentationTest import datadog.trace.civisibility.diff.FileDiff import datadog.trace.civisibility.diff.LineDiff +import datadog.trace.instrumentation.junit4.JUnit4Utils import datadog.trace.instrumentation.junit4.TestEventsHandlerHolder import junit.runner.Version import org.example.* @@ -207,8 +208,16 @@ class JUnit4Test extends CiVisibilityInstrumentationTest { "test-attempt-to-fix-disabled-succeeded" | true | [TestSucceed] | [new TestFQN("org.example.TestSucceed", "test_succeed")] | [] | [new TestFQN("org.example.TestSucceed", "test_succeed")] } + def "test capabilities tagging #testcaseName"() { + setup: + runTests([TestSucceed], true) + + expect: + assertCapabilities(JUnit4Utils.CAPABILITIES, 4) + } + private void runTests(Collection> tests, boolean expectSuccess = true) { - TestEventsHandlerHolder.start(TestFrameworkInstrumentation.JUNIT4) + TestEventsHandlerHolder.start(TestFrameworkInstrumentation.JUNIT4, JUnit4Utils.CAPABILITIES) try { Class[] array = tests.toArray(new Class[0]) def result = runner.run(array) diff --git a/dd-java-agent/instrumentation/junit-5.3/cucumber-junit-5/src/test/groovy/CucumberTest.groovy b/dd-java-agent/instrumentation/junit-5.3/cucumber-junit-5/src/test/groovy/CucumberTest.groovy index 2b6710602c6..549b16791c1 100644 --- a/dd-java-agent/instrumentation/junit-5.3/cucumber-junit-5/src/test/groovy/CucumberTest.groovy +++ b/dd-java-agent/instrumentation/junit-5.3/cucumber-junit-5/src/test/groovy/CucumberTest.groovy @@ -2,6 +2,7 @@ import datadog.trace.api.DisableTestTrace import datadog.trace.api.civisibility.config.TestFQN import datadog.trace.api.civisibility.config.TestIdentifier import datadog.trace.civisibility.CiVisibilityInstrumentationTest +import datadog.trace.instrumentation.junit5.JUnitPlatformUtils import datadog.trace.instrumentation.junit5.TestEventsHandlerHolder import io.cucumber.core.api.TypeRegistry import io.cucumber.core.options.Constants @@ -211,6 +212,14 @@ class CucumberTest extends CiVisibilityInstrumentationTest { ] } + def "test capabilities tagging #testcaseName"() { + setup: + runFeatures(["org/example/cucumber/calculator/basic_arithmetic.feature"], false, true) + + expect: + assertCapabilities(JUnitPlatformUtils.CUCUMBER_CAPABILITIES, 4) + } + private String parameterizedTestNameSuffix() { // older releases report different example names version() == "5.4.0" ? "Example #1" : "Example #1.1" diff --git a/dd-java-agent/instrumentation/junit-5.3/junit-5.8/src/test/groovy/JUnit58Test.groovy b/dd-java-agent/instrumentation/junit-5.3/junit-5.8/src/test/groovy/JUnit58Test.groovy index 016442eb5b8..46cc26e1d76 100644 --- a/dd-java-agent/instrumentation/junit-5.3/junit-5.8/src/test/groovy/JUnit58Test.groovy +++ b/dd-java-agent/instrumentation/junit-5.3/junit-5.8/src/test/groovy/JUnit58Test.groovy @@ -1,8 +1,9 @@ import datadog.trace.api.DisableTestTrace -import datadog.trace.api.civisibility.CIConstants import datadog.trace.civisibility.CiVisibilityInstrumentationTest +import datadog.trace.instrumentation.junit5.JUnitPlatformUtils import datadog.trace.instrumentation.junit5.TestEventsHandlerHolder import org.example.* +import org.junit.jupiter.api.Assumptions import org.junit.jupiter.api.ClassOrderer import org.junit.jupiter.api.MethodOrderer import org.junit.jupiter.engine.Constants @@ -82,6 +83,15 @@ class JUnit58Test extends CiVisibilityInstrumentationTest { ] } + def "test capabilities tagging #testcaseName"() { + setup: + Assumptions.assumeTrue(JUnitPlatformUtils.isJunitTestOrderingSupported(instrumentedLibraryVersion())) + runTests([TestSucceed], true) + + expect: + assertCapabilities(JUnitPlatformUtils.JUNIT_CAPABILITIES_ORDERING, 5) + } + private static void runTests(List> tests, boolean expectSuccess = true) { DiscoverySelector[] selectors = new DiscoverySelector[tests.size()] for (i in 0..> classes, boolean expectSuccess = true) { DiscoverySelector[] selectors = new DiscoverySelector[classes.size()] for (i in 0.. JUNIT_CAPABILITIES_BASE = + Arrays.asList( + LibraryCapability.TIA, + LibraryCapability.ATR, + LibraryCapability.EFD, + LibraryCapability.IMPACTED, + LibraryCapability.QUARANTINE, + LibraryCapability.DISABLED, + LibraryCapability.ATTEMPT_TO_FIX); + + public static final List JUNIT_CAPABILITIES_ORDERING = + Arrays.asList( + LibraryCapability.TIA, + LibraryCapability.ATR, + LibraryCapability.EFD, + LibraryCapability.IMPACTED, + LibraryCapability.QUARANTINE, + LibraryCapability.DISABLED, + LibraryCapability.ATTEMPT_TO_FIX, + LibraryCapability.FAIL_FAST); + + public static final List SPOCK_CAPABILITIES = + Arrays.asList( + LibraryCapability.TIA, + LibraryCapability.ATR, + LibraryCapability.EFD, + LibraryCapability.IMPACTED, + LibraryCapability.QUARANTINE, + LibraryCapability.DISABLED, + LibraryCapability.ATTEMPT_TO_FIX); + + public static final List CUCUMBER_CAPABILITIES = + Arrays.asList( + LibraryCapability.TIA, + LibraryCapability.ATR, + LibraryCapability.EFD, + LibraryCapability.QUARANTINE, + LibraryCapability.DISABLED, + LibraryCapability.ATTEMPT_TO_FIX); + private JUnitPlatformUtils() {} private static final MethodHandles METHOD_HANDLES = @@ -243,6 +288,31 @@ public static TestFrameworkInstrumentation engineIdToFramework(String engineId) } } + // only used in junit5 and spock, cucumber has its own utils method + @Nullable + public static String getFrameworkVersion(TestEngine testEngine) { + return testEngine.getVersion().orElse(null); + } + + public static boolean isJunitTestOrderingSupported(String version) { + return version != null && junitV58.compareTo(new ComparableVersion(version)) <= 0; + } + + public static List capabilities(TestEngine testEngine) { + TestFrameworkInstrumentation framework = engineToFramework(testEngine); + if (framework.equals(TestFrameworkInstrumentation.CUCUMBER)) { + return CUCUMBER_CAPABILITIES; + } else if (framework.equals(TestFrameworkInstrumentation.SPOCK)) { + return SPOCK_CAPABILITIES; + } else { + if (isJunitTestOrderingSupported(getFrameworkVersion(testEngine))) { + return JUNIT_CAPABILITIES_ORDERING; + } else { + return JUNIT_CAPABILITIES_BASE; + } + } + } + public static List getTags(TestDescriptor testDescriptor) { return testDescriptor.getTags().stream().map(TestTag::getName).collect(Collectors.toList()); } diff --git a/dd-java-agent/instrumentation/junit-5.3/src/main/java/datadog/trace/instrumentation/junit5/TestEventsHandlerHolder.java b/dd-java-agent/instrumentation/junit-5.3/src/main/java/datadog/trace/instrumentation/junit5/TestEventsHandlerHolder.java index cfffdcb708c..a53e419e020 100644 --- a/dd-java-agent/instrumentation/junit-5.3/src/main/java/datadog/trace/instrumentation/junit5/TestEventsHandlerHolder.java +++ b/dd-java-agent/instrumentation/junit-5.3/src/main/java/datadog/trace/instrumentation/junit5/TestEventsHandlerHolder.java @@ -63,7 +63,10 @@ public static synchronized void start( if (handler == null) { handler = InstrumentationBridge.createTestEventsHandler( - framework.name().toLowerCase(), suiteStore, testStore); + framework.name().toLowerCase(), + suiteStore, + testStore, + JUnitPlatformUtils.capabilities(testEngine)); HANDLERS.put(framework, handler); } } diff --git a/dd-java-agent/instrumentation/junit-5.3/src/main/java/datadog/trace/instrumentation/junit5/TracingListener.java b/dd-java-agent/instrumentation/junit-5.3/src/main/java/datadog/trace/instrumentation/junit5/TracingListener.java index 143de0659ec..e1b4cb8d3c0 100644 --- a/dd-java-agent/instrumentation/junit-5.3/src/main/java/datadog/trace/instrumentation/junit5/TracingListener.java +++ b/dd-java-agent/instrumentation/junit-5.3/src/main/java/datadog/trace/instrumentation/junit5/TracingListener.java @@ -23,7 +23,7 @@ public class TracingListener implements EngineExecutionListener { public TracingListener(TestEngine testEngine) { String engineId = testEngine.getId(); testFramework = engineId == null || engineId.startsWith("junit") ? "junit5" : engineId; - testFrameworkVersion = testEngine.getVersion().orElse(null); + testFrameworkVersion = JUnitPlatformUtils.getFrameworkVersion(testEngine); } @Override diff --git a/dd-java-agent/instrumentation/junit-5.3/src/test/groovy/JUnit5Test.groovy b/dd-java-agent/instrumentation/junit-5.3/src/test/groovy/JUnit5Test.groovy index 1e97c6464cb..20e5f45aa4d 100644 --- a/dd-java-agent/instrumentation/junit-5.3/src/test/groovy/JUnit5Test.groovy +++ b/dd-java-agent/instrumentation/junit-5.3/src/test/groovy/JUnit5Test.groovy @@ -1,9 +1,14 @@ +import datadog.trace.agent.test.asserts.ListWriterAssert +import datadog.trace.api.DDSpanTypes import datadog.trace.api.DisableTestTrace +import datadog.trace.api.civisibility.config.LibraryCapability import datadog.trace.api.civisibility.config.TestFQN import datadog.trace.api.civisibility.config.TestIdentifier import datadog.trace.civisibility.CiVisibilityInstrumentationTest +import datadog.trace.civisibility.CiVisibilityTestUtils import datadog.trace.civisibility.diff.FileDiff import datadog.trace.civisibility.diff.LineDiff +import datadog.trace.instrumentation.junit5.JUnitPlatformUtils import datadog.trace.instrumentation.junit5.TestEventsHandlerHolder import org.example.TestAssumption import org.example.TestAssumptionAndSucceed @@ -36,6 +41,7 @@ import org.example.TestSucceedVerySlow import org.example.TestSucceedWithCategories import org.example.TestSuiteSetUpAssumption import org.example.TestTemplate +import org.junit.jupiter.api.Assumptions import org.junit.jupiter.engine.JupiterTestEngine import org.junit.platform.engine.DiscoverySelector import org.junit.platform.engine.TestExecutionResult @@ -46,6 +52,7 @@ import org.junit.platform.launcher.core.LauncherFactory import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.CopyOnWriteArrayList +import java.util.stream.Collectors import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass @@ -245,6 +252,15 @@ class JUnit5Test extends CiVisibilityInstrumentationTest { "test-attempt-to-fix-disabled-succeeded" | true | [TestSucceed] | [new TestFQN("org.example.TestSucceed", "test_succeed")] | [] | [new TestFQN("org.example.TestSucceed", "test_succeed")] } + def "test capabilities tagging #testcaseName"() { + setup: + Assumptions.assumeTrue(!JUnitPlatformUtils.isJunitTestOrderingSupported(instrumentedLibraryVersion())) + runTests([TestSucceed], true) + + expect: + assertCapabilities(JUnitPlatformUtils.JUNIT_CAPABILITIES_BASE, 4) + } + protected void runTests(List> tests, boolean expectSuccess = true) { DiscoverySelector[] selectors = new DiscoverySelector[tests.size()] for (i in 0.. manualFeatureHooks; diff --git a/dd-java-agent/instrumentation/karate/src/main/java/datadog/trace/instrumentation/karate/KarateUtils.java b/dd-java-agent/instrumentation/karate/src/main/java/datadog/trace/instrumentation/karate/KarateUtils.java index d96697a2c63..3fc6348aa6e 100644 --- a/dd-java-agent/instrumentation/karate/src/main/java/datadog/trace/instrumentation/karate/KarateUtils.java +++ b/dd-java-agent/instrumentation/karate/src/main/java/datadog/trace/instrumentation/karate/KarateUtils.java @@ -2,6 +2,7 @@ import static datadog.json.JsonMapper.toJson; +import com.intuit.karate.FileUtils; import com.intuit.karate.core.Feature; import com.intuit.karate.core.FeatureRuntime; import com.intuit.karate.core.Result; @@ -9,13 +10,16 @@ import com.intuit.karate.core.ScenarioResult; import com.intuit.karate.core.ScenarioRuntime; import com.intuit.karate.core.Tag; +import datadog.trace.api.civisibility.config.LibraryCapability; import datadog.trace.api.civisibility.config.TestIdentifier; import datadog.trace.api.civisibility.events.TestDescriptor; import datadog.trace.api.civisibility.events.TestSuiteDescriptor; +import datadog.trace.util.ComparableVersion; import datadog.trace.util.MethodHandles; import datadog.trace.util.Strings; import java.lang.invoke.MethodHandle; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -45,6 +49,25 @@ private KarateUtils() {} private static final MethodHandle SCENARIO_RUNTIME_RESULT_SETTER = METHOD_HANDLES.privateFieldSetter(ScenarioRuntime.class, "result"); + private static final ComparableVersion karateV12 = new ComparableVersion("1.2.0"); + private static final ComparableVersion karateV13 = new ComparableVersion("1.3.0"); + + public static final List CAPABILITIES_BASE = + Arrays.asList( + LibraryCapability.ATR, + LibraryCapability.EFD, + LibraryCapability.QUARANTINE, + LibraryCapability.ATTEMPT_TO_FIX); + + public static final List CAPABILITIES_SKIPPING = + Arrays.asList( + LibraryCapability.ATR, + LibraryCapability.EFD, + LibraryCapability.QUARANTINE, + LibraryCapability.ATTEMPT_TO_FIX, + LibraryCapability.TIA, + LibraryCapability.DISABLED); + public static Feature getFeature(FeatureRuntime featureRuntime) { if (FEATURE_RUNTIME_FEATURE_CALL_GETTER != null) { Object featureCall = @@ -131,4 +154,24 @@ public static void resetBeforeHook(FeatureRuntime featureRuntime) { public static void setResult(ScenarioRuntime runtime, ScenarioResult result) { METHOD_HANDLES.invoke(SCENARIO_RUNTIME_RESULT_SETTER, runtime, result); } + + public static String getKarateVersion() { + return FileUtils.KARATE_VERSION; + } + + public static boolean isSkippingSupported(String version) { + return version != null && karateV12.compareTo(new ComparableVersion(version)) <= 0; + } + + public static boolean isSetupTagSupported(String version) { + return version != null && karateV13.compareTo(new ComparableVersion(version)) <= 0; + } + + public static List capabilities(String frameworkVersion) { + if (isSkippingSupported(frameworkVersion)) { + return CAPABILITIES_SKIPPING; + } + + return CAPABILITIES_BASE; + } } diff --git a/dd-java-agent/instrumentation/karate/src/main/java/datadog/trace/instrumentation/karate/TestEventsHandlerHolder.java b/dd-java-agent/instrumentation/karate/src/main/java/datadog/trace/instrumentation/karate/TestEventsHandlerHolder.java index 97777f8ff66..40a3ad8195d 100644 --- a/dd-java-agent/instrumentation/karate/src/main/java/datadog/trace/instrumentation/karate/TestEventsHandlerHolder.java +++ b/dd-java-agent/instrumentation/karate/src/main/java/datadog/trace/instrumentation/karate/TestEventsHandlerHolder.java @@ -21,7 +21,9 @@ public abstract class TestEventsHandlerHolder { } public static void start() { - TEST_EVENTS_HANDLER = InstrumentationBridge.createTestEventsHandler("karate", null, null); + TEST_EVENTS_HANDLER = + InstrumentationBridge.createTestEventsHandler( + "karate", null, null, KarateUtils.capabilities(KarateTracingHook.FRAMEWORK_VERSION)); } public static void stop() { diff --git a/dd-java-agent/instrumentation/karate/src/test/groovy/KarateTest.groovy b/dd-java-agent/instrumentation/karate/src/test/groovy/KarateTest.groovy index d99b550dec7..38ec2734e01 100644 --- a/dd-java-agent/instrumentation/karate/src/test/groovy/KarateTest.groovy +++ b/dd-java-agent/instrumentation/karate/src/test/groovy/KarateTest.groovy @@ -1,8 +1,8 @@ -import com.intuit.karate.FileUtils import datadog.trace.api.DisableTestTrace import datadog.trace.api.civisibility.config.TestFQN import datadog.trace.api.civisibility.config.TestIdentifier import datadog.trace.civisibility.CiVisibilityInstrumentationTest +import datadog.trace.instrumentation.karate.KarateUtils import datadog.trace.instrumentation.karate.TestEventsHandlerHolder import org.example.* import org.junit.jupiter.api.Assumptions @@ -33,7 +33,7 @@ class KarateTest extends CiVisibilityInstrumentationTest { testcaseName | success | tests | assumption "test-succeed" | true | [TestSucceedKarate] | true "test-succeed-parallel" | true | [TestSucceedParallelKarate] | true - "test-with-setup" | true | [TestWithSetupKarate] | isSetupTagSupported(FileUtils.KARATE_VERSION) + "test-with-setup" | true | [TestWithSetupKarate] | KarateUtils.isSetupTagSupported(KarateUtils.getKarateVersion()) "test-parameterized" | true | [TestParameterizedKarate] | true "test-failed" | false | [TestFailedKarate] | true "test-skipped-feature" | true | [TestSkippedFeatureKarate] | true @@ -41,7 +41,7 @@ class KarateTest extends CiVisibilityInstrumentationTest { } def "test ITR #testcaseName"() { - Assumptions.assumeTrue(isSkippingSupported(FileUtils.KARATE_VERSION)) + Assumptions.assumeTrue(KarateUtils.isSkippingSupported(KarateUtils.getKarateVersion())) givenSkippableTests(skippedTests) @@ -143,7 +143,7 @@ class KarateTest extends CiVisibilityInstrumentationTest { } def "test disabled #testcaseName"() { - Assumptions.assumeTrue(isSkippingSupported(FileUtils.KARATE_VERSION)) + Assumptions.assumeTrue(KarateUtils.isSkippingSupported(KarateUtils.getKarateVersion())) givenDisabledTests(disabled) @@ -175,6 +175,19 @@ class KarateTest extends CiVisibilityInstrumentationTest { "test-attempt-to-fix-disabled-succeeded" | true | [TestSucceedKarate] | [new TestFQN("[org/example/test_succeed] test succeed", "first scenario")] | [] | [new TestFQN("[org/example/test_succeed] test succeed", "first scenario")] } + def "test capabilities tagging #testcaseName"() { + Assumptions.assumeTrue(assumption) + + runTests([TestSucceedOneCaseKarate], true) + + assertCapabilities(capabilities, 5) + + where: + testcaseName | capabilities | assumption + "test-capabilities-base" | KarateUtils.CAPABILITIES_BASE | !KarateUtils.isSkippingSupported(KarateUtils.getKarateVersion()) + "test-capabilities-skipping" | KarateUtils.CAPABILITIES_SKIPPING | KarateUtils.isSkippingSupported(KarateUtils.getKarateVersion()) + } + private void runTests(List> tests, boolean expectSuccess = true) { TestEventsHandlerHolder.start() @@ -221,16 +234,7 @@ class KarateTest extends CiVisibilityInstrumentationTest { @Override String instrumentedLibraryVersion() { - return FileUtils.KARATE_VERSION - } - - boolean isSkippingSupported(String frameworkVersion) { - // earlier Karate version contain a bug that does not allow skipping scenarios - frameworkVersion >= "1.2.0" - } - - boolean isSetupTagSupported(String frameworkVersion) { - frameworkVersion >= "1.3.0" + return KarateUtils.getKarateVersion() } private static final class TestResultListener implements TestExecutionListener { diff --git a/dd-java-agent/instrumentation/scalatest/src/main/java/datadog/trace/instrumentation/scalatest/RunContext.java b/dd-java-agent/instrumentation/scalatest/src/main/java/datadog/trace/instrumentation/scalatest/RunContext.java index 1e243561c86..0b8b6806bb4 100644 --- a/dd-java-agent/instrumentation/scalatest/src/main/java/datadog/trace/instrumentation/scalatest/RunContext.java +++ b/dd-java-agent/instrumentation/scalatest/src/main/java/datadog/trace/instrumentation/scalatest/RunContext.java @@ -37,8 +37,11 @@ public static void destroy(int runStamp) { } private final int runStamp; + private final TestEventsHandler eventHandler = - InstrumentationBridge.createTestEventsHandler("scalatest", null, null); + InstrumentationBridge.createTestEventsHandler( + "scalatest", null, null, ScalatestUtils.CAPABILITIES); + private final java.util.Map skipReasonByTest = new ConcurrentHashMap<>(); private final java.util.Map> tagsByTest = diff --git a/dd-java-agent/instrumentation/scalatest/src/main/java/datadog/trace/instrumentation/scalatest/ScalatestUtils.java b/dd-java-agent/instrumentation/scalatest/src/main/java/datadog/trace/instrumentation/scalatest/ScalatestUtils.java index 16dcf2c861d..140b276244a 100644 --- a/dd-java-agent/instrumentation/scalatest/src/main/java/datadog/trace/instrumentation/scalatest/ScalatestUtils.java +++ b/dd-java-agent/instrumentation/scalatest/src/main/java/datadog/trace/instrumentation/scalatest/ScalatestUtils.java @@ -1,7 +1,10 @@ package datadog.trace.instrumentation.scalatest; +import datadog.trace.api.civisibility.config.LibraryCapability; import java.io.InputStream; import java.net.URL; +import java.util.Arrays; +import java.util.List; import java.util.Properties; import javax.annotation.Nullable; import org.scalatest.Reporter; @@ -15,6 +18,16 @@ public abstract class ScalatestUtils { private static final ClassLoader CLASS_LOADER = Reporter.class.getClassLoader(); + public static final List CAPABILITIES = + Arrays.asList( + LibraryCapability.TIA, + LibraryCapability.EFD, + LibraryCapability.ATR, + LibraryCapability.IMPACTED, + LibraryCapability.QUARANTINE, + LibraryCapability.DISABLED, + LibraryCapability.ATTEMPT_TO_FIX); + private ScalatestUtils() {} public static @Nullable String getScalatestVersion() { diff --git a/dd-java-agent/instrumentation/scalatest/src/test/groovy/ScalatestTest.groovy b/dd-java-agent/instrumentation/scalatest/src/test/groovy/ScalatestTest.groovy index 9f7ba01037d..f9e551788d4 100644 --- a/dd-java-agent/instrumentation/scalatest/src/test/groovy/ScalatestTest.groovy +++ b/dd-java-agent/instrumentation/scalatest/src/test/groovy/ScalatestTest.groovy @@ -180,6 +180,14 @@ class ScalatestTest extends CiVisibilityInstrumentationTest { "test-attempt-to-fix-disabled-succeeded" | true | [TestSucceed] | [new TestFQN("org.example.TestSucceed", "Example.add adds two numbers")] | [] | [new TestFQN("org.example.TestSucceed", "Example.add adds two numbers")] } + def "test capabilities tagging #testcaseName"() { + setup: + runTests([TestSucceed], true) + + expect: + assertCapabilities(ScalatestUtils.CAPABILITIES, 4) + } + @Override String instrumentedLibraryName() { return "scalatest" diff --git a/dd-java-agent/instrumentation/testng/src/main/java/datadog/trace/instrumentation/testng/TestEventsHandlerHolder.java b/dd-java-agent/instrumentation/testng/src/main/java/datadog/trace/instrumentation/testng/TestEventsHandlerHolder.java index 41835553f5a..d8dc16d391f 100644 --- a/dd-java-agent/instrumentation/testng/src/main/java/datadog/trace/instrumentation/testng/TestEventsHandlerHolder.java +++ b/dd-java-agent/instrumentation/testng/src/main/java/datadog/trace/instrumentation/testng/TestEventsHandlerHolder.java @@ -30,7 +30,9 @@ public static synchronized void setContextStore(ContextStore getTestClass(final ITestResult result) { IClass testClass = result.getTestClass(); if (testClass == null) { @@ -260,4 +265,41 @@ public static TestSuiteDescriptor toSuiteDescriptor(ITestClass testClass) { Class testSuiteClass = testClass.getRealClass(); return new TestSuiteDescriptor(testSuiteName, testSuiteClass); } + + public static boolean isEFDSupported(String version) { + return version != null && testNGv75.compareTo(new ComparableVersion(version)) <= 0; + } + + public static boolean isExceptionSuppressionSupported(String version) { + return version != null && testNGv75.compareTo(new ComparableVersion(version)) <= 0; + } + + public static boolean isTestOrderingSupported(String version) { + return version != null && testNGv70.compareTo(new ComparableVersion(version)) <= 0; + } + + public static List capabilities(String version) { + List baseCapabilities = + new ArrayList<>( + Arrays.asList( + LibraryCapability.TIA, LibraryCapability.IMPACTED, LibraryCapability.DISABLED)); + + boolean isEFDSupported = isEFDSupported(version); + boolean isExceptionSuppressionSupported = isExceptionSuppressionSupported(version); + if (isExceptionSuppressionSupported) { + baseCapabilities.add(LibraryCapability.ATR); + baseCapabilities.add(LibraryCapability.QUARANTINE); + } + if (isEFDSupported) { + baseCapabilities.add(LibraryCapability.EFD); + } + if (isExceptionSuppressionSupported && isEFDSupported) { + baseCapabilities.add(LibraryCapability.ATTEMPT_TO_FIX); + } + if (isTestOrderingSupported(version)) { + baseCapabilities.add(LibraryCapability.FAIL_FAST); + } + + return baseCapabilities; + } } diff --git a/dd-java-agent/instrumentation/testng/src/testFixtures/groovy/datadog/trace/instrumentation/testng/TestNGTest.groovy b/dd-java-agent/instrumentation/testng/src/testFixtures/groovy/datadog/trace/instrumentation/testng/TestNGTest.groovy index 589dad8f372..f737cafd5ef 100644 --- a/dd-java-agent/instrumentation/testng/src/testFixtures/groovy/datadog/trace/instrumentation/testng/TestNGTest.groovy +++ b/dd-java-agent/instrumentation/testng/src/testFixtures/groovy/datadog/trace/instrumentation/testng/TestNGTest.groovy @@ -6,7 +6,6 @@ import datadog.trace.api.civisibility.config.TestIdentifier import datadog.trace.civisibility.CiVisibilityInstrumentationTest import datadog.trace.civisibility.diff.FileDiff import datadog.trace.civisibility.diff.LineDiff -import org.apache.maven.artifact.versioning.ComparableVersion import org.example.* import org.junit.jupiter.api.Assumptions import org.testng.TestNG @@ -17,9 +16,7 @@ abstract class TestNGTest extends CiVisibilityInstrumentationTest { static testOutputDir = "build/tmp/test-output" - static ComparableVersion currentTestNGVersion = new ComparableVersion(TracingListener.FRAMEWORK_VERSION) - static ComparableVersion testNGv75 = new ComparableVersion("7.5") - static ComparableVersion testNGv70 = new ComparableVersion("7.0") + static currentTestNGVersion = TestNGUtils.getTestNGVersion() def "test #testcaseName"() { runTests(tests, null, success) @@ -97,7 +94,7 @@ abstract class TestNGTest extends CiVisibilityInstrumentationTest { } def "test flaky retries #testcaseName"() { - Assumptions.assumeTrue(isExceptionSuppressionSupported()) + Assumptions.assumeTrue(TestNGUtils.isExceptionSuppressionSupported(currentTestNGVersion)) givenFlakyRetryEnabled(true) givenFlakyTests(retriedTests) @@ -116,7 +113,7 @@ abstract class TestNGTest extends CiVisibilityInstrumentationTest { } def "test early flakiness detection #testcaseName"() { - Assumptions.assumeTrue(isEFDSupported()) + Assumptions.assumeTrue(TestNGUtils.isEFDSupported(currentTestNGVersion)) givenEarlyFlakinessDetectionEnabled(true) givenKnownTests(knownTestsList) @@ -159,7 +156,7 @@ abstract class TestNGTest extends CiVisibilityInstrumentationTest { } def "test quarantined #testcaseName"() { - Assumptions.assumeTrue(isExceptionSuppressionSupported()) + Assumptions.assumeTrue(TestNGUtils.isExceptionSuppressionSupported(currentTestNGVersion)) givenQuarantinedTests(quarantined) @@ -174,7 +171,7 @@ abstract class TestNGTest extends CiVisibilityInstrumentationTest { } def "test quarantined auto-retries #testcaseName"() { - Assumptions.assumeTrue(isExceptionSuppressionSupported()) + Assumptions.assumeTrue(TestNGUtils.isExceptionSuppressionSupported(currentTestNGVersion)) givenQuarantinedTests(quarantined) @@ -192,7 +189,7 @@ abstract class TestNGTest extends CiVisibilityInstrumentationTest { } def "test quarantined early flakiness detection #testcaseName"() { - Assumptions.assumeTrue(isExceptionSuppressionSupported()) + Assumptions.assumeTrue(TestNGUtils.isExceptionSuppressionSupported(currentTestNGVersion)) givenQuarantinedTests(quarantined) @@ -224,7 +221,8 @@ abstract class TestNGTest extends CiVisibilityInstrumentationTest { } def "test attempt to fix #testcaseName"() { - Assumptions.assumeTrue(isExceptionSuppressionSupported()) + Assumptions.assumeTrue(TestNGUtils.isExceptionSuppressionSupported(currentTestNGVersion)) + Assumptions.assumeTrue(TestNGUtils.isEFDSupported(currentTestNGVersion)) givenQuarantinedTests(quarantined) givenDisabledTests(disabled) @@ -245,7 +243,7 @@ abstract class TestNGTest extends CiVisibilityInstrumentationTest { } def "test known tests ordering #testcaseName"() { - Assumptions.assumeTrue(isTestOrderingSupported()) + Assumptions.assumeTrue(TestNGUtils.isTestOrderingSupported(currentTestNGVersion)) givenKnownTests(knownTestsList) @@ -271,16 +269,18 @@ abstract class TestNGTest extends CiVisibilityInstrumentationTest { ] } - private static boolean isEFDSupported() { - currentTestNGVersion >= testNGv75 - } + def "test capabilities tagging #testcaseName"() { + Assumptions.assumeTrue(assumption) - private static boolean isExceptionSuppressionSupported() { - currentTestNGVersion >= testNGv75 - } + runTests([TestSucceed], null, true) - private static boolean isTestOrderingSupported() { - currentTestNGVersion >= testNGv70 + assertCapabilities(capabilities, 4) + + where: + testcaseName | capabilities | assumption + "test-capabilities-base" | TestNGUtils.capabilities("6.0") | (!TestNGUtils.isTestOrderingSupported(currentTestNGVersion) && !TestNGUtils.isEFDSupported(currentTestNGVersion) && !TestNGUtils.isExceptionSuppressionSupported(currentTestNGVersion)) + "test-capabilities-ordering" | TestNGUtils.capabilities("7.0") | (TestNGUtils.isTestOrderingSupported(currentTestNGVersion) && !TestNGUtils.isEFDSupported(currentTestNGVersion) && !TestNGUtils.isExceptionSuppressionSupported(currentTestNGVersion)) + "test-capabilities-ordering-efd-suppression" | TestNGUtils.capabilities("7.5") | (TestNGUtils.isTestOrderingSupported(currentTestNGVersion) && TestNGUtils.isEFDSupported(currentTestNGVersion) && TestNGUtils.isExceptionSuppressionSupported(currentTestNGVersion)) } protected void runTests(List testClasses, String parallelMode = null, boolean expectSuccess = true) { diff --git a/dd-java-agent/instrumentation/weaver/src/main/java/datadog/trace/instrumentation/weaver/DatadogWeaverReporter.java b/dd-java-agent/instrumentation/weaver/src/main/java/datadog/trace/instrumentation/weaver/DatadogWeaverReporter.java index 19b59a1370e..7ba5d31906e 100644 --- a/dd-java-agent/instrumentation/weaver/src/main/java/datadog/trace/instrumentation/weaver/DatadogWeaverReporter.java +++ b/dd-java-agent/instrumentation/weaver/src/main/java/datadog/trace/instrumentation/weaver/DatadogWeaverReporter.java @@ -38,7 +38,9 @@ public class DatadogWeaverReporter { public static synchronized void start() { if (TEST_EVENTS_HANDLER == null) { - TEST_EVENTS_HANDLER = InstrumentationBridge.createTestEventsHandler("weaver", null, null); + TEST_EVENTS_HANDLER = + InstrumentationBridge.createTestEventsHandler( + "weaver", null, null, WeaverUtils.CAPABILITIES); } } diff --git a/dd-java-agent/instrumentation/weaver/src/main/java/datadog/trace/instrumentation/weaver/WeaverInstrumentation.java b/dd-java-agent/instrumentation/weaver/src/main/java/datadog/trace/instrumentation/weaver/WeaverInstrumentation.java index e432561af02..013aa56cc63 100644 --- a/dd-java-agent/instrumentation/weaver/src/main/java/datadog/trace/instrumentation/weaver/WeaverInstrumentation.java +++ b/dd-java-agent/instrumentation/weaver/src/main/java/datadog/trace/instrumentation/weaver/WeaverInstrumentation.java @@ -26,9 +26,9 @@ public String instrumentedType() { @Override public String[] helperClassNames() { return new String[] { + packageName + ".WeaverUtils", packageName + ".DatadogWeaverReporter", packageName + ".TaskDefAwareQueueProxy", - packageName + ".WeaverUtils", }; } diff --git a/dd-java-agent/instrumentation/weaver/src/main/java/datadog/trace/instrumentation/weaver/WeaverUtils.java b/dd-java-agent/instrumentation/weaver/src/main/java/datadog/trace/instrumentation/weaver/WeaverUtils.java index f86e95212ae..c06b8f5c6f5 100644 --- a/dd-java-agent/instrumentation/weaver/src/main/java/datadog/trace/instrumentation/weaver/WeaverUtils.java +++ b/dd-java-agent/instrumentation/weaver/src/main/java/datadog/trace/instrumentation/weaver/WeaverUtils.java @@ -1,7 +1,10 @@ package datadog.trace.instrumentation.weaver; +import datadog.trace.api.civisibility.config.LibraryCapability; import java.io.InputStream; import java.net.URL; +import java.util.Collections; +import java.util.List; import java.util.Properties; import javax.annotation.Nullable; import org.slf4j.Logger; @@ -14,6 +17,8 @@ public abstract class WeaverUtils { private static final ClassLoader CLASS_LOADER = SbtTask.class.getClassLoader(); + public static final List CAPABILITIES = Collections.emptyList(); + private WeaverUtils() {} public static @Nullable String getWeaverVersion() { diff --git a/dd-java-agent/instrumentation/weaver/src/test/groovy/WeaverTest.groovy b/dd-java-agent/instrumentation/weaver/src/test/groovy/WeaverTest.groovy index 736df932da7..93287de01e1 100644 --- a/dd-java-agent/instrumentation/weaver/src/test/groovy/WeaverTest.groovy +++ b/dd-java-agent/instrumentation/weaver/src/test/groovy/WeaverTest.groovy @@ -34,6 +34,14 @@ class WeaverTest extends CiVisibilityInstrumentationTest { "test-succeed-global-resource" | [TestSucceedGlobalResource] } + def "test capabilities tagging"() { + setup: + runTests([TestSucceed]) + + expect: + assertCapabilities(WeaverUtils.CAPABILITIES, 4) + } + @Override String instrumentedLibraryName() { return "weaver" diff --git a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/asserts/TagsAssert.groovy b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/asserts/TagsAssert.groovy index 98bbf2da0f5..cb361270cec 100644 --- a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/asserts/TagsAssert.groovy +++ b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/asserts/TagsAssert.groovy @@ -56,6 +56,21 @@ class TagsAssert { tag(name, { it != null }) } + def arePresent(Collection tags) { + for (String name : tags) { + isPresent(name) + } + } + + def isNotPresent(String name) { + tag(name, { it == null }) + } + + def areNotPresent(Collection tags) { + for (String name : tags) { + isNotPresent(name) + } + } /** * @param distributedRootSpan set to true if current span has a parent span but still considered 'root' for current service diff --git a/dd-smoke-tests/gradle/src/test/resources/test-failed-flaky-retries/events.ftl b/dd-smoke-tests/gradle/src/test/resources/test-failed-flaky-retries/events.ftl index 9c3aee98965..80821a8a9c0 100644 --- a/dd-smoke-tests/gradle/src/test/resources/test-failed-flaky-retries/events.ftl +++ b/dd-smoke-tests/gradle/src/test/resources/test-failed-flaky-retries/events.ftl @@ -239,6 +239,13 @@ "duration" : ${content_duration_7}, "error" : 1, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "true", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_7}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -294,6 +301,13 @@ "duration" : ${content_duration_8}, "error" : 1, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "true", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_8}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -351,6 +365,13 @@ "duration" : ${content_duration_9}, "error" : 1, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "true", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_9}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -408,6 +429,13 @@ "duration" : ${content_duration_10}, "error" : 1, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "true", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_10}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -465,6 +493,13 @@ "duration" : ${content_duration_11}, "error" : 1, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "true", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_11}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-smoke-tests/gradle/src/test/resources/test-failed-legacy-instrumentation/events.ftl b/dd-smoke-tests/gradle/src/test/resources/test-failed-legacy-instrumentation/events.ftl index bd3903f8a3c..c60d70b9b19 100644 --- a/dd-smoke-tests/gradle/src/test/resources/test-failed-legacy-instrumentation/events.ftl +++ b/dd-smoke-tests/gradle/src/test/resources/test-failed-legacy-instrumentation/events.ftl @@ -187,6 +187,13 @@ "duration" : ${content_duration_6}, "error" : 1, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_6}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-smoke-tests/gradle/src/test/resources/test-failed-new-instrumentation/events.ftl b/dd-smoke-tests/gradle/src/test/resources/test-failed-new-instrumentation/events.ftl index d450b99dd00..2eff4d5848a 100644 --- a/dd-smoke-tests/gradle/src/test/resources/test-failed-new-instrumentation/events.ftl +++ b/dd-smoke-tests/gradle/src/test/resources/test-failed-new-instrumentation/events.ftl @@ -239,6 +239,13 @@ "duration" : ${content_duration_7}, "error" : 1, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_7}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/events.ftl b/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/events.ftl index 5cf1df938c7..3462c439bd2 100644 --- a/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/events.ftl +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/events.ftl @@ -233,6 +233,14 @@ "duration" : ${content_duration_7}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.fail_fast_test_order" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_7}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-5/events.ftl b/dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-5/events.ftl index efef18567e5..5807153d23d 100644 --- a/dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-5/events.ftl +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-5/events.ftl @@ -235,6 +235,14 @@ "duration" : ${content_duration_7}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.fail_fast_test_order" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_7}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -288,6 +296,14 @@ "duration" : ${content_duration_8}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.fail_fast_test_order" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_8}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-legacy-instrumentation/events.ftl b/dd-smoke-tests/gradle/src/test/resources/test-succeed-legacy-instrumentation/events.ftl index 87c1fc8b342..e67352e1531 100644 --- a/dd-smoke-tests/gradle/src/test/resources/test-succeed-legacy-instrumentation/events.ftl +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-legacy-instrumentation/events.ftl @@ -185,6 +185,13 @@ "duration" : ${content_duration_6}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_6}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -238,6 +245,13 @@ "duration" : ${content_duration_7}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_7}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-legacy-instrumentation/coverages.ftl b/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-legacy-instrumentation/coverages.ftl index 567ef02b425..2fe41431bbf 100644 --- a/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-legacy-instrumentation/coverages.ftl +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-legacy-instrumentation/coverages.ftl @@ -1,15 +1,4 @@ [ { - "files" : [ { - "bitmap" : "AAE=", - "filename" : "src/main/java/datadog/smoke/Calculator.java" - }, { - "bitmap" : "AAw=", - "filename" : "src/test/java/datadog/smoke/TestSucceedJunit5.java" - } ], - "span_id" : ${content_span_id_5}, - "test_session_id" : ${content_test_session_id}, - "test_suite_id" : ${content_test_suite_id_2} -}, { "files" : [ { "bitmap" : "gAw=", "filename" : "src/test/java/datadog/smoke/TestSucceed.java" @@ -20,4 +9,15 @@ "span_id" : ${content_span_id_4}, "test_session_id" : ${content_test_session_id}, "test_suite_id" : ${content_test_suite_id} +}, { + "files" : [ { + "bitmap" : "AAE=", + "filename" : "src/main/java/datadog/smoke/Calculator.java" + }, { + "bitmap" : "AAw=", + "filename" : "src/test/java/datadog/smoke/TestSucceedJunit5.java" + } ], + "span_id" : ${content_span_id_5}, + "test_session_id" : ${content_test_session_id}, + "test_suite_id" : ${content_test_suite_id_2} } ] \ No newline at end of file diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-legacy-instrumentation/events.ftl b/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-legacy-instrumentation/events.ftl index fb67fceb29c..3357f857988 100644 --- a/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-legacy-instrumentation/events.ftl +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-legacy-instrumentation/events.ftl @@ -184,6 +184,13 @@ "duration" : ${content_duration_6}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_6}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -285,6 +292,14 @@ "duration" : ${content_duration_8}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.fail_fast_test_order" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_8}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-new-instrumentation/events.ftl b/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-new-instrumentation/events.ftl index ab6dd435cc6..9d66aab6ad6 100644 --- a/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-new-instrumentation/events.ftl +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-new-instrumentation/events.ftl @@ -233,6 +233,13 @@ "duration" : ${content_duration_7}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_7}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -334,6 +341,14 @@ "duration" : ${content_duration_9}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.fail_fast_test_order" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_9}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-module-legacy-instrumentation/events.ftl b/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-module-legacy-instrumentation/events.ftl index c261762f157..c9d9587c30f 100644 --- a/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-module-legacy-instrumentation/events.ftl +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-module-legacy-instrumentation/events.ftl @@ -191,6 +191,13 @@ "duration" : ${content_duration_5}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_5}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -244,6 +251,13 @@ "duration" : ${content_duration_6}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_6}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-module-new-instrumentation/events.ftl b/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-module-new-instrumentation/events.ftl index 4056720810b..a8d9cb20ab2 100644 --- a/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-module-new-instrumentation/events.ftl +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-module-new-instrumentation/events.ftl @@ -240,6 +240,13 @@ "duration" : ${content_duration_6}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_6}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -293,6 +300,13 @@ "duration" : ${content_duration_7}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_7}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-new-instrumentation/events.ftl b/dd-smoke-tests/gradle/src/test/resources/test-succeed-new-instrumentation/events.ftl index 736874b5af5..460c9fe9d6c 100644 --- a/dd-smoke-tests/gradle/src/test/resources/test-succeed-new-instrumentation/events.ftl +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-new-instrumentation/events.ftl @@ -235,6 +235,13 @@ "duration" : ${content_duration_7}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_7}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -288,6 +295,13 @@ "duration" : ${content_duration_8}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_8}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-old-gradle/events.ftl b/dd-smoke-tests/gradle/src/test/resources/test-succeed-old-gradle/events.ftl index abf6bc9aacb..23d159025ef 100644 --- a/dd-smoke-tests/gradle/src/test/resources/test-succeed-old-gradle/events.ftl +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-old-gradle/events.ftl @@ -185,6 +185,13 @@ "duration" : ${content_duration_6}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_6}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -238,6 +245,13 @@ "duration" : ${content_duration_7}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "false", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_7}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-smoke-tests/maven/src/test/resources/test_failed_maven_run_flaky_retries/events.ftl b/dd-smoke-tests/maven/src/test/resources/test_failed_maven_run_flaky_retries/events.ftl index b59b5300c95..94e172a837f 100644 --- a/dd-smoke-tests/maven/src/test/resources/test_failed_maven_run_flaky_retries/events.ftl +++ b/dd-smoke-tests/maven/src/test/resources/test_failed_maven_run_flaky_retries/events.ftl @@ -305,6 +305,13 @@ "duration" : ${content_duration_9}, "error" : 1, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "true", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "false", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_9}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -360,6 +367,13 @@ "duration" : ${content_duration_10}, "error" : 1, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "true", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "false", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_10}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -417,6 +431,13 @@ "duration" : ${content_duration_11}, "error" : 1, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "true", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "false", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_11}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -474,6 +495,13 @@ "duration" : ${content_duration_12}, "error" : 1, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "true", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "false", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_12}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -531,6 +559,13 @@ "duration" : ${content_duration_13}, "error" : 1, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "true", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "false", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_13}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run/events.ftl b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run/events.ftl index a4a29faf098..c4515a48f24 100644 --- a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run/events.ftl +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run/events.ftl @@ -309,6 +309,13 @@ "duration" : ${content_duration_9}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_9}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -362,6 +369,13 @@ "duration" : ${content_duration_10}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_10}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_builtin_coverage/events.ftl b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_builtin_coverage/events.ftl index fcd2fb63f19..f2646014b9d 100644 --- a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_builtin_coverage/events.ftl +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_builtin_coverage/events.ftl @@ -273,6 +273,13 @@ "duration" : ${content_duration_8}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_8}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -326,6 +333,13 @@ "duration" : ${content_duration_9}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_9}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_impacted_tests/events.ftl b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_impacted_tests/events.ftl index fdc76099e58..7a4cb662146 100644 --- a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_impacted_tests/events.ftl +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_impacted_tests/events.ftl @@ -271,6 +271,13 @@ "duration" : ${content_duration_8}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_8}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -325,6 +332,13 @@ "duration" : ${content_duration_9}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_9}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit_platform_runner/events.ftl b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit_platform_runner/events.ftl index b1d40342764..a4006651801 100644 --- a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit_platform_runner/events.ftl +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit_platform_runner/events.ftl @@ -326,6 +326,13 @@ "duration" : ${content_duration_10}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "false", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_10}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_multiple_forks/events.ftl b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_multiple_forks/events.ftl index 8ac978d4f71..67ef45ed060 100644 --- a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_multiple_forks/events.ftl +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_multiple_forks/events.ftl @@ -309,6 +309,14 @@ "duration" : ${content_duration_9}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.fail_fast_test_order" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_9}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -362,6 +370,14 @@ "duration" : ${content_duration_10}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.fail_fast_test_order" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_10}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_surefire_3_0_0/events.ftl b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_surefire_3_0_0/events.ftl index a4a29faf098..c4515a48f24 100644 --- a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_surefire_3_0_0/events.ftl +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_surefire_3_0_0/events.ftl @@ -309,6 +309,13 @@ "duration" : ${content_duration_9}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_9}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -362,6 +369,13 @@ "duration" : ${content_duration_10}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_10}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_surefire_3_5_0/events.ftl b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_surefire_3_5_0/events.ftl index a4a29faf098..c4515a48f24 100644 --- a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_surefire_3_5_0/events.ftl +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_surefire_3_5_0/events.ftl @@ -309,6 +309,13 @@ "duration" : ${content_duration_9}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_9}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -362,6 +369,13 @@ "duration" : ${content_duration_10}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_10}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_test_management/events.ftl b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_test_management/events.ftl index 20a78c831d7..42cd14dc56e 100644 --- a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_test_management/events.ftl +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_test_management/events.ftl @@ -273,6 +273,13 @@ "duration" : ${content_duration_8}, "error" : 1, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "true", + "_dd.library_capabilities.test_management.disable" : "true", + "_dd.library_capabilities.test_management.quarantine" : "true", "_dd.p.tid" : ${content_meta__dd_p_tid_8}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -330,6 +337,13 @@ "duration" : ${content_duration_9}, "error" : 1, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "true", + "_dd.library_capabilities.test_management.disable" : "true", + "_dd.library_capabilities.test_management.quarantine" : "true", "_dd.p.tid" : ${content_meta__dd_p_tid_9}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -389,6 +403,13 @@ "duration" : ${content_duration_10}, "error" : 1, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "true", + "_dd.library_capabilities.test_management.disable" : "true", + "_dd.library_capabilities.test_management.quarantine" : "true", "_dd.p.tid" : ${content_meta__dd_p_tid_10}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -448,6 +469,13 @@ "duration" : ${content_duration_11}, "error" : 1, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "true", + "_dd.library_capabilities.test_management.disable" : "true", + "_dd.library_capabilities.test_management.quarantine" : "true", "_dd.p.tid" : ${content_meta__dd_p_tid_11}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -507,6 +535,13 @@ "duration" : ${content_duration_12}, "error" : 1, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "true", + "_dd.library_capabilities.test_management.disable" : "true", + "_dd.library_capabilities.test_management.quarantine" : "true", "_dd.p.tid" : ${content_meta__dd_p_tid_12}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -567,6 +602,13 @@ "duration" : ${content_duration_13}, "error" : 1, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "true", + "_dd.library_capabilities.test_management.disable" : "true", + "_dd.library_capabilities.test_management.quarantine" : "true", "_dd.p.tid" : ${content_meta__dd_p_tid_13}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -671,6 +713,13 @@ "duration" : ${content_duration_15}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "true", + "_dd.library_capabilities.test_management.disable" : "true", + "_dd.library_capabilities.test_management.quarantine" : "true", "_dd.p.tid" : ${content_meta__dd_p_tid_15}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_with_arg_line_property/events.ftl b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_with_arg_line_property/events.ftl index bcfa36fb89b..3b1e2230da5 100644 --- a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_with_arg_line_property/events.ftl +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_with_arg_line_property/events.ftl @@ -265,6 +265,13 @@ "duration" : ${content_duration_8}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "false", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_8}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_with_cucumber/events.ftl b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_with_cucumber/events.ftl index 1bda6c6aa80..bc6b96c9fe9 100644 --- a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_with_cucumber/events.ftl +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_with_cucumber/events.ftl @@ -363,6 +363,12 @@ "duration" : ${content_duration_11}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.test_impact_analysis" : "false", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_11}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_with_jacoco_and_argline/events.ftl b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_with_jacoco_and_argline/events.ftl index 8507b84386a..521e50ac686 100644 --- a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_with_jacoco_and_argline/events.ftl +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_with_jacoco_and_argline/events.ftl @@ -309,6 +309,13 @@ "duration" : ${content_duration_9}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_9}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, @@ -362,6 +369,13 @@ "duration" : ${content_duration_10}, "error" : 0, "meta" : { + "_dd.library_capabilities.auto_test_retries" : "false", + "_dd.library_capabilities.early_flake_detection" : "false", + "_dd.library_capabilities.impacted_tests" : "true", + "_dd.library_capabilities.test_impact_analysis" : "true", + "_dd.library_capabilities.test_management.attempt_to_fix" : "false", + "_dd.library_capabilities.test_management.disable" : "false", + "_dd.library_capabilities.test_management.quarantine" : "false", "_dd.p.tid" : ${content_meta__dd_p_tid_10}, "_dd.test.is_user_provided_service" : "true", "_dd.tracer_host" : ${content_meta__dd_tracer_host}, diff --git a/dd-trace-api/src/main/java/datadog/trace/api/DDTags.java b/dd-trace-api/src/main/java/datadog/trace/api/DDTags.java index 4f4ae6813c3..11bb60129fb 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/DDTags.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/DDTags.java @@ -37,6 +37,7 @@ public class DDTags { /** Manually force tracer to keep the trace */ public static final String MANUAL_KEEP = "manual.keep"; + /** Manually force tracer to drop the trace */ public static final String MANUAL_DROP = "manual.drop"; diff --git a/internal-api/build.gradle b/internal-api/build.gradle index 5dbe7d16de6..f9eef196cf6 100644 --- a/internal-api/build.gradle +++ b/internal-api/build.gradle @@ -107,6 +107,7 @@ excludedClassesCoverage += [ "datadog.trace.api.civisibility.config.TestFQN", "datadog.trace.api.civisibility.config.TestMetadata", "datadog.trace.api.civisibility.config.TestSourceData", + "datadog.trace.api.civisibility.config.LibraryCapability", "datadog.trace.api.civisibility.coverage.CoveragePerTestBridge", "datadog.trace.api.civisibility.coverage.CoveragePercentageBridge", "datadog.trace.api.civisibility.coverage.NoOpCoverageStore", @@ -166,6 +167,12 @@ excludedClassesCoverage += [ "datadog.trace.util.ClassNameTrie.Builder", "datadog.trace.util.ClassNameTrie.JavaGenerator", "datadog.trace.util.CollectionUtils", + "datadog.trace.util.ComparableVersion", + "datadog.trace.util.ComparableVersion.BigIntegerItem", + "datadog.trace.util.ComparableVersion.IntItem", + "datadog.trace.util.ComparableVersion.ListItem", + "datadog.trace.util.ComparableVersion.LongItem", + "datadog.trace.util.ComparableVersion.StringItem", "datadog.trace.util.ConcurrentEnumMap", "datadog.trace.util.MethodHandles", "datadog.trace.util.PidHelper", diff --git a/internal-api/src/main/java/datadog/trace/api/civisibility/InstrumentationBridge.java b/internal-api/src/main/java/datadog/trace/api/civisibility/InstrumentationBridge.java index 3fa85c6c39f..ee3b1d51e19 100644 --- a/internal-api/src/main/java/datadog/trace/api/civisibility/InstrumentationBridge.java +++ b/internal-api/src/main/java/datadog/trace/api/civisibility/InstrumentationBridge.java @@ -1,10 +1,12 @@ package datadog.trace.api.civisibility; +import datadog.trace.api.civisibility.config.LibraryCapability; import datadog.trace.api.civisibility.events.BuildEventsHandler; import datadog.trace.api.civisibility.events.TestEventsHandler; import datadog.trace.api.civisibility.telemetry.CiVisibilityMetricCollector; import datadog.trace.api.civisibility.telemetry.NoOpMetricCollector; import datadog.trace.bootstrap.ContextStore; +import java.util.Collection; public abstract class InstrumentationBridge { @@ -21,8 +23,9 @@ public static void registerTestEventsHandlerFactory( public static TestEventsHandler createTestEventsHandler( String component, ContextStore suiteStore, - ContextStore testStore) { - return TEST_EVENTS_HANDLER_FACTORY.create(component, suiteStore, testStore); + ContextStore testStore, + Collection capabilities) { + return TEST_EVENTS_HANDLER_FACTORY.create(component, suiteStore, testStore, capabilities); } public static void registerBuildEventsHandlerFactory( diff --git a/internal-api/src/main/java/datadog/trace/api/civisibility/config/LibraryCapability.java b/internal-api/src/main/java/datadog/trace/api/civisibility/config/LibraryCapability.java new file mode 100644 index 00000000000..7e3980fc51f --- /dev/null +++ b/internal-api/src/main/java/datadog/trace/api/civisibility/config/LibraryCapability.java @@ -0,0 +1,22 @@ +package datadog.trace.api.civisibility.config; + +public enum LibraryCapability { + TIA("test_impact_analysis"), + EFD("early_flake_detection"), + ATR("auto_test_retries"), + IMPACTED("impacted_tests"), + FAIL_FAST("fail_fast_test_order"), + QUARANTINE("test_management.quarantine"), + DISABLED("test_management.disable"), + ATTEMPT_TO_FIX("test_management.attempt_to_fix"); + + private final String tag; + + LibraryCapability(String tag) { + this.tag = tag; + } + + public String asTag() { + return "_dd.library_capabilities." + tag; + } +} diff --git a/internal-api/src/main/java/datadog/trace/api/civisibility/events/TestEventsHandler.java b/internal-api/src/main/java/datadog/trace/api/civisibility/events/TestEventsHandler.java index 9295fe0b3a0..65b4dd15abf 100644 --- a/internal-api/src/main/java/datadog/trace/api/civisibility/events/TestEventsHandler.java +++ b/internal-api/src/main/java/datadog/trace/api/civisibility/events/TestEventsHandler.java @@ -2,6 +2,7 @@ import datadog.trace.api.civisibility.DDTest; import datadog.trace.api.civisibility.DDTestSuite; +import datadog.trace.api.civisibility.config.LibraryCapability; import datadog.trace.api.civisibility.config.TestIdentifier; import datadog.trace.api.civisibility.config.TestSourceData; import datadog.trace.api.civisibility.execution.TestExecutionHistory; @@ -117,6 +118,7 @@ interface Factory { TestEventsHandler create( String component, @Nullable ContextStore suiteStore, - @Nullable ContextStore testStore); + @Nullable ContextStore testStore, + Collection capabilities); } } diff --git a/internal-api/src/main/java/datadog/trace/util/ComparableVersion.java b/internal-api/src/main/java/datadog/trace/util/ComparableVersion.java new file mode 100644 index 00000000000..147607c71f0 --- /dev/null +++ b/internal-api/src/main/java/datadog/trace/util/ComparableVersion.java @@ -0,0 +1,523 @@ +package datadog.trace.util; + +import java.math.BigInteger; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Deque; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Properties; + +// backported from org.apache.maven:maven-artifact:3.9.9 +public class ComparableVersion implements Comparable { + private static final int MAX_INTITEM_LENGTH = 9; + private static final int MAX_LONGITEM_LENGTH = 18; + private String value; + private String canonical; + private ListItem items; + + public ComparableVersion(String version) { + this.parseVersion(version); + } + + public final void parseVersion(String version) { + this.value = version; + this.items = new ListItem(); + version = version.toLowerCase(Locale.ENGLISH); + ListItem list = this.items; + Deque stack = new ArrayDeque(); + stack.push(list); + boolean isDigit = false; + int startIndex = 0; + + for (int i = 0; i < version.length(); ++i) { + char c = version.charAt(i); + if (c == '.') { + if (i == startIndex) { + list.add(ComparableVersion.IntItem.ZERO); + } else { + list.add(parseItem(isDigit, version.substring(startIndex, i))); + } + + startIndex = i + 1; + } else if (c == '-') { + if (i == startIndex) { + list.add(ComparableVersion.IntItem.ZERO); + } else { + list.add(parseItem(isDigit, version.substring(startIndex, i))); + } + + startIndex = i + 1; + list.add(list = new ListItem()); + stack.push(list); + } else if (Character.isDigit(c)) { + if (!isDigit && i > startIndex) { + if (!list.isEmpty()) { + list.add(list = new ListItem()); + stack.push(list); + } + + list.add(new StringItem(version.substring(startIndex, i), true)); + startIndex = i; + list.add(list = new ListItem()); + stack.push(list); + } + + isDigit = true; + } else { + if (isDigit && i > startIndex) { + list.add(parseItem(true, version.substring(startIndex, i))); + startIndex = i; + list.add(list = new ListItem()); + stack.push(list); + } + + isDigit = false; + } + } + + if (version.length() > startIndex) { + if (!isDigit && !list.isEmpty()) { + list.add(list = new ListItem()); + stack.push(list); + } + + list.add(parseItem(isDigit, version.substring(startIndex))); + } + + while (!stack.isEmpty()) { + list = (ListItem) stack.pop(); + list.normalize(); + } + } + + private static Item parseItem(boolean isDigit, String buf) { + if (isDigit) { + buf = stripLeadingZeroes(buf); + if (buf.length() <= 9) { + return new IntItem(buf); + } else { + return buf.length() <= 18 ? new LongItem(buf) : new BigIntegerItem(buf); + } + } else { + return new StringItem(buf, false); + } + } + + private static String stripLeadingZeroes(String buf) { + if (buf != null && !buf.isEmpty()) { + for (int i = 0; i < buf.length(); ++i) { + char c = buf.charAt(i); + if (c != '0') { + return buf.substring(i); + } + } + + return buf; + } else { + return "0"; + } + } + + public int compareTo(ComparableVersion o) { + return this.items.compareTo(o.items); + } + + public String toString() { + return this.value; + } + + public String getCanonical() { + if (this.canonical == null) { + this.canonical = this.items.toString(); + } + + return this.canonical; + } + + public boolean equals(Object o) { + return o instanceof ComparableVersion && this.items.equals(((ComparableVersion) o).items); + } + + public int hashCode() { + return this.items.hashCode(); + } + + private static class IntItem implements Item { + private final int value; + public static final IntItem ZERO = new IntItem(); + + private IntItem() { + this.value = 0; + } + + IntItem(String str) { + this.value = Integer.parseInt(str); + } + + public int getType() { + return 3; + } + + public boolean isNull() { + return this.value == 0; + } + + public int compareTo(Item item) { + if (item == null) { + return this.value == 0 ? 0 : 1; + } else { + switch (item.getType()) { + case 0: + case 4: + return -1; + case 1: + return 1; + case 2: + return 1; + case 3: + int itemValue = ((IntItem) item).value; + return this.value < itemValue ? -1 : (this.value == itemValue ? 0 : 1); + default: + throw new IllegalStateException("invalid item: " + item.getClass()); + } + } + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } else if (o != null && this.getClass() == o.getClass()) { + IntItem intItem = (IntItem) o; + return this.value == intItem.value; + } else { + return false; + } + } + + public int hashCode() { + return this.value; + } + + public String toString() { + return Integer.toString(this.value); + } + } + + private static class LongItem implements Item { + private final long value; + + LongItem(String str) { + this.value = Long.parseLong(str); + } + + public int getType() { + return 4; + } + + public boolean isNull() { + return this.value == 0L; + } + + public int compareTo(Item item) { + if (item == null) { + return this.value == 0L ? 0 : 1; + } else { + switch (item.getType()) { + case 0: + return -1; + case 1: + return 1; + case 2: + return 1; + case 3: + return 1; + case 4: + long itemValue = ((LongItem) item).value; + return this.value < itemValue ? -1 : (this.value == itemValue ? 0 : 1); + default: + throw new IllegalStateException("invalid item: " + item.getClass()); + } + } + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } else if (o != null && this.getClass() == o.getClass()) { + LongItem longItem = (LongItem) o; + return this.value == longItem.value; + } else { + return false; + } + } + + public int hashCode() { + return (int) (this.value ^ this.value >>> 32); + } + + public String toString() { + return Long.toString(this.value); + } + } + + private static class BigIntegerItem implements Item { + private final BigInteger value; + + BigIntegerItem(String str) { + this.value = new BigInteger(str); + } + + public int getType() { + return 0; + } + + public boolean isNull() { + return BigInteger.ZERO.equals(this.value); + } + + public int compareTo(Item item) { + if (item == null) { + return BigInteger.ZERO.equals(this.value) ? 0 : 1; + } else { + switch (item.getType()) { + case 0: + return this.value.compareTo(((BigIntegerItem) item).value); + case 1: + return 1; + case 2: + return 1; + case 3: + case 4: + return 1; + default: + throw new IllegalStateException("invalid item: " + item.getClass()); + } + } + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } else if (o != null && this.getClass() == o.getClass()) { + BigIntegerItem that = (BigIntegerItem) o; + return this.value.equals(that.value); + } else { + return false; + } + } + + public int hashCode() { + return this.value.hashCode(); + } + + public String toString() { + return this.value.toString(); + } + } + + private static class StringItem implements Item { + private static final List QUALIFIERS = + Arrays.asList("alpha", "beta", "milestone", "rc", "snapshot", "", "sp"); + private static final Properties ALIASES = new Properties(); + private static final String RELEASE_VERSION_INDEX; + private final String value; + + StringItem(String value, boolean followedByDigit) { + if (followedByDigit && value.length() == 1) { + switch (value.charAt(0)) { + case 'a': + value = "alpha"; + break; + case 'b': + value = "beta"; + break; + case 'm': + value = "milestone"; + break; + default: + break; + } + } + + this.value = ALIASES.getProperty(value, value); + } + + public int getType() { + return 1; + } + + public boolean isNull() { + return comparableQualifier(this.value).compareTo(RELEASE_VERSION_INDEX) == 0; + } + + public static String comparableQualifier(String qualifier) { + int i = QUALIFIERS.indexOf(qualifier); + return i == -1 ? QUALIFIERS.size() + "-" + qualifier : String.valueOf(i); + } + + public int compareTo(Item item) { + if (item == null) { + return comparableQualifier(this.value).compareTo(RELEASE_VERSION_INDEX); + } else { + switch (item.getType()) { + case 0: + case 3: + case 4: + return -1; + case 1: + return comparableQualifier(this.value) + .compareTo(comparableQualifier(((StringItem) item).value)); + case 2: + return -1; + default: + throw new IllegalStateException("invalid item: " + item.getClass()); + } + } + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } else if (o != null && this.getClass() == o.getClass()) { + StringItem that = (StringItem) o; + return this.value.equals(that.value); + } else { + return false; + } + } + + public int hashCode() { + return this.value.hashCode(); + } + + public String toString() { + return this.value; + } + + static { + ALIASES.put("ga", ""); + ALIASES.put("final", ""); + ALIASES.put("release", ""); + ALIASES.put("cr", "rc"); + RELEASE_VERSION_INDEX = String.valueOf(QUALIFIERS.indexOf("")); + } + } + + private static class ListItem extends ArrayList implements Item { + private ListItem() { + super(); + } + + public int getType() { + return 2; + } + + public boolean isNull() { + return this.size() == 0; + } + + void normalize() { + for (int i = this.size() - 1; i >= 0; --i) { + Item lastItem = this.get(i); + if (lastItem.isNull()) { + this.remove(i); + } else if (!(lastItem instanceof ListItem)) { + break; + } + } + } + + public int compareTo(Item item) { + if (item == null) { + if (this.size() == 0) { + return 0; + } else { + for (Item i : this) { + int result = i.compareTo(null); + if (result != 0) { + return result; + } + } + + return 0; + } + } else { + switch (item.getType()) { + case 0: + case 3: + case 4: + return -1; + case 1: + return 1; + case 2: + Iterator left = this.iterator(); + Iterator right = ((ListItem) item).iterator(); + + while (left.hasNext() || right.hasNext()) { + Item l = left.hasNext() ? left.next() : null; + Item r = right.hasNext() ? right.next() : null; + int result = l == null ? (r == null ? 0 : -1 * r.compareTo(l)) : l.compareTo(r); + if (result != 0) { + return result; + } + } + + return 0; + default: + throw new IllegalStateException("invalid item: " + item.getClass()); + } + } + } + + public String toString() { + StringBuilder buffer = new StringBuilder(); + + for (Item item : this) { + if (buffer.length() > 0) { + buffer.append(item instanceof ListItem ? '-' : '.'); + } + + buffer.append(item); + } + + return buffer.toString(); + } + + private String toListString() { + StringBuilder buffer = new StringBuilder(); + buffer.append('['); + + for (Item item : this) { + if (buffer.length() > 1) { + buffer.append(", "); + } + + if (item instanceof ListItem) { + buffer.append(((ListItem) item).toListString()); + } else { + buffer.append(item); + } + } + + buffer.append(']'); + return buffer.toString(); + } + } + + private interface Item { + int INT_ITEM = 3; + int LONG_ITEM = 4; + int BIGINTEGER_ITEM = 0; + int STRING_ITEM = 1; + int LIST_ITEM = 2; + + int compareTo(Item var1); + + int getType(); + + boolean isNull(); + } +}