Skip to content
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

Closed
thombergs opened this issue Aug 24, 2018 · 20 comments
Closed

AmqpTarget doesn't find @PactVerifyProvider annotation #763

thombergs opened this issue Aug 24, 2018 · 20 comments

Comments

@thombergs
Copy link
Contributor

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
Copy link
Member

uglyog commented Aug 26, 2018

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

@thombergs
Copy link
Contributor Author

From both Gradle and the IDE.

@thombergs
Copy link
Contributor Author

@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
Copy link
Contributor Author

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

@uglyog
Copy link
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
Copy link
Contributor Author

@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
Copy link
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
Copy link

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.

@gumartinm
Copy link

The same problem with pact-jvm-provider-junit_2.12 version 3.6.1.
AmqpTarget works from IntelliJ but it does not from maven.

@uglyog
Copy link
Member

uglyog commented Feb 16, 2019

@PMT87 @gumartinm You need to set the Maven Surefire plugin to use an isolated class loader. For example:

             <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <useSystemClassLoader>false</useSystemClassLoader>
                </configuration>
            </plugin>

@eranberg
Copy link

eranberg commented Mar 26, 2019

@uglyog my test class setup is identical to the one @thombergs has and I am using pact-jvm-provider-junit_2.12 version 3.6.3 along with the suggested useSystemClassLoader configuration on surefire.
When building with Maven I am still getting the same error:

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

Any idea on what else I can do for this?

@uglyog
Copy link
Member

uglyog commented Apr 13, 2019

@eranberg are you able to provide your POM file?

@eranberg
Copy link

@uglyog My project is meant to demonstrate how to use Pact with our existing technological stack and libraries so I am using both consumer and provider in the same project to represent the whole lifecycle of the testing environment.
I use NetBeans (or Eclipse) as IDE and Maven for building it all.
The project setup is a bit complicated so I stripped out most of the complication and these are the bare Pact related parts:

sample sample-code 1.0.0 jar
<dependencies>
    <!-- Contract testing dependencies -->
    <dependency>
        <groupId>au.com.dius</groupId>
        <artifactId>pact-jvm-consumer-junit_2.12</artifactId>
        <version>3.6.3</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>au.com.dius</groupId>
        <artifactId>pact-jvm-provider-junit_2.12</artifactId>
        <version>3.6.3</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>au.com.dius</groupId>
        <artifactId>pact-jvm-provider-spring_2.12</artifactId>
        <version>3.6.3</version>
        <scope>test</scope>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.xolstice.maven.plugins</groupId> 
            <artifactId>protobuf-maven-plugin</artifactId> 
            <version>0.6.1</version>
        </plugin>
         
        <!-- invoke Pact Contract testing -->
        <plugin>
            <groupId>au.com.dius</groupId>
            <artifactId>pact-jvm-consumer-maven_2.12</artifactId>
            <version>3.6.3</version>
        </plugin>

        <plugin>
            <groupId>au.com.dius</groupId>
            <artifactId>pact-jvm-provider-maven_2.12</artifactId>
            <version>3.6.3</version>
        </plugin>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
                <useSystemClassLoader>false</useSystemClassLoader>
            </configuration>
        </plugin>
    </plugins>
</build>

@jon-ruckwood
Copy link
Contributor

jon-ruckwood commented Apr 30, 2019

@eranberg I was experiencing the same issue but with 3.6.4. I found that after upgrading maven-surefire-plugin, everything started to work:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.1</version>
    <configuration>
        <useSystemClassLoader>false</useSystemClassLoader>
    </configuration>
</plugin>

Intermediate versions may work, however I didn't look into it.

@uglyog
Copy link
Member

uglyog commented May 3, 2019

Thanks @jon-ruckwood I will update the docs to specify that version as a minimum.

@eranberg
Copy link

eranberg commented May 8, 2019

@jon-ruckwood @uglyog
I tried:

  1. upgrading the maven-surefire-plugin to 2.22.1
  2. upgrading the Pact dependencies to 3.6.4
  3. upgrading Maven itself to the latest 3.6.1

I still get the same error after all of these upgrades...
Any idea what to do next?

@uglyog
Copy link
Member

uglyog commented May 12, 2019

@eranberg have a look at https://github.com/uglyog/pact-maven-amqp-test, it is a simple project that works with Maven 3.5. You'll need to compare it to yours to work out what the issue is.

@eranberg
Copy link

eranberg commented May 13, 2019

@uglyog Thanks for providing the github project with the testing samples. It worked out of the box for me.
The example you provided also helped me setup my project in a better way and now I am on to new issues :)

@tylerkron
Copy link

Had this issue as well. My issue is that I am using Java 11. Upgraded to pact-jvm-consumer-junit version 4.0.0-beta.2 and I have provider verification working again.

@uglyog
Copy link
Member

uglyog commented Jun 1, 2019

Closing this as there looks like there are work arounds for all the issues

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants