Skip to content

Commit 0010b4c

Browse files
committed
[Spring] Do not share ContextCache between threads
The TestContextManager(Class<?>) uses a static ContextCache. This meant that step definitions from different threads could be registered in same context multiple times when running in parallel. This is resolved by creating a ThreadLocal ContextCache for each SpringFactory. Related issues: - https://travis-ci.org/cucumber/cucumber-jvm/jobs/244215644 - #1148
1 parent c70c0ec commit 0010b4c

File tree

2 files changed

+34
-4
lines changed

2 files changed

+34
-4
lines changed

spring/src/main/java/cucumber/runtime/java/spring/SpringFactory.java

+9-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package cucumber.runtime.java.spring;
22

3-
import cucumber.runtime.CucumberException;
3+
import static org.springframework.test.context.FixBootstrapUtils.createBootstrapContext;
4+
import static org.springframework.test.context.FixBootstrapUtils.resolveTestContextBootstrapper;
5+
46
import cucumber.api.java.ObjectFactory;
7+
import cucumber.runtime.CucumberException;
58
import org.springframework.beans.BeansException;
69
import org.springframework.beans.factory.config.BeanDefinition;
710
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
@@ -202,12 +205,14 @@ private boolean annotatedWithSupportedSpringRootTestAnnotations(Class<?> type) {
202205

203206
class CucumberTestContextManager extends TestContextManager {
204207

205-
public CucumberTestContextManager(Class<?> testClass) {
206-
super(testClass);
208+
CucumberTestContextManager(Class<?> testClass) {
209+
// Does the same as TestContextManager(Class<?>) but creates a
210+
// DefaultCacheAwareContextLoaderDelegate that uses a thread local contextCache.
211+
super(resolveTestContextBootstrapper(createBootstrapContext(testClass)));
207212
registerGlueCodeScope(getContext());
208213
}
209214

210-
public ConfigurableListableBeanFactory getBeanFactory() {
215+
ConfigurableListableBeanFactory getBeanFactory() {
211216
return getContext().getBeanFactory();
212217
}
213218

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package org.springframework.test.context;
2+
3+
import org.springframework.test.context.cache.ContextCache;
4+
import org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate;
5+
import org.springframework.test.context.cache.DefaultContextCache;
6+
import org.springframework.test.context.support.DefaultBootstrapContext;
7+
8+
public class FixBootstrapUtils extends BootstrapUtils {
9+
10+
private static ThreadLocal<ContextCache> contextCache = new ThreadLocal<ContextCache>(){
11+
@Override
12+
protected ContextCache initialValue() {
13+
return new DefaultContextCache();
14+
}
15+
};
16+
17+
public static BootstrapContext createBootstrapContext(Class<?> testClass) {
18+
CacheAwareContextLoaderDelegate contextLoader = new DefaultCacheAwareContextLoaderDelegate(contextCache.get());
19+
return new DefaultBootstrapContext(testClass, contextLoader);
20+
}
21+
22+
public static TestContextBootstrapper resolveTestContextBootstrapper(BootstrapContext bootstrapContext) {
23+
return BootstrapUtils.resolveTestContextBootstrapper(bootstrapContext);
24+
}
25+
}

0 commit comments

Comments
 (0)