4
4
import datadog .trace .api .civisibility .CIConstants ;
5
5
import datadog .trace .api .civisibility .CiVisibilityWellKnownTags ;
6
6
import datadog .trace .api .civisibility .config .TestIdentifier ;
7
- import datadog .trace .api .civisibility .config .TestMetadata ;
8
7
import datadog .trace .api .git .GitInfo ;
9
8
import datadog .trace .api .git .GitInfoProvider ;
10
9
import datadog .trace .civisibility .ci .PullRequestInfo ;
14
13
import datadog .trace .civisibility .git .tree .GitClient ;
15
14
import datadog .trace .civisibility .git .tree .GitDataUploader ;
16
15
import datadog .trace .civisibility .git .tree .GitRepoUnshallow ;
17
- import java .nio .file .Path ;
18
16
import java .nio .file .Paths ;
19
- import java .util .BitSet ;
20
17
import java .util .Collection ;
21
18
import java .util .Collections ;
22
19
import java .util .HashMap ;
23
20
import java .util .HashSet ;
24
21
import java .util .Map ;
22
+ import java .util .Objects ;
25
23
import java .util .Set ;
24
+ import java .util .concurrent .ExecutionException ;
25
+ import java .util .concurrent .ExecutorService ;
26
+ import java .util .concurrent .Executors ;
27
+ import java .util .concurrent .Future ;
28
+ import java .util .concurrent .ThreadFactory ;
26
29
import java .util .concurrent .TimeUnit ;
27
30
import java .util .function .Function ;
28
31
import javax .annotation .Nonnull ;
33
36
public class ExecutionSettingsFactoryImpl implements ExecutionSettingsFactory {
34
37
35
38
private static final Logger LOGGER = LoggerFactory .getLogger (ExecutionSettingsFactoryImpl .class );
39
+
36
40
private static final String TEST_CONFIGURATION_TAG_PREFIX = "test.configuration." ;
37
41
42
+ private static final ThreadFactory THREAD_FACTORY = r -> new Thread (null , r , "dd-ci-vis-config" );
43
+
38
44
/**
39
45
* A workaround for bulk-requesting module settings. For any module that has no settings that are
40
46
* exclusive to it (i.e. that has no skippable/flaky/known tests), the settings will be under this
@@ -113,9 +119,31 @@ private TracerEnvironment buildTracerEnvironment(
113
119
.build ();
114
120
}
115
121
116
- private @ Nonnull Map <String , ExecutionSettings > create (TracerEnvironment tracerEnvironment ) {
122
+ @ Nonnull
123
+ private Map <String , ExecutionSettings > create (TracerEnvironment tracerEnvironment ) {
117
124
CiVisibilitySettings settings = getCiVisibilitySettings (tracerEnvironment );
125
+ ExecutorService settingsExecutor = Executors .newCachedThreadPool (THREAD_FACTORY );
126
+ try {
127
+ return doCreate (tracerEnvironment , settings , settingsExecutor );
128
+
129
+ } catch (InterruptedException e ) {
130
+ Thread .currentThread ().interrupt ();
131
+ LOGGER .error ("Interrupted while creating execution settings" );
132
+ return Collections .singletonMap (DEFAULT_SETTINGS , ExecutionSettings .EMPTY );
118
133
134
+ } catch (ExecutionException e ) {
135
+ LOGGER .error ("Error while creating execution settings" , e );
136
+ return Collections .singletonMap (DEFAULT_SETTINGS , ExecutionSettings .EMPTY );
137
+
138
+ } finally {
139
+ settingsExecutor .shutdownNow ();
140
+ }
141
+ }
142
+
143
+ @ Nonnull
144
+ private Map <String , ExecutionSettings > doCreate (
145
+ TracerEnvironment tracerEnvironment , CiVisibilitySettings settings , ExecutorService executor )
146
+ throws InterruptedException , ExecutionException {
119
147
boolean itrEnabled =
120
148
isFeatureEnabled (
121
149
settings , CiVisibilitySettings ::isItrEnabled , Config ::isCiVisibilityItrEnabled );
@@ -134,7 +162,7 @@ private TracerEnvironment buildTracerEnvironment(
134
162
settings ,
135
163
CiVisibilitySettings ::isFlakyTestRetriesEnabled ,
136
164
Config ::isCiVisibilityFlakyRetryEnabled );
137
- boolean impactedTestsDetectionEnabled =
165
+ boolean impactedTestsEnabled =
138
166
isFeatureEnabled (
139
167
settings ,
140
168
CiVisibilitySettings ::isImpactedTestsDetectionEnabled ,
@@ -167,46 +195,27 @@ private TracerEnvironment buildTracerEnvironment(
167
195
codeCoverageEnabled ,
168
196
testSkippingEnabled ,
169
197
earlyFlakeDetectionEnabled ,
170
- impactedTestsDetectionEnabled ,
198
+ impactedTestsEnabled ,
171
199
knownTestsRequest ,
172
200
flakyTestRetriesEnabled );
173
201
174
- String itrCorrelationId = null ;
175
- Map <String , Map <TestIdentifier , TestMetadata >> skippableTestIdentifiers =
176
- Collections .emptyMap ();
177
- Map <String , BitSet > skippableTestsCoverage = null ;
178
- if (itrEnabled && repositoryRoot != null ) {
179
- SkippableTests skippableTests =
180
- getSkippableTests (Paths .get (repositoryRoot ), tracerEnvironment );
181
- if (skippableTests != null ) {
182
- itrCorrelationId = skippableTests .getCorrelationId ();
183
- skippableTestIdentifiers = skippableTests .getIdentifiersByModule ();
184
- skippableTestsCoverage = skippableTests .getCoveredLinesByRelativeSourcePath ();
185
- }
186
- }
187
-
188
- Map <String , Collection <TestIdentifier >> flakyTestsByModule =
189
- flakyTestRetriesEnabled && config .isCiVisibilityFlakyRetryOnlyKnownFlakes ()
190
- || CIConstants .FAIL_FAST_TEST_ORDER .equalsIgnoreCase (
191
- config .getCiVisibilityTestOrder ())
192
- ? getFlakyTestsByModule (tracerEnvironment )
193
- : null ;
194
-
195
- Map <String , Collection <TestIdentifier >> knownTestsByModule =
196
- knownTestsRequest ? getKnownTestsByModule (tracerEnvironment ) : null ;
197
-
198
- Set <String > moduleNames = new HashSet <>(Collections .singleton (DEFAULT_SETTINGS ));
199
- moduleNames .addAll (skippableTestIdentifiers .keySet ());
200
- if (flakyTestsByModule != null ) {
201
- moduleNames .addAll (flakyTestsByModule .keySet ());
202
- }
203
- if (knownTestsByModule != null ) {
204
- moduleNames .addAll (knownTestsByModule .keySet ());
205
- }
202
+ Future <SkippableTests > skippableTestsFuture =
203
+ executor .submit (() -> getSkippableTests (tracerEnvironment , itrEnabled ));
204
+ Future <Map <String , Collection <TestIdentifier >>> flakyTestsFuture =
205
+ executor .submit (() -> getFlakyTestsByModule (tracerEnvironment , flakyTestRetriesEnabled ));
206
+ Future <Map <String , Collection <TestIdentifier >>> knownTestsFuture =
207
+ executor .submit (() -> getKnownTestsByModule (tracerEnvironment , knownTestsRequest ));
208
+ Future <Diff > pullRequestDiffFuture =
209
+ executor .submit (() -> getPullRequestDiff (tracerEnvironment , impactedTestsEnabled ));
206
210
207
- Diff pullRequestDiff = getPullRequestDiff (impactedTestsDetectionEnabled , tracerEnvironment );
211
+ SkippableTests skippableTests = skippableTestsFuture .get ();
212
+ Map <String , Collection <TestIdentifier >> flakyTestsByModule = flakyTestsFuture .get ();
213
+ Map <String , Collection <TestIdentifier >> knownTestsByModule = knownTestsFuture .get ();
214
+ Diff pullRequestDiff = pullRequestDiffFuture .get ();
208
215
209
216
Map <String , ExecutionSettings > settingsByModule = new HashMap <>();
217
+ Set <String > moduleNames =
218
+ getModuleNames (skippableTests , flakyTestsByModule , knownTestsByModule );
210
219
for (String moduleName : moduleNames ) {
211
220
settingsByModule .put (
212
221
moduleName ,
@@ -215,13 +224,15 @@ private TracerEnvironment buildTracerEnvironment(
215
224
codeCoverageEnabled ,
216
225
testSkippingEnabled ,
217
226
flakyTestRetriesEnabled ,
218
- impactedTestsDetectionEnabled ,
227
+ impactedTestsEnabled ,
219
228
earlyFlakeDetectionEnabled
220
229
? settings .getEarlyFlakeDetectionSettings ()
221
230
: EarlyFlakeDetectionSettings .DEFAULT ,
222
- itrCorrelationId ,
223
- skippableTestIdentifiers .getOrDefault (moduleName , Collections .emptyMap ()),
224
- skippableTestsCoverage ,
231
+ skippableTests .getCorrelationId (),
232
+ skippableTests
233
+ .getIdentifiersByModule ()
234
+ .getOrDefault (moduleName , Collections .emptyMap ()),
235
+ skippableTests .getCoveredLinesByRelativeSourcePath (),
225
236
flakyTestsByModule != null
226
237
? flakyTestsByModule .getOrDefault (moduleName , Collections .emptyList ())
227
238
: null ,
@@ -258,47 +269,66 @@ private boolean isFeatureEnabled(
258
269
return remoteSetting .apply (ciVisibilitySettings ) && killSwitch .apply (config );
259
270
}
260
271
261
- @ Nullable
272
+ @ Nonnull
262
273
private SkippableTests getSkippableTests (
263
- Path repositoryRoot , TracerEnvironment tracerEnvironment ) {
274
+ TracerEnvironment tracerEnvironment , boolean itrEnabled ) {
275
+ if (!itrEnabled || repositoryRoot == null ) {
276
+ return SkippableTests .EMPTY ;
277
+ }
264
278
try {
265
279
// ensure git data upload is finished before asking for tests
266
280
gitDataUploader
267
281
.startOrObserveGitDataUpload ()
268
282
.get (config .getCiVisibilityGitUploadTimeoutMillis (), TimeUnit .MILLISECONDS );
269
283
270
284
SkippableTests skippableTests = configurationApi .getSkippableTests (tracerEnvironment );
271
- LOGGER .debug (
272
- "Received {} skippable tests in total for {}" ,
273
- skippableTests .getIdentifiersByModule ().size (),
274
- repositoryRoot );
285
+
286
+ if (LOGGER .isDebugEnabled ()) {
287
+ int totalSkippableTests =
288
+ skippableTests .getIdentifiersByModule ().values ().stream ()
289
+ .filter (Objects ::nonNull )
290
+ .mapToInt (Map ::size )
291
+ .sum ();
292
+ LOGGER .debug (
293
+ "Received {} skippable tests in total for {}" ,
294
+ totalSkippableTests ,
295
+ Paths .get (repositoryRoot ));
296
+ }
275
297
276
298
return skippableTests ;
277
299
278
300
} catch (InterruptedException e ) {
279
301
Thread .currentThread ().interrupt ();
280
302
LOGGER .error ("Interrupted while waiting for git data upload" , e );
281
- return null ;
303
+ return SkippableTests . EMPTY ;
282
304
283
305
} catch (Exception e ) {
284
306
LOGGER .error ("Could not obtain list of skippable tests, will proceed without skipping" , e );
285
- return null ;
307
+ return SkippableTests . EMPTY ;
286
308
}
287
309
}
288
310
311
+ @ Nullable
289
312
private Map <String , Collection <TestIdentifier >> getFlakyTestsByModule (
290
- TracerEnvironment tracerEnvironment ) {
313
+ TracerEnvironment tracerEnvironment , boolean flakyTestRetriesEnabled ) {
314
+ if (!(flakyTestRetriesEnabled && config .isCiVisibilityFlakyRetryOnlyKnownFlakes ())
315
+ && !CIConstants .FAIL_FAST_TEST_ORDER .equalsIgnoreCase (config .getCiVisibilityTestOrder ())) {
316
+ return null ;
317
+ }
291
318
try {
292
319
return configurationApi .getFlakyTestsByModule (tracerEnvironment );
293
-
294
320
} catch (Exception e ) {
295
321
LOGGER .error ("Could not obtain list of flaky tests" , e );
296
- return Collections . emptyMap () ;
322
+ return null ;
297
323
}
298
324
}
299
325
326
+ @ Nullable
300
327
private Map <String , Collection <TestIdentifier >> getKnownTestsByModule (
301
- TracerEnvironment tracerEnvironment ) {
328
+ TracerEnvironment tracerEnvironment , boolean knownTestsRequest ) {
329
+ if (!knownTestsRequest ) {
330
+ return null ;
331
+ }
302
332
try {
303
333
return configurationApi .getKnownTestsByModule (tracerEnvironment );
304
334
@@ -310,7 +340,7 @@ private Map<String, Collection<TestIdentifier>> getKnownTestsByModule(
310
340
311
341
@ Nonnull
312
342
private Diff getPullRequestDiff (
313
- boolean impactedTestsDetectionEnabled , TracerEnvironment tracerEnvironment ) {
343
+ TracerEnvironment tracerEnvironment , boolean impactedTestsDetectionEnabled ) {
314
344
if (!impactedTestsDetectionEnabled ) {
315
345
return LineDiff .EMPTY ;
316
346
}
@@ -362,4 +392,20 @@ private Diff getPullRequestDiff(
362
392
363
393
return LineDiff .EMPTY ;
364
394
}
395
+
396
+ @ Nonnull
397
+ private static Set <String > getModuleNames (
398
+ SkippableTests skippableTests ,
399
+ Map <String , Collection <TestIdentifier >> flakyTestsByModule ,
400
+ Map <String , Collection <TestIdentifier >> knownTestsByModule ) {
401
+ Set <String > moduleNames = new HashSet <>(Collections .singleton (DEFAULT_SETTINGS ));
402
+ moduleNames .addAll (skippableTests .getIdentifiersByModule ().keySet ());
403
+ if (flakyTestsByModule != null ) {
404
+ moduleNames .addAll (flakyTestsByModule .keySet ());
405
+ }
406
+ if (knownTestsByModule != null ) {
407
+ moduleNames .addAll (knownTestsByModule .keySet ());
408
+ }
409
+ return moduleNames ;
410
+ }
365
411
}
0 commit comments