What are the limitations of using Spy(class) ?

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

What are the limitations of using Spy(class) ?

Jan Peremsky

Hi, while experimenting with Quasar Fibers in order to allow easier testing of asyc frameworks, I came across a strange behavior of the Spy mock generated by the Spock framework.

Basically spying worked as expected with the "normal" e.g. synchronous methods of the spied class. 

But if a spied class were to execute some code on a different thread and then call a callback closure, the spied method hanged forever.

 

What are the limitations that apply for a class to be spied?

Are there any?

Or are there some limitations imposed by the cglib itself?

 

See below the test sources...

 

Thanks Jan



public class MiniSampler {
public MiniSampler() {}

private ExecutorService ex = Executors.newSingleThreadExecutor();

public String blockingSimpleMethod(String input) {
return new StringBuilder(input).reverse().toString();
}

public String blockingThreadExpensive(String input) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
return blockingSimpleMethod(input);
}

public void stop() throws Exception {
ex.shutdown();
ex.awaitTermination(2000, TimeUnit.MILLISECONDS);
}

public void viaConsumerOnDifferentThreadNoEx(final String input, final Consumer<String> resultConsumer) {
final Future<?> future = ex.submit(() -> {
resultConsumer.accept(blockingThreadExpensive(input));
});
try {
future.get();
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted", e);
} catch (ExecutionException e) {
throw new RuntimeException("worker thread exception", e.getCause());
}
}
}

class SpyTest extends Specification {
public static final String input = "Karel"
public static final String expected = "leraK"

def "real async method executes as expected"() {
given:
def MiniSampler sampler = new MiniSampler()
def AtomicReference<String> result = new AtomicReference<>()
def CountDownLatch cdl = new CountDownLatch(1)

when:
sampler.viaConsumerOnDifferentThreadNoEx(input, { str ->
result.set(str)
cdl.countDown()
})

then:
cdl.await(1, TimeUnit.SECONDS)
result.get() == expected

cleanup:
sampler?.stop()
}

def "spied sync method executes as expected"() {
given:
def MiniSampler sampler = Spy(MiniSampler)

when:
def result = sampler.blockingThreadExpensive(input)

then:
result == expected
1* sampler.blockingSimpleMethod(_)

cleanup:
sampler?.stop()
}

def "spied async method hangs forever"() {
given:
def MiniSampler sampler = Spy(MiniSampler)
def AtomicReference<String> result = new AtomicReference<>()
def CountDownLatch cdl = new CountDownLatch(1)

when:
sampler.viaConsumerOnDifferentThreadNoEx(input, { str ->
result.set(str)
cdl.countDown()
})
def boolean timeouted = cdl.await(1, TimeUnit.SECONDS)

then:
!timeouted
result.get() == expected
1* sampler.blockingSimpleMethod(_)

cleanup:
sampler?.stop()
}
}

--
You received this message because you are subscribed to the Google Groups "Spock Framework - User" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at http://groups.google.com/group/spockframework.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: What are the limitations of using Spy(class) ?

Jan Peremsky
Update: I have upgraded testRuntime cglib dependency to cglib-nodep-3.2.0-SNAPSHOT (built from github master) which should overcome potential issues with java 8.
However I'm still experiencing the same behavior...

--
You received this message because you are subscribed to the Google Groups "Spock Framework - User" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at http://groups.google.com/group/spockframework.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: What are the limitations of using Spy(class) ?

Przemysław Wojnowski
Could you display your test classpath? Maybe you've a few cglibs on the classpath, pulled as transitive deps, and the old one happens to be the first.

Didn't try cglib 3.2, so it's just a guess.

2015-11-05 11:33 GMT+01:00 Jan Peremsky <[hidden email]>:
Update: I have upgraded testRuntime cglib dependency to cglib-nodep-3.2.0-SNAPSHOT (built from github master) which should overcome potential issues with java 8.
However I'm still experiencing the same behavior...

--
You received this message because you are subscribed to the Google Groups "Spock Framework - User" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at http://groups.google.com/group/spockframework.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "Spock Framework - User" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at http://groups.google.com/group/spockframework.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: What are the limitations of using Spy(class) ?

Jan Peremsky
Hi, below is the current classpath taken from the running spock test.
There is only one cglib jar there.
I can't see anything suspicious at the first glance.

Jan

Actual classpath
=======================================
.../idea-15/lib/idea_rt.jar
.../idea-15/plugins/junit/lib/junit-rt.jar
.../jdk8/jre/lib/charsets.jar
.../jdk8/jre/lib/deploy.jar
.../jdk8/jre/lib/ext/access-bridge-32.jar
.../jdk8/jre/lib/ext/cldrdata.jar
.../jdk8/jre/lib/ext/dnsns.jar
.../jdk8/jre/lib/ext/jaccess.jar
.../jdk8/jre/lib/ext/jfxrt.jar
.../jdk8/jre/lib/ext/localedata.jar
.../jdk8/jre/lib/ext/nashorn.jar
.../jdk8/jre/lib/ext/sunec.jar
.../jdk8/jre/lib/ext/sunjce_provider.jar
.../jdk8/jre/lib/ext/sunmscapi.jar
.../jdk8/jre/lib/ext/sunpkcs11.jar
.../jdk8/jre/lib/ext/zipfs.jar
.../jdk8/jre/lib/javaws.jar
.../jdk8/jre/lib/jce.jar
.../jdk8/jre/lib/jfr.jar
.../jdk8/jre/lib/jfxswt.jar
.../jdk8/jre/lib/jsse.jar
.../jdk8/jre/lib/management-agent.jar
.../jdk8/jre/lib/plugin.jar
.../jdk8/jre/lib/resources.jar
.../jdk8/jre/lib/rt.jar
...idea.../tests/defibrilator/tobetested/build/classes/test/
...idea.../tests/defibrilator/tobetested/build/classes/main/
...idea.../tests/defibrilator/tobetested/build/resources/test/
...idea.../tests/defibrilator/tobetested/build/resources/main/
~/.m2/repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar
~/.gradle/caches/modules-2/files-2.1/co.paralleluniverse/quasar-core/0.7.3/700f4769e54b9363d19b67f8d0913b1b76fae325/quasar-core-0.7.3-jdk8.jar
~/.m2/repo/io/dropwizard/metrics/metrics-core/3.1.2/metrics-core-3.1.2.jar
~/.m2/repo/org/latencyutils/LatencyUtils/2.0.2/LatencyUtils-2.0.2.jar
~/.m2/repo/de/javakaffee/kryo-serializers/0.36/kryo-serializers-0.36.jar
~/.m2/repo/org/hdrhistogram/HdrHistogram/2.1.3/HdrHistogram-2.1.3.jar
~/.m2/repo/com/lmax/disruptor/3.3.2/disruptor-3.3.2.jar
~/.m2/repo/com/google/guava/guava/18.0/guava-18.0.jar
~/.m2/repo/com/esotericsoftware/kryo/kryo/2.24.0/kryo-2.24.0.jar
~/.m2/repo/com/google/protobuf/protobuf-java/2.6.1/protobuf-java-2.6.1.jar
~/.m2/repo/com/esotericsoftware/minlog/minlog/1.2/minlog-1.2.jar
~/.m2/repo/org/objenesis/objenesis/2.1/objenesis-2.1.jar
...idea.../tests/defibrilator/util/build/classes/main/
...idea.../tests/defibrilator/util/build/resources/test/
...idea.../tests/defibrilator/util/build/resources/main/
~/.m2/repo/junit/junit/4.11/junit-4.11.jar
~/.gradle/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-api/2.4/cc68e72d6d14098ba044123e10e048d203d3fd47/log4j-api-2.4.jar
~/.gradle/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-core/2.4/d99532ba3603f27bebf4cdd3653feb0e0b84cf6/log4j-core-2.4.jar
~/.gradle/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-jul/2.4/d5669a2d814e7eac0d9df267c1affa9658da300/log4j-jul-2.4.jar
~/.gradle/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-slf4j-impl/2.4/10014efa6c4d7f7e6df464c82629a443f987e215/log4j-slf4j-impl-2.4.jar
~/.gradle/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-jcl/2.4/833ed253e7e66fa5a01b098e0f324c56e6800faf/log4j-jcl-2.4.jar
~/.m2/repo/org/slf4j/slf4j-api/1.7.12/slf4j-api-1.7.12.jar
~/.m2/repo/commons-logging/commons-logging/1.2/commons-logging-1.2.jar
~/.m2/repo/io/vertx/vertx-web/3.1.0/vertx-web-3.1.0.jar
~/.m2/repo/io/vertx/vertx-auth-common/3.1.0/vertx-auth-common-3.1.0.jar
~/.m2/repo/io/vertx/vertx-core/3.1.0/vertx-core-3.1.0.jar
~/.m2/repo/io/netty/netty-common/4.0.31.Final/netty-common-4.0.31.Final.jar
~/.m2/repo/io/netty/netty-buffer/4.0.31.Final/netty-buffer-4.0.31.Final.jar
~/.m2/repo/io/netty/netty-transport/4.0.31.Final/netty-transport-4.0.31.Final.jar
~/.m2/repo/io/netty/netty-handler/4.0.31.Final/netty-handler-4.0.31.Final.jar
~/.m2/repo/io/netty/netty-codec-http/4.0.31.Final/netty-codec-http-4.0.31.Final.jar
~/.m2/repo/com/fasterxml/jackson/core/jackson-core/2.6.1/jackson-core-2.6.1.jar
~/.m2/repo/com/fasterxml/jackson/core/jackson-databind/2.6.1/jackson-databind-2.6.1.jar
~/.m2/repo/io/netty/netty-codec/4.0.31.Final/netty-codec-4.0.31.Final.jar
~/.m2/repo/com/fasterxml/jackson/core/jackson-annotations/2.6.0/jackson-annotations-2.6.0.jar
~/.m2/repo/org/codehaus/groovy/groovy-all/2.4.5/groovy-all-2.4.5.jar
~/.gradle/caches/modules-2/files-2.1/org.spockframework/spock-core/1.0-groovy-2.4/ceaa8b69f274ed3de24da3e6a6c86f673b426d1a/spock-core-1.0-groovy-2.4.jar
~/.gradle/caches/modules-2/files-2.1/com.blogspot.toomuchcoding/spock-subjects-collaborators-extension/1.1.0/aeb37fde45ee073ec7255b444a137d2231d01217/spock-subjects-collaborators-extension-1.1.0.jar
~/.m2/repo/junit/junit/4.12/junit-4.12.jar
...idea.../tests/defibrilator/tobetested/libs/cglib-nodep-3.2.0-SNAPSHOT.jar
=======================================

--
You received this message because you are subscribed to the Google Groups "Spock Framework - User" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at http://groups.google.com/group/spockframework.
For more options, visit https://groups.google.com/d/optout.