Skip to content

Commit

Permalink
[🍒 7435] Fix Cucumber JUnit 4 instrumentation to correctly handle fea…
Browse files Browse the repository at this point in the history
…ture and scenario names with brackets (#7447)
  • Loading branch information
nikita-tkachenko-datadog authored Aug 16, 2024
1 parent e4d2a06 commit 4f97ed1
Show file tree
Hide file tree
Showing 7 changed files with 229 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,14 @@ public void onTestStart(
}

TestSuiteImpl testSuite = inProgressTestSuites.get(suiteDescriptor);
if (testSuite == null) {
throw new IllegalStateException(
"Could not find test suite with descriptor "
+ suiteDescriptor
+ "; test descriptor: "
+ descriptor);
}

TestImpl test = testSuite.testStart(testName, testParameters, testMethod, null);

TestIdentifier thisTest = new TestIdentifier(testSuiteName, testName, testParameters, null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public void testSuiteFinished(final Description description) {
@Override
public void testStarted(final Description description) {
String testSuiteName = CucumberUtils.getTestSuiteNameForScenario(description);
String testName = description.getMethodName();
String testName = CucumberUtils.getTestNameForScenario(description);
List<String> categories = getCategories(description);

TestRetryPolicy retryPolicy = retryPolicies.get(description);
Expand Down Expand Up @@ -159,7 +159,7 @@ public void testIgnored(final Description description) {
TestEventsHandlerHolder.TEST_EVENTS_HANDLER.onTestSuiteFinish(suiteDescriptor);
} else {
String testSuiteName = CucumberUtils.getTestSuiteNameForScenario(description);
String testName = description.getMethodName();
String testName = CucumberUtils.getTestNameForScenario(description);
List<String> categories = getCategories(description);
TestEventsHandlerHolder.TEST_EVENTS_HANDLER.onTestIgnore(
new TestSuiteDescriptor(testSuiteName, null),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,53 @@ public static String getTestSuiteNameForFeature(Description featureDescription)

public static String getTestSuiteNameForScenario(Description scenarioDescription) {
URI featureUri = getFeatureUri(scenarioDescription);
return (featureUri != null ? featureUri + ":" : "") + scenarioDescription.getClassName();
return (featureUri != null ? featureUri + ":" : "")
+ getFeatureNameForScenario(scenarioDescription);
}

private static String getFeatureNameForScenario(Description scenarioDescription) {
String scenarioDescriptionString = scenarioDescription.toString();
int featureNameStart = getFeatureNameStartIdx(scenarioDescriptionString);
if (featureNameStart >= 0) {
int descriptionLength = scenarioDescriptionString.length();
// feature name is wrapped in brackets, hence the +1/-1
return scenarioDescriptionString.substring(featureNameStart + 1, descriptionLength - 1);
} else {
// fallback to default method
return scenarioDescription.getClassName();
}
}

public static String getTestNameForScenario(Description scenarioDescription) {
String scenarioDescriptionString = scenarioDescription.toString();
int featureNameStart = getFeatureNameStartIdx(scenarioDescriptionString);
if (featureNameStart >= 0) {
return scenarioDescriptionString.substring(0, featureNameStart);
} else {
// fallback to default method
return scenarioDescription.getMethodName();
}
}

/**
* JUnit 4 expects description string to have the form {@code "Scenario Name(Feature Name)"} The
* standard {@link Description#getClassName()} and {@link Description#getMethodName()} methods use
* a regex to split the name parts. This does not work correctly when feature or scenario names
* have bracket characters in them.
*/
private static int getFeatureNameStartIdx(String scenarioDescriptionString) {
int openBrackets = 0;
for (int i = scenarioDescriptionString.length() - 1; i >= 0; i--) {
char c = scenarioDescriptionString.charAt(i);
if (c == ')') {
openBrackets++;
} else if (c == '(') {
if (--openBrackets == 0) {
return i;
}
}
}
return -1;
}

private static URI getFeatureUri(Description scenarioDescription) {
Expand All @@ -100,13 +146,13 @@ public static Description getPickleRunnerDescription(

public static TestIdentifier toTestIdentifier(Description description) {
String suite = getTestSuiteNameForScenario(description);
String name = description.getMethodName();
String name = getTestNameForScenario(description);
return new TestIdentifier(suite, name, null, null);
}

public static TestDescriptor toTestDescriptor(Description description) {
String suite = getTestSuiteNameForScenario(description);
String name = description.getMethodName();
String name = getTestNameForScenario(description);
return new TestDescriptor(suite, null, name, null, null);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class CucumberTest extends CiVisibilityInstrumentationTest {
"org/example/cucumber/calculator/basic_arithmetic.feature",
"org/example/cucumber/calculator/basic_arithmetic_failed.feature"
] | 3
"test-name-with-brackets" | ["org/example/cucumber/calculator/name_with_brackets.feature"] | 2
}

def "test ITR #testcaseName"() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@foo
Feature: This (Name) Has Bracket Characters

Background: A Calculator
Given a calculator I just turned on

Scenario: Addition (Has) Brackets Too
# Try to change one of the values below to provoke a failure
When I add 4 and 5
Then the result is 9
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[ {
"test_session_id" : ${content_test_session_id},
"test_suite_id" : ${content_test_suite_id},
"span_id" : ${content_span_id},
"files" : [ {
"filename" : "org/example/cucumber/calculator/name_with_brackets.feature"
} ]
} ]
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
[ {
"type" : "test_suite_end",
"version" : 1,
"content" : {
"test_session_id" : ${content_test_session_id},
"test_module_id" : ${content_test_module_id},
"test_suite_id" : ${content_test_suite_id},
"service" : "worker.org.gradle.process.internal.worker.gradleworkermain",
"name" : "junit.test_suite",
"resource" : "classpath:org/example/cucumber/calculator/name_with_brackets.feature:This (Name) Has Bracket Characters",
"start" : ${content_start},
"duration" : ${content_duration},
"error" : 0,
"metrics" : { },
"meta" : {
"test.type" : "test",
"os.architecture" : ${content_meta_os_architecture},
"test.module" : "cucumber-junit-4",
"test.status" : "pass",
"runtime.name" : ${content_meta_runtime_name},
"runtime.vendor" : ${content_meta_runtime_vendor},
"env" : "none",
"os.platform" : ${content_meta_os_platform},
"dummy_ci_tag" : "dummy_ci_tag_value",
"os.version" : ${content_meta_os_version},
"library_version" : ${content_meta_library_version},
"component" : "junit",
"span.kind" : "test_suite_end",
"test.suite" : "classpath:org/example/cucumber/calculator/name_with_brackets.feature:This (Name) Has Bracket Characters",
"runtime.version" : ${content_meta_runtime_version},
"test.framework_version" : ${content_meta_test_framework_version},
"test.framework" : "cucumber"
}
}
}, {
"type" : "test",
"version" : 2,
"content" : {
"trace_id" : ${content_trace_id},
"span_id" : ${content_span_id},
"parent_id" : ${content_parent_id},
"test_session_id" : ${content_test_session_id},
"test_module_id" : ${content_test_module_id},
"test_suite_id" : ${content_test_suite_id},
"service" : "worker.org.gradle.process.internal.worker.gradleworkermain",
"name" : "junit.test",
"resource" : "classpath:org/example/cucumber/calculator/name_with_brackets.feature:This (Name) Has Bracket Characters.Addition (Has) Brackets Too",
"start" : ${content_start_2},
"duration" : ${content_duration_2},
"error" : 0,
"metrics" : {
"process_id" : ${content_metrics_process_id},
"_dd.profiling.enabled" : 0,
"_dd.trace_span_attribute_schema" : 0
},
"meta" : {
"os.architecture" : ${content_meta_os_architecture},
"test.module" : "cucumber-junit-4",
"test.status" : "pass",
"language" : "jvm",
"runtime.name" : ${content_meta_runtime_name},
"os.platform" : ${content_meta_os_platform},
"os.version" : ${content_meta_os_version},
"library_version" : ${content_meta_library_version},
"test.name" : "Addition (Has) Brackets Too",
"span.kind" : "test",
"test.suite" : "classpath:org/example/cucumber/calculator/name_with_brackets.feature:This (Name) Has Bracket Characters",
"runtime.version" : ${content_meta_runtime_version},
"runtime-id" : ${content_meta_runtime_id},
"test.type" : "test",
"test.traits" : "{\"category\":[\"foo\"]}",
"runtime.vendor" : ${content_meta_runtime_vendor},
"env" : "none",
"dummy_ci_tag" : "dummy_ci_tag_value",
"component" : "junit",
"_dd.profiling.ctx" : "test",
"test.framework_version" : ${content_meta_test_framework_version},
"test.framework" : "cucumber"
}
}
}, {
"type" : "test_session_end",
"version" : 1,
"content" : {
"test_session_id" : ${content_test_session_id},
"service" : "worker.org.gradle.process.internal.worker.gradleworkermain",
"name" : "junit.test_session",
"resource" : "cucumber-junit-4",
"start" : ${content_start_3},
"duration" : ${content_duration_3},
"error" : 0,
"metrics" : {
"process_id" : ${content_metrics_process_id},
"_dd.profiling.enabled" : 0,
"_dd.trace_span_attribute_schema" : 0
},
"meta" : {
"test.type" : "test",
"os.architecture" : ${content_meta_os_architecture},
"test.status" : "pass",
"language" : "jvm",
"runtime.name" : ${content_meta_runtime_name},
"runtime.vendor" : ${content_meta_runtime_vendor},
"env" : "none",
"os.platform" : ${content_meta_os_platform},
"dummy_ci_tag" : "dummy_ci_tag_value",
"os.version" : ${content_meta_os_version},
"library_version" : ${content_meta_library_version},
"component" : "junit",
"_dd.profiling.ctx" : "test",
"span.kind" : "test_session_end",
"runtime.version" : ${content_meta_runtime_version},
"runtime-id" : ${content_meta_runtime_id},
"test.command" : "cucumber-junit-4",
"test.framework_version" : ${content_meta_test_framework_version},
"test.framework" : "cucumber"
}
}
}, {
"type" : "test_module_end",
"version" : 1,
"content" : {
"test_session_id" : ${content_test_session_id},
"test_module_id" : ${content_test_module_id},
"service" : "worker.org.gradle.process.internal.worker.gradleworkermain",
"name" : "junit.test_module",
"resource" : "cucumber-junit-4",
"start" : ${content_start_4},
"duration" : ${content_duration_4},
"error" : 0,
"metrics" : { },
"meta" : {
"test.type" : "test",
"os.architecture" : ${content_meta_os_architecture},
"test.module" : "cucumber-junit-4",
"test.status" : "pass",
"runtime.name" : ${content_meta_runtime_name},
"runtime.vendor" : ${content_meta_runtime_vendor},
"env" : "none",
"os.platform" : ${content_meta_os_platform},
"dummy_ci_tag" : "dummy_ci_tag_value",
"os.version" : ${content_meta_os_version},
"library_version" : ${content_meta_library_version},
"component" : "junit",
"span.kind" : "test_module_end",
"runtime.version" : ${content_meta_runtime_version},
"test.framework_version" : ${content_meta_test_framework_version},
"test.framework" : "cucumber"
}
}
} ]

0 comments on commit 4f97ed1

Please sign in to comment.