Skip to content

Commit 91854ff

Browse files
Fix Karate instrumentation to handle parallel tests execution (#6924)
1 parent 40edb59 commit 91854ff

File tree

5 files changed

+280
-7
lines changed

5 files changed

+280
-7
lines changed

dd-java-agent/instrumentation/karate/src/main/java/datadog/trace/instrumentation/karate/KarateTracingHook.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.intuit.karate.core.FeatureResult;
99
import com.intuit.karate.core.FeatureRuntime;
1010
import com.intuit.karate.core.Scenario;
11+
import com.intuit.karate.core.ScenarioIterator;
1112
import com.intuit.karate.core.ScenarioResult;
1213
import com.intuit.karate.core.ScenarioRuntime;
1314
import com.intuit.karate.core.Step;
@@ -49,7 +50,7 @@ public boolean beforeFeature(FeatureRuntime fr) {
4950
suite.parallel,
5051
TestFrameworkInstrumentation.KARATE);
5152

52-
if (!fr.scenarios.hasNext()) {
53+
if (!isFeatureContainingScenarios(fr)) {
5354
// Karate will not trigger the afterFeature hook if suite has no scenarios
5455
TestEventsHandlerHolder.TEST_EVENTS_HANDLER.onTestSuiteSkip(suiteDescriptor, null);
5556
TestEventsHandlerHolder.TEST_EVENTS_HANDLER.onTestSuiteFinish(suiteDescriptor);
@@ -58,6 +59,13 @@ public boolean beforeFeature(FeatureRuntime fr) {
5859
return true;
5960
}
6061

62+
private boolean isFeatureContainingScenarios(FeatureRuntime fr) {
63+
// cannot use existing iterator (FeatureRuntime#scenarios) because it may have been traversed
64+
// already
65+
// (likely, when scheduling parallel execution of scenarios)
66+
return new ScenarioIterator(fr).filterSelected().iterator().hasNext();
67+
}
68+
6169
@Override
6270
public void afterFeature(FeatureRuntime fr) {
6371
if (skipTracking(fr)) {

dd-java-agent/instrumentation/karate/src/test/groovy/KarateTest.groovy

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import org.example.TestSkippedFeatureKarate
1212
import org.example.TestSucceedKarate
1313
import org.example.TestSucceedKarateSlow
1414
import org.example.TestSucceedOneCaseKarate
15+
import org.example.TestSucceedParallelKarate
1516
import org.example.TestUnskippableKarate
1617
import org.example.TestWithSetupKarate
1718
import org.junit.jupiter.api.Assumptions
@@ -34,12 +35,13 @@ class KarateTest extends CiVisibilityInstrumentationTest {
3435
assertSpansData(testcaseName, expectedTracesCount)
3536

3637
where:
37-
testcaseName | tests | expectedTracesCount | assumption
38-
"test-succeed" | [TestSucceedKarate] | 3 | true
39-
"test-with-setup" | [TestWithSetupKarate] | 3 | isSetupTagSupported(FileUtils.KARATE_VERSION)
40-
"test-parameterized" | [TestParameterizedKarate] | 3 | true
41-
"test-failed" | [TestFailedKarate] | 3 | true
42-
"test-skipped-feature" | [TestSkippedFeatureKarate] | 1 | true
38+
testcaseName | tests | expectedTracesCount | assumption
39+
"test-succeed" | [TestSucceedKarate] | 3 | true
40+
"test-succeed-parallel" | [TestSucceedParallelKarate] | 3 | true
41+
"test-with-setup" | [TestWithSetupKarate] | 3 | isSetupTagSupported(FileUtils.KARATE_VERSION)
42+
"test-parameterized" | [TestParameterizedKarate] | 3 | true
43+
"test-failed" | [TestFailedKarate] | 3 | true
44+
"test-skipped-feature" | [TestSkippedFeatureKarate] | 1 | true
4345
}
4446

4547
def "test ITR #testcaseName"() {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.example;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import com.intuit.karate.Results;
6+
import com.intuit.karate.Runner;
7+
import org.junit.jupiter.api.Test;
8+
9+
public class TestSucceedParallelKarate {
10+
11+
@Test
12+
public void testSucceed() {
13+
Results results = Runner.path("classpath:org/example/test_succeed.feature").parallel(4);
14+
assertEquals(0, results.getFailCount(), results.getErrorMessages());
15+
}
16+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[ ]
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
[ {
2+
"type" : "span",
3+
"version" : 1,
4+
"content" : {
5+
"trace_id" : ${content_trace_id},
6+
"span_id" : ${content_span_id},
7+
"parent_id" : ${content_parent_id},
8+
"service" : "worker.org.gradle.process.internal.worker.gradleworkermain",
9+
"name" : "karate.step",
10+
"resource" : "* print 'first'",
11+
"start" : ${content_start},
12+
"duration" : ${content_duration},
13+
"error" : 0,
14+
"metrics" : {
15+
"step.endLine" : 6,
16+
"step.startLine" : 6
17+
},
18+
"meta" : {
19+
"library_version" : ${content_meta_library_version},
20+
"component" : "karate",
21+
"step.name" : "* print 'first'",
22+
"env" : "none"
23+
}
24+
}
25+
}, {
26+
"type" : "span",
27+
"version" : 1,
28+
"content" : {
29+
"trace_id" : ${content_trace_id_2},
30+
"span_id" : ${content_span_id_2},
31+
"parent_id" : ${content_parent_id_2},
32+
"service" : "worker.org.gradle.process.internal.worker.gradleworkermain",
33+
"name" : "karate.step",
34+
"resource" : "* print 'second'",
35+
"start" : ${content_start_2},
36+
"duration" : ${content_duration_2},
37+
"error" : 0,
38+
"metrics" : {
39+
"step.endLine" : 9,
40+
"step.startLine" : 9
41+
},
42+
"meta" : {
43+
"library_version" : ${content_meta_library_version},
44+
"component" : "karate",
45+
"step.name" : "* print 'second'",
46+
"env" : "none"
47+
}
48+
}
49+
}, {
50+
"type" : "test_suite_end",
51+
"version" : 1,
52+
"content" : {
53+
"test_session_id" : ${content_test_session_id},
54+
"test_module_id" : ${content_test_module_id},
55+
"test_suite_id" : ${content_test_suite_id},
56+
"service" : "worker.org.gradle.process.internal.worker.gradleworkermain",
57+
"name" : "karate.test_suite",
58+
"resource" : "[org/example/test_succeed] test succeed",
59+
"start" : ${content_start_3},
60+
"duration" : ${content_duration_3},
61+
"error" : 0,
62+
"metrics" : { },
63+
"meta" : {
64+
"test.type" : "test",
65+
"os.architecture" : ${content_meta_os_architecture},
66+
"test.module" : "karate",
67+
"test.status" : "pass",
68+
"test.traits" : "{\"category\":[\"foo\"]}",
69+
"runtime.name" : ${content_meta_runtime_name},
70+
"runtime.vendor" : ${content_meta_runtime_vendor},
71+
"env" : "none",
72+
"os.platform" : ${content_meta_os_platform},
73+
"dummy_ci_tag" : "dummy_ci_tag_value",
74+
"os.version" : ${content_meta_os_version},
75+
"library_version" : ${content_meta_library_version},
76+
"component" : "karate",
77+
"span.kind" : "test_suite_end",
78+
"test.suite" : "[org/example/test_succeed] test succeed",
79+
"runtime.version" : ${content_meta_runtime_version},
80+
"test.framework_version" : ${content_meta_test_framework_version},
81+
"test.framework" : "karate"
82+
}
83+
}
84+
}, {
85+
"type" : "test",
86+
"version" : 2,
87+
"content" : {
88+
"trace_id" : ${content_trace_id},
89+
"span_id" : ${content_parent_id},
90+
"parent_id" : ${content_parent_id_3},
91+
"test_session_id" : ${content_test_session_id},
92+
"test_module_id" : ${content_test_module_id},
93+
"test_suite_id" : ${content_test_suite_id},
94+
"service" : "worker.org.gradle.process.internal.worker.gradleworkermain",
95+
"name" : "karate.test",
96+
"resource" : "[org/example/test_succeed] test succeed.first scenario",
97+
"start" : ${content_start_4},
98+
"duration" : ${content_duration_4},
99+
"error" : 0,
100+
"metrics" : {
101+
"process_id" : ${content_metrics_process_id},
102+
"_dd.profiling.enabled" : 0,
103+
"_dd.trace_span_attribute_schema" : 0
104+
},
105+
"meta" : {
106+
"os.architecture" : ${content_meta_os_architecture},
107+
"test.module" : "karate",
108+
"test.status" : "pass",
109+
"language" : "jvm",
110+
"runtime.name" : ${content_meta_runtime_name},
111+
"os.platform" : ${content_meta_os_platform},
112+
"os.version" : ${content_meta_os_version},
113+
"library_version" : ${content_meta_library_version},
114+
"test.name" : "first scenario",
115+
"span.kind" : "test",
116+
"test.suite" : "[org/example/test_succeed] test succeed",
117+
"runtime.version" : ${content_meta_runtime_version},
118+
"runtime-id" : ${content_meta_runtime_id},
119+
"test.type" : "test",
120+
"test.traits" : "{\"category\":[\"bar\",\"foo\"]}",
121+
"runtime.vendor" : ${content_meta_runtime_vendor},
122+
"env" : "none",
123+
"dummy_ci_tag" : "dummy_ci_tag_value",
124+
"component" : "karate",
125+
"_dd.profiling.ctx" : "test",
126+
"test.framework_version" : ${content_meta_test_framework_version},
127+
"test.framework" : "karate"
128+
}
129+
}
130+
}, {
131+
"type" : "test",
132+
"version" : 2,
133+
"content" : {
134+
"trace_id" : ${content_trace_id_2},
135+
"span_id" : ${content_parent_id_2},
136+
"parent_id" : ${content_parent_id_3},
137+
"test_session_id" : ${content_test_session_id},
138+
"test_module_id" : ${content_test_module_id},
139+
"test_suite_id" : ${content_test_suite_id},
140+
"service" : "worker.org.gradle.process.internal.worker.gradleworkermain",
141+
"name" : "karate.test",
142+
"resource" : "[org/example/test_succeed] test succeed.second scenario",
143+
"start" : ${content_start_5},
144+
"duration" : ${content_duration_5},
145+
"error" : 0,
146+
"metrics" : {
147+
"process_id" : ${content_metrics_process_id},
148+
"_dd.profiling.enabled" : 0,
149+
"_dd.trace_span_attribute_schema" : 0
150+
},
151+
"meta" : {
152+
"os.architecture" : ${content_meta_os_architecture},
153+
"test.module" : "karate",
154+
"test.status" : "pass",
155+
"language" : "jvm",
156+
"runtime.name" : ${content_meta_runtime_name},
157+
"os.platform" : ${content_meta_os_platform},
158+
"os.version" : ${content_meta_os_version},
159+
"library_version" : ${content_meta_library_version},
160+
"test.name" : "second scenario",
161+
"span.kind" : "test",
162+
"test.suite" : "[org/example/test_succeed] test succeed",
163+
"runtime.version" : ${content_meta_runtime_version},
164+
"runtime-id" : ${content_meta_runtime_id},
165+
"test.type" : "test",
166+
"test.traits" : "{\"category\":[\"foo\"]}",
167+
"runtime.vendor" : ${content_meta_runtime_vendor},
168+
"env" : "none",
169+
"dummy_ci_tag" : "dummy_ci_tag_value",
170+
"component" : "karate",
171+
"_dd.profiling.ctx" : "test",
172+
"test.framework_version" : ${content_meta_test_framework_version},
173+
"test.framework" : "karate"
174+
}
175+
}
176+
}, {
177+
"type" : "test_session_end",
178+
"version" : 1,
179+
"content" : {
180+
"test_session_id" : ${content_test_session_id},
181+
"service" : "worker.org.gradle.process.internal.worker.gradleworkermain",
182+
"name" : "karate.test_session",
183+
"resource" : "karate",
184+
"start" : ${content_start_6},
185+
"duration" : ${content_duration_6},
186+
"error" : 0,
187+
"metrics" : {
188+
"process_id" : ${content_metrics_process_id},
189+
"_dd.profiling.enabled" : 0,
190+
"_dd.trace_span_attribute_schema" : 0
191+
},
192+
"meta" : {
193+
"test.type" : "test",
194+
"os.architecture" : ${content_meta_os_architecture},
195+
"test.status" : "pass",
196+
"language" : "jvm",
197+
"runtime.name" : ${content_meta_runtime_name},
198+
"runtime.vendor" : ${content_meta_runtime_vendor},
199+
"env" : "none",
200+
"os.platform" : ${content_meta_os_platform},
201+
"dummy_ci_tag" : "dummy_ci_tag_value",
202+
"os.version" : ${content_meta_os_version},
203+
"library_version" : ${content_meta_library_version},
204+
"component" : "karate",
205+
"_dd.profiling.ctx" : "test",
206+
"span.kind" : "test_session_end",
207+
"runtime.version" : ${content_meta_runtime_version},
208+
"runtime-id" : ${content_meta_runtime_id},
209+
"test.command" : "karate",
210+
"test.framework_version" : ${content_meta_test_framework_version},
211+
"test.framework" : "karate"
212+
}
213+
}
214+
}, {
215+
"type" : "test_module_end",
216+
"version" : 1,
217+
"content" : {
218+
"test_session_id" : ${content_test_session_id},
219+
"test_module_id" : ${content_test_module_id},
220+
"service" : "worker.org.gradle.process.internal.worker.gradleworkermain",
221+
"name" : "karate.test_module",
222+
"resource" : "karate",
223+
"start" : ${content_start_7},
224+
"duration" : ${content_duration_7},
225+
"error" : 0,
226+
"metrics" : { },
227+
"meta" : {
228+
"test.type" : "test",
229+
"os.architecture" : ${content_meta_os_architecture},
230+
"test.module" : "karate",
231+
"test.status" : "pass",
232+
"runtime.name" : ${content_meta_runtime_name},
233+
"runtime.vendor" : ${content_meta_runtime_vendor},
234+
"env" : "none",
235+
"os.platform" : ${content_meta_os_platform},
236+
"dummy_ci_tag" : "dummy_ci_tag_value",
237+
"os.version" : ${content_meta_os_version},
238+
"library_version" : ${content_meta_library_version},
239+
"component" : "karate",
240+
"span.kind" : "test_module_end",
241+
"runtime.version" : ${content_meta_runtime_version},
242+
"test.framework_version" : ${content_meta_test_framework_version},
243+
"test.framework" : "karate"
244+
}
245+
}
246+
} ]

0 commit comments

Comments
 (0)