junit-team / junit5

✅ The 5th major version of the programmer-friendly testing framework for Java and the JVM
https://junit.org
Other
6.35k stars 1.48k forks source link

[ERROR] Task was deferred but should have been executed synchronously #4027

Open fslev opened 2 days ago

fslev commented 2 days ago

I've upgraded my Cucumber test framework with JUnit 5.11.1 and I get a new error:

[ERROR]   Task was deferred but should have been executed synchronously: NodeTestTask [PickleDescriptor: [engine:junit-platform-suite]/[suite:com.ionos.cloud.cucumber.ml.MlApiTest]/[engine:cucumber]/[feature:classpath%3Afeatures%2FModel%2FModelLB.feature]/[scenario:26]]

All I can say is that inside the feature file I have two scenarios: one marked with @isolated global read write exclusive resource and another scenario is marked with a simple read write exclusive resource.

Reverting to JUnit 5.11.0 works without any error !

I'm sorry I cannot give more details. Maybe I will try to isolate it to a more detailed scenario when I'll have more time.

mpkorstanje commented 2 days ago

This can be reproduced with https://github.com/mpkorstanje/junit5-locks/tree/main

Feature: example

  @isolated
  Scenario: a
    When I wait 1 hour

  @reads-and-writes-system-properties
  Scenario: b
    When I wait 1 hour
cucumber.execution.parallel.enabled=true
cucumber.execution.parallel.config.strategy=fixed
cucumber.execution.parallel.config.fixed.parallelism=2
cucumber.execution.exclusive-resources.isolated.read-write=org.junit.platform.engine.support.hierarchical.ExclusiveResource.GLOBAL_KEY
cucumber.execution.exclusive-resources.reads-and-writes-system-properties.read-write=java.lang.System.properties
package io.cucumber.skeleton;

import io.cucumber.java.en.When;

import java.util.concurrent.TimeUnit;

public class StepDefinitions {
    @When("I wait {int} hour")
    public void iWaitHour(int arg0) throws InterruptedException {
        TimeUnit.SECONDS.sleep(arg0);
    }
}

Unlike with JUnit Jupiter the ExclusiveResource.GLOBAL_KEY is not used at top level:

example
 - a  <- locks ExclusiveResource.GLOBAL_KEY
 - b <-  locks java.lang.System.properties

Prior to executing b, the nop lock from example and the exclusive resource from a is still held in the thread locks.

resourceLock = {SingleLock@3016} "SingleLock [resource = ExclusiveResource [key = 'java.lang.System.properties', lockMode = READ_WRITE]]"
 resources = {Collections$SingletonList@3025}  size = 1
  0 = {ExclusiveResource@3029} "ExclusiveResource [key = 'java.lang.System.properties', lockMode = READ_WRITE]"
 lock = {ReentrantReadWriteLock$WriteLock@3026} "java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock@2c79993b[Unlocked]"
threadLock = {ForkJoinPoolHierarchicalTestExecutorService$ThreadLock@2471} 
 locks = {ArrayDeque@3023}  size = 2
  0 = {SingleLock@2677} "SingleLock [resource = ExclusiveResource [key = 'org.junit.platform.engine.support.hierarchical.ExclusiveResource.GLOBAL_KEY', lockMode = READ_WRITE]]"
  1 = {NopLock@2217} "NopLock []"

So then ResourceLock.isCompatible returns false because

https://github.com/junit-team/junit5/blob/d0130853639346c962609e9f8b711336879e39ca/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ResourceLock.java#L81-L85

And it is worth noting that the comment about the ExclusiveResource.GLOBAL_KEY only applies to JUnit Jupiter.

https://github.com/junit-team/junit5/blob/d0130853639346c962609e9f8b711336879e39ca/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ResourceLock.java#L78-L80