Skip to content

Commit 6fdd1dd

Browse files
committed
Bug 2044193 - Exposed exceptions from LLM provider chooser
1 parent db79000 commit 6fdd1dd

2 files changed

Lines changed: 62 additions & 3 deletions

File tree

mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/llm/ext/MlpaTokenProvider.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ package org.mozilla.fenix.components.llm.ext
77
import mozilla.components.lib.llm.mlpa.MlpaTokenProvider
88
import mozilla.components.lib.llm.mlpa.service.AuthorizationToken
99

10-
internal class AllTokenProvidersFailed : IllegalStateException("All token providers failed to retrieve a token.")
1110
internal class FxaMissingAccessToken : IllegalStateException("Unable to get access token from FxaAccessTokenProvider")
1211

1312
/** Convenience interface for getting an fxa access token. */
@@ -17,13 +16,20 @@ fun interface FxaAccessTokenProvider {
1716
}
1817

1918
/** Implementation of [MlpaTokenProvider] that takes the first successful token it receives.
19+
* When every provider fails, the last provider's failure is propagated as-is so its
20+
* provider-specific error reaches logs, telemetry, and error services.
2021
* @param tokenProviders a list of [MlpaTokenProvider].
2122
* @return an [MlpaTokenProvider].
2223
*/
2324
fun MlpaTokenProvider.Companion.choose(vararg tokenProviders: MlpaTokenProvider) = MlpaTokenProvider {
25+
var lastResult = Result.failure<AuthorizationToken>(
26+
IllegalStateException("choose() called with no token providers"),
27+
)
2428
tokenProviders.firstNotNullOfOrNull { provider ->
25-
provider.fetchToken().takeIf { it.isSuccess }
26-
} ?: Result.failure(AllTokenProvidersFailed())
29+
provider.fetchToken()
30+
.also { lastResult = it }
31+
.takeIf { it.isSuccess }
32+
} ?: lastResult
2733
}
2834

2935
/** Implementation of [MlpaTokenProvider] that tries to fetch an fxa access token.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
package org.mozilla.fenix.components.llm.ext
6+
7+
import kotlinx.coroutines.test.runTest
8+
import mozilla.components.lib.llm.mlpa.MlpaTokenProvider
9+
import mozilla.components.lib.llm.mlpa.service.AuthorizationToken
10+
import org.junit.Assert.assertEquals
11+
import org.junit.Assert.assertSame
12+
import org.junit.Assert.assertTrue
13+
import org.junit.Assert.fail
14+
import org.junit.Test
15+
16+
class MlpaTokenProviderTest {
17+
18+
@Test
19+
fun `GIVEN the first provider succeeds WHEN fetching THEN its token is returned`() = runTest {
20+
val expected = AuthorizationToken.Integrity("first")
21+
val provider = MlpaTokenProvider.choose(
22+
{ Result.success(expected) },
23+
{ Result.failure(IllegalStateException("integrity failed")) },
24+
)
25+
26+
assertEquals(expected, provider.fetchToken().getOrThrow() as AuthorizationToken.Integrity)
27+
}
28+
29+
@Test
30+
fun `GIVEN the first provider fails WHEN fetching THEN the next provider's token is returned`() = runTest {
31+
val expected = AuthorizationToken.Integrity("second")
32+
val provider = MlpaTokenProvider.choose(
33+
{ Result.failure(FxaMissingAccessToken()) },
34+
{ Result.success(expected) },
35+
)
36+
37+
assertEquals(expected, provider.fetchToken().getOrThrow())
38+
}
39+
40+
@Test
41+
fun `GIVEN all providers fail WHEN fetching THEN the last provider's failure is propagated`() = runTest {
42+
val terminal = IllegalStateException("integrity failed")
43+
val provider = MlpaTokenProvider.choose(
44+
{ Result.failure(FxaMissingAccessToken()) },
45+
{ Result.failure(terminal) },
46+
)
47+
48+
val result = provider.fetchToken()
49+
50+
assertTrue(result.isFailure)
51+
assertSame(terminal, result.exceptionOrNull())
52+
}
53+
}

0 commit comments

Comments
 (0)