Skip to content

Commit

Permalink
Improve error logging for Realm-level Coroutine tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Christian Melchior committed Nov 27, 2023
1 parent a4b071b commit 21b7eee
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ suspend fun <T : Any?> Channel<T>.receiveOrFail(timeout: Duration = 1.minutes, m
this@receiveOrFail.onReceive { it }
onTimeout(timeout) {
@Suppress("invisible_member")
throw TimeoutCancellationException("Timeout: $message")
throw TimeoutCancellationException("Timeout after $timeout: ${if (message.isNullOrBlank()) "<no message>" else message}")

Check failure on line 102 in packages/test-base/src/commonMain/kotlin/io/realm/kotlin/test/util/Utils.kt

View workflow job for this annotation

GitHub Actions / Results - Android Base (Emulator)

io.realm.kotlin.test.android.InstrumentedTests ► io.realm.kotlin.test.common.notifications.RealmNotificationsTests ► cancelAsFlow

Failed test found in: ./packages/test-base/build/outputs/androidTest-results/connected/TEST-test(AVD) - 13-_test-base-.xml Error: kotlinx.coroutines.TimeoutCancellationException: Timeout after 1m: Did not receive Update event on Channel 1
Raw output
kotlinx.coroutines.TimeoutCancellationException: Timeout after 1m: Did not receive Update event on Channel 1
at io.realm.kotlin.test.util.UtilsKt$receiveOrFail$2$2.invokeSuspend(Utils.kt:102)
at io.realm.kotlin.test.util.UtilsKt$receiveOrFail$2$2.invoke(Unknown Source:8)
at io.realm.kotlin.test.util.UtilsKt$receiveOrFail$2$2.invoke(Unknown Source:2)
at kotlinx.coroutines.selects.SelectImplementation$ClauseData.invokeBlock(Select.kt:818)
at kotlinx.coroutines.selects.SelectImplementation.complete(Select.kt:692)
at kotlinx.coroutines.selects.SelectImplementation.doSelectSuspend(Select.kt:434)
at kotlinx.coroutines.selects.SelectImplementation.access$doSelectSuspend(Select.kt:243)
at kotlinx.coroutines.selects.SelectImplementation$doSelectSuspend$1.invokeSuspend(Unknown Source:14)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:280)
at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source:1)
at io.realm.kotlin.internal.platform.CoroutineUtilsSharedJvmKt.runBlocking(CoroutineUtilsSharedJvm.kt:22)
at io.realm.kotlin.internal.platform.CoroutineUtilsSharedJvmKt.runBlocking$default(CoroutineUtilsSharedJvm.kt:21)
at io.realm.kotlin.test.common.notifications.RealmNotificationsTests.cancelAsFlow(RealmNotificationsTests.kt:124)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -232,12 +232,12 @@ class VersionTrackingTests {
}

// Wait for the notifier to start
realmUpdates.receiveOrFail()
realmUpdates.receiveOrFail(message = "Initial event was not received")

realm.write { }

// Wait for the notifier to start
realmUpdates.receiveOrFail()
realmUpdates.receiveOrFail(message = "Update event was not received")

assertNull(realm.initialRealmReference.value, toString())
assertEquals(1, realm.versionTracker.versions().size, toString())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,69 +121,67 @@ class RealmNotificationsTests : FlowableTests {
}

@Test
override fun cancelAsFlow() {
runBlocking {
val c1 = Channel<RealmChange<Realm>>(1)
val c2 = Channel<RealmChange<Realm>>(1)
val startingVersion = realm.version()
override fun cancelAsFlow() = runBlocking<Unit> {
val c1 = Channel<RealmChange<Realm>>(1)
val c2 = Channel<RealmChange<Realm>>(1)
val startingVersion = realm.version()

val observer1 = async {
realm.asFlow().collect {
c1.send(it)
}
val observer1 = async {
realm.asFlow().collect {
c1.send(it)
}
val observer2Cancelled = Mutex(false)
val observer2 = async {
realm.asFlow().collect {
if (!observer2Cancelled.isLocked) {
c2.send(it)
} else {
fail("Should not receive notifications on a canceled scope")
}
}
val observer2Cancelled = Mutex(false)
val observer2 = async {
realm.asFlow().collect {
if (!observer2Cancelled.isLocked) {
c2.send(it)
} else {
fail("Should not receive notifications on a canceled scope")
}
}
}

// We should first receive an initial Realm notification.
c1.receiveOrFail().let { realmChange ->
assertIs<InitialRealm<Realm>>(realmChange)
assertEquals(startingVersion, realmChange.realm.version())
}

c2.receiveOrFail().let { realmChange ->
assertIs<InitialRealm<Realm>>(realmChange)
assertEquals(startingVersion, realmChange.realm.version())
}
// We should first receive an initial Realm notification.
c1.receiveOrFail(message = "Did not receive Initial event on Channel 1").let { realmChange ->
assertIs<InitialRealm<Realm>>(realmChange)
assertEquals(startingVersion, realmChange.realm.version())
}

realm.write { /* Do nothing */ }
c2.receiveOrFail(message = "Did not receive Initial event on Channel 2").let { realmChange ->
assertIs<InitialRealm<Realm>>(realmChange)
assertEquals(startingVersion, realmChange.realm.version())
}

// Now we we should receive an updated Realm change notification.
c1.receiveOrFail().let { realmChange ->
assertIs<UpdatedRealm<Realm>>(realmChange)
assertEquals(VersionId(startingVersion.version + 1), realmChange.realm.version())
}
realm.write { /* Do nothing */ }

c2.receiveOrFail().let { realmChange ->
assertIs<UpdatedRealm<Realm>>(realmChange)
assertEquals(VersionId(startingVersion.version + 1), realmChange.realm.version())
}
// Now we we should receive an updated Realm change notification.
c1.receiveOrFail(message = "Did not receive Update event on Channel 1").let { realmChange ->
assertIs<UpdatedRealm<Realm>>(realmChange)
assertEquals(VersionId(startingVersion.version + 1), realmChange.realm.version())
}

// Stop one observer and ensure that we dont receive any more notifications in that scope
observer2.cancel()
observer2Cancelled.lock()
c2.receiveOrFail(message = "Did not receive Update event on Channel 2").let { realmChange ->
assertIs<UpdatedRealm<Realm>>(realmChange)
assertEquals(VersionId(startingVersion.version + 1), realmChange.realm.version())
}

realm.write { /* Do nothing */ }
// Stop one observer and ensure that we dont receive any more notifications in that scope
observer2.cancel()
observer2Cancelled.lock()

// But unclosed channels should receive notifications
c1.receiveOrFail().let { realmChange ->
assertIs<UpdatedRealm<Realm>>(realmChange)
assertEquals(VersionId(startingVersion.version + 2), realmChange.realm.version())
}
realm.write { /* Do nothing */ }

realm.write { /* Do nothing */ }
observer1.cancel()
c1.close()
c2.close()
// But unclosed channels should receive notifications
c1.receiveOrFail(message = "Did not receive 2nd Update event on Channel 1").let { realmChange ->
assertIs<UpdatedRealm<Realm>>(realmChange)
assertEquals(VersionId(startingVersion.version + 2), realmChange.realm.version())
}

realm.write { /* Do nothing */ }
observer1.cancel()
c1.close()
c2.close()
}

@Test
Expand Down

0 comments on commit 21b7eee

Please sign in to comment.