Skip to content

Commit

Permalink
Do not throw in ApolloCall.execute()
Browse files Browse the repository at this point in the history
  • Loading branch information
BoD committed Feb 17, 2023
1 parent a190d88 commit 929aef6
Show file tree
Hide file tree
Showing 12 changed files with 183 additions and 137 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,12 @@ class ApolloCall<D : Operation.Data> internal constructor(
if (successes.size > 1) {
throw ApolloException("The operation returned multiple items, use .toFlow() instead of .execute()")
} else if (successes.isEmpty()) {
if (errors.size == 1) {
throw errors[0].exception!!
return if (errors.size == 1) {
errors[0]
} else if (errors.size > 1) {
throw ApolloCompositeException(errors[0].exception, errors[1].exception)
errors[1].newBuilder()
.exception(ApolloCompositeException(errors[0].exception, errors[1].exception))
.build()
} else {
throw ApolloException("The operation did not emit any item, check your interceptor chain")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ class DeferNormalizedCacheTest {
apolloClient = apolloClient.newBuilder().fetchPolicy(FetchPolicy.CacheOnly).build()

// Cache is empty
assertFailsWith<CacheMissException> {
apolloClient.query(WithFragmentSpreadsQuery()).execute()
}
assertIs<CacheMissException>(
apolloClient.query(WithFragmentSpreadsQuery()).execute().exception
)

// Fill the cache by doing a network only request
val jsonList = listOf(
Expand Down
61 changes: 30 additions & 31 deletions tests/http-cache/src/test/kotlin/HttpCacheTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ import okhttp3.OkHttpClient
import java.io.File
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFails
import kotlin.test.assertFailsWith
import kotlin.test.fail
import kotlin.test.assertIs
import kotlin.test.assertNotNull

class HttpCacheTest {
lateinit var mockServer: MockServer
Expand Down Expand Up @@ -95,11 +94,12 @@ class HttpCacheTest {
assertEquals(42, response.data?.random)
assertEquals(false, response.isFromHttpCache)

assertFails {
apolloClient.query(GetRandomQuery())
.httpFetchPolicy(HttpFetchPolicy.NetworkOnly)
.execute()
}
assertNotNull(
apolloClient.query(GetRandomQuery())
.httpFetchPolicy(HttpFetchPolicy.NetworkOnly)
.execute()
.exception
)
}
}

Expand Down Expand Up @@ -136,12 +136,13 @@ class HttpCacheTest {
assertEquals(true, response.isFromHttpCache)

delay(1000)
assertFailsWith(HttpCacheMissException::class) {
apolloClient.query(GetRandomQuery())
.httpExpireTimeout(500)
.httpFetchPolicy(HttpFetchPolicy.CacheOnly)
.execute()
}
assertIs<HttpCacheMissException>(
apolloClient.query(GetRandomQuery())
.httpExpireTimeout(500)
.httpFetchPolicy(HttpFetchPolicy.CacheOnly)
.execute()
.exception
)
}
}

Expand Down Expand Up @@ -209,13 +210,13 @@ class HttpCacheTest {
@Test
fun incompleteJsonIsNotCached() = runTest(before = { before() }, after = { tearDown() }) {
mockServer.enqueue("""{"data":""")
assertFailsWith<ApolloParseException> {
apolloClient.query(GetRandomQuery()).execute()
}
assertIs<ApolloParseException>(
apolloClient.query(GetRandomQuery()).execute().exception
)
// Should not have been cached
assertFailsWith<HttpCacheMissException> {
apolloClient.query(GetRandomQuery()).httpFetchPolicy(HttpFetchPolicy.CacheOnly).execute()
}
assertIs<HttpCacheMissException>(
apolloClient.query(GetRandomQuery()).httpFetchPolicy(HttpFetchPolicy.CacheOnly).execute().exception
)
}

@Test
Expand All @@ -230,9 +231,9 @@ class HttpCacheTest {
""")
apolloClient.query(GetRandomQuery()).execute()
// Should not have been cached
assertFailsWith<HttpCacheMissException> {
apolloClient.query(GetRandomQuery()).httpFetchPolicy(HttpFetchPolicy.CacheOnly).execute()
}
assertIs<HttpCacheMissException>(
apolloClient.query(GetRandomQuery()).httpFetchPolicy(HttpFetchPolicy.CacheOnly).execute().exception
)
}

@Test
Expand All @@ -243,14 +244,12 @@ class HttpCacheTest {

mockServer.enqueueData(data)

try {
apolloClient.query(GetRandomQuery())
.addHttpHeader("foo", "bar")
.execute()
fail("An exception was expected")
} catch (e: Exception) {

}
assertNotNull(
apolloClient.query(GetRandomQuery())
.addHttpHeader("foo", "bar")
.execute()
.exception
)
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,8 @@ class HttpEngineTest {
fun canReadNSError() = runTest {
val apolloClient = ApolloClient.Builder().serverUrl("https://inexistent.host/graphql").build()

val result = kotlin.runCatching {
apolloClient.query(HeroNameQuery()).execute()
}

val apolloNetworkException = result.exceptionOrNull()
val response = apolloClient.query(HeroNameQuery()).execute()
val apolloNetworkException = response.exception
assertNotNull(apolloNetworkException)
assertIs<ApolloNetworkException>(apolloNetworkException)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertIs
import kotlin.test.assertNotNull

class CacheFlagsTest {
Expand All @@ -47,9 +47,9 @@ class CacheFlagsTest {
apolloClient.query(query).doNotStore(true).execute()

// Since the previous request was not stored, this should fail
assertFailsWith(CacheMissException::class) {
apolloClient.query(query).fetchPolicy(FetchPolicy.CacheOnly).execute()
}
assertIs<CacheMissException>(
apolloClient.query(query).fetchPolicy(FetchPolicy.CacheOnly).execute().exception
)
}

@Test
Expand All @@ -70,9 +70,9 @@ class CacheFlagsTest {
assertEquals("R2-D2", response.data?.hero?.name)

// Second time should fail
assertFailsWith(CacheMissException::class) {
apolloClient.query(query).fetchPolicy(FetchPolicy.CacheOnly).execute()
}
assertIs<CacheMissException>(
apolloClient.query(query).fetchPolicy(FetchPolicy.CacheOnly).execute().exception
)
}

private val partialResponseData = HeroNameQuery.Data(null)
Expand All @@ -90,9 +90,9 @@ class CacheFlagsTest {
// this should not store the response
apolloClient.query(query).execute()

assertFailsWith(CacheMissException::class) {
apolloClient.query(query).fetchPolicy(FetchPolicy.CacheOnly).execute()
}
assertIs<CacheMissException>(
apolloClient.query(query).fetchPolicy(FetchPolicy.CacheOnly).execute().exception
)
}

@Test
Expand Down Expand Up @@ -123,8 +123,8 @@ class CacheFlagsTest {
apolloClient.query(query).fetchPolicy(FetchPolicy.NetworkFirst).execute()

// Since the previous request was not stored, this should fail
assertFailsWith(CacheMissException::class) {
apolloClient.query(query).fetchPolicy(FetchPolicy.CacheOnly).execute()
}
assertIs<CacheMissException>(
apolloClient.query(query).fetchPolicy(FetchPolicy.CacheOnly).execute().exception
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,16 @@ class ExceptionsTest {
fun whenQueryAndMalformedNetworkResponseAssertException() = runTest(before = { setUp() }, after = { tearDown() }) {
mockServer.enqueue("malformed")

val result = kotlin.runCatching {
apolloClient.query(HeroNameQuery()).execute()
}

assertTrue(result.exceptionOrNull() != null)
val response = apolloClient.query(HeroNameQuery()).execute()
assertTrue(response.exception != null)
}

@Test
fun whenHttpErrorAssertExecuteFails() = runTest(before = { setUp() }, after = { tearDown() }) {
mockServer.enqueue(statusCode = 404)

val result = kotlin.runCatching {
apolloClient.query(HeroNameQuery()).execute()
}

val exception = result.exceptionOrNull()
val response = apolloClient.query(HeroNameQuery()).execute()
val exception = response.exception
assertTrue(exception is ApolloHttpException)
assertEquals(404, exception.statusCode)
}
Expand All @@ -55,12 +49,8 @@ class ExceptionsTest {
fun whenNetworkErrorAssertApolloNetworkException() = runTest(before = { setUp() }) {
mockServer.stop()

val result = kotlin.runCatching {
apolloClient.query(HeroNameQuery()).execute()
}

val exception = result.exceptionOrNull()
assertTrue(exception is ApolloNetworkException)
val response = apolloClient.query(HeroNameQuery()).execute()
assertTrue(response.exception is ApolloNetworkException)
}

@Test
Expand Down
101 changes: 95 additions & 6 deletions tests/integration-tests/src/commonTest/kotlin/test/FetchPolicyTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,36 @@ class FetchPolicyTest {
assertNotNull(response.data)
assertTrue(response.isFromCache)

// Clear the store and offer a malformed response, we should get a composite error
store.clearAll()
mockServer.enqueue("malformed")
assertIs<ApolloCompositeException>(
apolloClient.query(query).execute().exception
)
}

@Test
fun cacheFirstExecuteThrowing() = runTest(before = { setUp() }, after = { tearDown() }) {
@Suppress("DEPRECATION")
apolloClient = apolloClient.newBuilder().foldFetchExceptions(true).throwOnException(true).build()
val query = HeroNameQuery()
val data = HeroNameQuery.Data(HeroNameQuery.Hero("R2-D2"))
mockServer.enqueue(query, data)

// First query should hit the network and save in cache
var response = apolloClient.query(query)
.fetchPolicy(FetchPolicy.NetworkFirst)
.execute()

assertNotNull(response.data)
assertFalse(response.isFromCache)

// Second query should only hit the cache
response = apolloClient.query(query).execute()

assertNotNull(response.data)
assertTrue(response.isFromCache)

// Clear the store and offer a malformed response, we should get a composite error
store.clearAll()
mockServer.enqueue("malformed")
Expand All @@ -97,8 +127,9 @@ class FetchPolicyTest {
}
}


@Test
fun cacheFirstThrowing() = runTest(before = { setUp() }, after = { tearDown() }) {
fun cacheFirstToFlowThrowing() = runTest(before = { setUp() }, after = { tearDown() }) {
@Suppress("DEPRECATION")
apolloClient = apolloClient.newBuilder().foldFetchExceptions(true).throwOnException(true).build()

Expand Down Expand Up @@ -168,6 +199,44 @@ class FetchPolicyTest {
assertNotNull(response.data)
assertTrue(response.isFromCache)

// Network error and no cache -> we should get an error
mockServer.enqueue("malformed")
store.clearAll()
assertIs<ApolloCompositeException>(
call.execute().exception
)
}

@Test
fun networkFirstExecuteThrowing() = runTest(before = { setUp() }, after = { tearDown() }) {
@Suppress("DEPRECATION")
apolloClient = apolloClient.newBuilder().foldFetchExceptions(true).throwOnException(true).build()
val query = HeroNameQuery()
val data = HeroNameQuery.Data(HeroNameQuery.Hero("R2-D2"))

val call = apolloClient.query(query).fetchPolicy(FetchPolicy.NetworkFirst)

// First query should hit the network and save in cache
mockServer.enqueue(query, data)
var response = call.execute()

assertNotNull(response.data)
assertFalse(response.isFromCache)

// Now data is cached but it shouldn't be used since network will go through
mockServer.enqueue(query, data)
response = call.execute()

assertNotNull(response.data)
assertFalse(response.isFromCache)

// Network error -> we should hit now the cache
mockServer.enqueue("malformed")
response = call.execute()

assertNotNull(response.data)
assertTrue(response.isFromCache)

// Network error and no cache -> we should get an error
mockServer.enqueue("malformed")
store.clearAll()
Expand All @@ -180,7 +249,7 @@ class FetchPolicyTest {
}

@Test
fun networkFirstThrowing() = runTest(before = { setUp() }, after = { tearDown() }) {
fun networkFirstToFlowThrowing() = runTest(before = { setUp() }, after = { tearDown() }) {
@Suppress("DEPRECATION")
apolloClient = apolloClient.newBuilder().foldFetchExceptions(true).throwOnException(true).build()

Expand Down Expand Up @@ -233,7 +302,6 @@ class FetchPolicyTest {
val query = HeroNameQuery()
val data = HeroNameQuery.Data(HeroNameQuery.Hero("R2-D2"))


// First query should hit the network and save in cache
mockServer.enqueue(query, data)
var response = apolloClient.query(query).execute()
Expand Down Expand Up @@ -263,6 +331,27 @@ class FetchPolicyTest {
assertNotNull(response.data)
assertFalse(response.isFromCache)

// Offer a malformed response, it should fail
mockServer.enqueue("malformed")
assertNotNull(call.execute().exception)
}

@Test
fun networkOnlyThrowing() = runTest(before = { setUp() }, after = { tearDown() }) {
@Suppress("DEPRECATION")
apolloClient = apolloClient.newBuilder().throwOnException(true).build()
val query = HeroNameQuery()
val data = HeroNameQuery.Data(HeroNameQuery.Hero("R2-D2"))

val call = apolloClient.query(query).fetchPolicy(FetchPolicy.NetworkOnly)

// First query should hit the network and save in cache
mockServer.enqueue(query, data)
val response = call.execute()

assertNotNull(response.data)
assertFalse(response.isFromCache)

// Offer a malformed response, it should fail
mockServer.enqueue("malformed")
try {
Expand All @@ -282,9 +371,9 @@ class FetchPolicyTest {
// Initial state: everything fails
// Cache Error + Network Error => Error
mockServer.enqueue(statusCode = 500)
assertFailsWith(ApolloCompositeException::class) {
apolloClient.query(query).fetchPolicy(FetchPolicy.CacheAndNetwork).execute()
}
assertIs<ApolloCompositeException>(
apolloClient.query(query).fetchPolicy(FetchPolicy.CacheAndNetwork).execute().exception
)

// Make the network return something
// Cache Error + Network Success => 2 responses
Expand Down
Loading

0 comments on commit 929aef6

Please sign in to comment.