From fe5d62863dc8da623dbc6388f0501ff16e54347e Mon Sep 17 00:00:00 2001 From: Dmitry Baev Date: Fri, 28 Aug 2026 18:34:37 +0100 Subject: [PATCH] Honor metadata label tags across Java test integrations --- allure-cucumber7-jvm/README.md | 3 +- allure-cucumber7-jvm/build.gradle.kts | 38 ++++++++++++ .../cucumber7jvm/AllureCucumber7JvmTest.java | 44 +++++++++++++ .../resources/features/metadata-tags.feature | 16 +++++ .../io/qameta/allure/AllureLifecycle.java | 61 ++++++++++++++++--- .../io/qameta/allure/AllureLifecycleTest.java | 55 +++++++++++++++++ .../AllureJunitPlatformTest.java | 24 ++++++++ .../junitplatform/features/TaggedTests.java | 2 + .../allure/junit4/AllureJunit4Test.java | 28 +++++++++ .../junit4/samples/MetadataTagTest.java | 32 ++++++++++ .../allure/karate/AllureKarateTest.java | 25 ++++++++ .../src/test/resources/testdata/tags.feature | 5 ++ .../allure/spock2/AllureSpock2Test.java | 28 +++++++++ .../spock2/samples/SpockMetadataTag.groovy | 32 ++++++++++ .../allure/testng/AllureTestNgTest.java | 27 ++++++++ .../testng/samples/MetadataTagTest.java | 32 ++++++++++ .../test/resources/suites/metadata-tag.xml | 10 +++ 17 files changed, 452 insertions(+), 10 deletions(-) create mode 100644 allure-cucumber7-jvm/src/test/resources/features/metadata-tags.feature create mode 100644 allure-junit4/src/test/java/io/qameta/allure/junit4/samples/MetadataTagTest.java create mode 100644 allure-spock2/src/test/groovy/io/qameta/allure/spock2/samples/SpockMetadataTag.groovy create mode 100644 allure-testng/src/test/java/io/qameta/allure/testng/samples/MetadataTagTest.java create mode 100644 allure-testng/src/test/resources/suites/metadata-tag.xml diff --git a/allure-cucumber7-jvm/README.md b/allure-cucumber7-jvm/README.md index 118b06228..936bf4831 100644 --- a/allure-cucumber7-jvm/README.md +++ b/allure-cucumber7-jvm/README.md @@ -8,7 +8,8 @@ Use this module when your BDD tests run on Cucumber JVM 7 and you want features, - Allure Java 3.x requires Java 17 or newer. - This module targets Cucumber JVM 7.x. -- The current build validates against Cucumber JVM 7.34.3 and Gherkin 36.1.0. +- The main test suite validates against Cucumber JVM 7.34.7, and a focused compatibility test validates the + metadata-label tag contract against the oldest runtime supported by the current adapter API, 7.3.0. ## Installation diff --git a/allure-cucumber7-jvm/build.gradle.kts b/allure-cucumber7-jvm/build.gradle.kts index ea33cb511..9a644cd56 100644 --- a/allure-cucumber7-jvm/build.gradle.kts +++ b/allure-cucumber7-jvm/build.gradle.kts @@ -1,6 +1,7 @@ description = "Allure CucumberJVM 7.0" val cucumberVersion = "7.34.7" +val minimumCucumberVersion = "7.3.0" dependencies { api(project(":allure-java-commons")) @@ -35,4 +36,41 @@ tasks.jar { tasks.test { useJUnitPlatform() + systemProperty("allure.test.cucumber.version", cucumberVersion) +} + +val minimumCucumberTestRuntimeClasspath = configurations.testRuntimeClasspath.get().copyRecursive().apply { + resolutionStrategy.eachDependency { + if (requested.group == "io.cucumber" && requested.name == "cucumber-bom") { + useVersion(minimumCucumberVersion) + because("7.3.0 is the oldest Cucumber JVM runtime supported by the current adapter API") + } + } +} + +val cucumber7MinimumVersionTest = tasks.register("cucumber7MinimumVersionTest") { + description = "Runs the metadata-label tag regression against Cucumber JVM $minimumCucumberVersion" + group = "verification" + dependsOn(tasks.testClasses) + mustRunAfter(tasks.test) + + testClassesDirs = sourceSets.test.get().output.classesDirs + classpath = sourceSets.main.get().output + sourceSets.test.get().output + minimumCucumberTestRuntimeClasspath + useJUnitPlatform() + filter { + includeTestsMatching( + "io.qameta.allure.cucumber7jvm.AllureCucumber7JvmTest.shouldPreferMetadataTagHierarchyOverDefaults" + ) + } + + val standardTest = tasks.test.get() + systemProperties(standardTest.systemProperties) + systemProperty("allure.test.cucumber.version", minimumCucumberVersion) + jvmArgs = standardTest.jvmArgs + maxHeapSize = standardTest.maxHeapSize + maxParallelForks = standardTest.maxParallelForks +} + +tasks.check { + dependsOn(cucumber7MinimumVersionTest) } diff --git a/allure-cucumber7-jvm/src/test/java/io/qameta/allure/cucumber7jvm/AllureCucumber7JvmTest.java b/allure-cucumber7-jvm/src/test/java/io/qameta/allure/cucumber7jvm/AllureCucumber7JvmTest.java index 98f28ba69..5c4fd2253 100644 --- a/allure-cucumber7-jvm/src/test/java/io/qameta/allure/cucumber7jvm/AllureCucumber7JvmTest.java +++ b/allure-cucumber7-jvm/src/test/java/io/qameta/allure/cucumber7jvm/AllureCucumber7JvmTest.java @@ -59,6 +59,8 @@ import java.util.stream.Collectors; import static io.qameta.allure.util.ResultsUtils.PACKAGE_LABEL_NAME; +import static io.qameta.allure.util.ResultsUtils.PARENT_SUITE_LABEL_NAME; +import static io.qameta.allure.util.ResultsUtils.SUB_SUITE_LABEL_NAME; import static io.qameta.allure.util.ResultsUtils.SUITE_LABEL_NAME; import static io.qameta.allure.util.ResultsUtils.TEST_CLASS_LABEL_NAME; import static io.qameta.allure.util.ResultsUtils.TEST_METHOD_LABEL_NAME; @@ -71,6 +73,8 @@ @IsolatedLifecycle class AllureCucumber7JvmTest { + private static final String EXPECTED_CUCUMBER_VERSION_PROPERTY = "allure.test.cucumber.version"; + @AllureFeatures.Base @Test void shouldSetName() { @@ -376,6 +380,46 @@ void shouldAddTags() { ); } + /** + * Metadata tags must replace Cucumber's generated hierarchy defaults so report generation cannot place the + * same scenario under both hierarchies. + */ + @Description + @Test + void shouldPreferMetadataTagHierarchyOverDefaults() { + assertThat(Runtime.class.getPackage().getImplementationVersion()) + .as("Cucumber runtime version") + .isEqualTo(System.getProperty(EXPECTED_CUCUMBER_VERSION_PROPERTY)); + + final AllureResults results = runFeature("features/metadata-tags.feature"); + + final List testResults = results.getTestResults(); + assertThat(testResults) + .hasSize(3) + .allSatisfy(testResult -> { + assertThat(testResult.getLabels()) + .filteredOn( + label -> PARENT_SUITE_LABEL_NAME.equals(label.getName()) + || SUITE_LABEL_NAME.equals(label.getName()) + || SUB_SUITE_LABEL_NAME.equals(label.getName()) + ) + .extracting(Label::getName, Label::getValue) + .containsExactlyInAnyOrder( + tuple(PARENT_SUITE_LABEL_NAME, "Cucumber"), + tuple(SUITE_LABEL_NAME, "Petstore"), + tuple(SUB_SUITE_LABEL_NAME, "CRUD") + ); + assertThat(testResult.getLabels()) + .filteredOn(label -> "tag".equals(label.getName())) + .extracting(Label::getValue) + .doesNotContain( + "allure.label.parentSuite:Cucumber", + "allure.label.suite:Petstore", + "allure.label.subSuite:CRUD" + ); + }); + } + @AllureFeatures.Links @ExtendWith(SystemPropertyExtension.class) @SystemProperty( diff --git a/allure-cucumber7-jvm/src/test/resources/features/metadata-tags.feature b/allure-cucumber7-jvm/src/test/resources/features/metadata-tags.feature new file mode 100644 index 000000000..63bb5bb52 --- /dev/null +++ b/allure-cucumber7-jvm/src/test/resources/features/metadata-tags.feature @@ -0,0 +1,16 @@ +@allure.label.parentSuite:Cucumber +@allure.label.suite:Petstore +@allure.label.subSuite:CRUD +Feature: Arithmetic_operations + + Scenario Outline: Addition + Given a is + And b is + When I add a to b + Then result is + + Examples: + | a | b | result | + | 1 | 1 | 2 | + | 2 | 1 | 3 | + | 2 | 7 | 9 | diff --git a/allure-java-commons/src/main/java/io/qameta/allure/AllureLifecycle.java b/allure-java-commons/src/main/java/io/qameta/allure/AllureLifecycle.java index 77ad20a0a..ec7d5c0fc 100644 --- a/allure-java-commons/src/main/java/io/qameta/allure/AllureLifecycle.java +++ b/allure-java-commons/src/main/java/io/qameta/allure/AllureLifecycle.java @@ -64,9 +64,13 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.BiConsumer; import java.util.function.Consumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Stream; import static io.qameta.allure.AllureConstants.ATTACHMENT_FILE_SUFFIX; +import static io.qameta.allure.util.ResultsUtils.TAG_LABEL_NAME; +import static io.qameta.allure.util.ResultsUtils.createLabel; import static io.qameta.allure.util.ResultsUtils.firstNonEmpty; import static io.qameta.allure.util.ResultsUtils.getStatus; import static io.qameta.allure.util.ResultsUtils.getStatusDetails; @@ -101,6 +105,10 @@ public class AllureLifecycle { private static final Logger LOGGER = LoggerFactory.getLogger(AllureLifecycle.class); + private static final Pattern ALLURE_LABEL_TAG = Pattern.compile( + "^@?allure\\.label\\.(?.+)[:=](?.+)$" + ); + private static final String EXTERNAL_KEY = "external key"; private static final String KEY_NOT_FOUND = "Could not {}: item with key {} not found"; @@ -346,8 +354,8 @@ public void updateTest(final Consumer update) { * Registers default labels for the test with given key. Default labels do not appear on the test result until * the test stops: {@link #stopTest(AllureExternalKey)} merges them after scope metadata, adding, for each * distinct label name, the default labels with that name only when the test has no labels with that name by - * then. Labels provided by the user — through annotations, the runtime API, or before fixtures — thus take - * precedence over defaults instead of being duplicated by them. Repeated calls accumulate. + * then. Labels provided by the user — through annotations, framework tags, the runtime API, or before fixtures + * — thus take precedence over defaults instead of being duplicated by them. Repeated calls accumulate. * *

Intended for the framework-computed grouping labels a user may legitimately override: the suite family * and BDD structure labels. System labels — framework, language, host, thread, package, testClass, testMethod @@ -366,11 +374,12 @@ public void addDefaultLabels(final AllureExternalKey key, final Collection