From 6f9eefd00cdc384056fb236fe05140c3a509e14a Mon Sep 17 00:00:00 2001 From: Davide Pianca Date: Tue, 8 Aug 2023 19:40:41 +0200 Subject: [PATCH] Fix JS tests --- gradle.properties | 1 + kmqtt-broker/build.gradle.kts | 4 +++- .../kotlin/integration/AuthenticationTest.kt | 17 +++++++++++------ .../PublishSubscribeMultipleClientsTest.kt | 17 +++++++++++------ .../PublishSubscribeSingleClientTest.kt | 11 ++++++++--- .../kotlin/integration/RetainedPublishTest.kt | 11 ++++++++--- .../commonTest/kotlin/integration/TLSTest.kt | 11 ++++++++--- kmqtt-client/build.gradle.kts | 6 +++++- .../src/commonMain/kotlin/MQTTClient.kt | 18 ++++++++++++++++-- kmqtt-common/src/jsMain/kotlin/utils.kt | 6 +++++- 10 files changed, 76 insertions(+), 26 deletions(-) diff --git a/gradle.properties b/gradle.properties index 1b7c97d..bde13ca 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,4 @@ kotlin.code.style=official serializationVersion=1.5.1 +coroutineVersion=1.7.3 kotlin.js.generate.executable.default=false diff --git a/kmqtt-broker/build.gradle.kts b/kmqtt-broker/build.gradle.kts index 0c5495e..ee44644 100644 --- a/kmqtt-broker/build.gradle.kts +++ b/kmqtt-broker/build.gradle.kts @@ -8,6 +8,7 @@ plugins { } val serializationVersion: String by project +val coroutineVersion: String by project kotlin { explicitApi() @@ -63,6 +64,7 @@ kotlin { implementation(project(":kmqtt-common")) implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serializationVersion") implementation("org.jetbrains.kotlinx:kotlinx-serialization-protobuf:$serializationVersion") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion") } } val commonTest by getting { @@ -70,6 +72,7 @@ kotlin { implementation(kotlin("test-common")) implementation(kotlin("test-annotations-common")) implementation(project(":kmqtt-client")) + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutineVersion") } } val jvmMain by getting { @@ -86,7 +89,6 @@ kotlin { val jsMain by getting { dependencies { implementation("org.jetbrains.kotlin-wrappers:kotlin-node:18.16.12-pre.599") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-js:1.7.2") } } val jsTest by getting { diff --git a/kmqtt-broker/src/commonTest/kotlin/integration/AuthenticationTest.kt b/kmqtt-broker/src/commonTest/kotlin/integration/AuthenticationTest.kt index c61fca6..ec4cb54 100644 --- a/kmqtt-broker/src/commonTest/kotlin/integration/AuthenticationTest.kt +++ b/kmqtt-broker/src/commonTest/kotlin/integration/AuthenticationTest.kt @@ -1,7 +1,10 @@ package integration -import IgnoreJs import MQTTClient +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.test.runTest +import kotlinx.coroutines.withContext import mqtt.MQTTException import mqtt.broker.Broker import mqtt.broker.interfaces.Authentication @@ -11,10 +14,9 @@ import mqtt.packets.mqttv5.ReasonCode import kotlin.test.Test import kotlin.test.assertFailsWith -@IgnoreJs class AuthenticationTest { - private fun testAuthentication( + private suspend fun testAuthentication( client: MQTTClient, broker: Broker ) { @@ -23,6 +25,9 @@ class AuthenticationTest { broker.step() client.step() i++ + withContext(Dispatchers.Default) { + delay(10) + } } if (i >= 1000) { throw Exception("Test timeout") @@ -31,7 +36,7 @@ class AuthenticationTest { } @Test - fun testSimpleAuthentication() { + fun testSimpleAuthentication() = runTest { val broker = Broker(authentication = object : Authentication { override fun authenticate(clientId: String, username: String?, password: UByteArray?): Boolean { return username == "user" && password?.toByteArray()?.decodeToString() == "pass" @@ -45,7 +50,7 @@ class AuthenticationTest { } @Test - fun testSimpleAuthenticationFailure() { + fun testSimpleAuthenticationFailure() = runTest { val broker = Broker(authentication = object : Authentication { override fun authenticate(clientId: String, username: String?, password: UByteArray?): Boolean { return username == "user" && password?.toByteArray()?.decodeToString() == "pass" @@ -61,7 +66,7 @@ class AuthenticationTest { } @Test - fun testEnhancedAuthentication() { + fun testEnhancedAuthentication() = runTest { val broker = Broker(enhancedAuthenticationProviders = mapOf("TEST-EN-AUTH" to object : EnhancedAuthenticationProvider { diff --git a/kmqtt-broker/src/commonTest/kotlin/integration/PublishSubscribeMultipleClientsTest.kt b/kmqtt-broker/src/commonTest/kotlin/integration/PublishSubscribeMultipleClientsTest.kt index f58ee10..ce627fc 100644 --- a/kmqtt-broker/src/commonTest/kotlin/integration/PublishSubscribeMultipleClientsTest.kt +++ b/kmqtt-broker/src/commonTest/kotlin/integration/PublishSubscribeMultipleClientsTest.kt @@ -1,7 +1,10 @@ package integration -import IgnoreJs import MQTTClient +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.test.runTest +import kotlinx.coroutines.withContext import mqtt.Subscription import mqtt.broker.Broker import mqtt.packets.Qos @@ -10,10 +13,9 @@ import kotlin.test.Test import kotlin.test.assertContentEquals import kotlin.test.assertEquals -@IgnoreJs class PublishSubscribeMultipleClientsTest { - private fun testPublish(qos: Qos, topic: String, payload: UByteArray) { + private suspend fun testPublish(qos: Qos, topic: String, payload: UByteArray) { var received = false val broker = Broker() @@ -39,6 +41,9 @@ class PublishSubscribeMultipleClientsTest { client1.step() client2.step() i++ + withContext(Dispatchers.Default) { + delay(10) + } } broker.stop() @@ -49,7 +54,7 @@ class PublishSubscribeMultipleClientsTest { } @Test - fun testPublishSubscribeTopicQos0() { + fun testPublishSubscribeTopicQos0() = runTest { val sendPayload = "Test1Test1Test1Test1Test1Test1Test1Test1Test1Test1Test1Test1".encodeToByteArray() val topic = "test/topic" @@ -57,7 +62,7 @@ class PublishSubscribeMultipleClientsTest { } @Test - fun testPublishSubscribeTopicQos1() { + fun testPublishSubscribeTopicQos1() = runTest { val sendPayload = "Test1Test1Test1Test1Test1Test1Test1Test1Test1Test1Test1Test1".encodeToByteArray() val topic = "test/topic" @@ -65,7 +70,7 @@ class PublishSubscribeMultipleClientsTest { } @Test - fun testPublishSubscribeTopicQos2() { + fun testPublishSubscribeTopicQos2() = runTest { val sendPayload = "Test1Test1Test1Test1Test1Test1Test1Test1Test1Test1Test1Test1".encodeToByteArray() val topic = "test/topic" diff --git a/kmqtt-broker/src/commonTest/kotlin/integration/PublishSubscribeSingleClientTest.kt b/kmqtt-broker/src/commonTest/kotlin/integration/PublishSubscribeSingleClientTest.kt index e233788..632fdcd 100644 --- a/kmqtt-broker/src/commonTest/kotlin/integration/PublishSubscribeSingleClientTest.kt +++ b/kmqtt-broker/src/commonTest/kotlin/integration/PublishSubscribeSingleClientTest.kt @@ -1,7 +1,10 @@ package integration -import IgnoreJs import MQTTClient +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.test.runTest +import kotlinx.coroutines.withContext import mqtt.Subscription import mqtt.broker.Broker import mqtt.packets.Qos @@ -11,11 +14,10 @@ import kotlin.test.assertContentEquals import kotlin.test.assertEquals -@IgnoreJs class PublishSubscribeSingleClientTest { @Test - fun testPublish() { + fun testPublish() = runTest { val sendPayload = "Test" val topic = "test/topic" @@ -41,6 +43,9 @@ class PublishSubscribeSingleClientTest { broker.step() client.step() i++ + withContext(Dispatchers.Default) { + delay(10) + } } broker.stop() diff --git a/kmqtt-broker/src/commonTest/kotlin/integration/RetainedPublishTest.kt b/kmqtt-broker/src/commonTest/kotlin/integration/RetainedPublishTest.kt index 2feb20c..ef384be 100644 --- a/kmqtt-broker/src/commonTest/kotlin/integration/RetainedPublishTest.kt +++ b/kmqtt-broker/src/commonTest/kotlin/integration/RetainedPublishTest.kt @@ -1,7 +1,10 @@ package integration -import IgnoreJs import MQTTClient +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.test.runTest +import kotlinx.coroutines.withContext import mqtt.Subscription import mqtt.broker.Broker import mqtt.packets.Qos @@ -10,11 +13,10 @@ import kotlin.test.Test import kotlin.test.assertContentEquals import kotlin.test.assertEquals -@IgnoreJs class RetainedPublishTest { @Test - fun testRetained() { + fun testRetained() = runTest { val qos0Topic = "from/qos 0" val qos1Topic = "from/qos 1" val qos2Topic = "from/qos 2" @@ -55,6 +57,9 @@ class RetainedPublishTest { broker.step() client.step() i++ + withContext(Dispatchers.Default) { + delay(10) + } } broker.stop() diff --git a/kmqtt-broker/src/commonTest/kotlin/integration/TLSTest.kt b/kmqtt-broker/src/commonTest/kotlin/integration/TLSTest.kt index 13933f6..ae8d21b 100644 --- a/kmqtt-broker/src/commonTest/kotlin/integration/TLSTest.kt +++ b/kmqtt-broker/src/commonTest/kotlin/integration/TLSTest.kt @@ -1,8 +1,11 @@ package integration -import IgnoreJs import MQTTClient import TLSClientSettings +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.test.runTest +import kotlinx.coroutines.withContext import mqtt.Subscription import mqtt.broker.Broker import mqtt.packets.Qos @@ -12,11 +15,10 @@ import kotlin.test.Test import kotlin.test.assertContentEquals import kotlin.test.assertEquals -@IgnoreJs class TLSTest { @Test - fun testPublish() { + fun testPublish() = runTest { val sendPayload = "Test" val topic = "test/topic" @@ -42,6 +44,9 @@ class TLSTest { broker.step() client.step() i++ + withContext(Dispatchers.Default) { + delay(10) + } } broker.stop() diff --git a/kmqtt-client/build.gradle.kts b/kmqtt-client/build.gradle.kts index 7c52249..51550e7 100644 --- a/kmqtt-client/build.gradle.kts +++ b/kmqtt-client/build.gradle.kts @@ -17,7 +17,11 @@ kotlin { binaries.executable() } } - mingwX64 {} + mingwX64 { + binaries { + executable { } + } + } linuxX64 {} linuxArm64 {} iosX64 {} diff --git a/kmqtt-client/src/commonMain/kotlin/MQTTClient.kt b/kmqtt-client/src/commonMain/kotlin/MQTTClient.kt index be17ddd..c799c85 100644 --- a/kmqtt-client/src/commonMain/kotlin/MQTTClient.kt +++ b/kmqtt-client/src/commonMain/kotlin/MQTTClient.kt @@ -10,6 +10,7 @@ import mqtt.packets.mqtt.* import mqtt.packets.mqttv4.* import mqtt.packets.mqttv5.* import socket.IOException +import socket.SocketClosedException import socket.SocketInterface import socket.streams.EOFException @@ -279,7 +280,14 @@ public class MQTTClient( } } + private var lastException: Exception? = null + private fun check() { + if (socket == null) { + close() + // Needed because of JS callbacks, otherwise the exception gets swallowed and tests don't complete correctly + throw lastException ?: SocketClosedException("") + } val data = socket!!.read() lock.withLock { if (data != null) { @@ -290,20 +298,24 @@ public class MQTTClient( handlePacket(it) } } catch (e: MQTTException) { + lastException = e e.printStackTrace() disconnect(e.reasonCode) close() throw e } catch (e: EOFException) { + lastException = e println("EOF") close() throw e } catch (e: IOException) { + lastException = e println("IOException ${e.message}") disconnect(ReasonCode.UNSPECIFIED_ERROR) close() throw e } catch (e: Exception) { + lastException = e println("Exception ${e.message} ${e.cause?.message}") disconnect(ReasonCode.IMPLEMENTATION_SPECIFIC_ERROR) close() @@ -314,14 +326,16 @@ public class MQTTClient( val currentTime = currentTimeMillis() if (!connackReceived && currentTime > lastActiveTimestamp + 30000) { close() - throw Exception("CONNACK not received in 30 seconds") + lastException = Exception("CONNACK not received in 30 seconds") + throw lastException!! } if (keepAlive != 0 && connackReceived) { if (currentTime > lastActiveTimestamp + (keepAlive * 1000)) { // Timeout close() - throw MQTTException(ReasonCode.KEEP_ALIVE_TIMEOUT) + lastException = MQTTException(ReasonCode.KEEP_ALIVE_TIMEOUT) + throw lastException!! } else if (currentTime > lastActiveTimestamp + (keepAlive * 1000 * 0.9)) { val pingreq = if (mqttVersion == 4) { MQTT4Pingreq() diff --git a/kmqtt-common/src/jsMain/kotlin/utils.kt b/kmqtt-common/src/jsMain/kotlin/utils.kt index c6e7aa9..687adf0 100644 --- a/kmqtt-common/src/jsMain/kotlin/utils.kt +++ b/kmqtt-common/src/jsMain/kotlin/utils.kt @@ -2,7 +2,11 @@ import node.buffer.Buffer public fun UByteArray.toBuffer(): Buffer { - return Buffer(this) + val result = Buffer.alloc(this.size) + for (i in indices) { + result.writeUint8(this[i].toInt(), i) + } + return result } public fun Buffer.toUByteArray(): UByteArray {