From 55663bcd75e7aac1611d00590a44e260c1a6a73a Mon Sep 17 00:00:00 2001 From: Calvin Bayer Date: Mon, 19 Oct 2026 23:13:23 +0200 Subject: [PATCH] Expose and verify native MUnit automation exclusion declarations --- .../src/test/groovy/MUnitTest.groovy | 33 +++++++++++++++++++ .../org/example/TestAutomationExcluded.scala | 18 ++++++++++ docs/test-automation-exclusions.md | 18 ++++++++++ 3 files changed, 69 insertions(+) create mode 100644 dd-java-agent/instrumentation/junit/junit-4/junit-4-munit-0.7.28/src/test/scala/org/example/TestAutomationExcluded.scala diff --git a/dd-java-agent/instrumentation/junit/junit-4/junit-4-munit-0.7.28/src/test/groovy/MUnitTest.groovy b/dd-java-agent/instrumentation/junit/junit-4/junit-4-munit-0.7.28/src/test/groovy/MUnitTest.groovy index f473ea62bcc..912daf3010b 100644 --- a/dd-java-agent/instrumentation/junit/junit-4/junit-4-munit-0.7.28/src/test/groovy/MUnitTest.groovy +++ b/dd-java-agent/instrumentation/junit/junit-4/junit-4-munit-0.7.28/src/test/groovy/MUnitTest.groovy @@ -8,6 +8,7 @@ import datadog.trace.instrumentation.junit4.MUnitUtils import datadog.trace.instrumentation.junit4.TestEventsHandlerHolder import org.example.TestFailedAssumptionMUnit import org.example.TestFailedMUnit +import org.example.TestAutomationExcluded import org.example.TestFailedThenSucceedMUnit import org.example.TestSkippedMUnit import org.example.TestSkippedSuiteMUnit @@ -21,6 +22,38 @@ class MUnitTest extends CiVisibilityInstrumentationTest { def runner = new JUnitCore() + def "test automation exclusions preserve a blocking failure and execute once"() { + given: + def id = new TestFQN("org.example.TestAutomationExcluded", "protected_failure") + givenDisabledTests([id]) + givenQuarantinedTests([id]) + givenAttemptToFixTests([id]) + givenFlakyRetryEnabled(true) + givenFlakyTests([id]) + givenEarlyFlakinessDetectionEnabled(true) + givenKnownTests([]) + + when: + runTests([TestAutomationExcluded], false) + + then: + TEST_WRITER.toList().flatten().count { it.getTag("test.name") == "protected_failure" } == 1 + def testSpan = TEST_WRITER.toList().flatten().find { it.getTag("test.name") == "protected_failure" } + testSpan != null + testSpan.getTag("test.test_management.no_auto_retry") == true + testSpan.getTag("test.test_management.prevent_failure_suppression") == true + testSpan.getTag("test.test_management.is_test_disabled") == true + testSpan.getTag("test.test_management.is_quarantined") == true + testSpan.getTag("test.test_management.is_attempt_to_fix") == true + testSpan.getTag("test.test_management.attempt_to_fix_passed") == null + def skippedSpan = TEST_WRITER.toList().flatten().find { it.getTag("test.name") == "protected_skip" } + skippedSpan != null + skippedSpan.getTag("test.test_management.no_auto_retry") == true + skippedSpan.getTag("test.test_management.prevent_failure_suppression") == true + skippedSpan.getTag("test.status").toString() == "skip" + } + + def "test #testcaseName"() { runTests(tests) diff --git a/dd-java-agent/instrumentation/junit/junit-4/junit-4-munit-0.7.28/src/test/scala/org/example/TestAutomationExcluded.scala b/dd-java-agent/instrumentation/junit/junit-4/junit-4-munit-0.7.28/src/test/scala/org/example/TestAutomationExcluded.scala new file mode 100644 index 00000000000..19aec4b48bb --- /dev/null +++ b/dd-java-agent/instrumentation/junit/junit-4/junit-4-munit-0.7.28/src/test/scala/org/example/TestAutomationExcluded.scala @@ -0,0 +1,18 @@ +package org.example + +import datadog.trace.api.civisibility.TestAutomationExclusions +import munit.FunSuite + +class TestAutomationExcluded extends FunSuite { + private val noRetry = new munit.Tag(TestAutomationExclusions.NO_AUTO_RETRY) + private val preventSuppression = + new munit.Tag(TestAutomationExclusions.PREVENT_FAILURE_SUPPRESSION) + + test("protected_failure".tag(noRetry).tag(preventSuppression)) { + assert(false) + } + + test("protected_skip".tag(noRetry).tag(preventSuppression).ignore) { + assert(false) + } +} diff --git a/docs/test-automation-exclusions.md b/docs/test-automation-exclusions.md index 8285366066c..898d9b8dadd 100644 --- a/docs/test-automation-exclusions.md +++ b/docs/test-automation-exclusions.md @@ -67,3 +67,21 @@ scenario tags before Datadog skipping and retry policy selection. Declare ScalaTest `Tag` instances from `TestAutomationExclusions.NO_AUTO_RETRY` and `PREVENT_FAILURE_SUPPRESSION`, then pass them to the test declaration. Native ignored tests remain ignored and carry their known exclusion tags. + +## MUnit + +Apply native MUnit tags using the public constants: + +```scala +import datadog.trace.api.civisibility.TestAutomationExclusions + +test("critical behavior" + .tag(new munit.Tag(TestAutomationExclusions.NO_AUTO_RETRY)) + .tag(new munit.Tag(TestAutomationExclusions.PREVENT_FAILURE_SUPPRESSION))) { + assert(false) +} +``` + +MUnit's existing category bridge passes these declarations to the shared policy +and reporter. Ignored tests retain their known tags. MUnit currently has no +Datadog disabling capability; exclusions do not enable unsupported automation.