From 30e9a1345a14cd1620cd8e7f09a2bb89291ea07a Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Fri, 31 Jul 2026 11:49:00 +0200 Subject: [PATCH 1/3] Carve slow/e2e tests into separate testSlow tasks, run only nightly/pre-release Tag long-running tests with @Tag("slow"), exclude them from the default test tasks, and add testSlow${Config} Gradle tasks (wired to gtest deps) run only by the nightly and release-validated CI workflows. Co-Authored-By: Claude Sonnet 5 --- .github/scripts/test_alpine_aarch64.sh | 8 +- .github/workflows/nightly.yml | 8 +- .github/workflows/release-validated.yml | 14 +++- .github/workflows/test_workflow.yml | 20 +++-- .../datadoghq/profiler/ProfilerTestPlugin.kt | 79 ++++++++++++++----- .../jfr/DumpWhileChurningThreadsTest.java | 2 + .../jfr/ObjectSampleDumpSmokeTest.java | 2 + .../memleak/CleanupAfterClassUnloadTest.java | 2 + .../memleak/GetLineNumberTableLeakTest.java | 2 + .../JMethodIDInvalidationStressTest.java | 2 + .../WriteStackTracesAfterClassUnloadTest.java | 2 + .../profiler/test/ProfilerTestRunner.java | 14 ++++ 12 files changed, 126 insertions(+), 29 deletions(-) diff --git a/.github/scripts/test_alpine_aarch64.sh b/.github/scripts/test_alpine_aarch64.sh index c816004821..3dfb16b8a2 100755 --- a/.github/scripts/test_alpine_aarch64.sh +++ b/.github/scripts/test_alpine_aarch64.sh @@ -10,6 +10,7 @@ export LIBRARY="musl" export CONFIG="${3}" export JAVA_HOME="${4}" export JAVA_TEST_HOME="${5}" +SLOW_TESTS="${6:-false}" export PATH="${JAVA_HOME}/bin":${PATH} @@ -33,4 +34,9 @@ apk update && apk add curl moreutils wget hexdump linux-headers bash make g++ cl # Install debug symbols for musl libc apk add musl-dbg -./gradlew -PCI -PkeepJFRs :ddprof-test:test${CONFIG} --no-daemon --parallel --build-cache --no-watch-fs \ No newline at end of file +TASK_PREFIX="test" +if [ "${SLOW_TESTS}" = "true" ]; then + TASK_PREFIX="testSlow" +fi + +./gradlew -PCI -PkeepJFRs :ddprof-test:${TASK_PREFIX}${CONFIG} --no-daemon --parallel --build-cache --no-watch-fs \ No newline at end of file diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 2a9b0a1cd3..2751838c9e 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -18,6 +18,12 @@ jobs: # C++ gtests (ASan + TSan) run on every PR via native-sanitizer-tests in ci.yml. # Skip them here so the nightly focuses on Java functional tests under ASan. skip_gtest: true + run-slow-test: + uses: ./.github/workflows/test_workflow.yml + with: + configuration: '["debug"]' + skip_gtest: true + slow_tests: true fuzz: runs-on: ubuntu-latest continue-on-error: true @@ -52,7 +58,7 @@ jobs: path: ddprof-lib/fuzz/build/fuzz-crashes/ report-failures: runs-on: ubuntu-latest - needs: run-test + needs: [run-test, run-slow-test] if: failure() steps: - name: Download all failure artifacts diff --git a/.github/workflows/release-validated.yml b/.github/workflows/release-validated.yml index eb70807820..550d2cdee6 100644 --- a/.github/workflows/release-validated.yml +++ b/.github/workflows/release-validated.yml @@ -169,9 +169,17 @@ jobs: with: configuration: '["debug", "asan"]' + pre-release-slow-tests: + needs: validate-inputs + if: ${{ inputs.dry_run != true && inputs.skip_tests != true && inputs.release_type != 'retag' }} + uses: ./.github/workflows/test_workflow.yml + with: + configuration: '["debug"]' + slow_tests: true + create-release: - needs: [validate-inputs, pre-release-tests] - if: always() && needs.validate-inputs.result == 'success' && (needs.pre-release-tests.result == 'success' || needs.pre-release-tests.result == 'skipped') + needs: [validate-inputs, pre-release-tests, pre-release-slow-tests] + if: always() && needs.validate-inputs.result == 'success' && (needs.pre-release-tests.result == 'success' || needs.pre-release-tests.result == 'skipped') && (needs.pre-release-slow-tests.result == 'success' || needs.pre-release-slow-tests.result == 'skipped') runs-on: ubuntu-latest permissions: contents: write @@ -179,7 +187,7 @@ jobs: id-token: write # Needed to federate a token for the bump-PR create-release step steps: - name: Check test results - if: ${{ inputs.dry_run != true && inputs.skip_tests != true && inputs.release_type != 'retag' && needs.pre-release-tests.result != 'success' }} + if: ${{ inputs.dry_run != true && inputs.skip_tests != true && inputs.release_type != 'retag' && (needs.pre-release-tests.result != 'success' || needs.pre-release-slow-tests.result != 'success') }} run: | echo "::error::Pre-release tests failed. Cannot proceed with release." exit 1 diff --git a/.github/workflows/test_workflow.yml b/.github/workflows/test_workflow.yml index b7b9c764fc..767a9917f9 100644 --- a/.github/workflows/test_workflow.yml +++ b/.github/workflows/test_workflow.yml @@ -11,6 +11,11 @@ on: required: false type: boolean default: false + slow_tests: + description: "Run the slow/e2e test suite (testSlow) instead of the regular suite" + required: false + type: boolean + default: false permissions: contents: read @@ -133,7 +138,7 @@ jobs: for attempt in $(seq 1 $MAX_ATTEMPTS); do mkdir -p build/logs - ${GRADLEW_PREFIX} ./gradlew -PCI -PkeepJFRs ${{ inputs.skip_gtest == true && '-Pskip-gtest' || '' }} :ddprof-test:test${{ matrix.config }} --no-daemon --parallel --build-cache --no-watch-fs 2>&1 \ + ${GRADLEW_PREFIX} ./gradlew -PCI -PkeepJFRs ${{ inputs.skip_gtest == true && '-Pskip-gtest' || '' }} :ddprof-test:test${{ inputs.slow_tests && 'Slow' || '' }}${{ matrix.config }} --no-daemon --parallel --build-cache --no-watch-fs 2>&1 \ | tee -a build/test-raw.log \ | python3 -u .github/scripts/filter_gradle_log.py EXIT_CODE=${PIPESTATUS[0]} @@ -273,7 +278,7 @@ jobs: echo "JAVA_VERSION=${JAVA_VERSION}" mkdir -p build/logs - ./gradlew -PCI -PkeepJFRs :ddprof-test:test${{ matrix.config }} --no-daemon --parallel --build-cache --no-watch-fs 2>&1 \ + ./gradlew -PCI -PkeepJFRs :ddprof-test:test${{ inputs.slow_tests && 'Slow' || '' }}${{ matrix.config }} --no-daemon --parallel --build-cache --no-watch-fs 2>&1 \ | tee -a build/test-raw.log \ | python3 -u .github/scripts/filter_gradle_log.py EXIT_CODE=${PIPESTATUS[0]} @@ -387,10 +392,14 @@ jobs: - name: Setup OS if: steps.set_enabled.outputs.enabled == 'true' run: | + # ports.ubuntu.com's IPv6 route is intermittently unreachable from GH-hosted + # aarch64 runners; force IPv4 so apt doesn't stall/fail on a dead IPv6 path, + # and retry on top in case of other transient connection blips. + printf 'Acquire::ForceIPv4 "true";\nAcquire::Retries "5";\n' | sudo tee /etc/apt/apt.conf.d/99force-ipv4 >/dev/null sudo apt update -y sudo apt remove -y g++ sudo apt autoremove -y - sudo apt install -y curl zip unzip clang make build-essential binutils gdb + sudo apt install -y curl zip unzip clang make build-essential binutils gdb libgtest-dev libgmock-dev # Install debug symbols for system libraries sudo apt install -y libc6-dbg if [[ ${{ matrix.java_version }} =~ "-zing" ]]; then @@ -448,7 +457,7 @@ jobs: for attempt in $(seq 1 $MAX_ATTEMPTS); do mkdir -p build/logs - ${GRADLEW_PREFIX} ./gradlew -PCI -PkeepJFRs ${{ inputs.skip_gtest == true && '-Pskip-gtest' || '' }} :ddprof-test:test${{ matrix.config }} --no-daemon --parallel --build-cache --no-watch-fs 2>&1 \ + ${GRADLEW_PREFIX} ./gradlew -PCI -PkeepJFRs ${{ inputs.skip_gtest == true && '-Pskip-gtest' || '' }} :ddprof-test:test${{ inputs.slow_tests && 'Slow' || '' }}${{ matrix.config }} --no-daemon --parallel --build-cache --no-watch-fs 2>&1 \ | tee -a build/test-raw.log \ | python3 -u .github/scripts/filter_gradle_log.py EXIT_CODE=${PIPESTATUS[0]} @@ -565,7 +574,8 @@ jobs: docker run --cpus 4 --rm -v /tmp:/tmp -v "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}" -w "${GITHUB_WORKSPACE}" alpine:3.21 /bin/sh -c " \"$GITHUB_WORKSPACE/.github/scripts/test_alpine_aarch64.sh\" \ \"${{ github.sha }}\" \"musl/${{ matrix.java_version }}-${{ matrix.config }}-aarch64\" \ - \"${{ matrix.config }}\" \"${{ env.JAVA_HOME }}\" \"${{ env.JAVA_TEST_HOME }}\" + \"${{ matrix.config }}\" \"${{ env.JAVA_HOME }}\" \"${{ env.JAVA_TEST_HOME }}\" \ + \"${{ inputs.slow_tests }}\" " 2>&1 \ | tee -a build/test-raw.log \ | python3 -u .github/scripts/filter_gradle_log.py diff --git a/build-logic/conventions/src/main/kotlin/com/datadoghq/profiler/ProfilerTestPlugin.kt b/build-logic/conventions/src/main/kotlin/com/datadoghq/profiler/ProfilerTestPlugin.kt index 4d85bc78ba..9cd5b964dc 100644 --- a/build-logic/conventions/src/main/kotlin/com/datadoghq/profiler/ProfilerTestPlugin.kt +++ b/build-logic/conventions/src/main/kotlin/com/datadoghq/profiler/ProfilerTestPlugin.kt @@ -244,6 +244,23 @@ class ProfilerTestPlugin : Plugin { ) } + /** + * Task name for a given config, shared between the glibc Test task and the musl Exec task + * so both platforms expose the same testXxx/testSlowXxx naming. + */ + private fun testTaskName(configName: String, slow: Boolean): String { + val capitalized = configName.replaceFirstChar { it.uppercase() } + return if (slow) "testSlow$capitalized" else "test$capitalized" + } + + private fun testTaskDescription(configName: String, slow: Boolean, platformSuffix: String = ""): String { + return if (slow) { + "Runs the slow/e2e test suite with the $configName library variant$platformSuffix" + } else { + "Runs unit tests with the $configName library variant$platformSuffix" + } + } + /** * Create native Test task for glibc/macOS (normal path). * Uses Gradle's Test task with -Ptests property support. @@ -253,11 +270,13 @@ class ProfilerTestPlugin : Plugin { extension: ProfilerTestExtension, testConfig: TestTaskConfiguration, testCfg: Configuration, - sourceSets: SourceSetContainer + sourceSets: SourceSetContainer, + slow: Boolean = false ) { - project.tasks.register("test${testConfig.configName.replaceFirstChar { it.uppercase() }}", Test::class.java) { + val taskName = testTaskName(testConfig.configName, slow) + project.tasks.register(taskName, Test::class.java) { val testTask = this - testTask.description = "Runs unit tests with the ${testConfig.configName} library variant" + testTask.description = testTaskDescription(testConfig.configName, slow) testTask.group = "verification" testTask.onlyIf { testConfig.isActive && !project.hasProperty("skip-tests") } @@ -271,7 +290,14 @@ class ProfilerTestPlugin : Plugin { testTask.classpath = testConfig.testClasspath // Use JUnit Platform - testTask.useJUnitPlatform() + testTask.useJUnitPlatform { + val platformOptions = this + if (slow) { + platformOptions.includeTags("slow") + } else { + platformOptions.excludeTags("slow") + } + } // Configure Java executable - bypasses toolchain system testTask.setExecutable(PlatformUtils.testJavaExecutable()) @@ -365,11 +391,13 @@ class ProfilerTestPlugin : Plugin { extension: ProfilerTestExtension, testConfig: TestTaskConfiguration, testCfg: Configuration, - sourceSets: SourceSetContainer + sourceSets: SourceSetContainer, + slow: Boolean = false ) { - project.tasks.register("test${testConfig.configName.replaceFirstChar { it.uppercase() }}", Exec::class.java) { + val taskName = testTaskName(testConfig.configName, slow) + project.tasks.register(taskName, Exec::class.java) { val execTask = this - execTask.description = "Runs unit tests with the ${testConfig.configName} library variant (musl workaround)" + execTask.description = testTaskDescription(testConfig.configName, slow, " (musl workaround)") execTask.group = "verification" execTask.onlyIf { testConfig.isActive && !project.hasProperty("skip-tests") } @@ -405,6 +433,14 @@ class ProfilerTestPlugin : Plugin { allArgs.add("-Dtest.filter=$testsFilter") } + // Carve out the "slow" suite the same way the glibc Test task does via + // useJUnitPlatform { includeTags/excludeTags } + if (slow) { + allArgs.add("-Dtest.tags.include=slow") + } else { + allArgs.add("-Dtest.tags.exclude=slow") + } + // Classpath (includes custom test runner) allArgs.add("-cp") allArgs.add(testConfig.testClasspath.asPath) @@ -508,9 +544,11 @@ class ProfilerTestPlugin : Plugin { if (isMuslSystem) { project.logger.info("Creating Exec task for $configName (musl workaround, LIBC=${System.getenv("LIBC")})") createExecTestTask(project, extension, testConfig, testCfg, sourceSets) + createExecTestTask(project, extension, testConfig, testCfg, sourceSets, slow = true) } else { project.logger.info("Creating Test task for $configName (glibc/macOS, LIBC=${System.getenv("LIBC")})") createTestTask(project, extension, testConfig, testCfg, sourceSets) + createTestTask(project, extension, testConfig, testCfg, sourceSets, slow = true) } // Create application tasks for specified configs @@ -654,22 +692,25 @@ class ProfilerTestPlugin : Plugin { } } - // Wire up gtest -> test dependencies (C++ tests run before Java tests) + // Wire up gtest -> test dependencies (C++ tests run before Java tests). + // Both the regular and slow/e2e test tasks get the same gtest dependency: each is an + // independent Gradle invocation (e.g. a separate CI job), so gtest coverage from a + // "sibling" regular test job doesn't carry over to a testSlow-only invocation. project.gradle.projectsEvaluated { configNames.forEach { cfgName -> val capitalizedCfgName = cfgName.replaceFirstChar { it.uppercaseChar() } - val testTaskName = "test$capitalizedCfgName" - val testTask = project.tasks.findByName(testTaskName) val profilerLibProject = project.rootProject.findProject(profilerLibProjectPath) - - if (profilerLibProject != null && testTask != null) { - // gtest runs before test (C++ unit tests run before Java integration tests) - val gtestTaskName = "gtest${capitalizedCfgName}" - try { - val gtestTask = profilerLibProject.tasks.named(gtestTaskName) - testTask.dependsOn(gtestTask) - } catch (e: org.gradle.api.UnknownTaskException) { - project.logger.info("Task $gtestTaskName not found in $profilerLibProjectPath - gtest may not be available") + val gtestTaskName = "gtest${capitalizedCfgName}" + + listOf("test$capitalizedCfgName", "testSlow$capitalizedCfgName").forEach { taskName -> + val testTask = project.tasks.findByName(taskName) + if (profilerLibProject != null && testTask != null) { + try { + val gtestTask = profilerLibProject.tasks.named(gtestTaskName) + testTask.dependsOn(gtestTask) + } catch (e: org.gradle.api.UnknownTaskException) { + project.logger.info("Task $gtestTaskName not found in $profilerLibProjectPath - gtest may not be available") + } } } } diff --git a/ddprof-test/src/test/java/com/datadoghq/profiler/jfr/DumpWhileChurningThreadsTest.java b/ddprof-test/src/test/java/com/datadoghq/profiler/jfr/DumpWhileChurningThreadsTest.java index 67d4a4265e..e64cae8d76 100644 --- a/ddprof-test/src/test/java/com/datadoghq/profiler/jfr/DumpWhileChurningThreadsTest.java +++ b/ddprof-test/src/test/java/com/datadoghq/profiler/jfr/DumpWhileChurningThreadsTest.java @@ -6,6 +6,7 @@ import com.datadoghq.profiler.junit.RetryTest; import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.Timeout; import org.junit.jupiter.params.provider.ValueSource; @@ -27,6 +28,7 @@ * Exercises the race by churning short-lived threads while calling dump() repeatedly. * A SIGSEGV would abort the JVM and fail the test with a non-zero exit code. */ +@Tag("slow") public class DumpWhileChurningThreadsTest extends CStackAwareAbstractProfilerTest { private static final int TEST_DURATION_SECS = 10; diff --git a/ddprof-test/src/test/java/com/datadoghq/profiler/jfr/ObjectSampleDumpSmokeTest.java b/ddprof-test/src/test/java/com/datadoghq/profiler/jfr/ObjectSampleDumpSmokeTest.java index d094916209..f73839cbfb 100644 --- a/ddprof-test/src/test/java/com/datadoghq/profiler/jfr/ObjectSampleDumpSmokeTest.java +++ b/ddprof-test/src/test/java/com/datadoghq/profiler/jfr/ObjectSampleDumpSmokeTest.java @@ -3,6 +3,7 @@ import com.datadoghq.profiler.Platform; import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Timeout; import org.junit.jupiter.params.provider.ValueSource; import org.junit.jupiter.api.TestTemplate; @@ -10,6 +11,7 @@ import com.datadoghq.profiler.junit.CStack; import com.datadoghq.profiler.junit.RetryTest; +@Tag("slow") public class ObjectSampleDumpSmokeTest extends JfrDumpTest { public ObjectSampleDumpSmokeTest(@CStack String cstack) { super(cstack); diff --git a/ddprof-test/src/test/java/com/datadoghq/profiler/memleak/CleanupAfterClassUnloadTest.java b/ddprof-test/src/test/java/com/datadoghq/profiler/memleak/CleanupAfterClassUnloadTest.java index 12ea41ccf9..895ead220c 100644 --- a/ddprof-test/src/test/java/com/datadoghq/profiler/memleak/CleanupAfterClassUnloadTest.java +++ b/ddprof-test/src/test/java/com/datadoghq/profiler/memleak/CleanupAfterClassUnloadTest.java @@ -15,6 +15,7 @@ */ package com.datadoghq.profiler.memleak; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; @@ -53,6 +54,7 @@ *
  • cleanupUnreferencedMethods() must not SIGSEGV when freeing the line number table
  • * */ +@Tag("slow") public class CleanupAfterClassUnloadTest extends AbstractDynamicClassTest { // AGE_THRESHOLD in C++ is 3; run 4 dumps to ensure cleanup fires diff --git a/ddprof-test/src/test/java/com/datadoghq/profiler/memleak/GetLineNumberTableLeakTest.java b/ddprof-test/src/test/java/com/datadoghq/profiler/memleak/GetLineNumberTableLeakTest.java index 32a5ede710..54d720b373 100644 --- a/ddprof-test/src/test/java/com/datadoghq/profiler/memleak/GetLineNumberTableLeakTest.java +++ b/ddprof-test/src/test/java/com/datadoghq/profiler/memleak/GetLineNumberTableLeakTest.java @@ -15,6 +15,7 @@ */ package com.datadoghq.profiler.memleak; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import java.io.IOException; @@ -49,6 +50,7 @@ *
  • Combined cleanup: method_map cleanup + class unloading
  • * */ +@Tag("slow") public class GetLineNumberTableLeakTest extends AbstractDynamicClassTest { @Override diff --git a/ddprof-test/src/test/java/com/datadoghq/profiler/memleak/JMethodIDInvalidationStressTest.java b/ddprof-test/src/test/java/com/datadoghq/profiler/memleak/JMethodIDInvalidationStressTest.java index 40f28a7f69..b098b46070 100644 --- a/ddprof-test/src/test/java/com/datadoghq/profiler/memleak/JMethodIDInvalidationStressTest.java +++ b/ddprof-test/src/test/java/com/datadoghq/profiler/memleak/JMethodIDInvalidationStressTest.java @@ -16,6 +16,7 @@ package com.datadoghq.profiler.memleak; import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; import org.objectweb.asm.ClassWriter; @@ -86,6 +87,7 @@ * is evidence of nothing more than "no crash was hit this time" for whatever code paths happened * to be exercised. */ +@Tag("slow") public class JMethodIDInvalidationStressTest extends AbstractDynamicClassTest { private static final int CHURN_THREADS = 4; diff --git a/ddprof-test/src/test/java/com/datadoghq/profiler/memleak/WriteStackTracesAfterClassUnloadTest.java b/ddprof-test/src/test/java/com/datadoghq/profiler/memleak/WriteStackTracesAfterClassUnloadTest.java index 2201f7cac0..21fd9f3100 100644 --- a/ddprof-test/src/test/java/com/datadoghq/profiler/memleak/WriteStackTracesAfterClassUnloadTest.java +++ b/ddprof-test/src/test/java/com/datadoghq/profiler/memleak/WriteStackTracesAfterClassUnloadTest.java @@ -9,6 +9,7 @@ */ package com.datadoghq.profiler.memleak; +import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; @@ -63,6 +64,7 @@ * covered by {@code CleanupAfterClassUnloadTest}. * */ +@Tag("slow") public class WriteStackTracesAfterClassUnloadTest extends AbstractDynamicClassTest { @Override diff --git a/ddprof-test/src/test/java/com/datadoghq/profiler/test/ProfilerTestRunner.java b/ddprof-test/src/test/java/com/datadoghq/profiler/test/ProfilerTestRunner.java index 2689256447..81649bef86 100644 --- a/ddprof-test/src/test/java/com/datadoghq/profiler/test/ProfilerTestRunner.java +++ b/ddprof-test/src/test/java/com/datadoghq/profiler/test/ProfilerTestRunner.java @@ -4,6 +4,7 @@ import org.junit.platform.engine.TestSource; import org.junit.platform.engine.discovery.ClassNameFilter; import org.junit.platform.engine.discovery.DiscoverySelectors; +import org.junit.platform.engine.discovery.TagFilter; import org.junit.platform.engine.support.descriptor.MethodSource; import org.junit.platform.launcher.Launcher; import org.junit.platform.launcher.LauncherDiscoveryRequest; @@ -33,6 +34,8 @@ * - -Dtest.filter=ClassName - Run all tests in a class * - -Dtest.filter=ClassName#method - Run specific test method * - -Dtest.filter=*.Pattern* - Pattern matching on class names + * - -Dtest.tags.include=tag1,tag2 - Only run tests tagged with one of these tags + * - -Dtest.tags.exclude=tag1,tag2 - Skip tests tagged with any of these tags */ public class ProfilerTestRunner { public static void main(String[] args) { @@ -106,6 +109,17 @@ private static void runTests() { ); } + // Tag filtering, orthogonal to the class/method filter above (e.g. carving the + // "slow" suite out of the default run, or selecting only "slow" tests for it). + String includeTags = System.getProperty("test.tags.include"); + if (includeTags != null && !includeTags.isEmpty()) { + requestBuilder.filters(TagFilter.includeTags(includeTags.split(","))); + } + String excludeTags = System.getProperty("test.tags.exclude"); + if (excludeTags != null && !excludeTags.isEmpty()) { + requestBuilder.filters(TagFilter.excludeTags(excludeTags.split(","))); + } + LauncherDiscoveryRequest request = requestBuilder.build(); // Create launcher and register listeners From 55029082901fdba8a40f184b561b67dc1e1ae9a8 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Fri, 31 Jul 2026 12:20:38 +0200 Subject: [PATCH 2/3] Fix TagFilter import in ProfilerTestRunner (wrong package) Co-Authored-By: Claude Sonnet 5 --- .../java/com/datadoghq/profiler/test/ProfilerTestRunner.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddprof-test/src/test/java/com/datadoghq/profiler/test/ProfilerTestRunner.java b/ddprof-test/src/test/java/com/datadoghq/profiler/test/ProfilerTestRunner.java index 81649bef86..18901a544e 100644 --- a/ddprof-test/src/test/java/com/datadoghq/profiler/test/ProfilerTestRunner.java +++ b/ddprof-test/src/test/java/com/datadoghq/profiler/test/ProfilerTestRunner.java @@ -4,10 +4,10 @@ import org.junit.platform.engine.TestSource; import org.junit.platform.engine.discovery.ClassNameFilter; import org.junit.platform.engine.discovery.DiscoverySelectors; -import org.junit.platform.engine.discovery.TagFilter; import org.junit.platform.engine.support.descriptor.MethodSource; import org.junit.platform.launcher.Launcher; import org.junit.platform.launcher.LauncherDiscoveryRequest; +import org.junit.platform.launcher.TagFilter; import org.junit.platform.launcher.TestExecutionListener; import org.junit.platform.launcher.TestIdentifier; import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; From 0a04cee77ba0d6addf944ced7558a2340851519f Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Mon, 3 Aug 2026 13:07:46 +0200 Subject: [PATCH 3/3] Namespace test artifacts by slow/regular, run slow tests under ASan, add copyright header Co-Authored-By: Claude Sonnet 5 --- .github/workflows/nightly.yml | 10 +++- .github/workflows/release-validated.yml | 2 +- .github/workflows/test_workflow.yml | 48 +++++++++---------- .../profiler/test/ProfilerTestRunner.java | 5 ++ 4 files changed, 39 insertions(+), 26 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 2751838c9e..7a98687458 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -24,6 +24,14 @@ jobs: configuration: '["debug"]' skip_gtest: true slow_tests: true + run-slow-test-asan: + uses: ./.github/workflows/test_workflow.yml + with: + configuration: '["asan"]' + # C++ gtests (ASan + TSan) run on every PR via native-sanitizer-tests in ci.yml. + # Skip them here so the nightly focuses on Java functional tests under ASan. + skip_gtest: true + slow_tests: true fuzz: runs-on: ubuntu-latest continue-on-error: true @@ -58,7 +66,7 @@ jobs: path: ddprof-lib/fuzz/build/fuzz-crashes/ report-failures: runs-on: ubuntu-latest - needs: [run-test, run-slow-test] + needs: [run-test, run-slow-test, run-slow-test-asan] if: failure() steps: - name: Download all failure artifacts diff --git a/.github/workflows/release-validated.yml b/.github/workflows/release-validated.yml index 550d2cdee6..e3086ba804 100644 --- a/.github/workflows/release-validated.yml +++ b/.github/workflows/release-validated.yml @@ -174,7 +174,7 @@ jobs: if: ${{ inputs.dry_run != true && inputs.skip_tests != true && inputs.release_type != 'retag' }} uses: ./.github/workflows/test_workflow.yml with: - configuration: '["debug"]' + configuration: '["debug", "asan"]' slow_tests: true create-release: diff --git a/.github/workflows/test_workflow.yml b/.github/workflows/test_workflow.yml index 767a9917f9..e3a1fa761a 100644 --- a/.github/workflows/test_workflow.yml +++ b/.github/workflows/test_workflow.yml @@ -167,13 +167,13 @@ jobs: uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: success() with: - name: (build) test-linux-glibc-amd64 (${{ matrix.java_version }}, ${{ matrix.config }}) + name: (build) test-linux-glibc-amd64 (${{ matrix.java_version }}, ${{ matrix.config }}, ${{ inputs.slow_tests && 'slow' || 'regular' }}) path: build/ - name: Upload failures uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: failure() with: - name: failures-glibc-${{ matrix.java_version }}-${{ matrix.config }}-amd64 + name: failures-glibc-${{ matrix.java_version }}-${{ matrix.config }}-amd64-${{ inputs.slow_tests && 'slow' || 'regular' }} path: failures_glibc-${{ matrix.java_version }}-${{ matrix.config }}-amd64.txt - name: Prepare reports if: always() && steps.set_enabled.outputs.enabled == 'true' @@ -183,26 +183,26 @@ jobs: uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: success() && matrix.config == 'debug' with: - name: (unwinding-reports) unwinding-linux-glibc-amd64 (${{ matrix.java_version }}, ${{ matrix.config }}) + name: (unwinding-reports) unwinding-linux-glibc-amd64 (${{ matrix.java_version }}, ${{ matrix.config }}, ${{ inputs.slow_tests && 'slow' || 'regular' }}) path: unwinding-reports - name: Upload test reports uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: failure() with: - name: (test-reports) test-linux-glibc-amd64 (${{ matrix.java_version }}, ${{ matrix.config }}) + name: (test-reports) test-linux-glibc-amd64 (${{ matrix.java_version }}, ${{ matrix.config }}, ${{ inputs.slow_tests && 'slow' || 'regular' }}) path: test-reports - name: Upload signal-safety violation log uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: failure() with: - name: signal-safety-violation-glibc-${{ matrix.java_version }}-${{ matrix.config }}-amd64 + name: signal-safety-violation-glibc-${{ matrix.java_version }}-${{ matrix.config }}-amd64-${{ inputs.slow_tests && 'slow' || 'regular' }} path: /tmp/signal-safety-violation.txt if-no-files-found: ignore - name: Upload ASan logs uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: failure() && matrix.config == 'asan' with: - name: asan-logs-glibc-${{ matrix.java_version }}-amd64 + name: asan-logs-glibc-${{ matrix.java_version }}-amd64-${{ inputs.slow_tests && 'slow' || 'regular' }} path: /tmp/asan.log.* if-no-files-found: ignore @@ -300,13 +300,13 @@ jobs: uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: success() with: - name: (build) test-linux-musl-amd64 (${{ matrix.java_version }}, ${{ matrix.config }}) + name: (build) test-linux-musl-amd64 (${{ matrix.java_version }}, ${{ matrix.config }}, ${{ inputs.slow_tests && 'slow' || 'regular' }}) path: build/ - name: Upload failures uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: failure() with: - name: failures-musl-${{ matrix.java_version }}-${{ matrix.config }}-amd64 + name: failures-musl-${{ matrix.java_version }}-${{ matrix.config }}-amd64-${{ inputs.slow_tests && 'slow' || 'regular' }} path: failures_musl-${{ matrix.java_version }}-${{ matrix.config }}-amd64.txt - name: Prepare reports if: always() @@ -316,26 +316,26 @@ jobs: uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: success() && matrix.config == 'debug' with: - name: (unwinding-reports) unwinding-linux-musl-amd64 (${{ matrix.java_version }}, ${{ matrix.config }}) + name: (unwinding-reports) unwinding-linux-musl-amd64 (${{ matrix.java_version }}, ${{ matrix.config }}, ${{ inputs.slow_tests && 'slow' || 'regular' }}) path: unwinding-reports - name: Upload test reports uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: failure() with: - name: (test-reports) test-linux-musl-amd64 (${{ matrix.java_version }}, ${{ matrix.config }}) + name: (test-reports) test-linux-musl-amd64 (${{ matrix.java_version }}, ${{ matrix.config }}, ${{ inputs.slow_tests && 'slow' || 'regular' }}) path: test-reports - name: Upload signal-safety violation log uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: failure() with: - name: signal-safety-violation-musl-${{ matrix.java_version }}-${{ matrix.config }}-amd64 + name: signal-safety-violation-musl-${{ matrix.java_version }}-${{ matrix.config }}-amd64-${{ inputs.slow_tests && 'slow' || 'regular' }} path: /tmp/signal-safety-violation.txt if-no-files-found: ignore - name: Upload ASan logs uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: failure() && matrix.config == 'asan' with: - name: asan-logs-musl-${{ matrix.java_version }}-amd64 + name: asan-logs-musl-${{ matrix.java_version }}-amd64-${{ inputs.slow_tests && 'slow' || 'regular' }} path: /tmp/asan.log.* if-no-files-found: ignore @@ -491,13 +491,13 @@ jobs: uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: success() with: - name: (build) test-linux-glibc-aarch64 (${{ matrix.java_version }}, ${{ matrix.config }}) + name: (build) test-linux-glibc-aarch64 (${{ matrix.java_version }}, ${{ matrix.config }}, ${{ inputs.slow_tests && 'slow' || 'regular' }}) path: build/ - name: Upload failures uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: failure() with: - name: failures-glibc-${{ matrix.java_version }}-${{ matrix.config }}-aarch64 + name: failures-glibc-${{ matrix.java_version }}-${{ matrix.config }}-aarch64-${{ inputs.slow_tests && 'slow' || 'regular' }} path: failures_glibc-${{ matrix.java_version }}-${{ matrix.config }}-aarch64.txt - name: Prepare reports if: always() && steps.set_enabled.outputs.enabled == 'true' @@ -507,26 +507,26 @@ jobs: uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: success() && matrix.config == 'debug' with: - name: (unwinding-reports) unwinding-linux-glibc-aarch64 (${{ matrix.java_version }}, ${{ matrix.config }}) + name: (unwinding-reports) unwinding-linux-glibc-aarch64 (${{ matrix.java_version }}, ${{ matrix.config }}, ${{ inputs.slow_tests && 'slow' || 'regular' }}) path: unwinding-reports - name: Upload test reports uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: failure() with: - name: (test-reports) test-linux-glibc-aarch64 (${{ matrix.java_version }}, ${{ matrix.config }}) + name: (test-reports) test-linux-glibc-aarch64 (${{ matrix.java_version }}, ${{ matrix.config }}, ${{ inputs.slow_tests && 'slow' || 'regular' }}) path: test-reports - name: Upload signal-safety violation log uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: failure() with: - name: signal-safety-violation-glibc-${{ matrix.java_version }}-${{ matrix.config }}-aarch64 + name: signal-safety-violation-glibc-${{ matrix.java_version }}-${{ matrix.config }}-aarch64-${{ inputs.slow_tests && 'slow' || 'regular' }} path: /tmp/signal-safety-violation.txt if-no-files-found: ignore - name: Upload ASan logs uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: failure() && matrix.config == 'asan' with: - name: asan-logs-glibc-${{ matrix.java_version }}-aarch64 + name: asan-logs-glibc-${{ matrix.java_version }}-aarch64-${{ inputs.slow_tests && 'slow' || 'regular' }} path: /tmp/asan.log.* if-no-files-found: ignore @@ -613,13 +613,13 @@ jobs: uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: success() with: - name: (build) test-linux-musl-aarch64 (${{ matrix.java_version }}, ${{ matrix.config }}) + name: (build) test-linux-musl-aarch64 (${{ matrix.java_version }}, ${{ matrix.config }}, ${{ inputs.slow_tests && 'slow' || 'regular' }}) path: build/ - name: Upload failures uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: failure() with: - name: failures-musl-${{ matrix.java_version }}-${{ matrix.config }}-aarch64 + name: failures-musl-${{ matrix.java_version }}-${{ matrix.config }}-aarch64-${{ inputs.slow_tests && 'slow' || 'regular' }} path: failures_musl-${{ matrix.java_version }}-${{ matrix.config }}-aarch64.txt - name: Prepare reports if: always() @@ -629,25 +629,25 @@ jobs: uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: success() && matrix.config == 'debug' with: - name: (unwinding-reports) unwinding-linux-musl-aarch64 (${{ matrix.java_version }}, ${{ matrix.config }}) + name: (unwinding-reports) unwinding-linux-musl-aarch64 (${{ matrix.java_version }}, ${{ matrix.config }}, ${{ inputs.slow_tests && 'slow' || 'regular' }}) path: unwinding-reports - name: Upload test reports uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: failure() with: - name: (test-reports) test-linux-musl-aarch64 (${{ matrix.java_version }}, ${{ matrix.config }}) + name: (test-reports) test-linux-musl-aarch64 (${{ matrix.java_version }}, ${{ matrix.config }}, ${{ inputs.slow_tests && 'slow' || 'regular' }}) path: test-reports - name: Upload signal-safety violation log uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: failure() with: - name: signal-safety-violation-musl-${{ matrix.java_version }}-${{ matrix.config }}-aarch64 + name: signal-safety-violation-musl-${{ matrix.java_version }}-${{ matrix.config }}-aarch64-${{ inputs.slow_tests && 'slow' || 'regular' }} path: /tmp/signal-safety-violation.txt if-no-files-found: ignore - name: Upload ASan logs uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: failure() && matrix.config == 'asan' with: - name: asan-logs-musl-${{ matrix.java_version }}-aarch64 + name: asan-logs-musl-${{ matrix.java_version }}-aarch64-${{ inputs.slow_tests && 'slow' || 'regular' }} path: /tmp/asan.log.* if-no-files-found: ignore diff --git a/ddprof-test/src/test/java/com/datadoghq/profiler/test/ProfilerTestRunner.java b/ddprof-test/src/test/java/com/datadoghq/profiler/test/ProfilerTestRunner.java index 18901a544e..ff7c0a2e68 100644 --- a/ddprof-test/src/test/java/com/datadoghq/profiler/test/ProfilerTestRunner.java +++ b/ddprof-test/src/test/java/com/datadoghq/profiler/test/ProfilerTestRunner.java @@ -1,3 +1,8 @@ +/* + * Copyright 2026, Datadog, Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + package com.datadoghq.profiler.test; import org.junit.platform.engine.TestExecutionResult;