kittinunf / fuel

The easiest HTTP networking library for Kotlin/Android
https://fuel.gitbook.io/documentation/
MIT License
4.57k stars 430 forks source link

Cannot use Fuel in JUnit tests, NoSuchMethodError: kotlin.jvm.internal.MutablePropertyReference1Impl #772

Open tomholub opened 4 years ago

tomholub commented 4 years ago

Bug Report

Description

We use Fuel in our prod code, which works well. When testing this code, we get:

/usr/lib/jvm/java-1.8.0-openjdk-amd64/<.. snip ..>

java.lang.NoSuchMethodError: kotlin.jvm.internal.MutablePropertyReference1Impl.<init>(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V

    at com.github.kittinunf.fuel.core.FuelManager.<clinit>(FuelManager.kt)
    at com.github.kittinunf.fuel.Fuel.<init>(Fuel.kt:11)
    at com.github.kittinunf.fuel.Fuel.<clinit>(Fuel.kt:11)
    at com.flowcrypt.services.WkdApiClient.pushSync(WkdApiClient.kt:28)
    at com.flowcrypt.services.WkdApiClientTest.serverDown(WkdApiClientTest.kt:15)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:675)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:125)
    at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:132)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:124)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:74)
    at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:104)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:62)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:43)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:35)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:202)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:198)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at java.util.ArrayList.forEach(ArrayList.java:1259)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at java.util.ArrayList.forEach(ArrayList.java:1259)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:229)
    at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:197)
    at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
    at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)

To Reproduce

Write a class like:

package com.flowcrypt.services

import com.github.kittinunf.fuel.Fuel
import com.github.kittinunf.result.Result

class ApiClient {

    fun call() {
            when (val result = Fuel.put("http://domain.com/place").response()) {
                is Result.Failure<*> -> throw result.getException()
                is Result.Success<*> -> return
            }
}

Which you can use in your project normally:

ApiClient().call()

But when trying to test it:

package com.flowcrypt.services

import org.junit.jupiter.api.*

internal class ApiClientTest {
    @Test
    fun demoTest() {
        ApiClient().call()
    }
}

You will get NoSuchMethodError:

java.lang.NoSuchMethodError: kotlin.jvm.internal.MutablePropertyReference1Impl.<init>(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V

    at com.github.kittinunf.fuel.core.FuelManager.<clinit>(FuelManager.kt)
    at com.github.kittinunf.fuel.Fuel.<init>(Fuel.kt:11)
    at com.github.kittinunf.fuel.Fuel.<clinit>(Fuel.kt:11)

Expected behavior

Ability to use in tests.

Environment

Development Machine

Complete the following information if applicable

Additional context

We use a multi-module setup in our project, with folders like:

shared
projectOne
projectTwo

Where projectOne and projectTwo depends on shared. The gradle dependency implementation, class code as well as testing was all done in projectOne so I don't think this is relevant, just adding for completeness.

kittinunf commented 4 years ago

Hmm, this is quite interesting. Do you have any pointer to help me identify the problem here?

I tried the following;

  1. Create a class
  2. Use Fuel to call put to https://httpbin.org/put
  3. Expect the result

class ApiClient {
    fun put(): Result<String, FuelError> = Fuel.put("https://httpbin.org/put", listOf("foo" to "bar"))
            .header(Headers.ACCEPT, "application/json")
            .responseString().third
}

class JUnitTest {

    @Test
    fun test() {
        with(ApiClient().put()) {
            success {
                println("success: $it")
            }

            failure {
                println("failure : $it")
            }
        }
    }
}

This is what I got (which is correct as expected)

Screen Shot 2020-09-28 at 23 50 58
tomholub commented 4 years ago

Thank you for the response. I'm not sure what is going on. I'll try to arrange a repro on our end that we could share.

DanySK commented 4 years ago

Same issue here. Just imported fuel in gradle with:

    implementation("com.github.kittinunf.fuel:fuel:2.3.0")

And then:

fun main() {
    val (request, response, result) = "https://httpbin.org/get"
        .httpGet()
        .responseString()
}

Result:

Exception in thread "main" java.lang.NoSuchMethodError: 'void kotlin.jvm.internal.MutablePropertyReference1Impl.<init>(java.lang.Class, java.lang.String, java.lang.String, int)'
    at com.github.kittinunf.fuel.core.FuelManager.<clinit>(FuelManager.kt)
    at com.github.kittinunf.fuel.Fuel.<init>(Fuel.kt:11)
    at com.github.kittinunf.fuel.Fuel.<clinit>(Fuel.kt:11)
    at com.github.kittinunf.fuel.FuelKt.httpGet(Fuel.kt:23)
    at com.github.kittinunf.fuel.FuelKt.httpGet$default(Fuel.kt:22)
kittinunf commented 4 years ago

🙇 Not sure what exactly is the problem here but I tried the following;

Create a brand new project with these settings

build.gradle.kts

plugins {
    application
    kotlin("jvm")
}

version = ""
group = "com.github.kittinunf"

application {
    mainClassName = "com.github.kittinunf.fuel.MainKt"
}

repositories {
    mavenCentral()
}

dependencies {
    implementation(kotlin("stdlib"))
    implementation("com.github.kittinunf.fuel:fuel:2.3.0")
}

main/Main.kt


fun main(args: Array<String>) {
    println("Hello Fuel!")

    val (_, _, result) = Fuel.get("https://httpbin.org/get").responseString()
    println(result)
}

test/MainTest.kt

class MainTest {

    @Test
    fun test() {
        val (_, _, result) = Fuel.get("https://httpbin.org/get").responseString()
        println(result)
    }
}

It works as expected on both test and main classes.

Do you think it has something to do with old Kotlin version left in the classpath or something?

DanySK commented 4 years ago

It happened to me while writing a Gradle plugin, so that might be the culprit. Maybe Gradle 6.6.1 pulls in the classpath some incompatible Kotlin version? Which version of Kotlin does Fuel require?

kittinunf commented 4 years ago

For the latest version, it requires Kotlin 1.4.x and up

DanySK commented 4 years ago

My feeling is that Gradle is still using 1.3.x, so developing with implementation(gradleApi()) makes the system incompatible with fuel.

On Sun, Oct 4, 2020 at 3:36 PM Kittinun Vantasin notifications@github.com wrote:

For the latest version, it requires Kotlin 1.4.x and up

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

-- Ing. Dott. Danilo Pianini, PhD

Site: http://www.danilopianini.org/ Phone: +39 320 41 36 573 Hangouts: danilo.pianini@gmail.com

kittinunf commented 4 years ago

@DanySK Thanks for reporting and sorry for the problem you are experiencing.

Do you think you could try to update to this version of the gradle instead?

https://github.com/gradle/gradle/issues/12660#issuecomment-700629974

Except from this issue; https://github.com/gradle/gradle/issues/12660

dbrgn commented 3 years ago

Upgrading to gradle 6.8 (not yet released as a final version!) seems to work. Latest milestone is M3:

./gradlew wrapper --gradle-version=6.8-milestone-3
DanySK commented 3 years ago

@kittinunf yes I will eventually upgrade to Gradle 6.8 once it reaches stability