|
1 | 1 | package datadog.trace.bootstrap.instrumentation.decorator; |
2 | 2 |
|
| 3 | +import static datadog.trace.util.Strings.toJson; |
| 4 | + |
| 5 | +import datadog.trace.api.Config; |
3 | 6 | import datadog.trace.api.DDTags; |
| 7 | +import datadog.trace.api.civisibility.InstrumentationBridge; |
| 8 | +import datadog.trace.api.civisibility.codeowners.Codeowners; |
| 9 | +import datadog.trace.api.civisibility.source.MethodLinesResolver; |
| 10 | +import datadog.trace.api.civisibility.source.SourcePathResolver; |
4 | 11 | import datadog.trace.api.sampling.PrioritySampling; |
5 | 12 | import datadog.trace.bootstrap.instrumentation.api.AgentSpan; |
6 | 13 | import datadog.trace.bootstrap.instrumentation.api.InternalSpanTypes; |
7 | 14 | import datadog.trace.bootstrap.instrumentation.api.Tags; |
8 | 15 | import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString; |
9 | | -import datadog.trace.bootstrap.instrumentation.ci.CIProviderInfoFactory; |
10 | | -import datadog.trace.bootstrap.instrumentation.ci.CITagsProvider; |
11 | | -import datadog.trace.bootstrap.instrumentation.ci.CITagsProviderImpl; |
12 | | -import datadog.trace.bootstrap.instrumentation.ci.git.info.CILocalGitInfoBuilder; |
13 | | -import datadog.trace.bootstrap.instrumentation.ci.git.info.UserSuppliedGitInfoBuilder; |
14 | 16 | import java.lang.annotation.Annotation; |
15 | 17 | import java.lang.reflect.Method; |
16 | 18 | import java.util.ArrayList; |
| 19 | +import java.util.Collection; |
17 | 20 | import java.util.List; |
18 | 21 | import java.util.Map; |
19 | | -import org.slf4j.Logger; |
20 | | -import org.slf4j.LoggerFactory; |
21 | 22 |
|
22 | 23 | public abstract class TestDecorator extends BaseDecorator { |
23 | 24 |
|
24 | | - private static final Logger log = LoggerFactory.getLogger(TestDecorator.class); |
25 | | - |
26 | 25 | public static final String TEST_TYPE = "test"; |
27 | 26 | public static final String TEST_PASS = "pass"; |
28 | 27 | public static final String TEST_FAIL = "fail"; |
29 | 28 | public static final String TEST_SKIP = "skip"; |
30 | 29 | public static final UTF8BytesString CIAPP_TEST_ORIGIN = UTF8BytesString.create("ciapp-test"); |
31 | 30 |
|
32 | | - private static final String GIT_FOLDER_NAME = ".git"; |
33 | | - |
34 | | - private final boolean isCI; |
35 | | - private final Map<String, String> ciTags; |
36 | | - |
37 | | - public TestDecorator() { |
38 | | - this( |
39 | | - new CITagsProviderImpl( |
40 | | - CIProviderInfoFactory.createCIProviderInfo(), |
41 | | - new CILocalGitInfoBuilder(), |
42 | | - new UserSuppliedGitInfoBuilder(), |
43 | | - GIT_FOLDER_NAME)); |
44 | | - } |
45 | | - |
46 | | - TestDecorator(final CITagsProvider ciTagsProvider) { |
47 | | - isCI = ciTagsProvider.isCI(); |
48 | | - ciTags = ciTagsProvider.getCiTags(); |
49 | | - } |
| 31 | + public TestDecorator() {} |
50 | 32 |
|
51 | 33 | public boolean isCI() { |
52 | | - return isCI; |
| 34 | + return InstrumentationBridge.isCi(); |
53 | 35 | } |
54 | 36 |
|
55 | 37 | public Map<String, String> getCiTags() { |
56 | | - return ciTags; |
| 38 | + return InstrumentationBridge.getCiTags(); |
57 | 39 | } |
58 | 40 |
|
59 | 41 | protected abstract String testFramework(); |
@@ -113,32 +95,83 @@ public AgentSpan afterStart(final AgentSpan span) { |
113 | 95 | span.setTag(Tags.OS_VERSION, osVersion()); |
114 | 96 | span.setTag(DDTags.ORIGIN_KEY, CIAPP_TEST_ORIGIN); |
115 | 97 |
|
| 98 | + Map<String, String> ciTags = InstrumentationBridge.getCiTags(); |
116 | 99 | for (final Map.Entry<String, String> ciTag : ciTags.entrySet()) { |
117 | 100 | span.setTag(ciTag.getKey(), ciTag.getValue()); |
118 | 101 | } |
119 | 102 |
|
120 | 103 | return super.afterStart(span); |
121 | 104 | } |
122 | 105 |
|
123 | | - public AgentSpan afterStart(final AgentSpan span, final String version) { |
| 106 | + protected AgentSpan afterTestStart( |
| 107 | + final AgentSpan span, |
| 108 | + final String testSuiteName, |
| 109 | + final String testName, |
| 110 | + final String testParameters, |
| 111 | + final String version, |
| 112 | + final Class<?> testClass, |
| 113 | + final Method testMethod) { |
| 114 | + |
| 115 | + span.setResourceName(testSuiteName + "." + testName); |
| 116 | + span.setTag(Tags.TEST_SUITE, testSuiteName); |
| 117 | + span.setTag(Tags.TEST_NAME, testName); |
| 118 | + |
| 119 | + if (testParameters != null) { |
| 120 | + span.setTag(Tags.TEST_PARAMETERS, testParameters); |
| 121 | + } |
| 122 | + |
124 | 123 | // Version can be null. The testing framework version extraction is best-effort basis. |
125 | 124 | if (version != null) { |
126 | 125 | span.setTag(Tags.TEST_FRAMEWORK_VERSION, version); |
127 | 126 | } |
| 127 | + |
| 128 | + if (Config.get().isCiVisibilitySourceDataEnabled()) { |
| 129 | + populateSourceDataTags(span, testClass, testMethod); |
| 130 | + } |
| 131 | + |
128 | 132 | return afterStart(span); |
129 | 133 | } |
130 | 134 |
|
131 | | - public List<String> testNames( |
| 135 | + private void populateSourceDataTags(AgentSpan span, Class<?> testClass, Method testMethod) { |
| 136 | + if (testClass == null) { |
| 137 | + return; |
| 138 | + } |
| 139 | + |
| 140 | + SourcePathResolver sourcePathResolver = InstrumentationBridge.getSourcePathResolver(); |
| 141 | + String sourcePath = sourcePathResolver.getSourcePath(testClass); |
| 142 | + if (sourcePath == null || sourcePath.isEmpty()) { |
| 143 | + return; |
| 144 | + } |
| 145 | + |
| 146 | + span.setTag(Tags.TEST_SOURCE_FILE, sourcePath); |
| 147 | + |
| 148 | + if (testMethod != null) { |
| 149 | + MethodLinesResolver methodLinesResolver = InstrumentationBridge.getMethodLinesResolver(); |
| 150 | + MethodLinesResolver.MethodLines testMethodLines = methodLinesResolver.getLines(testMethod); |
| 151 | + if (testMethodLines.isValid()) { |
| 152 | + span.setTag(Tags.TEST_SOURCE_START, testMethodLines.getStartLineNumber()); |
| 153 | + span.setTag(Tags.TEST_SOURCE_END, testMethodLines.getFinishLineNumber()); |
| 154 | + } |
| 155 | + } |
| 156 | + |
| 157 | + Codeowners codeowners = InstrumentationBridge.getCodeowners(); |
| 158 | + Collection<String> testCodeOwners = codeowners.getOwners(sourcePath); |
| 159 | + if (testCodeOwners != null) { |
| 160 | + span.setTag(Tags.TEST_CODEOWNERS, toJson(testCodeOwners)); |
| 161 | + } |
| 162 | + } |
| 163 | + |
| 164 | + public List<Method> testMethods( |
132 | 165 | final Class<?> testClass, final Class<? extends Annotation> testAnnotation) { |
133 | | - final List<String> testNames = new ArrayList<>(); |
| 166 | + final List<Method> testMethods = new ArrayList<>(); |
134 | 167 |
|
135 | 168 | final Method[] methods = testClass.getMethods(); |
136 | 169 | for (final Method method : methods) { |
137 | 170 | if (method.getAnnotation(testAnnotation) != null) { |
138 | | - testNames.add(method.getName()); |
| 171 | + testMethods.add(method); |
139 | 172 | } |
140 | 173 | } |
141 | | - return testNames; |
| 174 | + return testMethods; |
142 | 175 | } |
143 | 176 |
|
144 | 177 | public boolean isTestSpan(final AgentSpan activeSpan) { |
|
0 commit comments