davidliu

update kotlin versions and tests

@@ -2,8 +2,9 @@ @@ -2,8 +2,9 @@
2 2
3 buildscript { 3 buildscript {
4 ext { 4 ext {
5 - compose_version = '1.0.5'  
6 - kotlin_version = '1.5.31' 5 + compose_version = '1.1.0-rc01'
  6 + compose_compiler_version = '1.1.0-rc02'
  7 + kotlin_version = '1.6.10'
7 java_version = JavaVersion.VERSION_1_8 8 java_version = JavaVersion.VERSION_1_8
8 dokka_version = '1.5.0' 9 dokka_version = '1.5.0'
9 } 10 }
@@ -13,7 +14,7 @@ buildscript { @@ -13,7 +14,7 @@ buildscript {
13 jcenter() 14 jcenter()
14 } 15 }
15 dependencies { 16 dependencies {
16 - classpath 'com.android.tools.build:gradle:7.0.3' 17 + classpath 'com.android.tools.build:gradle:7.0.4'
17 classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 18 classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
18 classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" 19 classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
19 classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version" 20 classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version"
@@ -69,7 +70,7 @@ ext { @@ -69,7 +70,7 @@ ext {
69 'service' : "com.google.auto.service:auto-service:${versions.autoService}", 70 'service' : "com.google.auto.service:auto-service:${versions.autoService}",
70 'serviceAnnotations': "com.google.auto.service:auto-service-annotations:${versions.autoService}", 71 'serviceAnnotations': "com.google.auto.service:auto-service-annotations:${versions.autoService}",
71 ], 72 ],
72 - kotlinx_coroutines: "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2", 73 + kotlinx_coroutines: "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0",
73 timber : "com.github.ajalt:timberkt:1.5.1", 74 timber : "com.github.ajalt:timberkt:1.5.1",
74 // lint 75 // lint
75 lint : "com.android.tools.lint:lint:${versions.lint}", 76 lint : "com.android.tools.lint:lint:${versions.lint}",
1 package io.livekit.android.events 1 package io.livekit.android.events
2 2
3 import kotlinx.coroutines.flow.SharedFlow 3 import kotlinx.coroutines.flow.SharedFlow
4 -import kotlinx.coroutines.flow.collect  
5 4
6 interface EventListenable<out T> { 5 interface EventListenable<out T> {
7 val events: SharedFlow<T> 6 val events: SharedFlow<T>
8 } 7 }
9 8
10 suspend inline fun <T> EventListenable<T>.collect(crossinline action: suspend (value: T) -> Unit) { 9 suspend inline fun <T> EventListenable<T>.collect(crossinline action: suspend (value: T) -> Unit) {
11 - return events.collect(action) 10 + events.collect { value -> action(value) }
12 } 11 }
  1 +package io.livekit.android
  2 +
  3 +import io.livekit.android.coroutines.TestCoroutineRule
  4 +import kotlinx.coroutines.ExperimentalCoroutinesApi
  5 +import kotlinx.coroutines.test.TestScope
  6 +import kotlinx.coroutines.test.runTest
  7 +import org.junit.Rule
  8 +import org.mockito.junit.MockitoJUnit
  9 +
  10 +@ExperimentalCoroutinesApi
  11 +abstract class BaseTest {
  12 +
  13 + @get:Rule
  14 + var mockitoRule = MockitoJUnit.rule()
  15 +
  16 + @get:Rule
  17 + var coroutineRule = TestCoroutineRule()
  18 +
  19 + @ExperimentalCoroutinesApi
  20 + fun runTest(testBody: suspend TestScope.() -> Unit) = coroutineRule.scope.runTest(testBody = testBody)
  21 +}
@@ -2,7 +2,6 @@ package io.livekit.android @@ -2,7 +2,6 @@ package io.livekit.android
2 2
3 import android.content.Context 3 import android.content.Context
4 import androidx.test.core.app.ApplicationProvider 4 import androidx.test.core.app.ApplicationProvider
5 -import io.livekit.android.coroutines.TestCoroutineRule  
6 import io.livekit.android.mock.MockWebSocketFactory 5 import io.livekit.android.mock.MockWebSocketFactory
7 import io.livekit.android.mock.dagger.DaggerTestLiveKitComponent 6 import io.livekit.android.mock.dagger.DaggerTestLiveKitComponent
8 import io.livekit.android.mock.dagger.TestCoroutinesModule 7 import io.livekit.android.mock.dagger.TestCoroutinesModule
@@ -12,22 +11,13 @@ import io.livekit.android.room.SignalClientTest @@ -12,22 +11,13 @@ import io.livekit.android.room.SignalClientTest
12 import io.livekit.android.util.toOkioByteString 11 import io.livekit.android.util.toOkioByteString
13 import kotlinx.coroutines.ExperimentalCoroutinesApi 12 import kotlinx.coroutines.ExperimentalCoroutinesApi
14 import kotlinx.coroutines.launch 13 import kotlinx.coroutines.launch
15 -import kotlinx.coroutines.test.runBlockingTest  
16 import okhttp3.Protocol 14 import okhttp3.Protocol
17 import okhttp3.Request 15 import okhttp3.Request
18 import okhttp3.Response 16 import okhttp3.Response
19 import org.junit.Before 17 import org.junit.Before
20 -import org.junit.Rule  
21 -import org.mockito.junit.MockitoJUnit  
22 18
23 @ExperimentalCoroutinesApi 19 @ExperimentalCoroutinesApi
24 -abstract class MockE2ETest {  
25 -  
26 - @get:Rule  
27 - var mockitoRule = MockitoJUnit.rule()  
28 -  
29 - @get:Rule  
30 - var coroutineRule = TestCoroutineRule() 20 +abstract class MockE2ETest : BaseTest() {
31 21
32 internal lateinit var component: TestLiveKitComponent 22 internal lateinit var component: TestLiveKitComponent
33 lateinit var context: Context 23 lateinit var context: Context
@@ -46,7 +36,7 @@ abstract class MockE2ETest { @@ -46,7 +36,7 @@ abstract class MockE2ETest {
46 wsFactory = component.websocketFactory() 36 wsFactory = component.websocketFactory()
47 } 37 }
48 38
49 - fun connect() { 39 + suspend fun connect() {
50 val job = coroutineRule.scope.launch { 40 val job = coroutineRule.scope.launch {
51 room.connect( 41 room.connect(
52 url = SignalClientTest.EXAMPLE_URL, 42 url = SignalClientTest.EXAMPLE_URL,
@@ -56,11 +46,7 @@ abstract class MockE2ETest { @@ -56,11 +46,7 @@ abstract class MockE2ETest {
56 wsFactory.listener.onOpen(wsFactory.ws, createOpenResponse(wsFactory.request)) 46 wsFactory.listener.onOpen(wsFactory.ws, createOpenResponse(wsFactory.request))
57 wsFactory.listener.onMessage(wsFactory.ws, SignalClientTest.JOIN.toOkioByteString()) 47 wsFactory.listener.onMessage(wsFactory.ws, SignalClientTest.JOIN.toOkioByteString())
58 48
59 - // PeerTransport negotiation is on a debounce delay.  
60 - coroutineRule.dispatcher.advanceTimeBy(1000L)  
61 - runBlockingTest {  
62 - job.join()  
63 - } 49 + job.join()
64 } 50 }
65 51
66 fun createOpenResponse(request: Request): Response { 52 fun createOpenResponse(request: Request): Response {
1 package io.livekit.android.coroutines 1 package io.livekit.android.coroutines
2 2
  3 +import kotlinx.coroutines.Dispatchers
3 import kotlinx.coroutines.ExperimentalCoroutinesApi 4 import kotlinx.coroutines.ExperimentalCoroutinesApi
4 -import kotlinx.coroutines.test.TestCoroutineDispatcher  
5 -import kotlinx.coroutines.test.TestCoroutineScope 5 +import kotlinx.coroutines.test.TestScope
  6 +import kotlinx.coroutines.test.UnconfinedTestDispatcher
  7 +import kotlinx.coroutines.test.resetMain
  8 +import kotlinx.coroutines.test.setMain
  9 +import org.junit.Assert
6 import org.junit.rules.TestRule 10 import org.junit.rules.TestRule
7 import org.junit.runner.Description 11 import org.junit.runner.Description
8 import org.junit.runners.model.Statement 12 import org.junit.runners.model.Statement
9 13
10 @OptIn(ExperimentalCoroutinesApi::class) 14 @OptIn(ExperimentalCoroutinesApi::class)
11 class TestCoroutineRule : TestRule { 15 class TestCoroutineRule : TestRule {
12 - val dispatcher = TestCoroutineDispatcher()  
13 - val scope = TestCoroutineScope(dispatcher) 16 + val dispatcher = UnconfinedTestDispatcher()
  17 + val scope = TestScope(dispatcher)
14 18
15 override fun apply(base: Statement, description: Description?) = object : Statement() { 19 override fun apply(base: Statement, description: Description?) = object : Statement() {
16 @Throws(Throwable::class) 20 @Throws(Throwable::class)
17 override fun evaluate() { 21 override fun evaluate() {
  22 + Dispatchers.setMain(dispatcher)
18 base.evaluate() 23 base.evaluate()
19 - scope.cleanupTestCoroutines() 24 + val timeAfterTest = dispatcher.scheduler.currentTime
  25 + dispatcher.scheduler.advanceUntilIdle() // run the remaining tasks
  26 + Assert.assertEquals(
  27 + timeAfterTest,
  28 + dispatcher.scheduler.currentTime
  29 + ) // will fail if there were tasks scheduled at a later moment
  30 + Dispatchers.resetMain()
20 } 31 }
21 } 32 }
22 } 33 }
@@ -6,7 +6,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -6,7 +6,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
6 import kotlinx.coroutines.async 6 import kotlinx.coroutines.async
7 import kotlinx.coroutines.flow.Flow 7 import kotlinx.coroutines.flow.Flow
8 import kotlinx.coroutines.flow.MutableStateFlow 8 import kotlinx.coroutines.flow.MutableStateFlow
9 -import kotlinx.coroutines.test.runBlockingTest  
10 9
11 open class FlowCollector<T>( 10 open class FlowCollector<T>(
12 private val flow: Flow<T>, 11 private val flow: Flow<T>,
@@ -21,13 +20,9 @@ open class FlowCollector<T>( @@ -21,13 +20,9 @@ open class FlowCollector<T>(
21 * Stop collecting events. returns the events collected. 20 * Stop collecting events. returns the events collected.
22 */ 21 */
23 @OptIn(ExperimentalCoroutinesApi::class) 22 @OptIn(ExperimentalCoroutinesApi::class)
24 - fun stopCollecting(): List<T> { 23 + suspend fun stopCollecting(): List<T> {
25 signal.compareAndSet(null, Unit) 24 signal.compareAndSet(null, Unit)
26 - var events: List<T> = emptyList()  
27 - runBlockingTest {  
28 - events = collectEventsDeferred.await()  
29 - }  
30 - return events 25 + return collectEventsDeferred.await()
31 } 26 }
32 27
33 } 28 }
@@ -6,7 +6,7 @@ import io.livekit.android.mock.MockWebSocket @@ -6,7 +6,7 @@ import io.livekit.android.mock.MockWebSocket
6 import io.livekit.android.util.LoggingRule 6 import io.livekit.android.util.LoggingRule
7 import io.livekit.android.util.toPBByteString 7 import io.livekit.android.util.toPBByteString
8 import kotlinx.coroutines.ExperimentalCoroutinesApi 8 import kotlinx.coroutines.ExperimentalCoroutinesApi
9 -import kotlinx.coroutines.test.runBlockingTest 9 +import kotlinx.coroutines.test.runTest
10 import livekit.LivekitRtc 10 import livekit.LivekitRtc
11 import org.junit.Assert 11 import org.junit.Assert
12 import org.junit.Before 12 import org.junit.Before
@@ -34,7 +34,7 @@ class RTCEngineMockE2ETest : MockE2ETest() { @@ -34,7 +34,7 @@ class RTCEngineMockE2ETest : MockE2ETest() {
34 } 34 }
35 35
36 @Test 36 @Test
37 - fun iceSubscriberConnect() = runBlockingTest { 37 + fun iceSubscriberConnect() = runTest {
38 connect() 38 connect()
39 39
40 val remoteOffer = SessionDescription(SessionDescription.Type.OFFER, "remote_offer") 40 val remoteOffer = SessionDescription(SessionDescription.Type.OFFER, "remote_offer")
@@ -59,7 +59,7 @@ class RTCEngineMockE2ETest : MockE2ETest() { @@ -59,7 +59,7 @@ class RTCEngineMockE2ETest : MockE2ETest() {
59 } 59 }
60 60
61 @Test 61 @Test
62 - fun reconnectOnFailure() = runBlockingTest { 62 + fun reconnectOnFailure() = runTest {
63 connect() 63 connect()
64 val oldWs = wsFactory.ws 64 val oldWs = wsFactory.ws
65 wsFactory.listener.onFailure(oldWs, Exception(), null) 65 wsFactory.listener.onFailure(oldWs, Exception(), null)
@@ -13,7 +13,6 @@ import io.livekit.android.room.track.Track @@ -13,7 +13,6 @@ import io.livekit.android.room.track.Track
13 import io.livekit.android.util.toOkioByteString 13 import io.livekit.android.util.toOkioByteString
14 import kotlinx.coroutines.ExperimentalCoroutinesApi 14 import kotlinx.coroutines.ExperimentalCoroutinesApi
15 import kotlinx.coroutines.launch 15 import kotlinx.coroutines.launch
16 -import kotlinx.coroutines.test.runBlockingTest  
17 import org.junit.Assert 16 import org.junit.Assert
18 import org.junit.Test 17 import org.junit.Test
19 import org.junit.runner.RunWith 18 import org.junit.runner.RunWith
@@ -25,12 +24,12 @@ import org.robolectric.RobolectricTestRunner @@ -25,12 +24,12 @@ import org.robolectric.RobolectricTestRunner
25 class RoomMockE2ETest : MockE2ETest() { 24 class RoomMockE2ETest : MockE2ETest() {
26 25
27 @Test 26 @Test
28 - fun connectTest() { 27 + fun connectTest() = runTest {
29 connect() 28 connect()
30 } 29 }
31 30
32 @Test 31 @Test
33 - fun connectFailureProperlyContinues() { 32 + fun connectFailureProperlyContinues() = runTest {
34 33
35 var didThrowException = false 34 var didThrowException = false
36 val job = coroutineRule.scope.launch { 35 val job = coroutineRule.scope.launch {
@@ -46,15 +45,13 @@ class RoomMockE2ETest : MockE2ETest() { @@ -46,15 +45,13 @@ class RoomMockE2ETest : MockE2ETest() {
46 45
47 wsFactory.listener.onFailure(wsFactory.ws, Exception(), null) 46 wsFactory.listener.onFailure(wsFactory.ws, Exception(), null)
48 47
49 - runBlockingTest {  
50 - job.join()  
51 - } 48 + job.join()
52 49
53 Assert.assertTrue(didThrowException) 50 Assert.assertTrue(didThrowException)
54 } 51 }
55 52
56 @Test 53 @Test
57 - fun roomUpdateTest() { 54 + fun roomUpdateTest() = runTest {
58 connect() 55 connect()
59 val eventCollector = EventCollector(room.events, coroutineRule.scope) 56 val eventCollector = EventCollector(room.events, coroutineRule.scope)
60 wsFactory.listener.onMessage(wsFactory.ws, SignalClientTest.ROOM_UPDATE.toOkioByteString()) 57 wsFactory.listener.onMessage(wsFactory.ws, SignalClientTest.ROOM_UPDATE.toOkioByteString())
@@ -69,7 +66,7 @@ class RoomMockE2ETest : MockE2ETest() { @@ -69,7 +66,7 @@ class RoomMockE2ETest : MockE2ETest() {
69 } 66 }
70 67
71 @Test 68 @Test
72 - fun connectionQualityUpdateTest() { 69 + fun connectionQualityUpdateTest() = runTest {
73 connect() 70 connect()
74 val eventCollector = EventCollector(room.events, coroutineRule.scope) 71 val eventCollector = EventCollector(room.events, coroutineRule.scope)
75 wsFactory.listener.onMessage( 72 wsFactory.listener.onMessage(
@@ -84,7 +81,7 @@ class RoomMockE2ETest : MockE2ETest() { @@ -84,7 +81,7 @@ class RoomMockE2ETest : MockE2ETest() {
84 } 81 }
85 82
86 @Test 83 @Test
87 - fun participantConnected() { 84 + fun participantConnected() = runTest {
88 connect() 85 connect()
89 86
90 val eventCollector = EventCollector(room.events, coroutineRule.scope) 87 val eventCollector = EventCollector(room.events, coroutineRule.scope)
@@ -99,7 +96,7 @@ class RoomMockE2ETest : MockE2ETest() { @@ -99,7 +96,7 @@ class RoomMockE2ETest : MockE2ETest() {
99 } 96 }
100 97
101 @Test 98 @Test
102 - fun participantDisconnected() { 99 + fun participantDisconnected() = runTest {
103 connect() 100 connect()
104 wsFactory.listener.onMessage( 101 wsFactory.listener.onMessage(
105 wsFactory.ws, 102 wsFactory.ws,
@@ -118,7 +115,7 @@ class RoomMockE2ETest : MockE2ETest() { @@ -118,7 +115,7 @@ class RoomMockE2ETest : MockE2ETest() {
118 } 115 }
119 116
120 @Test 117 @Test
121 - fun onActiveSpeakersChanged() { 118 + fun onActiveSpeakersChanged() = runTest {
122 connect() 119 connect()
123 120
124 val eventCollector = EventCollector(room.events, coroutineRule.scope) 121 val eventCollector = EventCollector(room.events, coroutineRule.scope)
@@ -133,7 +130,7 @@ class RoomMockE2ETest : MockE2ETest() { @@ -133,7 +130,7 @@ class RoomMockE2ETest : MockE2ETest() {
133 } 130 }
134 131
135 @Test 132 @Test
136 - fun participantMetadataChanged() { 133 + fun participantMetadataChanged() = runTest {
137 connect() 134 connect()
138 135
139 wsFactory.listener.onMessage( 136 wsFactory.listener.onMessage(
@@ -153,7 +150,7 @@ class RoomMockE2ETest : MockE2ETest() { @@ -153,7 +150,7 @@ class RoomMockE2ETest : MockE2ETest() {
153 } 150 }
154 151
155 @Test 152 @Test
156 - fun trackStreamStateChanged() { 153 + fun trackStreamStateChanged() = runTest {
157 connect() 154 connect()
158 155
159 wsFactory.listener.onMessage( 156 wsFactory.listener.onMessage(
@@ -189,7 +186,7 @@ class RoomMockE2ETest : MockE2ETest() { @@ -189,7 +186,7 @@ class RoomMockE2ETest : MockE2ETest() {
189 } 186 }
190 187
191 @Test 188 @Test
192 - fun trackSubscriptionPermissionChanged() { 189 + fun trackSubscriptionPermissionChanged() = runTest {
193 connect() 190 connect()
194 191
195 wsFactory.listener.onMessage( 192 wsFactory.listener.onMessage(
@@ -224,7 +221,7 @@ class RoomMockE2ETest : MockE2ETest() { @@ -224,7 +221,7 @@ class RoomMockE2ETest : MockE2ETest() {
224 } 221 }
225 222
226 @Test 223 @Test
227 - fun onConnectionAvailableWillReconnect() { 224 + fun onConnectionAvailableWillReconnect() = runTest {
228 connect() 225 connect()
229 val eventCollector = EventCollector(room.events, coroutineRule.scope) 226 val eventCollector = EventCollector(room.events, coroutineRule.scope)
230 val network = Mockito.mock(Network::class.java) 227 val network = Mockito.mock(Network::class.java)
@@ -237,7 +234,7 @@ class RoomMockE2ETest : MockE2ETest() { @@ -237,7 +234,7 @@ class RoomMockE2ETest : MockE2ETest() {
237 } 234 }
238 235
239 @Test 236 @Test
240 - fun leave() { 237 + fun leave() = runTest {
241 connect() 238 connect()
242 val eventCollector = EventCollector(room.events, coroutineRule.scope) 239 val eventCollector = EventCollector(room.events, coroutineRule.scope)
243 wsFactory.listener.onMessage( 240 wsFactory.listener.onMessage(
@@ -8,8 +8,8 @@ import io.livekit.android.events.EventCollector @@ -8,8 +8,8 @@ import io.livekit.android.events.EventCollector
8 import io.livekit.android.events.RoomEvent 8 import io.livekit.android.events.RoomEvent
9 import io.livekit.android.mock.MockEglBase 9 import io.livekit.android.mock.MockEglBase
10 import io.livekit.android.room.participant.LocalParticipant 10 import io.livekit.android.room.participant.LocalParticipant
11 -import kotlinx.coroutines.*  
12 -import kotlinx.coroutines.test.runBlockingTest 11 +import kotlinx.coroutines.ExperimentalCoroutinesApi
  12 +import kotlinx.coroutines.test.runTest
13 import livekit.LivekitModels 13 import livekit.LivekitModels
14 import org.junit.Assert 14 import org.junit.Assert
15 import org.junit.Before 15 import org.junit.Before
@@ -32,6 +32,7 @@ class RoomTest { @@ -32,6 +32,7 @@ class RoomTest {
32 32
33 @get:Rule 33 @get:Rule
34 var mockitoRule = MockitoJUnit.rule() 34 var mockitoRule = MockitoJUnit.rule()
  35 +
35 @get:Rule 36 @get:Rule
36 var coroutineRule = TestCoroutineRule() 37 var coroutineRule = TestCoroutineRule()
37 38
@@ -64,7 +65,7 @@ class RoomTest { @@ -64,7 +65,7 @@ class RoomTest {
64 ) 65 )
65 } 66 }
66 67
67 - fun connect() { 68 + suspend fun connect() {
68 rtcEngine.stub { 69 rtcEngine.stub {
69 onBlocking { rtcEngine.join(any(), any(), anyOrNull()) } 70 onBlocking { rtcEngine.join(any(), any(), anyOrNull()) }
70 .doReturn(SignalClientTest.JOIN.join) 71 .doReturn(SignalClientTest.JOIN.join)
@@ -73,24 +74,20 @@ class RoomTest { @@ -73,24 +74,20 @@ class RoomTest {
73 onBlocking { rtcEngine.client } 74 onBlocking { rtcEngine.client }
74 .doReturn(Mockito.mock(SignalClient::class.java)) 75 .doReturn(Mockito.mock(SignalClient::class.java))
75 } 76 }
76 - val job = coroutineRule.scope.launch {  
77 - room.connect(  
78 - url = SignalClientTest.EXAMPLE_URL,  
79 - token = "",  
80 - )  
81 - }  
82 - runBlockingTest {  
83 - job.join()  
84 - } 77 +
  78 + room.connect(
  79 + url = SignalClientTest.EXAMPLE_URL,
  80 + token = "",
  81 + )
85 } 82 }
86 83
87 @Test 84 @Test
88 - fun connectTest() { 85 + fun connectTest() = runTest {
89 connect() 86 connect()
90 } 87 }
91 88
92 @Test 89 @Test
93 - fun onConnectionAvailableWillReconnect() { 90 + fun onConnectionAvailableWillReconnect() = runTest {
94 connect() 91 connect()
95 92
96 val network = Mockito.mock(Network::class.java) 93 val network = Mockito.mock(Network::class.java)
@@ -100,7 +97,7 @@ class RoomTest { @@ -100,7 +97,7 @@ class RoomTest {
100 } 97 }
101 98
102 @Test 99 @Test
103 - fun onDisconnect() { 100 + fun onDisconnect() = runTest {
104 connect() 101 connect()
105 102
106 val eventCollector = EventCollector(room.events, coroutineRule.scope) 103 val eventCollector = EventCollector(room.events, coroutineRule.scope)
1 package io.livekit.android.room 1 package io.livekit.android.room
2 2
3 import com.google.protobuf.util.JsonFormat 3 import com.google.protobuf.util.JsonFormat
  4 +import io.livekit.android.BaseTest
4 import io.livekit.android.mock.MockWebSocketFactory 5 import io.livekit.android.mock.MockWebSocketFactory
5 import io.livekit.android.mock.TestData 6 import io.livekit.android.mock.TestData
6 import io.livekit.android.util.toOkioByteString 7 import io.livekit.android.util.toOkioByteString
7 import kotlinx.coroutines.ExperimentalCoroutinesApi 8 import kotlinx.coroutines.ExperimentalCoroutinesApi
8 import kotlinx.coroutines.async 9 import kotlinx.coroutines.async
9 -import kotlinx.coroutines.test.TestCoroutineDispatcher  
10 -import kotlinx.coroutines.test.TestCoroutineScope  
11 -import kotlinx.coroutines.test.runBlockingTest  
12 import kotlinx.serialization.json.Json 10 import kotlinx.serialization.json.Json
13 import livekit.LivekitModels 11 import livekit.LivekitModels
14 import livekit.LivekitRtc 12 import livekit.LivekitRtc
15 import okhttp3.* 13 import okhttp3.*
16 -import org.junit.After  
17 import org.junit.Assert 14 import org.junit.Assert
18 import org.junit.Before 15 import org.junit.Before
19 import org.junit.Test 16 import org.junit.Test
  17 +import org.mockito.Mock
20 import org.mockito.Mockito 18 import org.mockito.Mockito
21 import org.mockito.kotlin.any 19 import org.mockito.kotlin.any
22 import org.mockito.kotlin.argThat 20 import org.mockito.kotlin.argThat
23 import org.webrtc.SessionDescription 21 import org.webrtc.SessionDescription
24 22
25 @ExperimentalCoroutinesApi 23 @ExperimentalCoroutinesApi
26 -class SignalClientTest { 24 +class SignalClientTest : BaseTest() {
27 25
28 lateinit var wsFactory: MockWebSocketFactory 26 lateinit var wsFactory: MockWebSocketFactory
29 lateinit var client: SignalClient 27 lateinit var client: SignalClient
  28 +
  29 + @Mock
30 lateinit var listener: SignalClient.Listener 30 lateinit var listener: SignalClient.Listener
31 - lateinit var okHttpClient: OkHttpClient  
32 31
33 - lateinit var coroutineDispatcher: TestCoroutineDispatcher  
34 - lateinit var coroutineScope: TestCoroutineScope 32 + @Mock
  33 + lateinit var okHttpClient: OkHttpClient
35 34
36 @Before 35 @Before
37 fun setup() { 36 fun setup() {
38 - coroutineDispatcher = TestCoroutineDispatcher()  
39 - coroutineScope = TestCoroutineScope(coroutineDispatcher)  
40 wsFactory = MockWebSocketFactory() 37 wsFactory = MockWebSocketFactory()
41 - okHttpClient = Mockito.mock(OkHttpClient::class.java)  
42 client = SignalClient( 38 client = SignalClient(
43 wsFactory, 39 wsFactory,
44 JsonFormat.parser(), 40 JsonFormat.parser(),
@@ -46,17 +42,11 @@ class SignalClientTest { @@ -46,17 +42,11 @@ class SignalClientTest {
46 Json, 42 Json,
47 useJson = false, 43 useJson = false,
48 okHttpClient = okHttpClient, 44 okHttpClient = okHttpClient,
49 - ioDispatcher = coroutineDispatcher 45 + ioDispatcher = coroutineRule.dispatcher
50 ) 46 )
51 - listener = Mockito.mock(SignalClient.Listener::class.java)  
52 client.listener = listener 47 client.listener = listener
53 } 48 }
54 49
55 - @After  
56 - fun tearDown() {  
57 - coroutineScope.cleanupTestCoroutines()  
58 - }  
59 -  
60 private fun createOpenResponse(request: Request): Response { 50 private fun createOpenResponse(request: Request): Response {
61 return Response.Builder() 51 return Response.Builder()
62 .request(request) 52 .request(request)
@@ -75,36 +65,35 @@ class SignalClientTest { @@ -75,36 +65,35 @@ class SignalClientTest {
75 } 65 }
76 66
77 @Test 67 @Test
78 - fun joinAndResponse() {  
79 - val job = coroutineScope.async { 68 + fun joinAndResponse() = runTest {
  69 + println("dispatcher = ${this.coroutineContext}")
  70 + val job = async {
80 client.join(EXAMPLE_URL, "") 71 client.join(EXAMPLE_URL, "")
81 } 72 }
82 73
83 connectWebsocketAndJoin() 74 connectWebsocketAndJoin()
84 75
85 - runBlockingTest {  
86 - val response = job.await()  
87 - Assert.assertEquals(response, JOIN.join)  
88 - } 76 + val response = job.await()
  77 + Assert.assertEquals(true, client.isConnected)
  78 + Assert.assertEquals(response, JOIN.join)
89 } 79 }
90 80
91 @Test 81 @Test
92 - fun reconnect() {  
93 - val job = coroutineScope.async { 82 + fun reconnect() = runTest {
  83 + val job = async {
94 client.reconnect(EXAMPLE_URL, "") 84 client.reconnect(EXAMPLE_URL, "")
95 } 85 }
96 86
97 client.onOpen(wsFactory.ws, createOpenResponse(wsFactory.request)) 87 client.onOpen(wsFactory.ws, createOpenResponse(wsFactory.request))
98 88
99 - runBlockingTest {  
100 - job.await()  
101 - } 89 + job.await()
  90 + Assert.assertEquals(true, client.isConnected)
102 } 91 }
103 92
104 @Test 93 @Test
105 - fun joinFailure() { 94 + fun joinFailure() = runTest {
106 var failed = false 95 var failed = false
107 - val job = coroutineScope.async { 96 + val job = async {
108 try { 97 try {
109 client.join(EXAMPLE_URL, "") 98 client.join(EXAMPLE_URL, "")
110 } catch (e: Exception) { 99 } catch (e: Exception) {
@@ -113,34 +102,34 @@ class SignalClientTest { @@ -113,34 +102,34 @@ class SignalClientTest {
113 } 102 }
114 103
115 client.onFailure(wsFactory.ws, Exception(), null) 104 client.onFailure(wsFactory.ws, Exception(), null)
116 - runBlockingTest { job.await() } 105 + job.await()
117 106
118 Assert.assertTrue(failed) 107 Assert.assertTrue(failed)
119 } 108 }
120 109
121 @Test 110 @Test
122 - fun listenerNotCalledUntilOnReady() {  
123 - val job = coroutineScope.async { 111 + fun listenerNotCalledUntilOnReady() = runTest {
  112 + val job = async {
124 client.join(EXAMPLE_URL, "") 113 client.join(EXAMPLE_URL, "")
125 } 114 }
126 115
127 connectWebsocketAndJoin() 116 connectWebsocketAndJoin()
128 client.onMessage(wsFactory.ws, OFFER.toOkioByteString()) 117 client.onMessage(wsFactory.ws, OFFER.toOkioByteString())
129 118
130 - runBlockingTest { job.await() } 119 + job.await()
131 120
132 Mockito.verifyNoInteractions(listener) 121 Mockito.verifyNoInteractions(listener)
133 } 122 }
134 123
135 @Test 124 @Test
136 - fun listenerCalledAfterOnReady() {  
137 - val job = coroutineScope.async { 125 + fun listenerCalledAfterOnReady() = runTest {
  126 + val job = async {
138 client.join(EXAMPLE_URL, "") 127 client.join(EXAMPLE_URL, "")
139 } 128 }
140 connectWebsocketAndJoin() 129 connectWebsocketAndJoin()
141 client.onMessage(wsFactory.ws, OFFER.toOkioByteString()) 130 client.onMessage(wsFactory.ws, OFFER.toOkioByteString())
142 131
143 - runBlockingTest { job.await() } 132 + job.await()
144 client.onReady() 133 client.onReady()
145 Mockito.verify(listener) 134 Mockito.verify(listener)
146 .onOffer(argThat { type == SessionDescription.Type.OFFER && description == OFFER.offer.sdp }) 135 .onOffer(argThat { type == SessionDescription.Type.OFFER && description == OFFER.offer.sdp })
@@ -151,12 +140,12 @@ class SignalClientTest { @@ -151,12 +140,12 @@ class SignalClientTest {
151 * [WebSocketListener.onClosed]. Ensure that listener is called properly. 140 * [WebSocketListener.onClosed]. Ensure that listener is called properly.
152 */ 141 */
153 @Test 142 @Test
154 - fun listenerNotifiedAfterFailure() {  
155 - val job = coroutineScope.async { 143 + fun listenerNotifiedAfterFailure() = runTest {
  144 + val job = async {
156 client.join(EXAMPLE_URL, "") 145 client.join(EXAMPLE_URL, "")
157 } 146 }
158 connectWebsocketAndJoin() 147 connectWebsocketAndJoin()
159 - runBlockingTest { job.await() } 148 + job.await()
160 149
161 client.onFailure(wsFactory.ws, Exception(), null) 150 client.onFailure(wsFactory.ws, Exception(), null)
162 151
@@ -4,6 +4,8 @@ import io.livekit.android.coroutines.TestCoroutineRule @@ -4,6 +4,8 @@ import io.livekit.android.coroutines.TestCoroutineRule
4 import io.livekit.android.events.EventCollector 4 import io.livekit.android.events.EventCollector
5 import io.livekit.android.events.ParticipantEvent 5 import io.livekit.android.events.ParticipantEvent
6 import io.livekit.android.room.track.TrackPublication 6 import io.livekit.android.room.track.TrackPublication
  7 +import kotlinx.coroutines.ExperimentalCoroutinesApi
  8 +import kotlinx.coroutines.test.runTest
7 import livekit.LivekitModels 9 import livekit.LivekitModels
8 import org.junit.Assert.assertEquals 10 import org.junit.Assert.assertEquals
9 import org.junit.Assert.assertTrue 11 import org.junit.Assert.assertTrue
@@ -11,6 +13,7 @@ import org.junit.Before @@ -11,6 +13,7 @@ import org.junit.Before
11 import org.junit.Rule 13 import org.junit.Rule
12 import org.junit.Test 14 import org.junit.Test
13 15
  16 +@ExperimentalCoroutinesApi
14 class ParticipantTest { 17 class ParticipantTest {
15 18
16 @get:Rule 19 @get:Rule
@@ -24,7 +27,7 @@ class ParticipantTest { @@ -24,7 +27,7 @@ class ParticipantTest {
24 } 27 }
25 28
26 @Test 29 @Test
27 - fun updateFromInfo() { 30 + fun updateFromInfo() = runTest {
28 participant.updateFromInfo(INFO) 31 participant.updateFromInfo(INFO)
29 32
30 assertTrue(participant.hasInfo) 33 assertTrue(participant.hasInfo)
@@ -36,7 +39,7 @@ class ParticipantTest { @@ -36,7 +39,7 @@ class ParticipantTest {
36 } 39 }
37 40
38 @Test 41 @Test
39 - fun setMetadataCallsListeners() { 42 + fun setMetadataCallsListeners() = runTest {
40 class MetadataListener : ParticipantListener { 43 class MetadataListener : ParticipantListener {
41 var wasCalled = false 44 var wasCalled = false
42 lateinit var participantValue: Participant 45 lateinit var participantValue: Participant
@@ -69,7 +72,7 @@ class ParticipantTest { @@ -69,7 +72,7 @@ class ParticipantTest {
69 } 72 }
70 73
71 @Test 74 @Test
72 - fun setMetadataChangedEvent() { 75 + fun setMetadataChangedEvent() = runTest {
73 val eventCollector = EventCollector(participant.events, coroutineRule.scope) 76 val eventCollector = EventCollector(participant.events, coroutineRule.scope)
74 val prevMetadata = participant.metadata 77 val prevMetadata = participant.metadata
75 val metadata = "metadata" 78 val metadata = "metadata"
@@ -87,7 +90,7 @@ class ParticipantTest { @@ -87,7 +90,7 @@ class ParticipantTest {
87 } 90 }
88 91
89 @Test 92 @Test
90 - fun setIsSpeakingChangedEvent() { 93 + fun setIsSpeakingChangedEvent() = runTest {
91 val eventCollector = EventCollector(participant.events, coroutineRule.scope) 94 val eventCollector = EventCollector(participant.events, coroutineRule.scope)
92 val newIsSpeaking = !participant.isSpeaking 95 val newIsSpeaking = !participant.isSpeaking
93 participant.isSpeaking = newIsSpeaking 96 participant.isSpeaking = newIsSpeaking
@@ -104,7 +107,7 @@ class ParticipantTest { @@ -104,7 +107,7 @@ class ParticipantTest {
104 } 107 }
105 108
106 @Test 109 @Test
107 - fun addTrackPublication() { 110 + fun addTrackPublication() = runTest {
108 val audioPublication = TrackPublication(TRACK_INFO, null, participant) 111 val audioPublication = TrackPublication(TRACK_INFO, null, participant)
109 participant.addTrackPublication(audioPublication) 112 participant.addTrackPublication(audioPublication)
110 113
@@ -38,8 +38,7 @@ android { @@ -38,8 +38,7 @@ android {
38 compose true 38 compose true
39 } 39 }
40 composeOptions { 40 composeOptions {
41 - kotlinCompilerExtensionVersion compose_version  
42 - kotlinCompilerVersion kotlin_version 41 + kotlinCompilerExtensionVersion compose_compiler_version
43 } 42 }
44 packagingOptions { 43 packagingOptions {
45 resources { 44 resources {