Committed by
GitHub
Fix reconnected event not firing on full reconnect (#158)
* Fix reconnect events on full reconnect * parameterized tests
正在显示
5 个修改的文件
包含
135 行增加
和
73 行删除
| @@ -139,7 +139,7 @@ dependencies { | @@ -139,7 +139,7 @@ dependencies { | ||
| 139 | testImplementation "org.mockito.kotlin:mockito-kotlin:4.0.0" | 139 | testImplementation "org.mockito.kotlin:mockito-kotlin:4.0.0" |
| 140 | testImplementation 'androidx.test:core:1.4.0' | 140 | testImplementation 'androidx.test:core:1.4.0' |
| 141 | testImplementation deps.coroutines.test | 141 | testImplementation deps.coroutines.test |
| 142 | - kaptTest 'com.google.dagger:dagger-compiler:2.38' | 142 | + kaptTest "com.google.dagger:dagger-compiler:${versions.dagger}" |
| 143 | androidTestImplementation 'androidx.test.ext:junit:1.1.3' | 143 | androidTestImplementation 'androidx.test.ext:junit:1.1.3' |
| 144 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' | 144 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' |
| 145 | } | 145 | } |
| @@ -324,10 +324,12 @@ internal constructor( | @@ -324,10 +324,12 @@ internal constructor( | ||
| 324 | reconnectingJob = null | 324 | reconnectingJob = null |
| 325 | coroutineScope.close() | 325 | coroutineScope.close() |
| 326 | closeResources(reason) | 326 | closeResources(reason) |
| 327 | + connectionState = ConnectionState.DISCONNECTED | ||
| 327 | } | 328 | } |
| 328 | 329 | ||
| 329 | private fun closeResources(reason: String) { | 330 | private fun closeResources(reason: String) { |
| 330 | - connectionState = ConnectionState.DISCONNECTED | 331 | + publisherObserver.connectionChangeListener = null |
| 332 | + subscriberObserver.connectionChangeListener = null | ||
| 331 | _publisher?.close() | 333 | _publisher?.close() |
| 332 | _publisher = null | 334 | _publisher = null |
| 333 | _subscriber?.close() | 335 | _subscriber?.close() |
| @@ -32,7 +32,7 @@ abstract class MockE2ETest : BaseTest() { | @@ -32,7 +32,7 @@ abstract class MockE2ETest : BaseTest() { | ||
| 32 | internal lateinit var subscriber: PeerConnectionTransport | 32 | internal lateinit var subscriber: PeerConnectionTransport |
| 33 | 33 | ||
| 34 | @Before | 34 | @Before |
| 35 | - fun setup() { | 35 | + fun mocksSetup() { |
| 36 | context = ApplicationProvider.getApplicationContext() | 36 | context = ApplicationProvider.getApplicationContext() |
| 37 | component = DaggerTestLiveKitComponent | 37 | component = DaggerTestLiveKitComponent |
| 38 | .factory() | 38 | .factory() |
| @@ -18,88 +18,30 @@ import org.junit.Test | @@ -18,88 +18,30 @@ import org.junit.Test | ||
| 18 | import org.junit.runner.RunWith | 18 | import org.junit.runner.RunWith |
| 19 | import org.robolectric.RobolectricTestRunner | 19 | import org.robolectric.RobolectricTestRunner |
| 20 | 20 | ||
| 21 | +/** | ||
| 22 | + * For tests that only target one reconnection type. | ||
| 23 | + * | ||
| 24 | + * Tests that cover all connection types should be put in [RoomReconnectionTypesMockE2ETest]. | ||
| 25 | + */ | ||
| 21 | @ExperimentalCoroutinesApi | 26 | @ExperimentalCoroutinesApi |
| 22 | @RunWith(RobolectricTestRunner::class) | 27 | @RunWith(RobolectricTestRunner::class) |
| 23 | class RoomReconnectionMockE2ETest : MockE2ETest() { | 28 | class RoomReconnectionMockE2ETest : MockE2ETest() { |
| 24 | 29 | ||
| 25 | - private fun prepareForReconnect(softReconnect: Boolean = false) { | 30 | + private fun prepareForReconnect() { |
| 26 | wsFactory.onOpen = { | 31 | wsFactory.onOpen = { |
| 27 | wsFactory.listener.onOpen(wsFactory.ws, createOpenResponse(wsFactory.request)) | 32 | wsFactory.listener.onOpen(wsFactory.ws, createOpenResponse(wsFactory.request)) |
| 28 | - if (!softReconnect) { | 33 | + val softReconnectParam = wsFactory.request.url |
| 34 | + .queryParameter(SignalClient.CONNECT_QUERY_RECONNECT) | ||
| 35 | + ?.toIntOrNull() | ||
| 36 | + ?: 0 | ||
| 37 | + | ||
| 38 | + if (softReconnectParam == 0) { | ||
| 29 | simulateMessageFromServer(SignalClientTest.JOIN) | 39 | simulateMessageFromServer(SignalClientTest.JOIN) |
| 30 | } | 40 | } |
| 31 | } | 41 | } |
| 32 | } | 42 | } |
| 33 | 43 | ||
| 34 | @Test | 44 | @Test |
| 35 | - fun reconnectFromPeerConnectionDisconnect() = runTest { | ||
| 36 | - connect() | ||
| 37 | - | ||
| 38 | - val eventCollector = EventCollector(room.events, coroutineRule.scope) | ||
| 39 | - val stateCollector = FlowCollector(room::state.flow, coroutineRule.scope) | ||
| 40 | - prepareForReconnect() | ||
| 41 | - disconnectPeerConnection() | ||
| 42 | - // Wait so that the reconnect job properly starts first. | ||
| 43 | - testScheduler.advanceTimeBy(1000) | ||
| 44 | - connectPeerConnection() | ||
| 45 | - | ||
| 46 | - testScheduler.advanceUntilIdle() | ||
| 47 | - val events = eventCollector.stopCollecting() | ||
| 48 | - val states = stateCollector.stopCollecting() | ||
| 49 | - | ||
| 50 | - assertIsClassList( | ||
| 51 | - listOf( | ||
| 52 | - RoomEvent.Reconnecting::class.java, | ||
| 53 | - RoomEvent.Reconnected::class.java, | ||
| 54 | - ), | ||
| 55 | - events | ||
| 56 | - ) | ||
| 57 | - | ||
| 58 | - assertEquals( | ||
| 59 | - listOf( | ||
| 60 | - Room.State.CONNECTED, | ||
| 61 | - Room.State.RECONNECTING, | ||
| 62 | - Room.State.CONNECTED, | ||
| 63 | - ), | ||
| 64 | - states | ||
| 65 | - ) | ||
| 66 | - } | ||
| 67 | - | ||
| 68 | - @Test | ||
| 69 | - fun reconnectFromWebSocketFailure() = runTest { | ||
| 70 | - connect() | ||
| 71 | - | ||
| 72 | - val eventCollector = EventCollector(room.events, coroutineRule.scope) | ||
| 73 | - val stateCollector = FlowCollector(room::state.flow, coroutineRule.scope) | ||
| 74 | - prepareForReconnect() | ||
| 75 | - wsFactory.ws.cancel() | ||
| 76 | - // Wait so that the reconnect job properly starts first. | ||
| 77 | - testScheduler.advanceTimeBy(1000) | ||
| 78 | - connectPeerConnection() | ||
| 79 | - | ||
| 80 | - testScheduler.advanceUntilIdle() | ||
| 81 | - val events = eventCollector.stopCollecting() | ||
| 82 | - val states = stateCollector.stopCollecting() | ||
| 83 | - | ||
| 84 | - assertIsClassList( | ||
| 85 | - listOf( | ||
| 86 | - RoomEvent.Reconnecting::class.java, | ||
| 87 | - RoomEvent.Reconnected::class.java, | ||
| 88 | - ), | ||
| 89 | - events | ||
| 90 | - ) | ||
| 91 | - | ||
| 92 | - assertEquals( | ||
| 93 | - listOf( | ||
| 94 | - Room.State.CONNECTED, | ||
| 95 | - Room.State.RECONNECTING, | ||
| 96 | - Room.State.CONNECTED, | ||
| 97 | - ), | ||
| 98 | - states | ||
| 99 | - ) | ||
| 100 | - } | ||
| 101 | - | ||
| 102 | - @Test | ||
| 103 | fun softReconnectSendsSyncState() = runTest { | 45 | fun softReconnectSendsSyncState() = runTest { |
| 104 | room.setReconnectionType(ReconnectType.FORCE_SOFT_RECONNECT) | 46 | room.setReconnectionType(ReconnectType.FORCE_SOFT_RECONNECT) |
| 105 | 47 |
livekit-android-sdk/src/test/java/io/livekit/android/room/RoomReconnectionTypesMockE2ETest.kt
0 → 100644
| 1 | +package io.livekit.android.room | ||
| 2 | + | ||
| 3 | +import io.livekit.android.MockE2ETest | ||
| 4 | +import io.livekit.android.assert.assertIsClassList | ||
| 5 | +import io.livekit.android.events.EventCollector | ||
| 6 | +import io.livekit.android.events.FlowCollector | ||
| 7 | +import io.livekit.android.events.RoomEvent | ||
| 8 | +import io.livekit.android.util.flow | ||
| 9 | +import junit.framework.Assert.assertEquals | ||
| 10 | +import kotlinx.coroutines.ExperimentalCoroutinesApi | ||
| 11 | +import org.junit.Before | ||
| 12 | +import org.junit.Test | ||
| 13 | +import org.junit.runner.RunWith | ||
| 14 | +import org.robolectric.ParameterizedRobolectricTestRunner | ||
| 15 | + | ||
| 16 | +@ExperimentalCoroutinesApi | ||
| 17 | +@RunWith(ParameterizedRobolectricTestRunner::class) | ||
| 18 | +class RoomReconnectionTypesMockE2ETest( | ||
| 19 | + private val reconnectType: ReconnectType | ||
| 20 | +) : MockE2ETest() { | ||
| 21 | + | ||
| 22 | + companion object { | ||
| 23 | + @JvmStatic | ||
| 24 | + @ParameterizedRobolectricTestRunner.Parameters(name = "Input: {0}") | ||
| 25 | + // parameters are provided as arrays, allowing more than one parameter | ||
| 26 | + fun params() = listOf( | ||
| 27 | + ReconnectType.FORCE_SOFT_RECONNECT, | ||
| 28 | + ReconnectType.FORCE_FULL_RECONNECT, | ||
| 29 | + ) | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + private fun prepareForReconnect() { | ||
| 33 | + wsFactory.onOpen = { | ||
| 34 | + wsFactory.listener.onOpen(wsFactory.ws, createOpenResponse(wsFactory.request)) | ||
| 35 | + val softReconnectParam = wsFactory.request.url | ||
| 36 | + .queryParameter(SignalClient.CONNECT_QUERY_RECONNECT) | ||
| 37 | + ?.toIntOrNull() | ||
| 38 | + ?: 0 | ||
| 39 | + | ||
| 40 | + if (softReconnectParam == 0) { | ||
| 41 | + simulateMessageFromServer(SignalClientTest.JOIN) | ||
| 42 | + } | ||
| 43 | + } | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + @Before | ||
| 47 | + fun setup() { | ||
| 48 | + room.setReconnectionType(reconnectType) | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + @Test | ||
| 52 | + fun reconnectFromPeerConnectionDisconnect() = runTest { | ||
| 53 | + connect() | ||
| 54 | + | ||
| 55 | + val eventCollector = EventCollector(room.events, coroutineRule.scope) | ||
| 56 | + val stateCollector = FlowCollector(room::state.flow, coroutineRule.scope) | ||
| 57 | + prepareForReconnect() | ||
| 58 | + disconnectPeerConnection() | ||
| 59 | + // Wait so that the reconnect job properly starts first. | ||
| 60 | + testScheduler.advanceTimeBy(1000) | ||
| 61 | + connectPeerConnection() | ||
| 62 | + | ||
| 63 | + testScheduler.advanceUntilIdle() | ||
| 64 | + val events = eventCollector.stopCollecting() | ||
| 65 | + val states = stateCollector.stopCollecting() | ||
| 66 | + | ||
| 67 | + assertIsClassList( | ||
| 68 | + listOf( | ||
| 69 | + RoomEvent.Reconnecting::class.java, | ||
| 70 | + RoomEvent.Reconnected::class.java, | ||
| 71 | + ), | ||
| 72 | + events | ||
| 73 | + ) | ||
| 74 | + | ||
| 75 | + assertEquals( | ||
| 76 | + listOf( | ||
| 77 | + Room.State.CONNECTED, | ||
| 78 | + Room.State.RECONNECTING, | ||
| 79 | + Room.State.CONNECTED, | ||
| 80 | + ), | ||
| 81 | + states | ||
| 82 | + ) | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + @Test | ||
| 86 | + fun reconnectFromWebSocketFailure() = runTest { | ||
| 87 | + connect() | ||
| 88 | + | ||
| 89 | + val eventCollector = EventCollector(room.events, coroutineRule.scope) | ||
| 90 | + val stateCollector = FlowCollector(room::state.flow, coroutineRule.scope) | ||
| 91 | + prepareForReconnect() | ||
| 92 | + wsFactory.ws.cancel() | ||
| 93 | + // Wait so that the reconnect job properly starts first. | ||
| 94 | + testScheduler.advanceTimeBy(1000) | ||
| 95 | + connectPeerConnection() | ||
| 96 | + | ||
| 97 | + testScheduler.advanceUntilIdle() | ||
| 98 | + val events = eventCollector.stopCollecting() | ||
| 99 | + val states = stateCollector.stopCollecting() | ||
| 100 | + | ||
| 101 | + assertIsClassList( | ||
| 102 | + listOf( | ||
| 103 | + RoomEvent.Reconnecting::class.java, | ||
| 104 | + RoomEvent.Reconnected::class.java, | ||
| 105 | + ), | ||
| 106 | + events | ||
| 107 | + ) | ||
| 108 | + | ||
| 109 | + assertEquals( | ||
| 110 | + listOf( | ||
| 111 | + Room.State.CONNECTED, | ||
| 112 | + Room.State.RECONNECTING, | ||
| 113 | + Room.State.CONNECTED, | ||
| 114 | + ), | ||
| 115 | + states | ||
| 116 | + ) | ||
| 117 | + } | ||
| 118 | +} |
-
请 注册 或 登录 后发表评论