davidliu
Committed by GitHub

Fix reconnected event not firing on full reconnect (#158)

* Fix reconnect events on full reconnect

* parameterized tests
... ... @@ -139,7 +139,7 @@ dependencies {
testImplementation "org.mockito.kotlin:mockito-kotlin:4.0.0"
testImplementation 'androidx.test:core:1.4.0'
testImplementation deps.coroutines.test
kaptTest 'com.google.dagger:dagger-compiler:2.38'
kaptTest "com.google.dagger:dagger-compiler:${versions.dagger}"
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
... ...
... ... @@ -324,10 +324,12 @@ internal constructor(
reconnectingJob = null
coroutineScope.close()
closeResources(reason)
connectionState = ConnectionState.DISCONNECTED
}
private fun closeResources(reason: String) {
connectionState = ConnectionState.DISCONNECTED
publisherObserver.connectionChangeListener = null
subscriberObserver.connectionChangeListener = null
_publisher?.close()
_publisher = null
_subscriber?.close()
... ...
... ... @@ -32,7 +32,7 @@ abstract class MockE2ETest : BaseTest() {
internal lateinit var subscriber: PeerConnectionTransport
@Before
fun setup() {
fun mocksSetup() {
context = ApplicationProvider.getApplicationContext()
component = DaggerTestLiveKitComponent
.factory()
... ...
... ... @@ -18,88 +18,30 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
/**
* For tests that only target one reconnection type.
*
* Tests that cover all connection types should be put in [RoomReconnectionTypesMockE2ETest].
*/
@ExperimentalCoroutinesApi
@RunWith(RobolectricTestRunner::class)
class RoomReconnectionMockE2ETest : MockE2ETest() {
private fun prepareForReconnect(softReconnect: Boolean = false) {
private fun prepareForReconnect() {
wsFactory.onOpen = {
wsFactory.listener.onOpen(wsFactory.ws, createOpenResponse(wsFactory.request))
if (!softReconnect) {
val softReconnectParam = wsFactory.request.url
.queryParameter(SignalClient.CONNECT_QUERY_RECONNECT)
?.toIntOrNull()
?: 0
if (softReconnectParam == 0) {
simulateMessageFromServer(SignalClientTest.JOIN)
}
}
}
@Test
fun reconnectFromPeerConnectionDisconnect() = runTest {
connect()
val eventCollector = EventCollector(room.events, coroutineRule.scope)
val stateCollector = FlowCollector(room::state.flow, coroutineRule.scope)
prepareForReconnect()
disconnectPeerConnection()
// Wait so that the reconnect job properly starts first.
testScheduler.advanceTimeBy(1000)
connectPeerConnection()
testScheduler.advanceUntilIdle()
val events = eventCollector.stopCollecting()
val states = stateCollector.stopCollecting()
assertIsClassList(
listOf(
RoomEvent.Reconnecting::class.java,
RoomEvent.Reconnected::class.java,
),
events
)
assertEquals(
listOf(
Room.State.CONNECTED,
Room.State.RECONNECTING,
Room.State.CONNECTED,
),
states
)
}
@Test
fun reconnectFromWebSocketFailure() = runTest {
connect()
val eventCollector = EventCollector(room.events, coroutineRule.scope)
val stateCollector = FlowCollector(room::state.flow, coroutineRule.scope)
prepareForReconnect()
wsFactory.ws.cancel()
// Wait so that the reconnect job properly starts first.
testScheduler.advanceTimeBy(1000)
connectPeerConnection()
testScheduler.advanceUntilIdle()
val events = eventCollector.stopCollecting()
val states = stateCollector.stopCollecting()
assertIsClassList(
listOf(
RoomEvent.Reconnecting::class.java,
RoomEvent.Reconnected::class.java,
),
events
)
assertEquals(
listOf(
Room.State.CONNECTED,
Room.State.RECONNECTING,
Room.State.CONNECTED,
),
states
)
}
@Test
fun softReconnectSendsSyncState() = runTest {
room.setReconnectionType(ReconnectType.FORCE_SOFT_RECONNECT)
... ...
package io.livekit.android.room
import io.livekit.android.MockE2ETest
import io.livekit.android.assert.assertIsClassList
import io.livekit.android.events.EventCollector
import io.livekit.android.events.FlowCollector
import io.livekit.android.events.RoomEvent
import io.livekit.android.util.flow
import junit.framework.Assert.assertEquals
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.ParameterizedRobolectricTestRunner
@ExperimentalCoroutinesApi
@RunWith(ParameterizedRobolectricTestRunner::class)
class RoomReconnectionTypesMockE2ETest(
private val reconnectType: ReconnectType
) : MockE2ETest() {
companion object {
@JvmStatic
@ParameterizedRobolectricTestRunner.Parameters(name = "Input: {0}")
// parameters are provided as arrays, allowing more than one parameter
fun params() = listOf(
ReconnectType.FORCE_SOFT_RECONNECT,
ReconnectType.FORCE_FULL_RECONNECT,
)
}
private fun prepareForReconnect() {
wsFactory.onOpen = {
wsFactory.listener.onOpen(wsFactory.ws, createOpenResponse(wsFactory.request))
val softReconnectParam = wsFactory.request.url
.queryParameter(SignalClient.CONNECT_QUERY_RECONNECT)
?.toIntOrNull()
?: 0
if (softReconnectParam == 0) {
simulateMessageFromServer(SignalClientTest.JOIN)
}
}
}
@Before
fun setup() {
room.setReconnectionType(reconnectType)
}
@Test
fun reconnectFromPeerConnectionDisconnect() = runTest {
connect()
val eventCollector = EventCollector(room.events, coroutineRule.scope)
val stateCollector = FlowCollector(room::state.flow, coroutineRule.scope)
prepareForReconnect()
disconnectPeerConnection()
// Wait so that the reconnect job properly starts first.
testScheduler.advanceTimeBy(1000)
connectPeerConnection()
testScheduler.advanceUntilIdle()
val events = eventCollector.stopCollecting()
val states = stateCollector.stopCollecting()
assertIsClassList(
listOf(
RoomEvent.Reconnecting::class.java,
RoomEvent.Reconnected::class.java,
),
events
)
assertEquals(
listOf(
Room.State.CONNECTED,
Room.State.RECONNECTING,
Room.State.CONNECTED,
),
states
)
}
@Test
fun reconnectFromWebSocketFailure() = runTest {
connect()
val eventCollector = EventCollector(room.events, coroutineRule.scope)
val stateCollector = FlowCollector(room::state.flow, coroutineRule.scope)
prepareForReconnect()
wsFactory.ws.cancel()
// Wait so that the reconnect job properly starts first.
testScheduler.advanceTimeBy(1000)
connectPeerConnection()
testScheduler.advanceUntilIdle()
val events = eventCollector.stopCollecting()
val states = stateCollector.stopCollecting()
assertIsClassList(
listOf(
RoomEvent.Reconnecting::class.java,
RoomEvent.Reconnected::class.java,
),
events
)
assertEquals(
listOf(
Room.State.CONNECTED,
Room.State.RECONNECTING,
Room.State.CONNECTED,
),
states
)
}
}
\ No newline at end of file
... ...