Hi all, we are running a kotlin mpp project (which...
# multiplatform
k
Hi all, we are running a kotlin mpp project (which currently targets jvm and js). As part of this, we have a integration test suite that needs to feed a large json file into the code being tested. Currently, we are fetching this over http from somewhere in the cloud, which is far from ideal. We are looking to change this, and tried implemeting file operations for jvm and js targets, but then we ran into problems finding the root path that gradle executes the testcases from, and it just became messy. An alternative would be to start a small http server as part of the gradle build, which would eliminate the cloud dependency. Has anyone done anything similar? Any recommendations?
j
I would be really happy to hear any experience with this as well. I’m writing a multiplatform STOMP client over websockets, and I’d really like to test it without internet connection. That is, I’d like to spin up a local server to test the lib on all platforms, but I don’t want to implement an independent test server in every platform (I believe I can find nice JVM servers to launch during the test and to reuse when testing the JS client)
@Kenneth Andersson In your case, where would the local HTTP server serve the JSON from? I don’t really understand your use case. If you need a variable JSON file that actually corresponds to the cloud version, then you’ll have to download it at some point during the build (maybe only once, via gradle). If you want to have a fixed test file, why not just checkin the test JSON file in your repo?
Oh maybe I get it now, is your file fetched via HTTP in the production code? And you just want to use the same production code (under test) to access the test file locally?
k
I can check-in a file, but I cant read it from the testcode as the paths where the different platforms execute the testcase from seems to differ between targets and platforms. Suppose we place the json file in the root of our project. How do we reference that file in the testcase?
Our alternative was to declare a variable that contains a multiline string with json content, but that didnt work as this is larger than the java string constant limit of roughly 32K
j
you may have to place it rather in
src/commonTest/resources
and access it like a resource, wouldn’t that work?
Copy code
MyTest::class.java.getResource("/testData.json").readText()
Not sure if this works on JS platform, though, to be honest…
k
We can place it anywhere - thats not problem. The issue as I said is how the different targets resolve the root path. We tried searching in the path on the target-specific platform for the root, but it doesnt feel like a viable solution.
j
My point was that you don’t need the actual path to access it like a resource, but maybe this only works on JVM
k
Copy code
@ExperimentalStdlibApi
actual fun readAbsoluteFile(absolutePath: String): Array<Byte>? {
    val str = readFileSync(absolutePath, "UTF-8")
    return str.encodeToByteArray().toTypedArray()
}

@ExperimentalStdlibApi
actual fun readRelativeFile(relativePath: String): Array<Byte>? {
    return readAbsoluteFile("${rootPath()}$relativePath")
}

fun rootPath(): String {
    val falseRoot = resolve(".")
    /* absolute returns the build-catalog. Let us go back to project root */
    return falseRoot.subSequence(0, falseRoot.indexOf("realroot")).toString()
}
I think that only works on jvm
but I will give it a shot
j
actually, there’s literally
::class.java
in it, so I bet that won’t work on JS.. 😞 maybe you can implement an
expect
/
actual
function to get this file’s contents, the JVM version would use the resource normally with the snippet above, the JS version can probably simply
js(require("./testData.json"))
the file, given that gradle places the JSON in the right location during the resources processing
k
right, I will test moving the file to resources and see if that works on js target. If it does - you deserve a gold star 😄
😄 1
j
k
on JVM, i read resource files by accessing via relative path (src/commontTest/resources). on iOS, I copy those files to a new directory in /tmp, and delete them once the test step is done. unsure if you could use something similar for JS.
k
I have tried the resources variant, and the files in resources and not copied over to the build folder during, together where the compiled testcase is running for js target. Relative path works fine on jvm target.
I like your idea of copying them to a different path on the fs, and just accessing them there.
k
yes, and then i have an expect/actual to get the resources directory for my test code
j
@Kris Wong but if you’re copying the file to
/tmp
anyway for iOS, why don’t you use the same implementation for all tests (reading from
/tmp
) instead of using expect/actual?
k
because testing on iOS requires me to create a gradle task anyway, which I can hook into to easily handle the files. for Android/JVM I am just using the existing gradle tasks
k
copying the files solved the problem. Thanks for that solution. I just need to tune it for different host systems. We have a few in the team on windows computers, but thats managable. Thanks a lot for good tips both
🍻 1
j
@Kris Wong fair enough 🙂