Skip to content

Commit 0314458

Browse files
authored
fix(authenticator): Improve error messaging if auth configuration is invalid/incomplete (#112)
1 parent 9da6be9 commit 0314458

File tree

4 files changed

+60
-17
lines changed

4 files changed

+60
-17
lines changed

authenticator/src/main/java/com/amplifyframework/ui/authenticator/AuthenticatorViewModel.kt

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,13 @@ import com.amplifyframework.ui.authenticator.forms.setFieldError
6060
import com.amplifyframework.ui.authenticator.states.BaseStateImpl
6161
import com.amplifyframework.ui.authenticator.states.StepStateFactory
6262
import com.amplifyframework.ui.authenticator.util.AmplifyResult
63+
import com.amplifyframework.ui.authenticator.util.AuthConfigurationResult
6364
import com.amplifyframework.ui.authenticator.util.AuthProvider
6465
import com.amplifyframework.ui.authenticator.util.AuthenticatorMessage
6566
import com.amplifyframework.ui.authenticator.util.CannotSendCodeMessage
6667
import com.amplifyframework.ui.authenticator.util.CodeSentMessage
6768
import com.amplifyframework.ui.authenticator.util.ExpiredCodeMessage
69+
import com.amplifyframework.ui.authenticator.util.InvalidConfigurationException
6870
import com.amplifyframework.ui.authenticator.util.InvalidLoginMessage
6971
import com.amplifyframework.ui.authenticator.util.MissingConfigurationException
7072
import com.amplifyframework.ui.authenticator.util.NetworkErrorMessage
@@ -121,15 +123,20 @@ internal class AuthenticatorViewModel(
121123
this.configuration = configuration
122124

123125
viewModelScope.launch {
124-
val authConfig = authProvider.getConfiguration()
125-
126-
if (authConfig == null) {
127-
handleGeneralFailure(MissingConfigurationException())
128-
return@launch
126+
when (val authConfigResult = authProvider.getConfiguration()) {
127+
is AuthConfigurationResult.Invalid -> {
128+
handleGeneralFailure(
129+
InvalidConfigurationException(authConfigResult.message, authConfigResult.cause)
130+
)
131+
return@launch
132+
}
133+
AuthConfigurationResult.Missing -> {
134+
handleGeneralFailure(MissingConfigurationException())
135+
return@launch
136+
}
137+
is AuthConfigurationResult.Valid -> authConfiguration = authConfigResult.configuration
129138
}
130139

131-
authConfiguration = authConfig
132-
133140
stateFactory = StepStateFactory(
134141
authConfiguration,
135142
buildForm(configuration.signUpForm),

authenticator/src/main/java/com/amplifyframework/ui/authenticator/util/AuthProvider.kt

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,13 @@ internal interface AuthProvider {
101101

102102
fun authStatusEvents(): Flow<HubEvent<*>>
103103

104-
suspend fun getConfiguration(): AmplifyAuthConfiguration?
104+
suspend fun getConfiguration(): AuthConfigurationResult
105+
}
106+
107+
internal sealed interface AuthConfigurationResult {
108+
data class Valid(val configuration: AmplifyAuthConfiguration) : AuthConfigurationResult
109+
data class Invalid(val message: String, val cause: Exception? = null) : AuthConfigurationResult
110+
object Missing : AuthConfigurationResult
105111
}
106112

107113
/**
@@ -246,8 +252,8 @@ internal class RealAuthProvider : AuthProvider {
246252
awaitClose { Amplify.Hub.unsubscribe(token) }
247253
}
248254

249-
override suspend fun getConfiguration(): AmplifyAuthConfiguration? {
250-
val authConfigJSON = getCognitoPlugin()?.getPluginConfiguration() ?: return null
255+
override suspend fun getConfiguration(): AuthConfigurationResult {
256+
val authConfigJSON = getCognitoPlugin()?.getPluginConfiguration() ?: return AuthConfigurationResult.Missing
251257
try {
252258
val innerJSON = authConfigJSON
253259
.getJSONObject("Auth")
@@ -292,14 +298,16 @@ internal class RealAuthProvider : AuthProvider {
292298
}
293299
}.toSet()
294300

295-
return AmplifyAuthConfiguration(
296-
signInMethod,
297-
signUpAttributeList,
298-
passwordCriteria,
299-
verificationMechanisms
301+
return AuthConfigurationResult.Valid(
302+
AmplifyAuthConfiguration(
303+
signInMethod,
304+
signUpAttributeList,
305+
passwordCriteria,
306+
verificationMechanisms
307+
)
300308
)
301309
} catch (e: JSONException) {
302-
return null
310+
return AuthConfigurationResult.Invalid(e.message ?: "Auth configuration is not valid", e)
303311
}
304312
}
305313

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,13 @@ class MissingConfigurationException : AuthException(
2626
"Make sure the Auth plugin is added and Amplify.configure is called. See " +
2727
"https://docs.amplify.aws/lib/auth/getting-started/q/platform/android/ for details"
2828
)
29+
30+
/**
31+
* Exception that is passed to the errorContent if the configuration passed to the auth plugin is missing a required
32+
* property or has an invalid property
33+
*/
34+
class InvalidConfigurationException(message: String, cause: Exception?) : AuthException(
35+
message = message,
36+
recoverySuggestion = "Check that the configuration passed to Amplify.configure has all required fields",
37+
cause = cause
38+
)

authenticator/src/test/java/com/amplifyframework/ui/authenticator/AuthenticatorViewModelTest.kt

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import app.cash.turbine.test
2020
import com.amplifyframework.auth.result.step.AuthSignInStep
2121
import com.amplifyframework.ui.authenticator.enums.AuthenticatorStep
2222
import com.amplifyframework.ui.authenticator.util.AmplifyResult
23+
import com.amplifyframework.ui.authenticator.util.AuthConfigurationResult
2324
import com.amplifyframework.ui.authenticator.util.AuthProvider
2425
import com.amplifyframework.ui.testing.CoroutineTestRule
2526
import io.kotest.matchers.shouldBe
@@ -29,6 +30,7 @@ import io.mockk.mockk
2930
import kotlinx.coroutines.ExperimentalCoroutinesApi
3031
import kotlinx.coroutines.test.advanceUntilIdle
3132
import kotlinx.coroutines.test.runTest
33+
import org.junit.Before
3234
import org.junit.Rule
3335
import org.junit.Test
3436

@@ -46,6 +48,11 @@ class AuthenticatorViewModelTest {
4648

4749
private val viewModel = AuthenticatorViewModel(application, authProvider)
4850

51+
@Before
52+
fun setup() {
53+
coEvery { authProvider.getConfiguration() } returns AuthConfigurationResult.Valid(mockk(relaxed = true))
54+
}
55+
4956
//region start tests
5057

5158
@Test
@@ -62,7 +69,18 @@ class AuthenticatorViewModelTest {
6269

6370
@Test
6471
fun `missing configuration results in an error`() = runTest {
65-
coEvery { authProvider.getConfiguration() } returns null
72+
coEvery { authProvider.getConfiguration() } returns AuthConfigurationResult.Missing
73+
74+
viewModel.start(mockAuthConfiguration())
75+
advanceUntilIdle()
76+
77+
coVerify(exactly = 0) { authProvider.fetchAuthSession() }
78+
viewModel.currentStep shouldBe AuthenticatorStep.Error
79+
}
80+
81+
@Test
82+
fun `invalid configuration results in an error`() = runTest {
83+
coEvery { authProvider.getConfiguration() } returns AuthConfigurationResult.Invalid("Invalid")
6684

6785
viewModel.start(mockAuthConfiguration())
6886
advanceUntilIdle()

0 commit comments

Comments
 (0)