diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ef437eebae2..62520f362fe 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -87,6 +87,7 @@ /dd-java-agent/instrumentation/maven-surefire/ @DataDog/ci-app-libraries-java /dd-java-agent/instrumentation/weaver/ @DataDog/ci-app-libraries-java /dd-smoke-tests/gradle/ @DataDog/ci-app-libraries-java +/dd-smoke-tests/junit-console/ @DataDog/ci-app-libraries-java /dd-smoke-tests/maven/ @DataDog/ci-app-libraries-java /internal-api/src/main/java/datadog/trace/api/git/ @DataDog/ci-app-libraries-java **/civisibility/ @DataDog/ci-app-libraries-java diff --git a/communication/src/main/java/datadog/communication/BackendApiFactory.java b/communication/src/main/java/datadog/communication/BackendApiFactory.java index f3382792baa..5cea26600de 100644 --- a/communication/src/main/java/datadog/communication/BackendApiFactory.java +++ b/communication/src/main/java/datadog/communication/BackendApiFactory.java @@ -5,8 +5,8 @@ import datadog.communication.http.HttpRetryPolicy; import datadog.communication.http.OkHttpUtils; import datadog.trace.api.Config; +import datadog.trace.api.intake.Intake; import datadog.trace.util.throwable.FatalAgentMisconfigurationError; -import java.util.function.Function; import javax.annotation.Nullable; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; @@ -28,8 +28,8 @@ public BackendApiFactory(Config config, SharedCommunicationObjects sharedCommuni public @Nullable BackendApi createBackendApi(Intake intake) { HttpRetryPolicy.Factory retryPolicyFactory = new HttpRetryPolicy.Factory(5, 100, 2.0, true); - if (intake.agentlessModeEnabled.apply(config)) { - HttpUrl agentlessUrl = getAgentlessUrl(intake); + if (intake.isAgentlessEnabled(config)) { + HttpUrl agentlessUrl = HttpUrl.get(intake.getAgentlessUrl(config)); String apiKey = config.getApiKey(); if (apiKey == null || apiKey.isEmpty()) { throw new FatalAgentMisconfigurationError( @@ -58,41 +58,4 @@ public BackendApiFactory(Config config, SharedCommunicationObjects sharedCommuni + "and agent does not support EVP proxy"); return null; } - - private HttpUrl getAgentlessUrl(Intake intake) { - String customUrl = intake.customUrl.apply(config); - if (customUrl != null && !customUrl.isEmpty()) { - return HttpUrl.get(String.format("%s/api/%s/", customUrl, intake.version)); - } else { - String site = config.getSite(); - return HttpUrl.get( - String.format("https://%s.%s/api/%s/", intake.urlPrefix, site, intake.version)); - } - } - - public enum Intake { - API("api", "v2", Config::isCiVisibilityAgentlessEnabled, Config::getCiVisibilityAgentlessUrl), - LLMOBS_API("api", "v2", Config::isLlmObsAgentlessEnabled, Config::getLlMObsAgentlessUrl), - LOGS( - "http-intake.logs", - "v2", - Config::isAgentlessLogSubmissionEnabled, - Config::getAgentlessLogSubmissionUrl); - - public final String urlPrefix; - public final String version; - public final Function agentlessModeEnabled; - public final Function customUrl; - - Intake( - String urlPrefix, - String version, - Function agentlessModeEnabled, - Function customUrl) { - this.urlPrefix = urlPrefix; - this.version = version; - this.agentlessModeEnabled = agentlessModeEnabled; - this.customUrl = customUrl; - } - } } diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java index d8f09c75089..97b72054861 100644 --- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java @@ -632,6 +632,7 @@ public void execute() { } maybeStartAppSec(scoClass, sco); + // start civisibility before debugger to enable Failed Test Replay correctly in headless mode maybeStartCiVisibility(instrumentation, scoClass, sco); maybeStartLLMObs(instrumentation, scoClass, sco); // start debugger before remote config to subscribe to it before starting to poll @@ -1308,10 +1309,6 @@ && isExplicitlyDisabled(TraceInstrumentationConfig.CODE_ORIGIN_FOR_SPANS_ENABLED && isExplicitlyDisabled(DebuggerConfig.DISTRIBUTED_DEBUGGER_ENABLED)) { return; } - if (!remoteConfigEnabled) { - log.warn("Cannot enable Dynamic Instrumentation because Remote Configuration is not enabled"); - return; - } startDebuggerAgent(inst, scoClass, sco); } diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/CiVisibilityServices.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/CiVisibilityServices.java index 2cd94ba8799..095215cf44e 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/CiVisibilityServices.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/CiVisibilityServices.java @@ -14,6 +14,7 @@ import datadog.trace.api.civisibility.telemetry.CiVisibilityMetricCollector; import datadog.trace.api.civisibility.telemetry.tag.Command; import datadog.trace.api.git.GitInfoProvider; +import datadog.trace.api.intake.Intake; import datadog.trace.civisibility.ci.CIProviderInfoFactory; import datadog.trace.civisibility.ci.env.CiEnvironment; import datadog.trace.civisibility.ci.env.CiEnvironmentImpl; @@ -83,8 +84,7 @@ public class CiVisibilityServices { this.processHierarchy = new ProcessHierarchy(); this.config = config; this.metricCollector = metricCollector; - this.backendApi = - new BackendApiFactory(config, sco).createBackendApi(BackendApiFactory.Intake.API); + this.backendApi = new BackendApiFactory(config, sco).createBackendApi(Intake.API); this.jvmInfoFactory = new CachingJvmInfoFactory(config, new JvmInfoFactoryImpl()); this.gitClientFactory = buildGitClientFactory(config, metricCollector); 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 575e9a38442..85b6e96b526 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 @@ -101,6 +101,11 @@ public static void start(Instrumentation inst, SharedCommunicationObjects sco) { inst.addTransformer(new CoverageClassTransformer(instrumentationFilter)); } + if (executionSettings.isFailedTestReplayEnabled()) { + // only marks the feature as active in child or headless processes + config.setCiVisibilityFailedTestReplayActive(true); + } + CiVisibilityCoverageServices.Child coverageServices = new CiVisibilityCoverageServices.Child(services, repoServices, executionSettings); TestEventsHandlerFactory testEventsHandlerFactory = diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/CiVisibilitySettings.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/CiVisibilitySettings.java index bdce3fb02b8..13e254496ca 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/CiVisibilitySettings.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/CiVisibilitySettings.java @@ -17,6 +17,7 @@ public class CiVisibilitySettings { false, false, false, + false, EarlyFlakeDetectionSettings.DEFAULT, TestManagementSettings.DEFAULT, null); @@ -28,6 +29,7 @@ public class CiVisibilitySettings { private final boolean flakyTestRetriesEnabled; private final boolean impactedTestsDetectionEnabled; private final boolean knownTestsEnabled; + private final boolean failedTestReplayEnabled; private final EarlyFlakeDetectionSettings earlyFlakeDetectionSettings; private final TestManagementSettings testManagementSettings; @Nullable private final String defaultBranch; @@ -40,6 +42,7 @@ public class CiVisibilitySettings { boolean flakyTestRetriesEnabled, boolean impactedTestsDetectionEnabled, boolean knownTestsEnabled, + boolean failedTestReplayEnabled, EarlyFlakeDetectionSettings earlyFlakeDetectionSettings, TestManagementSettings testManagementSettings, @Nullable String defaultBranch) { @@ -50,6 +53,7 @@ public class CiVisibilitySettings { this.flakyTestRetriesEnabled = flakyTestRetriesEnabled; this.impactedTestsDetectionEnabled = impactedTestsDetectionEnabled; this.knownTestsEnabled = knownTestsEnabled; + this.failedTestReplayEnabled = failedTestReplayEnabled; this.earlyFlakeDetectionSettings = earlyFlakeDetectionSettings; this.testManagementSettings = testManagementSettings; this.defaultBranch = defaultBranch; @@ -83,6 +87,10 @@ public boolean isKnownTestsEnabled() { return knownTestsEnabled; } + public boolean isFailedTestReplayEnabled() { + return failedTestReplayEnabled; + } + public EarlyFlakeDetectionSettings getEarlyFlakeDetectionSettings() { return earlyFlakeDetectionSettings; } @@ -112,6 +120,7 @@ public boolean equals(Object o) { && flakyTestRetriesEnabled == that.flakyTestRetriesEnabled && impactedTestsDetectionEnabled == that.impactedTestsDetectionEnabled && knownTestsEnabled == that.knownTestsEnabled + && failedTestReplayEnabled == that.failedTestReplayEnabled && Objects.equals(earlyFlakeDetectionSettings, that.earlyFlakeDetectionSettings) && Objects.equals(testManagementSettings, that.testManagementSettings) && Objects.equals(defaultBranch, that.defaultBranch); @@ -127,6 +136,7 @@ public int hashCode() { flakyTestRetriesEnabled, impactedTestsDetectionEnabled, knownTestsEnabled, + failedTestReplayEnabled, earlyFlakeDetectionSettings, testManagementSettings, defaultBranch); @@ -154,6 +164,7 @@ public CiVisibilitySettings fromJson(Map json) { getBoolean(json, "flaky_test_retries_enabled", false), getBoolean(json, "impacted_tests_enabled", false), getBoolean(json, "known_tests_enabled", false), + getBoolean(json, "di_enabled", false), EarlyFlakeDetectionSettings.JsonAdapter.INSTANCE.fromJson( (Map) json.get("early_flake_detection")), TestManagementSettings.JsonAdapter.INSTANCE.fromJson( diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ConfigurationApiImpl.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ConfigurationApiImpl.java index 9d94ed10cc0..d3bc8345e0b 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ConfigurationApiImpl.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ConfigurationApiImpl.java @@ -17,6 +17,7 @@ import datadog.trace.api.civisibility.telemetry.CiVisibilityMetricCollector; import datadog.trace.api.civisibility.telemetry.tag.CoverageEnabled; import datadog.trace.api.civisibility.telemetry.tag.EarlyFlakeDetectionEnabled; +import datadog.trace.api.civisibility.telemetry.tag.FailedTestReplayEnabled; import datadog.trace.api.civisibility.telemetry.tag.FlakyTestRetriesEnabled; import datadog.trace.api.civisibility.telemetry.tag.ImpactedTestsDetectionEnabled; import datadog.trace.api.civisibility.telemetry.tag.ItrEnabled; @@ -156,6 +157,7 @@ public CiVisibilitySettings getSettings(TracerEnvironment tracerEnvironment) thr settings.isKnownTestsEnabled() ? KnownTestsEnabled.TRUE : null, settings.isImpactedTestsDetectionEnabled() ? ImpactedTestsDetectionEnabled.TRUE : null, settings.getTestManagementSettings().isEnabled() ? TestManagementEnabled.TRUE : null, + settings.isFailedTestReplayEnabled() ? FailedTestReplayEnabled.SettingsMetric.TRUE : null, settings.isGitUploadRequired() ? RequireGit.TRUE : null); return settings; 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..c20ce5d15db 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 @@ -26,6 +26,7 @@ public class ExecutionSettings { false, false, false, + false, EarlyFlakeDetectionSettings.DEFAULT, TestManagementSettings.DEFAULT, null, @@ -43,6 +44,7 @@ public class ExecutionSettings { private final boolean testSkippingEnabled; private final boolean flakyTestRetriesEnabled; private final boolean impactedTestsDetectionEnabled; + private final boolean failedTestReplayEnabled; @Nonnull private final EarlyFlakeDetectionSettings earlyFlakeDetectionSettings; @Nonnull private final TestManagementSettings testManagementSettings; @Nullable private final String itrCorrelationId; @@ -58,6 +60,7 @@ public ExecutionSettings( boolean testSkippingEnabled, boolean flakyTestRetriesEnabled, boolean impactedTestsDetectionEnabled, + boolean failedTestReplayEnabled, @Nonnull EarlyFlakeDetectionSettings earlyFlakeDetectionSettings, @Nonnull TestManagementSettings testManagementSettings, @Nullable String itrCorrelationId, @@ -74,6 +77,7 @@ public ExecutionSettings( this.testSkippingEnabled = testSkippingEnabled; this.flakyTestRetriesEnabled = flakyTestRetriesEnabled; this.impactedTestsDetectionEnabled = impactedTestsDetectionEnabled; + this.failedTestReplayEnabled = failedTestReplayEnabled; this.earlyFlakeDetectionSettings = earlyFlakeDetectionSettings; this.testManagementSettings = testManagementSettings; this.itrCorrelationId = itrCorrelationId; @@ -110,6 +114,7 @@ private ExecutionSettings( boolean testSkippingEnabled, boolean flakyTestRetriesEnabled, boolean impactedTestsDetectionEnabled, + boolean failedTestReplayEnabled, @Nonnull EarlyFlakeDetectionSettings earlyFlakeDetectionSettings, @Nonnull TestManagementSettings testManagementSettings, @Nullable String itrCorrelationId, @@ -123,6 +128,7 @@ private ExecutionSettings( this.testSkippingEnabled = testSkippingEnabled; this.flakyTestRetriesEnabled = flakyTestRetriesEnabled; this.impactedTestsDetectionEnabled = impactedTestsDetectionEnabled; + this.failedTestReplayEnabled = failedTestReplayEnabled; this.earlyFlakeDetectionSettings = earlyFlakeDetectionSettings; this.testManagementSettings = testManagementSettings; this.itrCorrelationId = itrCorrelationId; @@ -157,6 +163,10 @@ public boolean isImpactedTestsDetectionEnabled() { return impactedTestsDetectionEnabled; } + public boolean isFailedTestReplayEnabled() { + return failedTestReplayEnabled; + } + @Nonnull public EarlyFlakeDetectionSettings getEarlyFlakeDetectionSettings() { return earlyFlakeDetectionSettings; @@ -243,6 +253,7 @@ public boolean equals(Object o) { && testSkippingEnabled == that.testSkippingEnabled && flakyTestRetriesEnabled == that.flakyTestRetriesEnabled && impactedTestsDetectionEnabled == that.impactedTestsDetectionEnabled + && failedTestReplayEnabled == that.failedTestReplayEnabled && Objects.equals(earlyFlakeDetectionSettings, that.earlyFlakeDetectionSettings) && Objects.equals(testManagementSettings, that.testManagementSettings) && Objects.equals(itrCorrelationId, that.itrCorrelationId) @@ -261,6 +272,7 @@ public int hashCode() { testSkippingEnabled, flakyTestRetriesEnabled, impactedTestsDetectionEnabled, + failedTestReplayEnabled, earlyFlakeDetectionSettings, testManagementSettings, itrCorrelationId, @@ -278,6 +290,7 @@ public static class Serializer { private static final int TEST_SKIPPING_ENABLED_FLAG = 4; private static final int FLAKY_TEST_RETRIES_ENABLED_FLAG = 8; private static final int IMPACTED_TESTS_DETECTION_ENABLED_FLAG = 16; + private static final int FAILED_TEST_REPLAY_ENABLED_FLAG = 32; public static ByteBuffer serialize(ExecutionSettings settings) { datadog.trace.civisibility.ipc.serialization.Serializer s = @@ -291,7 +304,8 @@ public static ByteBuffer serialize(ExecutionSettings settings) { | (settings.flakyTestRetriesEnabled ? FLAKY_TEST_RETRIES_ENABLED_FLAG : 0) | (settings.impactedTestsDetectionEnabled ? IMPACTED_TESTS_DETECTION_ENABLED_FLAG - : 0)); + : 0) + | (settings.failedTestReplayEnabled ? FAILED_TEST_REPLAY_ENABLED_FLAG : 0)); s.write(flags); EarlyFlakeDetectionSettings.Serializer.serialize(s, settings.earlyFlakeDetectionSettings); @@ -330,6 +344,7 @@ public static ExecutionSettings deserialize(ByteBuffer buffer) { boolean testSkippingEnabled = (flags & TEST_SKIPPING_ENABLED_FLAG) != 0; boolean flakyTestRetriesEnabled = (flags & FLAKY_TEST_RETRIES_ENABLED_FLAG) != 0; boolean impactedTestsDetectionEnabled = (flags & IMPACTED_TESTS_DETECTION_ENABLED_FLAG) != 0; + boolean failedTestReplayEnabled = (flags & FAILED_TEST_REPLAY_ENABLED_FLAG) != 0; EarlyFlakeDetectionSettings earlyFlakeDetectionSettings = EarlyFlakeDetectionSettings.Serializer.deserialize(buffer); @@ -372,6 +387,7 @@ public static ExecutionSettings deserialize(ByteBuffer buffer) { testSkippingEnabled, flakyTestRetriesEnabled, impactedTestsDetectionEnabled, + failedTestReplayEnabled, earlyFlakeDetectionSettings, testManagementSettings, itrCorrelationId, diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ExecutionSettingsFactoryImpl.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ExecutionSettingsFactoryImpl.java index c0acb7f83a6..636d3ef9bc9 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ExecutionSettingsFactoryImpl.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ExecutionSettingsFactoryImpl.java @@ -177,6 +177,11 @@ private Map doCreate( settings, CiVisibilitySettings::isKnownTestsEnabled, Config::isCiVisibilityKnownTestsRequestEnabled); + boolean failedTestReplayEnabled = + isFeatureEnabled( + settings, + CiVisibilitySettings::isFailedTestReplayEnabled, + Config::isCiVisibilityFailedTestReplayEnabled); TestManagementSettings testManagementSettings = getTestManagementSettings(settings); @@ -189,7 +194,8 @@ private Map doCreate( + "Impacted tests detection - {},\n" + "Known tests marking - {},\n" + "Auto test retries - {},\n" - + "Test Management - {}", + + "Test Management - {},\n" + + "Failed Test Replay - {}", repositoryRoot, tracerEnvironment.getConfigurations().getRuntimeName(), tracerEnvironment.getConfigurations().getRuntimeVersion(), @@ -201,7 +207,8 @@ private Map doCreate( impactedTestsEnabled, knownTestsRequest, flakyTestRetriesEnabled, - testManagementSettings.isEnabled()); + testManagementSettings.isEnabled(), + failedTestReplayEnabled); Future skippableTestsFuture = executor.submit(() -> getSkippableTests(tracerEnvironment, itrEnabled)); @@ -253,6 +260,7 @@ private Map doCreate( testSkippingEnabled, flakyTestRetriesEnabled, impactedTestsEnabled, + failedTestReplayEnabled, earlyFlakeDetectionEnabled ? settings.getEarlyFlakeDetectionSettings() : EarlyFlakeDetectionSettings.DEFAULT, 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 a2d8d155ea6..8e04e5527f9 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 @@ -20,6 +20,7 @@ import datadog.trace.api.civisibility.telemetry.TagValue; import datadog.trace.api.civisibility.telemetry.tag.BrowserDriver; import datadog.trace.api.civisibility.telemetry.tag.EventType; +import datadog.trace.api.civisibility.telemetry.tag.FailedTestReplayEnabled; import datadog.trace.api.civisibility.telemetry.tag.HasFailedAllRetries; import datadog.trace.api.civisibility.telemetry.tag.IsAttemptToFix; import datadog.trace.api.civisibility.telemetry.tag.IsDisabled; @@ -305,6 +306,9 @@ public void end(@Nullable Long endTime) { span.getTag(Tags.TEST_IS_RETRY) != null ? IsRetry.TRUE : null, span.getTag(Tags.TEST_HAS_FAILED_ALL_RETRIES) != null ? HasFailedAllRetries.TRUE : null, retryReason instanceof TagValue ? (TagValue) retryReason : null, + span.getTag(Tags.ERROR_DEBUG_INFO_CAPTURED) != null + ? FailedTestReplayEnabled.TestMetric.TRUE + : null, span.getTag(Tags.TEST_IS_RUM_ACTIVE) != null ? IsRum.TRUE : null, CIConstants.SELENIUM_BROWSER_DRIVER.equals(span.getTag(Tags.TEST_BROWSER_DRIVER)) ? BrowserDriver.SELENIUM 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 c29fa175229..89f509ad4cd 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.InstrumentationTestBridge; import datadog.trace.api.civisibility.config.LibraryCapability; import datadog.trace.api.civisibility.coverage.CoverageStore; import datadog.trace.api.civisibility.execution.TestStatus; @@ -220,6 +221,8 @@ public void end(@Nullable Long endTime) { AgentTracer.closeActive(); } + InstrumentationTestBridge.fireBeforeSuiteEnd(); + onSpanFinish.accept(span); if (endTime != null) { diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/buildsystem/BuildSystemModuleImpl.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/buildsystem/BuildSystemModuleImpl.java index 9c95f5e8450..f772e928be6 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/buildsystem/BuildSystemModuleImpl.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/buildsystem/BuildSystemModuleImpl.java @@ -12,6 +12,7 @@ import datadog.trace.api.civisibility.domain.JavaAgent; import datadog.trace.api.civisibility.telemetry.CiVisibilityMetricCollector; import datadog.trace.api.config.CiVisibilityConfig; +import datadog.trace.api.config.DebuggerConfig; import datadog.trace.api.config.GeneralConfig; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext; @@ -184,6 +185,18 @@ private Map getPropertiesPropagatedToChildProcess( Strings.propertyNameToSystemPropertyName(CiVisibilityConfig.TEST_MANAGEMENT_ENABLED), Boolean.toString(executionSettings.getTestManagementSettings().isEnabled())); + propagatedSystemProperties.put( + Strings.propertyNameToSystemPropertyName( + CiVisibilityConfig.TEST_FAILED_TEST_REPLAY_ENABLED), + Boolean.toString(executionSettings.isFailedTestReplayEnabled())); + + // enable exception replay if failed test replay is enabled + if (executionSettings.isFailedTestReplayEnabled()) { + propagatedSystemProperties.put( + Strings.propertyNameToSystemPropertyName(DebuggerConfig.EXCEPTION_REPLAY_ENABLED), + "true"); + } + // explicitly disable build instrumentation in child processes, // because some projects run "embedded" Maven/Gradle builds as part of their integration tests, // and we don't want to show those as if they were regular build executions diff --git a/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/config/ConfigurationApiImplTest.groovy b/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/config/ConfigurationApiImplTest.groovy index c284fce0199..0c55870a6eb 100644 --- a/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/config/ConfigurationApiImplTest.groovy +++ b/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/config/ConfigurationApiImplTest.groovy @@ -1,7 +1,6 @@ package datadog.trace.civisibility.config import datadog.communication.BackendApi -import datadog.communication.BackendApiFactory import datadog.communication.EvpProxyApi import datadog.communication.IntakeApi import datadog.communication.http.HttpRetryPolicy @@ -12,6 +11,7 @@ import datadog.trace.api.civisibility.config.TestIdentifier import datadog.trace.api.civisibility.config.TestMetadata import datadog.trace.api.civisibility.telemetry.CiVisibilityMetricCollector import datadog.trace.civisibility.CiVisibilityTestUtils +import datadog.trace.api.intake.Intake import okhttp3.HttpUrl import okhttp3.OkHttpClient import org.apache.commons.io.IOUtils @@ -55,10 +55,10 @@ class ConfigurationApiImplTest extends Specification { where: agentless | compression | expectedSettings - false | false | new CiVisibilitySettings(false, false, false, false, false, false, false, EarlyFlakeDetectionSettings.DEFAULT, TestManagementSettings.DEFAULT, null) - false | true | new CiVisibilitySettings(true, true, true, true, true, true, true, EarlyFlakeDetectionSettings.DEFAULT, TestManagementSettings.DEFAULT, "main") - true | false | new CiVisibilitySettings(false, true, false, true, false, true, false, new EarlyFlakeDetectionSettings(true, [new ExecutionsByDuration(1000, 3)], 10), new TestManagementSettings(true, 10), "master") - true | true | new CiVisibilitySettings(false, false, true, true, false, false, true, new EarlyFlakeDetectionSettings(true, [new ExecutionsByDuration(5000, 3), new ExecutionsByDuration(120000, 2)], 10), new TestManagementSettings(true, 20), "prod") + false | false | new CiVisibilitySettings(false, false, false, false, false, false, false, false, EarlyFlakeDetectionSettings.DEFAULT, TestManagementSettings.DEFAULT, null) + false | true | new CiVisibilitySettings(true, true, true, true, true, true, true, true, EarlyFlakeDetectionSettings.DEFAULT, TestManagementSettings.DEFAULT, "main") + true | false | new CiVisibilitySettings(false, true, false, true, false, true, false, true, new EarlyFlakeDetectionSettings(true, [new ExecutionsByDuration(1000, 3)], 10), new TestManagementSettings(true, 10), "master") + true | true | new CiVisibilitySettings(false, false, true, true, false, false, true, false, new EarlyFlakeDetectionSettings(true, [new ExecutionsByDuration(5000, 3), new ExecutionsByDuration(120000, 2)], 10), new TestManagementSettings(true, 20), "prod") } def "test skippable tests request"() { @@ -273,7 +273,7 @@ class ConfigurationApiImplTest extends Specification { } private BackendApi givenIntakeApi(URI address, boolean responseCompression) { - HttpUrl intakeUrl = HttpUrl.get(String.format("%s/api/%s/", address.toString(), BackendApiFactory.Intake.API.version)) + HttpUrl intakeUrl = HttpUrl.get(String.format("%s/api/%s/", address.toString(), Intake.API.getVersion())) String apiKey = "api-key" String traceId = "a-trace-id" 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 cd9a84e3fd8..2af232bfb1c 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,7 +1,6 @@ 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 @@ -9,7 +8,6 @@ import datadog.trace.api.config.CiVisibilityConfig import datadog.trace.civisibility.diff.LineDiff import datadog.trace.test.util.DDSpecification -import java.util.stream.Collectors import static datadog.trace.civisibility.TestUtils.lines @@ -31,6 +29,7 @@ class ExecutionSettingsTest extends DDSpecification { false, false, false, + false, EarlyFlakeDetectionSettings.DEFAULT, TestManagementSettings.DEFAULT, null, @@ -49,6 +48,7 @@ class ExecutionSettingsTest extends DDSpecification { false, true, true, + true, new EarlyFlakeDetectionSettings(true, [], 10), new TestManagementSettings(true, 20), "", @@ -68,6 +68,7 @@ class ExecutionSettingsTest extends DDSpecification { true, false, true, + false, new EarlyFlakeDetectionSettings(true, [new ExecutionsByDuration(10, 20)], 10), new TestManagementSettings(true, 20), "itrCorrelationId", @@ -91,6 +92,7 @@ class ExecutionSettingsTest extends DDSpecification { true, true, true, + true, new EarlyFlakeDetectionSettings(true, [new ExecutionsByDuration(10, 20), new ExecutionsByDuration(30, 40)], 10), new TestManagementSettings(true, 20), "itrCorrelationId", @@ -127,6 +129,7 @@ class ExecutionSettingsTest extends DDSpecification { settingsEnabled, settingsEnabled, settingsEnabled, + settingsEnabled, earlyFlakeDetectionSettings, testManagementSettings, null, diff --git a/dd-java-agent/agent-ci-visibility/src/test/resources/datadog/trace/civisibility/config/settings-response.ftl b/dd-java-agent/agent-ci-visibility/src/test/resources/datadog/trace/civisibility/config/settings-response.ftl index f21b821434e..43f79b251b8 100644 --- a/dd-java-agent/agent-ci-visibility/src/test/resources/datadog/trace/civisibility/config/settings-response.ftl +++ b/dd-java-agent/agent-ci-visibility/src/test/resources/datadog/trace/civisibility/config/settings-response.ftl @@ -10,6 +10,7 @@ "flaky_test_retries_enabled": ${settings.flakyTestRetriesEnabled?c}, "impacted_tests_enabled": ${settings.impactedTestsDetectionEnabled?c}, "known_tests_enabled": ${settings.knownTestsEnabled?c}, + "di_enabled": ${settings.failedTestReplayEnabled?c}, <#if settings.defaultBranch??> "default_branch": "${settings.defaultBranch}", 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 e4031ecdf30..a8481ce3562 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 @@ -112,6 +112,7 @@ abstract class CiVisibilityInstrumentationTest extends AgentTestRunner { private volatile boolean earlyFlakinessDetectionEnabled private volatile boolean impactedTestsDetectionEnabled private volatile boolean testManagementEnabled + private volatile boolean failedTestReplayEnabled = false } private final Settings settings = new Settings() @@ -233,6 +234,7 @@ abstract class CiVisibilityInstrumentationTest extends AgentTestRunner { settings.itrEnabled, settings.flakyRetryEnabled, settings.impactedTestsDetectionEnabled, + settings.failedTestReplayEnabled, earlyFlakinessDetectionSettings, testManagementSettings, settings.itrEnabled ? "itrCorrelationId" : null, 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 4251f586597..220c864a1b9 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 @@ -52,4 +52,38 @@ abstract class CiVisibilitySmokeTest extends Specification { // an even more basic smoke check for distributions: assert that we received some assert !receivedTelemetryDistributions.isEmpty() } + + protected static verifySnapshotLogs(List> receivedLogs, int expectedSnapshots) { + def logsPerSnapshot = 4 // 3 probe statuses + 1 snapshot log are expected per snapshot + + assert receivedLogs.size() == logsPerSnapshot * expectedSnapshots + + def probeStatusLogs = receivedLogs.findAll { it.containsKey("message") } + def snapshotLogs = receivedLogs.findAll { !it.containsKey("message") } + + verifyProbeStatuses(probeStatusLogs, expectedSnapshots) + verifySnapshots(snapshotLogs) + } + + private static verifyProbeStatuses(List> logs, int expectedCount) { + assert logs.findAll { log -> ((String) log.message).startsWith("Received probe") }.size() == expectedCount + assert logs.findAll { log -> ((String) log.message).startsWith("Installed probe") }.size() == expectedCount + assert logs.findAll { log -> ((String) log.message).endsWith("is emitting.") }.size() == expectedCount + } + + private static verifySnapshots(List> logs) { + def requiredLogFields = ["logger.name", "logger.method", "dd.spanid", "dd.traceid"] + def requiredSnapshotFields = ["captures", "exceptionId", "probe", "stack"] + + logs.each { log -> + assert log.product == "test_optimization" + requiredLogFields.each { field -> log.containsKey(field) } + + Map debuggerMap = log.debugger as Map + Map snapshotContent = debuggerMap.snapshot as Map + + assert snapshotContent != null + requiredSnapshotFields.each { field -> snapshotContent.containsKey(field) } + } + } } diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerAgent.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerAgent.java index 4de8622576a..eabf4752fca 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerAgent.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerAgent.java @@ -40,7 +40,6 @@ import java.lang.ref.WeakReference; import java.nio.file.Path; import java.nio.file.Paths; -import java.time.Duration; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -210,13 +209,7 @@ public static void startExceptionReplay() { Config config = Config.get(); commonInit(config); initClassNameFilter(); - exceptionDebugger = - new DefaultExceptionDebugger( - configurationUpdater, - classNameFilter, - Duration.ofSeconds(config.getDebuggerExceptionCaptureInterval()), - config.getDebuggerMaxExceptionPerSecond(), - config.getDebuggerExceptionMaxCapturedFrames()); + exceptionDebugger = new DefaultExceptionDebugger(configurationUpdater, classNameFilter, config); DebuggerContext.initExceptionDebugger(exceptionDebugger); LOGGER.info("Started Exception Replay"); } diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/JsonSnapshotSerializer.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/JsonSnapshotSerializer.java index 1fbeddfad49..8dd27ffc590 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/JsonSnapshotSerializer.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/JsonSnapshotSerializer.java @@ -14,13 +14,15 @@ public class JsonSnapshotSerializer implements DebuggerContext.ValueSerializer { private static final String DD_TRACE_ID = "dd.trace_id"; private static final String DD_SPAN_ID = "dd.span_id"; + public static final String TEST_OPT_PRODUCT = "test_optimization"; private static final JsonAdapter ADAPTER = MoshiHelper.createMoshiSnapshot().adapter(IntakeRequest.class); private static final JsonAdapter VALUE_ADAPTER = new MoshiSnapshotHelper.CapturedValueAdapter(); - public String serializeSnapshot(String serviceName, Snapshot snapshot) { - IntakeRequest request = new IntakeRequest(serviceName, new DebuggerIntakeRequestData(snapshot)); + public String serializeSnapshot(String serviceName, Snapshot snapshot, Config config) { + IntakeRequest request = + new IntakeRequest(serviceName, new DebuggerIntakeRequestData(snapshot), config); handleCorrelationFields(snapshot, request); handleDuration(snapshot, request); handlerLogger(snapshot, request); @@ -53,6 +55,7 @@ public static class IntakeRequest { private final String service; private final DebuggerIntakeRequestData debugger; private final String ddsource = "dd_debugger"; + private final String product; private final String message; private final String ddtags; @@ -85,7 +88,7 @@ public static class IntakeRequest { @Json(name = "logger.thread_name") private String loggerThreadName; - public IntakeRequest(String service, DebuggerIntakeRequestData debugger) { + public IntakeRequest(String service, DebuggerIntakeRequestData debugger, Config config) { this.service = service; this.debugger = debugger; this.message = debugger.snapshot.getMessage(); @@ -93,6 +96,7 @@ public IntakeRequest(String service, DebuggerIntakeRequestData debugger) { this.timestamp = debugger.snapshot.getTimestamp(); final CharSequence pt = ProcessTags.getTagsForSerialization(); this.processTags = pt != null ? pt.toString() : null; + this.product = config.isCiVisibilityFailedTestReplayActive() ? TEST_OPT_PRODUCT : null; } public String getService() { @@ -107,6 +111,10 @@ public String getDdsource() { return ddsource; } + public String getProduct() { + return product; + } + public String getMessage() { return message; } diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/exception/DefaultExceptionDebugger.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/exception/DefaultExceptionDebugger.java index 981f52208b8..98653d9f997 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/exception/DefaultExceptionDebugger.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/exception/DefaultExceptionDebugger.java @@ -9,9 +9,11 @@ import com.datadog.debugger.sink.Snapshot; import com.datadog.debugger.util.CircuitBreaker; import com.datadog.debugger.util.ExceptionHelper; +import datadog.trace.api.Config; import datadog.trace.bootstrap.debugger.DebuggerContext; import datadog.trace.bootstrap.debugger.DebuggerContext.ClassNameFilter; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import datadog.trace.bootstrap.instrumentation.api.Tags; import datadog.trace.util.AgentTaskScheduler; import java.time.Duration; import java.util.ArrayDeque; @@ -31,27 +33,33 @@ public class DefaultExceptionDebugger implements DebuggerContext.ExceptionDebugg public static final String DD_DEBUG_ERROR_EXCEPTION_ID = DD_DEBUG_ERROR_PREFIX + "exception_id"; public static final String DD_DEBUG_ERROR_EXCEPTION_HASH = DD_DEBUG_ERROR_PREFIX + "exception_hash"; - public static final String ERROR_DEBUG_INFO_CAPTURED = "error.debug_info_captured"; public static final String SNAPSHOT_ID_TAG_FMT = DD_DEBUG_ERROR_PREFIX + "%d.snapshot_id"; + // Test Optimization / Failed Test Replay specific + public static final String TEST_DEBUG_ERROR_FILE_TAG_FMT = DD_DEBUG_ERROR_PREFIX + "%d.file"; + public static final String TEST_DEBUG_ERROR_LINE_TAG_FMT = DD_DEBUG_ERROR_PREFIX + "%d.line"; + private final ExceptionProbeManager exceptionProbeManager; private final ConfigurationUpdater configurationUpdater; private final ClassNameFilter classNameFiltering; private final CircuitBreaker circuitBreaker; private final int maxCapturedFrames; + private final boolean applyConfigAsync; + private final boolean isFailedTestReplayActive; public DefaultExceptionDebugger( ConfigurationUpdater configurationUpdater, ClassNameFilter classNameFiltering, - Duration captureInterval, - int maxExceptionPerSecond, - int maxCapturedFrames) { + Config config) { this( - new ExceptionProbeManager(classNameFiltering, captureInterval), + new ExceptionProbeManager( + classNameFiltering, Duration.ofSeconds(config.getDebuggerExceptionCaptureInterval())), configurationUpdater, classNameFiltering, - maxExceptionPerSecond, - maxCapturedFrames); + config.getDebuggerMaxExceptionPerSecond(), + config.getDebuggerExceptionMaxCapturedFrames(), + config.isDebuggerExceptionAsyncConfig(), + config.isCiVisibilityFailedTestReplayActive()); } DefaultExceptionDebugger( @@ -59,17 +67,22 @@ public DefaultExceptionDebugger( ConfigurationUpdater configurationUpdater, ClassNameFilter classNameFiltering, int maxExceptionPerSecond, - int maxCapturedFrames) { + int maxCapturedFrames, + boolean applyConfigAsync, + boolean isFailedTestReplayActive) { this.exceptionProbeManager = exceptionProbeManager; this.configurationUpdater = configurationUpdater; this.classNameFiltering = classNameFiltering; this.circuitBreaker = new CircuitBreaker(maxExceptionPerSecond, Duration.ofSeconds(1)); this.maxCapturedFrames = maxCapturedFrames; + this.applyConfigAsync = applyConfigAsync; + this.isFailedTestReplayActive = isFailedTestReplayActive; } @Override public void handleException(Throwable t, AgentSpan span) { - if (t instanceof Error) { + // CIVIS Failed Test Replay acts on errors + if (t instanceof Error && !isFailedTestReplayActive) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Skip handling error: {}", t.toString()); } @@ -97,7 +110,13 @@ public void handleException(Throwable t, AgentSpan span) { return; } processSnapshotsAndSetTags( - t, span, state, chainedExceptionsList, fingerprint, maxCapturedFrames); + t, + span, + state, + chainedExceptionsList, + fingerprint, + maxCapturedFrames, + isFailedTestReplayActive); exceptionProbeManager.updateLastCapture(fingerprint); } else { // climb up the exception chain to find the first exception that has instrumented frames @@ -108,7 +127,11 @@ public void handleException(Throwable t, AgentSpan span) { exceptionProbeManager.createProbesForException( throwable.getStackTrace(), chainedExceptionIdx); if (creationResult.probesCreated > 0) { - AgentTaskScheduler.INSTANCE.execute(() -> applyExceptionConfiguration(fingerprint)); + if (isFailedTestReplayActive || !applyConfigAsync) { + applyExceptionConfiguration(fingerprint); + } else { + AgentTaskScheduler.INSTANCE.execute(() -> applyExceptionConfiguration(fingerprint)); + } break; } else { if (LOGGER.isDebugEnabled()) { @@ -135,7 +158,8 @@ private static void processSnapshotsAndSetTags( ThrowableState state, List chainedExceptions, String fingerprint, - int maxCapturedFrames) { + int maxCapturedFrames, + boolean isFailedTestReplayActive) { if (span.getTag(DD_DEBUG_ERROR_EXCEPTION_ID) != null) { LOGGER.debug("Clear previous frame tags"); // already set for this span, clear the frame tags @@ -166,6 +190,23 @@ private static void processSnapshotsAndSetTags( String tagName = String.format(SNAPSHOT_ID_TAG_FMT, frameIndex); span.setTag(tagName, snapshot.getId()); LOGGER.debug("add tag to span[{}]: {}: {}", span.getSpanId(), tagName, snapshot.getId()); + + if (isFailedTestReplayActive) { + StackTraceElement stackFrame = innerTrace[currentIdx]; + String fileTag = String.format(TEST_DEBUG_ERROR_FILE_TAG_FMT, frameIndex); + String lineTag = String.format(TEST_DEBUG_ERROR_LINE_TAG_FMT, frameIndex); + span.setTag(fileTag, stackFrame.getFileName()); + span.setTag(lineTag, stackFrame.getLineNumber()); + + LOGGER.debug( + "add ftr debug tags to span[{}]: {}={}, {}={}", + span.getSpanId(), + fileTag, + stackFrame.getFileName(), + lineTag, + stackFrame.getLineNumber()); + } + if (!state.isSnapshotSent()) { DebuggerAgent.getSink().addSnapshot(snapshot); } @@ -179,7 +220,7 @@ private static void processSnapshotsAndSetTags( span.getSpanId(), DD_DEBUG_ERROR_EXCEPTION_ID, state.getExceptionId()); - span.setTag(ERROR_DEBUG_INFO_CAPTURED, true); + span.setTag(Tags.ERROR_DEBUG_INFO_CAPTURED, true); span.setTag(DD_DEBUG_ERROR_EXCEPTION_HASH, fingerprint); } } diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/sink/DebuggerSink.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/sink/DebuggerSink.java index f2cee0e4940..d22516ae122 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/sink/DebuggerSink.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/sink/DebuggerSink.java @@ -4,6 +4,8 @@ import com.datadog.debugger.uploader.BatchUploader; import com.datadog.debugger.util.DebuggerMetrics; import datadog.trace.api.Config; +import datadog.trace.api.civisibility.InstrumentationTestBridge; +import datadog.trace.api.civisibility.domain.TestContext; import datadog.trace.bootstrap.debugger.DebuggerContext.SkipCause; import datadog.trace.bootstrap.debugger.ProbeId; import datadog.trace.util.AgentTaskScheduler; @@ -68,6 +70,11 @@ public DebuggerSink( this.snapshotSink = snapshotSink; this.symbolSink = symbolSink; this.uploadFlushInterval = config.getDynamicInstrumentationUploadFlushInterval(); + + if (config.isCiVisibilityFailedTestReplayActive()) { + // register test listener to flush snapshots on suite end + InstrumentationTestBridge.registerListener(new DebuggerTestListener(this)); + } } public void start() { @@ -235,4 +242,23 @@ public void skipSnapshot(String probeId, SkipCause cause) { long getCurrentLowRateFlushInterval() { return currentLowRateFlushInterval; } + + static class DebuggerTestListener implements InstrumentationTestBridge.TestListener { + private final DebuggerSink sink; + + DebuggerTestListener(DebuggerSink sink) { + this.sink = sink; + } + + @Override + public void beforeTestEnd(TestContext ignored) { + // noop + } + + @Override + public void beforeSuiteEnd() { + LOGGER.debug("CiVisibility BeforeSuiteEnd fired, flushing sink"); + sink.lowRateFlush(sink); + } + } } diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/sink/SnapshotSink.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/sink/SnapshotSink.java index 7eefe2ff296..73190fbb3ae 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/sink/SnapshotSink.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/sink/SnapshotSink.java @@ -45,10 +45,12 @@ public class SnapshotSink { private final AtomicBoolean started = new AtomicBoolean(); private volatile AgentTaskScheduler.Scheduled highRateScheduled; private volatile long currentHighRateFlushInterval = HIGH_RATE_MAX_FLUSH_INTERVAL_MS; + private final Config config; public SnapshotSink(Config config, String tags, BatchUploader snapshotUploader) { this.serviceName = TagsHelper.sanitize(config.getServiceName()); this.batchSize = config.getDynamicInstrumentationUploadBatchSize(); + this.config = config; this.tags = tags; this.snapshotUploader = snapshotUploader; } @@ -183,7 +185,8 @@ private List getSerializedSnapshots(BlockingQueue queue, int l private String serializeSnapshot(String serviceName, Snapshot snapshot) { snapshot.getId(); // Ensure id is generated - String str = DebuggerAgent.getSnapshotSerializer().serializeSnapshot(serviceName, snapshot); + String str = + DebuggerAgent.getSnapshotSerializer().serializeSnapshot(serviceName, snapshot, config); String prunedStr = SnapshotPruner.prune(str, MAX_SNAPSHOT_SIZE, 4); if (prunedStr.length() != str.length()) { LOGGER.debug( diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/exception/DefaultExceptionDebuggerTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/exception/DefaultExceptionDebuggerTest.java index 09dd8917dd6..76912eafdcc 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/exception/DefaultExceptionDebuggerTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/exception/DefaultExceptionDebuggerTest.java @@ -65,9 +65,9 @@ public void setUp() { classNameFiltering = new ClassNameFiltering( new HashSet<>(singletonList("com.datadog.debugger.exception.ThirdPartyCode"))); + Config config = createConfig(); exceptionDebugger = - new DefaultExceptionDebugger( - configurationUpdater, classNameFiltering, Duration.ofHours(1), 100, 3); + new DefaultExceptionDebugger(configurationUpdater, classNameFiltering, config); listener = new TestSnapshotListener(createConfig(), mock(ProbeStatusSink.class)); DebuggerAgentHelper.injectSink(listener); } @@ -275,11 +275,24 @@ public void nestedExceptionFullThirdParty() { public void filteringOutErrors() { ExceptionProbeManager manager = mock(ExceptionProbeManager.class); exceptionDebugger = - new DefaultExceptionDebugger(manager, configurationUpdater, classNameFiltering, 100, 3); + new DefaultExceptionDebugger( + manager, configurationUpdater, classNameFiltering, 100, 3, true, false); exceptionDebugger.handleException(new AssertionError("test"), mock(AgentSpan.class)); verify(manager, times(0)).isAlreadyInstrumented(any()); } + @Test + public void syncConfig() { + RuntimeException exception = new RuntimeException("test"); + String fingerprint = Fingerprinter.fingerprint(exception, classNameFiltering); + AgentSpan span = mock(AgentSpan.class); + exceptionDebugger.handleException(exception, span); + // instrumentation should be applied synchronously + assertTrue(exceptionDebugger.getExceptionProbeManager().isAlreadyInstrumented(fingerprint)); + exceptionDebugger.handleException(exception, span); + verify(configurationUpdater).accept(eq(ConfigurationAcceptor.Source.EXCEPTION), any()); + } + private Object recordTags(InvocationOnMock invocationOnMock) { Object[] args = invocationOnMock.getArguments(); String key = (String) args[0]; @@ -414,6 +427,9 @@ public static Config createConfig() { .thenReturn("http://localhost:8126/debugger/v1/input"); when(config.getFinalDebuggerSymDBUrl()).thenReturn("http://localhost:8126/symdb/v1/input"); when(config.getDynamicInstrumentationUploadBatchSize()).thenReturn(100); + when(config.getDebuggerExceptionCaptureInterval()).thenReturn(3600); + when(config.getDebuggerMaxExceptionPerSecond()).thenReturn(100); + when(config.getDebuggerExceptionMaxCapturedFrames()).thenReturn(3); return config; } } diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/exception/ExceptionProbeInstrumentationTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/exception/ExceptionProbeInstrumentationTest.java index f5266fc8d5f..976287d0cb4 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/exception/ExceptionProbeInstrumentationTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/exception/ExceptionProbeInstrumentationTest.java @@ -3,7 +3,6 @@ import static com.datadog.debugger.agent.ConfigurationAcceptor.Source.REMOTE_CONFIG; import static com.datadog.debugger.exception.DefaultExceptionDebugger.DD_DEBUG_ERROR_EXCEPTION_HASH; import static com.datadog.debugger.exception.DefaultExceptionDebugger.DD_DEBUG_ERROR_EXCEPTION_ID; -import static com.datadog.debugger.exception.DefaultExceptionDebugger.ERROR_DEBUG_INFO_CAPTURED; import static com.datadog.debugger.exception.DefaultExceptionDebugger.SNAPSHOT_ID_TAG_FMT; import static com.datadog.debugger.util.MoshiSnapshotTestHelper.getValue; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -38,6 +37,7 @@ import datadog.trace.bootstrap.debugger.ProbeId; import datadog.trace.bootstrap.debugger.ProbeLocation; import datadog.trace.bootstrap.debugger.ProbeRateLimiter; +import datadog.trace.bootstrap.instrumentation.api.Tags; import datadog.trace.core.CoreTracer; import java.io.IOException; import java.lang.instrument.ClassFileTransformer; @@ -157,7 +157,7 @@ public void instrumentAndCaptureSnapshots() throws Exception { MutableSpan span = traceInterceptor.getFirstSpan(); assertEquals(snapshot0.getExceptionId(), span.getTags().get(DD_DEBUG_ERROR_EXCEPTION_ID)); assertEquals(fingerprint, span.getTags().get(DD_DEBUG_ERROR_EXCEPTION_HASH)); - assertEquals(Boolean.TRUE, span.getTags().get(ERROR_DEBUG_INFO_CAPTURED)); + assertEquals(Boolean.TRUE, span.getTags().get(Tags.ERROR_DEBUG_INFO_CAPTURED)); assertEquals(snapshot0.getId(), span.getTags().get(String.format(SNAPSHOT_ID_TAG_FMT, 0))); assertEquals(1, probeSampler.getCallCount()); assertEquals(1, globalSampler.getCallCount()); @@ -198,11 +198,11 @@ public void differentExceptionsSameStack() throws Exception { assertExceptionMsg("illegal argument", snapshot1); MutableSpan span0 = traceInterceptor.getAllTraces().get(0).get(0); assertEquals(snapshot0.getExceptionId(), span0.getTags().get(DD_DEBUG_ERROR_EXCEPTION_ID)); - assertEquals(Boolean.TRUE, span0.getTags().get(ERROR_DEBUG_INFO_CAPTURED)); + assertEquals(Boolean.TRUE, span0.getTags().get(Tags.ERROR_DEBUG_INFO_CAPTURED)); assertEquals(snapshot0.getId(), span0.getTags().get(String.format(SNAPSHOT_ID_TAG_FMT, 0))); MutableSpan span1 = traceInterceptor.getAllTraces().get(1).get(0); assertEquals(snapshot1.getExceptionId(), span1.getTags().get(DD_DEBUG_ERROR_EXCEPTION_ID)); - assertEquals(Boolean.TRUE, span1.getTags().get(ERROR_DEBUG_INFO_CAPTURED)); + assertEquals(Boolean.TRUE, span1.getTags().get(Tags.ERROR_DEBUG_INFO_CAPTURED)); assertEquals(snapshot1.getId(), span1.getTags().get(String.format(SNAPSHOT_ID_TAG_FMT, 0))); } @@ -383,7 +383,7 @@ private TestSnapshotListener setupExceptionDebugging( DebuggerContext.initValueSerializer(new JsonSnapshotSerializer()); DefaultExceptionDebugger exceptionDebugger = new DefaultExceptionDebugger( - exceptionProbeManager, configurationUpdater, classNameFiltering, 100, 3); + exceptionProbeManager, configurationUpdater, classNameFiltering, 100, 3, true, false); DebuggerContext.initExceptionDebugger(exceptionDebugger); configurationUpdater.accept(REMOTE_CONFIG, definitions); return listener; diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/sink/DebuggerSinkTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/sink/DebuggerSinkTest.java index 9d9cd95ca05..37cac100c6f 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/sink/DebuggerSinkTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/sink/DebuggerSinkTest.java @@ -27,6 +27,7 @@ import com.squareup.moshi.Types; import datadog.trace.api.Config; import datadog.trace.api.ProcessTags; +import datadog.trace.api.civisibility.InstrumentationTestBridge; import datadog.trace.bootstrap.debugger.CapturedContext; import datadog.trace.bootstrap.debugger.CapturedContext.CapturedValue; import datadog.trace.bootstrap.debugger.CapturedStackFrame; @@ -124,6 +125,22 @@ public void addSnapshot(boolean processTagsEnabled) throws IOException { } } + @Test + public void addFailedTestReplaySnapshot() throws IOException { + when(config.isCiVisibilityFailedTestReplayActive()).thenReturn(true); + ProcessTags.reset(config); + DebuggerSink sink = createDefaultDebuggerSink(); + DebuggerAgentHelper.injectSerializer(new JsonSnapshotSerializer()); + Snapshot snapshot = createSnapshot(); + sink.addSnapshot(snapshot); + InstrumentationTestBridge.fireBeforeSuiteEnd(); // flush on suite end + verify(batchUploader).upload(payloadCaptor.capture(), matches(EXPECTED_SNAPSHOT_TAGS)); + String strPayload = new String(payloadCaptor.getValue(), StandardCharsets.UTF_8); + System.out.println(strPayload); + JsonSnapshotSerializer.IntakeRequest intakeRequest = assertOneIntakeRequest(strPayload); + assertEquals(JsonSnapshotSerializer.TEST_OPT_PRODUCT, intakeRequest.getProduct()); + } + @Test public void addMultipleSnapshots() throws IOException { when(config.getDynamicInstrumentationUploadBatchSize()).thenReturn(2); diff --git a/dd-java-agent/agent-logs-intake/src/main/java/datadog/trace/logging/intake/LogsWriterImpl.java b/dd-java-agent/agent-logs-intake/src/main/java/datadog/trace/logging/intake/LogsWriterImpl.java index 44ef25c7c00..c36950f422c 100644 --- a/dd-java-agent/agent-logs-intake/src/main/java/datadog/trace/logging/intake/LogsWriterImpl.java +++ b/dd-java-agent/agent-logs-intake/src/main/java/datadog/trace/logging/intake/LogsWriterImpl.java @@ -4,8 +4,8 @@ import datadog.communication.BackendApi; import datadog.communication.BackendApiFactory; -import datadog.communication.BackendApiFactory.Intake; import datadog.trace.api.Config; +import datadog.trace.api.intake.Intake; import datadog.trace.api.logging.intake.LogsWriter; import datadog.trace.util.AgentThreadFactory; import java.util.ArrayList; 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 d3014374988..7587e58373d 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 @@ -73,6 +73,7 @@ public static String getVersion() { LibraryCapability.TIA, LibraryCapability.ATR, LibraryCapability.EFD, + LibraryCapability.FTR, LibraryCapability.QUARANTINE, LibraryCapability.DISABLED, LibraryCapability.ATTEMPT_TO_FIX); 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 cb0755ffe0d..3ba001c3ba4 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 @@ -27,6 +27,7 @@ public abstract class MUnitUtils { LibraryCapability.ATR, LibraryCapability.EFD, LibraryCapability.IMPACTED, + LibraryCapability.FTR, LibraryCapability.QUARANTINE, LibraryCapability.ATTEMPT_TO_FIX); 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 2351d58a076..9b46dc9b351 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 @@ -65,6 +65,7 @@ public abstract class JUnit4Utils { LibraryCapability.ATR, LibraryCapability.EFD, LibraryCapability.IMPACTED, + LibraryCapability.FTR, LibraryCapability.QUARANTINE, LibraryCapability.DISABLED, LibraryCapability.ATTEMPT_TO_FIX); diff --git a/dd-java-agent/instrumentation/junit-5.3/src/main/java/datadog/trace/instrumentation/junit5/JUnitPlatformUtils.java b/dd-java-agent/instrumentation/junit-5.3/src/main/java/datadog/trace/instrumentation/junit5/JUnitPlatformUtils.java index d8435812082..d2b62499aa1 100644 --- a/dd-java-agent/instrumentation/junit-5.3/src/main/java/datadog/trace/instrumentation/junit5/JUnitPlatformUtils.java +++ b/dd-java-agent/instrumentation/junit-5.3/src/main/java/datadog/trace/instrumentation/junit5/JUnitPlatformUtils.java @@ -59,6 +59,7 @@ public abstract class JUnitPlatformUtils { LibraryCapability.ATR, LibraryCapability.EFD, LibraryCapability.IMPACTED, + LibraryCapability.FTR, LibraryCapability.QUARANTINE, LibraryCapability.DISABLED, LibraryCapability.ATTEMPT_TO_FIX); @@ -69,6 +70,7 @@ public abstract class JUnitPlatformUtils { LibraryCapability.ATR, LibraryCapability.EFD, LibraryCapability.IMPACTED, + LibraryCapability.FTR, LibraryCapability.QUARANTINE, LibraryCapability.DISABLED, LibraryCapability.ATTEMPT_TO_FIX, @@ -80,6 +82,7 @@ public abstract class JUnitPlatformUtils { LibraryCapability.ATR, LibraryCapability.EFD, LibraryCapability.IMPACTED, + LibraryCapability.FTR, LibraryCapability.QUARANTINE, LibraryCapability.DISABLED, LibraryCapability.ATTEMPT_TO_FIX); @@ -89,6 +92,7 @@ public abstract class JUnitPlatformUtils { LibraryCapability.TIA, LibraryCapability.ATR, LibraryCapability.EFD, + LibraryCapability.FTR, LibraryCapability.QUARANTINE, LibraryCapability.DISABLED, LibraryCapability.ATTEMPT_TO_FIX); 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 3fc6348aa6e..72ac6775cbe 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 @@ -56,6 +56,7 @@ private KarateUtils() {} Arrays.asList( LibraryCapability.ATR, LibraryCapability.EFD, + LibraryCapability.FTR, LibraryCapability.QUARANTINE, LibraryCapability.ATTEMPT_TO_FIX); @@ -63,6 +64,7 @@ private KarateUtils() {} Arrays.asList( LibraryCapability.ATR, LibraryCapability.EFD, + LibraryCapability.FTR, LibraryCapability.QUARANTINE, LibraryCapability.ATTEMPT_TO_FIX, LibraryCapability.TIA, 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 140b276244a..c6be5171199 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 @@ -24,6 +24,7 @@ public abstract class ScalatestUtils { LibraryCapability.EFD, LibraryCapability.ATR, LibraryCapability.IMPACTED, + LibraryCapability.FTR, LibraryCapability.QUARANTINE, LibraryCapability.DISABLED, LibraryCapability.ATTEMPT_TO_FIX); diff --git a/dd-java-agent/instrumentation/selenium/src/main/java/datadog/trace/instrumentation/selenium/SeleniumTestListener.java b/dd-java-agent/instrumentation/selenium/src/main/java/datadog/trace/instrumentation/selenium/SeleniumTestListener.java index 9b2d93af88b..d9c10f8f0f5 100644 --- a/dd-java-agent/instrumentation/selenium/src/main/java/datadog/trace/instrumentation/selenium/SeleniumTestListener.java +++ b/dd-java-agent/instrumentation/selenium/src/main/java/datadog/trace/instrumentation/selenium/SeleniumTestListener.java @@ -25,4 +25,9 @@ public void beforeTestEnd(TestContext testContext) { SeleniumUtils.beforePageClose(driver); } + + @Override + public void beforeSuiteEnd() { + // noop + } } diff --git a/dd-java-agent/instrumentation/testng/src/main/java/datadog/trace/instrumentation/testng/TestNGUtils.java b/dd-java-agent/instrumentation/testng/src/main/java/datadog/trace/instrumentation/testng/TestNGUtils.java index b29bdae6d25..c67da143832 100644 --- a/dd-java-agent/instrumentation/testng/src/main/java/datadog/trace/instrumentation/testng/TestNGUtils.java +++ b/dd-java-agent/instrumentation/testng/src/main/java/datadog/trace/instrumentation/testng/TestNGUtils.java @@ -288,6 +288,7 @@ public static List capabilities(String version) { boolean isExceptionSuppressionSupported = isExceptionSuppressionSupported(version); if (isExceptionSuppressionSupported) { baseCapabilities.add(LibraryCapability.ATR); + baseCapabilities.add(LibraryCapability.FTR); baseCapabilities.add(LibraryCapability.QUARANTINE); } if (isEFDSupported) { diff --git a/dd-smoke-tests/backend-mock/src/main/groovy/datadog/smoketest/MockBackend.groovy b/dd-smoke-tests/backend-mock/src/main/groovy/datadog/smoketest/MockBackend.groovy index e16b118f0be..426ea6c5615 100644 --- a/dd-smoke-tests/backend-mock/src/main/groovy/datadog/smoketest/MockBackend.groovy +++ b/dd-smoke-tests/backend-mock/src/main/groovy/datadog/smoketest/MockBackend.groovy @@ -40,6 +40,7 @@ class MockBackend implements AutoCloseable { private boolean knownTestsEnabled = false private boolean testManagementEnabled = false private int attemptToFixRetries = 0 + private boolean failedTestReplayEnabled = false void reset() { receivedTraces.clear() @@ -61,6 +62,7 @@ class MockBackend implements AutoCloseable { knownTestsEnabled = false testManagementEnabled = false attemptToFixRetries = 0 + failedTestReplayEnabled = false } @Override @@ -131,6 +133,10 @@ class MockBackend implements AutoCloseable { ]) } + void givenFailedTestReplay(boolean failedTestReplayEnabled) { + this.failedTestReplayEnabled = failedTestReplayEnabled + } + String getIntakeUrl() { return intakeServer.address.toString() } @@ -177,6 +183,7 @@ class MockBackend implements AutoCloseable { "flaky_test_retries_enabled": $flakyRetriesEnabled, "impacted_tests_enabled": $impactedTestsDetectionEnabled, "known_tests_enabled": $knownTestsEnabled, + "di_enabled": $failedTestReplayEnabled, "test_management": { "enabled": $testManagementEnabled, "attempt_to_fix_retries": $attemptToFixRetries 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 8fb894266ae..89322d79f42 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 @@ -241,6 +241,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -303,6 +304,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -367,6 +369,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -431,6 +434,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -495,6 +499,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", 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 686f52c3af4..25b6900a1c9 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 @@ -189,6 +189,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", 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 f60c9131589..2a1c6b15c38 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 @@ -241,6 +241,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", 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 527ee76d9dc..165a708f84f 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 @@ -236,6 +236,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -464,4 +465,4 @@ }, "type" : "span", "version" : 1 -} ] +} ] \ No newline at end of file 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 d5db1127f85..8be83d86374 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 @@ -238,6 +238,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -299,6 +300,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", 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 9c28dbea433..1ba73ff6574 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 @@ -187,6 +187,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -247,6 +248,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", 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 3e09ab667c8..4ac79928d3c 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 @@ -187,6 +187,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -296,6 +297,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", 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 a36672985a7..b80115a0c1e 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 @@ -236,6 +236,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -345,6 +346,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", 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 999f7f04106..8c8b2158165 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 @@ -193,6 +193,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -253,6 +254,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", 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 85a0f8abdad..3193d2dafd7 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 @@ -242,6 +242,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -302,6 +303,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", 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 5cb427be12e..48269e43118 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 @@ -237,6 +237,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -297,6 +298,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", 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 5111b76f994..d5d26e85e58 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 @@ -187,6 +187,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -247,6 +248,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", diff --git a/dd-smoke-tests/junit-console/build.gradle b/dd-smoke-tests/junit-console/build.gradle new file mode 100644 index 00000000000..d81f14fcf48 --- /dev/null +++ b/dd-smoke-tests/junit-console/build.gradle @@ -0,0 +1,20 @@ +import java.time.Duration +import java.time.temporal.ChronoUnit + +apply from: "$rootDir/gradle/java.gradle" +description = 'JUnit Console Smoke Tests.' + +dependencies { + implementation group: 'org.junit.platform', name: 'junit-platform-console-standalone', version: '1.13.4' + + testImplementation project(':dd-smoke-tests:backend-mock') +} + +tasks.withType(Test).configureEach { + jvmArgs "-Ddatadog.smoketest.junit.console.jar.path=${configurations.runtimeClasspath.find { it.name.contains('junit-platform-console-standalone') }}" + + if (project.hasProperty("mavenRepositoryProxy")) { + // propagate proxy URL to tests, to then propagate it to nested Gradle builds + environment "MAVEN_REPOSITORY_PROXY", project.property("mavenRepositoryProxy") + } +} diff --git a/dd-smoke-tests/junit-console/gradle.lockfile b/dd-smoke-tests/junit-console/gradle.lockfile new file mode 100644 index 00000000000..ca5e4e49be2 --- /dev/null +++ b/dd-smoke-tests/junit-console/gradle.lockfile @@ -0,0 +1,166 @@ +# This is a Gradle generated file for dependency locking. +# Manual edits can break the build and are not advised. +# This file is expected to be part of source control. +cafe.cryptography:curve25519-elisabeth:0.1.0=testRuntimeClasspath +cafe.cryptography:ed25519-elisabeth:0.1.0=testRuntimeClasspath +ch.qos.logback:logback-classic:1.2.3=testCompileClasspath,testRuntimeClasspath +ch.qos.logback:logback-core:1.2.3=testCompileClasspath,testRuntimeClasspath +com.beust:jcommander:1.78=testRuntimeClasspath +com.blogspot.mydailyjava:weak-lock-free:0.17=testCompileClasspath,testRuntimeClasspath +com.datadoghq.okhttp3:okhttp:3.12.15=testCompileClasspath,testRuntimeClasspath +com.datadoghq.okio:okio:1.17.6=testCompileClasspath,testRuntimeClasspath +com.datadoghq:dd-javac-plugin-client:0.2.2=testCompileClasspath,testRuntimeClasspath +com.datadoghq:java-dogstatsd-client:4.4.3=testRuntimeClasspath +com.datadoghq:sketches-java:0.8.3=testRuntimeClasspath +com.fasterxml.jackson.core:jackson-annotations:2.16.0=testCompileClasspath,testRuntimeClasspath +com.fasterxml.jackson.core:jackson-core:2.16.0=testCompileClasspath,testRuntimeClasspath +com.fasterxml.jackson.core:jackson-databind:2.16.0=testCompileClasspath,testRuntimeClasspath +com.fasterxml.jackson:jackson-bom:2.16.0=testCompileClasspath,testRuntimeClasspath +com.github.javaparser:javaparser-core:3.25.6=testCompileClasspath,testRuntimeClasspath +com.github.jnr:jffi:1.3.13=testRuntimeClasspath +com.github.jnr:jnr-a64asm:1.0.0=testRuntimeClasspath +com.github.jnr:jnr-constants:0.10.4=testRuntimeClasspath +com.github.jnr:jnr-enxio:0.32.17=testRuntimeClasspath +com.github.jnr:jnr-ffi:2.2.16=testRuntimeClasspath +com.github.jnr:jnr-posix:3.1.19=testRuntimeClasspath +com.github.jnr:jnr-unixsocket:0.38.22=testRuntimeClasspath +com.github.jnr:jnr-x86asm:1.0.2=testRuntimeClasspath +com.github.spotbugs:spotbugs-annotations:4.2.0=compileClasspath,testCompileClasspath,testRuntimeClasspath +com.github.spotbugs:spotbugs-annotations:4.7.3=spotbugs +com.github.spotbugs:spotbugs:4.7.3=spotbugs +com.github.stefanbirkner:system-rules:1.19.0=testCompileClasspath,testRuntimeClasspath +com.google.code.findbugs:jsr305:3.0.2=compileClasspath,spotbugs,testCompileClasspath,testRuntimeClasspath +com.google.code.gson:gson:2.9.1=spotbugs +com.google.guava:guava:20.0=testCompileClasspath,testRuntimeClasspath +com.google.re2j:re2j:1.7=testRuntimeClasspath +com.jayway.jsonpath:json-path:2.8.0=testCompileClasspath,testRuntimeClasspath +com.squareup.moshi:moshi:1.11.0=testCompileClasspath,testRuntimeClasspath +com.squareup.okhttp3:logging-interceptor:3.12.12=testCompileClasspath,testRuntimeClasspath +com.squareup.okhttp3:okhttp:3.12.12=testCompileClasspath,testRuntimeClasspath +com.squareup.okio:okio:1.17.5=testCompileClasspath,testRuntimeClasspath +com.thoughtworks.qdox:qdox:1.12.1=testRuntimeClasspath +com.vaadin.external.google:android-json:0.0.20131108.vaadin1=testCompileClasspath,testRuntimeClasspath +commons-codec:commons-codec:1.15=spotbugs +commons-fileupload:commons-fileupload:1.5=testCompileClasspath,testRuntimeClasspath +commons-io:commons-io:2.11.0=testCompileClasspath,testRuntimeClasspath +de.thetaphi:forbiddenapis:3.8=compileClasspath +info.picocli:picocli:4.6.3=testRuntimeClasspath +io.sqreen:libsqreen:15.0.1=testRuntimeClasspath +javax.servlet:javax.servlet-api:3.1.0=testCompileClasspath,testRuntimeClasspath +jaxen:jaxen:1.2.0=spotbugs +jline:jline:2.14.6=testRuntimeClasspath +junit:junit-dep:4.11=testCompileClasspath,testRuntimeClasspath +junit:junit:4.13.2=testCompileClasspath,testRuntimeClasspath +net.bytebuddy:byte-buddy-agent:1.17.5=testCompileClasspath,testRuntimeClasspath +net.bytebuddy:byte-buddy:1.17.5=testCompileClasspath,testRuntimeClasspath +net.java.dev.jna:jna-platform:5.8.0=testRuntimeClasspath +net.java.dev.jna:jna:5.8.0=testRuntimeClasspath +net.jcip:jcip-annotations:1.0=compileClasspath,spotbugs,testCompileClasspath,testRuntimeClasspath +net.minidev:accessors-smart:2.4.9=testRuntimeClasspath +net.minidev:json-smart:2.4.10=testRuntimeClasspath +net.sf.saxon:Saxon-HE:11.4=spotbugs +org.apache.ant:ant-antlr:1.10.15=testRuntimeClasspath +org.apache.ant:ant-antlr:1.9.15=codenarc +org.apache.ant:ant-junit:1.10.15=testRuntimeClasspath +org.apache.ant:ant-junit:1.9.15=codenarc +org.apache.ant:ant-launcher:1.10.15=testRuntimeClasspath +org.apache.ant:ant:1.10.15=testCompileClasspath,testRuntimeClasspath +org.apache.bcel:bcel:6.5.0=spotbugs +org.apache.commons:commons-lang3:3.12.0=spotbugs +org.apache.commons:commons-text:1.10.0=spotbugs +org.apache.httpcomponents.client5:httpclient5:5.1.3=spotbugs +org.apache.httpcomponents.core5:httpcore5-h2:5.1.3=spotbugs +org.apache.httpcomponents.core5:httpcore5:5.1.3=spotbugs +org.apache.logging.log4j:log4j-api:2.19.0=spotbugs +org.apache.logging.log4j:log4j-core:2.19.0=spotbugs +org.apache.maven.wrapper:maven-wrapper:3.2.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath +org.codehaus.groovy:groovy-all:3.0.24=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-ant:2.5.14=codenarc +org.codehaus.groovy:groovy-ant:3.0.24=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-astbuilder:3.0.24=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-cli-picocli:3.0.24=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-console:3.0.24=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-datetime:3.0.24=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-docgenerator:3.0.24=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-groovydoc:2.5.14=codenarc +org.codehaus.groovy:groovy-groovydoc:3.0.24=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-groovysh:3.0.24=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-jmx:3.0.24=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-json:2.5.14=codenarc +org.codehaus.groovy:groovy-json:3.0.24=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-jsr223:3.0.24=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-macro:3.0.24=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-nio:3.0.24=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-servlet:3.0.24=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-sql:3.0.24=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-swing:3.0.24=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-templates:2.5.14=codenarc +org.codehaus.groovy:groovy-templates:3.0.24=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-test-junit5:3.0.24=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-test:3.0.24=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-testng:3.0.24=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-xml:2.5.14=codenarc +org.codehaus.groovy:groovy-xml:3.0.24=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy:2.5.14=codenarc +org.codehaus.groovy:groovy:3.0.24=testCompileClasspath,testRuntimeClasspath +org.codenarc:CodeNarc:2.2.0=codenarc +org.dom4j:dom4j:2.1.3=spotbugs +org.eclipse.jetty:jetty-http:9.4.56.v20240826=testCompileClasspath,testRuntimeClasspath +org.eclipse.jetty:jetty-io:9.4.56.v20240826=testCompileClasspath,testRuntimeClasspath +org.eclipse.jetty:jetty-server:9.4.56.v20240826=testCompileClasspath,testRuntimeClasspath +org.eclipse.jetty:jetty-util:9.4.56.v20240826=testCompileClasspath,testRuntimeClasspath +org.freemarker:freemarker:2.3.31=testCompileClasspath,testRuntimeClasspath +org.gmetrics:GMetrics:1.1=codenarc +org.hamcrest:hamcrest-core:1.3=testCompileClasspath,testRuntimeClasspath +org.hamcrest:hamcrest:2.2=testCompileClasspath,testRuntimeClasspath +org.jacoco:org.jacoco.core:0.8.12=testRuntimeClasspath +org.jacoco:org.jacoco.report:0.8.12=testRuntimeClasspath +org.jctools:jctools-core:3.3.0=testRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-common:1.6.21=testCompileClasspath,testRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.21=testCompileClasspath,testRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.21=testCompileClasspath,testRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib:1.6.21=testCompileClasspath,testRuntimeClasspath +org.jetbrains:annotations:13.0=testCompileClasspath,testRuntimeClasspath +org.junit.jupiter:junit-jupiter-api:5.12.0=testCompileClasspath,testRuntimeClasspath +org.junit.jupiter:junit-jupiter-engine:5.12.0=testRuntimeClasspath +org.junit.jupiter:junit-jupiter-params:5.12.0=testCompileClasspath,testRuntimeClasspath +org.junit.jupiter:junit-jupiter:5.12.0=testCompileClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-commons:1.12.0=testCompileClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-engine:1.12.0=testCompileClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-launcher:1.12.0=testRuntimeClasspath +org.junit.platform:junit-platform-runner:1.12.0=testRuntimeClasspath +org.junit.platform:junit-platform-suite-api:1.12.0=testRuntimeClasspath +org.junit.platform:junit-platform-suite-commons:1.12.0=testRuntimeClasspath +org.junit:junit-bom:5.12.0=testCompileClasspath,testRuntimeClasspath +org.junit:junit-bom:5.9.1=spotbugs +org.msgpack:jackson-dataformat-msgpack:0.9.6=testCompileClasspath,testRuntimeClasspath +org.msgpack:msgpack-core:0.9.6=testCompileClasspath,testRuntimeClasspath +org.objenesis:objenesis:3.3=testCompileClasspath,testRuntimeClasspath +org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testRuntimeClasspath +org.ow2.asm:asm-analysis:9.2=testRuntimeClasspath +org.ow2.asm:asm-analysis:9.4=spotbugs +org.ow2.asm:asm-commons:9.4=spotbugs +org.ow2.asm:asm-commons:9.8=testRuntimeClasspath +org.ow2.asm:asm-tree:9.4=spotbugs +org.ow2.asm:asm-tree:9.8=testRuntimeClasspath +org.ow2.asm:asm-util:9.2=testRuntimeClasspath +org.ow2.asm:asm-util:9.4=spotbugs +org.ow2.asm:asm:9.4=spotbugs +org.ow2.asm:asm:9.8=testRuntimeClasspath +org.skyscreamer:jsonassert:1.5.1=testCompileClasspath,testRuntimeClasspath +org.slf4j:jcl-over-slf4j:1.7.30=testCompileClasspath,testRuntimeClasspath +org.slf4j:jul-to-slf4j:1.7.30=testCompileClasspath,testRuntimeClasspath +org.slf4j:log4j-over-slf4j:1.7.30=testCompileClasspath,testRuntimeClasspath +org.slf4j:slf4j-api:1.7.30=testCompileClasspath +org.slf4j:slf4j-api:1.7.36=testRuntimeClasspath +org.slf4j:slf4j-api:2.0.0=spotbugs,spotbugsSlf4j +org.slf4j:slf4j-simple:2.0.0=spotbugsSlf4j +org.snakeyaml:snakeyaml-engine:2.9=testRuntimeClasspath +org.spockframework:spock-core:2.3-groovy-3.0=testCompileClasspath,testRuntimeClasspath +org.spockframework:spock-junit4:2.3-groovy-3.0=testCompileClasspath,testRuntimeClasspath +org.testng:testng:7.5.1=testRuntimeClasspath +org.webjars:jquery:3.5.1=testRuntimeClasspath +org.xmlresolver:xmlresolver:4.4.3=spotbugs +xml-apis:xml-apis:1.4.01=spotbugs +empty=annotationProcessor,shadow,spotbugsPlugins,testAnnotationProcessor diff --git a/dd-smoke-tests/junit-console/src/test/groovy/datadog/smoketest/JUnitConsoleSmokeTest.groovy b/dd-smoke-tests/junit-console/src/test/groovy/datadog/smoketest/JUnitConsoleSmokeTest.groovy new file mode 100644 index 00000000000..17bf1d15bc2 --- /dev/null +++ b/dd-smoke-tests/junit-console/src/test/groovy/datadog/smoketest/JUnitConsoleSmokeTest.groovy @@ -0,0 +1,289 @@ +package datadog.smoketest + + +import datadog.trace.api.config.CiVisibilityConfig +import datadog.trace.api.config.GeneralConfig +import datadog.trace.civisibility.CiVisibilitySmokeTest +import datadog.trace.util.Strings +import java.nio.file.FileVisitResult +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.Paths +import java.nio.file.SimpleFileVisitor +import java.nio.file.attribute.BasicFileAttributes +import java.util.concurrent.TimeUnit +import java.util.concurrent.TimeoutException +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import spock.lang.AutoCleanup +import spock.lang.Shared +import spock.lang.TempDir +import spock.util.environment.Jvm + +class JUnitConsoleSmokeTest extends CiVisibilitySmokeTest { + // CodeNarc incorrectly thinks ".class" is unnecessary in getLogger + @SuppressWarnings('UnnecessaryDotClass') + private static final Logger LOGGER = LoggerFactory.getLogger(JUnitConsoleSmokeTest.class) + + private static final String TEST_SERVICE_NAME = "test-headless-service" + private static final String TEST_ENVIRONMENT_NAME = "integration-test" + + private static final int PROCESS_TIMEOUT_SECS = 60 + private static final String JUNIT_CONSOLE_JAR_PATH = System.getProperty("datadog.smoketest.junit.console.jar.path") + private static final String JAVA_HOME = buildJavaHome() + + @TempDir + Path projectHome + + @Shared + @AutoCleanup + MockBackend mockBackend = new MockBackend() + + def setup() { + mockBackend.reset() + } + + def "test headless failed test replay"() { + givenProjectFiles(projectName) + + mockBackend.givenFlakyRetries(true) + mockBackend.givenFailedTestReplay(true) + + def compileCode = compileTestProject() + assert compileCode == 0 + + def exitCode = whenRunningJUnitConsole([ + "${Strings.propertyNameToSystemPropertyName(CiVisibilityConfig.CIVISIBILITY_FLAKY_RETRY_COUNT)}=2" as String, + "${Strings.propertyNameToSystemPropertyName(GeneralConfig.AGENTLESS_LOG_SUBMISSION_URL)}=${mockBackend.intakeUrl}" as String + ], + [:]) + assert exitCode == 1 + + def additionalDynamicTags = ["content.meta.['_dd.debug.error.6.snapshot_id']", "content.meta.['_dd.debug.error.exception_id']"] + verifyEventsAndCoverages(projectName, "junit-console", "headless", mockBackend.waitForEvents(5), mockBackend.waitForCoverages(0), additionalDynamicTags) + verifySnapshotLogs(mockBackend.waitForLogs(4), 1) + + where: + projectName = "test_junit_console_failed_test_replay" + } + + private void givenProjectFiles(String projectFilesSources) { + def projectResourcesUri = this.getClass().getClassLoader().getResource(projectFilesSources).toURI() + def projectResourcesPath = Paths.get(projectResourcesUri) + copyFolder(projectResourcesPath, projectHome) + } + + private void copyFolder(Path src, Path dest) throws IOException { + Files.walkFileTree(src, new SimpleFileVisitor() { + @Override + FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) + throws IOException { + Files.createDirectories(dest.resolve(src.relativize(dir))) + return FileVisitResult.CONTINUE + } + + @Override + FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException { + Files.copy(file, dest.resolve(src.relativize(file))) + return FileVisitResult.CONTINUE + } + }) + + // creating empty .git directory so that the tracer could detect projectFolder as repo root + Files.createDirectory(projectHome.resolve(".git")) + } + + private int compileTestProject() { + def srcDir = projectHome.resolve("src/main/java") + def testSrcDir = projectHome.resolve("src/test/java") + def classesDir = projectHome.resolve("target/classes") + def testClassesDir = projectHome.resolve("target/test-classes") + + Files.createDirectories(classesDir) + Files.createDirectories(testClassesDir) + + // Compile main classes if they exist + if (Files.exists(srcDir)) { + def mainJavaFiles = findJavaFiles(srcDir) + if (!mainJavaFiles.isEmpty()) { + def result = runProcess(createCompilerProcessBuilder(classesDir.toString(), mainJavaFiles).start()) + if (result != 0) { + LOGGER.error("Error compiling source classes for JUnit Console smoke test") + return result + } + } + } + + // Compile test classes + def testJavaFiles = findJavaFiles(testSrcDir) + if (!testJavaFiles.isEmpty()) { + def result = runProcess(createCompilerProcessBuilder(testClassesDir.toString(), testJavaFiles, [classesDir.toString()]).start()) + if (result != 0) { + LOGGER.error("Error compiling source classes for JUnit Console smoke test") + return result + } + } + + return 0 + } + + private ProcessBuilder createCompilerProcessBuilder(String targetDir, List files, List additionalDeps = []) { + assert new File(JUNIT_CONSOLE_JAR_PATH).isFile() + + List deps = [JUNIT_CONSOLE_JAR_PATH] + deps.addAll(additionalDeps) + + List command = new ArrayList<>() + command.add(javacPath()) + command.addAll(["-cp", deps.join(":")]) + command.addAll(["-d", targetDir]) // TODO: check dir exists + command.addAll(files) + + ProcessBuilder processBuilder = new ProcessBuilder(command) + + processBuilder.directory(projectHome.toFile()) + processBuilder.environment().put("JAVA_HOME", JAVA_HOME) + + return processBuilder + } + + private static List findJavaFiles(Path directory) { + if (!Files.exists(directory)) { + return [] + } + + List javaFiles = [] + Files.walkFileTree(directory, new SimpleFileVisitor() { + @Override + FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + if (file.toString().endsWith(".java")) { + javaFiles.add(file.toString()) + } + return FileVisitResult.CONTINUE + } + }) + + return javaFiles + } + + private int whenRunningJUnitConsole(List additionalAgentArgs, Map additionalEnvVars) { + def processBuilder = createConsoleProcessBuilder(["execute"], additionalAgentArgs, additionalEnvVars) + + processBuilder.environment().put("DD_API_KEY", "01234567890abcdef123456789ABCDEF") + + return runProcess(processBuilder.start()) + } + + private static runProcess(Process p, int timeoutSecs = PROCESS_TIMEOUT_SECS) { + StreamConsumer errorGobbler = new StreamConsumer(p.getErrorStream(), "ERROR") + StreamConsumer outputGobbler = new StreamConsumer(p.getInputStream(), "OUTPUT") + outputGobbler.start() + errorGobbler.start() + + if (!p.waitFor(timeoutSecs , TimeUnit.SECONDS)) { + p.destroyForcibly() + throw new TimeoutException("Instrumented process failed to exit within $timeoutSecs seconds") + } + + return p.exitValue() + } + + ProcessBuilder createConsoleProcessBuilder(List consoleCommand, List additionalAgentArgs, Map additionalEnvVars) { + assert new File(JUNIT_CONSOLE_JAR_PATH).isFile() + + List command = new ArrayList<>() + command.add(javaPath()) + command.addAll((String[]) ["-jar", JUNIT_CONSOLE_JAR_PATH]) + command.addAll(consoleCommand) + command.addAll([ + "--class-path", + [projectHome.resolve("target/classes").toString(), projectHome.resolve("target/test-classes")].join(":") + ]) + command.add("--scan-class-path") + + ProcessBuilder processBuilder = new ProcessBuilder(command) + processBuilder.directory(projectHome.toFile()) + + processBuilder.environment().put("JAVA_HOME", JAVA_HOME) + processBuilder.environment().put("JAVA_TOOL_OPTIONS", javaToolOptions(additionalAgentArgs)) + for (envVar in additionalEnvVars) { + processBuilder.environment().put(envVar.key, envVar.value) + } + + def mavenRepositoryProxy = System.getenv("MAVEN_REPOSITORY_PROXY") + if (mavenRepositoryProxy != null) { + processBuilder.environment().put("MAVEN_REPOSITORY_PROXY", mavenRepositoryProxy) + } + + return processBuilder + } + + String javaPath() { + final String separator = System.getProperty("file.separator") + return JAVA_HOME + separator + "bin" + separator + "java" + } + + String javacPath() { + final String separator = System.getProperty("file.separator") + return JAVA_HOME + separator + "bin" + separator + "javac" + } + + String javaToolOptions(List additionalAgentArgs) { + def arguments = [] + + if (System.getenv("DD_CIVISIBILITY_SMOKETEST_DEBUG_PARENT") != null) { + // for convenience when debugging locally + arguments += "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005" + } + + def agentShadowJar = System.getProperty("datadog.smoketest.agent.shadowJar.path") + def agentArgument = "-javaagent:${agentShadowJar}=" + + // for convenience when debugging locally + (System.getenv("DD_CIVISIBILITY_SMOKETEST_DEBUG_CHILD") != null ? "${Strings.propertyNameToSystemPropertyName(CiVisibilityConfig.CIVISIBILITY_DEBUG_PORT)}=5055," : "") + + "${Strings.propertyNameToSystemPropertyName(GeneralConfig.TRACE_DEBUG)}=true," + + "${Strings.propertyNameToSystemPropertyName(GeneralConfig.ENV)}=${TEST_ENVIRONMENT_NAME}," + + "${Strings.propertyNameToSystemPropertyName(CiVisibilityConfig.CIVISIBILITY_ENABLED)}=true," + + "${Strings.propertyNameToSystemPropertyName(CiVisibilityConfig.CIVISIBILITY_AGENTLESS_ENABLED)}=true," + + "${Strings.propertyNameToSystemPropertyName(CiVisibilityConfig.CIVISIBILITY_CIPROVIDER_INTEGRATION_ENABLED)}=false," + + "${Strings.propertyNameToSystemPropertyName(CiVisibilityConfig.CIVISIBILITY_GIT_UPLOAD_ENABLED)}=false," + + "${Strings.propertyNameToSystemPropertyName(CiVisibilityConfig.CIVISIBILITY_AGENTLESS_URL)}=${mockBackend.intakeUrl}," + + "${Strings.propertyNameToSystemPropertyName(GeneralConfig.SERVICE_NAME)}=${TEST_SERVICE_NAME}," + + "${Strings.propertyNameToSystemPropertyName(CiVisibilityConfig.CIVISIBILITY_BUILD_INSTRUMENTATION_ENABLED)}=false," + + agentArgument += additionalAgentArgs.join(",") + + arguments += agentArgument.toString() + return arguments.join("\\ ") + } + + private static String buildJavaHome() { + if (Jvm.current.isJava8()) { + return System.getenv("JAVA_8_HOME") + } + return System.getenv("JAVA_" + Jvm.current.getJavaSpecificationVersion() + "_HOME") + } + + private static class StreamConsumer extends Thread { + final InputStream is + final String messagePrefix + + StreamConsumer(InputStream is, String messagePrefix) { + this.is = is + this.messagePrefix = messagePrefix + } + + @Override + void run() { + try { + BufferedReader br = new BufferedReader(new InputStreamReader(is)) + String line + while ((line = br.readLine()) != null) { + System.out.println(messagePrefix + ": " + line) + } + } catch (IOException e) { + e.printStackTrace() + } + } + } +} diff --git a/dd-smoke-tests/junit-console/src/test/resources/logback.xml b/dd-smoke-tests/junit-console/src/test/resources/logback.xml new file mode 100644 index 00000000000..24d6bcd768a --- /dev/null +++ b/dd-smoke-tests/junit-console/src/test/resources/logback.xml @@ -0,0 +1,3 @@ + + + diff --git a/dd-smoke-tests/junit-console/src/test/resources/test_junit_console_failed_test_replay/coverages.ftl b/dd-smoke-tests/junit-console/src/test/resources/test_junit_console_failed_test_replay/coverages.ftl new file mode 100644 index 00000000000..2f72ca231ee --- /dev/null +++ b/dd-smoke-tests/junit-console/src/test/resources/test_junit_console_failed_test_replay/coverages.ftl @@ -0,0 +1,19 @@ +[ { + "files" : [ { + "filename" : "src/main/java/com/example/Calculator.java" + }, { + "filename" : "src/test/java/com/example/TestFailed.java" + } ], + "span_id" : ${content_span_id}, + "test_session_id" : ${content_test_session_id}, + "test_suite_id" : ${content_test_suite_id} +}, { + "files" : [ { + "filename" : "src/main/java/com/example/Calculator.java" + }, { + "filename" : "src/test/java/com/example/TestFailed.java" + } ], + "span_id" : ${content_span_id_2}, + "test_session_id" : ${content_test_session_id}, + "test_suite_id" : ${content_test_suite_id} +} ] \ No newline at end of file diff --git a/dd-smoke-tests/junit-console/src/test/resources/test_junit_console_failed_test_replay/events.ftl b/dd-smoke-tests/junit-console/src/test/resources/test_junit_console_failed_test_replay/events.ftl new file mode 100644 index 00000000000..36b7b6d98c3 --- /dev/null +++ b/dd-smoke-tests/junit-console/src/test/resources/test_junit_console_failed_test_replay/events.ftl @@ -0,0 +1,271 @@ +[ { + "content" : { + "duration" : ${content_duration}, + "error" : 0, + "meta" : { + "_dd.p.tid" : ${content_meta__dd_p_tid}, + "_dd.test.is_user_provided_service" : "true", + "ci.workspace_path" : ${content_meta_ci_workspace_path}, + "component" : "junit5", + "env" : "integration-test", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "runtime-id" : ${content_meta_runtime_id}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version}, + "span.kind" : "test_suite_end", + "test.framework" : "junit5", + "test.framework_version" : "5.13.4", + "test.module" : "test-headless-service", + "test.source.file" : "src/test/java/com/example/TestFailed.java", + "test.status" : "fail", + "test.suite" : "com.example.TestFailed", + "test.type" : "test", + "test_session.name" : "test-headless-service" + }, + "metrics" : { + "_dd.host.vcpu_count" : ${content_metrics__dd_host_vcpu_count} + }, + "name" : "junit5.test_suite", + "resource" : "com.example.TestFailed", + "service" : "test-headless-service", + "start" : ${content_start}, + "test_module_id" : ${content_test_module_id}, + "test_session_id" : ${content_test_session_id}, + "test_suite_id" : ${content_test_suite_id} + }, + "type" : "test_suite_end", + "version" : 1 +}, { + "content" : { + "duration" : ${content_duration_2}, + "error" : 1, + "meta" : { + "_dd.library_capabilities.auto_test_retries" : "1", + "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", + "_dd.library_capabilities.impacted_tests" : "1", + "_dd.library_capabilities.test_impact_analysis" : "1", + "_dd.library_capabilities.test_management.attempt_to_fix" : "5", + "_dd.library_capabilities.test_management.disable" : "1", + "_dd.library_capabilities.test_management.quarantine" : "1", + "_dd.p.tid" : ${content_meta__dd_p_tid_2}, + "_dd.test.is_user_provided_service" : "true", + "_dd.tracer_host" : ${content_meta__dd_tracer_host}, + "ci.workspace_path" : ${content_meta_ci_workspace_path}, + "component" : "junit5", + "env" : "integration-test", + "error.message" : ${content_meta_error_message}, + "error.stack" : ${content_meta_error_stack}, + "error.type" : "org.opentest4j.AssertionFailedError", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "runtime-id" : ${content_meta_runtime_id}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version}, + "span.kind" : "test", + "test.framework" : "junit5", + "test.framework_version" : "5.13.4", + "test.module" : "test-headless-service", + "test.name" : "test_failed", + "test.source.file" : "src/test/java/com/example/TestFailed.java", + "test.source.method" : "test_failed()V", + "test.status" : "fail", + "test.suite" : "com.example.TestFailed", + "test.type" : "test", + "test_session.name" : "test-headless-service" + }, + "metrics" : { + "_dd.host.vcpu_count" : ${content_metrics__dd_host_vcpu_count_2}, + "_dd.profiling.enabled" : 0, + "_dd.trace_span_attribute_schema" : 0, + "process_id" : ${content_metrics_process_id}, + "test.source.end" : 11, + "test.source.start" : 10 + }, + "name" : "junit5.test", + "parent_id" : ${content_parent_id}, + "resource" : "com.example.TestFailed.test_failed", + "service" : "test-headless-service", + "span_id" : ${content_span_id}, + "start" : ${content_start_2}, + "test_module_id" : ${content_test_module_id}, + "test_session_id" : ${content_test_session_id}, + "test_suite_id" : ${content_test_suite_id}, + "trace_id" : ${content_trace_id} + }, + "type" : "test", + "version" : 2 +}, { + "content" : { + "duration" : ${content_duration_3}, + "error" : 1, + "meta" : { + "_dd.debug.error.6.file" : "TestFailed.java", + "_dd.debug.error.6.snapshot_id" : ${content_meta__dd_debug_error_6_snapshot_id}, + "_dd.debug.error.exception_hash" : "2959ee575767ef8f3474753647822b7aaf286fc0bf8e273117a7ceb47b525", + "_dd.debug.error.exception_id" : ${content_meta__dd_debug_error_exception_id}, + "_dd.library_capabilities.auto_test_retries" : "1", + "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", + "_dd.library_capabilities.impacted_tests" : "1", + "_dd.library_capabilities.test_impact_analysis" : "1", + "_dd.library_capabilities.test_management.attempt_to_fix" : "5", + "_dd.library_capabilities.test_management.disable" : "1", + "_dd.library_capabilities.test_management.quarantine" : "1", + "_dd.p.tid" : ${content_meta__dd_p_tid_3}, + "_dd.test.is_user_provided_service" : "true", + "_dd.tracer_host" : ${content_meta__dd_tracer_host}, + "ci.workspace_path" : ${content_meta_ci_workspace_path}, + "component" : "junit5", + "env" : "integration-test", + "error.debug_info_captured" : "true", + "error.message" : ${content_meta_error_message}, + "error.stack" : ${content_meta_error_stack_2}, + "error.type" : "org.opentest4j.AssertionFailedError", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "runtime-id" : ${content_meta_runtime_id}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version}, + "span.kind" : "test", + "test.framework" : "junit5", + "test.framework_version" : "5.13.4", + "test.has_failed_all_retries" : "true", + "test.is_retry" : "true", + "test.module" : "test-headless-service", + "test.name" : "test_failed", + "test.retry_reason" : "auto_test_retry", + "test.source.file" : "src/test/java/com/example/TestFailed.java", + "test.source.method" : "test_failed()V", + "test.status" : "fail", + "test.suite" : "com.example.TestFailed", + "test.type" : "test", + "test_session.name" : "test-headless-service" + }, + "metrics" : { + "_dd.debug.error.6.line" : 10, + "_dd.host.vcpu_count" : ${content_metrics__dd_host_vcpu_count_3}, + "_dd.profiling.enabled" : 0, + "_dd.trace_span_attribute_schema" : 0, + "process_id" : ${content_metrics_process_id}, + "test.source.end" : 11, + "test.source.start" : 10 + }, + "name" : "junit5.test", + "parent_id" : ${content_parent_id}, + "resource" : "com.example.TestFailed.test_failed", + "service" : "test-headless-service", + "span_id" : ${content_span_id_2}, + "start" : ${content_start_3}, + "test_module_id" : ${content_test_module_id}, + "test_session_id" : ${content_test_session_id}, + "test_suite_id" : ${content_test_suite_id}, + "trace_id" : ${content_trace_id_2} + }, + "type" : "test", + "version" : 2 +}, { + "content" : { + "duration" : ${content_duration_4}, + "error" : 0, + "meta" : { + "_dd.p.tid" : ${content_meta__dd_p_tid_4}, + "_dd.test.is_user_provided_service" : "true", + "_dd.tracer_host" : ${content_meta__dd_tracer_host}, + "ci.workspace_path" : ${content_meta_ci_workspace_path}, + "component" : "junit5", + "env" : "integration-test", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "runtime-id" : ${content_meta_runtime_id}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version}, + "span.kind" : "test_session_end", + "test.code_coverage.enabled" : "true", + "test.command" : "test-headless-service", + "test.framework" : "junit5", + "test.framework_version" : "5.13.4", + "test.itr.tests_skipping.enabled" : "true", + "test.itr.tests_skipping.type" : "test", + "test.status" : "fail", + "test.type" : "test", + "test_session.name" : "test-headless-service" + }, + "metrics" : { + "_dd.host.vcpu_count" : ${content_metrics__dd_host_vcpu_count_4}, + "_dd.profiling.enabled" : 0, + "_dd.trace_span_attribute_schema" : 0, + "process_id" : ${content_metrics_process_id}, + "test.itr.tests_skipping.count" : 0 + }, + "name" : "junit5.test_session", + "resource" : "test-headless-service", + "service" : "test-headless-service", + "start" : ${content_start_4}, + "test_session_id" : ${content_test_session_id} + }, + "type" : "test_session_end", + "version" : 1 +}, { + "content" : { + "duration" : ${content_duration_5}, + "error" : 0, + "meta" : { + "_dd.p.tid" : ${content_meta__dd_p_tid_5}, + "_dd.test.is_user_provided_service" : "true", + "ci.workspace_path" : ${content_meta_ci_workspace_path}, + "component" : "junit5", + "env" : "integration-test", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "runtime-id" : ${content_meta_runtime_id}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version}, + "span.kind" : "test_module_end", + "test.code_coverage.enabled" : "true", + "test.framework" : "junit5", + "test.framework_version" : "5.13.4", + "test.itr.tests_skipping.enabled" : "true", + "test.itr.tests_skipping.type" : "test", + "test.module" : "test-headless-service", + "test.status" : "fail", + "test.type" : "test", + "test_session.name" : "test-headless-service" + }, + "metrics" : { + "_dd.host.vcpu_count" : ${content_metrics__dd_host_vcpu_count_5}, + "test.itr.tests_skipping.count" : 0 + }, + "name" : "junit5.test_module", + "resource" : "test-headless-service", + "service" : "test-headless-service", + "start" : ${content_start_5}, + "test_module_id" : ${content_test_module_id}, + "test_session_id" : ${content_test_session_id} + }, + "type" : "test_module_end", + "version" : 1 +} ] \ No newline at end of file diff --git a/dd-smoke-tests/junit-console/src/test/resources/test_junit_console_failed_test_replay/src/main/java/com/example/Calculator.java b/dd-smoke-tests/junit-console/src/test/resources/test_junit_console_failed_test_replay/src/main/java/com/example/Calculator.java new file mode 100644 index 00000000000..3acf064086f --- /dev/null +++ b/dd-smoke-tests/junit-console/src/test/resources/test_junit_console_failed_test_replay/src/main/java/com/example/Calculator.java @@ -0,0 +1,11 @@ +package com.example; + +public class Calculator { + public static int add(int a, int b) { + return a + b; + } + + public static int subtract(int a, int b) { + return a - b; + } +} diff --git a/dd-smoke-tests/junit-console/src/test/resources/test_junit_console_failed_test_replay/src/test/java/com/example/TestFailed.java b/dd-smoke-tests/junit-console/src/test/resources/test_junit_console_failed_test_replay/src/test/java/com/example/TestFailed.java new file mode 100644 index 00000000000..adcb8a03a9b --- /dev/null +++ b/dd-smoke-tests/junit-console/src/test/resources/test_junit_console_failed_test_replay/src/test/java/com/example/TestFailed.java @@ -0,0 +1,13 @@ +package com.example; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; + +public class TestFailed { + + @Test + public void test_failed() { + assertTrue(Calculator.add(2, 2) == 22); + } + +} diff --git a/dd-smoke-tests/maven/src/test/groovy/datadog/smoketest/MavenSmokeTest.groovy b/dd-smoke-tests/maven/src/test/groovy/datadog/smoketest/MavenSmokeTest.groovy index 83da2154689..f3a9ee21634 100644 --- a/dd-smoke-tests/maven/src/test/groovy/datadog/smoketest/MavenSmokeTest.groovy +++ b/dd-smoke-tests/maven/src/test/groovy/datadog/smoketest/MavenSmokeTest.groovy @@ -164,55 +164,55 @@ class MavenSmokeTest extends CiVisibilitySmokeTest { verifyTestOrder(mockBackend.waitForEvents(eventsNumber), expectedOrder) where: - testcaseName | projectName | mavenVersion | surefireVersion | flakyTests | knownTests | expectedOrder | eventsNumber - "junit4-provider" | "test_successful_maven_run_junit4_class_ordering" | "3.9.9" | "3.0.0" | [ + testcaseName | projectName | mavenVersion | surefireVersion | flakyTests | knownTests | expectedOrder | eventsNumber + "junit4-provider" | "test_successful_maven_run_junit4_class_ordering" | "3.9.9" | "3.0.0" | [ test("datadog.smoke.TestSucceedB", "test_succeed"), test("datadog.smoke.TestSucceedB", "test_succeed_another"), test("datadog.smoke.TestSucceedA", "test_succeed") - ] | [ + ] | [ test("datadog.smoke.TestSucceedB", "test_succeed"), test("datadog.smoke.TestSucceedB", "test_succeed_another"), test("datadog.smoke.TestSucceedA", "test_succeed") - ] | [ + ] | [ test("datadog.smoke.TestSucceedC", "test_succeed"), test("datadog.smoke.TestSucceedC", "test_succeed_another"), test("datadog.smoke.TestSucceedA", "test_succeed_another"), test("datadog.smoke.TestSucceedA", "test_succeed"), test("datadog.smoke.TestSucceedB", "test_succeed"), test("datadog.smoke.TestSucceedB", "test_succeed_another") - ] | 15 - "junit47-provider" | "test_successful_maven_run_junit4_class_ordering_parallel" | "3.9.9" | "3.0.0" | [test("datadog.smoke.TestSucceedC", "test_succeed")] | [ + ] | 15 + "junit47-provider" | "test_successful_maven_run_junit4_class_ordering_parallel" | "3.9.9" | "3.0.0" | [test("datadog.smoke.TestSucceedC", "test_succeed")] | [ test("datadog.smoke.TestSucceedC", "test_succeed"), test("datadog.smoke.TestSucceedA", "test_succeed") - ] | [ + ] | [ test("datadog.smoke.TestSucceedB", "test_succeed"), test("datadog.smoke.TestSucceedC", "test_succeed"), test("datadog.smoke.TestSucceedA", "test_succeed") - ] | 12 - "junit4-provider-latest-surefire" | "test_successful_maven_run_junit4_class_ordering" | "3.9.9" | getLatestMavenSurefireVersion() | [ + ] | 12 + "junit4-provider-latest-surefire" | "test_successful_maven_run_junit4_class_ordering" | "3.9.9" | getLatestMavenSurefireVersion() | [ test("datadog.smoke.TestSucceedB", "test_succeed"), test("datadog.smoke.TestSucceedB", "test_succeed_another"), test("datadog.smoke.TestSucceedA", "test_succeed") - ] | [ + ] | [ test("datadog.smoke.TestSucceedB", "test_succeed"), test("datadog.smoke.TestSucceedB", "test_succeed_another"), test("datadog.smoke.TestSucceedA", "test_succeed") - ] | [ + ] | [ test("datadog.smoke.TestSucceedC", "test_succeed"), test("datadog.smoke.TestSucceedC", "test_succeed_another"), test("datadog.smoke.TestSucceedA", "test_succeed_another"), test("datadog.smoke.TestSucceedA", "test_succeed"), test("datadog.smoke.TestSucceedB", "test_succeed"), test("datadog.smoke.TestSucceedB", "test_succeed_another") - ] | 15 - "junit47-provider-latest-surefire" | "test_successful_maven_run_junit4_class_ordering_parallel" | "3.9.9" | getLatestMavenSurefireVersion() | [test("datadog.smoke.TestSucceedC", "test_succeed")] | [ + ] | 15 + "junit47-provider-latest-surefire" | "test_successful_maven_run_junit4_class_ordering_parallel" | "3.9.9" | getLatestMavenSurefireVersion() | [test("datadog.smoke.TestSucceedC", "test_succeed")] | [ test("datadog.smoke.TestSucceedC", "test_succeed"), test("datadog.smoke.TestSucceedA", "test_succeed") - ] | [ + ] | [ test("datadog.smoke.TestSucceedB", "test_succeed"), test("datadog.smoke.TestSucceedC", "test_succeed"), test("datadog.smoke.TestSucceedA", "test_succeed") - ] | 12 + ] | 12 } def "test service name is propagated to child processes"() { @@ -227,10 +227,36 @@ class MavenSmokeTest extends CiVisibilitySmokeTest { verifyEventsAndCoverages(projectName, "maven", mavenVersion, mockBackend.waitForEvents(5), mockBackend.waitForCoverages(1), additionalDynamicPaths) where: - projectName | mavenVersion + projectName | mavenVersion "test_successful_maven_run_child_service_propagation" | "3.9.9" } + def "test failed test replay"() { + givenWrapperPropertiesFile(mavenVersion) + givenMavenProjectFiles(projectName) + givenMavenDependenciesAreLoaded(projectName, mavenVersion) + + mockBackend.givenFlakyRetries(true) + mockBackend.givenFlakyTest("Maven Smoke Tests Project maven-surefire-plugin default-test", "com.example.TestFailed", "test_failed") + mockBackend.givenFailedTestReplay(true) + + def exitCode = whenRunningMavenBuild([ + "${Strings.propertyNameToSystemPropertyName(CiVisibilityConfig.CIVISIBILITY_FLAKY_RETRY_COUNT)}=2" as String, + "${Strings.propertyNameToSystemPropertyName(GeneralConfig.AGENTLESS_LOG_SUBMISSION_URL)}=${mockBackend.intakeUrl}" as String + ], + [], + [:]) + assert exitCode == 1 + + def additionalDynamicTags = ["content.meta.['_dd.debug.error.3.snapshot_id']", "content.meta.['_dd.debug.error.exception_id']"] + verifyEventsAndCoverages(projectName, "maven", mavenVersion, mockBackend.waitForEvents(5), mockBackend.waitForCoverages(0), additionalDynamicTags) + verifySnapshotLogs(mockBackend.waitForLogs(4), 1) + + where: + projectName | mavenVersion + "test_failed_maven_failed_test_replay" | "3.9.9" + } + private void givenWrapperPropertiesFile(String mavenVersion) { def distributionUrl = "https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/${mavenVersion}/apache-maven-${mavenVersion}-bin.zip" diff --git a/dd-smoke-tests/maven/src/test/resources/test_failed_maven_failed_test_replay/coverages.ftl b/dd-smoke-tests/maven/src/test/resources/test_failed_maven_failed_test_replay/coverages.ftl new file mode 100644 index 00000000000..0ccad374ea0 --- /dev/null +++ b/dd-smoke-tests/maven/src/test/resources/test_failed_maven_failed_test_replay/coverages.ftl @@ -0,0 +1,19 @@ +[ { + "files" : [ { + "filename" : "src/main/java/com/example/Calculator.java" + }, { + "filename" : "src/test/java/com/example/TestFailed.java" + } ], + "span_id" : ${content_span_id_5}, + "test_session_id" : ${content_test_session_id}, + "test_suite_id" : ${content_test_suite_id} +}, { + "files" : [ { + "filename" : "src/main/java/com/example/Calculator.java" + }, { + "filename" : "src/test/java/com/example/TestFailed.java" + } ], + "span_id" : ${content_span_id_6}, + "test_session_id" : ${content_test_session_id}, + "test_suite_id" : ${content_test_suite_id} +} ] \ No newline at end of file diff --git a/dd-smoke-tests/maven/src/test/resources/test_failed_maven_failed_test_replay/events.ftl b/dd-smoke-tests/maven/src/test/resources/test_failed_maven_failed_test_replay/events.ftl new file mode 100644 index 00000000000..b10b68bb6b9 --- /dev/null +++ b/dd-smoke-tests/maven/src/test/resources/test_failed_maven_failed_test_replay/events.ftl @@ -0,0 +1,412 @@ +[ { + "content" : { + "duration" : ${content_duration}, + "error" : 1, + "meta" : { + "_dd.p.tid" : ${content_meta__dd_p_tid}, + "_dd.test.is_user_provided_service" : "true", + "_dd.tracer_host" : ${content_meta__dd_tracer_host}, + "ci.workspace_path" : ${content_meta_ci_workspace_path}, + "component" : "maven", + "env" : "integration-test", + "error.message" : ${content_meta_error_message}, + "error.stack" : ${content_meta_error_stack}, + "error.type" : "org.apache.maven.lifecycle.LifecycleExecutionException", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "runtime-id" : ${content_meta_runtime_id}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version}, + "span.kind" : "test_session_end", + "test.code_coverage.enabled" : "true", + "test.command" : "mvn -B test", + "test.framework" : "junit4", + "test.framework_version" : "4.13.2", + "test.itr.tests_skipping.enabled" : "true", + "test.itr.tests_skipping.type" : "test", + "test.status" : "fail", + "test.toolchain" : ${content_meta_test_toolchain}, + "test.type" : "test", + "test_session.name" : "mvn -B test" + }, + "metrics" : { + "_dd.host.vcpu_count" : ${content_metrics__dd_host_vcpu_count}, + "_dd.profiling.enabled" : 0, + "_dd.trace_span_attribute_schema" : 0, + "process_id" : ${content_metrics_process_id}, + "test.itr.tests_skipping.count" : 0 + }, + "name" : "maven.test_session", + "resource" : "Maven Smoke Tests Project", + "service" : "test-maven-service", + "start" : ${content_start}, + "test_session_id" : ${content_test_session_id} + }, + "type" : "test_session_end", + "version" : 1 +}, { + "content" : { + "duration" : ${content_duration_2}, + "error" : 1, + "meta" : { + "_dd.p.tid" : ${content_meta__dd_p_tid_2}, + "_dd.test.is_user_provided_service" : "true", + "ci.workspace_path" : ${content_meta_ci_workspace_path}, + "component" : "maven", + "env" : "integration-test", + "error.message" : ${content_meta_error_message}, + "error.stack" : ${content_meta_error_stack_2}, + "error.type" : "org.apache.maven.lifecycle.LifecycleExecutionException", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "runtime-id" : ${content_meta_runtime_id}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version}, + "span.kind" : "test_module_end", + "test.code_coverage.enabled" : "true", + "test.command" : "mvn -B test", + "test.execution" : "maven-surefire-plugin:test:default-test", + "test.framework" : "junit4", + "test.framework_version" : "4.13.2", + "test.itr.tests_skipping.enabled" : "true", + "test.itr.tests_skipping.type" : "test", + "test.module" : "Maven Smoke Tests Project maven-surefire-plugin default-test", + "test.status" : "fail", + "test.type" : "test", + "test_session.name" : "mvn -B test" + }, + "metrics" : { + "_dd.host.vcpu_count" : ${content_metrics__dd_host_vcpu_count_2}, + "test.itr.tests_skipping.count" : 0 + }, + "name" : "maven.test_module", + "resource" : "Maven Smoke Tests Project maven-surefire-plugin default-test", + "service" : "test-maven-service", + "start" : ${content_start_2}, + "test_module_id" : ${content_test_module_id}, + "test_session_id" : ${content_test_session_id} + }, + "type" : "test_module_end", + "version" : 1 +}, { + "content" : { + "duration" : ${content_duration_3}, + "error" : 0, + "meta" : { + "_dd.p.tid" : ${content_meta__dd_p_tid_3}, + "_dd.test.is_user_provided_service" : "true", + "env" : "integration-test", + "execution" : "default-compile", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "plugin" : "maven-compiler-plugin", + "project" : "Maven Smoke Tests Project", + "runtime-id" : ${content_meta_runtime_id}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version} + }, + "metrics" : { }, + "name" : "Maven_Smoke_Tests_Project_maven_compiler_plugin_default_compile", + "parent_id" : ${content_test_session_id}, + "resource" : "Maven_Smoke_Tests_Project_maven_compiler_plugin_default_compile", + "service" : "test-maven-service", + "span_id" : ${content_span_id}, + "start" : ${content_start_3}, + "trace_id" : ${content_test_session_id} + }, + "type" : "span", + "version" : 1 +}, { + "content" : { + "duration" : ${content_duration_4}, + "error" : 0, + "meta" : { + "_dd.p.tid" : ${content_meta__dd_p_tid_4}, + "_dd.test.is_user_provided_service" : "true", + "env" : "integration-test", + "execution" : "default-testCompile", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "plugin" : "maven-compiler-plugin", + "project" : "Maven Smoke Tests Project", + "runtime-id" : ${content_meta_runtime_id}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version} + }, + "metrics" : { }, + "name" : "Maven_Smoke_Tests_Project_maven_compiler_plugin_default_testCompile", + "parent_id" : ${content_test_session_id}, + "resource" : "Maven_Smoke_Tests_Project_maven_compiler_plugin_default_testCompile", + "service" : "test-maven-service", + "span_id" : ${content_span_id_2}, + "start" : ${content_start_4}, + "trace_id" : ${content_test_session_id} + }, + "type" : "span", + "version" : 1 +}, { + "content" : { + "duration" : ${content_duration_5}, + "error" : 0, + "meta" : { + "_dd.p.tid" : ${content_meta__dd_p_tid_5}, + "_dd.test.is_user_provided_service" : "true", + "env" : "integration-test", + "execution" : "default-resources", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "plugin" : "maven-resources-plugin", + "project" : "Maven Smoke Tests Project", + "runtime-id" : ${content_meta_runtime_id}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version} + }, + "metrics" : { }, + "name" : "Maven_Smoke_Tests_Project_maven_resources_plugin_default_resources", + "parent_id" : ${content_test_session_id}, + "resource" : "Maven_Smoke_Tests_Project_maven_resources_plugin_default_resources", + "service" : "test-maven-service", + "span_id" : ${content_span_id_3}, + "start" : ${content_start_5}, + "trace_id" : ${content_test_session_id} + }, + "type" : "span", + "version" : 1 +}, { + "content" : { + "duration" : ${content_duration_6}, + "error" : 0, + "meta" : { + "_dd.p.tid" : ${content_meta__dd_p_tid_6}, + "_dd.test.is_user_provided_service" : "true", + "env" : "integration-test", + "execution" : "default-testResources", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "plugin" : "maven-resources-plugin", + "project" : "Maven Smoke Tests Project", + "runtime-id" : ${content_meta_runtime_id}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version} + }, + "metrics" : { }, + "name" : "Maven_Smoke_Tests_Project_maven_resources_plugin_default_testResources", + "parent_id" : ${content_test_session_id}, + "resource" : "Maven_Smoke_Tests_Project_maven_resources_plugin_default_testResources", + "service" : "test-maven-service", + "span_id" : ${content_span_id_4}, + "start" : ${content_start_6}, + "trace_id" : ${content_test_session_id} + }, + "type" : "span", + "version" : 1 +}, { + "content" : { + "duration" : ${content_duration_7}, + "error" : 0, + "meta" : { + "_dd.p.tid" : ${content_meta__dd_p_tid_7}, + "_dd.test.is_user_provided_service" : "true", + "_dd.tracer_host" : ${content_meta__dd_tracer_host}, + "ci.workspace_path" : ${content_meta_ci_workspace_path}, + "component" : "junit4", + "env" : "integration-test", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "runtime-id" : ${content_meta_runtime_id_2}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version}, + "span.kind" : "test_suite_end", + "test.framework" : "junit4", + "test.framework_version" : "4.13.2", + "test.module" : "Maven Smoke Tests Project maven-surefire-plugin default-test", + "test.source.file" : "src/test/java/com/example/TestFailed.java", + "test.status" : "fail", + "test.suite" : "com.example.TestFailed", + "test.type" : "test", + "test_session.name" : "mvn -B test" + }, + "metrics" : { + "_dd.host.vcpu_count" : ${content_metrics__dd_host_vcpu_count_3}, + "_dd.profiling.enabled" : 0, + "_dd.trace_span_attribute_schema" : 0, + "process_id" : ${content_metrics_process_id_2}, + "test.source.end" : 14, + "test.source.start" : 7 + }, + "name" : "junit4.test_suite", + "resource" : "com.example.TestFailed", + "service" : "test-maven-service", + "start" : ${content_start_7}, + "test_module_id" : ${content_test_module_id}, + "test_session_id" : ${content_test_session_id}, + "test_suite_id" : ${content_test_suite_id} + }, + "type" : "test_suite_end", + "version" : 1 +}, { + "content" : { + "duration" : ${content_duration_8}, + "error" : 1, + "meta" : { + "_dd.library_capabilities.auto_test_retries" : "1", + "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", + "_dd.library_capabilities.impacted_tests" : "1", + "_dd.library_capabilities.test_impact_analysis" : "1", + "_dd.library_capabilities.test_management.attempt_to_fix" : "5", + "_dd.library_capabilities.test_management.disable" : "1", + "_dd.library_capabilities.test_management.quarantine" : "1", + "_dd.p.tid" : ${content_meta__dd_p_tid_8}, + "_dd.test.is_user_provided_service" : "true", + "_dd.tracer_host" : ${content_meta__dd_tracer_host}, + "ci.workspace_path" : ${content_meta_ci_workspace_path}, + "component" : "junit4", + "env" : "integration-test", + "error.stack" : ${content_meta_error_stack_3}, + "error.type" : "java.lang.AssertionError", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "runtime-id" : ${content_meta_runtime_id_2}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version}, + "span.kind" : "test", + "test.framework" : "junit4", + "test.framework_version" : "4.13.2", + "test.module" : "Maven Smoke Tests Project maven-surefire-plugin default-test", + "test.name" : "test_failed", + "test.source.file" : "src/test/java/com/example/TestFailed.java", + "test.source.method" : "test_failed()V", + "test.status" : "fail", + "test.suite" : "com.example.TestFailed", + "test.type" : "test", + "test_session.name" : "mvn -B test" + }, + "metrics" : { + "_dd.host.vcpu_count" : ${content_metrics__dd_host_vcpu_count_4}, + "_dd.profiling.enabled" : 0, + "_dd.trace_span_attribute_schema" : 0, + "process_id" : ${content_metrics_process_id_2}, + "test.source.end" : 12, + "test.source.start" : 9 + }, + "name" : "junit4.test", + "parent_id" : ${content_parent_id}, + "resource" : "com.example.TestFailed.test_failed", + "service" : "test-maven-service", + "span_id" : ${content_span_id_5}, + "start" : ${content_start_8}, + "test_module_id" : ${content_test_module_id}, + "test_session_id" : ${content_test_session_id}, + "test_suite_id" : ${content_test_suite_id}, + "trace_id" : ${content_trace_id} + }, + "type" : "test", + "version" : 2 +}, { + "content" : { + "duration" : ${content_duration_9}, + "error" : 1, + "meta" : { + "_dd.debug.error.3.file" : "TestFailed.java", + "_dd.debug.error.3.snapshot_id" : ${content_meta__dd_debug_error_3_snapshot_id}, + "_dd.debug.error.exception_hash" : "4e99779ed72c43d4b87387ee7cf4695cd904d2c4853b6054adcacfcfeffa", + "_dd.debug.error.exception_id" : ${content_meta__dd_debug_error_exception_id}, + "_dd.library_capabilities.auto_test_retries" : "1", + "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", + "_dd.library_capabilities.impacted_tests" : "1", + "_dd.library_capabilities.test_impact_analysis" : "1", + "_dd.library_capabilities.test_management.attempt_to_fix" : "5", + "_dd.library_capabilities.test_management.disable" : "1", + "_dd.library_capabilities.test_management.quarantine" : "1", + "_dd.p.tid" : ${content_meta__dd_p_tid_9}, + "_dd.test.is_user_provided_service" : "true", + "_dd.tracer_host" : ${content_meta__dd_tracer_host}, + "ci.workspace_path" : ${content_meta_ci_workspace_path}, + "component" : "junit4", + "env" : "integration-test", + "error.debug_info_captured" : "true", + "error.stack" : ${content_meta_error_stack_4}, + "error.type" : "java.lang.AssertionError", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "runtime-id" : ${content_meta_runtime_id_2}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version}, + "span.kind" : "test", + "test.framework" : "junit4", + "test.framework_version" : "4.13.2", + "test.has_failed_all_retries" : "true", + "test.is_retry" : "true", + "test.module" : "Maven Smoke Tests Project maven-surefire-plugin default-test", + "test.name" : "test_failed", + "test.retry_reason" : "auto_test_retry", + "test.source.file" : "src/test/java/com/example/TestFailed.java", + "test.source.method" : "test_failed()V", + "test.status" : "fail", + "test.suite" : "com.example.TestFailed", + "test.type" : "test", + "test_session.name" : "mvn -B test" + }, + "metrics" : { + "_dd.debug.error.3.line" : 11, + "_dd.host.vcpu_count" : ${content_metrics__dd_host_vcpu_count_5}, + "_dd.profiling.enabled" : 0, + "_dd.trace_span_attribute_schema" : 0, + "process_id" : ${content_metrics_process_id_2}, + "test.source.end" : 12, + "test.source.start" : 9 + }, + "name" : "junit4.test", + "parent_id" : ${content_parent_id}, + "resource" : "com.example.TestFailed.test_failed", + "service" : "test-maven-service", + "span_id" : ${content_span_id_6}, + "start" : ${content_start_9}, + "test_module_id" : ${content_test_module_id}, + "test_session_id" : ${content_test_session_id}, + "test_suite_id" : ${content_test_suite_id}, + "trace_id" : ${content_trace_id_2} + }, + "type" : "test", + "version" : 2 +} ] \ No newline at end of file diff --git a/dd-smoke-tests/maven/src/test/resources/test_failed_maven_failed_test_replay/pom.xml b/dd-smoke-tests/maven/src/test/resources/test_failed_maven_failed_test_replay/pom.xml new file mode 100644 index 00000000000..48f92df3632 --- /dev/null +++ b/dd-smoke-tests/maven/src/test/resources/test_failed_maven_failed_test_replay/pom.xml @@ -0,0 +1,62 @@ + + + + 4.0.0 + com.datadog.ci.test + maven-smoke-test + 1.0-SNAPSHOT + Maven Smoke Tests Project + + + 8 + 8 + UTF-8 + + + + + + + false + + central + Central Repository + https://repo.maven.apache.org/maven2 + + + + + + never + + + false + + central + Central Repository + https://repo.maven.apache.org/maven2 + + + + + + junit + junit + 4.13.2 + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0 + + + + + diff --git a/dd-smoke-tests/maven/src/test/resources/test_failed_maven_failed_test_replay/src/main/java/com/example/Calculator.java b/dd-smoke-tests/maven/src/test/resources/test_failed_maven_failed_test_replay/src/main/java/com/example/Calculator.java new file mode 100644 index 00000000000..3acf064086f --- /dev/null +++ b/dd-smoke-tests/maven/src/test/resources/test_failed_maven_failed_test_replay/src/main/java/com/example/Calculator.java @@ -0,0 +1,11 @@ +package com.example; + +public class Calculator { + public static int add(int a, int b) { + return a + b; + } + + public static int subtract(int a, int b) { + return a - b; + } +} diff --git a/dd-smoke-tests/maven/src/test/resources/test_failed_maven_failed_test_replay/src/test/java/com/example/TestFailed.java b/dd-smoke-tests/maven/src/test/resources/test_failed_maven_failed_test_replay/src/test/java/com/example/TestFailed.java new file mode 100644 index 00000000000..7371566479a --- /dev/null +++ b/dd-smoke-tests/maven/src/test/resources/test_failed_maven_failed_test_replay/src/test/java/com/example/TestFailed.java @@ -0,0 +1,14 @@ +package com.example; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class TestFailed { + + @Test + public void test_failed() { + assertTrue(Calculator.add(2, 2) == 22); + } + +} 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 3663a2bd36e..0f15d93fddd 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 @@ -308,6 +308,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -371,6 +372,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -436,6 +438,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -501,6 +504,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -566,6 +570,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", 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 4c68a894536..3d1ee989665 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 @@ -312,6 +312,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -373,6 +374,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", 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 5f7cce4a596..f72903d44ea 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 @@ -276,6 +276,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -337,6 +338,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_child_service_propagation/events.ftl b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_child_service_propagation/events.ftl index 3b8e1dbfb0f..e1fbc9b86bb 100644 --- a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_child_service_propagation/events.ftl +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_child_service_propagation/events.ftl @@ -274,6 +274,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", 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 822de2307e4..4233a8678f5 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 @@ -328,6 +328,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -378,4 +379,4 @@ }, "type" : "test", "version" : 2 -} ] +} ] \ No newline at end of file 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 5b1e5a20fa6..9d0971cf8f8 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 @@ -312,6 +312,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -373,6 +374,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", 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 4c68a894536..3d1ee989665 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 @@ -312,6 +312,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -373,6 +374,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", 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 4c68a894536..3d1ee989665 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 @@ -312,6 +312,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -373,6 +374,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", 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 8add90e5a8d..5c517b22379 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 @@ -276,6 +276,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -341,6 +342,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -408,6 +410,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -475,6 +478,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -542,6 +546,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -611,6 +616,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -723,6 +729,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", 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 efac85e2237..fdd829eef04 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 @@ -268,6 +268,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", 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 fa8d74caf57..065610b1b8a 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 @@ -365,6 +365,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", "_dd.library_capabilities.test_management.disable" : "1", 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 5d23ecff637..9fa02ca2a7b 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 @@ -312,6 +312,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", @@ -373,6 +374,7 @@ "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", "_dd.library_capabilities.fail_fast_test_order" : "1", + "_dd.library_capabilities.failed_test_replay" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "5", diff --git a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java index ad94c6bed52..bb3218eafb3 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java @@ -208,6 +208,7 @@ public final class ConfigDefaults { static final boolean DEFAULT_DEBUGGER_EXCEPTION_CAPTURE_INTERMEDIATE_SPANS_ENABLED = true; static final int DEFAULT_DEBUGGER_EXCEPTION_MAX_CAPTURED_FRAMES = 3; static final int DEFAULT_DEBUGGER_EXCEPTION_CAPTURE_INTERVAL_SECONDS = 60 * 60; + static final boolean DEFAULT_DEBUGGER_EXCEPTION_ASYNC_CONFIG = true; static final boolean DEFAULT_DISTRIBUTED_DEBUGGER_ENABLED = false; static final boolean DEFAULT_DEBUGGER_SOURCE_FILE_TRACKING_ENABLED = true; diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/CiVisibilityConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/CiVisibilityConfig.java index ad93aa9dfc7..e468bcf6761 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/CiVisibilityConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/CiVisibilityConfig.java @@ -82,6 +82,7 @@ public final class CiVisibilityConfig { public static final String TEST_MANAGEMENT_ENABLED = "test.management.enabled"; public static final String TEST_MANAGEMENT_ATTEMPT_TO_FIX_RETRIES = "test.management.attempt.to.fix.retries"; + public static final String TEST_FAILED_TEST_REPLAY_ENABLED = "test.failed.test.replay.enabled"; /* Git PR info */ public static final String GIT_PULL_REQUEST_BASE_BRANCH = "git.pull.request.base.branch"; diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/DebuggerConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/DebuggerConfig.java index 536821c9a25..f9695695ee0 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/DebuggerConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/DebuggerConfig.java @@ -58,6 +58,8 @@ public final class DebuggerConfig { "exception.replay.capture.max.frames"; public static final String DEBUGGER_EXCEPTION_CAPTURE_INTERVAL_SECONDS = "exception.replay.capture.interval.seconds"; + public static final String DEBUGGER_EXCEPTION_ASYNC_CONFIG = + "internal.exception.replay.async.config"; public static final String DEBUGGER_EXCEPTION_CAPTURE_INTERMEDIATE_SPANS_ENABLED = "exception.replay.capture.intermediate.spans.enabled"; public static final String DISTRIBUTED_DEBUGGER_ENABLED = "distributed.debugger.enabled"; diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index 5ff002d4144..5aae96ac738 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -54,6 +54,7 @@ import static datadog.trace.api.ConfigDefaults.DEFAULT_DB_CLIENT_HOST_SPLIT_BY_INSTANCE_TYPE_SUFFIX; import static datadog.trace.api.ConfigDefaults.DEFAULT_DB_DBM_PROPAGATION_MODE_MODE; import static datadog.trace.api.ConfigDefaults.DEFAULT_DB_DBM_TRACE_PREPARED_STATEMENTS; +import static datadog.trace.api.ConfigDefaults.DEFAULT_DEBUGGER_EXCEPTION_ASYNC_CONFIG; import static datadog.trace.api.ConfigDefaults.DEFAULT_DEBUGGER_EXCEPTION_CAPTURE_INTERMEDIATE_SPANS_ENABLED; import static datadog.trace.api.ConfigDefaults.DEFAULT_DEBUGGER_EXCEPTION_CAPTURE_INTERVAL_SECONDS; import static datadog.trace.api.ConfigDefaults.DEFAULT_DEBUGGER_EXCEPTION_ENABLED; @@ -270,6 +271,7 @@ import static datadog.trace.api.config.CiVisibilityConfig.GIT_COMMIT_HEAD_SHA; import static datadog.trace.api.config.CiVisibilityConfig.GIT_PULL_REQUEST_BASE_BRANCH; import static datadog.trace.api.config.CiVisibilityConfig.GIT_PULL_REQUEST_BASE_BRANCH_SHA; +import static datadog.trace.api.config.CiVisibilityConfig.TEST_FAILED_TEST_REPLAY_ENABLED; import static datadog.trace.api.config.CiVisibilityConfig.TEST_MANAGEMENT_ATTEMPT_TO_FIX_RETRIES; import static datadog.trace.api.config.CiVisibilityConfig.TEST_MANAGEMENT_ENABLED; import static datadog.trace.api.config.CiVisibilityConfig.TEST_SESSION_NAME; @@ -278,6 +280,7 @@ import static datadog.trace.api.config.CrashTrackingConfig.CRASH_TRACKING_TAGS; import static datadog.trace.api.config.CwsConfig.CWS_ENABLED; import static datadog.trace.api.config.CwsConfig.CWS_TLS_REFRESH; +import static datadog.trace.api.config.DebuggerConfig.DEBUGGER_EXCEPTION_ASYNC_CONFIG; import static datadog.trace.api.config.DebuggerConfig.DEBUGGER_EXCEPTION_CAPTURE_INTERMEDIATE_SPANS_ENABLED; import static datadog.trace.api.config.DebuggerConfig.DEBUGGER_EXCEPTION_CAPTURE_INTERVAL_SECONDS; import static datadog.trace.api.config.DebuggerConfig.DEBUGGER_EXCEPTION_CAPTURE_MAX_FRAMES; @@ -302,6 +305,7 @@ import static datadog.trace.api.config.DebuggerConfig.DYNAMIC_INSTRUMENTATION_REDACTED_IDENTIFIERS; import static datadog.trace.api.config.DebuggerConfig.DYNAMIC_INSTRUMENTATION_REDACTED_TYPES; import static datadog.trace.api.config.DebuggerConfig.DYNAMIC_INSTRUMENTATION_REDACTION_EXCLUDED_IDENTIFIERS; +import static datadog.trace.api.config.DebuggerConfig.DYNAMIC_INSTRUMENTATION_SNAPSHOT_URL; import static datadog.trace.api.config.DebuggerConfig.DYNAMIC_INSTRUMENTATION_UPLOAD_BATCH_SIZE; import static datadog.trace.api.config.DebuggerConfig.DYNAMIC_INSTRUMENTATION_UPLOAD_FLUSH_INTERVAL; import static datadog.trace.api.config.DebuggerConfig.DYNAMIC_INSTRUMENTATION_UPLOAD_INTERVAL_SECONDS; @@ -643,6 +647,7 @@ import datadog.trace.api.iast.IastContext; import datadog.trace.api.iast.IastDetectionMode; import datadog.trace.api.iast.telemetry.Verbosity; +import datadog.trace.api.intake.Intake; import datadog.trace.api.naming.SpanNaming; import datadog.trace.api.profiling.ProfilingEnablement; import datadog.trace.api.rum.RumInjectorConfig; @@ -1029,6 +1034,8 @@ public static String getHostName() { private final String gitPullRequestBaseBranch; private final String gitPullRequestBaseBranchSha; private final String gitCommitHeadSha; + private final boolean ciVisibilityFailedTestReplayEnabled; + private boolean ciVisibilityFailedTestReplayActive = false; // propagates setting to DI private final boolean remoteConfigEnabled; private final boolean remoteConfigIntegrityCheckEnabled; @@ -1044,6 +1051,7 @@ public static String getHostName() { private final boolean DBMTracePreparedStatements; private final boolean dynamicInstrumentationEnabled; + private final String dynamicInstrumentationSnapshotUrl; private final int dynamicInstrumentationUploadTimeout; private final int dynamicInstrumentationUploadFlushInterval; private final boolean dynamicInstrumentationClassFileDumpEnabled; @@ -1072,6 +1080,7 @@ public static String getHostName() { private final boolean debuggerExceptionCaptureIntermediateSpansEnabled; private final int debuggerExceptionMaxCapturedFrames; private final int debuggerExceptionCaptureInterval; + private final boolean debuggerExceptionAsyncConfig; private final boolean debuggerCodeOriginEnabled; private final int debuggerCodeOriginMaxUserFrames; private final boolean distributedDebuggerEnabled; @@ -2307,6 +2316,8 @@ PROFILING_DATADOG_PROFILER_ENABLED, isDatadogProfilerSafeInCurrentEnvironment()) gitPullRequestBaseBranch = configProvider.getString(GIT_PULL_REQUEST_BASE_BRANCH); gitPullRequestBaseBranchSha = configProvider.getString(GIT_PULL_REQUEST_BASE_BRANCH_SHA); gitCommitHeadSha = configProvider.getString(GIT_COMMIT_HEAD_SHA); + ciVisibilityFailedTestReplayEnabled = + configProvider.getBoolean(TEST_FAILED_TEST_REPLAY_ENABLED, true); remoteConfigEnabled = configProvider.getBoolean( @@ -2335,6 +2346,8 @@ PROFILING_DATADOG_PROFILER_ENABLED, isDatadogProfilerSafeInCurrentEnvironment()) dynamicInstrumentationEnabled = configProvider.getBoolean( DYNAMIC_INSTRUMENTATION_ENABLED, DEFAULT_DYNAMIC_INSTRUMENTATION_ENABLED); + dynamicInstrumentationSnapshotUrl = + configProvider.getString(DYNAMIC_INSTRUMENTATION_SNAPSHOT_URL); distributedDebuggerEnabled = configProvider.getBoolean( DISTRIBUTED_DEBUGGER_ENABLED, DEFAULT_DISTRIBUTED_DEBUGGER_ENABLED); @@ -2444,6 +2457,9 @@ PROFILING_DATADOG_PROFILER_ENABLED, isDatadogProfilerSafeInCurrentEnvironment()) configProvider.getInteger( DEBUGGER_EXCEPTION_CAPTURE_INTERVAL_SECONDS, DEFAULT_DEBUGGER_EXCEPTION_CAPTURE_INTERVAL_SECONDS); + debuggerExceptionAsyncConfig = + configProvider.getBoolean( + DEBUGGER_EXCEPTION_ASYNC_CONFIG, DEFAULT_DEBUGGER_EXCEPTION_ASYNC_CONFIG); debuggerSourceFileTrackingEnabled = configProvider.getBoolean( DEBUGGER_SOURCE_FILE_TRACKING_ENABLED, DEFAULT_DEBUGGER_SOURCE_FILE_TRACKING_ENABLED); @@ -3933,6 +3949,18 @@ public Integer getCiVisibilityTestManagementAttemptToFixRetries() { return ciVisibilityTestManagementAttemptToFixRetries; } + public boolean isCiVisibilityFailedTestReplayEnabled() { + return ciVisibilityFailedTestReplayEnabled; + } + + public boolean isCiVisibilityFailedTestReplayActive() { + return ciVisibilityFailedTestReplayActive; + } + + public void setCiVisibilityFailedTestReplayActive(boolean enabled) { + ciVisibilityFailedTestReplayActive = enabled; + } + public String getGitPullRequestBaseBranch() { return gitPullRequestBaseBranch; } @@ -4054,7 +4082,7 @@ public boolean isSymbolDatabaseCompressed() { } public boolean isDebuggerExceptionEnabled() { - return debuggerExceptionEnabled; + return debuggerExceptionEnabled || isCiVisibilityFailedTestReplayActive(); } public int getDebuggerMaxExceptionPerSecond() { @@ -4077,6 +4105,10 @@ public int getDebuggerExceptionCaptureInterval() { return debuggerExceptionCaptureInterval; } + public boolean isDebuggerExceptionAsyncConfig() { + return debuggerExceptionAsyncConfig; + } + public boolean isDebuggerCodeOriginEnabled() { return debuggerCodeOriginEnabled; } @@ -4115,11 +4147,21 @@ private String getFinalDebuggerBaseUrl() { } public String getFinalDebuggerSnapshotUrl() { - return getFinalDebuggerBaseUrl() + "/debugger/v1/input"; + if (Strings.isNotBlank(dynamicInstrumentationSnapshotUrl)) { + return dynamicInstrumentationSnapshotUrl; + } else if (isCiVisibilityFailedTestReplayActive() && isCiVisibilityAgentlessEnabled()) { + return Intake.LOGS.getAgentlessUrl(this) + "logs"; + } else { + return getFinalDebuggerBaseUrl() + "/debugger/v1/input"; + } } public String getFinalDebuggerSymDBUrl() { - return getFinalDebuggerBaseUrl() + "/symdb/v1/input"; + if (isCiVisibilityFailedTestReplayActive() && isCiVisibilityAgentlessEnabled()) { + return Intake.LOGS.getAgentlessUrl(this) + "logs"; + } else { + return getFinalDebuggerBaseUrl() + "/symdb/v1/input"; + } } public String getDynamicInstrumentationProbeFile() { diff --git a/internal-api/src/main/java/datadog/trace/api/civisibility/InstrumentationTestBridge.java b/internal-api/src/main/java/datadog/trace/api/civisibility/InstrumentationTestBridge.java index 084cc1a2926..e69f69ac390 100644 --- a/internal-api/src/main/java/datadog/trace/api/civisibility/InstrumentationTestBridge.java +++ b/internal-api/src/main/java/datadog/trace/api/civisibility/InstrumentationTestBridge.java @@ -38,11 +38,19 @@ public static void fireBeforeTestEnd(TestContext testContext) { } } + public static void fireBeforeSuiteEnd() { + for (TestListener testListener : TEST_LISTENERS) { + testListener.beforeSuiteEnd(); + } + } + public static void registerListener(TestListener listener) { TEST_LISTENERS.addIfAbsent(listener); } public interface TestListener { void beforeTestEnd(TestContext testContext); + + void beforeSuiteEnd(); } } 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 index f4ed209ae30..9087e7d5783 100644 --- 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 @@ -6,6 +6,7 @@ public enum LibraryCapability { ATR("auto_test_retries", "1"), IMPACTED("impacted_tests", "1"), FAIL_FAST("fail_fast_test_order", "1"), + FTR("failed_test_replay", "1"), QUARANTINE("test_management.quarantine", "1"), DISABLED("test_management.disable", "1"), ATTEMPT_TO_FIX("test_management.attempt_to_fix", "5"); diff --git a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/CiVisibilityCountMetric.java b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/CiVisibilityCountMetric.java index 868ecde90b8..ccc9d790d68 100644 --- a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/CiVisibilityCountMetric.java +++ b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/CiVisibilityCountMetric.java @@ -13,6 +13,7 @@ import datadog.trace.api.civisibility.telemetry.tag.EventType; import datadog.trace.api.civisibility.telemetry.tag.ExitCode; import datadog.trace.api.civisibility.telemetry.tag.FailFastTestOrderEnabled; +import datadog.trace.api.civisibility.telemetry.tag.FailedTestReplayEnabled; import datadog.trace.api.civisibility.telemetry.tag.FlakyTestRetriesEnabled; import datadog.trace.api.civisibility.telemetry.tag.GitProviderDiscrepant; import datadog.trace.api.civisibility.telemetry.tag.GitProviderExpected; @@ -84,6 +85,7 @@ public enum CiVisibilityCountMetric { IsRetry.class, HasFailedAllRetries.class, RetryReason.class, + FailedTestReplayEnabled.TestMetric.class, IsRum.class, BrowserDriver.class), /** The number of successfully collected code coverages that are empty */ @@ -138,6 +140,7 @@ public enum CiVisibilityCountMetric { ImpactedTestsDetectionEnabled.class, KnownTestsEnabled.class, TestManagementEnabled.class, + FailedTestReplayEnabled.SettingsMetric.class, RequireGit.class), /** The number of requests sent to the itr skippable tests endpoint */ ITR_SKIPPABLE_TESTS_REQUEST("itr_skippable_tests.request", RequestCompressed.class), diff --git a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/FailedTestReplayEnabled.java b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/FailedTestReplayEnabled.java new file mode 100644 index 00000000000..3bca7092725 --- /dev/null +++ b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/FailedTestReplayEnabled.java @@ -0,0 +1,32 @@ +package datadog.trace.api.civisibility.telemetry.tag; + +import datadog.trace.api.civisibility.telemetry.TagValue; + +public abstract class FailedTestReplayEnabled { + public enum SettingsMetric implements TagValue { + TRUE; + + @Override + public String asString() { + return "failed_test_replay_enabled:true"; + } + } + + public enum SessionMetric implements TagValue { + TRUE; + + @Override + public String asString() { + return "has_failed_test_replay:true"; + } + } + + public enum TestMetric implements TagValue { + TRUE; + + @Override + public String asString() { + return "is_failed_test_replay_enabled:true"; + } + } +} diff --git a/internal-api/src/main/java/datadog/trace/api/intake/Intake.java b/internal-api/src/main/java/datadog/trace/api/intake/Intake.java new file mode 100644 index 00000000000..1dab2795d07 --- /dev/null +++ b/internal-api/src/main/java/datadog/trace/api/intake/Intake.java @@ -0,0 +1,52 @@ +package datadog.trace.api.intake; + +import datadog.trace.api.Config; +import java.util.function.Function; + +public enum Intake { + API("api", "v2", Config::isCiVisibilityAgentlessEnabled, Config::getCiVisibilityAgentlessUrl), + LLMOBS_API("api", "v2", Config::isLlmObsAgentlessEnabled, Config::getLlMObsAgentlessUrl), + LOGS( + "http-intake.logs", + "v2", + Config::isAgentlessLogSubmissionEnabled, + Config::getAgentlessLogSubmissionUrl); + + public final String urlPrefix; + public final String version; + public final Function agentlessModeEnabled; + public final Function customUrl; + + Intake( + String urlPrefix, + String version, + Function agentlessModeEnabled, + Function customUrl) { + this.urlPrefix = urlPrefix; + this.version = version; + this.agentlessModeEnabled = agentlessModeEnabled; + this.customUrl = customUrl; + } + + public String getUrlPrefix() { + return urlPrefix; + } + + public String getVersion() { + return version; + } + + public boolean isAgentlessEnabled(Config config) { + return agentlessModeEnabled.apply(config); + } + + public String getAgentlessUrl(Config config) { + String custom = customUrl.apply(config); + if (custom != null && !custom.isEmpty()) { + return String.format("%s/api/%s/", custom, version); + } else { + String site = config.getSite(); + return String.format("https://%s.%s/api/%s/", urlPrefix, site, version); + } + } +} diff --git a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/Tags.java b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/Tags.java index c4bf7527906..573d9026ea0 100644 --- a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/Tags.java +++ b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/Tags.java @@ -107,6 +107,8 @@ public class Tags { public static final String TEST_TEST_MANAGEMENT_ATTEMPT_TO_FIX_PASSED = "test.test_management.attempt_to_fix_passed"; + public static final String ERROR_DEBUG_INFO_CAPTURED = "error.debug_info_captured"; + public static final String CI_PROVIDER_NAME = "ci.provider.name"; public static final String CI_PIPELINE_ID = "ci.pipeline.id"; public static final String CI_PIPELINE_NAME = "ci.pipeline.name"; diff --git a/internal-api/src/test/groovy/datadog/trace/api/intake/IntakeTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/intake/IntakeTest.groovy new file mode 100644 index 00000000000..d8e344feb90 --- /dev/null +++ b/internal-api/src/test/groovy/datadog/trace/api/intake/IntakeTest.groovy @@ -0,0 +1,34 @@ +package datadog.trace.api.intake + +import datadog.trace.api.Config +import datadog.trace.test.util.DDSpecification + +class IntakeTest extends DDSpecification { + def "intake URLs are generated correctly"() { + def config = Stub(Config) + config.getSite() >> "datadoghq.com" + + when: + def apiUrl = Intake.API.getAgentlessUrl(config) + def llmObsUrl = Intake.LLMOBS_API.getAgentlessUrl(config) + def logsUrl = Intake.LOGS.getAgentlessUrl(config) + + then: + apiUrl == "https://api.datadoghq.com/api/v2/" + llmObsUrl == "https://api.datadoghq.com/api/v2/" + logsUrl == "https://http-intake.logs.datadoghq.com/api/v2/" + + when: + config.getCiVisibilityAgentlessUrl() >> "agentless-civis" + config.getLlMObsAgentlessUrl() >> "agentless-llmobs" + config.getAgentlessLogSubmissionUrl() >> "agentless-log" + apiUrl = Intake.API.getAgentlessUrl(config) + llmObsUrl = Intake.LLMOBS_API.getAgentlessUrl(config) + logsUrl = Intake.LOGS.getAgentlessUrl(config) + + then: + apiUrl == "agentless-civis/api/v2/" + llmObsUrl == "agentless-llmobs/api/v2/" + logsUrl == "agentless-log/api/v2/" + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 70bbfb5679f..6a35ad1a354 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -163,6 +163,7 @@ include( ":dd-smoke-tests:jersey-2", ":dd-smoke-tests:jersey-3", ":dd-smoke-tests:jboss-modules", + ":dd-smoke-tests:junit-console", ":dd-smoke-tests:kafka-2", ":dd-smoke-tests:kafka-3", ":dd-smoke-tests:lib-injection",