Skip to content

Commit 1d93b33

Browse files
authored
feat: expose socket connected state (#32)
* feat: expose socket connected state * test: stabilize jvm connection state coverage
1 parent 81b4f9e commit 1d93b33

4 files changed

Lines changed: 130 additions & 2 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
object Consts {
22
const val releaseGroup = "com.piasy"
33
const val releaseName = "kmp-socketio"
4-
const val releaseVersion = "1.4.3"
4+
const val releaseVersion = "1.4.4"
55

66
val androidNS = "$releaseGroup.${releaseName.replace('-', '.')}"
77
}

kmp-socketio/src/commonMain/kotlin/com/piasy/kmp/socketio/socketio/Socket.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ class Socket(
1717
private val auth: Map<String, String>,
1818
private val scope: CoroutineScope,
1919
) : Emitter() {
20-
private var connected = false
20+
/**
21+
* Whether this socket namespace is currently connected.
22+
*/
23+
var connected = false
24+
private set
2125
private val subs = ArrayList<On.Handle>()
2226
private val ack = HashMap<Int, Ack>()
2327
private var ackId = 0

kmp-socketio/src/commonTest/kotlin/com/piasy/kmp/socketio/socketio/ConnectionTest.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,31 @@ abstract class ConnectionTest {
7676
assertEquals(now.toString(), args[3])
7777
}
7878

79+
@Test
80+
fun shouldExposeConnectionState() = doTest {
81+
val isConnectedBeforeOpen = CompletableDeferred<Boolean>()
82+
val isConnectedWhenConnectedEvent = CompletableDeferred<Boolean>()
83+
val isConnectedWhenDisconnectedEvent = CompletableDeferred<Boolean>()
84+
85+
val opt = IO.Options()
86+
opt.transports = listOf(WebSocket.NAME)
87+
client(opt = opt) { socket ->
88+
isConnectedBeforeOpen.complete(socket.connected)
89+
socket.on(Socket.EVENT_CONNECT) {
90+
isConnectedWhenConnectedEvent.complete(socket.connected)
91+
socket.close()
92+
}.on(Socket.EVENT_DISCONNECT) {
93+
isConnectedWhenDisconnectedEvent.complete(socket.connected)
94+
}
95+
96+
socket.open()
97+
}
98+
99+
assertFalse(isConnectedBeforeOpen.await())
100+
assertTrue(isConnectedWhenConnectedEvent.await())
101+
assertFalse(isConnectedWhenDisconnectedEvent.await())
102+
}
103+
79104
@Test
80105
open fun shouldConnectUntrusted() = doTest {
81106
val trustAllCertsHttpClientFactory = DefaultHttpClientFactory(
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package com.piasy.kmp.socketio.socketio
2+
3+
import com.piasy.kmp.socketio.engineio.transports.WebSocket
4+
import com.piasy.kmp.xlog.Logging
5+
import java.io.BufferedReader
6+
import java.io.InputStreamReader
7+
import java.util.concurrent.CountDownLatch
8+
import java.util.concurrent.TimeUnit
9+
import kotlin.test.assertFalse
10+
import kotlin.test.assertTrue
11+
import kotlin.concurrent.thread
12+
import kotlin.test.Test
13+
import kotlin.test.AfterTest
14+
import kotlin.test.BeforeTest
15+
import kotlinx.coroutines.CompletableDeferred
16+
import kotlinx.coroutines.Dispatchers
17+
import kotlinx.coroutines.delay
18+
import kotlinx.coroutines.test.runTest
19+
import kotlinx.coroutines.withContext
20+
import kotlin.time.Duration.Companion.seconds
21+
22+
class ConnectionTestJvm {
23+
private var server: Process? = null
24+
private var serverOutputThread: Thread? = null
25+
private val serverReady = CountDownLatch(1)
26+
27+
@BeforeTest
28+
fun startServer() {
29+
Logging.info(TAG, "startServer")
30+
val process = ProcessBuilder("node", "src/jvmTest/resources/socket-server.js", "/")
31+
.redirectErrorStream(true)
32+
.start()
33+
server = process
34+
serverOutputThread = thread(start = true, isDaemon = true, name = "socket-server-jvm-test-stdout") {
35+
BufferedReader(InputStreamReader(process.inputStream)).use { reader ->
36+
while (true) {
37+
val line = reader.readLine() ?: break
38+
Logging.info(TAG, "SERVER OUT: $line")
39+
if (line.contains("Socket.IO server listening on port 3000")) {
40+
serverReady.countDown()
41+
}
42+
}
43+
}
44+
}
45+
check(serverReady.await(3, TimeUnit.SECONDS)) { "Socket.IO test server did not start in 3s" }
46+
Logging.info(TAG, "startServer finish")
47+
}
48+
49+
@AfterTest
50+
fun stopServer() {
51+
Logging.info(TAG, "stopServer")
52+
serverReady.countDown()
53+
server?.let { process ->
54+
process.destroy()
55+
if (!process.waitFor(3, TimeUnit.SECONDS)) {
56+
process.destroyForcibly()
57+
process.waitFor(3, TimeUnit.SECONDS)
58+
}
59+
}
60+
server = null
61+
62+
serverOutputThread?.join(1000)
63+
serverOutputThread = null
64+
Logging.info(TAG, "stopServer finish")
65+
}
66+
67+
@Test
68+
fun shouldExposeConnectionState() = runTest(timeout = 10.seconds) {
69+
withContext(Dispatchers.Default) {
70+
delay(1000)
71+
}
72+
73+
val isConnectedBeforeOpen = CompletableDeferred<Boolean>()
74+
val isConnectedWhenConnectedEvent = CompletableDeferred<Boolean>()
75+
val isConnectedWhenDisconnectedEvent = CompletableDeferred<Boolean>()
76+
77+
val opt = IO.Options()
78+
opt.transports = listOf(WebSocket.NAME)
79+
IO.socket("http://localhost:3000/", opt) { socket ->
80+
isConnectedBeforeOpen.complete(socket.connected)
81+
socket.on(Socket.EVENT_CONNECT) {
82+
isConnectedWhenConnectedEvent.complete(socket.connected)
83+
socket.close()
84+
}.on(Socket.EVENT_DISCONNECT) {
85+
isConnectedWhenDisconnectedEvent.complete(socket.connected)
86+
}
87+
88+
socket.open()
89+
}
90+
91+
assertFalse(isConnectedBeforeOpen.await())
92+
assertTrue(isConnectedWhenConnectedEvent.await())
93+
assertFalse(isConnectedWhenDisconnectedEvent.await())
94+
}
95+
96+
companion object {
97+
private const val TAG = "ConnectionTestJvm"
98+
}
99+
}

0 commit comments

Comments
 (0)