Skip to content

Commit a00e2be

Browse files
authored
dataconnect: fix flaky test: collect_gets_notified_of_per_data_deserializer_successes (#7210)
1 parent 59df53b commit a00e2be

File tree

1 file changed

+44
-3
lines changed

1 file changed

+44
-3
lines changed

firebase-dataconnect/src/androidTest/kotlin/com/google/firebase/dataconnect/QuerySubscriptionIntegrationTest.kt

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ import kotlinx.coroutines.FlowPreview
4141
import kotlinx.coroutines.TimeoutCancellationException
4242
import kotlinx.coroutines.async
4343
import kotlinx.coroutines.flow.catch
44-
import kotlinx.coroutines.flow.collect
4544
import kotlinx.coroutines.flow.distinctUntilChanged
4645
import kotlinx.coroutines.flow.first
4746
import kotlinx.coroutines.flow.flowOn
@@ -446,8 +445,18 @@ class QuerySubscriptionIntegrationTest : DataConnectIntegrationTestBase() {
446445
schema.getPerson(personId).withDataDeserializer(serializer<GetPersonDataNoName2>())
447446

448447
turbineScope {
449-
val noName1Flow = noName1Query.subscribe().flow.distinctUntilChanged().testIn(backgroundScope)
450-
val noName2Flow = noName2Query.subscribe().flow.distinctUntilChanged().testIn(backgroundScope)
448+
val noName1Flow =
449+
noName1Query
450+
.subscribe()
451+
.flow
452+
.distinctUntilChanged(::areEquivalentQuerySubscriptionResults)
453+
.testIn(backgroundScope)
454+
val noName2Flow =
455+
noName2Query
456+
.subscribe()
457+
.flow
458+
.distinctUntilChanged(::areEquivalentQuerySubscriptionResults)
459+
.testIn(backgroundScope)
451460
withClue("noName1Flow-0") { noName1Flow.awaitPersonWithName("Name0") }
452461
withClue("noName2Flow-0") { noName2Flow.awaitPersonWithName("Name0") }
453462

@@ -636,5 +645,37 @@ class QuerySubscriptionIntegrationTest : DataConnectIntegrationTestBase() {
636645
val person = withClue("data.person") { data.person.shouldNotBeNull() }
637646
withClue("person.name") { person.name shouldBe name }
638647
}
648+
649+
/**
650+
* Returns `true` if, and only if, the receiver is a non-null instance of
651+
* [DataConnectOperationException] that indicates that the failure is due to decoding of the
652+
* server response failed.
653+
*/
654+
fun Throwable?.isDecodingServerResponseFailed(): Boolean =
655+
this is DataConnectOperationException && this.response.errors.isEmpty()
656+
657+
/**
658+
* Returns `true` if, and only if, the receiver's result is a failure that indicates that
659+
* decoding of the server response failed.
660+
*/
661+
fun QuerySubscriptionResult<*, *>.isDecodingServerResponseFailed(): Boolean =
662+
result.exceptionOrNull().isDecodingServerResponseFailed()
663+
664+
/**
665+
* Checks if two [QuerySubscriptionResult] instances are "equivalent"; that is, they are both
666+
* equal when compared using the `==` operator, or they are both failures due to decoding of the
667+
* server response failed.
668+
*
669+
* This is useful when testing flows because the same decoding failure can happen more than once
670+
* in a row based on other asynchronous operations but testing for "distinctness" will consider
671+
* those two failures as "distinct" when the test wants them to be treated as "equal".
672+
*
673+
* See https://github.com/firebase/firebase-android-sdk/pull/7210 for a full explanation.
674+
*/
675+
fun areEquivalentQuerySubscriptionResults(
676+
old: QuerySubscriptionResult<*, *>,
677+
new: QuerySubscriptionResult<*, *>
678+
): Boolean =
679+
(old == new) || (old.isDecodingServerResponseFailed() && new.isDecodingServerResponseFailed())
639680
}
640681
}

0 commit comments

Comments
 (0)