Skip to content

Commit

Permalink
Fix integration tests
Browse files Browse the repository at this point in the history
  • Loading branch information
BoD committed Feb 14, 2023
1 parent 49d7e51 commit 8deb17a
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 167 deletions.
38 changes: 20 additions & 18 deletions tests/defer/src/commonTest/kotlin/test/DeferNormalizedCacheTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import defer.fragment.ComputerFields
import defer.fragment.ScreenFields
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.toList
Expand All @@ -37,6 +36,7 @@ import kotlin.test.assertEquals
import kotlin.test.assertFails
import kotlin.test.assertFailsWith
import kotlin.test.assertIs
import kotlin.test.assertTrue

class DeferNormalizedCacheTest {
private lateinit var mockServer: MockServer
Expand Down Expand Up @@ -134,7 +134,9 @@ class DeferNormalizedCacheTest {
mockServer.enqueueMultipart(jsonList)

// Cache is empty, so this goes to the server
val networkActual = apolloClient.query(WithFragmentSpreadsQuery()).toFlow().toList().map { it.dataAssertNoErrors }
val responses = apolloClient.query(WithFragmentSpreadsQuery()).toFlow().toList()
assertTrue(responses[0].exception is CacheMissException)
val networkActual = responses.drop(1).map { it.dataAssertNoErrors }
mockServer.takeRequest()

val networkExpected = listOf(
Expand Down Expand Up @@ -214,7 +216,9 @@ class DeferNormalizedCacheTest {
mockServer.enqueueMultipart(jsonList1)

// Cache is empty
val networkActual = apolloClient.query(WithFragmentSpreadsQuery()).toFlow().toList().map { it.dataAssertNoErrors }
val responses = apolloClient.query(WithFragmentSpreadsQuery()).toFlow().toList()
assertTrue(responses[0].exception is CacheMissException)
val networkActual = responses.drop(1).map { it.dataAssertNoErrors }
mockServer.takeRequest()

val networkExpected = listOf(
Expand Down Expand Up @@ -277,7 +281,7 @@ class DeferNormalizedCacheTest {
mockServer.enqueueMultipart(jsonList)

// Cache is empty, so this goes to the server
val networkActual = apolloClient.query(WithFragmentSpreadsQuery()).toFlow().toList()
val networkActual = apolloClient.query(WithFragmentSpreadsQuery()).toFlow().toList().drop(1)
mockServer.takeRequest()

val query = WithFragmentSpreadsQuery()
Expand Down Expand Up @@ -370,7 +374,10 @@ class DeferNormalizedCacheTest {
emit(networkResponse as ApolloResponse<D>)
}
delay(10)
throw ApolloNetworkException("Network error")
emit(ApolloResponse.Builder(requestUuid = uuid, operation = query, data = null)
.exception(ApolloNetworkException("Network error"))
.isLast(true)
.build() as ApolloResponse<D>)
}
}

Expand All @@ -383,19 +390,14 @@ class DeferNormalizedCacheTest {
// - an exception happens
// - fallback to the cache
// - because of the error the cache is missing some fields, so we get a cache miss
var throwable: Throwable? = null
val networkActual = apolloClient.query(WithFragmentSpreadsQuery()).toFlow()
.catch { t ->
throwable = t
}
.toList()

assertResponseListEquals(networkResponses, networkActual)
assertIs<ApolloCompositeException>(throwable)
throwable as ApolloCompositeException
assertIs<ApolloNetworkException>(throwable!!.suppressedExceptions.first())
assertIs<CacheMissException>(throwable!!.suppressedExceptions.getOrNull(1))
assertEquals("Object 'computers.0.screen' has no field named 'isColor'", throwable!!.suppressedExceptions.getOrNull(1)!!.message)
val actual = apolloClient.query(WithFragmentSpreadsQuery()).toFlow().toList()

assertResponseListEquals(networkResponses, actual.dropLast(2))
val networkExceptionResponse = actual[actual.size - 2]
val cacheExceptionResponse = actual.last()
assertIs<ApolloNetworkException>(networkExceptionResponse.exception)
assertIs<CacheMissException>(cacheExceptionResponse.exception)
assertEquals("Object 'computers.0.screen' has no field named 'isColor'", cacheExceptionResponse.exception!!.message)
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package test

import com.apollographql.apollo3.ApolloClient
import com.apollographql.apollo3.cache.normalized.FetchPolicy
import com.apollographql.apollo3.cache.normalized.api.MemoryCacheFactory
import com.apollographql.apollo3.cache.normalized.executeCacheAndNetwork
import com.apollographql.apollo3.cache.normalized.fetchPolicy
import com.apollographql.apollo3.cache.normalized.normalizedCache
import com.apollographql.apollo3.integration.normalizer.EpisodeHeroNameQuery
import com.apollographql.apollo3.integration.normalizer.type.Episode
Expand Down Expand Up @@ -46,7 +47,7 @@ class CancelTest {
val apolloClient = ApolloClient.Builder().serverUrl(mockServer.url()).normalizedCache(MemoryCacheFactory()).build()

val job = launch {
apolloClient.query(EpisodeHeroNameQuery(Episode.EMPIRE)).executeCacheAndNetwork().toList()
apolloClient.query(EpisodeHeroNameQuery(Episode.EMPIRE)).fetchPolicy(FetchPolicy.CacheAndNetwork).toFlow().toList()
}
delay(100)
job.cancel()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ import com.apollographql.apollo3.exception.ApolloNetworkException
import com.apollographql.apollo3.integration.normalizer.HeroNameQuery
import com.apollographql.apollo3.mockserver.MockServer
import com.apollographql.apollo3.mockserver.enqueue
import com.apollographql.apollo3.testing.enqueue
import com.apollographql.apollo3.testing.internal.runTest
import kotlinx.coroutines.flow.retryWhen
import kotlinx.coroutines.flow.single
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
Expand Down Expand Up @@ -62,20 +59,4 @@ class ExceptionsTest {
val exception = result.exceptionOrNull()
assertTrue(exception is ApolloNetworkException)
}

@Test
fun WhenQueryAndMalformedNetworkResponseAssertSuccessAfterRetry() = runTest(before = { setUp() }, after = { tearDown() }) {
mockServer.enqueue("")
val query = HeroNameQuery()
val data = HeroNameQuery.Data(HeroNameQuery.Hero("R2-D2"))
mockServer.enqueue(query, data)

val response = apolloClient
.query(query)
.toFlow()
.retryWhen { _, attempt -> attempt == 0L }
.single()

assertEquals(data, response.data)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ import com.apollographql.apollo3.cache.normalized.CacheOnlyInterceptor
import com.apollographql.apollo3.cache.normalized.FetchPolicy
import com.apollographql.apollo3.cache.normalized.api.CacheKey
import com.apollographql.apollo3.cache.normalized.api.MemoryCacheFactory
import com.apollographql.apollo3.cache.normalized.executeCacheAndNetwork
import com.apollographql.apollo3.cache.normalized.fetchPolicy
import com.apollographql.apollo3.cache.normalized.isFromCache
import com.apollographql.apollo3.cache.normalized.refetchPolicyInterceptor
import com.apollographql.apollo3.cache.normalized.store
import com.apollographql.apollo3.cache.normalized.watch
import com.apollographql.apollo3.exception.ApolloCompositeException
import com.apollographql.apollo3.exception.ApolloException
import com.apollographql.apollo3.exception.ApolloHttpException
import com.apollographql.apollo3.exception.CacheMissException
import com.apollographql.apollo3.integration.normalizer.CharacterNameByIdQuery
import com.apollographql.apollo3.integration.normalizer.HeroNameQuery
import com.apollographql.apollo3.interceptor.ApolloInterceptor
Expand Down Expand Up @@ -188,33 +188,37 @@ class FetchPolicyTest {
// Cache Error + Network Error => Error
mockServer.enqueue(statusCode = 500)
assertFailsWith(ApolloCompositeException::class) {
apolloClient.query(query).fetchPolicy(FetchPolicy.CacheAndNetwork).toFlow().toList()
apolloClient.query(query).fetchPolicy(FetchPolicy.CacheAndNetwork).execute()
}

// Make the network return something
// Cache Error + Network Success => 1 response (no exception)
// Cache Error + Network Success => 2 responses
mockServer.enqueue(query, data)
var responses = apolloClient.query(query).fetchPolicy(FetchPolicy.CacheAndNetwork).toFlow().catch { caught = it }.toList()

assertNull(caught)
assertEquals(1, responses.size)
assertNotNull(responses[0].data)
assertFalse(responses[0].isFromCache)
assertEquals("R2-D2", responses[0].data?.hero?.name)
assertEquals(2, responses.size)
assertNull(responses[0].data)
assertIs<CacheMissException>(responses[0].exception)
assertNotNull(responses[1].data)
assertFalse(responses[1].isFromCache)
assertEquals("R2-D2", responses[1].data?.hero?.name)

// Now cache is populated but make the network fail again
// Cache Success + Network Error => 1 response + 1 network exception
// Cache Success + Network Error => 1 response with cache value + 1 response with network exception
caught = null
mockServer.enqueue(statusCode = 500)
responses = apolloClient.query(query).fetchPolicy(FetchPolicy.CacheAndNetwork).toFlow().catch { caught = it }.toList()

assertIs<ApolloException>(caught)
assertEquals(1, responses.size)
assertNull(caught)
assertEquals(2, responses.size)
assertNotNull(responses[0].data)
assertTrue(responses[0].isFromCache)
assertEquals("R2-D2", responses[0].data?.hero?.name)
assertNull(responses[1].data)
assertIs<ApolloHttpException>(responses[1].exception)

// Cache Success + Network Success => 1 response
// Cache Success + Network Success => 2 responses
mockServer.enqueue(query, data)
responses = apolloClient.query(query).fetchPolicy(FetchPolicy.CacheAndNetwork).toFlow().toList()

Expand All @@ -225,48 +229,6 @@ class FetchPolicyTest {
assertFalse(responses[1].isFromCache)
}

@Test
fun queryCacheAndNetwork() = runTest(before = { setUp() }, after = { tearDown() }) {
val query = HeroNameQuery()
val data = HeroNameQuery.Data(HeroNameQuery.Hero("R2-D2"))

// Initial state: everything fails
// Cache Error + Network Error => Error
mockServer.enqueue(statusCode = 500)
assertFailsWith(ApolloCompositeException::class) {
apolloClient.query(query).executeCacheAndNetwork().toList()
}

// Make the network return something
// Cache Error + Nework Success => 1 response
mockServer.enqueue(query, data)
var responses = apolloClient.query(query).executeCacheAndNetwork().toList()

assertEquals(1, responses.size)
assertNotNull(responses[0].data)
assertFalse(responses[0].isFromCache)
assertEquals("R2-D2", responses[0].data?.hero?.name)

// Now cache is populated but make the network fail again
// Cache Success + Network Error => 1 response
mockServer.enqueue(statusCode = 500)
responses = apolloClient.query(query).executeCacheAndNetwork().toList()

assertEquals(1, responses.size)
assertNotNull(responses[0].data)
assertTrue(responses[0].isFromCache)
assertEquals("R2-D2", responses[0].data?.hero?.name)

// Cache Success + Network Success => 1 response
mockServer.enqueue(query, data)
responses = apolloClient.query(query).executeCacheAndNetwork().toList()

assertEquals(2, responses.size)
assertNotNull(responses[0].data)
assertTrue(responses[0].isFromCache)
assertNotNull(responses[1].data)
assertFalse(responses[1].isFromCache)
}

private val refetchPolicyInterceptor = object : ApolloInterceptor {
var hasSeenValidResponse: Boolean = false
Expand Down Expand Up @@ -302,8 +264,8 @@ class FetchPolicyTest {
.refetchPolicyInterceptor(refetchPolicyInterceptor)
.watch()
.collect {
println(it.data)
channel.send(it)
// Don't send the first response, it's a cache miss
if (it.exception == null) channel.send(it)
}
}

Expand Down
Loading

0 comments on commit 8deb17a

Please sign in to comment.