pact-foundation / pact-jvm

JVM version of Pact. Enables consumer driven contract testing, providing a mock service and DSL for the consumer project, and interaction playback and verification for the service provider project.
https://docs.pact.io
Apache License 2.0
1.08k stars 478 forks source link

Exception in thread "Thread-2" java.lang.NoSuchMethodError: kotlin.io.ByteStreamsKt.readBytes #1102

Open Joothi opened 4 years ago

Joothi commented 4 years ago

Getting the Below Errror:

Exception in thread "Thread-2" java.lang.NoSuchMethodError: kotlin.io.ByteStreamsKt.readBytes(Ljava/io/InputStream;)[B at au.com.dius.pact.consumer.BaseJdkMockServer.toPactRequest(MockHttpServer.kt:227) at au.com.dius.pact.consumer.BaseJdkMockServer.handle(MockHttpServer.kt:198) at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:79) at sun.net.httpserver.AuthFilter.doFilter(AuthFilter.java:83) at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:82) at sun.net.httpserver.ServerImpl$Exchange$LinkHandler.handle(ServerImpl.java:675) at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:79) at sun.net.httpserver.ServerImpl$Exchange.run(ServerImpl.java:647) at sun.net.httpserver.ServerImpl$DefaultExecutor.execute(ServerImpl.java:158) at sun.net.httpserver.ServerImpl$Dispatcher.handle(ServerImpl.java:431) at sun.net.httpserver.ServerImpl$Dispatcher.run(ServerImpl.java:396) at java.lang.Thread.run(Thread.java:748)

Code:

public class PactConsumerDrivenContractUnitTest {
    @Rule
    public PactProviderRule mockProvider = new PactProviderRule("test_provider", "localhost", 8080, this);
    @au.com.dius.pact.core.model.annotations.Pact(consumer = "test_consumer")
    public RequestResponsePact createPact(PactDslWithProvider builder) {
        Map<String, String> headers = new HashMap<String, String>();
        headers.put("Content-Type", "application/json");

        return builder.given("test GET").uponReceiving("GET REQUEST").path("/pact").method("GET").willRespondWith()
                .status(200).headers(headers).body("{\"condition\": true, \"name\": \"tom\"}").given("test POST")
                .uponReceiving("POST REQUEST").method("POST").headers(headers).body("{\"name\": \"Michael\"}")
                .path("/pact").willRespondWith().status(201).toPact();
    }

    @Test
    //@Ignore
    @PactVerification()
    public void givenGet_whenSendRequest_shouldReturn200WithProperHeaderAndBody() {
        ResponseEntity<String> response = new RestTemplate().getForEntity(mockProvider.getUrl() + "/pact",
                String.class);      
        Assert.assertEquals(response.getStatusCode().value(), 200);
        Assert.assertTrue(response.getHeaders().get("Content-Type").contains("application/json"));
        Assert.assertTrue(response.getBody().contains("tom"));
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        String jsonBody = "{\"name\": \"Michael\"}";
        ResponseEntity<String> postResponse = new RestTemplate().exchange(mockProvider.getUrl() + "/pact",
                HttpMethod.POST, new HttpEntity<>(jsonBody, httpHeaders), String.class);
        Assert.assertEquals(response.getStatusCode().value(), 201); 
    }

POM.XML

<dependencies>
        <!-- https://mvnrepository.com/artifact/au.com.dius/pact-jvm-consumer-junit -->
        <dependency>
            <groupId>au.com.dius</groupId>
            <artifactId>pact-jvm-consumer-junit</artifactId>
            <version>4.0.10</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.3.0.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/au.com.dius/pact-jvm-provider-junit -->
        <dependency>
            <groupId>au.com.dius</groupId>
            <artifactId>pact-jvm-provider-junit</artifactId>
            <version>4.0.10</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

}
uglyog commented 4 years ago

This issue is caused by Maven + Springboot causing the wrong version of the Kotlin standard library to be loaded. I recently diagnosed this for someone else. See https://stackoverflow.com/questions/62001663/exception-in-thread-thread-2-java-lang-nosuchmethoderror-kotlin-io-bytestream

Running maven dependency tree plugin showed:

au.com.dius:pact-jvm-consumer-junit5:jar:4.0.10
  -> au.com.dius:pact-jvm-consumer:jar:4.0.10
    -> io.ktor:ktor-server-netty:jar:1.2.6
      -> org.jetbrains.kotlin:kotlin-stdlib:jar:1.2.71

which is the wrong version of the Kotlin standard lib (it should be 1.3.x).

Checking Maven Central, https://search.maven.org/artifact/io.ktor/ktor-server-netty/1.2.6/jar has the following in it's POM:

    <dependency>
      <groupId>org.jetbrains.kotlin</groupId>
      <artifactId>kotlin-stdlib</artifactId>
      <version>1.3.60</version>
      <scope>compile</scope>
    </dependency>

Also, https://search.maven.org/artifact/au.com.dius/pact-jvm-core-support/4.0.10/jar has

<dependency>
      <groupId>org.jetbrains.kotlin</groupId>
      <artifactId>kotlin-stdlib-jdk8</artifactId>
      <version>1.3.71</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>org.jetbrains.kotlin</groupId>
      <artifactId>kotlin-reflect</artifactId>
      <version>1.3.71</version>
      <scope>runtime</scope>
    </dependency>

Looks like there is the same issue with Gson (#1077).

I was able to fix the provided project by adding the following to the dependencies:

        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-stdlib</artifactId>
            <version>1.3.72</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.6</version>
        </dependency>

But I have no idea why Maven is resolving the Kotlin standard library to 1.2.71. Probably time to move to Gradle! :-D

Vinodkomeershetty commented 3 years ago

I am seeing the same issue with gradle + groovy

testCompile group: 'au.com.dius.pact.consumer', name: 'groovy', version: '4.1.0'
testCompile group: 'au.com.dius.pact.consumer', name: 'junit', version: '4.1.0'

image

uglyog commented 3 years ago

@Vinodkomeershetty are you using Springboot?

Vinodkomeershetty commented 3 years ago

@uglyog We are using groovy on grails for development and also we are using few dependencies related to spring boot

uglyog commented 3 years ago

@Vinodkomeershetty the pactPublish task runs using the build classpath. You may need to include the correct version of Kotlin there. See https://docs.gradle.org/current/userguide/tutorial_using_tasks.html#sec:build_script_external_dependencies