Skip to content

🐞: allure-spock2 tests uuid conflicts during parallel tests execution #1203

@n1kolass

Description

@n1kolass

What happened?

There is an issue with allure-results reporting during parallel tests execution using Spock framework:

// File SpockConfig.groovy
runner {
    parallel {
        enabled true
        dynamicWithReservedProcessors(1.0, 0)
    }
}

I am not 100% sure how to reproduce the issue, but with a large number of tests and with run in parallel, there is an issue, when allure-spock2 extension AllureSpock2 reuses ThreadLocal<String> testResults with already defined initial UUID. It leads to the tests being registered with a non-unique UUID.
The symptoms are:

2025-10-15 14:17:09,189 [ERROR] [ForkJoinPool-1-worker-9] [] - io.qameta.allure.AllureLifecycle.updateTestCase - Could not update test case: test case with uuid 4a4716fb-ada4-40ab-91a7-9fd615c19401 not found
2025-10-15 14:17:09,189 [ERROR] [ForkJoinPool-1-worker-9] [] - io.qameta.allure.AllureLifecycle.stopTestCase - Could not stop test case: test case with uuid 4a4716fb-ada4-40ab-91a7-9fd615c19401 not found
2025-10-15 14:17:09,189 [ERROR] [ForkJoinPool-1-worker-9] [] - io.qameta.allure.AllureLifecycle.writeTestCase - Could not write test case: test case with uuid 4a4716fb-ada4-40ab-91a7-9fd615c19401 not found

And there are fewer tests in the Allure report than were actually run.

I've prepared the fix, but I do not have permissions to push into the repo.

Please, take a look at the fix below, and if you find it suitable - apply the fix.

// allure-spock2/src/main/java/io/qameta/allure/spock2/AllureSpock2.java 
// instead of
private final ThreadLocal<String> testResults = new InheritableThreadLocal<String>() {
    @Override
    protected String initialValue() {
        return UUID.randomUUID().toString();
    }
};
// use
private final ThreadLocal<String> testResults = new ThreadLocal<>();

// in beforeIteration
@Override
public void beforeIteration(final IterationInfo iteration) {
    final String uuid = UUID.randomUUID().toString();
    testResults.set(uuid);
    // ...
}

// in afterIteration
@Override
public void afterIteration(final IterationInfo iteration) {
    final String uuid = testResults.get();

    if (uuid == null) {
        return;
    }

    try {
        getLifecycle().updateTestCase(uuid, testResult -> {
            if (Objects.isNull(testResult.getStatus())) {
                testResult.setStatus(Status.PASSED);
            }
        });
        getLifecycle().stopTestCase(uuid);
        getLifecycle().writeTestCase(uuid);
    } finally {
        testResults.remove();
    }
}

What Allure Integration are you using?

allure-spock2

What version of Allure Integration you are using?

2.30.0

What version of Allure Report you are using?

2.12.0

Code of Conduct

  • I agree to follow this project's Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions