Skip to content

Commit 7c80dbe

Browse files
Align retry logic for all test framework instrumentations (#8803)
1 parent 80eed8e commit 7c80dbe

File tree

57 files changed

+339
-257
lines changed

Some content is hidden

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

57 files changed

+339
-257
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import static datadog.trace.civisibility.Constants.CI_VISIBILITY_INSTRUMENTATION_NAME;
44

55
import datadog.trace.api.Config;
6+
import datadog.trace.api.civisibility.execution.TestStatus;
67
import datadog.trace.api.civisibility.telemetry.CiVisibilityCountMetric;
78
import datadog.trace.api.civisibility.telemetry.CiVisibilityMetricCollector;
89
import datadog.trace.api.civisibility.telemetry.tag.EventType;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import datadog.trace.api.DDTraceId;
88
import datadog.trace.api.IdGenerationStrategy;
99
import datadog.trace.api.civisibility.CIConstants;
10+
import datadog.trace.api.civisibility.execution.TestStatus;
1011
import datadog.trace.api.civisibility.telemetry.CiVisibilityCountMetric;
1112
import datadog.trace.api.civisibility.telemetry.CiVisibilityMetricCollector;
1213
import datadog.trace.api.civisibility.telemetry.TagValue;

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

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import datadog.trace.api.civisibility.coverage.CoveragePerTestBridge;
1515
import datadog.trace.api.civisibility.coverage.CoverageStore;
1616
import datadog.trace.api.civisibility.domain.TestContext;
17+
import datadog.trace.api.civisibility.execution.TestStatus;
1718
import datadog.trace.api.civisibility.telemetry.CiVisibilityCountMetric;
1819
import datadog.trace.api.civisibility.telemetry.CiVisibilityMetricCollector;
1920
import datadog.trace.api.civisibility.telemetry.TagValue;
@@ -30,6 +31,7 @@
3031
import datadog.trace.api.civisibility.telemetry.tag.SkipReason;
3132
import datadog.trace.api.civisibility.telemetry.tag.TestFrameworkInstrumentation;
3233
import datadog.trace.api.gateway.RequestContextSlot;
34+
import datadog.trace.api.time.SystemTimeSource;
3335
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
3436
import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext;
3537
import datadog.trace.bootstrap.instrumentation.api.AgentTracer;
@@ -45,6 +47,7 @@
4547
import java.lang.reflect.Method;
4648
import java.util.Collection;
4749
import java.util.Collections;
50+
import java.util.concurrent.TimeUnit;
4851
import java.util.function.Consumer;
4952
import javax.annotation.Nonnull;
5053
import javax.annotation.Nullable;
@@ -64,6 +67,7 @@ public class TestImpl implements DDTest {
6467
private final Consumer<AgentSpan> onSpanFinish;
6568
private final TestContext context;
6669
private final TestIdentifier identifier;
70+
private final long startMicros;
6771

6872
public TestImpl(
6973
AgentSpanContext moduleSpanContext,
@@ -111,7 +115,10 @@ public TestImpl(
111115
.withRequestContextData(RequestContextSlot.CI_VISIBILITY, context);
112116

113117
if (startTime != null) {
118+
startMicros = startTime;
114119
spanBuilder = spanBuilder.withStartTimestamp(startTime);
120+
} else {
121+
startMicros = SystemTimeSource.INSTANCE.getCurrentTimeMicros();
115122
}
116123

117124
span = spanBuilder.start();
@@ -201,10 +208,6 @@ public TestIdentifier getIdentifier() {
201208
return identifier;
202209
}
203210

204-
public boolean hasFailed() {
205-
return span.isError();
206-
}
207-
208211
@Override
209212
public void setTag(String key, Object value) {
210213
span.setTag(key, value);
@@ -231,6 +234,17 @@ public void setSkipReason(String skipReason) {
231234
}
232235
}
233236

237+
public TestStatus getStatus() {
238+
return (TestStatus) span.getTag(Tags.TEST_STATUS);
239+
}
240+
241+
public long getDuration(@Nullable Long endMicros) {
242+
if (endMicros == null) {
243+
endMicros = SystemTimeSource.INSTANCE.getCurrentTimeMicros();
244+
}
245+
return TimeUnit.MICROSECONDS.toMillis(endMicros - startMicros);
246+
}
247+
234248
@Override
235249
public void end(@Nullable Long endTime) {
236250
closeOutstandingSpans();

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import datadog.trace.api.civisibility.DDTestSuite;
99
import datadog.trace.api.civisibility.config.LibraryCapability;
1010
import datadog.trace.api.civisibility.coverage.CoverageStore;
11+
import datadog.trace.api.civisibility.execution.TestStatus;
1112
import datadog.trace.api.civisibility.telemetry.CiVisibilityCountMetric;
1213
import datadog.trace.api.civisibility.telemetry.CiVisibilityMetricCollector;
1314
import datadog.trace.api.civisibility.telemetry.tag.EventType;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
import datadog.trace.api.civisibility.domain.BuildSessionSettings;
66
import datadog.trace.api.civisibility.domain.JavaAgent;
77
import datadog.trace.api.civisibility.events.BuildEventsHandler;
8+
import datadog.trace.api.civisibility.execution.TestStatus;
89
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
910
import datadog.trace.bootstrap.instrumentation.api.Tags;
1011
import datadog.trace.civisibility.config.JvmInfo;
1112
import datadog.trace.civisibility.config.JvmInfoFactory;
1213
import datadog.trace.civisibility.domain.BuildSystemModule;
1314
import datadog.trace.civisibility.domain.BuildSystemSession;
14-
import datadog.trace.civisibility.domain.TestStatus;
1515
import java.nio.file.Path;
1616
import java.util.Collection;
1717
import java.util.Map;

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ public void onTestIgnore(
8989
@Nullable String testParameters,
9090
@Nullable Collection<String> categories,
9191
@Nonnull TestSourceData testSourceData,
92-
@Nullable String reason) {
92+
@Nullable String reason,
93+
@Nullable TestExecutionHistory testExecutionHistory) {
9394
// do nothing
9495
}
9596

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

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import datadog.trace.api.civisibility.events.TestEventsHandler;
1111
import datadog.trace.api.civisibility.execution.TestExecutionHistory;
1212
import datadog.trace.api.civisibility.execution.TestExecutionPolicy;
13+
import datadog.trace.api.civisibility.execution.TestStatus;
1314
import datadog.trace.api.civisibility.telemetry.CiVisibilityCountMetric;
1415
import datadog.trace.api.civisibility.telemetry.CiVisibilityMetricCollector;
1516
import datadog.trace.api.civisibility.telemetry.tag.EventType;
@@ -255,11 +256,14 @@ public void onTestFinish(
255256

256257
TestIdentifier thisTest = test.getIdentifier();
257258
if (testExecutionHistory != null) {
258-
if (test.hasFailed() && testExecutionHistory.hasFailedAllRetries()) {
259+
TestStatus testStatus = test.getStatus();
260+
testExecutionHistory.registerExecution(
261+
testStatus != null ? testStatus : TestStatus.skip, test.getDuration(endTime));
262+
263+
if (testExecutionHistory.hasFailedAllRetries()) {
259264
test.setTag(Tags.TEST_HAS_FAILED_ALL_RETRIES, true);
260-
} else if (!test.hasFailed()
261-
&& testModule.isAttemptToFix(thisTest)
262-
&& testExecutionHistory.hasSucceededAllRetries()) {
265+
} else if (testExecutionHistory.hasSucceededAllRetries()
266+
&& testModule.isAttemptToFix(thisTest)) {
263267
test.setTag(Tags.TEST_TEST_MANAGEMENT_ATTEMPT_TO_FIX_PASSED, true);
264268
}
265269
}
@@ -277,7 +281,8 @@ public void onTestIgnore(
277281
final @Nullable String testParameters,
278282
final @Nullable Collection<String> categories,
279283
@Nonnull TestSourceData testSourceData,
280-
final @Nullable String reason) {
284+
final @Nullable String reason,
285+
@Nullable TestExecutionHistory testExecutionHistory) {
281286
onTestStart(
282287
suiteDescriptor,
283288
testDescriptor,
@@ -288,9 +293,9 @@ public void onTestIgnore(
288293
categories,
289294
testSourceData,
290295
null,
291-
null);
296+
testExecutionHistory);
292297
onTestSkip(testDescriptor, reason);
293-
onTestFinish(testDescriptor, null, null);
298+
onTestFinish(testDescriptor, null, testExecutionHistory);
294299
}
295300

296301
@Override

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package datadog.trace.civisibility.execution;
22

33
import datadog.trace.api.civisibility.execution.TestExecutionPolicy;
4+
import datadog.trace.api.civisibility.execution.TestStatus;
45
import datadog.trace.api.civisibility.telemetry.tag.RetryReason;
56
import javax.annotation.Nullable;
67

@@ -12,17 +13,20 @@ public class Regular implements TestExecutionPolicy {
1213
private Regular() {}
1314

1415
@Override
15-
public boolean applicable() {
16-
return false;
16+
public void registerExecution(TestStatus status, long durationMillis) {}
17+
18+
@Override
19+
public boolean wasLastExecution() {
20+
return true;
1721
}
1822

1923
@Override
20-
public boolean suppressFailures() {
24+
public boolean applicable() {
2125
return false;
2226
}
2327

2428
@Override
25-
public boolean retry(boolean successful, long durationMillis) {
29+
public boolean suppressFailures() {
2630
return false;
2731
}
2832

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

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package datadog.trace.civisibility.execution;
22

33
import datadog.trace.api.civisibility.execution.TestExecutionPolicy;
4+
import datadog.trace.api.civisibility.execution.TestStatus;
45
import datadog.trace.api.civisibility.telemetry.tag.RetryReason;
56
import java.util.concurrent.atomic.AtomicInteger;
67
import javax.annotation.Nullable;
@@ -13,42 +14,47 @@ public class RetryUntilSuccessful implements TestExecutionPolicy {
1314
private int executions;
1415
private boolean successfulExecutionSeen;
1516

16-
/** Total execution counter that is shared by all retry policies */
17-
private final AtomicInteger totalExecutions;
17+
/** Total retry counter that is shared by all retry until successful policies (currently ATR) */
18+
private final AtomicInteger totalRetryCount;
1819

1920
public RetryUntilSuccessful(
20-
int maxExecutions, boolean suppressFailures, AtomicInteger totalExecutions) {
21+
int maxExecutions, boolean suppressFailures, AtomicInteger totalRetryCount) {
2122
this.maxExecutions = maxExecutions;
2223
this.suppressFailures = suppressFailures;
23-
this.totalExecutions = totalExecutions;
24+
this.totalRetryCount = totalRetryCount;
2425
this.executions = 0;
2526
}
2627

2728
@Override
28-
public boolean applicable() {
29-
return !currentExecutionIsLast() || suppressFailures;
29+
public void registerExecution(TestStatus status, long durationMillis) {
30+
++executions;
31+
successfulExecutionSeen |= (status != TestStatus.fail);
32+
if (executions > 1) {
33+
totalRetryCount.incrementAndGet();
34+
}
3035
}
3136

3237
@Override
33-
public boolean suppressFailures() {
34-
// do not suppress failures for last execution
35-
// (unless flag to suppress all failures is set)
36-
return !currentExecutionIsLast() || suppressFailures;
38+
public boolean wasLastExecution() {
39+
return successfulExecutionSeen || executions == maxExecutions;
3740
}
3841

3942
private boolean currentExecutionIsLast() {
4043
return executions == maxExecutions - 1;
4144
}
4245

4346
@Override
44-
public boolean retry(boolean successful, long durationMillis) {
45-
successfulExecutionSeen |= successful;
46-
if (!successful && ++executions < maxExecutions) {
47-
totalExecutions.incrementAndGet();
48-
return true;
49-
} else {
50-
return false;
51-
}
47+
public boolean applicable() {
48+
// executions must always be registered, therefore consider it applicable as long as there are
49+
// retries left
50+
return !wasLastExecution();
51+
}
52+
53+
@Override
54+
public boolean suppressFailures() {
55+
// do not suppress failures for last execution
56+
// (unless flag to suppress all failures is set)
57+
return !currentExecutionIsLast() || suppressFailures;
5258
}
5359

5460
@Nullable
@@ -63,7 +69,7 @@ private boolean currentExecutionIsRetry() {
6369

6470
@Override
6571
public boolean hasFailedAllRetries() {
66-
return currentExecutionIsLast() && !successfulExecutionSeen;
72+
return wasLastExecution() && !successfulExecutionSeen;
6773
}
6874

6975
@Override

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

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package datadog.trace.civisibility.execution;
22

33
import datadog.trace.api.civisibility.execution.TestExecutionPolicy;
4+
import datadog.trace.api.civisibility.execution.TestStatus;
45
import datadog.trace.api.civisibility.telemetry.tag.RetryReason;
56
import datadog.trace.civisibility.config.ExecutionsByDuration;
67
import java.util.List;
@@ -13,9 +14,9 @@ public class RunNTimes implements TestExecutionPolicy {
1314
private final List<ExecutionsByDuration> executionsByDuration;
1415
private int executions;
1516
private int maxExecutions;
16-
private int totalExecutionsSeen;
1717
private int successfulExecutionsSeen;
1818
private final RetryReason retryReason;
19+
private TestStatus lastStatus;
1920

2021
public RunNTimes(
2122
List<ExecutionsByDuration> executionsByDuration,
@@ -25,18 +26,32 @@ public RunNTimes(
2526
this.executionsByDuration = executionsByDuration;
2627
this.executions = 0;
2728
this.maxExecutions = getExecutions(0);
28-
this.totalExecutionsSeen = 0;
2929
this.successfulExecutionsSeen = 0;
3030
this.retryReason = retryReason;
3131
}
3232

3333
@Override
34-
public boolean applicable() {
35-
return !currentExecutionIsLast() || suppressFailures();
34+
public void registerExecution(TestStatus status, long durationMillis) {
35+
lastStatus = status;
36+
++executions;
37+
if (status != TestStatus.fail) {
38+
++successfulExecutionsSeen;
39+
}
40+
int maxExecutionsForGivenDuration = getExecutions(durationMillis);
41+
maxExecutions = Math.min(maxExecutions, maxExecutionsForGivenDuration);
3642
}
3743

38-
private boolean currentExecutionIsLast() {
39-
return executions == maxExecutions - 1;
44+
@Override
45+
public boolean wasLastExecution() {
46+
// skipped tests (either by the framework or DD) should not be retried
47+
return lastStatus == TestStatus.skip || executions >= maxExecutions;
48+
}
49+
50+
@Override
51+
public boolean applicable() {
52+
// executions must always be registered, therefore consider it applicable as long as there are
53+
// retries left
54+
return !wasLastExecution();
4055
}
4156

4257
@Override
@@ -53,17 +68,6 @@ private int getExecutions(long durationMillis) {
5368
return 0;
5469
}
5570

56-
@Override
57-
public boolean retry(boolean successful, long durationMillis) {
58-
++totalExecutionsSeen;
59-
if (successful) {
60-
++successfulExecutionsSeen;
61-
}
62-
int maxExecutionsForGivenDuration = getExecutions(durationMillis);
63-
maxExecutions = Math.min(maxExecutions, maxExecutionsForGivenDuration);
64-
return ++executions < maxExecutions;
65-
}
66-
6771
@Nullable
6872
@Override
6973
public RetryReason currentExecutionRetryReason() {
@@ -76,11 +80,11 @@ private boolean currentExecutionIsRetry() {
7680

7781
@Override
7882
public boolean hasFailedAllRetries() {
79-
return currentExecutionIsLast() && successfulExecutionsSeen == 0;
83+
return wasLastExecution() && successfulExecutionsSeen == 0;
8084
}
8185

8286
@Override
8387
public boolean hasSucceededAllRetries() {
84-
return currentExecutionIsLast() && successfulExecutionsSeen == totalExecutionsSeen;
88+
return wasLastExecution() && successfulExecutionsSeen == executions;
8589
}
8690
}

0 commit comments

Comments
 (0)