Skip to content

Commit d955e62

Browse files
authored
Merge pull request #186 from alexanderwiederin/kotlin-lint
Add CI Checks for Kotlin
2 parents 7a4ecd0 + 52c9694 commit d955e62

File tree

6 files changed

+213
-45
lines changed

6 files changed

+213
-45
lines changed

.github/workflows/kotlin.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: Continuous Integration Checks - Kotlin
2+
3+
on: [push, pull_request]
4+
5+
jobs:
6+
check-kotlin:
7+
runs-on: ubuntu-latest
8+
9+
env:
10+
LDK_NODE_JVM_DIR: bindings/kotlin/ldk-node-jvm
11+
LDK_NODE_ANDROID_DIR: bindings/kotlin/ldk-node-android
12+
13+
steps:
14+
- name: Checkout repository
15+
uses: actions/checkout@v4
16+
17+
- name: Set up JDK
18+
uses: actions/setup-java@v3
19+
with:
20+
distribution: temurin
21+
java-version: 11
22+
23+
- name: Run ktlintCheck on ldk-node-jvm
24+
run: |
25+
cd $LDK_NODE_JVM_DIR
26+
./gradlew ktlintCheck
27+
28+
- name: Run ktlintCheck on ldk-node-android
29+
run: |
30+
cd $LDK_NODE_ANDROID_DIR
31+
./gradlew ktlintCheck
32+
33+
- name: Generate Kotlin JVM
34+
run: ./scripts/uniffi_bindgen_generate_kotlin.sh
35+
36+
- name: Start bitcoind and electrs
37+
run: docker compose up -d
38+
39+
- name: Run ldk-node-jvm tests
40+
run: |
41+
cd $LDK_NODE_JVM_DIR
42+
./gradlew test -Penv=ci
43+
44+
- name: Run ldk-node-android tests
45+
run: |
46+
cd $LDK_NODE_ANDROID_DIR
47+
./gradlew test

bindings/kotlin/ldk-node-android/lib/build.gradle.kts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
import org.gradle.api.tasks.testing.logging.TestExceptionFormat.*
2-
import org.gradle.api.tasks.testing.logging.TestLogEvent.*
3-
41
// library version is defined in gradle.properties
52
val libraryVersion: String by project
63

@@ -10,6 +7,7 @@ plugins {
107

118
id("maven-publish")
129
id("signing")
10+
id("org.jlleitschuh.gradle.ktlint") version "11.6.1"
1311
}
1412

1513
repositories {
@@ -106,3 +104,11 @@ signing {
106104
// useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword)
107105
sign(publishing.publications)
108106
}
107+
108+
ktlint {
109+
filter {
110+
exclude { entry ->
111+
entry.file.toString().contains("main")
112+
}
113+
}
114+
}

bindings/kotlin/ldk-node-jvm/lib/build.gradle.kts

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
import org.gradle.api.tasks.testing.logging.TestExceptionFormat.*
2-
import org.gradle.api.tasks.testing.logging.TestLogEvent.*
1+
import org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
2+
import org.gradle.api.tasks.testing.logging.TestLogEvent.FAILED
3+
import org.gradle.api.tasks.testing.logging.TestLogEvent.PASSED
4+
import org.gradle.api.tasks.testing.logging.TestLogEvent.SKIPPED
5+
import org.gradle.api.tasks.testing.logging.TestLogEvent.STANDARD_ERROR
6+
import org.gradle.api.tasks.testing.logging.TestLogEvent.STANDARD_OUT
37

48
// library version is defined in gradle.properties
59
val libraryVersion: String by project
@@ -12,6 +16,7 @@ plugins {
1216
id("java-library")
1317
id("maven-publish")
1418
id("signing")
19+
id("org.jlleitschuh.gradle.ktlint") version "11.6.1"
1520
}
1621

1722
repositories {
@@ -31,12 +36,12 @@ dependencies {
3136
// Use the JUnit 5 integration.
3237
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.1")
3338

34-
//// This dependency is exported to consumers, that is to say found on their compile classpath.
35-
//api("org.apache.commons:commons-math3:3.6.1")
39+
// // This dependency is exported to consumers, that is to say found on their compile classpath.
40+
// api("org.apache.commons:commons-math3:3.6.1")
3641

37-
//// This dependency is used internally, and not exposed to consumers on their own compile classpath.
38-
//implementation("com.google.guava:guava:31.1-jre")
39-
// Align versions of all Kotlin components
42+
// // This dependency is used internally, and not exposed to consumers on their own compile classpath.
43+
// implementation("com.google.guava:guava:31.1-jre")
44+
// Align versions of all Kotlin components
4045
implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
4146

4247
// Use the Kotlin JDK 8 standard library.
@@ -49,13 +54,30 @@ tasks.named<Test>("test") {
4954
// Use JUnit Platform for unit tests.
5055
useJUnitPlatform()
5156

52-
testLogging {
57+
testLogging {
5358
events(PASSED, SKIPPED, FAILED, STANDARD_OUT, STANDARD_ERROR)
5459
exceptionFormat = FULL
5560
showExceptions = true
5661
showCauses = true
5762
showStackTraces = true
58-
showStandardStreams = true
63+
showStandardStreams = true
64+
}
65+
}
66+
67+
tasks.test {
68+
doFirst {
69+
if (project.hasProperty("env") && project.property("env") == "ci") {
70+
environment("BITCOIN_CLI_BIN", "docker exec ldk-node-bitcoin-1 bitcoin-cli")
71+
environment("BITCOIND_RPC_USER", "user")
72+
environment("BITCOIND_RPC_PASSWORD", "pass")
73+
environment("ESPLORA_ENDPOINT", "http://127.0.0.1:3002")
74+
} else {
75+
// Adapt these to your local environment
76+
environment("BITCOIN_CLI_BIN", "bitcoin-cli")
77+
environment("BITCOIND_RPC_USER", "")
78+
environment("BITCOIND_RPC_PASSWORD", "")
79+
environment("ESPLORA_ENDPOINT", "http://127.0.0.1:3002")
80+
}
5981
}
6082
}
6183

@@ -88,8 +110,8 @@ afterEvaluate {
88110
developers {
89111
developer {
90112
id.set("tnull")
91-
name.set("Elias Rohrer")
92-
email.set("dev@tnull.de")
113+
name.set("Elias Rohrer")
114+
email.set("dev@tnull.de")
93115
}
94116
}
95117
}
@@ -111,3 +133,11 @@ signing {
111133
// useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword)
112134
sign(publishing.publications)
113135
}
136+
137+
ktlint {
138+
filter {
139+
exclude { entry ->
140+
entry.file.toString().contains("main")
141+
}
142+
}
143+
}

bindings/kotlin/ldk-node-jvm/lib/src/test/kotlin/org/lightningdevkit/ldknode/LibraryTest.kt

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
1-
/*
2-
* This Kotlin source file was generated by the Gradle 'init' task.
3-
*/
41
package org.lightningdevkit.ldknode
52

6-
import kotlin.UInt
7-
import kotlin.test.Test
8-
import kotlin.test.assertEquals
9-
import kotlin.io.path.createTempDirectory
3+
import org.junit.jupiter.api.BeforeAll
4+
import org.junit.jupiter.api.Test
5+
import org.junit.jupiter.api.TestInstance
106
import java.net.URI
117
import java.net.http.HttpClient
128
import java.net.http.HttpRequest
139
import java.net.http.HttpResponse
10+
import kotlin.io.path.createTempDirectory
11+
import kotlin.test.assertEquals
1412

1513
fun runCommandAndWait(vararg cmd: String): String {
1614
println("Running command \"${cmd.joinToString(" ")}\"")
@@ -24,12 +22,29 @@ fun runCommandAndWait(vararg cmd: String): String {
2422
return stdout + stderr
2523
}
2624

25+
fun bitcoinCli(vararg cmd: String): String {
26+
val bitcoinCliBin = System.getenv("BITCOIN_CLI_BIN")?.split(" ") ?: listOf("bitcoin-cli")
27+
val bitcoinDRpcUser = System.getenv("BITCOIND_RPC_USER") ?: ""
28+
val bitcoinDRpcPassword = System.getenv("BITCOIND_RPC_PASSWORD") ?: ""
29+
30+
val baseCommand = bitcoinCliBin + "-regtest"
31+
32+
val rpcAuth = if (bitcoinDRpcUser.isNotBlank() && bitcoinDRpcPassword.isNotBlank()) {
33+
listOf("-rpcuser=$bitcoinDRpcUser", "-rpcpassword=$bitcoinDRpcPassword")
34+
} else {
35+
emptyList()
36+
}
37+
38+
val fullCommand = baseCommand + rpcAuth + cmd.toList()
39+
return runCommandAndWait(*fullCommand.toTypedArray())
40+
}
41+
2742
fun mine(blocks: UInt): String {
28-
val address = runCommandAndWait("bitcoin-cli", "-regtest", "getnewaddress")
29-
val output = runCommandAndWait("bitcoin-cli", "-regtest", "generatetoaddress", blocks.toString(), address)
43+
val address = bitcoinCli("getnewaddress")
44+
val output = bitcoinCli("generatetoaddress", blocks.toString(), address)
3045
println("Mining output: $output")
3146
val re = Regex("\n.+\n\\]$")
32-
val lastBlock = re.find(output)!!.value.replace("]","").replace("\"", "").replace("\n","").trim()
47+
val lastBlock = re.find(output)!!.value.replace("]", "").replace("\"", "").replace("\n", "").trim()
3348
println("Last block: $lastBlock")
3449
return lastBlock
3550
}
@@ -41,54 +56,56 @@ fun mineAndWait(esploraEndpoint: String, blocks: UInt) {
4156

4257
fun sendToAddress(address: String, amountSats: UInt): String {
4358
val amountBtc = amountSats.toDouble() / 100000000.0
44-
val output = runCommandAndWait("bitcoin-cli", "-regtest", "sendtoaddress", address, amountBtc.toString())
59+
val output = bitcoinCli("sendtoaddress", address, amountBtc.toString())
4560
return output
4661
}
4762

48-
fun setup() {
49-
runCommandAndWait("bitcoin-cli", "-regtest", "createwallet", "ldk_node_test")
50-
runCommandAndWait("bitcoin-cli", "-regtest", "loadwallet", "ldk_node_test", "true")
51-
mine(101u)
52-
Thread.sleep(5_000)
53-
}
54-
5563
fun waitForTx(esploraEndpoint: String, txid: String) {
5664
var esploraPickedUpTx = false
57-
val re = Regex("\"txid\":\"$txid\"");
65+
val re = Regex("\"txid\":\"$txid\"")
5866
while (!esploraPickedUpTx) {
5967
val client = HttpClient.newBuilder().build()
6068
val request = HttpRequest.newBuilder()
6169
.uri(URI.create(esploraEndpoint + "/tx/" + txid))
62-
.build();
70+
.build()
6371

64-
val response = client.send(request, HttpResponse.BodyHandlers.ofString());
72+
val response = client.send(request, HttpResponse.BodyHandlers.ofString())
6573

66-
esploraPickedUpTx = re.containsMatchIn(response.body());
74+
esploraPickedUpTx = re.containsMatchIn(response.body())
6775
Thread.sleep(500)
6876
}
6977
}
7078

7179
fun waitForBlock(esploraEndpoint: String, blockHash: String) {
7280
var esploraPickedUpBlock = false
73-
val re = Regex("\"in_best_chain\":true");
81+
val re = Regex("\"in_best_chain\":true")
7482
while (!esploraPickedUpBlock) {
7583
val client = HttpClient.newBuilder().build()
7684
val request = HttpRequest.newBuilder()
7785
.uri(URI.create(esploraEndpoint + "/block/" + blockHash + "/status"))
78-
.build();
86+
.build()
7987

80-
val response = client.send(request, HttpResponse.BodyHandlers.ofString());
88+
val response = client.send(request, HttpResponse.BodyHandlers.ofString())
8189

82-
esploraPickedUpBlock = re.containsMatchIn(response.body());
90+
esploraPickedUpBlock = re.containsMatchIn(response.body())
8391
Thread.sleep(500)
8492
}
8593
}
8694

95+
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
8796
class LibraryTest {
88-
@Test fun fullCycle() {
89-
val esploraEndpoint = "http://127.0.0.1:3002"
90-
setup()
9197

98+
val esploraEndpoint = System.getenv("ESPLORA_ENDPOINT")
99+
100+
@BeforeAll
101+
fun setup() {
102+
bitcoinCli("createwallet", "ldk_node_test")
103+
bitcoinCli("loadwallet", "ldk_node_test", "true")
104+
mine(101u)
105+
Thread.sleep(5_000)
106+
}
107+
108+
@Test fun fullCycle() {
92109
val tmpDir1 = createTempDirectory("ldk_node").toString()
93110
println("Random dir 1: $tmpDir1")
94111
val tmpDir2 = createTempDirectory("ldk_node").toString()
@@ -172,7 +189,7 @@ class LibraryTest {
172189

173190
val fundingTxid = when (channelPendingEvent1) {
174191
is Event.ChannelPending -> channelPendingEvent1.fundingTxo.txid
175-
else -> return
192+
else -> return
176193
}
177194

178195
waitForTx(esploraEndpoint, fundingTxid)
@@ -202,7 +219,7 @@ class LibraryTest {
202219

203220
val channelId = when (channelReadyEvent2) {
204221
is Event.ChannelReady -> channelReadyEvent2.channelId
205-
else -> return
222+
else -> return
206223
}
207224

208225
val invoice = node2.receivePayment(2500000u, "asdf", 9217u)

docker-compose.yml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
version: '3'
2+
3+
services:
4+
bitcoin:
5+
image: blockstream/bitcoind:24.1
6+
platform: linux/amd64
7+
command:
8+
[
9+
"bitcoind",
10+
"-printtoconsole",
11+
"-regtest=1",
12+
"-rpcallowip=0.0.0.0/0",
13+
"-rpcbind=0.0.0.0",
14+
"-rpcuser=user",
15+
"-rpcpassword=pass",
16+
"-fallbackfee=0.00001"
17+
]
18+
ports:
19+
- "18443:18443" # Regtest RPC port
20+
- "18444:18444" # Regtest P2P port
21+
networks:
22+
- bitcoin-electrs
23+
healthcheck:
24+
test: ["CMD", "bitcoin-cli", "-regtest", "-rpcuser=user", "-rpcpassword=pass", "getblockchaininfo"]
25+
interval: 5s
26+
timeout: 10s
27+
retries: 5
28+
29+
electrs:
30+
image: blockstream/esplora:electrs-cd9f90c115751eb9d2bca9a4da89d10d048ae931
31+
platform: linux/amd64
32+
depends_on:
33+
bitcoin:
34+
condition: service_healthy
35+
command:
36+
[
37+
"/app/electrs_bitcoin/bin/electrs",
38+
"-vvvv",
39+
"--timestamp",
40+
"--jsonrpc-import",
41+
"--cookie=user:pass",
42+
"--network=regtest",
43+
"--daemon-rpc-addr=bitcoin:18443",
44+
"--http-addr=0.0.0.0:3002"
45+
]
46+
ports:
47+
- "3002:3002"
48+
networks:
49+
- bitcoin-electrs
50+
51+
networks:
52+
bitcoin-electrs:
53+
driver: bridge

scripts/format_kotlin.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/bash
2+
LDK_NODE_ANDROID_DIR="bindings/kotlin/ldk-node-android"
3+
LDK_NODE_JVM_DIR="bindings/kotlin/ldk-node-jvm"
4+
5+
# Run ktlintFormat in ldk-node-android
6+
(
7+
cd $LDK_NODE_ANDROID_DIR || exit 1
8+
./gradlew ktlintFormat
9+
)
10+
11+
# Run ktlintFormat in ldk-node-jvm
12+
(
13+
cd $LDK_NODE_JVM_DIR || exit 1
14+
./gradlew ktlintFormat
15+
)

0 commit comments

Comments
 (0)