Skip to content

Commit ff190af

Browse files
ITR code coverage support (#7367)
1 parent 5f325b0 commit ff190af

File tree

220 files changed

+5346
-3087
lines changed

Some content is hidden

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

220 files changed

+5346
-3087
lines changed

communication/src/main/java/datadog/communication/ddagent/TracerVersion.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package datadog.communication.ddagent;
22

33
import java.io.BufferedReader;
4-
import java.io.IOException;
54
import java.io.InputStreamReader;
65
import java.nio.charset.StandardCharsets;
76

@@ -16,7 +15,7 @@ private static String getTracerVersion() {
1615
cl.getResourceAsStream("dd-java-agent.version"), StandardCharsets.ISO_8859_1))) {
1716
String line = reader.readLine();
1817
return line != null ? line : "0.0.0";
19-
} catch (IOException e) {
18+
} catch (Exception e) {
2019
return "0.0.0";
2120
}
2221
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package datadog.trace.civisibility;
2+
3+
import datadog.trace.api.civisibility.config.TestIdentifier;
4+
import datadog.trace.api.civisibility.config.TestMetadata;
5+
import datadog.trace.api.civisibility.coverage.CoveragePercentageBridge;
6+
import datadog.trace.api.civisibility.coverage.CoverageStore;
7+
import datadog.trace.api.civisibility.coverage.NoOpCoverageStore;
8+
import datadog.trace.civisibility.config.ExecutionSettings;
9+
import datadog.trace.civisibility.coverage.SkippableAwareCoverageStoreFactory;
10+
import datadog.trace.civisibility.coverage.file.FileCoverageStore;
11+
import datadog.trace.civisibility.coverage.line.LineCoverageStore;
12+
import datadog.trace.civisibility.coverage.percentage.CoverageCalculator;
13+
import datadog.trace.civisibility.coverage.percentage.JacocoCoverageCalculator;
14+
import datadog.trace.civisibility.coverage.percentage.child.ChildProcessCoverageReporter;
15+
import datadog.trace.civisibility.coverage.percentage.child.JacocoChildProcessCoverageReporter;
16+
import datadog.trace.civisibility.domain.buildsystem.ModuleSignalRouter;
17+
import java.util.Map;
18+
19+
/**
20+
* Services that are related to coverage calculation (both per-test coverage and total coverage
21+
* percentage). The scope is session/module.
22+
*/
23+
public class CiVisibilityCoverageServices {
24+
25+
/** Services used in the parent process (build system). */
26+
static class Parent {
27+
final ModuleSignalRouter moduleSignalRouter;
28+
final CoverageCalculator.Factory<?> coverageCalculatorFactory;
29+
30+
Parent(CiVisibilityServices services, CiVisibilityRepoServices repoServices) {
31+
moduleSignalRouter = new ModuleSignalRouter();
32+
coverageCalculatorFactory =
33+
new JacocoCoverageCalculator.Factory(
34+
services.config,
35+
repoServices.repoIndexProvider,
36+
repoServices.repoRoot,
37+
moduleSignalRouter);
38+
}
39+
}
40+
41+
/** Services used in the children processes (JVMs forked to run tests). */
42+
static class Child {
43+
final CoverageStore.Factory coverageStoreFactory;
44+
final ChildProcessCoverageReporter coverageReporter;
45+
46+
Child(
47+
CiVisibilityServices services,
48+
CiVisibilityRepoServices repoServices,
49+
ExecutionSettings executionSettings) {
50+
coverageReporter =
51+
new JacocoChildProcessCoverageReporter(CoveragePercentageBridge::getJacocoCoverageData);
52+
53+
coverageStoreFactory = buildCoverageStoreFactory(services, repoServices, executionSettings);
54+
}
55+
56+
private static CoverageStore.Factory buildCoverageStoreFactory(
57+
CiVisibilityServices services,
58+
CiVisibilityRepoServices repoServices,
59+
ExecutionSettings executionSettings) {
60+
61+
CoverageStore.Factory factory;
62+
if (!services.config.isCiVisibilityCodeCoverageEnabled()) {
63+
factory = new NoOpCoverageStore.Factory();
64+
} else if (services.config.isCiVisibilityCoverageLinesEnabled()) {
65+
factory =
66+
new LineCoverageStore.Factory(
67+
services.metricCollector, repoServices.sourcePathResolver);
68+
} else {
69+
factory =
70+
new FileCoverageStore.Factory(
71+
services.metricCollector, repoServices.sourcePathResolver);
72+
}
73+
74+
if (executionSettings.isItrEnabled()) {
75+
Map<TestIdentifier, TestMetadata> skippableTests = executionSettings.getSkippableTests();
76+
return new SkippableAwareCoverageStoreFactory(skippableTests.keySet(), factory);
77+
} else {
78+
return factory;
79+
}
80+
}
81+
}
82+
}

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

+27-43
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22

33
import datadog.communication.BackendApi;
44
import datadog.trace.api.Config;
5-
import datadog.trace.api.civisibility.config.ModuleExecutionSettings;
6-
import datadog.trace.api.civisibility.coverage.CoverageStore;
7-
import datadog.trace.api.civisibility.coverage.NoOpCoverageStore;
85
import datadog.trace.api.civisibility.telemetry.CiVisibilityMetricCollector;
96
import datadog.trace.api.civisibility.telemetry.tag.Provider;
107
import datadog.trace.api.git.GitInfoProvider;
@@ -14,20 +11,19 @@
1411
import datadog.trace.civisibility.codeowners.Codeowners;
1512
import datadog.trace.civisibility.codeowners.CodeownersProvider;
1613
import datadog.trace.civisibility.codeowners.NoCodeowners;
17-
import datadog.trace.civisibility.config.CachingModuleExecutionSettingsFactory;
1814
import datadog.trace.civisibility.config.ConfigurationApi;
1915
import datadog.trace.civisibility.config.ConfigurationApiImpl;
16+
import datadog.trace.civisibility.config.ExecutionSettings;
17+
import datadog.trace.civisibility.config.ExecutionSettingsFactory;
18+
import datadog.trace.civisibility.config.ExecutionSettingsFactoryImpl;
2019
import datadog.trace.civisibility.config.JvmInfo;
21-
import datadog.trace.civisibility.config.ModuleExecutionSettingsFactory;
22-
import datadog.trace.civisibility.config.ModuleExecutionSettingsFactoryImpl;
23-
import datadog.trace.civisibility.coverage.file.FileCoverageStore;
24-
import datadog.trace.civisibility.coverage.line.LineCoverageStore;
20+
import datadog.trace.civisibility.config.MultiModuleExecutionSettingsFactory;
2521
import datadog.trace.civisibility.git.tree.GitClient;
2622
import datadog.trace.civisibility.git.tree.GitDataApi;
2723
import datadog.trace.civisibility.git.tree.GitDataUploader;
2824
import datadog.trace.civisibility.git.tree.GitDataUploaderImpl;
29-
import datadog.trace.civisibility.ipc.ModuleSettingsRequest;
30-
import datadog.trace.civisibility.ipc.ModuleSettingsResponse;
25+
import datadog.trace.civisibility.ipc.ExecutionSettingsRequest;
26+
import datadog.trace.civisibility.ipc.ExecutionSettingsResponse;
3127
import datadog.trace.civisibility.ipc.SignalClient;
3228
import datadog.trace.civisibility.source.BestEffortSourcePathResolver;
3329
import datadog.trace.civisibility.source.CompilerAidedSourcePathResolver;
@@ -43,7 +39,7 @@
4339
import org.slf4j.Logger;
4440
import org.slf4j.LoggerFactory;
4541

46-
/** Services that need repository root location to be instantiated */
42+
/** Services that need repository root location to be instantiated. The scope is session. */
4743
public class CiVisibilityRepoServices {
4844

4945
private static final Logger LOGGER = LoggerFactory.getLogger(CiVisibilityRepoServices.class);
@@ -57,15 +53,14 @@ public class CiVisibilityRepoServices {
5753
final RepoIndexProvider repoIndexProvider;
5854
final Codeowners codeowners;
5955
final SourcePathResolver sourcePathResolver;
60-
final CoverageStore.Factory coverageStoreFactory;
61-
final ModuleExecutionSettingsFactory moduleExecutionSettingsFactory;
56+
final ExecutionSettingsFactory executionSettingsFactory;
6257

6358
CiVisibilityRepoServices(CiVisibilityServices services, Path path) {
6459
CIProviderInfo ciProviderInfo = services.ciProviderInfoFactory.createCIProviderInfo(path);
6560
ciProvider = ciProviderInfo.getProvider();
6661

6762
CIInfo ciInfo = ciProviderInfo.buildCIInfo();
68-
repoRoot = ciInfo.getCiWorkspace();
63+
repoRoot = ciInfo.getNormalizedCiWorkspace();
6964
moduleName = getModuleName(services.config, path, ciInfo);
7065
ciTags = new CITagsProvider().getCiTags(ciInfo);
7166

@@ -80,20 +75,16 @@ public class CiVisibilityRepoServices {
8075
repoIndexProvider = services.repoIndexProviderFactory.create(repoRoot);
8176
codeowners = buildCodeowners(repoRoot);
8277
sourcePathResolver = buildSourcePathResolver(repoRoot, repoIndexProvider);
83-
coverageStoreFactory =
84-
buildCoverageStoreFactory(services.config, services.metricCollector, sourcePathResolver);
8578

8679
if (ProcessHierarchyUtils.isChild()) {
87-
moduleExecutionSettingsFactory =
88-
buildModuleExecutionSettingsFetcher(services.signalClientFactory);
80+
executionSettingsFactory = buildExecutionSettingsFetcher(services.signalClientFactory);
8981
} else {
90-
moduleExecutionSettingsFactory =
91-
buildModuleExecutionSettingsFactory(
82+
executionSettingsFactory =
83+
buildExecutionSettingsFactory(
9284
services.config,
9385
services.metricCollector,
9486
services.backendApi,
9587
gitDataUploader,
96-
repoIndexProvider,
9788
repoRoot);
9889
}
9990
}
@@ -104,7 +95,7 @@ private static String getModuleName(Config config, Path path, CIInfo ciInfo) {
10495
if (parentModuleName != null) {
10596
return parentModuleName;
10697
}
107-
String repoRoot = ciInfo.getCiWorkspace();
98+
String repoRoot = ciInfo.getNormalizedCiWorkspace();
10899
if (repoRoot != null
109100
&& path.startsWith(repoRoot)
110101
// module name cannot be empty
@@ -114,38 +105,27 @@ private static String getModuleName(Config config, Path path, CIInfo ciInfo) {
114105
return config.getServiceName();
115106
}
116107

117-
private static CoverageStore.Factory buildCoverageStoreFactory(
118-
Config config, CiVisibilityMetricCollector metrics, SourcePathResolver sourcePathResolver) {
119-
if (!config.isCiVisibilityCodeCoverageEnabled()) {
120-
return new NoOpCoverageStore.Factory();
121-
}
122-
if (!config.isCiVisibilityCoverageSegmentsEnabled()) {
123-
return new FileCoverageStore.Factory(metrics, sourcePathResolver);
124-
}
125-
return new LineCoverageStore.Factory(metrics, sourcePathResolver);
126-
}
127-
128-
private static ModuleExecutionSettingsFactory buildModuleExecutionSettingsFetcher(
108+
private static ExecutionSettingsFactory buildExecutionSettingsFetcher(
129109
SignalClient.Factory signalClientFactory) {
130110
return (JvmInfo jvmInfo, String moduleName) -> {
131111
try (SignalClient signalClient = signalClientFactory.create()) {
132-
ModuleSettingsRequest request = new ModuleSettingsRequest(moduleName, JvmInfo.CURRENT_JVM);
133-
ModuleSettingsResponse response = (ModuleSettingsResponse) signalClient.send(request);
112+
ExecutionSettingsRequest request =
113+
new ExecutionSettingsRequest(moduleName, JvmInfo.CURRENT_JVM);
114+
ExecutionSettingsResponse response = (ExecutionSettingsResponse) signalClient.send(request);
134115
return response.getSettings();
135116

136117
} catch (Exception e) {
137118
LOGGER.error("Could not get module execution settings from parent process", e);
138-
return ModuleExecutionSettings.EMPTY;
119+
return ExecutionSettings.EMPTY;
139120
}
140121
};
141122
}
142123

143-
private static ModuleExecutionSettingsFactory buildModuleExecutionSettingsFactory(
124+
private static ExecutionSettingsFactory buildExecutionSettingsFactory(
144125
Config config,
145126
CiVisibilityMetricCollector metricCollector,
146127
BackendApi backendApi,
147128
GitDataUploader gitDataUploader,
148-
RepoIndexProvider repoIndexProvider,
149129
String repoRoot) {
150130
ConfigurationApi configurationApi;
151131
if (backendApi == null) {
@@ -155,10 +135,14 @@ private static ModuleExecutionSettingsFactory buildModuleExecutionSettingsFactor
155135
} else {
156136
configurationApi = new ConfigurationApiImpl(backendApi, metricCollector);
157137
}
158-
return new CachingModuleExecutionSettingsFactory(
159-
config,
160-
new ModuleExecutionSettingsFactoryImpl(
161-
config, configurationApi, gitDataUploader, repoIndexProvider, repoRoot));
138+
139+
ExecutionSettingsFactoryImpl factory =
140+
new ExecutionSettingsFactoryImpl(config, configurationApi, gitDataUploader, repoRoot);
141+
if (ProcessHierarchyUtils.isHeadless()) {
142+
return factory;
143+
} else {
144+
return new MultiModuleExecutionSettingsFactory(config, factory);
145+
}
162146
}
163147

164148
private static GitDataUploader buildGitDataUploader(

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@
3333
import java.nio.file.Path;
3434
import javax.annotation.Nullable;
3535

36-
/** Services that do not need repository root location to be instantiated */
36+
/**
37+
* Services that do not need repository root location to be instantiated. Can be shared between
38+
* multiple sessions.
39+
*/
3740
public class CiVisibilityServices {
3841

3942
private static final String GIT_FOLDER_NAME = ".git";

0 commit comments

Comments
 (0)