Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update JUnit 4 method name extraction logic to properly handle Kotlin test names #6751

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions dd-java-agent/instrumentation/junit-4.10/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
apply from: "$rootDir/gradle/java.gradle"
apply from: "$rootDir/gradle/test-with-kotlin.gradle"

muzzle {
pass {
Expand All @@ -11,14 +12,22 @@ muzzle {

addTestSuiteForDir('latestDepTest', 'test')

tasks.named("compileLatestDepTestGroovy").configure {
classpath += files(compileLatestDepTestKotlin.destinationDirectory)
}

dependencies {
compileOnly group: 'junit', name: 'junit', version: '4.10'

// prevents kotlin plugin from including kotlin classes into the agent Jar
compileOnly deps.kotlin

testImplementation testFixtures(project(':dd-java-agent:agent-ci-visibility'))

// version used below is not the minimum one that we support,
// but the tests need to use it in order to be compliant with Spock 2.x
testImplementation group: 'junit', name: 'junit', version: '4.13.2'
testImplementation 'pl.pragmatists:JUnitParams:1.1.0'

latestDepTestImplementation group: 'junit', name: 'junit', version: '+'
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.Description;
import org.junit.runner.RunWith;
import org.junit.runner.notification.RunListener;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.ParentRunner;
Expand Down Expand Up @@ -95,17 +96,18 @@ public static Method getTestMethod(final Description description) {
return null;
}

int actualMethodNameStart, actualMethodNameEnd;
if ((actualMethodNameStart = methodName.indexOf('(')) > 0
&& (actualMethodNameEnd = methodName.indexOf(')', actualMethodNameStart)) > 0) {
RunWith runWith = testClass.getAnnotation(RunWith.class);
boolean isJunitParamsTestCase =
runWith != null && "junitparams.JUnitParamsRunner".equals(runWith.value().getName());
int junitParamsStartIdx;
if (isJunitParamsTestCase && (junitParamsStartIdx = methodName.indexOf('(')) >= 0) {
// assuming this is a parameterized test case that uses use pl.pragmatists.JUnitParams
// in that case method name will have the following structure:
// [test case number] param1, param2, param3 (methodName)
// e.g. [0] 2, 2, 4 (shouldReturnCorrectSum)
// methodName(param1, param2, param3) [test case number]
// e.g. test_parameterized(1, 2, 3) [0]

int parameterCount = countCharacter(methodName, ',') + 1;

methodName = methodName.substring(actualMethodNameStart + 1, actualMethodNameEnd);
methodName = methodName.substring(0, junitParamsStartIdx);

// below is a best-effort attempt to find a matching method with the information we have
// this is not terribly efficient, but this case should be rare
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,15 @@ import org.example.TestFailedSuiteTearDown
import org.example.TestFailedThenSucceed
import org.example.TestInheritance
import org.example.TestParameterized
import org.example.TestParameterizedJUnitParams
import org.example.TestSkipped
import org.example.TestSkippedClass
import org.example.TestSucceed
import org.example.TestSucceedAndSkipped
import org.example.TestSucceedExpectedException
import org.example.TestSucceedKotlin
import org.example.TestSucceedLegacy
import org.example.TestSucceedParameterizedKotlin
import org.example.TestSucceedSlow
import org.example.TestSucceedSuite
import org.example.TestSucceedUnskippable
Expand Down Expand Up @@ -60,6 +63,9 @@ class JUnit4Test extends CiVisibilityInstrumentationTest {
"test-parameterized" | [TestParameterized] | 3
"test-suite-runner" | [TestSucceedSuite] | 3
"test-legacy" | [TestSucceedLegacy] | 2
"test-parameterized-junit-params" | [TestParameterizedJUnitParams] | 3
"test-succeed-kotlin" | [TestSucceedKotlin] | 2
"test-succeed-parameterized-kotlin" | [TestSucceedParameterizedKotlin] | 3
}

def "test ITR #testcaseName"() {
Expand Down Expand Up @@ -100,7 +106,7 @@ class JUnit4Test extends CiVisibilityInstrumentationTest {
"test-retry-parameterized" | [TestFailedParameterized] | 7 | [
new TestIdentifier("org.example.TestFailedParameterized", "test_failed_parameterized", /* backend cannot provide parameters for flaky parameterized tests yet */ null, null)
]
"test-expected-exception-is-not-retried" | [TestSucceedExpectedException] | 2 | [new TestIdentifier("org.example.TestSucceedExpectedException", "test_succeed", null, null)]
"test-expected-exception-is-not-retried" | [TestSucceedExpectedException] | 2 | [new TestIdentifier("org.example.TestSucceedExpectedException", "test_succeed", null, null)]
}

def "test early flakiness detection #testcaseName"() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.example;

import static org.junit.Assert.assertEquals;

import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(JUnitParamsRunner.class)
public class TestParameterizedJUnitParams {

@Test
@Parameters({"1, 2, 3", "2, 2, 4"})
public void test_parameterized(int a, int b, int expectedValue) {
assertEquals(expectedValue, a + b);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.example

import org.junit.Assert
import org.junit.Test

class TestSucceedKotlin {

@Test
fun `single document (without provider) deserialized from json`() {
Assert.assertTrue(true)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.example

import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized

@RunWith(Parameterized::class)
class TestSucceedParameterizedKotlin(
private val param1: ParamObject,
private val param2: String,
private val param3: Int
) {

companion object {
@JvmStatic
@Parameterized.Parameters(name = "{1}")
fun data(): Collection<Array<Any>> = listOf(
arrayOf(ParamObject(), "str1", 0),
arrayOf(ParamObject(), "str2", 1)
)
}

@Test
fun `single document (without provider) deserialized from json`() {
assertTrue(true)
}

class ParamObject
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[ ]
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
[ {
"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" : "junit-4.10",
"start" : ${content_start},
"duration" : ${content_duration},
"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" : "junit-4.10",
"test.framework_version" : ${content_meta_test_framework_version},
"test.framework" : "junit4"
}
}
}, {
"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" : "junit-4.10",
"start" : ${content_start_2},
"duration" : ${content_duration_2},
"error" : 0,
"metrics" : { },
"meta" : {
"test.type" : "test",
"os.architecture" : ${content_meta_os_architecture},
"test.module" : "junit-4.10",
"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" : "junit4"
}
}
}, {
"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" : "org.example.TestParameterizedJUnitParams",
"start" : ${content_start_3},
"duration" : ${content_duration_3},
"error" : 0,
"metrics" : { },
"meta" : {
"test.type" : "test",
"os.architecture" : ${content_meta_os_architecture},
"test.source.file" : "dummy_source_path",
"test.module" : "junit-4.10",
"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" : "org.example.TestParameterizedJUnitParams",
"runtime.version" : ${content_meta_runtime_version},
"test.framework_version" : ${content_meta_test_framework_version},
"test.framework" : "junit4"
}
}
}, {
"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" : "org.example.TestParameterizedJUnitParams.test_parameterized(1, 2, 3) ",
"start" : ${content_start_4},
"duration" : ${content_duration_4},
"error" : 0,
"metrics" : {
"process_id" : ${content_metrics_process_id},
"_dd.profiling.enabled" : 0,
"_dd.trace_span_attribute_schema" : 0,
"test.source.end" : 18,
"test.source.start" : 12
},
"meta" : {
"os.architecture" : ${content_meta_os_architecture},
"test.source.file" : "dummy_source_path",
"test.source.method" : "test_parameterized(III)V",
"test.module" : "junit-4.10",
"test.status" : "pass",
"language" : "jvm",
"runtime.name" : ${content_meta_runtime_name},
"os.platform" : ${content_meta_os_platform},
"test.codeowners" : "[\"owner1\",\"owner2\"]",
"os.version" : ${content_meta_os_version},
"library_version" : ${content_meta_library_version},
"test.name" : "test_parameterized(1, 2, 3) ",
"span.kind" : "test",
"test.suite" : "org.example.TestParameterizedJUnitParams",
"runtime.version" : ${content_meta_runtime_version},
"runtime-id" : ${content_meta_runtime_id},
"test.type" : "test",
"runtime.vendor" : ${content_meta_runtime_vendor},
"env" : "none",
"dummy_ci_tag" : "dummy_ci_tag_value",
"test.parameters" : "{\"metadata\":{\"test_name\":\"test_parameterized(1, 2, 3) [0]\"}}",
"component" : "junit",
"_dd.profiling.ctx" : "test",
"test.framework_version" : ${content_meta_test_framework_version},
"test.framework" : "junit4"
}
}
}, {
"type" : "test",
"version" : 2,
"content" : {
"trace_id" : ${content_trace_id_2},
"span_id" : ${content_span_id_2},
"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" : "org.example.TestParameterizedJUnitParams.test_parameterized(2, 2, 4) ",
"start" : ${content_start_5},
"duration" : ${content_duration_5},
"error" : 0,
"metrics" : {
"process_id" : ${content_metrics_process_id},
"_dd.profiling.enabled" : 0,
"_dd.trace_span_attribute_schema" : 0,
"test.source.end" : 18,
"test.source.start" : 12
},
"meta" : {
"os.architecture" : ${content_meta_os_architecture},
"test.source.file" : "dummy_source_path",
"test.source.method" : "test_parameterized(III)V",
"test.module" : "junit-4.10",
"test.status" : "pass",
"language" : "jvm",
"runtime.name" : ${content_meta_runtime_name},
"os.platform" : ${content_meta_os_platform},
"test.codeowners" : "[\"owner1\",\"owner2\"]",
"os.version" : ${content_meta_os_version},
"library_version" : ${content_meta_library_version},
"test.name" : "test_parameterized(2, 2, 4) ",
"span.kind" : "test",
"test.suite" : "org.example.TestParameterizedJUnitParams",
"runtime.version" : ${content_meta_runtime_version},
"runtime-id" : ${content_meta_runtime_id},
"test.type" : "test",
"runtime.vendor" : ${content_meta_runtime_vendor},
"env" : "none",
"dummy_ci_tag" : "dummy_ci_tag_value",
"test.parameters" : "{\"metadata\":{\"test_name\":\"test_parameterized(2, 2, 4) [1]\"}}",
"component" : "junit",
"_dd.profiling.ctx" : "test",
"test.framework_version" : ${content_meta_test_framework_version},
"test.framework" : "junit4"
}
}
} ]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[ ]
Loading
Loading