44import datadog .trace .api .civisibility .CIConstants ;
55import datadog .trace .api .civisibility .CiVisibilityWellKnownTags ;
66import datadog .trace .api .civisibility .config .TestIdentifier ;
7- import datadog .trace .api .civisibility .config .TestMetadata ;
87import datadog .trace .api .git .GitInfo ;
98import datadog .trace .api .git .GitInfoProvider ;
109import datadog .trace .civisibility .ci .PullRequestInfo ;
1413import datadog .trace .civisibility .git .tree .GitClient ;
1514import datadog .trace .civisibility .git .tree .GitDataUploader ;
1615import datadog .trace .civisibility .git .tree .GitRepoUnshallow ;
17- import java .nio .file .Path ;
1816import java .nio .file .Paths ;
19- import java .util .BitSet ;
2017import java .util .Collection ;
2118import java .util .Collections ;
2219import java .util .HashMap ;
2320import java .util .HashSet ;
2421import java .util .Map ;
22+ import java .util .Objects ;
2523import 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 ;
2629import java .util .concurrent .TimeUnit ;
2730import java .util .function .Function ;
2831import javax .annotation .Nonnull ;
3336public class ExecutionSettingsFactoryImpl implements ExecutionSettingsFactory {
3437
3538 private static final Logger LOGGER = LoggerFactory .getLogger (ExecutionSettingsFactoryImpl .class );
39+
3640 private static final String TEST_CONFIGURATION_TAG_PREFIX = "test.configuration." ;
3741
42+ private static final ThreadFactory THREAD_FACTORY = r -> new Thread (null , r , "dd-ci-vis-config" );
43+
3844 /**
3945 * A workaround for bulk-requesting module settings. For any module that has no settings that are
4046 * 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(
113119 .build ();
114120 }
115121
116- private @ Nonnull Map <String , ExecutionSettings > create (TracerEnvironment tracerEnvironment ) {
122+ @ Nonnull
123+ private Map <String , ExecutionSettings > create (TracerEnvironment tracerEnvironment ) {
117124 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 );
118133
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 {
119147 boolean itrEnabled =
120148 isFeatureEnabled (
121149 settings , CiVisibilitySettings ::isItrEnabled , Config ::isCiVisibilityItrEnabled );
@@ -134,7 +162,7 @@ private TracerEnvironment buildTracerEnvironment(
134162 settings ,
135163 CiVisibilitySettings ::isFlakyTestRetriesEnabled ,
136164 Config ::isCiVisibilityFlakyRetryEnabled );
137- boolean impactedTestsDetectionEnabled =
165+ boolean impactedTestsEnabled =
138166 isFeatureEnabled (
139167 settings ,
140168 CiVisibilitySettings ::isImpactedTestsDetectionEnabled ,
@@ -167,46 +195,27 @@ private TracerEnvironment buildTracerEnvironment(
167195 codeCoverageEnabled ,
168196 testSkippingEnabled ,
169197 earlyFlakeDetectionEnabled ,
170- impactedTestsDetectionEnabled ,
198+ impactedTestsEnabled ,
171199 knownTestsRequest ,
172200 flakyTestRetriesEnabled );
173201
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 ));
206210
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 ();
208215
209216 Map <String , ExecutionSettings > settingsByModule = new HashMap <>();
217+ Set <String > moduleNames =
218+ getModuleNames (skippableTests , flakyTestsByModule , knownTestsByModule );
210219 for (String moduleName : moduleNames ) {
211220 settingsByModule .put (
212221 moduleName ,
@@ -215,13 +224,15 @@ private TracerEnvironment buildTracerEnvironment(
215224 codeCoverageEnabled ,
216225 testSkippingEnabled ,
217226 flakyTestRetriesEnabled ,
218- impactedTestsDetectionEnabled ,
227+ impactedTestsEnabled ,
219228 earlyFlakeDetectionEnabled
220229 ? settings .getEarlyFlakeDetectionSettings ()
221230 : 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 (),
225236 flakyTestsByModule != null
226237 ? flakyTestsByModule .getOrDefault (moduleName , Collections .emptyList ())
227238 : null ,
@@ -258,47 +269,66 @@ private boolean isFeatureEnabled(
258269 return remoteSetting .apply (ciVisibilitySettings ) && killSwitch .apply (config );
259270 }
260271
261- @ Nullable
272+ @ Nonnull
262273 private SkippableTests getSkippableTests (
263- Path repositoryRoot , TracerEnvironment tracerEnvironment ) {
274+ TracerEnvironment tracerEnvironment , boolean itrEnabled ) {
275+ if (!itrEnabled || repositoryRoot == null ) {
276+ return SkippableTests .EMPTY ;
277+ }
264278 try {
265279 // ensure git data upload is finished before asking for tests
266280 gitDataUploader
267281 .startOrObserveGitDataUpload ()
268282 .get (config .getCiVisibilityGitUploadTimeoutMillis (), TimeUnit .MILLISECONDS );
269283
270284 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+ }
275297
276298 return skippableTests ;
277299
278300 } catch (InterruptedException e ) {
279301 Thread .currentThread ().interrupt ();
280302 LOGGER .error ("Interrupted while waiting for git data upload" , e );
281- return null ;
303+ return SkippableTests . EMPTY ;
282304
283305 } catch (Exception e ) {
284306 LOGGER .error ("Could not obtain list of skippable tests, will proceed without skipping" , e );
285- return null ;
307+ return SkippableTests . EMPTY ;
286308 }
287309 }
288310
311+ @ Nullable
289312 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+ }
291318 try {
292319 return configurationApi .getFlakyTestsByModule (tracerEnvironment );
293-
294320 } catch (Exception e ) {
295321 LOGGER .error ("Could not obtain list of flaky tests" , e );
296- return Collections . emptyMap () ;
322+ return null ;
297323 }
298324 }
299325
326+ @ Nullable
300327 private Map <String , Collection <TestIdentifier >> getKnownTestsByModule (
301- TracerEnvironment tracerEnvironment ) {
328+ TracerEnvironment tracerEnvironment , boolean knownTestsRequest ) {
329+ if (!knownTestsRequest ) {
330+ return null ;
331+ }
302332 try {
303333 return configurationApi .getKnownTestsByModule (tracerEnvironment );
304334
@@ -310,7 +340,7 @@ private Map<String, Collection<TestIdentifier>> getKnownTestsByModule(
310340
311341 @ Nonnull
312342 private Diff getPullRequestDiff (
313- boolean impactedTestsDetectionEnabled , TracerEnvironment tracerEnvironment ) {
343+ TracerEnvironment tracerEnvironment , boolean impactedTestsDetectionEnabled ) {
314344 if (!impactedTestsDetectionEnabled ) {
315345 return LineDiff .EMPTY ;
316346 }
@@ -362,4 +392,20 @@ private Diff getPullRequestDiff(
362392
363393 return LineDiff .EMPTY ;
364394 }
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+ }
365411}
0 commit comments