Kotlin multiplatform test error ("Error_0: Fail to fetch") - kotlin

I have a kotlin-multiplatform project that has a kotlinJS client and a JVM backend. I'm creating some integration tests that are supposed to test the API calls from the client. The function is a suspend function with an HttpClient call with a POST method. I'm using kotlinx-coroutines-test, the test looks like this:
#OptIn(ExperimentalCoroutinesApi::class)
#Test
fun testGetSingleResult() = runTest {
val result = getSingleResult(TESTED_ID)
assertThat(result.ID).isEqualTo(TESTED_ID)
}
It should call the server in localhost:8080 and receive the result with the given ID. Instead of that, it gives the following error:
Error_0: Fail to fetch
Error_0: Fail to fetch
at <global>.<unknown>(/tmp/_karma_webpack_59097/commons.js:148488)
...
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':jsBrowserTest'.
I don't know what's happening, I thought that maybe the test is not launching the backend, so it won't find it when doing the request but I tried running the app at the same time that I launched the test and nothing changed.
EDIT:
Here is my build.gradle file and the link to the project.

Related

How to provide an HttpClient to ktor server from the outside to facilitate mocking external services?

I am trying to provide an HttpClient from the outside to my ktor server so that I can mock external services and write tests, however I get this exception when I run my test:
Please make sure that you use unique name for the plugin and don't install it twice. Conflicting application plugin is already installed with the same key as `Compression`
io.ktor.server.application.DuplicatePluginException: Please make sure that you use unique name for the plugin and don't install it twice. Conflicting application plugin is already installed with the same key as `Compression`
at app//io.ktor.server.application.ApplicationPluginKt.install(ApplicationPlugin.kt:112)
at app//com.example.plugins.HTTPKt.configureHTTP(HTTP.kt:13)
at app//com.example.ApplicationKt.module(Application.kt:14)
at app//com.example.ApplicationTest$expected to work$1$1.invoke(ApplicationTest.kt:39)
at app//com.example.ApplicationTest$expected to work$1$1.invoke(ApplicationTest.kt:38)
and thats a bit unexpected to me because I am not applying the Compression plugin twice as far as I can tell. If I run the server normally and manually call my endpoint with curl then it works as expected. What am I doing wrong?
I added a runnable sample project here with a failing test.
sample project
official ktor-documentation-sample project.
The problem is that you have the application.conf file and by default, the testApplication function tries to load modules which are enumerated there. Since you also explicitly load them in the application {} block the DuplicatePluginException occurs. To solve your problem you can explicitly load an empty configuration instead of the default one:
// ...
application {
module(client)
}
environment {
config = MapApplicationConfig()
}
// ...

Gradle Kotlin FileCollection JavaExec classpath

I'm attempting to create a gradle kotlin based SoapUI launcher of sorts sans plugins using native gradle functionality for incorporating SoapUI tests into our ci/cd pipeline. So far I have the following:
val soapui: Configuration by configurations.creating
dependencies {
// Old version is intentional
soapui("com.smartbear.soapui:soapui:5.4.0")
}
var clazzpath: List<Any> = mutableListOf()
var files: FileCollection = project.files()
task("soapui", JavaExec::class) {
doFirst {
// Validating iteration causes resolution
soapui.forEach { clazzpath += it }
// Validating contents of List
//clazzpath.forEach { println(it) }
// Creating a FileCollection from my List
files = project.files(clazzpath)
// Validating contents of my FileCollection
//files.forEach { println(it) }
}
// My first thought which does not work
//classpath = soapui
// My second thought which also does not work
//classpath = project.files(clazzpath)
// My third thought which also does not work
classpath = files
systemProperties = mapOf(
"soapui.properties.MyProject" to "src/test/integration/environments/my.properties")
main = "com.eviware.soapui.SoapUI"
// Will be invoked for automated test runs
//main = "com.eviware.soapui.tools.SoapUITestCaseRunner"
args = listOf("src/test/integration/my_project.xml")
}
I've found that iterating over a configuration causes gradle to resolve the configuration allowing for all the transitive dependencies to be discovered. The commented println statements validate that.
When using classpath = soapui, the SoapUI main jar file is put on the classpath, the main class is found, and the SoapUI GUI starts up fine. However, none of it's transient dependencies end up on the classpath and test cases fail when their assertions are performed.
When I try constructing the classpath explicitly, nothing ends up on the classpath and the SoapUI GUI fails to load because the main class is not found.
> Task :soapui FAILED
Picked up _JAVA_OPTIONS: -Djava.net.preferIPv4Stack=true
Error: Could not find or load main class com.eviware.soapui.SoapUI
Caused by: java.lang.ClassNotFoundException: com.eviware.soapui.SoapUI
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':soapui'.
> Process 'command 'C:\<path to JDK\bin\java.exe'' finished with non-zero exit value 1
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 1s
1 actionable task: 1 executed
<list of transitive dependencies on one line with no path separation characters (;)>
That last line of output may be what was used as the classpath, which consists of a list of all the transitive dependencies printed one after another without any path separation characters (semicolons).
Based off of my investigation and reading of the documentation, I'm clearly misunderstanding how this is supposed to work. What am I missing?
Time for me to publicly eat some crow. Turns out, the error I'm investigating has nothing to do with gradle or my understanding of it. Firstly, in the question I mention that the last line of output is a list of all the SoapUI 5.4.0 dependencies on one line without any path separators. It turns out that was being caused by my lack of experience with gradle. In the gradle build file I was working with, I had the following task defined as part of my investigation of gradle.
task("soapuiDependencies") {
soapui.forEach { print(it.toString()) }
}
Since the code is not inside a doFirst {} or doLast{} block, it is executed when the task is realized, and does not need to be called explicitly for the output to be sent to the console. Lesson learned. What I should have had was
task("soapuiDependencies") {
doLast {
soapui.forEach { print(it.toString()) }
}
}
Or some such. Second lesson has to do with dependency versions. Soapui 5.4.0 is packaged with json-path-0.9.1.jar (yikes, that's old) which contains the file
com/jayway/jsonpath/spi/JsonProvider.class
while gradle is pulling in as a dependency json-path-2.7.0.jar which contains the file
com/jayway/jsonpath/spi/json/JsonProvider.class.
Causing a ClassNotFoundException on the JsonProvider class when invoked via gradle.
This is the root of my problem and has nothing to do with my understanding of how gradle FileCollections, JavaExec, or classpath parameters work. I know I'm treading with dinosaurs, but hopefully the lessons learned will be of help to someone else.

Error: Could not find or load main class MainKt

In Multiplatform project, I want to use main function inside jvmMain to test the library I’m working on, but when I’m trying to run this it returns an error Error: Could not find or load main class MainKt for following function in Main.kt
fun main() {
println("Hello World!")
}
I've got Main.kt file in a root directory of my module, but putting it under some package is also throwing this error.
I'm using Java 8 JDK:
Are there any additional steps I should make to be able to use main function?
EDIT:
I did additional checks and I found out that when in the project I have android target then in the jvm main function I’m getting this error above. When I’m creating a new project with exactly the same configuration, but without android target it’s working properly, main function compiles and it is printing a message.
Any guess what is causing this problem?

No coverage results using the eclEmma plugin for server code in a gwt application

I'm using the eclEmma plugin to test code coverage for my gwt application. I've written jUnit test classes for client code, such as testing get/set methods etc. as well as jUnit tests for rpc services. I used "syncproxy" to test my equivalent GreetService, GreetServiceAsync and GreetServiceImpl rpc services. For example I have a location service that gets a users location and this is part of my test class:
public class LocationServiceTest {
private static LocationService rpcService =
(LocationService) SyncProxy.newProxyInstance(LocationService.class,
"http://localhost:...", "location");
#Test
public void testAdministrativeAreaLevel2LocationService() {
String result = rpcService.getAddress("49.28839970000001,-123.1259316");
assertTrue((result != null) && (result.startsWith("Vancouver")));
}
The jUnit tests all pass, but when I run eclEmma on my project (I right click the project, select "Coverage as" then "jUnit test") I only get coverage results for client code, and 0% coverage for all my server code.
Any suggestions for how to get eclEmma to cover server code? Or for what I might be doing wrong?
EclEmma tracks coverage on code launched at the test jvm (the vm you launch when you run the test). You seem to be running your server before, so eclEmma "can't see" its coverage. You could try running the server inside your tests, with Cargo, for example.

Gradle jettyRun: how does this thing work?

Normally, I would start Jetty by constructing a Server instance, setting a connector, a handler, and LifeCycleListener, followed by a call to start() on the Server instance. I haven't the foggiest idea how to make this happen with the jettyRun task in Gradle. The documentation is confusing to me, and I have yet to find an example of how this task works, other than page after page of gradle jettyRun.
This task is appealing to me because it allegedly returns immediately after execution. This is helpful for running Selenium tests after my webapp is running from Jenkins. I tried to do this via a JavaExec task, but this won't work since the JavaExec task does not terminate until the underlying JVM terminates as well.
It sounds like you want to start Jetty for in-container integration tests. Besides having a look at the source code these two posts should get you started:
War and Jetty plugins with http integration tests
Right way to do basic web integration testing?
The key feature you are looking for, starting Jetty in the background, is jettyRun.daemon = true.
What I'm using for integration test in build.gradle is looks like below. I think this code is simple and intuitive.
test {
exclude '**/*IntegrationTest*'
}
task integrationTest(type: Test) {
include '**/*IntegrationTest*'
doFirst {
jettyRun.httpPort = 8080 // Port for test
jettyRun.daemon = true
jettyRun.execute()
}
doLast {
jettyStop.stopPort = 8091 // Port for stop signal
jettyStop.stopKey = 'stopKey'
jettyStop.execute()
}
}