New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AmqpTarget doesn't find @PactVerifyProvider annotation #763

Open
thombergs opened this Issue Aug 24, 2018 · 8 comments

Comments

Projects
None yet
3 participants
@thombergs
Contributor

thombergs commented Aug 24, 2018

I'm running a simple message provider test:

@RunWith(PactRunner.class)
@Provider("userservice")
@PactFolder("../pact-message-consumer/target/pacts")
@SpringBootTest
public class MessageProviderTest {

	@TestTarget
	public final Target target = new AmqpTarget(Collections.singletonList("io.reflectoring"));

	@PactVerifyProvider("a user created message")
	public String verifyUserCreatedMessage() {
		return "{\"testParam1\": \"value1\",\"testParam2\": \"value2\"}";
	}
}

Executing this test results in

Failures:

0) a user created message
      No annotated methods were found for interaction 'a user created message'. You need to provide a method annotated with @PactVerifyProvider("a user created message") that returns the message contents.

The cause for this is that the Reflections call in ProviderVerifier#verifyResponseByInvokingProviderMethods doesn't find the @PactVerifyProvider annotation on my test method. There must be something wrong with the setup of the Reflections instance (class loader?).

When I'm using the following code snippet from a test, the annotation is found:

Reflections r = new Reflections(ClasspathHelper.forPackage("io.reflectoring"), new MethodAnnotationsScanner());
Set<Method> methods = r.getMethodsAnnotatedWith(PactVerifyProvider.class);
@uglyog

This comment has been minimized.

Member

uglyog commented Aug 26, 2018

How are you running the test, from Maven or from your IDE?

@thombergs

This comment has been minimized.

Contributor

thombergs commented Aug 26, 2018

From both Gradle and the IDE.

@thombergs

This comment has been minimized.

Contributor

thombergs commented Aug 26, 2018

@uglyog

I took a deeper look. In ProviderVerifier#verifyResponseByInvokingProviderMethods() the ConfigurationBuilder used for the Reflections instance is initialized with classpath URLs via def urls = projectClasspath.get().

Running my test from the IDE, the resolved URLs are:
0 = {URL@3601} "file:/C:/Users/Tom/AppData/Local/Temp/classpath1765335879.jar"
1 = {URL@3602} "file:/C:/Users/Tom/.IntelliJIdea2018.2/system/groovyHotSwap/gragent.jar"
2 = {URL@3603} "file:/C:/Users/Tom/.IntelliJIdea2018.2/system/captureAgent/debugger-agent.jar"

None of those JARs contains my classes.

@thombergs

This comment has been minimized.

Contributor

thombergs commented Sep 3, 2018

@uglyog did you have a chance to look into this?

@uglyog

This comment has been minimized.

Member

uglyog commented Sep 8, 2018

I've run a few, and they work for me in IntelliJ. Looks like you are getting an empty classpath, not your project's. Check your run configuration in IntelliJ to see what classpath is being set.

The AmqpTarget is using ClassLoader.getSystemClassLoader() to get the classpath to use. You could try extending a class from AmqpTarget and use the classpath from the test class to see if that works. Just override the setupVerifier method and then override the projectClasspath field on the verifier.

@thombergs

This comment has been minimized.

Contributor

thombergs commented Sep 10, 2018

@uglyog I still couldn't get it to work, even when overriding the projectClasspath field. Must be some issue with the classloader.

I can get it to work when overriding the whole usage of Reflections (i.e. subclassing AmqpTarget and ProviderVerifier, but that is a very ugly workaround (see here).

Instead of using a specific classloader, I simply use Reflections r = new Reflections(packages, new MethodAnnotationsScanner()); to scan the classpath for annotations.

Why does ProviderVerifier use a specific class loader? Wouldn't it make sense to use the Reflections default as I did above?

@uglyog

This comment has been minimized.

Member

uglyog commented Sep 10, 2018

The problem is that different build tools setup the classpaths in different ways. Pact-JVM also supports running verifications from Gradle, Maven, Leiningen and SBT.

However, what we can do is default it to no classpath, and if it hasn't been overridden by one of the build plugins, then use the default.

@PMT87

This comment has been minimized.

PMT87 commented Dec 3, 2018

We run into the same problem. But in combination with pact-jvm-provider-junit5_2.12 and maven.
The PactVerifyProvider-annotation will not be found running with maven.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment