How to Set Kotlin Integration Test Source Directory Gradle Kotlin DSL - kotlin

Please note there are several similar questions (like this and this and this and this) regarding how to set source-set for integration tests in Gradle but none of them is using JvmTestSuite.
I've got my build.gradle.kt configured as below (please let me know if full script is needed to answer my question):
testing {
suites {
val test by getting(JvmTestSuite::class) {
useJUnitJupiter()
}
val integration by registering(JvmTestSuite::class) {
testType.set(TestSuiteType.INTEGRATION_TEST)
dependencies {
implementation(project)
}
sources {
java {
setSrcDirs(listOf("src/it/java"))
}
resources {
setSrcDirs(listOf("src/it/resources"))
}
}
targets {
all {
testTask.configure {
shouldRunAfter(test)
}
}
}
}
}
}
Having that, Gradle finds my Java tests in java folder and runs them correctly. Now my question is how to set the source directory for kotlin folder. The same syntax doesn't seem to work. I also tried different solutions found on the web, but none works. Thanks.
Update
It seems to be as simple as:
java {
setSrcDirs(listOf("src/it/kotlin"))
}
I'll wait if someone else has a better answer.

Related

Kotlin Multiplatform Dependency Injection with Annotations

I am attempting to use this library for dependency injection within my Kotlin Multiplatform project - https://github.com/corbella83/PopKorn
The library is based on kapt and the Android part works perfectly! However, I'm struggling to understand why iOS doesn't seem to be working (I have filed an issue on their end but wanted to ask here in case I'm issing something obvious).
I have a vanilla KMM project out-of-the-box from the KMM Android Studio plugin with the following dependency-related setup:
// In shared/build.gradle.kts
kotlin {
...
sourceSets {
val commonMain by getting {
dependencies {
implementation("cc.popkorn:popkorn:2.1.1")
}
}
}
}
dependencies {
"kapt" ("cc.popkorn:popkorn-compiler:2.1.1") <- SHOULD THIS BE HERE?
}
// In androidApp/build.gradle.kts
dependencies {
implementation("cc.popkorn:popkorn:2.1.1")
}
// In commonMain source set
#Injectable
class Greeting {
fun greeting(): String {
return "Hello, ${Platform().platform}!"
}
}
// In MainActivity.kt
val greeting by popkorn<Greeting>() <- WORKS!
// In iosMain/Bridge.kt
fun init(creator: (ObjCClass) -> Mapping) = cc.popkorn.setup(creator)
fun getInjector() = InjectorObjC(popKorn())
// In iosApp
#main
struct iOSApp: App {
init() {
BridgeKt.doInit { (clazz) -> PopkornMapping in
return clazz.alloc() as! PopkornMapping
}
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
// In ContentView.swift
let greet = (BridgeKt.getInjector().inject(clazz: Greeting.self) as! Greeting).greeting()
The error I have is Could not find Provider for this class: com.example.myapplication.Greeting. Did you forget to add #Injectable? which is clearly not true as I do have the annotation.
My concern is that when android compiles I can see some logs related to annotation generation with PopKorn, however I do not see this when I build the iOS app using the following Run Script (the default when a new project is created):
./gradlew :shared:embedAndSignAppleFrameworkForXcode
Is there any additional setup required for kapt to work on iOS?
I ended up using a different library for dependency injection for Kotlin Multiplatform (Kodein) but for what it's worth I thought it'd be helpful for anyone having similar issues to know how I resolved it. The key was to expose the generated code to Swift using this:
val iosMain by getting {
...
kotlin.srcDir("${buildDir.absolutePath}/generated/source/kaptKotlin/")
}
After this the injection from Swift worked as it was meant to. However, I ended up having more issues trying to inject things from multiple modules and felt Kodein has better support for what I'm trying to do at the moment.

KTor site not reachable

I want to make a simple http server using ktor. However, when I enter the site (127.0.0.1:8080 or 0.0.0.0:8080), it just isn't there. It doesn't print and doesn't respond.
However if I use NanoHttpd instead of ktor, everything works fine. What is my issue?
import io.ktor.application.call
import io.ktor.http.ContentType
import io.ktor.response.respondText
import io.ktor.routing.get
import io.ktor.routing.routing
import io.ktor.server.engine.embeddedServer
import io.ktor.server.netty.Netty
fun main() {
val server = embeddedServer(Netty, port = 8080) {
routing {
get("/") {
println("TEST")
call.respondText("Hello World!", ContentType.Text.Plain)
}
}
}
server.start(wait = true)
}
The output is just:
[main] INFO ktor.application - No ktor.deployment.watch patterns specified, automatic reload is not active
[main] INFO ktor.application - Responding at http://0.0.0.0:8080
It could be one of the following things:
The application code
The run configuration
I am leaning towards there being a problem with the run configuration rather than the application code.
Application code
Even though I think your issue is with the run configuration, in case that it isn't, I'm providing sample code here.
When I use the IntelliJ Ktor plugin, the Ktor app is bootstrapped as follows:
Application.kt
package com.example
import io.ktor.application.*
import io.ktor.http.*
import io.ktor.response.*
import io.ktor.routing.*
fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)
#kotlin.jvm.JvmOverloads
#Suppress("unused") // Referenced in application.conf
fun Application.module(testing: Boolean = false) {
routing {
get("/") {
call.respondText("Hello, world!", ContentType.Text.Plain)
}
}
}
application.conf
ktor {
deployment {
port = 8080
port = ${?PORT}
}
application {
modules = [ com.example.ApplicationKt.module ]
}
}
I've provided an example Ktor code base here: https://gitlab.com/tinacious/ktor-example
Run configuration
It could be your run configuration in IntelliJ. It needs to be set up as a Kotlin script (and not an Application). When it's set up as an Application, I get the same error you do. Here is how to set up the run configuration I have, allowing me to run the server in IntelliJ:
Add a configuration
Choose Kotlin script from the Templates section. Do not choose Application.
Near the bottom where it says "Use classpath of module" choose your application.main.
Near the top where it says "Main class" you should be able to choose your main application. I found this only showed up after I chose the classpath of the module.
Here are the relevant sections in the configuration:
Here is what I describe in step 4, i.e. I can choose my main class after the class path is added:
The run symbol should be a Kotlin logo:
I would recommend installing the IntelliJ Ktor plugin for bootstrapping your project. It uses Gradle and bootstraps everything so when you run ./gradlew run, you are running it properly and can access it without the manual build configuration step.

Documenting Ktor routes with KDoc

Does anyone know whats the correct way to document Ktor routes, aiming to show it on KDoc?
Example:
route(DogoBot.data.API.ROUTE){
route("token"){
route("add"){
get("fromdiscord") { ... }
get { ... }
}
}
route("user"){
route("{id}") {
get { ... }
}
}
route("guild"){
route("{id}") {
get { ... }
}
}
}
Well, if is it possible, how do I do this? Which type of information should I put in it? How do I implement that Ktor compatibility in other things? (I have another router made by my own for other things)
Dokka has no support for Ktor routes, and I'm not aware of any plans to add such support, so there's no way to include information about routes into the generated documentation.

How to test a server side debugOnly package

I don't understand how it is possible to test a package that is debugOnly.
My package.js is quite simple :
Package.describe({
name: 'lambda',
version: '0.0.1',
debugOnly: true // Will not be packaged into the production build
});
Package.onUse(function(api) {
api.versionsFrom('1.2.1');
api.addFiles('lambda.js');
api.export("Lambda", 'server');
});
Package.onTest(function(api) {
api.use('tinytest');
api.use('lambda');
api.addFiles('lambda-tests.js', 'server');
});
My lambda-test.js :
Tinytest.add('example', function (test) {
test.equal(Lambda.func(), true);
});
My lambda.js :
Lambda = {
func: function() {
return "Christmas";
}
}
When I run meteor test-packages, it just fails : Lambda is not defined. If I remove the debugOnly: true the test pass. So how can I test my package using tinytest ?
Or this is a bug !
I had the same issue! It turns out the tests are working fine. The Lambda is not getting exported in the project either.
from https://github.com/meteor/meteor/blob/0f0c5d3bb3a5492254cd0843339a6716ef65fce1/tools/isobuild/compiler.js
// don't import symbols from debugOnly and prodOnly packages, because
// if the package is not linked it will cause a runtime error.
// the code must access them with `Package["my-package"].MySymbol`.
Try:
Tinytest.add('example', function (test) {
//also changed expected value from true to Christmas to make test pass
test.equal(Package['lambda']['Lambda'].func(), "Christmas");
//you can use Package['lambda'].Lambda as well, but my IDE complains
});
Now you can do something like this:
if (Package['lambda']) {
console.log("we are in debug mode and we have lamda");
console.log("does this say Christmas? " + Package['lambda']["Lambda"]['func']());
} else {
console.log("we are in production mode, or we have not installed lambda");
}

intern dojo loader issue

I'm trying to setup intern for my project, a Dojo/JS project, and the server is not Node... I get a loader issue, which seems to be due to dojo.has using Dojo loader... The require wrapper suggested in here did not work for me.
I get the error below:
> node node_modules/intern/client.js config=tests/intern
Defaulting to "console" reporter
dojo/text plugin failed to load because loader does not support getText
TypeError: undefined is not a function
at Object.load (lib/dojo/dojo/text.js:199:6)
Below are my intern configuration and the test file:
/tests/intern.js: (config file)
loader: {
packages: [ { name: 'visitorsPortal', location: 'portals/visitor' },
{ name: 'dojo', location: 'lib/dojo/dojo'},
{ name: 'dijit', location: 'lib/dojo/dijit'},
{ name: 'portalLib', location: 'portals/lib'} ]
},
suites: [ 'tests/uitests' ],
tests/uitests:
define([
'intern!tdd',
'intern/chai!assert',
'portals/visitor/views/MyModule'
], function (test, assert, MyModule) {
// empty for now...
});
This has nothing to do with dojo/has and everything to do with the dojo/text plugin requiring functionality that only exists within the Dojo 1 loader when being used server-side.
If you are attempting to test software that relies on any non-standard AMD loader functionality, you will need to use the non-standard loader, or override those modules with alternative copies that are compatible with other loaders.
In this specific case, your easiest path forward is to use the geezer edition of Intern, since it includes the old Dojo loader which contains these non-standard extensions. The best path forward is to remap the dojo/text module to another compatible module that does not need anything special in the loader in order to retrieve the data:
// in intern.js
// ...
loader: {
map: {
'*': {
'dojo/text': 'my/text'
}
}
},
// ...
I struggled with the same problem yesterday, but thanks to C Snover's answer here and the question you're linking to, I did make some progress.
I added the map directive to the intern.js loader config (as C Snover suggests).
// in intern.js
// ...
loader: {
map: {
'*': {
'dojo/text': 'my/text'
}
}
},
// ...
For the my/text module, I just copied dojo/text and added an else if clause to the part that resolves the getText function:
if(has("host-browser")){
getText= function(url, sync, load){
request(url, {sync:!!sync}).then(load);
};
} else if(has("host-node")){
// This was my addition...
getText = function(url, sync, load) {
require(["dojo/node!fs"], function(fs) {
fs.readFile(url, 'utf-8', function(err, data) {
if(err) console.error("Failed to read file", url);
load(data);
});
});
};
} else {
// Path for node.js and rhino, to load from local file system.
// TODO: use node.js native methods rather than depending on a require.getText() method to exist.
if(require.getText){
getText= require.getText;
}else{
console.error("dojo/text plugin failed to load because loader does not support getText");
}
}
However, even though the tests were running in intern via node, the host-node value wasn't being set. That was fixed by setting dojo-has-api in my intern.js config:
define(["intern/node_modules/dojo/has"], function(has) {
has.add("dojo-has-api", true);
return { /* my intern config as normal */ };
});
I'll admit I don't understand 100% what I've done here, and with the copy/pasting it's not exactly pretty, but it serves as a temporary fix for my problem at least.
Note: This did introduce another set of issues though: Since Dojo now knows that it's running in node, dojo/request no longer tries to use XHR. I was using sinon.js to mock my xhr requests, so this had to be changed.