Skip to content

Commit cb81aca

Browse files
Implement Failed Test Replay (#9214)
1 parent 03d997e commit cb81aca

File tree

113 files changed

+2846
-485
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

113 files changed

+2846
-485
lines changed

.github/CODEOWNERS

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,15 +87,17 @@
8787
/dd-java-agent/instrumentation/maven-surefire/ @DataDog/ci-app-libraries-java
8888
/dd-java-agent/instrumentation/weaver/ @DataDog/ci-app-libraries-java
8989
/dd-smoke-tests/gradle/ @DataDog/ci-app-libraries-java
90+
/dd-smoke-tests/junit-console/ @DataDog/ci-app-libraries-java
9091
/dd-smoke-tests/maven/ @DataDog/ci-app-libraries-java
9192
/internal-api/src/main/java/datadog/trace/api/git/ @DataDog/ci-app-libraries-java
9293
**/civisibility/ @DataDog/ci-app-libraries-java
9394
**/CiVisibility*.java @DataDog/ci-app-libraries-java
9495
**/CiVisibility*.groovy @DataDog/ci-app-libraries-java
9596

9697
# @DataDog/debugger-java (Live Debugger)
97-
/dd-java-agent/agent-debugger/ @DataDog/debugger-java
98-
/dd-smoke-tests/debugger-integration-tests/ @DataDog/debugger-java
98+
/dd-java-agent/agent-debugger/ @DataDog/debugger-java
99+
/dd-smoke-tests/debugger-integration-tests/ @DataDog/debugger-java
100+
/internal-api/src/main/java/datadog/trace/api/debugger/ @DataDog/debugger-java
99101

100102
# @DataDog/data-jobs-monitoring
101103
/dd-java-agent/instrumentation/spark/ @DataDog/data-jobs-monitoring

communication/src/main/java/datadog/communication/BackendApiFactory.java

Lines changed: 3 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
import datadog.communication.http.HttpRetryPolicy;
66
import datadog.communication.http.OkHttpUtils;
77
import datadog.trace.api.Config;
8+
import datadog.trace.api.intake.Intake;
89
import datadog.trace.util.throwable.FatalAgentMisconfigurationError;
9-
import java.util.function.Function;
1010
import javax.annotation.Nullable;
1111
import okhttp3.HttpUrl;
1212
import okhttp3.OkHttpClient;
@@ -28,8 +28,8 @@ public BackendApiFactory(Config config, SharedCommunicationObjects sharedCommuni
2828
public @Nullable BackendApi createBackendApi(Intake intake) {
2929
HttpRetryPolicy.Factory retryPolicyFactory = new HttpRetryPolicy.Factory(5, 100, 2.0, true);
3030

31-
if (intake.agentlessModeEnabled.apply(config)) {
32-
HttpUrl agentlessUrl = getAgentlessUrl(intake);
31+
if (intake.isAgentlessEnabled(config)) {
32+
HttpUrl agentlessUrl = HttpUrl.get(intake.getAgentlessUrl(config));
3333
String apiKey = config.getApiKey();
3434
if (apiKey == null || apiKey.isEmpty()) {
3535
throw new FatalAgentMisconfigurationError(
@@ -58,46 +58,4 @@ public BackendApiFactory(Config config, SharedCommunicationObjects sharedCommuni
5858
+ "and agent does not support EVP proxy");
5959
return null;
6060
}
61-
62-
private HttpUrl getAgentlessUrl(Intake intake) {
63-
String customUrl = intake.customUrl.apply(config);
64-
if (customUrl != null && !customUrl.isEmpty()) {
65-
return HttpUrl.get(String.format("%s/api/%s/", customUrl, intake.version));
66-
} else {
67-
String site = config.getSite();
68-
return HttpUrl.get(
69-
String.format("https://%s.%s/api/%s/", intake.urlPrefix, site, intake.version));
70-
}
71-
}
72-
73-
public enum Intake {
74-
API("api", "v2", Config::isCiVisibilityAgentlessEnabled, Config::getCiVisibilityAgentlessUrl),
75-
LLMOBS_API("api", "v2", Config::isLlmObsAgentlessEnabled, Config::getLlMObsAgentlessUrl),
76-
LOGS(
77-
"http-intake.logs",
78-
"v2",
79-
Config::isAgentlessLogSubmissionEnabled,
80-
Config::getAgentlessLogSubmissionUrl),
81-
CI_INTAKE(
82-
"ci-intake",
83-
"v2",
84-
Config::isCiVisibilityAgentlessEnabled,
85-
Config::getCiVisibilityIntakeAgentlessUrl);
86-
87-
public final String urlPrefix;
88-
public final String version;
89-
public final Function<Config, Boolean> agentlessModeEnabled;
90-
public final Function<Config, String> customUrl;
91-
92-
Intake(
93-
String urlPrefix,
94-
String version,
95-
Function<Config, Boolean> agentlessModeEnabled,
96-
Function<Config, String> customUrl) {
97-
this.urlPrefix = urlPrefix;
98-
this.version = version;
99-
this.agentlessModeEnabled = agentlessModeEnabled;
100-
this.customUrl = customUrl;
101-
}
102-
}
10361
}

dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1308,10 +1308,6 @@ && isExplicitlyDisabled(TraceInstrumentationConfig.CODE_ORIGIN_FOR_SPANS_ENABLED
13081308
&& isExplicitlyDisabled(DebuggerConfig.DISTRIBUTED_DEBUGGER_ENABLED)) {
13091309
return;
13101310
}
1311-
if (!remoteConfigEnabled) {
1312-
log.warn("Cannot enable Dynamic Instrumentation because Remote Configuration is not enabled");
1313-
return;
1314-
}
13151311
startDebuggerAgent(inst, scoClass, sco);
13161312
}
13171313

dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/CiVisibilityServices.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import datadog.trace.api.civisibility.telemetry.CiVisibilityMetricCollector;
1515
import datadog.trace.api.civisibility.telemetry.tag.Command;
1616
import datadog.trace.api.git.GitInfoProvider;
17+
import datadog.trace.api.intake.Intake;
1718
import datadog.trace.civisibility.ci.CIProviderInfoFactory;
1819
import datadog.trace.civisibility.ci.env.CiEnvironment;
1920
import datadog.trace.civisibility.ci.env.CiEnvironmentImpl;
@@ -84,10 +85,8 @@ public class CiVisibilityServices {
8485
this.processHierarchy = new ProcessHierarchy();
8586
this.config = config;
8687
this.metricCollector = metricCollector;
87-
this.backendApi =
88-
new BackendApiFactory(config, sco).createBackendApi(BackendApiFactory.Intake.API);
89-
this.ciIntake =
90-
new BackendApiFactory(config, sco).createBackendApi(BackendApiFactory.Intake.CI_INTAKE);
88+
this.backendApi = new BackendApiFactory(config, sco).createBackendApi(Intake.API);
89+
this.ciIntake = new BackendApiFactory(config, sco).createBackendApi(Intake.CI_INTAKE);
9190
this.jvmInfoFactory = new CachingJvmInfoFactory(config, new JvmInfoFactoryImpl());
9291
this.gitClientFactory = buildGitClientFactory(config, metricCollector);
9392

dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/CiVisibilitySystem.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import datadog.trace.api.civisibility.events.TestEventsHandler;
1414
import datadog.trace.api.civisibility.telemetry.CiVisibilityMetricCollector;
1515
import datadog.trace.api.civisibility.telemetry.NoOpMetricCollector;
16+
import datadog.trace.api.debugger.DebuggerConfigBridge;
17+
import datadog.trace.api.debugger.DebuggerConfigUpdate;
1618
import datadog.trace.api.git.GitInfoProvider;
1719
import datadog.trace.bootstrap.ContextStore;
1820
import datadog.trace.bootstrap.instrumentation.api.AgentTracer;
@@ -102,6 +104,10 @@ public static void start(Instrumentation inst, SharedCommunicationObjects sco) {
102104
inst.addTransformer(new CoverageClassTransformer(instrumentationFilter));
103105
}
104106

107+
if (executionSettings.isFailedTestReplayEnabled()) {
108+
DebuggerConfigBridge.updateConfig(new DebuggerConfigUpdate(null, true, null, null));
109+
}
110+
105111
CiVisibilityCoverageServices.Child coverageServices =
106112
new CiVisibilityCoverageServices.Child(services, repoServices, executionSettings);
107113
TestEventsHandlerFactory testEventsHandlerFactory =

dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/CiVisibilitySettings.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public class CiVisibilitySettings {
1818
false,
1919
false,
2020
false,
21+
false,
2122
EarlyFlakeDetectionSettings.DEFAULT,
2223
TestManagementSettings.DEFAULT,
2324
null);
@@ -30,6 +31,7 @@ public class CiVisibilitySettings {
3031
private final boolean impactedTestsDetectionEnabled;
3132
private final boolean knownTestsEnabled;
3233
private final boolean coverageReportUploadEnabled;
34+
private final boolean failedTestReplayEnabled;
3335
private final EarlyFlakeDetectionSettings earlyFlakeDetectionSettings;
3436
private final TestManagementSettings testManagementSettings;
3537
@Nullable private final String defaultBranch;
@@ -43,6 +45,7 @@ public class CiVisibilitySettings {
4345
boolean impactedTestsDetectionEnabled,
4446
boolean knownTestsEnabled,
4547
boolean coverageReportUploadEnabled,
48+
boolean failedTestReplayEnabled,
4649
EarlyFlakeDetectionSettings earlyFlakeDetectionSettings,
4750
TestManagementSettings testManagementSettings,
4851
@Nullable String defaultBranch) {
@@ -54,6 +57,7 @@ public class CiVisibilitySettings {
5457
this.impactedTestsDetectionEnabled = impactedTestsDetectionEnabled;
5558
this.knownTestsEnabled = knownTestsEnabled;
5659
this.coverageReportUploadEnabled = coverageReportUploadEnabled;
60+
this.failedTestReplayEnabled = failedTestReplayEnabled;
5761
this.earlyFlakeDetectionSettings = earlyFlakeDetectionSettings;
5862
this.testManagementSettings = testManagementSettings;
5963
this.defaultBranch = defaultBranch;
@@ -91,6 +95,10 @@ public boolean isCoverageReportUploadEnabled() {
9195
return coverageReportUploadEnabled;
9296
}
9397

98+
public boolean isFailedTestReplayEnabled() {
99+
return failedTestReplayEnabled;
100+
}
101+
94102
public EarlyFlakeDetectionSettings getEarlyFlakeDetectionSettings() {
95103
return earlyFlakeDetectionSettings;
96104
}
@@ -121,6 +129,7 @@ public boolean equals(Object o) {
121129
&& impactedTestsDetectionEnabled == that.impactedTestsDetectionEnabled
122130
&& knownTestsEnabled == that.knownTestsEnabled
123131
&& coverageReportUploadEnabled == that.coverageReportUploadEnabled
132+
&& failedTestReplayEnabled == that.failedTestReplayEnabled
124133
&& Objects.equals(earlyFlakeDetectionSettings, that.earlyFlakeDetectionSettings)
125134
&& Objects.equals(testManagementSettings, that.testManagementSettings)
126135
&& Objects.equals(defaultBranch, that.defaultBranch);
@@ -137,6 +146,7 @@ public int hashCode() {
137146
impactedTestsDetectionEnabled,
138147
knownTestsEnabled,
139148
coverageReportUploadEnabled,
149+
failedTestReplayEnabled,
140150
earlyFlakeDetectionSettings,
141151
testManagementSettings,
142152
defaultBranch);
@@ -165,6 +175,7 @@ public CiVisibilitySettings fromJson(Map<String, Object> json) {
165175
getBoolean(json, "impacted_tests_enabled", false),
166176
getBoolean(json, "known_tests_enabled", false),
167177
getBoolean(json, "coverage_report_upload_enabled", false),
178+
getBoolean(json, "di_enabled", false),
168179
EarlyFlakeDetectionSettings.JsonAdapter.INSTANCE.fromJson(
169180
(Map<String, Object>) json.get("early_flake_detection")),
170181
TestManagementSettings.JsonAdapter.INSTANCE.fromJson(

dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ConfigurationApiImpl.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import datadog.trace.api.civisibility.telemetry.CiVisibilityMetricCollector;
1818
import datadog.trace.api.civisibility.telemetry.tag.CoverageEnabled;
1919
import datadog.trace.api.civisibility.telemetry.tag.EarlyFlakeDetectionEnabled;
20+
import datadog.trace.api.civisibility.telemetry.tag.FailedTestReplayEnabled;
2021
import datadog.trace.api.civisibility.telemetry.tag.FlakyTestRetriesEnabled;
2122
import datadog.trace.api.civisibility.telemetry.tag.ImpactedTestsDetectionEnabled;
2223
import datadog.trace.api.civisibility.telemetry.tag.ItrEnabled;
@@ -156,6 +157,7 @@ public CiVisibilitySettings getSettings(TracerEnvironment tracerEnvironment) thr
156157
settings.isKnownTestsEnabled() ? KnownTestsEnabled.TRUE : null,
157158
settings.isImpactedTestsDetectionEnabled() ? ImpactedTestsDetectionEnabled.TRUE : null,
158159
settings.getTestManagementSettings().isEnabled() ? TestManagementEnabled.TRUE : null,
160+
settings.isFailedTestReplayEnabled() ? FailedTestReplayEnabled.SettingsMetric.TRUE : null,
159161
settings.isGitUploadRequired() ? RequireGit.TRUE : null);
160162

161163
return settings;

dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ExecutionSettings.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public class ExecutionSettings {
2727
false,
2828
false,
2929
false,
30+
false,
3031
EarlyFlakeDetectionSettings.DEFAULT,
3132
TestManagementSettings.DEFAULT,
3233
null,
@@ -45,6 +46,7 @@ public class ExecutionSettings {
4546
private final boolean flakyTestRetriesEnabled;
4647
private final boolean impactedTestsDetectionEnabled;
4748
private final boolean codeCoverageReportUploadEnabled;
49+
private final boolean failedTestReplayEnabled;
4850
@Nonnull private final EarlyFlakeDetectionSettings earlyFlakeDetectionSettings;
4951
@Nonnull private final TestManagementSettings testManagementSettings;
5052
@Nullable private final String itrCorrelationId;
@@ -61,6 +63,7 @@ public ExecutionSettings(
6163
boolean flakyTestRetriesEnabled,
6264
boolean impactedTestsDetectionEnabled,
6365
boolean codeCoverageReportUploadEnabled,
66+
boolean failedTestReplayEnabled,
6467
@Nonnull EarlyFlakeDetectionSettings earlyFlakeDetectionSettings,
6568
@Nonnull TestManagementSettings testManagementSettings,
6669
@Nullable String itrCorrelationId,
@@ -78,6 +81,7 @@ public ExecutionSettings(
7881
this.flakyTestRetriesEnabled = flakyTestRetriesEnabled;
7982
this.impactedTestsDetectionEnabled = impactedTestsDetectionEnabled;
8083
this.codeCoverageReportUploadEnabled = codeCoverageReportUploadEnabled;
84+
this.failedTestReplayEnabled = failedTestReplayEnabled;
8185
this.earlyFlakeDetectionSettings = earlyFlakeDetectionSettings;
8286
this.testManagementSettings = testManagementSettings;
8387
this.itrCorrelationId = itrCorrelationId;
@@ -115,6 +119,7 @@ private ExecutionSettings(
115119
boolean flakyTestRetriesEnabled,
116120
boolean impactedTestsDetectionEnabled,
117121
boolean codeCoverageReportUploadEnabled,
122+
boolean failedTestReplayEnabled,
118123
@Nonnull EarlyFlakeDetectionSettings earlyFlakeDetectionSettings,
119124
@Nonnull TestManagementSettings testManagementSettings,
120125
@Nullable String itrCorrelationId,
@@ -129,6 +134,7 @@ private ExecutionSettings(
129134
this.flakyTestRetriesEnabled = flakyTestRetriesEnabled;
130135
this.impactedTestsDetectionEnabled = impactedTestsDetectionEnabled;
131136
this.codeCoverageReportUploadEnabled = codeCoverageReportUploadEnabled;
137+
this.failedTestReplayEnabled = failedTestReplayEnabled;
132138
this.earlyFlakeDetectionSettings = earlyFlakeDetectionSettings;
133139
this.testManagementSettings = testManagementSettings;
134140
this.itrCorrelationId = itrCorrelationId;
@@ -167,6 +173,10 @@ public boolean isCodeCoverageReportUploadEnabled() {
167173
return codeCoverageReportUploadEnabled;
168174
}
169175

176+
public boolean isFailedTestReplayEnabled() {
177+
return failedTestReplayEnabled;
178+
}
179+
170180
@Nonnull
171181
public EarlyFlakeDetectionSettings getEarlyFlakeDetectionSettings() {
172182
return earlyFlakeDetectionSettings;
@@ -254,6 +264,7 @@ public boolean equals(Object o) {
254264
&& flakyTestRetriesEnabled == that.flakyTestRetriesEnabled
255265
&& impactedTestsDetectionEnabled == that.impactedTestsDetectionEnabled
256266
&& codeCoverageReportUploadEnabled == that.codeCoverageReportUploadEnabled
267+
&& failedTestReplayEnabled == that.failedTestReplayEnabled
257268
&& Objects.equals(earlyFlakeDetectionSettings, that.earlyFlakeDetectionSettings)
258269
&& Objects.equals(testManagementSettings, that.testManagementSettings)
259270
&& Objects.equals(itrCorrelationId, that.itrCorrelationId)
@@ -273,6 +284,7 @@ public int hashCode() {
273284
flakyTestRetriesEnabled,
274285
impactedTestsDetectionEnabled,
275286
codeCoverageReportUploadEnabled,
287+
failedTestReplayEnabled,
276288
earlyFlakeDetectionSettings,
277289
testManagementSettings,
278290
itrCorrelationId,
@@ -291,6 +303,7 @@ public static class Serializer {
291303
private static final int FLAKY_TEST_RETRIES_ENABLED_FLAG = 8;
292304
private static final int IMPACTED_TESTS_DETECTION_ENABLED_FLAG = 16;
293305
private static final int CODE_COVERAGE_REPORT_UPLOAD_ENABLED_FLAG = 32;
306+
private static final int FAILED_TEST_REPLAY_ENABLED_FLAG = 64;
294307

295308
public static ByteBuffer serialize(ExecutionSettings settings) {
296309
datadog.trace.civisibility.ipc.serialization.Serializer s =
@@ -307,7 +320,8 @@ public static ByteBuffer serialize(ExecutionSettings settings) {
307320
: 0)
308321
| (settings.codeCoverageReportUploadEnabled
309322
? CODE_COVERAGE_REPORT_UPLOAD_ENABLED_FLAG
310-
: 0));
323+
: 0)
324+
| (settings.failedTestReplayEnabled ? FAILED_TEST_REPLAY_ENABLED_FLAG : 0));
311325
s.write(flags);
312326

313327
EarlyFlakeDetectionSettings.Serializer.serialize(s, settings.earlyFlakeDetectionSettings);
@@ -348,6 +362,7 @@ public static ExecutionSettings deserialize(ByteBuffer buffer) {
348362
boolean impactedTestsDetectionEnabled = (flags & IMPACTED_TESTS_DETECTION_ENABLED_FLAG) != 0;
349363
boolean codeCoverageReportUploadEnabled =
350364
(flags & CODE_COVERAGE_REPORT_UPLOAD_ENABLED_FLAG) != 0;
365+
boolean failedTestReplayEnabled = (flags & FAILED_TEST_REPLAY_ENABLED_FLAG) != 0;
351366

352367
EarlyFlakeDetectionSettings earlyFlakeDetectionSettings =
353368
EarlyFlakeDetectionSettings.Serializer.deserialize(buffer);
@@ -391,6 +406,7 @@ public static ExecutionSettings deserialize(ByteBuffer buffer) {
391406
flakyTestRetriesEnabled,
392407
impactedTestsDetectionEnabled,
393408
codeCoverageReportUploadEnabled,
409+
failedTestReplayEnabled,
394410
earlyFlakeDetectionSettings,
395411
testManagementSettings,
396412
itrCorrelationId,

dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/config/ExecutionSettingsFactoryImpl.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,11 @@ private Map<String, ExecutionSettings> doCreate(
182182
settings,
183183
CiVisibilitySettings::isCoverageReportUploadEnabled,
184184
Config::isCiVisibilityCodeCoverageReportUploadEnabled);
185+
boolean failedTestReplayEnabled =
186+
isFeatureEnabled(
187+
settings,
188+
CiVisibilitySettings::isFailedTestReplayEnabled,
189+
Config::isCiVisibilityFailedTestReplayEnabled);
185190

186191
TestManagementSettings testManagementSettings = getTestManagementSettings(settings);
187192

@@ -195,7 +200,8 @@ private Map<String, ExecutionSettings> doCreate(
195200
+ "Known tests marking - {},\n"
196201
+ "Auto test retries - {},\n"
197202
+ "Test Management - {},\n"
198-
+ "Code coverage report upload - {}",
203+
+ "Code coverage report upload - {},\n"
204+
+ "Failed Test Replay - {}",
199205
repositoryRoot,
200206
tracerEnvironment.getConfigurations().getRuntimeName(),
201207
tracerEnvironment.getConfigurations().getRuntimeVersion(),
@@ -208,7 +214,8 @@ private Map<String, ExecutionSettings> doCreate(
208214
knownTestsRequest,
209215
flakyTestRetriesEnabled,
210216
testManagementSettings.isEnabled(),
211-
codeCoverageReportUpload);
217+
codeCoverageReportUpload,
218+
failedTestReplayEnabled);
212219

213220
Future<SkippableTests> skippableTestsFuture =
214221
executor.submit(() -> getSkippableTests(tracerEnvironment, itrEnabled));
@@ -261,6 +268,7 @@ private Map<String, ExecutionSettings> doCreate(
261268
flakyTestRetriesEnabled,
262269
impactedTestsEnabled,
263270
codeCoverageReportUpload,
271+
failedTestReplayEnabled,
264272
earlyFlakeDetectionEnabled
265273
? settings.getEarlyFlakeDetectionSettings()
266274
: EarlyFlakeDetectionSettings.DEFAULT,

0 commit comments

Comments
 (0)