I also have had the need for some concurrency testing so I tried to
implement this myself and have been banging my head on this for
awhile. I'm wondering if you could check my work as I'm having a hard
time trying to follow where it's getting caught up in the Spock code.
Here is my extension so far:
import org.spockframework.runtime.extension.ExtensionAnnotation;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@ExtensionAnnotation(ConcurrentExtension.class)
public @interface Concurrent {
int value();
}
import
org.spockframework.runtime.extension.AbstractAnnotationDrivenExtension;
import org.spockframework.runtime.model.FeatureInfo;
public class ConcurrentExtension extends
AbstractAnnotationDrivenExtension<Concurrent> {
@Override
public void visitFeatureAnnotation(Concurrent concurrent,
FeatureInfo feature) {
feature.getFeatureMethod().addInterceptor(new
ConcurrentInterceptor(concurrent));
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class ConcurrentInterceptor implements IMethodInterceptor {
private final Concurrent concurrent;
public ConcurrentInterceptor(Concurrent concurrent) {
this.concurrent = concurrent;
}
public void intercept(final IMethodInvocation invocation) throws
Throwable {
List<Future<Throwable>> futures = new
ArrayList<Future<Throwable>>();
ExecutorService executor =
Executors.newFixedThreadPool(concurrent.value());
for (int i = 0; i < concurrent.value(); i++) {
futures.add(executor.submit(new Callable<Throwable>() {
public Throwable call() throws Exception {
try {
invocation.proceed();
} catch (Throwable t) {
return t;
}
return null;
}
}));
}
for (Future<Throwable> future : futures) {
Throwable throwable = future.get();
if (throwable != null) {
throw throwable;
}
}
}
}
Here is an example spec I've tried:
import com.entero.spock.Concurrent
import spock.lang.Specification
class ConcurrentSpecification extends Specification {
@Concurrent(2)
def "test"() {
when:
def a = "foo"
then:
a == "foo"
}
}
I'm not sure I have the interceptor quite right but it blows up in a
weird spot:
org.spockframework.util.UnreachableCodeError: verifyInteractions
at
org.spockframework.mock.DefaultInteractionScope.verifyInteractions(DefaultInteractionScope.java:
48)
at
org.spockframework.mock.MockController.leaveScope(MockController.java:
76)
at ConcurrentSpecification.test(ConcurrentSpecification.groovy:12)
I have also seen this:
java.util.NoSuchElementException
at java.util.LinkedList.remove(LinkedList.java:788)
at java.util.LinkedList.removeFirst(LinkedList.java:134)
at
org.spockframework.mock.MockController.leaveScope(MockController.java:
75)
at ConcurrentSpecification.test(ConcurrentSpecification.groovy:12)
I'm kind of at a loss since I don't really understand what the
MockController is trying to do. Thanks for any guidance you can
provide and apologies for my ignorance :)