Skip to content

Concurrency issue with resolving parameters in test methods using the SpringExtension #1686

@mdolinin

Description

@mdolinin

Concurrency issues with resolving parameters in test methods

Steps to reproduce

  • Gradle java project with Junit5 tests that use SpringExtension
  • Have at least one method @Test/@BeforeEach with parameter annotated with spring @Autowired
  • Run all test with enabled default parallel strategy junit.jupiter.execution.parallel.enabled= true
  • And with default "per-method" test instance lifecycle

Expected behavior

  • Test passed

Actual behavior

  • Some times get concurrency issues for example
Caused by: java.lang.IllegalArgumentException: 
Given parameter [com.example.project.Calculator arg0] 
does not match any parameter in the declaring executable

Example project

Context

  • Used versions : Jupiter 5.3.1 /Platform 1.3.1/ Spring Test 5.1.2
  • Build Tool/IDE: gradle 4.10.2

Posible rootcause

  • After some investigation found that this exceptions is thrown by Spring from org.springframework.core.MethodParameter
protected static int findParameterIndex(Parameter parameter) {
	Executable executable = parameter.getDeclaringExecutable();
	Parameter[] allParams = executable.getParameters();
	for (int i = 0; i < allParams.length; i++) {
		if (parameter == allParams[i]) {
			return i;
		}
	}
	throw new IllegalArgumentException("Given parameter [" + parameter +
			"] does not match any parameter in the declaring executable");
}
private Parameter[] privateGetParameters() {
        // Use tmp to avoid multiple writes to a volatile.
        Parameter[] tmp = parameters;

        if (tmp == null) {

            // Otherwise, go to the JVM to get them
            try {
                tmp = getParameters0();
            } catch(IllegalArgumentException e) {
                // Rethrow ClassFormatErrors
                throw new MalformedParametersException("Invalid constant pool index");
            }

            // If we get back nothing, then synthesize parameters
            if (tmp == null) {
                hasRealParameterData = false;
                tmp = synthesizeAllParams();
            } else {
                hasRealParameterData = true;
                verifyParameters(tmp);
            }

            parameters = tmp;
        }

        return tmp;
    } 
  • First thread could get parameters array from second one

Posible solutions

  • Synchronize calls to executable
  • Or provide clone of executable to each thread

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions