From f316f0343845813ff6c1026c4a3dde1df52cbd1a Mon Sep 17 00:00:00 2001 From: Sunil Timalsina Date: Thu, 27 Oct 2022 13:11:54 -0700 Subject: [PATCH 01/36] refactor feature testing fw --- .../generators/SerializationTools.kt | 60 +++++++++++++++++++ .../utilities/AuthOptionsFactory.kt | 13 +--- 2 files changed, 61 insertions(+), 12 deletions(-) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/SerializationTools.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/SerializationTools.kt index bbb675a420..e0c63f6eb7 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/SerializationTools.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/SerializationTools.kt @@ -81,6 +81,66 @@ internal fun AuthState.exportJson() { println("Serialized can be reversed = ${reverse.serialize() == result}") } +internal fun List.exportToMd() { + val outputStream = FileOutputStream("testSuite.md") + val writer = outputStream.bufferedWriter() + val jsonFormat = Json { prettyPrint = true } + + groupBy { it.api.name } + .forEach { + with(writer) { + newLine() + write("# ${it.key.name}") // Header 1 + newLine() + it.value.forEach { + newLine() + write("## Case: *${it.description}*") + newLine() + // Preconditions (GIVEN) + write("### Preconditions") // Header 2 + newLine() + write("- **Amplify Configuration**: ${it.preConditions.`amplify-configuration`}") + newLine() + write("- **Initial State:** ${it.preConditions.state}") + newLine() + write("- **Mock Responses:** ") + printCodeBlock { + if (it.preConditions.mockedResponses.isEmpty()) "[]" else + jsonFormat.encodeToString(it.preConditions.mockedResponses) + } + + // Parameters (WHEN) + write("### Input") + newLine() + write("- **params:**") + printCodeBlock { + jsonFormat.encodeToString(it.api.params) + } + write("- **options:**") + printCodeBlock { jsonFormat.encodeToString(it.api.options) } + + // Then + write("### Validations") + newLine() + it.validations.forEach { + printCodeBlock { jsonFormat.encodeToString(it) } + } + } + } + } + writer.flush() +} + +private fun BufferedWriter.printCodeBlock(blob: () -> String) { + newLine() + write("```json") + newLine() + write(blob.invoke()) + newLine() + write("```") + newLine() +} + /** * Generates a md file with all the test cases formatted. */ diff --git a/aws-auth-cognito/src/test/java/featureTest/utilities/AuthOptionsFactory.kt b/aws-auth-cognito/src/test/java/featureTest/utilities/AuthOptionsFactory.kt index 449a02fcc3..946e3ca153 100644 --- a/aws-auth-cognito/src/test/java/featureTest/utilities/AuthOptionsFactory.kt +++ b/aws-auth-cognito/src/test/java/featureTest/utilities/AuthOptionsFactory.kt @@ -3,11 +3,8 @@ package featureTest.utilities import com.amplifyframework.auth.AuthUserAttribute import com.amplifyframework.auth.AuthUserAttributeKey import com.amplifyframework.auth.cognito.featuretest.AuthAPI -import com.amplifyframework.auth.cognito.featuretest.AuthAPI.confirmSignIn -import com.amplifyframework.auth.cognito.featuretest.AuthAPI.deleteUser import com.amplifyframework.auth.cognito.featuretest.AuthAPI.resetPassword import com.amplifyframework.auth.cognito.featuretest.AuthAPI.signIn -import com.amplifyframework.auth.cognito.featuretest.AuthAPI.signOut import com.amplifyframework.auth.cognito.featuretest.AuthAPI.signUp import com.amplifyframework.auth.options.AuthConfirmResetPasswordOptions import com.amplifyframework.auth.options.AuthConfirmSignInOptions @@ -23,7 +20,6 @@ import com.amplifyframework.auth.options.AuthUpdateUserAttributesOptions import com.amplifyframework.auth.options.AuthWebUISignInOptions import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive -import kotlinx.serialization.json.booleanOrNull /** * Factory to create specialized options object for the top level APIs @@ -49,7 +45,7 @@ object AuthOptionsFactory { signIn -> AuthSignInOptions.defaults() AuthAPI.signInWithSocialWebUI -> AuthWebUISignInOptions.builder().build() AuthAPI.signInWithWebUI -> AuthWebUISignInOptions.builder().build() - AuthAPI.signOut -> getSignOutOptions(optionsData) + AuthAPI.signOut -> AuthSignOutOptions.builder().build() AuthAPI.updatePassword -> TODO() AuthAPI.updateUserAttribute -> AuthUpdateUserAttributeOptions.defaults() AuthAPI.updateUserAttributes -> AuthUpdateUserAttributesOptions.defaults() @@ -67,11 +63,4 @@ object AuthOptionsFactory { AuthUserAttribute(AuthUserAttributeKey.custom(it.key), (it.value as JsonPrimitive).content) } ).build() - - private fun getSignOutOptions(optionsData: JsonObject): AuthSignOutOptions { - val globalSignOutData = (optionsData["globalSignOut"] as JsonPrimitive).booleanOrNull ?: false - return AuthSignOutOptions.builder() - .globalSignOut(globalSignOutData) - .build() - } } From 28317735b93792add54902696584387492c345a4 Mon Sep 17 00:00:00 2001 From: Sunil Timalsina Date: Sat, 29 Oct 2022 18:46:02 -0700 Subject: [PATCH 02/36] documentation and move verify to test --- .../auth/cognito/featuretest/generators/SerializationTools.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/SerializationTools.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/SerializationTools.kt index e0c63f6eb7..3582b3d949 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/SerializationTools.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/SerializationTools.kt @@ -81,6 +81,9 @@ internal fun AuthState.exportJson() { println("Serialized can be reversed = ${reverse.serialize() == result}") } +/** + * Generates a md file with all the test cases formatted. + */ internal fun List.exportToMd() { val outputStream = FileOutputStream("testSuite.md") val writer = outputStream.bufferedWriter() From aeaf9b22294a0e365d7ca39d3e2d7f060364f3aa Mon Sep 17 00:00:00 2001 From: Banji Jolaoso Date: Wed, 2 Nov 2022 12:09:47 -0700 Subject: [PATCH 03/36] added fetchAuthSession test case generator --- .../AWSCognitoAuthPluginFeatureTest.kt | 7 + .../featuretest/generators/JsonGenerator.kt | 4 +- .../FetchAuthSessionTestCaseGenerator.kt | 112 ++++++++++++++++ .../featureTest/utilities/APICaptorFactory.kt | 120 ++++++++++++++++++ .../utilities/AuthOptionsFactory.kt | 17 ++- 5 files changed, 258 insertions(+), 2 deletions(-) create mode 100644 aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt create mode 100644 aws-auth-cognito/src/test/java/featureTest/utilities/APICaptorFactory.kt diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/AWSCognitoAuthPluginFeatureTest.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/AWSCognitoAuthPluginFeatureTest.kt index 87f95f6d18..f4ffc60a6c 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/AWSCognitoAuthPluginFeatureTest.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/AWSCognitoAuthPluginFeatureTest.kt @@ -123,6 +123,13 @@ class AWSCognitoAuthPluginFeatureTest(private val testCase: FeatureTestCase) { @Test fun api_feature_test() { + + mockkObject(AuthHelper) + coEvery { AuthHelper.getSecretHash(any(), any(), any()) } returns "a hash" + + mockkStatic("com.amplifyframework.auth.cognito.AWSCognitoAuthSessionKt") + every { any().isValid() } returns true + // GIVEN mockAndroidAPIs() feature.preConditions.mockedResponses.forEach(cognitoMockFactory::mock) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/JsonGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/JsonGenerator.kt index 82aa69c1d5..0425956220 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/JsonGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/JsonGenerator.kt @@ -4,6 +4,7 @@ import com.amplifyframework.auth.cognito.featuretest.FeatureTestCase import com.amplifyframework.auth.cognito.featuretest.generators.authstategenerators.AuthStateJsonGenerator import com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators.ConfirmSignInTestCaseGenerator import com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators.DeleteUserTestCaseGenerator +import com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators.FetchAuthSessionTestCaseGenerator import com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators.ResetPasswordTestCaseGenerator import com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators.SignInTestCaseGenerator import com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators.SignOutTestCaseGenerator @@ -25,7 +26,8 @@ object JsonGenerator { SignInTestCaseGenerator, SignOutTestCaseGenerator, ConfirmSignInTestCaseGenerator, - DeleteUserTestCaseGenerator + DeleteUserTestCaseGenerator, + FetchAuthSessionTestCaseGenerator, ) fun generate() { diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt new file mode 100644 index 0000000000..737ca70c8b --- /dev/null +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt @@ -0,0 +1,112 @@ +package com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators + +import aws.sdk.kotlin.services.cognitoidentityprovider.model.NotAuthorizedException +import com.amazonaws.auth.CognitoCredentialsProvider +import com.amplifyframework.auth.cognito.AWSCognitoAuthSession +import com.amplifyframework.auth.cognito.AWSCognitoUserPoolTokens +import com.amplifyframework.auth.cognito.featuretest.API +import com.amplifyframework.auth.cognito.featuretest.AuthAPI +import com.amplifyframework.auth.cognito.featuretest.CognitoType +import com.amplifyframework.auth.cognito.featuretest.ExpectationShapes +import com.amplifyframework.auth.cognito.featuretest.FeatureTestCase +import com.amplifyframework.auth.cognito.featuretest.MockResponse +import com.amplifyframework.auth.cognito.featuretest.PreConditions +import com.amplifyframework.auth.cognito.featuretest.ResponseType +import com.amplifyframework.auth.cognito.featuretest.generators.SerializableProvider +import com.amplifyframework.auth.cognito.featuretest.generators.authstategenerators.AuthStateJsonGenerator +import com.amplifyframework.auth.cognito.featuretest.generators.toJsonElement +import com.amplifyframework.auth.exceptions.InvalidStateException +import com.amplifyframework.auth.options.AuthFetchSessionOptions +import com.amplifyframework.auth.result.AuthSessionResult +import com.amplifyframework.statemachine.codegen.data.AWSCredentials +import kotlinx.serialization.json.JsonObject + +object FetchAuthSessionTestCaseGenerator : SerializableProvider { + + private val expectedSuccess = AWSCognitoAuthSession( + true, + identityIdResult = AWSCognitoAuthSession.getIdentityIdResult("someIdentityId"), + awsCredentialsResult = AuthSessionResult.success(com.amplifyframework.auth.AWSCredentials("someid","someid")), + userSubResult = AuthSessionResult.success("userId"), + userPoolTokensResult = AuthSessionResult.success(AWSCognitoUserPoolTokens( + accessToken = AuthStateJsonGenerator.dummyToken, + idToken = AuthStateJsonGenerator.dummyToken, + refreshToken = AuthStateJsonGenerator.dummyToken) + ) + ).toJsonElement() +/* + mapOf( + "isSignedIn" to true, + "identityIdResult" to mapOf("value" to "someid"), + "awsCredentialsResult" to mapOf("value" to "someid"), + "userSubResult" to mapOf("value" to "someid"), + "userPoolTokensResult" to AuthSessionResult.success( + AWSCognitoUserPoolTokens( + accessToken = AuthStateJsonGenerator.dummyToken, + idToken = AuthStateJsonGenerator.dummyToken, + refreshToken = AuthStateJsonGenerator.dummyToken + ) + ) + ).toJsonElement()*/ + + + private val apiReturnValidation = ExpectationShapes.Amplify( + AuthAPI.fetchAuthSession, + ResponseType.Success, + expectedSuccess, + ) + + private val baseCase = FeatureTestCase( + description = "Test that API is called with given payload and returns successful data", + preConditions = PreConditions( + "authconfiguration.json", + "SignedIn_SessionEstablished.json", + mockedResponses = listOf() + ), + api = API( + name = AuthAPI.fetchAuthSession, + params = JsonObject(emptyMap()), + JsonObject(emptyMap()) + ), + validations = listOf(apiReturnValidation) + ) + + + private val successCase: FeatureTestCase = baseCase.copy( + description = "AuthSession object is successfully returned", + preConditions = baseCase.preConditions, + validations = baseCase.validations.plus(apiReturnValidation) + ) + + private val refreshSuccessCase: FeatureTestCase = baseCase.copy( + description = "AuthSession object is successfully returned after refresh", + preConditions = baseCase.preConditions, + api = API( + name = AuthAPI.fetchAuthSession, + params = JsonObject(emptyMap()), + options = mapOf("forceRefresh" to true).toJsonElement(), + ), + validations = baseCase.validations.plus(apiReturnValidation) + ) + private val errorCase: FeatureTestCase + get() { + val notAuthorizedErrorResponse = NotAuthorizedException.invoke { } + return baseCase.copy( + description = "AuthException is thrown when fetchAuthSession API call fails", + preConditions = baseCase.preConditions.copy( + state = "SignedOut_Configured.json" + ), + validations = listOf( + ExpectationShapes.Amplify( + AuthAPI.fetchAuthSession, + ResponseType.Failure, + com.amplifyframework.auth.exceptions.NotAuthorizedException( + cause = notAuthorizedErrorResponse + ).toJsonElement() + ) + ) + ) + } + + override val serializables: List = listOf(baseCase, errorCase, successCase, refreshSuccessCase) +} \ No newline at end of file diff --git a/aws-auth-cognito/src/test/java/featureTest/utilities/APICaptorFactory.kt b/aws-auth-cognito/src/test/java/featureTest/utilities/APICaptorFactory.kt new file mode 100644 index 0000000000..8472916a84 --- /dev/null +++ b/aws-auth-cognito/src/test/java/featureTest/utilities/APICaptorFactory.kt @@ -0,0 +1,120 @@ +/* + * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package featureTest.utilities + +import com.amplifyframework.auth.AuthException +import com.amplifyframework.auth.AuthSession +import com.amplifyframework.auth.cognito.featuretest.AuthAPI +import com.amplifyframework.auth.cognito.featuretest.ExpectationShapes +import com.amplifyframework.auth.cognito.featuretest.ResponseType +import com.amplifyframework.auth.result.AuthResetPasswordResult +import com.amplifyframework.auth.result.AuthSignInResult +import com.amplifyframework.auth.result.AuthSignOutResult +import com.amplifyframework.auth.result.AuthSignUpResult +import com.amplifyframework.core.Action +import com.amplifyframework.core.Consumer +import io.mockk.CapturingSlot +import io.mockk.every +import io.mockk.mockk +import io.mockk.slot +import java.util.concurrent.CountDownLatch + +/** + * Factory with association of results captor to top level APIs + */ +class APICaptorFactory( + private val authApi: ExpectationShapes.Amplify, + private val latch: CountDownLatch, // ToDo: Remove this param +) { + companion object { + val onSuccess = mapOf( + AuthAPI.resetPassword to mockk>(), + AuthAPI.signUp to mockk>(), + AuthAPI.signIn to mockk>(), + AuthAPI.deleteUser to mockk(), + AuthAPI.fetchAuthSession to mockk() + ) + val onError = mockk>() + val onComplete = mapOf( + AuthAPI.signOut to mockk>() + ) + val successCaptors: MutableMap> = mutableMapOf() + val completeCaptors: MutableMap> = mutableMapOf() + val errorCaptor = slot() + val actionCaptor = slot>().apply { + captured = emptyMap() + isCaptured = true + } + } + + init { + successCaptors.clear() + completeCaptors.clear() + if (authApi.responseType == ResponseType.Success) setupOnSuccess() + if (authApi.responseType == ResponseType.Complete) setupOnComplete() + else setupOnError() + } + + private fun setupOnSuccess() { + when (val apiName = authApi.apiName) { + AuthAPI.resetPassword -> { + val resultCaptor = slot() + val consumer = onSuccess[apiName] as Consumer + every { consumer.accept(capture(resultCaptor)) } answers { latch.countDown() } + successCaptors[apiName] = resultCaptor + } + AuthAPI.signUp -> { + val resultCaptor = slot() + val consumer = onSuccess[apiName] as Consumer + every { consumer.accept(capture(resultCaptor)) } answers { latch.countDown() } + successCaptors[apiName] = resultCaptor + } + AuthAPI.signIn -> { + val resultCaptor = slot() + val consumer = onSuccess[apiName] as Consumer + every { consumer.accept(capture(resultCaptor)) } answers { latch.countDown() } + successCaptors[apiName] = resultCaptor + } + AuthAPI.deleteUser -> { + val consumer = onSuccess[apiName] as Action + every { consumer.call() } answers { latch.countDown() } + successCaptors[apiName] = actionCaptor + } + AuthAPI.fetchAuthSession -> { + val consumer = onSuccess[apiName] as Action + every { consumer.call() } answers { latch.countDown() } + successCaptors[apiName] = actionCaptor + } + else -> throw Error("onSuccess for $authApi is not defined!") + } + } + + private fun setupOnComplete() { + when (val apiName = authApi.apiName) { + AuthAPI.signOut -> { + val resultCaptor = slot() + val consumer = onComplete[apiName] as Consumer + every { consumer.accept(capture(resultCaptor)) } answers { latch.countDown() } + completeCaptors[apiName] = resultCaptor + } + else -> throw Error("onComplete for $authApi is not defined!") + } + } + + private fun setupOnError() { + every { onError.accept(capture(errorCaptor)) } answers { latch.countDown() } + } +} diff --git a/aws-auth-cognito/src/test/java/featureTest/utilities/AuthOptionsFactory.kt b/aws-auth-cognito/src/test/java/featureTest/utilities/AuthOptionsFactory.kt index 946e3ca153..e8ef22486f 100644 --- a/aws-auth-cognito/src/test/java/featureTest/utilities/AuthOptionsFactory.kt +++ b/aws-auth-cognito/src/test/java/featureTest/utilities/AuthOptionsFactory.kt @@ -9,6 +9,7 @@ import com.amplifyframework.auth.cognito.featuretest.AuthAPI.signUp import com.amplifyframework.auth.options.AuthConfirmResetPasswordOptions import com.amplifyframework.auth.options.AuthConfirmSignInOptions import com.amplifyframework.auth.options.AuthConfirmSignUpOptions +import com.amplifyframework.auth.options.AuthFetchSessionOptions import com.amplifyframework.auth.options.AuthResendSignUpCodeOptions import com.amplifyframework.auth.options.AuthResendUserAttributeConfirmationCodeOptions import com.amplifyframework.auth.options.AuthResetPasswordOptions @@ -33,7 +34,7 @@ object AuthOptionsFactory { AuthAPI.confirmSignUp -> AuthConfirmSignUpOptions.defaults() AuthAPI.confirmUserAttribute -> null AuthAPI.deleteUser -> null - AuthAPI.fetchAuthSession -> null + AuthAPI.fetchAuthSession -> getFetchAuthSessionOptions(optionsData) AuthAPI.fetchDevices -> null AuthAPI.fetchUserAttributes -> TODO() AuthAPI.forgetDevice -> TODO() @@ -63,4 +64,18 @@ object AuthOptionsFactory { AuthUserAttribute(AuthUserAttributeKey.custom(it.key), (it.value as JsonPrimitive).content) } ).build() + + private fun getSignOutOptions(optionsData: JsonObject): AuthSignOutOptions { + val globalSignOutData = (optionsData["globalSignOut"] as JsonPrimitive).booleanOrNull ?: false + return AuthSignOutOptions.builder() + .globalSignOut(globalSignOutData) + .build() + } + + private fun getFetchAuthSessionOptions(optionsData: JsonObject): AuthFetchSessionOptions { + val refresh = (optionsData["forceRefresh"] as JsonPrimitive).booleanOrNull ?: false + return AuthFetchSessionOptions.builder() + .forceRefresh(refresh) + .build() + } } From 0a8911ea51728803c019db1fde112c01821045b0 Mon Sep 17 00:00:00 2001 From: Sunil Timalsina Date: Wed, 2 Nov 2022 14:31:26 -0700 Subject: [PATCH 04/36] add new default serializer and fix options --- .../generators/SerializationTools.kt | 88 +++++-------------- .../FetchAuthSessionTestCaseGenerator.kt | 14 +-- .../utilities/AuthOptionsFactory.kt | 8 +- 3 files changed, 34 insertions(+), 76 deletions(-) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/SerializationTools.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/SerializationTools.kt index 3582b3d949..65ce778de0 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/SerializationTools.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/SerializationTools.kt @@ -17,6 +17,9 @@ package com.amplifyframework.auth.cognito.featuretest.generators import aws.sdk.kotlin.services.cognitoidentity.model.CognitoIdentityException import aws.sdk.kotlin.services.cognitoidentityprovider.model.CognitoIdentityProviderException +import aws.sdk.kotlin.services.cognitoidentityprovider.model.DeliveryMediumType +import aws.sdk.kotlin.services.cognitoidentityprovider.model.OAuthFlowType +import aws.smithy.kotlin.runtime.time.Instant import com.amplifyframework.auth.AuthException import com.amplifyframework.auth.cognito.featuretest.FeatureTestCase import com.amplifyframework.auth.cognito.featuretest.serializers.CognitoIdentityExceptionSerializer @@ -24,6 +27,7 @@ import com.amplifyframework.auth.cognito.featuretest.serializers.CognitoIdentity import com.amplifyframework.auth.cognito.featuretest.serializers.deserializeToAuthState import com.amplifyframework.auth.cognito.featuretest.serializers.serialize import com.amplifyframework.statemachine.codegen.states.AuthState +import com.amplifyframework.testutils.random.RandomString import com.google.gson.Gson import java.io.BufferedWriter import java.io.File @@ -36,6 +40,12 @@ import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonNull import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive +import kotlin.reflect.KClass +import kotlin.reflect.KType +import kotlin.reflect.KVisibility +import kotlin.reflect.full.declaredFunctions +import kotlin.reflect.full.declaredMemberProperties +import kotlin.reflect.full.memberProperties const val basePath = "aws-auth-cognito/src/test/resources/feature-test" @@ -144,69 +154,6 @@ private fun BufferedWriter.printCodeBlock(blob: () -> String) { newLine() } -/** - * Generates a md file with all the test cases formatted. - */ -internal fun List.exportToMd() { - val outputStream = FileOutputStream("testSuite.md") - val writer = outputStream.bufferedWriter() - val jsonFormat = Json { prettyPrint = true } - - groupBy { it.api.name } - .forEach { - with(writer) { - newLine() - write("# ${it.key.name}") // Header 1 - newLine() - it.value.forEach { - newLine() - write("## Case: *${it.description}*") - newLine() - // Preconditions (GIVEN) - write("### Preconditions") // Header 2 - newLine() - write("- **Amplify Configuration**: ${it.preConditions.`amplify-configuration`}") - newLine() - write("- **Initial State:** ${it.preConditions.state}") - newLine() - write("- **Mock Responses:** ") - printCodeBlock { - if (it.preConditions.mockedResponses.isEmpty()) "[]" else - jsonFormat.encodeToString(it.preConditions.mockedResponses) - } - - // Parameters (WHEN) - write("### Input") - newLine() - write("- **params:**") - printCodeBlock { - jsonFormat.encodeToString(it.api.params) - } - write("- **options:**") - printCodeBlock { jsonFormat.encodeToString(it.api.options) } - - // Then - write("### Validations") - newLine() - it.validations.forEach { - printCodeBlock { jsonFormat.encodeToString(it) } - } - } - } - } - writer.flush() -} - -private fun BufferedWriter.printCodeBlock(blob: () -> String) { - newLine() - write("```json") - newLine() - write(blob.invoke()) - newLine() - write("```") - newLine() -} - /** * Extension class to convert primitives and collections * from [https://github.com/Kotlin/kotlinx.serialization/issues/296#issuecomment-1132714147] @@ -259,6 +206,19 @@ fun gsonBasedSerializer(value: Any): JsonElement { return try { gson.fromJson(gson.toJson(value).toString(), Map::class.java).toJsonElement() } catch (ex: Exception) { - JsonPrimitive(value.toString()) + reflectionBasedSerializer(value) } } + +/** + * Final fallback to serialize by using reflection, traversing the object members and converting it to Map. + * Note that this method is similar to what Gson does. But Gson fails when there is name collision in parent and child + * classes. + */ +fun reflectionBasedSerializer(value: Any): JsonElement { + return (value::class as KClass<*>).declaredMemberProperties.filter { + it.visibility == KVisibility.PUBLIC + }.associate { + it.name to it.getter.call(value) + }.toMap().toJsonElement() +} diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt index 737ca70c8b..50caa6ff36 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt @@ -1,32 +1,27 @@ package com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators import aws.sdk.kotlin.services.cognitoidentityprovider.model.NotAuthorizedException -import com.amazonaws.auth.CognitoCredentialsProvider +import com.amplifyframework.auth.AWSCredentials import com.amplifyframework.auth.cognito.AWSCognitoAuthSession import com.amplifyframework.auth.cognito.AWSCognitoUserPoolTokens import com.amplifyframework.auth.cognito.featuretest.API import com.amplifyframework.auth.cognito.featuretest.AuthAPI -import com.amplifyframework.auth.cognito.featuretest.CognitoType import com.amplifyframework.auth.cognito.featuretest.ExpectationShapes import com.amplifyframework.auth.cognito.featuretest.FeatureTestCase -import com.amplifyframework.auth.cognito.featuretest.MockResponse import com.amplifyframework.auth.cognito.featuretest.PreConditions import com.amplifyframework.auth.cognito.featuretest.ResponseType import com.amplifyframework.auth.cognito.featuretest.generators.SerializableProvider import com.amplifyframework.auth.cognito.featuretest.generators.authstategenerators.AuthStateJsonGenerator import com.amplifyframework.auth.cognito.featuretest.generators.toJsonElement -import com.amplifyframework.auth.exceptions.InvalidStateException -import com.amplifyframework.auth.options.AuthFetchSessionOptions import com.amplifyframework.auth.result.AuthSessionResult -import com.amplifyframework.statemachine.codegen.data.AWSCredentials import kotlinx.serialization.json.JsonObject object FetchAuthSessionTestCaseGenerator : SerializableProvider { private val expectedSuccess = AWSCognitoAuthSession( - true, + isSignedIn = true, identityIdResult = AWSCognitoAuthSession.getIdentityIdResult("someIdentityId"), - awsCredentialsResult = AuthSessionResult.success(com.amplifyframework.auth.AWSCredentials("someid","someid")), + awsCredentialsResult = AuthSessionResult.success(AWSCredentials("someid","someid")), userSubResult = AuthSessionResult.success("userId"), userPoolTokensResult = AuthSessionResult.success(AWSCognitoUserPoolTokens( accessToken = AuthStateJsonGenerator.dummyToken, @@ -75,7 +70,6 @@ object FetchAuthSessionTestCaseGenerator : SerializableProvider { private val successCase: FeatureTestCase = baseCase.copy( description = "AuthSession object is successfully returned", preConditions = baseCase.preConditions, - validations = baseCase.validations.plus(apiReturnValidation) ) private val refreshSuccessCase: FeatureTestCase = baseCase.copy( @@ -86,7 +80,7 @@ object FetchAuthSessionTestCaseGenerator : SerializableProvider { params = JsonObject(emptyMap()), options = mapOf("forceRefresh" to true).toJsonElement(), ), - validations = baseCase.validations.plus(apiReturnValidation) + validations = baseCase.validations ) private val errorCase: FeatureTestCase get() { diff --git a/aws-auth-cognito/src/test/java/featureTest/utilities/AuthOptionsFactory.kt b/aws-auth-cognito/src/test/java/featureTest/utilities/AuthOptionsFactory.kt index e8ef22486f..ccb0b74493 100644 --- a/aws-auth-cognito/src/test/java/featureTest/utilities/AuthOptionsFactory.kt +++ b/aws-auth-cognito/src/test/java/featureTest/utilities/AuthOptionsFactory.kt @@ -1,3 +1,5 @@ +@file:Suppress("IMPLICIT_CAST_TO_ANY") + package featureTest.utilities import com.amplifyframework.auth.AuthUserAttribute @@ -21,11 +23,13 @@ import com.amplifyframework.auth.options.AuthUpdateUserAttributesOptions import com.amplifyframework.auth.options.AuthWebUISignInOptions import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.booleanOrNull /** * Factory to create specialized options object for the top level APIs */ object AuthOptionsFactory { + @Suppress("UNCHECKED_CAST") fun create(apiName: AuthAPI, optionsData: JsonObject): T = when (apiName) { AuthAPI.confirmResetPassword -> AuthConfirmResetPasswordOptions.defaults() resetPassword -> AuthResetPasswordOptions.defaults() @@ -46,7 +50,7 @@ object AuthOptionsFactory { signIn -> AuthSignInOptions.defaults() AuthAPI.signInWithSocialWebUI -> AuthWebUISignInOptions.builder().build() AuthAPI.signInWithWebUI -> AuthWebUISignInOptions.builder().build() - AuthAPI.signOut -> AuthSignOutOptions.builder().build() + AuthAPI.signOut -> getSignOutOptions(optionsData) AuthAPI.updatePassword -> TODO() AuthAPI.updateUserAttribute -> AuthUpdateUserAttributeOptions.defaults() AuthAPI.updateUserAttributes -> AuthUpdateUserAttributesOptions.defaults() @@ -73,7 +77,7 @@ object AuthOptionsFactory { } private fun getFetchAuthSessionOptions(optionsData: JsonObject): AuthFetchSessionOptions { - val refresh = (optionsData["forceRefresh"] as JsonPrimitive).booleanOrNull ?: false + val refresh = (optionsData["forceRefresh"] as? JsonPrimitive)?.booleanOrNull ?: false return AuthFetchSessionOptions.builder() .forceRefresh(refresh) .build() From 6401b4f74a1ce39618c6d4745779e21f6fba52d2 Mon Sep 17 00:00:00 2001 From: Sunil Timalsina Date: Thu, 3 Nov 2022 10:14:00 -0700 Subject: [PATCH 05/36] fix serializer for AuthSessionResult and success test case --- .../AWSCognitoAuthPluginFeatureTest.kt | 7 --- .../generators/SerializationTools.kt | 19 ++++---- .../AuthStateJsonGenerator.kt | 16 +++++-- .../FetchAuthSessionTestCaseGenerator.kt | 47 +++++++------------ 4 files changed, 39 insertions(+), 50 deletions(-) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/AWSCognitoAuthPluginFeatureTest.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/AWSCognitoAuthPluginFeatureTest.kt index f4ffc60a6c..87f95f6d18 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/AWSCognitoAuthPluginFeatureTest.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/AWSCognitoAuthPluginFeatureTest.kt @@ -123,13 +123,6 @@ class AWSCognitoAuthPluginFeatureTest(private val testCase: FeatureTestCase) { @Test fun api_feature_test() { - - mockkObject(AuthHelper) - coEvery { AuthHelper.getSecretHash(any(), any(), any()) } returns "a hash" - - mockkStatic("com.amplifyframework.auth.cognito.AWSCognitoAuthSessionKt") - every { any().isValid() } returns true - // GIVEN mockAndroidAPIs() feature.preConditions.mockedResponses.forEach(cognitoMockFactory::mock) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/SerializationTools.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/SerializationTools.kt index 65ce778de0..4484cd8695 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/SerializationTools.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/SerializationTools.kt @@ -17,8 +17,6 @@ package com.amplifyframework.auth.cognito.featuretest.generators import aws.sdk.kotlin.services.cognitoidentity.model.CognitoIdentityException import aws.sdk.kotlin.services.cognitoidentityprovider.model.CognitoIdentityProviderException -import aws.sdk.kotlin.services.cognitoidentityprovider.model.DeliveryMediumType -import aws.sdk.kotlin.services.cognitoidentityprovider.model.OAuthFlowType import aws.smithy.kotlin.runtime.time.Instant import com.amplifyframework.auth.AuthException import com.amplifyframework.auth.cognito.featuretest.FeatureTestCase @@ -26,13 +24,16 @@ import com.amplifyframework.auth.cognito.featuretest.serializers.CognitoIdentity import com.amplifyframework.auth.cognito.featuretest.serializers.CognitoIdentityProviderExceptionSerializer import com.amplifyframework.auth.cognito.featuretest.serializers.deserializeToAuthState import com.amplifyframework.auth.cognito.featuretest.serializers.serialize +import com.amplifyframework.auth.result.AuthSessionResult import com.amplifyframework.statemachine.codegen.states.AuthState -import com.amplifyframework.testutils.random.RandomString import com.google.gson.Gson import java.io.BufferedWriter import java.io.File import java.io.FileOutputStream import java.io.FileWriter +import kotlin.reflect.KClass +import kotlin.reflect.KVisibility +import kotlin.reflect.full.declaredMemberProperties import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonArray @@ -40,12 +41,6 @@ import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonNull import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive -import kotlin.reflect.KClass -import kotlin.reflect.KType -import kotlin.reflect.KVisibility -import kotlin.reflect.full.declaredFunctions -import kotlin.reflect.full.declaredMemberProperties -import kotlin.reflect.full.memberProperties const val basePath = "aws-auth-cognito/src/test/resources/feature-test" @@ -176,11 +171,13 @@ fun Any?.toJsonElement(): JsonElement { is Boolean -> JsonPrimitive(this) is Number -> JsonPrimitive(this) is String -> JsonPrimitive(this) + is Instant -> JsonPrimitive(this.epochSeconds) is AuthException -> toJsonElement() is CognitoIdentityProviderException -> Json.encodeToJsonElement( CognitoIdentityProviderExceptionSerializer, this ) + is AuthSessionResult<*> -> toJsonElement() is CognitoIdentityException -> Json.encodeToJsonElement(CognitoIdentityExceptionSerializer, this) else -> gsonBasedSerializer(this) } @@ -197,6 +194,10 @@ fun AuthException.toJsonElement(): JsonElement { return responseMap.toJsonElement() } +fun AuthSessionResult<*>.toJsonElement(): JsonElement { + return (if (type == AuthSessionResult.Type.SUCCESS) value else error).toJsonElement() +} + /** * Uses Gson to convert objects which cannot be serialized, * tries to convert to map of params to vals diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/authstategenerators/AuthStateJsonGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/authstategenerators/AuthStateJsonGenerator.kt index 55ce81a5d3..538d3bddb5 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/authstategenerators/AuthStateJsonGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/authstategenerators/AuthStateJsonGenerator.kt @@ -40,10 +40,16 @@ object AuthStateJsonGenerator : SerializableProvider { const val dummyToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1l" + "IiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" + const val accessKeyId = "someAccessKey" + const val secretAccessKey = "someSecretKey" + const val identityId = "someIdentityId" + const val expiration: Long = 2342134 + const val userId = "userId" + private const val username = "username" private val signedInData = SignedInData( - userId = "userId", + userId = userId, username = username, signedInDate = Date.from(Instant.ofEpochSecond(0)), signInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_SRP_AUTH), @@ -60,12 +66,12 @@ object AuthStateJsonGenerator : SerializableProvider { AuthorizationState.SessionEstablished( AmplifyCredential.UserAndIdentityPool( signedInData, - identityId = "someIdentityId", + identityId = identityId, AWSCredentials( - accessKeyId = "someAccessKey", - secretAccessKey = "someSecretKey", + accessKeyId = accessKeyId, + secretAccessKey = secretAccessKey, sessionToken = dummyToken, - expiration = 2342134 + expiration = expiration ) ) ) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt index 50caa6ff36..38b3231bf1 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt @@ -21,29 +21,23 @@ object FetchAuthSessionTestCaseGenerator : SerializableProvider { private val expectedSuccess = AWSCognitoAuthSession( isSignedIn = true, identityIdResult = AWSCognitoAuthSession.getIdentityIdResult("someIdentityId"), - awsCredentialsResult = AuthSessionResult.success(AWSCredentials("someid","someid")), - userSubResult = AuthSessionResult.success("userId"), - userPoolTokensResult = AuthSessionResult.success(AWSCognitoUserPoolTokens( - accessToken = AuthStateJsonGenerator.dummyToken, - idToken = AuthStateJsonGenerator.dummyToken, - refreshToken = AuthStateJsonGenerator.dummyToken) + awsCredentialsResult = AuthSessionResult.success( + AWSCredentials.createAWSCredentials( + AuthStateJsonGenerator.accessKeyId, + AuthStateJsonGenerator.secretAccessKey, + AuthStateJsonGenerator.dummyToken, + AuthStateJsonGenerator.expiration + ) + ), + userSubResult = AuthSessionResult.success(AuthStateJsonGenerator.userId), + userPoolTokensResult = AuthSessionResult.success( + AWSCognitoUserPoolTokens( + accessToken = AuthStateJsonGenerator.dummyToken, + idToken = AuthStateJsonGenerator.dummyToken, + refreshToken = AuthStateJsonGenerator.dummyToken + ) ) ).toJsonElement() -/* - mapOf( - "isSignedIn" to true, - "identityIdResult" to mapOf("value" to "someid"), - "awsCredentialsResult" to mapOf("value" to "someid"), - "userSubResult" to mapOf("value" to "someid"), - "userPoolTokensResult" to AuthSessionResult.success( - AWSCognitoUserPoolTokens( - accessToken = AuthStateJsonGenerator.dummyToken, - idToken = AuthStateJsonGenerator.dummyToken, - refreshToken = AuthStateJsonGenerator.dummyToken - ) - ) - ).toJsonElement()*/ - private val apiReturnValidation = ExpectationShapes.Amplify( AuthAPI.fetchAuthSession, @@ -66,12 +60,6 @@ object FetchAuthSessionTestCaseGenerator : SerializableProvider { validations = listOf(apiReturnValidation) ) - - private val successCase: FeatureTestCase = baseCase.copy( - description = "AuthSession object is successfully returned", - preConditions = baseCase.preConditions, - ) - private val refreshSuccessCase: FeatureTestCase = baseCase.copy( description = "AuthSession object is successfully returned after refresh", preConditions = baseCase.preConditions, @@ -102,5 +90,6 @@ object FetchAuthSessionTestCaseGenerator : SerializableProvider { ) } - override val serializables: List = listOf(baseCase, errorCase, successCase, refreshSuccessCase) -} \ No newline at end of file + // TODO : Fix error case and refresh session case + override val serializables: List = listOf(baseCase) +} From b339cd37e7a081d8236757823e8e21768afc6cbd Mon Sep 17 00:00:00 2001 From: Sunil Timalsina Date: Thu, 3 Nov 2022 10:18:51 -0700 Subject: [PATCH 06/36] add generated test case --- ...n_payload_and_returns_successful_data.json | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchAuthSession/Test_that_API_is_called_with_given_payload_and_returns_successful_data.json diff --git a/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchAuthSession/Test_that_API_is_called_with_given_payload_and_returns_successful_data.json b/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchAuthSession/Test_that_API_is_called_with_given_payload_and_returns_successful_data.json new file mode 100644 index 0000000000..aacf3ab58c --- /dev/null +++ b/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchAuthSession/Test_that_API_is_called_with_given_payload_and_returns_successful_data.json @@ -0,0 +1,39 @@ +{ + "description": "Test that API is called with given payload and returns successful data", + "preConditions": { + "amplify-configuration": "authconfiguration.json", + "state": "SignedIn_SessionEstablished.json", + "mockedResponses": [ + ] + }, + "api": { + "name": "fetchAuthSession", + "params": { + }, + "options": { + } + }, + "validations": [ + { + "type": "amplify", + "apiName": "fetchAuthSession", + "responseType": "success", + "response": { + "awsCredentialsResult": { + "accessKeyId": "someAccessKey", + "expiration": 2342134, + "secretAccessKey": "someSecretKey", + "sessionToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" + }, + "identityIdResult": "someIdentityId", + "isSignedIn": true, + "userPoolTokensResult": { + "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "idToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" + }, + "userSubResult": "userId" + } + } + ] +} \ No newline at end of file From c9537ff0d597df4281ef005d224f9bf1476cb92e Mon Sep 17 00:00:00 2001 From: Banji Jolaoso Date: Thu, 3 Nov 2022 21:00:54 -0700 Subject: [PATCH 07/36] added fetchAuthSession test case generator --- .../testcasegenerators/FetchAuthSessionTestCaseGenerator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt index 38b3231bf1..16788fcb99 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt @@ -91,5 +91,5 @@ object FetchAuthSessionTestCaseGenerator : SerializableProvider { } // TODO : Fix error case and refresh session case - override val serializables: List = listOf(baseCase) + override val serializables: List = listOf(baseCase,refreshSuccessCase) } From f1791cf77ca3cf0aae5e2fc462a612ad4b882028 Mon Sep 17 00:00:00 2001 From: Banji Jolaoso Date: Fri, 4 Nov 2022 16:55:28 -0700 Subject: [PATCH 08/36] added fetchAuthSession test case generator for different auth flow types --- .../FetchAuthSessionTestCaseGenerator.kt | 95 ++++++++++++++++++- 1 file changed, 92 insertions(+), 3 deletions(-) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt index 16788fcb99..479aeeac5c 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt @@ -1,23 +1,43 @@ package com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators +import aws.sdk.kotlin.services.cognitoidentityprovider.model.ChallengeNameType import aws.sdk.kotlin.services.cognitoidentityprovider.model.NotAuthorizedException import com.amplifyframework.auth.AWSCredentials import com.amplifyframework.auth.cognito.AWSCognitoAuthSession import com.amplifyframework.auth.cognito.AWSCognitoUserPoolTokens import com.amplifyframework.auth.cognito.featuretest.API import com.amplifyframework.auth.cognito.featuretest.AuthAPI +import com.amplifyframework.auth.cognito.featuretest.CognitoType import com.amplifyframework.auth.cognito.featuretest.ExpectationShapes import com.amplifyframework.auth.cognito.featuretest.FeatureTestCase +import com.amplifyframework.auth.cognito.featuretest.MockResponse import com.amplifyframework.auth.cognito.featuretest.PreConditions import com.amplifyframework.auth.cognito.featuretest.ResponseType import com.amplifyframework.auth.cognito.featuretest.generators.SerializableProvider import com.amplifyframework.auth.cognito.featuretest.generators.authstategenerators.AuthStateJsonGenerator import com.amplifyframework.auth.cognito.featuretest.generators.toJsonElement +import com.amplifyframework.auth.exceptions.ConfigurationException +import com.amplifyframework.auth.exceptions.InvalidStateException +import com.amplifyframework.auth.exceptions.SignedOutException import com.amplifyframework.auth.result.AuthSessionResult import kotlinx.serialization.json.JsonObject object FetchAuthSessionTestCaseGenerator : SerializableProvider { + private val mockedInitiateAuthResponse = MockResponse( + CognitoType.CognitoIdentityProvider, + "initiateAuth", + ResponseType.Success, + mapOf( + "authenticationResult" to mapOf( + "idToken" to AuthStateJsonGenerator.dummyToken, + "accessToken" to AuthStateJsonGenerator.dummyToken, + "refreshToken" to AuthStateJsonGenerator.dummyToken, + "expiresIn" to 300 + ) + ).toJsonElement() + ) + private val expectedSuccess = AWSCognitoAuthSession( isSignedIn = true, identityIdResult = AWSCognitoAuthSession.getIdentityIdResult("someIdentityId"), @@ -46,7 +66,7 @@ object FetchAuthSessionTestCaseGenerator : SerializableProvider { ) private val baseCase = FeatureTestCase( - description = "Test that API is called with given payload and returns successful data", + description = "AuthSession object is successfully returned for UserAndIdentity Pool", preConditions = PreConditions( "authconfiguration.json", "SignedIn_SessionEstablished.json", @@ -62,7 +82,9 @@ object FetchAuthSessionTestCaseGenerator : SerializableProvider { private val refreshSuccessCase: FeatureTestCase = baseCase.copy( description = "AuthSession object is successfully returned after refresh", - preConditions = baseCase.preConditions, + preConditions = baseCase.preConditions.copy( + mockedResponses = listOf(mockedInitiateAuthResponse) + ), api = API( name = AuthAPI.fetchAuthSession, params = JsonObject(emptyMap()), @@ -70,6 +92,73 @@ object FetchAuthSessionTestCaseGenerator : SerializableProvider { ), validations = baseCase.validations ) + + private val identityPoolCase: FeatureTestCase = baseCase.copy( + description = "AuthSession object is successfully returned for Identity Pool", + preConditions = baseCase.preConditions.copy( + state = "SignedOut_IdentityPool.json" + ), + api = baseCase.api, + validations = listOf(ExpectationShapes.Amplify( + AuthAPI.fetchAuthSession, + ResponseType.Success, + AWSCognitoAuthSession( + isSignedIn = false, + identityIdResult = AWSCognitoAuthSession.getIdentityIdResult("someIdentityId"), + awsCredentialsResult = AuthSessionResult.success( + AWSCredentials.createAWSCredentials( + AuthStateJsonGenerator.accessKeyId, + AuthStateJsonGenerator.secretAccessKey, + AuthStateJsonGenerator.dummyToken, + AuthStateJsonGenerator.expiration + ) + ), + userSubResult = AuthSessionResult.failure(SignedOutException()), + userPoolTokensResult = AuthSessionResult.failure(SignedOutException()) + ).toJsonElement() + )) + ) + + val userPoolException = InvalidStateException( + message = "Users Federated to Identity Pool do not have User Pool access.", + recoverySuggestion = "To access User Pool data, you must use a Sign In method." + ) + + private val userPoolCase: FeatureTestCase = baseCase.copy( + description = "AuthSession object is successfully returned for User Pool", + preConditions = baseCase.preConditions.copy( + state = "SignedIn_UserPoolSessionEstablished.json" + ), + api = baseCase.api, + validations = listOf(ExpectationShapes.Amplify( + AuthAPI.fetchAuthSession, + ResponseType.Success, + AWSCognitoAuthSession( + isSignedIn = true, + identityIdResult = AuthSessionResult.failure( + ConfigurationException( + "Could not retrieve Identity ID", + "Cognito Identity not configured. Please check amplifyconfiguration.json file." + ) + ), + awsCredentialsResult = AuthSessionResult.failure( + ConfigurationException( + "Could not fetch AWS Cognito credentials", + "Cognito Identity not configured. Please check amplifyconfiguration.json file." + ) + ), + userSubResult = AuthSessionResult.success(AuthStateJsonGenerator.userId), + userPoolTokensResult = AuthSessionResult.success( + AWSCognitoUserPoolTokens( + accessToken = AuthStateJsonGenerator.dummyToken, + idToken = AuthStateJsonGenerator.dummyToken, + refreshToken = AuthStateJsonGenerator.dummyToken + ) + ) + ).toJsonElement() + )) + ) + private val errorCase: FeatureTestCase get() { val notAuthorizedErrorResponse = NotAuthorizedException.invoke { } @@ -91,5 +180,5 @@ object FetchAuthSessionTestCaseGenerator : SerializableProvider { } // TODO : Fix error case and refresh session case - override val serializables: List = listOf(baseCase,refreshSuccessCase) + override val serializables: List = listOf(baseCase,refreshSuccessCase,identityPoolCase, userPoolCase) } From 03d2d0b7e3832aaf171a8a5ee591ea0489f5d53f Mon Sep 17 00:00:00 2001 From: Banji Jolaoso Date: Mon, 7 Nov 2022 09:47:46 -0800 Subject: [PATCH 09/36] added fetchAuthSession test case generator for different auth flow types --- .../FetchAuthSessionTestCaseGenerator.kt | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt index 479aeeac5c..4b17b0622d 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt @@ -159,26 +159,6 @@ object FetchAuthSessionTestCaseGenerator : SerializableProvider { )) ) - private val errorCase: FeatureTestCase - get() { - val notAuthorizedErrorResponse = NotAuthorizedException.invoke { } - return baseCase.copy( - description = "AuthException is thrown when fetchAuthSession API call fails", - preConditions = baseCase.preConditions.copy( - state = "SignedOut_Configured.json" - ), - validations = listOf( - ExpectationShapes.Amplify( - AuthAPI.fetchAuthSession, - ResponseType.Failure, - com.amplifyframework.auth.exceptions.NotAuthorizedException( - cause = notAuthorizedErrorResponse - ).toJsonElement() - ) - ) - ) - } - // TODO : Fix error case and refresh session case override val serializables: List = listOf(baseCase,refreshSuccessCase,identityPoolCase, userPoolCase) } From ebddbd447ce6e25cdb7a45339a174be3c8419e76 Mon Sep 17 00:00:00 2001 From: Banji Jolaoso Date: Tue, 8 Nov 2022 21:05:21 -0800 Subject: [PATCH 10/36] added GetCurrentUserTestCaseGenerator --- .../FetchAuthSessionTestCaseGenerator.kt | 8 +-- .../GetCurrentUserTestCaseGenerator.kt | 62 +++++++++++++++++++ .../utilities/AuthOptionsFactory.kt | 2 +- .../SignedIn_UserPoolSessionEstablished.json | 42 +++++++++++++ .../SignedOut_IdentityPoolConfigured.json | 34 ++++++++++ 5 files changed, 140 insertions(+), 8 deletions(-) create mode 100644 aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/GetCurrentUserTestCaseGenerator.kt create mode 100644 aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_UserPoolSessionEstablished.json create mode 100644 aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_IdentityPoolConfigured.json diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt index 4b17b0622d..5146fd86c3 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt @@ -96,7 +96,7 @@ object FetchAuthSessionTestCaseGenerator : SerializableProvider { private val identityPoolCase: FeatureTestCase = baseCase.copy( description = "AuthSession object is successfully returned for Identity Pool", preConditions = baseCase.preConditions.copy( - state = "SignedOut_IdentityPool.json" + state = "SignedOut_IdentityPoolConfigured.json" ), api = baseCase.api, validations = listOf(ExpectationShapes.Amplify( @@ -119,11 +119,6 @@ object FetchAuthSessionTestCaseGenerator : SerializableProvider { )) ) - val userPoolException = InvalidStateException( - message = "Users Federated to Identity Pool do not have User Pool access.", - recoverySuggestion = "To access User Pool data, you must use a Sign In method." - ) - private val userPoolCase: FeatureTestCase = baseCase.copy( description = "AuthSession object is successfully returned for User Pool", preConditions = baseCase.preConditions.copy( @@ -159,6 +154,5 @@ object FetchAuthSessionTestCaseGenerator : SerializableProvider { )) ) - // TODO : Fix error case and refresh session case override val serializables: List = listOf(baseCase,refreshSuccessCase,identityPoolCase, userPoolCase) } diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/GetCurrentUserTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/GetCurrentUserTestCaseGenerator.kt new file mode 100644 index 0000000000..b2ee45f76b --- /dev/null +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/GetCurrentUserTestCaseGenerator.kt @@ -0,0 +1,62 @@ +package com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators + +import aws.sdk.kotlin.services.cognitoidentityprovider.model.NotAuthorizedException +import com.amplifyframework.auth.AuthUser +import com.amplifyframework.auth.cognito.featuretest.API +import com.amplifyframework.auth.cognito.featuretest.AuthAPI +import com.amplifyframework.auth.cognito.featuretest.ExpectationShapes +import com.amplifyframework.auth.cognito.featuretest.FeatureTestCase +import com.amplifyframework.auth.cognito.featuretest.PreConditions +import com.amplifyframework.auth.cognito.featuretest.ResponseType +import com.amplifyframework.auth.cognito.featuretest.generators.SerializableProvider +import com.amplifyframework.auth.cognito.featuretest.generators.authstategenerators.AuthStateJsonGenerator +import com.amplifyframework.auth.cognito.featuretest.generators.toJsonElement +import kotlinx.serialization.json.JsonObject + +object GetCurrentUserTestCaseGenerator : SerializableProvider { + + private val expectedSuccess = AuthUser("userId","username").toJsonElement() + + private val apiReturnValidation = ExpectationShapes.Amplify( + AuthAPI.getCurrentUser, + ResponseType.Success, + expectedSuccess, + ) + + private val baseCase = FeatureTestCase( + description = "User object is successfully returned", + preConditions = PreConditions( + "authconfiguration.json", + "SignedIn_SessionEstablished.json", + mockedResponses = listOf() + ), + api = API( + name = AuthAPI.getCurrentUser, + params = JsonObject(emptyMap()), + JsonObject(emptyMap()) + ), + validations = listOf(apiReturnValidation) + ) + + private val errorCase: FeatureTestCase + get() { + val errorResponse = NotAuthorizedException.invoke {} + return baseCase.copy( + description = "SignedOutException is thrown when user signs out", + preConditions = baseCase.preConditions.copy( + state = "SignedOut_Configured.json" + ), + validations = listOf( + ExpectationShapes.Amplify( + AuthAPI.getCurrentUser, + ResponseType.Failure, + com.amplifyframework.auth.exceptions.SignedOutException().toJsonElement(), + ) + ) + ) + } + + override val serializables: List = listOf( + baseCase, errorCase + ) +} \ No newline at end of file diff --git a/aws-auth-cognito/src/test/java/featureTest/utilities/AuthOptionsFactory.kt b/aws-auth-cognito/src/test/java/featureTest/utilities/AuthOptionsFactory.kt index ddb1b530cc..3a80d136f4 100644 --- a/aws-auth-cognito/src/test/java/featureTest/utilities/AuthOptionsFactory.kt +++ b/aws-auth-cognito/src/test/java/featureTest/utilities/AuthOptionsFactory.kt @@ -54,7 +54,7 @@ object AuthOptionsFactory { AuthAPI.fetchDevices -> null AuthAPI.fetchUserAttributes -> TODO() AuthAPI.forgetDevice -> TODO() - AuthAPI.getCurrentUser -> TODO() + AuthAPI.getCurrentUser -> null AuthAPI.handleWebUISignInResponse -> TODO() AuthAPI.rememberDevice -> TODO() AuthAPI.resendSignUpCode -> AuthResendSignUpCodeOptions.defaults() diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_UserPoolSessionEstablished.json b/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_UserPoolSessionEstablished.json new file mode 100644 index 0000000000..93bbd31c57 --- /dev/null +++ b/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_UserPoolSessionEstablished.json @@ -0,0 +1,42 @@ +{ + "type": "AuthState.Configured", + "AuthenticationState": { + "type": "AuthenticationState.SignedIn", + "signedInData": { + "userId": "userId", + "username": "username", + "signedInDate": 0, + "signInMethod": { + "type": "SignInMethod.ApiBased", + "authType": "USER_SRP_AUTH" + }, + "cognitoUserPoolTokens": { + "idToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "expiration": 300 + } + } + }, + "AuthorizationState": { + "type": "AuthorizationState.SessionEstablished", + "amplifyCredential": { + "type": "userPool", + "signedInData": { + "userId": "userId", + "username": "username", + "signedInDate": 0, + "signInMethod": { + "type": "SignInMethod.ApiBased", + "authType": "USER_SRP_AUTH" + }, + "cognitoUserPoolTokens": { + "idToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "expiration": 300 + } + } + } + } +} \ No newline at end of file diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_IdentityPoolConfigured.json b/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_IdentityPoolConfigured.json new file mode 100644 index 0000000000..028d2d4bd1 --- /dev/null +++ b/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_IdentityPoolConfigured.json @@ -0,0 +1,34 @@ +{ + "type": "AuthState.Configured", + "AuthenticationState": { + "type": "AuthenticationState.SignedIn", + "signedInData": { + "userId": "userId", + "username": "username", + "signedInDate": 0, + "signInMethod": { + "type": "SignInMethod.ApiBased", + "authType": "USER_SRP_AUTH" + }, + "cognitoUserPoolTokens": { + "idToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "expiration": 300 + } + } + }, + "AuthorizationState": { + "type": "AuthorizationState.SessionEstablished", + "amplifyCredential": { + "type": "identityPool", + "identityId": "someIdentityId", + "credentials": { + "accessKeyId": "someAccessKey", + "secretAccessKey": "someSecretKey", + "sessionToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "expiration": 2342134 + } + } + } +} \ No newline at end of file From e31feda2100cd57cb7c81a056a02cd9b6fc45850 Mon Sep 17 00:00:00 2001 From: Banji Jolaoso Date: Wed, 9 Nov 2022 13:15:13 -0800 Subject: [PATCH 11/36] added GetCurrentUserTestCaseGenerator --- .../test/java/featureTest/utilities/APICaptorFactory.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/aws-auth-cognito/src/test/java/featureTest/utilities/APICaptorFactory.kt b/aws-auth-cognito/src/test/java/featureTest/utilities/APICaptorFactory.kt index 8472916a84..a7a625de8b 100644 --- a/aws-auth-cognito/src/test/java/featureTest/utilities/APICaptorFactory.kt +++ b/aws-auth-cognito/src/test/java/featureTest/utilities/APICaptorFactory.kt @@ -17,6 +17,7 @@ package featureTest.utilities import com.amplifyframework.auth.AuthException import com.amplifyframework.auth.AuthSession +import com.amplifyframework.auth.AuthUser import com.amplifyframework.auth.cognito.featuretest.AuthAPI import com.amplifyframework.auth.cognito.featuretest.ExpectationShapes import com.amplifyframework.auth.cognito.featuretest.ResponseType @@ -45,7 +46,8 @@ class APICaptorFactory( AuthAPI.signUp to mockk>(), AuthAPI.signIn to mockk>(), AuthAPI.deleteUser to mockk(), - AuthAPI.fetchAuthSession to mockk() + AuthAPI.fetchAuthSession to mockk(), + AuthAPI.getCurrentUser to mockk() ) val onError = mockk>() val onComplete = mapOf( @@ -98,6 +100,11 @@ class APICaptorFactory( every { consumer.call() } answers { latch.countDown() } successCaptors[apiName] = actionCaptor } + AuthAPI.getCurrentUser -> { + val consumer = onSuccess[apiName] as Action + every { consumer.call() } answers { latch.countDown() } + successCaptors[apiName] = actionCaptor + } else -> throw Error("onSuccess for $authApi is not defined!") } } From 3eba5a42549a7bd6c51d8f1a738758c757330001 Mon Sep 17 00:00:00 2001 From: Banji Jolaoso Date: Thu, 10 Nov 2022 14:38:28 -0800 Subject: [PATCH 12/36] added GetCurrentUserTestCaseGenerator --- .../FetchAuthSessionTestCaseGenerator.kt | 97 ++++++++++--------- .../GetCurrentUserTestCaseGenerator.kt | 8 +- 2 files changed, 53 insertions(+), 52 deletions(-) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt index 5146fd86c3..02c413dac3 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt @@ -1,7 +1,5 @@ package com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators -import aws.sdk.kotlin.services.cognitoidentityprovider.model.ChallengeNameType -import aws.sdk.kotlin.services.cognitoidentityprovider.model.NotAuthorizedException import com.amplifyframework.auth.AWSCredentials import com.amplifyframework.auth.cognito.AWSCognitoAuthSession import com.amplifyframework.auth.cognito.AWSCognitoUserPoolTokens @@ -17,7 +15,6 @@ import com.amplifyframework.auth.cognito.featuretest.generators.SerializableProv import com.amplifyframework.auth.cognito.featuretest.generators.authstategenerators.AuthStateJsonGenerator import com.amplifyframework.auth.cognito.featuretest.generators.toJsonElement import com.amplifyframework.auth.exceptions.ConfigurationException -import com.amplifyframework.auth.exceptions.InvalidStateException import com.amplifyframework.auth.exceptions.SignedOutException import com.amplifyframework.auth.result.AuthSessionResult import kotlinx.serialization.json.JsonObject @@ -99,24 +96,26 @@ object FetchAuthSessionTestCaseGenerator : SerializableProvider { state = "SignedOut_IdentityPoolConfigured.json" ), api = baseCase.api, - validations = listOf(ExpectationShapes.Amplify( - AuthAPI.fetchAuthSession, - ResponseType.Success, - AWSCognitoAuthSession( - isSignedIn = false, - identityIdResult = AWSCognitoAuthSession.getIdentityIdResult("someIdentityId"), - awsCredentialsResult = AuthSessionResult.success( - AWSCredentials.createAWSCredentials( - AuthStateJsonGenerator.accessKeyId, - AuthStateJsonGenerator.secretAccessKey, - AuthStateJsonGenerator.dummyToken, - AuthStateJsonGenerator.expiration - ) - ), - userSubResult = AuthSessionResult.failure(SignedOutException()), - userPoolTokensResult = AuthSessionResult.failure(SignedOutException()) - ).toJsonElement() - )) + validations = listOf( + ExpectationShapes.Amplify( + AuthAPI.fetchAuthSession, + ResponseType.Success, + AWSCognitoAuthSession( + isSignedIn = false, + identityIdResult = AWSCognitoAuthSession.getIdentityIdResult("someIdentityId"), + awsCredentialsResult = AuthSessionResult.success( + AWSCredentials.createAWSCredentials( + AuthStateJsonGenerator.accessKeyId, + AuthStateJsonGenerator.secretAccessKey, + AuthStateJsonGenerator.dummyToken, + AuthStateJsonGenerator.expiration + ) + ), + userSubResult = AuthSessionResult.failure(SignedOutException()), + userPoolTokensResult = AuthSessionResult.failure(SignedOutException()) + ).toJsonElement() + ) + ) ) private val userPoolCase: FeatureTestCase = baseCase.copy( @@ -125,34 +124,36 @@ object FetchAuthSessionTestCaseGenerator : SerializableProvider { state = "SignedIn_UserPoolSessionEstablished.json" ), api = baseCase.api, - validations = listOf(ExpectationShapes.Amplify( - AuthAPI.fetchAuthSession, - ResponseType.Success, - AWSCognitoAuthSession( - isSignedIn = true, - identityIdResult = AuthSessionResult.failure( - ConfigurationException( - "Could not retrieve Identity ID", - "Cognito Identity not configured. Please check amplifyconfiguration.json file." - ) - ), - awsCredentialsResult = AuthSessionResult.failure( - ConfigurationException( - "Could not fetch AWS Cognito credentials", - "Cognito Identity not configured. Please check amplifyconfiguration.json file." + validations = listOf( + ExpectationShapes.Amplify( + AuthAPI.fetchAuthSession, + ResponseType.Success, + AWSCognitoAuthSession( + isSignedIn = true, + identityIdResult = AuthSessionResult.failure( + ConfigurationException( + "Could not retrieve Identity ID", + "Cognito Identity not configured. Please check amplifyconfiguration.json file." + ) + ), + awsCredentialsResult = AuthSessionResult.failure( + ConfigurationException( + "Could not fetch AWS Cognito credentials", + "Cognito Identity not configured. Please check amplifyconfiguration.json file." + ) + ), + userSubResult = AuthSessionResult.success(AuthStateJsonGenerator.userId), + userPoolTokensResult = AuthSessionResult.success( + AWSCognitoUserPoolTokens( + accessToken = AuthStateJsonGenerator.dummyToken, + idToken = AuthStateJsonGenerator.dummyToken, + refreshToken = AuthStateJsonGenerator.dummyToken + ) ) - ), - userSubResult = AuthSessionResult.success(AuthStateJsonGenerator.userId), - userPoolTokensResult = AuthSessionResult.success( - AWSCognitoUserPoolTokens( - accessToken = AuthStateJsonGenerator.dummyToken, - idToken = AuthStateJsonGenerator.dummyToken, - refreshToken = AuthStateJsonGenerator.dummyToken - ) - ) - ).toJsonElement() - )) + ).toJsonElement() + ) + ) ) - override val serializables: List = listOf(baseCase,refreshSuccessCase,identityPoolCase, userPoolCase) + override val serializables: List = listOf(baseCase, refreshSuccessCase, identityPoolCase, userPoolCase) } diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/GetCurrentUserTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/GetCurrentUserTestCaseGenerator.kt index b2ee45f76b..7eebb704b1 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/GetCurrentUserTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/GetCurrentUserTestCaseGenerator.kt @@ -9,13 +9,12 @@ import com.amplifyframework.auth.cognito.featuretest.FeatureTestCase import com.amplifyframework.auth.cognito.featuretest.PreConditions import com.amplifyframework.auth.cognito.featuretest.ResponseType import com.amplifyframework.auth.cognito.featuretest.generators.SerializableProvider -import com.amplifyframework.auth.cognito.featuretest.generators.authstategenerators.AuthStateJsonGenerator import com.amplifyframework.auth.cognito.featuretest.generators.toJsonElement import kotlinx.serialization.json.JsonObject object GetCurrentUserTestCaseGenerator : SerializableProvider { - private val expectedSuccess = AuthUser("userId","username").toJsonElement() + private val expectedSuccess = AuthUser("userId", "username").toJsonElement() private val apiReturnValidation = ExpectationShapes.Amplify( AuthAPI.getCurrentUser, @@ -57,6 +56,7 @@ object GetCurrentUserTestCaseGenerator : SerializableProvider { } override val serializables: List = listOf( - baseCase, errorCase + baseCase, + errorCase ) -} \ No newline at end of file +} From 294cb4ebdcdc47ba7940539334a7544021f39dcc Mon Sep 17 00:00:00 2001 From: Matt Creaser Date: Thu, 10 Nov 2022 09:55:33 -0400 Subject: [PATCH 13/36] fix(auth): Fix State Machine token race condition (#2100) * Pass token to stateMachine listen This is a workaround for a race condition that can occur where the listener is invoked on a background thread prior to the token value being assigned on the main thread * Rename error -> exception --- .../auth/cognito/CredentialStoreClient.kt | 9 +- .../auth/cognito/RealAWSCognitoAuthPlugin.kt | 89 +++++++++++-------- .../result/AWSCognitoAuthSignOutResult.kt | 10 +-- .../statemachine/StateMachine.kt | 11 ++- .../auth/cognito/StateTransitionTests.kt | 78 +++++++++------- .../statemachine/StateMachineListenerTests.kt | 11 ++- 6 files changed, 122 insertions(+), 86 deletions(-) diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/CredentialStoreClient.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/CredentialStoreClient.kt index 3bc9a26623..f44d415462 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/CredentialStoreClient.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/CredentialStoreClient.kt @@ -56,8 +56,9 @@ internal class CredentialStoreClient(configuration: AuthConfiguration, context: ) { var capturedSuccess: Result? = null var capturedError: Exception? = null - var token: StateChangeListenerToken? = null - token = credentialStoreStateMachine.listen( + val token = StateChangeListenerToken() + credentialStoreStateMachine.listen( + token, { storeState -> logger.verbose("Credential Store State Change: $storeState") @@ -72,10 +73,10 @@ internal class CredentialStoreClient(configuration: AuthConfiguration, context: val success = capturedSuccess val error = capturedError if (success != null) { - token?.let(credentialStoreStateMachine::cancel) + credentialStoreStateMachine.cancel(token) onSuccess(success) } else if (error != null) { - token?.let(credentialStoreStateMachine::cancel) + credentialStoreStateMachine.cancel(token) onError(error) } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPlugin.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPlugin.kt index e29fba9fde..eaf569ee53 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPlugin.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPlugin.kt @@ -168,12 +168,13 @@ internal class RealAWSCognitoAuthPlugin( @WorkerThread @Throws(AmplifyException::class) fun initialize() { - var token: StateChangeListenerToken? = null + val token = StateChangeListenerToken() val latch = CountDownLatch(1) - token = authStateMachine.listen( + authStateMachine.listen( + token, { authState -> if (authState is AuthState.Configured) { - token?.let(authStateMachine::cancel) + authStateMachine.cancel(token) latch.countDown() } }, @@ -476,8 +477,9 @@ internal class RealAWSCognitoAuthPlugin( onSuccess: Consumer, onError: Consumer ) { - var token: StateChangeListenerToken? = null - token = authStateMachine.listen( + val token = StateChangeListenerToken() + authStateMachine.listen( + token, { authState -> val authNState = authState.authNState val authZState = authState.authZState @@ -488,26 +490,26 @@ internal class RealAWSCognitoAuthPlugin( val challengeState = (signInState as? SignInState.ResolvingChallenge)?.challengeState when { srpSignInState is SRPSignInState.Error -> { - token?.let(authStateMachine::cancel) + authStateMachine.cancel(token) onError.accept( CognitoAuthExceptionConverter.lookup(srpSignInState.exception, "Sign in failed.") ) } signInState is SignInState.Error -> { - token?.let(authStateMachine::cancel) + authStateMachine.cancel(token) onError.accept( CognitoAuthExceptionConverter.lookup(signInState.exception, "Sign in failed.") ) } challengeState is SignInChallengeState.WaitingForAnswer -> { - token?.let(authStateMachine::cancel) + authStateMachine.cancel(token) SignInChallengeHelper.getNextStep(challengeState.challenge, onSuccess, onError) } } } authNState is AuthenticationState.SignedIn && authZState is AuthorizationState.SessionEstablished -> { - token?.let(authStateMachine::cancel) + authStateMachine.cancel(token) val authSignInResult = AuthSignInResult( true, AuthNextSignInStep(AuthSignInStep.DONE, mapOf(), null) @@ -571,8 +573,9 @@ internal class RealAWSCognitoAuthPlugin( onSuccess: Consumer, onError: Consumer ) { - var token: StateChangeListenerToken? = null - token = authStateMachine.listen( + val token = StateChangeListenerToken() + authStateMachine.listen( + token, { authState -> val authNState = authState.authNState val authZState = authState.authZState @@ -581,7 +584,7 @@ internal class RealAWSCognitoAuthPlugin( when { authNState is AuthenticationState.SignedIn && authZState is AuthorizationState.SessionEstablished -> { - token?.let(authStateMachine::cancel) + authStateMachine.cancel(token) val authSignInResult = AuthSignInResult( true, AuthNextSignInStep(AuthSignInStep.DONE, mapOf(), null) @@ -590,7 +593,7 @@ internal class RealAWSCognitoAuthPlugin( sendHubEvent(AuthChannelEventName.SIGNED_IN.toString()) } signInState is SignInState.Error -> { - token?.let(authStateMachine::cancel) + authStateMachine.cancel(token) onError.accept( CognitoAuthExceptionConverter.lookup(signInState.exception, "Confirm Sign in failed.") ) @@ -703,8 +706,9 @@ internal class RealAWSCognitoAuthPlugin( onError: Consumer, provider: AuthProvider? = null ) { - var token: StateChangeListenerToken? = null - token = authStateMachine.listen( + val token = StateChangeListenerToken() + authStateMachine.listen( + token, { authState -> val authNState = authState.authNState val authZState = authState.authZState @@ -712,7 +716,7 @@ internal class RealAWSCognitoAuthPlugin( authNState is AuthenticationState.SigningIn -> { val hostedUISignInState = authNState.signInState.hostedUISignInState if (hostedUISignInState is HostedUISignInState.Error) { - token?.let(authStateMachine::cancel) + authStateMachine.cancel(token) val exception = hostedUISignInState.exception onError.accept( if (exception is AuthException) { @@ -726,7 +730,7 @@ internal class RealAWSCognitoAuthPlugin( } authNState is AuthenticationState.SignedIn && authZState is AuthorizationState.SessionEstablished -> { - token?.let(authStateMachine::cancel) + authStateMachine.cancel(token) val authSignInResult = AuthSignInResult( true, @@ -912,16 +916,17 @@ internal class RealAWSCognitoAuthPlugin( onSuccess: Consumer, onError: Consumer ) { - var token: StateChangeListenerToken? = null - token = authStateMachine.listen( + val token = StateChangeListenerToken() + authStateMachine.listen( + token, { authState -> when (val authZState = authState.authZState) { is AuthorizationState.SessionEstablished -> { - token?.let(authStateMachine::cancel) + authStateMachine.cancel(token) onSuccess.accept(authZState.amplifyCredential.getCognitoSession()) } is AuthorizationState.Error -> { - token?.let(authStateMachine::cancel) + authStateMachine.cancel(token) when (val error = authZState.exception) { is SessionError -> { when (error.exception) { @@ -1559,14 +1564,15 @@ internal class RealAWSCognitoAuthPlugin( } private fun _signOut(sendHubEvent: Boolean = true, onComplete: Consumer) { - var token: StateChangeListenerToken? = null - token = authStateMachine.listen( + val token = StateChangeListenerToken() + authStateMachine.listen( + token, { authState -> if (authState is AuthState.Configured) { val (authNState, authZState) = authState when { authNState is AuthenticationState.SignedOut && authZState is AuthorizationState.Configured -> { - token?.let(authStateMachine::cancel) + authStateMachine.cancel(token) if (authNState.signedOutData.hasError) { val signedOutData = authNState.signedOutData onComplete.accept( @@ -1593,7 +1599,7 @@ internal class RealAWSCognitoAuthPlugin( } } authNState is AuthenticationState.Error -> { - token?.let(authStateMachine::cancel) + authStateMachine.cancel(token) onComplete.accept( AWSCognitoAuthSignOutResult.FailedSignOut( CognitoAuthExceptionConverter.lookup(authNState.exception, "Sign out failed.") @@ -1633,8 +1639,9 @@ internal class RealAWSCognitoAuthPlugin( } private fun _deleteUser(token: String, onSuccess: Action, onError: Consumer) { - var listenerToken: StateChangeListenerToken? = null - listenerToken = authStateMachine.listen( + val listenerToken = StateChangeListenerToken() + authStateMachine.listen( + listenerToken, { authState -> when (val authNState = authState.authNState) { is AuthenticationState.SignedOut -> { @@ -1654,10 +1661,10 @@ internal class RealAWSCognitoAuthPlugin( is DeleteUserState.UserDeleted -> { onSuccess.call() sendHubEvent(AuthChannelEventName.USER_DELETED.toString()) - listenerToken?.let(authStateMachine::cancel) + authStateMachine.cancel(listenerToken) } is DeleteUserState.Error -> { - listenerToken?.let(authStateMachine::cancel) + authStateMachine.cancel(listenerToken) onError.accept( CognitoAuthExceptionConverter.lookup( deleteUserState.exception, @@ -1678,16 +1685,21 @@ internal class RealAWSCognitoAuthPlugin( } private fun addAuthStateChangeListener() { - authStateMachine.listen({ authState -> logger.verbose("Auth State Change: $authState") }, null) + authStateMachine.listen( + StateChangeListenerToken(), + { authState -> logger.verbose("Auth State Change: $authState") }, + null + ) } private fun configureAuthStates() { - var token: StateChangeListenerToken? = null - token = authStateMachine.listen( + val token = StateChangeListenerToken() + authStateMachine.listen( + token, { authState -> when (authState) { is AuthState.Configured -> { - token?.let(authStateMachine::cancel) + authStateMachine.cancel(token) } else -> Unit // handle errors } @@ -1753,15 +1765,16 @@ internal class RealAWSCognitoAuthPlugin( onSuccess: Consumer, onError: Consumer ) { - var token: StateChangeListenerToken? = null - token = authStateMachine.listen( + val token = StateChangeListenerToken() + authStateMachine.listen( + token, { authState -> val authNState = authState.authNState val authZState = authState.authZState when { authNState is AuthenticationState.FederatedToIdentityPool && authZState is AuthorizationState.SessionEstablished -> { - token?.let(authStateMachine::cancel) + authStateMachine.cancel(token) val credential = authZState.amplifyCredential as? AmplifyCredential.IdentityPoolFederated val identityId = credential?.identityId val awsCredentials = credential?.credentials @@ -1787,7 +1800,7 @@ internal class RealAWSCognitoAuthPlugin( } } authNState is AuthenticationState.Error && authZState is AuthorizationState.Error -> { - token?.let(authStateMachine::cancel) + authStateMachine.cancel(token) onError.accept( CognitoAuthExceptionConverter.lookup( authZState.exception, @@ -1835,7 +1848,7 @@ internal class RealAWSCognitoAuthPlugin( _signOut(sendHubEvent = false) { when (it) { is AWSCognitoAuthSignOutResult.FailedSignOut -> { - onError.accept(it.error) + onError.accept(it.exception) } else -> { onSuccess.call() diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/result/AWSCognitoAuthSignOutResult.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/result/AWSCognitoAuthSignOutResult.kt index 6e0e454400..1005a23e9a 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/result/AWSCognitoAuthSignOutResult.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/result/AWSCognitoAuthSignOutResult.kt @@ -46,9 +46,9 @@ sealed class AWSCognitoAuthSignOutResult : AuthSignOutResult() { /** * Indicates a failed sign out that did not complete. The user will remain signed in - * @param error that occurred during sign out + * @param exception that occurred during sign out */ - data class FailedSignOut internal constructor(val error: AuthException) : AWSCognitoAuthSignOutResult() { + data class FailedSignOut internal constructor(val exception: AuthException) : AWSCognitoAuthSignOutResult() { /** * Indicates if credentials have been cleared from local device @@ -89,7 +89,7 @@ class HostedUIError internal constructor(hostedUIErrorData: HostedUIErrorData) { /** * Error containing information about hosted ui sign out failure */ - val error = hostedUIErrorData.error + val exception = hostedUIErrorData.error } /** @@ -105,7 +105,7 @@ class GlobalSignOutError internal constructor(globalSignOutErrorData: GlobalSign /** * Error containing information about global sign out failure */ - val error = GlobalSignOutException(globalSignOutErrorData.error) + val exception = GlobalSignOutException(globalSignOutErrorData.error) } /** @@ -122,5 +122,5 @@ class RevokeTokenError internal constructor(revokeTokenErrorData: RevokeTokenErr /** * Error containing information about revoke token failure */ - val error = RevokeTokenException(revokeTokenErrorData.error) + val exception = RevokeTokenException(revokeTokenErrorData.error) } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/StateMachine.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/StateMachine.kt index 041e7265cf..42b4a9a169 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/StateMachine.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/StateMachine.kt @@ -24,9 +24,14 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlinx.coroutines.newFixedThreadPoolContext -internal typealias StateChangeListenerToken = UUID internal typealias OnSubscribedCallback = () -> Unit +internal class StateChangeListenerToken private constructor(val uuid: UUID) { + constructor() : this(UUID.randomUUID()) + override fun equals(other: Any?) = other is StateChangeListenerToken && other.uuid == uuid + override fun hashCode() = uuid.hashCode() +} + /** * Model, mutate and process effects of a system as a finite state automaton. It consists of: * State - which represents the current state of the system @@ -89,12 +94,10 @@ internal open class StateMachine Unit, onSubscribe: OnSubscribedCallback?): StateChangeListenerToken { - val token = UUID.randomUUID() + fun listen(token: StateChangeListenerToken, listener: (StateType) -> Unit, onSubscribe: OnSubscribedCallback?) { GlobalScope.launch(stateMachineScope) { addSubscription(token, listener, onSubscribe) } - return token } /** diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/StateTransitionTests.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/StateTransitionTests.kt index 79a075c121..48dba44b10 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/StateTransitionTests.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/StateTransitionTests.kt @@ -217,14 +217,15 @@ class StateTransitionTests : StateTransitionTestBase() { setupConfigureSignedOut() val listenLatch = CountDownLatch(1) val subscribeLatch = CountDownLatch(1) - var token: StateChangeListenerToken? = null - token = stateMachine.listen( + val token = StateChangeListenerToken() + stateMachine.listen( + token, { if (it is AuthState.Configured && it.authNState is AuthenticationState.SignedOut && it.authZState is AuthorizationState.Configured ) { - token?.let(stateMachine::cancel) + stateMachine.cancel(token) listenLatch.countDown() } }, @@ -246,14 +247,15 @@ class StateTransitionTests : StateTransitionTestBase() { val listenLatch = CountDownLatch(1) val subscribeLatch = CountDownLatch(1) - var token: StateChangeListenerToken? = null - token = stateMachine.listen( + val token = StateChangeListenerToken() + stateMachine.listen( + token, { if (it is AuthState.Configured && it.authNState is AuthenticationState.SignedIn && it.authZState is AuthorizationState.SessionEstablished ) { - token?.let(stateMachine::cancel) + stateMachine.cancel(token) listenLatch.countDown() } }, @@ -288,8 +290,9 @@ class StateTransitionTests : StateTransitionTestBase() { val testLatch = CountDownLatch(1) val configureLatch = CountDownLatch(1) val subscribeLatch = CountDownLatch(1) - var token: StateChangeListenerToken? = null - token = stateMachine.listen( + val token = StateChangeListenerToken() + stateMachine.listen( + token, { val authState = it.takeIf { it is AuthState.Configured && it.authNState is AuthenticationState.SignedOut } @@ -311,7 +314,7 @@ class StateTransitionTests : StateTransitionTestBase() { itN is AuthenticationState.SignedIn && it.authZState is AuthorizationState.SessionEstablished } authNState?.apply { - token?.let(stateMachine::cancel) + stateMachine.cancel(token) testLatch.countDown() } }, @@ -353,8 +356,9 @@ class StateTransitionTests : StateTransitionTestBase() { val testLatch = CountDownLatch(1) val configureLatch = CountDownLatch(1) val subscribeLatch = CountDownLatch(1) - var token: StateChangeListenerToken? = null - token = stateMachine.listen( + val token = StateChangeListenerToken() + stateMachine.listen( + token, { val authState = it.takeIf { it is AuthState.Configured && it.authNState is AuthenticationState.SignedOut } @@ -389,7 +393,7 @@ class StateTransitionTests : StateTransitionTestBase() { itN is AuthenticationState.SignedIn && it.authZState is AuthorizationState.SessionEstablished } authNState?.apply { - token?.let(stateMachine::cancel) + stateMachine.cancel(token) testLatch.countDown() } }, @@ -416,8 +420,9 @@ class StateTransitionTests : StateTransitionTestBase() { val testLatch = CountDownLatch(1) val configureLatch = CountDownLatch(1) val subscribeLatch = CountDownLatch(1) - var token: StateChangeListenerToken? = null - token = stateMachine.listen( + val token = StateChangeListenerToken() + stateMachine.listen( + token, { val authState = it.takeIf { it is AuthState.Configured && it.authNState is AuthenticationState.SignedIn } @@ -434,7 +439,7 @@ class StateTransitionTests : StateTransitionTestBase() { itN is AuthenticationState.SignedOut && it.authZState is AuthorizationState.Configured } authNState?.apply { - token?.let(stateMachine::cancel) + stateMachine.cancel(token) testLatch.countDown() } }, @@ -461,8 +466,9 @@ class StateTransitionTests : StateTransitionTestBase() { val testLatch = CountDownLatch(1) val configureLatch = CountDownLatch(1) val subscribeLatch = CountDownLatch(1) - var token: StateChangeListenerToken? = null - token = stateMachine.listen( + val token = StateChangeListenerToken() + stateMachine.listen( + token, { val authState = it.takeIf { it is AuthState.Configured && it.authNState is AuthenticationState.SignedIn } @@ -479,7 +485,7 @@ class StateTransitionTests : StateTransitionTestBase() { itN is AuthenticationState.SignedOut && it.authZState is AuthorizationState.Configured } authNState?.apply { - token?.let(stateMachine::cancel) + stateMachine.cancel(token) testLatch.countDown() } }, @@ -505,8 +511,9 @@ class StateTransitionTests : StateTransitionTestBase() { val testLatch = CountDownLatch(1) val configureLatch = CountDownLatch(1) val subscribeLatch = CountDownLatch(1) - var token: StateChangeListenerToken? = null - token = stateMachine.listen( + val token = StateChangeListenerToken() + stateMachine.listen( + token, { val authState = it.takeIf { it is AuthState.Configured && it.authNState is AuthenticationState.SignedIn } @@ -523,7 +530,7 @@ class StateTransitionTests : StateTransitionTestBase() { itN is AuthenticationState.SignedOut && it.authZState is AuthorizationState.Configured } authNState?.apply { - token?.let(stateMachine::cancel) + stateMachine.cancel(token) testLatch.countDown() } }, @@ -549,8 +556,9 @@ class StateTransitionTests : StateTransitionTestBase() { val testLatch = CountDownLatch(1) val subscribeLatch = CountDownLatch(1) configureLatch.countDown() - var token: StateChangeListenerToken? = null - token = stateMachine.listen( + val token = StateChangeListenerToken() + stateMachine.listen( + token, { it -> val authState = it.takeIf { it is AuthState.Configured && it.authNState is AuthenticationState.SignedIn @@ -564,7 +572,7 @@ class StateTransitionTests : StateTransitionTestBase() { itN is AuthenticationState.SignedIn && it.authZState is AuthorizationState.SessionEstablished } authNState?.run { - token?.let(stateMachine::cancel) + stateMachine.cancel(token) testLatch.countDown() } }, @@ -590,8 +598,9 @@ class StateTransitionTests : StateTransitionTestBase() { val testLatch = CountDownLatch(1) val subscribeLatch = CountDownLatch(1) configureLatch.countDown() - var token: StateChangeListenerToken? = null - token = stateMachine.listen( + val token = StateChangeListenerToken() + stateMachine.listen( + token, { it -> val authState = it.takeIf { it is AuthState.Configured && it.authNState is AuthenticationState.SignedOut @@ -605,7 +614,7 @@ class StateTransitionTests : StateTransitionTestBase() { itN is AuthenticationState.SignedOut && it.authZState is AuthorizationState.SessionEstablished } authNState?.run { - token?.let(stateMachine::cancel) + stateMachine.cancel(token) testLatch.countDown() } }, @@ -630,8 +639,9 @@ class StateTransitionTests : StateTransitionTestBase() { val configureLatch = CountDownLatch(1) val subscribeLatch = CountDownLatch(1) val testLatch = CountDownLatch(1) - var token: StateChangeListenerToken? = null - token = stateMachine.listen( + val token = StateChangeListenerToken() + stateMachine.listen( + token, { it -> val authState = it.takeIf { it is AuthState.Configured && it.authNState is AuthenticationState.SignedIn @@ -642,6 +652,7 @@ class StateTransitionTests : StateTransitionTestBase() { stateMachine.send(AuthorizationEvent(AuthorizationEvent.EventType.RefreshSession(credentials))) stateMachine.listen( + StateChangeListenerToken(), { it2 -> val authNState = it2.takeIf { it2 is AuthState.Configured && @@ -649,7 +660,7 @@ class StateTransitionTests : StateTransitionTestBase() { it2.authZState is AuthorizationState.SessionEstablished } authNState?.run { - token?.let(stateMachine::cancel) + stateMachine.cancel(token) testLatch.countDown() } }, @@ -678,8 +689,9 @@ class StateTransitionTests : StateTransitionTestBase() { val configureLatch = CountDownLatch(1) val subscribeLatch = CountDownLatch(1) val testLatch = CountDownLatch(1) - var token: StateChangeListenerToken? = null - token = stateMachine.listen( + val token = StateChangeListenerToken() + stateMachine.listen( + token, { it -> val authState = it.takeIf { it is AuthState.Configured && it.authNState is AuthenticationState.SignedIn } @@ -705,7 +717,7 @@ class StateTransitionTests : StateTransitionTestBase() { } userDeletedSuccess?.run { - token?.let(stateMachine::cancel) + stateMachine.cancel(token) testLatch.countDown() } }, diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/statemachine/StateMachineListenerTests.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/statemachine/StateMachineListenerTests.kt index 3113abf856..bdd265a944 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/statemachine/StateMachineListenerTests.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/statemachine/StateMachineListenerTests.kt @@ -55,6 +55,7 @@ class StateMachineListenerTests { stateMachine.send(Counter.Event("1", eventType = Increment)) val testLatch = CountDownLatch(2) stateMachine.listen( + StateChangeListenerToken(), { assertEquals(1, it.value) testLatch.countDown() @@ -72,6 +73,7 @@ class StateMachineListenerTests { val listenLatch = CountDownLatch(2) val subscribeLatch = CountDownLatch(1) stateMachine.listen( + StateChangeListenerToken(), { listenLatch.countDown() }, @@ -91,6 +93,7 @@ class StateMachineListenerTests { val listenLatch = CountDownLatch(1) val subscribeLatch = CountDownLatch(1) stateMachine.listen( + StateChangeListenerToken(), { listenLatch.countDown() }, @@ -109,7 +112,9 @@ class StateMachineListenerTests { stateMachine.send(Counter.Event("1", eventType = Increment)) val listenLatch = CountDownLatch(1) val subscribeLatch = CountDownLatch(1) - val token = stateMachine.listen( + val token = StateChangeListenerToken() + stateMachine.listen( + token, { listenLatch.countDown() }, @@ -128,7 +133,9 @@ class StateMachineListenerTests { fun testNoNotifyImmediateCancel() { stateMachine.send(Counter.Event("1", eventType = Increment)) val listenLatch = CountDownLatch(1) - val token = stateMachine.listen( + val token = StateChangeListenerToken() + stateMachine.listen( + token, { listenLatch.countDown() }, From a87e9ad2e927f0911dc7466cfb036faae9b5db4d Mon Sep 17 00:00:00 2001 From: Divyesh Chitroda Date: Thu, 10 Nov 2022 15:18:45 -0800 Subject: [PATCH 14/36] Update release_pr.yml (#2105) Use branch ref from workflow trigger. --- .github/workflows/release_pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release_pr.yml b/.github/workflows/release_pr.yml index 2444138979..4d7a29b1c7 100644 --- a/.github/workflows/release_pr.yml +++ b/.github/workflows/release_pr.yml @@ -9,7 +9,7 @@ on: env: GIT_USER_NAME: amplify-android-dev+ghops GIT_USER_EMAIL: amplify-android-dev+ghops@amazon.com - BASE_BRANCH: main + BASE_BRANCH: ${{ github.event.ref }} jobs: create_pr_for_next_release: runs-on: ubuntu-latest From 9d6a48dc20fb5ed7578ed431789dec139a0c0b28 Mon Sep 17 00:00:00 2001 From: Sunil Timalsina Date: Thu, 10 Nov 2022 21:43:55 -0800 Subject: [PATCH 15/36] chore: add retries to identify flaky tests (#2099) --- .../auth/cognito/AWSCognitoAuthPlugin.kt | 4 +- ...ceBehavior.kt => AWSCognitoAuthService.kt} | 6 +- .../auth/cognito/AuthEnvironment.kt | 2 +- .../service/GlobalSignOutException.kt | 2 +- .../AWSCognitoAuthPluginFeatureTest.kt | 2 +- .../auth/cognito/AWSCognitoAuthPluginTest.kt | 2 +- ...orTest.kt => AWSCognitoAuthServiceTest.kt} | 4 +- .../cognito/RealAWSCognitoAuthPluginTest.kt | 2 +- .../auth/cognito/StateTransitionTestBase.kt | 2 +- .../SignOutTestCaseGenerator.kt | 140 +++++++++++++++--- ...rtial_success_with_revoke_token_error.json | 57 +++++++ ...al_success_with_global_sign_out_error.json | 67 +++++++++ ...rtial_success_with_revoke_token_error.json | 50 +++++++ build.gradle | 11 ++ 14 files changed, 314 insertions(+), 37 deletions(-) rename aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/{AWSCognitoAuthServiceBehavior.kt => AWSCognitoAuthService.kt} (92%) rename aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/{AWSCognitoAuthServiceBehaviorTest.kt => AWSCognitoAuthServiceTest.kt} (94%) create mode 100644 aws-auth-cognito/src/test/resources/feature-test/testsuites/signOut/Test_that_globalSignOut_returns_partial_success_with_revoke_token_error.json create mode 100644 aws-auth-cognito/src/test/resources/feature-test/testsuites/signOut/Test_that_global_signOut_error_returns_partial_success_with_global_sign_out_error.json create mode 100644 aws-auth-cognito/src/test/resources/feature-test/testsuites/signOut/Test_that_signOut_returns_partial_success_with_revoke_token_error.json diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthPlugin.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthPlugin.kt index 838cb2aa18..929179d318 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthPlugin.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthPlugin.kt @@ -68,7 +68,7 @@ import org.json.JSONObject /** * A Cognito implementation of the Auth Plugin. */ -class AWSCognitoAuthPlugin : AuthPlugin() { +class AWSCognitoAuthPlugin : AuthPlugin() { companion object { const val AWS_COGNITO_AUTH_LOG_NAMESPACE = "amplify:aws-cognito-auth:%s" private const val AWS_COGNITO_AUTH_PLUGIN_KEY = "awsCognitoAuthPlugin" @@ -111,7 +111,7 @@ class AWSCognitoAuthPlugin : AuthPlugin() { val authEnvironment = AuthEnvironment( context, configuration, - AWSCognitoAuthServiceBehavior.fromConfiguration(configuration), + AWSCognitoAuthService.fromConfiguration(configuration), credentialStoreClient, configuration.userPool?.let { UserContextDataProvider(context, it.poolId!!, it.appClient!!) }, HostedUIClient.create(context, configuration.oauth, logger), diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthServiceBehavior.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthService.kt similarity index 92% rename from aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthServiceBehavior.kt rename to aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthService.kt index ccdd1c4b0c..38d9c9c3d1 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthServiceBehavior.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthService.kt @@ -20,12 +20,12 @@ import aws.sdk.kotlin.services.cognitoidentityprovider.CognitoIdentityProviderCl import aws.smithy.kotlin.runtime.http.endpoints.Endpoint import com.amplifyframework.statemachine.codegen.data.AuthConfiguration -interface AWSCognitoAuthServiceBehavior { +interface AWSCognitoAuthService { var cognitoIdentityProviderClient: CognitoIdentityProviderClient? var cognitoIdentityClient: CognitoIdentityClient? companion object { - internal fun fromConfiguration(configuration: AuthConfiguration): AWSCognitoAuthServiceBehavior { + internal fun fromConfiguration(configuration: AuthConfiguration): AWSCognitoAuthService { val cognitoIdentityProviderClient = configuration.userPool?.let { it -> CognitoIdentityProviderClient { @@ -40,7 +40,7 @@ interface AWSCognitoAuthServiceBehavior { CognitoIdentityClient { this.region = it.region } } - return object : AWSCognitoAuthServiceBehavior { + return object : AWSCognitoAuthService { override var cognitoIdentityProviderClient = cognitoIdentityProviderClient override var cognitoIdentityClient = cognitoIdentityClient } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AuthEnvironment.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AuthEnvironment.kt index eb420aacf6..027e9c8099 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AuthEnvironment.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AuthEnvironment.kt @@ -37,7 +37,7 @@ import java.util.UUID internal class AuthEnvironment internal constructor( val context: Context, val configuration: AuthConfiguration, - val cognitoAuthService: AWSCognitoAuthServiceBehavior, + val cognitoAuthService: AWSCognitoAuthService, val credentialStoreClient: StoreClientBehavior, private val userContextDataProvider: UserContextDataProvider? = null, val hostedUIClient: HostedUIClient?, diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/exceptions/service/GlobalSignOutException.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/exceptions/service/GlobalSignOutException.kt index bb0097bb9d..5ee67063db 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/exceptions/service/GlobalSignOutException.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/exceptions/service/GlobalSignOutException.kt @@ -23,6 +23,6 @@ import com.amplifyframework.auth.exceptions.ServiceException open class GlobalSignOutException(cause: Throwable) : ServiceException( "Failed to sign out globally", "See attached exception for more details. GlobalSignOut can be retried using the " + - "CognitoIdentityProviderClient is accessible from the escape hatch.", + "CognitoIdentityProviderClient accessible from the escape hatch.", cause ) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/AWSCognitoAuthPluginFeatureTest.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/AWSCognitoAuthPluginFeatureTest.kt index 87f95f6d18..8b1a1f8a80 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/AWSCognitoAuthPluginFeatureTest.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/AWSCognitoAuthPluginFeatureTest.kt @@ -152,7 +152,7 @@ class AWSCognitoAuthPluginFeatureTest(private val testCase: FeatureTestCase) { .getJSONObject("awsCognitoAuthPlugin") val authConfiguration = AuthConfiguration.fromJson(configJSONObject) - val authService = mockk { + val authService = mockk { every { cognitoIdentityProviderClient } returns mockCognitoIPClient every { cognitoIdentityClient } returns mockCognitoIdClient } diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/AWSCognitoAuthPluginTest.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/AWSCognitoAuthPluginTest.kt index f8f121ecea..4a7738e2be 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/AWSCognitoAuthPluginTest.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/AWSCognitoAuthPluginTest.kt @@ -516,7 +516,7 @@ class AWSCognitoAuthPluginTest { @Test fun verifyEscapeHatch() { - val expectedEscapeHatch = mockk() + val expectedEscapeHatch = mockk() every { realPlugin.escapeHatch() } returns expectedEscapeHatch assertEquals(expectedEscapeHatch, authPlugin.escapeHatch) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/AWSCognitoAuthServiceBehaviorTest.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/AWSCognitoAuthServiceTest.kt similarity index 94% rename from aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/AWSCognitoAuthServiceBehaviorTest.kt rename to aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/AWSCognitoAuthServiceTest.kt index 03e33ce907..9162032888 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/AWSCognitoAuthServiceBehaviorTest.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/AWSCognitoAuthServiceTest.kt @@ -25,7 +25,7 @@ import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner @RunWith(RobolectricTestRunner::class) -class AWSCognitoAuthServiceBehaviorTest { +class AWSCognitoAuthServiceTest { // Robolectric needed due to internals of AWSCognitoAuthServiceBehavior initialization @Test @@ -45,7 +45,7 @@ class AWSCognitoAuthServiceBehaviorTest { authFlowType = AuthFlowType.USER_SRP_AUTH ) - val testObject = AWSCognitoAuthServiceBehavior.fromConfiguration(config) + val testObject = AWSCognitoAuthService.fromConfiguration(config) assertEquals(expectedIdentityPoolConfigRegion, testObject.cognitoIdentityClient!!.config.region) assertEquals(expectedUserPoolRegion, testObject.cognitoIdentityProviderClient!!.config.region) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPluginTest.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPluginTest.kt index 1c9e7e2ea2..8b3d201a7e 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPluginTest.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPluginTest.kt @@ -129,7 +129,7 @@ class RealAWSCognitoAuthPluginTest { ) private val mockCognitoIPClient = mockk() - private var authService = mockk { + private var authService = mockk { every { cognitoIdentityProviderClient } returns mockCognitoIPClient } diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/StateTransitionTestBase.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/StateTransitionTestBase.kt index 32bd799900..51c5e1004f 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/StateTransitionTestBase.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/StateTransitionTestBase.kt @@ -81,7 +81,7 @@ open class StateTransitionTestBase { internal lateinit var configuration: AuthConfiguration @Mock - internal lateinit var cognitoAuthService: AWSCognitoAuthServiceBehavior + internal lateinit var cognitoAuthService: AWSCognitoAuthService @Mock internal lateinit var mockAuthActions: AuthActions diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/SignOutTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/SignOutTestCaseGenerator.kt index b20a5e7409..08d7a305e2 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/SignOutTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/SignOutTestCaseGenerator.kt @@ -14,6 +14,7 @@ */ package com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators +import aws.sdk.kotlin.services.cognitoidentityprovider.model.NotAuthorizedException import com.amplifyframework.auth.cognito.featuretest.API import com.amplifyframework.auth.cognito.featuretest.AuthAPI import com.amplifyframework.auth.cognito.featuretest.CognitoType @@ -23,8 +24,13 @@ import com.amplifyframework.auth.cognito.featuretest.MockResponse import com.amplifyframework.auth.cognito.featuretest.PreConditions import com.amplifyframework.auth.cognito.featuretest.ResponseType import com.amplifyframework.auth.cognito.featuretest.generators.SerializableProvider +import com.amplifyframework.auth.cognito.featuretest.generators.authstategenerators.AuthStateJsonGenerator import com.amplifyframework.auth.cognito.featuretest.generators.toJsonElement import com.amplifyframework.auth.cognito.result.AWSCognitoAuthSignOutResult +import com.amplifyframework.auth.cognito.result.GlobalSignOutError +import com.amplifyframework.auth.cognito.result.RevokeTokenError +import com.amplifyframework.statemachine.codegen.data.GlobalSignOutErrorData +import com.amplifyframework.statemachine.codegen.data.RevokeTokenErrorData import kotlinx.serialization.json.JsonObject object SignOutTestCaseGenerator : SerializableProvider { @@ -36,19 +42,35 @@ object SignOutTestCaseGenerator : SerializableProvider { JsonObject(emptyMap()) ) - private val mockedRevokeTokenSignOutSuccessResponse = MockResponse( + private val mockedGlobalSignOutFailureResponse = MockResponse( + CognitoType.CognitoIdentityProvider, + "globalSignOut", + ResponseType.Failure, + NotAuthorizedException.invoke {}.toJsonElement() + ) + + private val mockedRevokeTokenSuccessResponse = MockResponse( CognitoType.CognitoIdentityProvider, "revokeToken", ResponseType.Success, JsonObject(emptyMap()) ) - private val signedOutSuccessCase = FeatureTestCase( - description = "Test that signOut while already signed out returns complete with success", + private val mockedRevokeTokenFailureResponse = MockResponse( + CognitoType.CognitoIdentityProvider, + "revokeToken", + ResponseType.Failure, + NotAuthorizedException.invoke {}.toJsonElement() + ) + + private val successCase = FeatureTestCase( + description = "Test that signOut while signed in returns complete with success", preConditions = PreConditions( "authconfiguration.json", - "SignedOut_Configured.json", - mockedResponses = emptyList() + "SignedIn_SessionEstablished.json", + mockedResponses = listOf( + mockedRevokeTokenSuccessResponse + ) ), api = API( AuthAPI.signOut, @@ -66,43 +88,113 @@ object SignOutTestCaseGenerator : SerializableProvider { ) ) - private val signedInSuccessCase = FeatureTestCase( - description = "Test that signOut while signed in returns complete with success", - preConditions = PreConditions( - "authconfiguration.json", - "SignedIn_SessionEstablished.json", + private val signedOutSuccessCase = successCase.copy( + description = "Test that signOut while already signed out returns complete with success", + preConditions = successCase.preConditions.copy( + state = "SignedOut_Configured.json", + mockedResponses = emptyList() + ) + ) + + private val globalSuccessCase = successCase.copy( + description = "Test that global signOut while signed in returns complete with success", + preConditions = successCase.preConditions.copy( mockedResponses = listOf( - mockedRevokeTokenSignOutSuccessResponse + mockedGlobalSignOutSuccessResponse, + mockedRevokeTokenSuccessResponse ) ), - api = API( - AuthAPI.signOut, - params = emptyMap().toJsonElement(), - options = mapOf( - "globalSignOut" to false - ).toJsonElement() + api = successCase.api.copy( + options = mapOf("globalSignOut" to true).toJsonElement() + ) + ) + + private val revokeTokenErrorCase = successCase.copy( + description = "Test that signOut returns partial success with revoke token error", + preConditions = successCase.preConditions.copy( + mockedResponses = listOf( + mockedRevokeTokenFailureResponse + ) ), validations = listOf( ExpectationShapes.Amplify( apiName = AuthAPI.signOut, responseType = ResponseType.Complete, - response = AWSCognitoAuthSignOutResult.CompleteSignOut.toJsonElement() + response = AWSCognitoAuthSignOutResult.PartialSignOut( + revokeTokenError = RevokeTokenError( + RevokeTokenErrorData( + refreshToken = AuthStateJsonGenerator.dummyToken, + error = NotAuthorizedException.invoke { } + ) + ) + ).toJsonElement() ) ) ) - private val globalSignedInSuccessCase = signedInSuccessCase.copy( - description = "Test that global signOut while signed in returns complete with success", - preConditions = signedInSuccessCase.preConditions.copy( + private val revokeTokenWithGlobalSignOutErrorCase = successCase.copy( + description = "Test that globalSignOut returns partial success with revoke token error", + preConditions = successCase.preConditions.copy( mockedResponses = listOf( mockedGlobalSignOutSuccessResponse, - mockedRevokeTokenSignOutSuccessResponse + mockedRevokeTokenFailureResponse + ) + ), + validations = listOf( + ExpectationShapes.Amplify( + apiName = AuthAPI.signOut, + responseType = ResponseType.Complete, + response = AWSCognitoAuthSignOutResult.PartialSignOut( + revokeTokenError = RevokeTokenError( + RevokeTokenErrorData( + refreshToken = AuthStateJsonGenerator.dummyToken, + error = NotAuthorizedException.invoke { } + ) + ) + ).toJsonElement() + ) + ), + api = successCase.api.copy( + options = mapOf("globalSignOut" to true).toJsonElement() + ) + ) + + private val globalErrorCase = successCase.copy( + description = "Test that global signOut error returns partial success with global sign out error", + preConditions = successCase.preConditions.copy( + mockedResponses = listOf(mockedGlobalSignOutFailureResponse) + ), + validations = listOf( + ExpectationShapes.Amplify( + apiName = AuthAPI.signOut, + responseType = ResponseType.Complete, + response = AWSCognitoAuthSignOutResult.PartialSignOut( + globalSignOutError = GlobalSignOutError( + GlobalSignOutErrorData( + accessToken = AuthStateJsonGenerator.dummyToken, + error = NotAuthorizedException.invoke { } + ) + ), + revokeTokenError = RevokeTokenError( + RevokeTokenErrorData( + refreshToken = AuthStateJsonGenerator.dummyToken, + error = Exception("RevokeToken not attempted because GlobalSignOut failed.") + ) + ) + ).toJsonElement() ) ), - api = signedInSuccessCase.api.copy( + api = successCase.api.copy( options = mapOf("globalSignOut" to true).toJsonElement() ) ) - override val serializables: List = listOf(signedOutSuccessCase, signedInSuccessCase, globalSignedInSuccessCase) + override val serializables: List = listOf( + successCase, + signedOutSuccessCase, + revokeTokenErrorCase, + revokeTokenWithGlobalSignOutErrorCase, + globalSuccessCase, + globalErrorCase + ) } diff --git a/aws-auth-cognito/src/test/resources/feature-test/testsuites/signOut/Test_that_globalSignOut_returns_partial_success_with_revoke_token_error.json b/aws-auth-cognito/src/test/resources/feature-test/testsuites/signOut/Test_that_globalSignOut_returns_partial_success_with_revoke_token_error.json new file mode 100644 index 0000000000..ece33c3204 --- /dev/null +++ b/aws-auth-cognito/src/test/resources/feature-test/testsuites/signOut/Test_that_globalSignOut_returns_partial_success_with_revoke_token_error.json @@ -0,0 +1,57 @@ +{ + "description": "Test that globalSignOut returns partial success with revoke token error", + "preConditions": { + "amplify-configuration": "authconfiguration.json", + "state": "SignedIn_SessionEstablished.json", + "mockedResponses": [ + { + "type": "cognitoIdentityProvider", + "apiName": "globalSignOut", + "responseType": "success", + "response": { + } + }, + { + "type": "cognitoIdentityProvider", + "apiName": "revokeToken", + "responseType": "failure", + "response": { + "errorType": "NotAuthorizedException", + "errorMessage": null + } + } + ] + }, + "api": { + "name": "signOut", + "params": { + }, + "options": { + "globalSignOut": true + } + }, + "validations": [ + { + "type": "amplify", + "apiName": "signOut", + "responseType": "complete", + "response": { + "globalSignOutError": null, + "hostedUIError": null, + "revokeTokenError": { + "exception": { + "errorType": "RevokeTokenException", + "errorMessage": "Failed to revoke token", + "recoverySuggestion": "See attached exception for more details. RevokeToken can be retried using the CognitoIdentityProviderClient accessible from the escape hatch.", + "cause": { + "errorType": "NotAuthorizedException", + "errorMessage": null + } + }, + "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" + }, + "signedOutLocally": true + } + } + ] +} \ No newline at end of file diff --git a/aws-auth-cognito/src/test/resources/feature-test/testsuites/signOut/Test_that_global_signOut_error_returns_partial_success_with_global_sign_out_error.json b/aws-auth-cognito/src/test/resources/feature-test/testsuites/signOut/Test_that_global_signOut_error_returns_partial_success_with_global_sign_out_error.json new file mode 100644 index 0000000000..80b7fcb772 --- /dev/null +++ b/aws-auth-cognito/src/test/resources/feature-test/testsuites/signOut/Test_that_global_signOut_error_returns_partial_success_with_global_sign_out_error.json @@ -0,0 +1,67 @@ +{ + "description": "Test that global signOut error returns partial success with global sign out error", + "preConditions": { + "amplify-configuration": "authconfiguration.json", + "state": "SignedIn_SessionEstablished.json", + "mockedResponses": [ + { + "type": "cognitoIdentityProvider", + "apiName": "globalSignOut", + "responseType": "failure", + "response": { + "errorType": "NotAuthorizedException", + "errorMessage": null + } + } + ] + }, + "api": { + "name": "signOut", + "params": { + }, + "options": { + "globalSignOut": true + } + }, + "validations": [ + { + "type": "amplify", + "apiName": "signOut", + "responseType": "complete", + "response": { + "globalSignOutError": { + "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "exception": { + "errorType": "GlobalSignOutException", + "errorMessage": "Failed to sign out globally", + "recoverySuggestion": "See attached exception for more details. GlobalSignOut can be retried using the CognitoIdentityProviderClient accessible from the escape hatch.", + "cause": { + "errorType": "NotAuthorizedException", + "errorMessage": null + } + } + }, + "hostedUIError": null, + "revokeTokenError": { + "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "exception": { + "recoverySuggestion": "See attached exception for more details. RevokeToken can be retried using the CognitoIdentityProviderClient accessible from the escape hatch.", + "detailMessage": "Failed to revoke token", + "cause": { + "detailMessage": "RevokeToken not attempted because GlobalSignOut failed.", + "stackTrace": [ + ], + "suppressedExceptions": [ + ] + }, + "stackTrace": [ + ], + "suppressedExceptions": [ + ] + } + }, + "signedOutLocally": true + } + } + ] +} \ No newline at end of file diff --git a/aws-auth-cognito/src/test/resources/feature-test/testsuites/signOut/Test_that_signOut_returns_partial_success_with_revoke_token_error.json b/aws-auth-cognito/src/test/resources/feature-test/testsuites/signOut/Test_that_signOut_returns_partial_success_with_revoke_token_error.json new file mode 100644 index 0000000000..857211df4b --- /dev/null +++ b/aws-auth-cognito/src/test/resources/feature-test/testsuites/signOut/Test_that_signOut_returns_partial_success_with_revoke_token_error.json @@ -0,0 +1,50 @@ +{ + "description": "Test that signOut returns partial success with revoke token error", + "preConditions": { + "amplify-configuration": "authconfiguration.json", + "state": "SignedIn_SessionEstablished.json", + "mockedResponses": [ + { + "type": "cognitoIdentityProvider", + "apiName": "revokeToken", + "responseType": "failure", + "response": { + "errorType": "NotAuthorizedException", + "errorMessage": null + } + } + ] + }, + "api": { + "name": "signOut", + "params": { + }, + "options": { + "globalSignOut": false + } + }, + "validations": [ + { + "type": "amplify", + "apiName": "signOut", + "responseType": "complete", + "response": { + "globalSignOutError": null, + "hostedUIError": null, + "revokeTokenError": { + "exception": { + "errorType": "RevokeTokenException", + "errorMessage": "Failed to revoke token", + "recoverySuggestion": "See attached exception for more details. RevokeToken can be retried using the CognitoIdentityProviderClient accessible from the escape hatch.", + "cause": { + "errorType": "NotAuthorizedException", + "errorMessage": null + } + }, + "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" + }, + "signedOutLocally": true + } + } + ] +} \ No newline at end of file diff --git a/build.gradle b/build.gradle index 26bf10b416..547a37374c 100644 --- a/build.gradle +++ b/build.gradle @@ -27,6 +27,7 @@ buildscript { classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10' classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.7.10" classpath 'org.jlleitschuh.gradle:ktlint-gradle:9.4.1' + classpath "org.gradle:test-retry-gradle-plugin:1.4.1" } } @@ -181,6 +182,16 @@ subprojects { project -> } } } + + apply plugin: 'org.gradle.test-retry' + + tasks.withType(Test).configureEach { + retry { + maxRetries = 9 + maxFailures = 100 + failOnPassedAfterRetry = true + } + } } private void configureAndroidLibrary(Project project) { From 175c3a4022725e2baa5ed7be03eac85442b4afd8 Mon Sep 17 00:00:00 2001 From: Saijad Dhuka <83975678+sdhuka@users.noreply.github.com> Date: Fri, 11 Nov 2022 10:25:37 -0600 Subject: [PATCH 16/36] fix: Errors across storage and analytics category (#2096) * fix: check whether cursor is open before reading * update api documentation * Update progress frequency for transfer operations, prevent simultaneously runs for submit events * fix unit tests Co-authored-by: Sunil Timalsina Co-authored-by: Tyler Roach --- .../analytics/pinpoint/EventRecorder.kt | 18 +++++- .../result/AWSCognitoAuthSignOutResult.kt | 2 +- .../storage/s3/transfer/ProgressListener.kt | 33 +++++++++-- .../storage/s3/transfer/TransferDB.kt | 2 +- .../s3/transfer/TransferStatusUpdater.kt | 13 +++-- .../s3/transfer/TransferWorkerObserver.kt | 28 +++++---- .../s3/transfer/worker/BaseTransferWorker.kt | 2 +- .../s3/transfer/worker/DownloadWorker.kt | 58 +++++++++++-------- .../s3/transfer/worker/DownloadWorkerTest.kt | 19 ++++-- .../operation/StorageTransferOperation.java | 4 +- 10 files changed, 119 insertions(+), 60 deletions(-) diff --git a/aws-analytics-pinpoint/src/main/java/com/amplifyframework/analytics/pinpoint/EventRecorder.kt b/aws-analytics-pinpoint/src/main/java/com/amplifyframework/analytics/pinpoint/EventRecorder.kt index 3bc97bd8c6..3706734c1f 100644 --- a/aws-analytics-pinpoint/src/main/java/com/amplifyframework/analytics/pinpoint/EventRecorder.kt +++ b/aws-analytics-pinpoint/src/main/java/com/amplifyframework/analytics/pinpoint/EventRecorder.kt @@ -53,6 +53,7 @@ internal class EventRecorder( AWS_PINPOINT_ANALYTICS_LOG_NAMESPACE.format(EventRecorder::class.java.simpleName) ) ) { + private var isSyncInProgress = false private val defaultMaxSubmissionAllowed = 3 private val defaultMaxSubmissionSize = 1024 * 100 private val serviceDefinedMaxEventsPerBatch: Int = 100 @@ -71,14 +72,25 @@ internal class EventRecorder( } } + @Synchronized internal suspend fun submitEvents(): List { return withContext(coroutineDispatcher) { val result = runCatching { - processEvents() + if (!isSyncInProgress) { + isSyncInProgress = true + processEvents() + } else { + logger.info("Sync is already in progress, skipping") + emptyList() + } } when { - result.isSuccess -> result.getOrNull() ?: emptyList() + result.isSuccess -> { + isSyncInProgress = false + result.getOrNull() ?: emptyList() + } else -> { + isSyncInProgress = false logger.error("Failed to submit events ${result.exceptionOrNull()}") emptyList() } @@ -115,7 +127,7 @@ internal class EventRecorder( } } currentSubmissions++ - } while (currentSubmissions < maxSubmissionsAllowed && cursor.moveToNext()) + } while (currentSubmissions < maxSubmissionsAllowed && !cursor.isClosed && cursor.moveToNext()) } syncedPinpointEvents.forEach { pinpointEvent -> syncedAnalyticsEvents.add(convertPinpointEventToAnalyticsEvent(pinpointEvent)) diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/result/AWSCognitoAuthSignOutResult.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/result/AWSCognitoAuthSignOutResult.kt index 1005a23e9a..5cbc6d443d 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/result/AWSCognitoAuthSignOutResult.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/result/AWSCognitoAuthSignOutResult.kt @@ -110,7 +110,7 @@ class GlobalSignOutError internal constructor(globalSignOutErrorData: GlobalSign /** * Revoke Token Error - * @param revokeTokenErrorData Information about failed global sign out. + * @param revokeTokenErrorData Information about failed token revocation. */ class RevokeTokenError internal constructor(revokeTokenErrorData: RevokeTokenErrorData) { diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/ProgressListener.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/ProgressListener.kt index 3c03bbb679..3052fe2840 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/ProgressListener.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/ProgressListener.kt @@ -15,6 +15,7 @@ package com.amplifyframework.storage.s3.transfer import java.util.concurrent.atomic.AtomicLong +import kotlin.math.min /** * ProgressListener to track progress for any S3 transfer request. @@ -34,6 +35,7 @@ internal class MultiPartUploadTaskListener( ProgressListener { private var totalBytesTransferred: AtomicLong = AtomicLong(0L) + private var progressUpdateSink: AtomicLong = AtomicLong(0L) init { val previouslyTransferBytes = @@ -41,13 +43,20 @@ internal class MultiPartUploadTaskListener( totalBytesTransferred.getAndAdd(previouslyTransferBytes) } + @Synchronized override fun progressChanged(bytesTransferred: Long) { totalBytesTransferred.getAndAdd(bytesTransferred) transferRecord.bytesCurrent = totalBytesTransferred.get() if (transferRecord.bytesCurrent > transferRecord.bytesTotal) { transferRecord.bytesCurrent = transferRecord.bytesTotal } - updateProgress(true) + progressUpdateSink.getAndAdd(bytesTransferred) + if (progressUpdateSink.get() >= + min(transferRecord.bytesTotal / 100, transferRecord.bytesTotal - transferRecord.bytesCurrent) + ) { + updateProgress(true) + progressUpdateSink.getAndSet(0L) + } } private fun updateProgress(notifyListener: Boolean) { @@ -92,12 +101,19 @@ internal class UploadProgressListener( ) : ProgressListener { private var bytesTransferredSoFar = 0L + private var progressUpdateSink = 0L @Synchronized override fun progressChanged(byteTransferred: Long) { + progressUpdateSink += byteTransferred bytesTransferredSoFar += byteTransferred transferRecord.bytesCurrent = bytesTransferredSoFar - updateProgress(true) + if (progressUpdateSink >= + min(transferRecord.bytesTotal / 100, transferRecord.bytesTotal - transferRecord.bytesCurrent) + ) { + updateProgress(true) + progressUpdateSink = 0L + } } private fun updateProgress(notifyListener: Boolean) { @@ -118,6 +134,7 @@ internal class DownloadProgressListener( private val transferStatusUpdater: TransferStatusUpdater ) : ProgressListener { private var bytesTransferredSoFar = 0L + private var progressUpdateSink = 0L init { bytesTransferredSoFar = transferRecord.bytesCurrent @@ -125,11 +142,17 @@ internal class DownloadProgressListener( override fun progressChanged(bytesTransferred: Long) { bytesTransferredSoFar += bytesTransferred + progressUpdateSink += bytesTransferred transferRecord.bytesCurrent = bytesTransferredSoFar if (transferRecord.bytesCurrent > transferRecord.bytesTotal) { transferRecord.bytesCurrent = transferRecord.bytesTotal } - updateProgress() + if (progressUpdateSink >= + min(transferRecord.bytesTotal / 100, transferRecord.bytesTotal - transferRecord.bytesCurrent) + ) { + updateProgress() + progressUpdateSink = 0L + } } private fun updateProgress() { @@ -137,7 +160,9 @@ internal class DownloadProgressListener( transferRecord.id, transferRecord.bytesCurrent, transferRecord.bytesTotal, - true + true, + // writing progress to DB is not required for download operation, as current progress could be inferred from the file length + updateDB = false ) } } diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferDB.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferDB.kt index 2d52bcf6fa..f069908202 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferDB.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferDB.kt @@ -639,7 +639,7 @@ internal class TransferDB private constructor(context: Context) { null, selection = TransferTable.COLUMN_STATE + "!=?", arrayOf( - TransferState.COMPLETED.toString() + TransferState.PART_COMPLETED.toString() ), null ) diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferStatusUpdater.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferStatusUpdater.kt index e388f52696..ef180800c5 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferStatusUpdater.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferStatusUpdater.kt @@ -44,7 +44,7 @@ internal class TransferStatusUpdater private constructor( } val activeTransferMap = object : AbstractMutableMap() { - val transferRecordMap = mutableMapOf() + val transferRecordMap = ConcurrentHashMap() override fun put(key: Int, value: TransferRecord): TransferRecord? { return transferRecordMap.put(key, value) @@ -124,13 +124,16 @@ internal class TransferStatusUpdater private constructor( transferRecordId: Int, bytesCurrent: Long, bytesTotal: Long, - notifyListener: Boolean + notifyListener: Boolean, + updateDB: Boolean = true ) { activeTransferMap[transferRecordId]?.let { it.bytesCurrent = bytesCurrent it.bytesTotal = bytesTotal } - transferDB.updateBytesTransferred(transferRecordId, bytesCurrent, bytesTotal) + if (updateDB) { + transferDB.updateBytesTransferred(transferRecordId, bytesCurrent, bytesTotal) + } if (notifyListener) { transferStatusListenerMap[transferRecordId]?.forEach { mainHandler.post { @@ -174,9 +177,7 @@ internal class TransferStatusUpdater private constructor( transferRecordId: Int, transferListener: MultiPartUploadTaskListener ) { - if (!multiPartTransferStatusListener.containsKey(transferRecordId)) { - multiPartTransferStatusListener[transferRecordId] = transferListener - } + multiPartTransferStatusListener[transferRecordId] = transferListener } fun getMultiPartTransferListener(transferRecordId: Int): MultiPartUploadTaskListener? { diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferWorkerObserver.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferWorkerObserver.kt index 5a1c00be4a..3c8f2dc04c 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferWorkerObserver.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferWorkerObserver.kt @@ -111,7 +111,7 @@ internal class TransferWorkerObserver private constructor( WorkInfo.State.FAILED to TransferState.FAILED, WorkInfo.State.SUCCEEDED to TransferState.COMPLETED ) - updateTransferState(transferRecord, workManagerToAmplifyStatesMap[workInfo.state], workInfo.id.toString()) + updateTransferState(transferRecord.id, workManagerToAmplifyStatesMap[workInfo.state], workInfo.id.toString()) if (workInfo.state.isFinished || transferRecord.state == TransferState.PAUSED) { logger.debug("remove observer for ${transferRecord.id}") removeObserver(transferRecord.id.toString()) @@ -139,7 +139,7 @@ internal class TransferWorkerObserver private constructor( } if (workInfo.state.isFinished) { updateTransferState( - transferRecord, + transferRecord.id, workManagerToAmplifyStatesMap[workInfo.state], workInfo.id.toString() ) @@ -149,21 +149,19 @@ internal class TransferWorkerObserver private constructor( } } - private fun updateTransferState(transferRecord: TransferRecord, transferState: TransferState?, workInfoId: String) { - transferRecord.state?.let { + private fun updateTransferState(transferRecordId: Int, transferState: TransferState?, workInfoId: String) { + transferStatusUpdater.activeTransferMap[transferRecordId]?.state?.let { state -> var nextState = transferState ?: TransferState.UNKNOWN - transferRecord.state?.let { state -> - if (TransferState.isPaused(state)) { - nextState = TransferState.PAUSED - transferStatusUpdater.removeWorkInfoId(workInfoId) - } - if (TransferState.isCancelled(state)) { - nextState = TransferState.CANCELED - transferStatusUpdater.removeWorkInfoId(workInfoId) - } + if (TransferState.isPaused(state)) { + nextState = TransferState.PAUSED + transferStatusUpdater.removeWorkInfoId(workInfoId) + } + if (TransferState.isCancelled(state)) { + nextState = TransferState.CANCELED + transferStatusUpdater.removeWorkInfoId(workInfoId) } - if (!TransferState.isInTerminalState(transferRecord.state)) { - transferStatusUpdater.updateTransferState(transferRecord.id, nextState) + if (!TransferState.isInTerminalState(state)) { + transferStatusUpdater.updateTransferState(transferRecordId, nextState) } } } diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/BaseTransferWorker.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/BaseTransferWorker.kt index f62e8f534c..de399907fa 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/BaseTransferWorker.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/BaseTransferWorker.kt @@ -111,7 +111,7 @@ internal abstract class BaseTransferWorker( } else -> { val ex = result.exceptionOrNull() - logger.error("${this.javaClass.simpleName} failed with exception: $ex") + logger.error("${this.javaClass.simpleName} failed with exception: $ex, stacktrace: ${ex?.stackTrace}") if (isRetryableError(ex)) { Result.retry() } else { diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/DownloadWorker.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/DownloadWorker.kt index e9092effad..225dde2b28 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/DownloadWorker.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/DownloadWorker.kt @@ -20,12 +20,14 @@ import androidx.work.WorkerParameters import aws.sdk.kotlin.services.s3.S3Client import aws.sdk.kotlin.services.s3.model.GetObjectRequest import aws.smithy.kotlin.runtime.content.ByteStream -import aws.smithy.kotlin.runtime.io.writeChannel import aws.smithy.kotlin.runtime.util.InternalApi import com.amplifyframework.storage.s3.transfer.DownloadProgressListener import com.amplifyframework.storage.s3.transfer.TransferDB import com.amplifyframework.storage.s3.transfer.TransferStatusUpdater +import java.io.BufferedOutputStream import java.io.File +import java.io.FileOutputStream +import kotlinx.coroutines.runBlocking /** * Worker to perform download file task. @@ -39,23 +41,26 @@ internal class DownloadWorker( ) : BaseTransferWorker(transferStatusUpdater, transferDB, context, workerParameters) { private lateinit var downloadProgressListener: DownloadProgressListener - private val defaultBufferSize = 16 * 1024 + private val defaultBufferSize = 4096 @OptIn(InternalApi::class) override suspend fun performWork(): Result { - downloadProgressListener = DownloadProgressListener(transferRecord, transferStatusUpdater) val file = File(transferRecord.file) val downloadedBytes = file.length() + if (downloadedBytes > 0 && transferRecord.bytesTotal == downloadedBytes) { + return Result.success(outputData) + } val getObjectRequest = GetObjectRequest { key = transferRecord.key bucket = transferRecord.bucketName - range = downloadedBytes.toString() + range = "bytes=$downloadedBytes-" } return s3.getObject(getObjectRequest) { response -> - val totalBytes = response.contentLength + val totalBytes = (response.body?.contentLength ?: 0L) + downloadedBytes transferRecord.bytesTotal = totalBytes transferRecord.bytesCurrent = downloadedBytes file.parentFile?.takeIf { !it.exists() }?.mkdirs() + downloadProgressListener = DownloadProgressListener(transferRecord, transferStatusUpdater) writeToFileWithProgressUpdates(response.body as ByteStream.OneShotStream, file, downloadProgressListener) transferStatusUpdater.updateProgress( transferRecord.id, @@ -68,29 +73,36 @@ internal class DownloadWorker( } @OptIn(InternalApi::class) - private suspend fun writeToFileWithProgressUpdates( + private fun writeToFileWithProgressUpdates( stream: ByteStream.OneShotStream, file: File, progressListener: DownloadProgressListener ) { - val limit = stream.contentLength ?: 0L - val buffer = ByteArray(defaultBufferSize) + var outputStream: BufferedOutputStream? = null val sdkByteReadChannel = stream.readFrom() - file.writeChannel().use { destination -> - val flushDst = !destination.autoFlush - val copied = 0L - while (true) { - val remaining = limit - copied - if (remaining == 0L) break - val readBytes = - sdkByteReadChannel.readAvailable(buffer, 0, minOf(buffer.size.toLong(), remaining).toInt()) - if (readBytes == -1) break - if (readBytes > 0) { - progressListener.progressChanged(readBytes.toLong()) - } - destination.writeFully(buffer, 0, readBytes) - if (flushDst && stream.readFrom().availableForRead == 0) { - destination.flush() + runBlocking { + val limit = stream.contentLength ?: 0L + val buffer = ByteArray(defaultBufferSize) + val append = file.length() > 0 + val fileOutputStream = FileOutputStream(file, append) + outputStream = BufferedOutputStream(fileOutputStream) + var totalRead = 0L + outputStream?.use { fileOutput -> + val copied = 0L + while (!isStopped) { + val remaining = limit - copied + if (remaining == 0L) break + val readBytes = + sdkByteReadChannel.readAvailable(buffer, 0, minOf(buffer.size.toLong(), remaining).toInt()) + if (readBytes == -1) break + if (readBytes > 0) { + totalRead += readBytes + progressListener.progressChanged(readBytes.toLong()) + } + fileOutput.write(buffer, 0, readBytes) + if (sdkByteReadChannel.availableForRead == 0) { + fileOutput.flush() + } } } } diff --git a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/DownloadWorkerTest.kt b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/DownloadWorkerTest.kt index 53f0ffb3ff..63f49d0250 100644 --- a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/DownloadWorkerTest.kt +++ b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/transfer/worker/DownloadWorkerTest.kt @@ -77,8 +77,8 @@ internal class DownloadWorkerTest { ) val response = GetObjectResponse { - contentLength = 1000 - body = ByteStream.readAsOneShotStream(createFile(1000)) + contentLength = 10 + body = ByteStream.readAsOneShotStream(createFile(10)) } coEvery { s3Client.getObject( @@ -87,12 +87,13 @@ internal class DownloadWorkerTest { ) }.coAnswers { secondArg ListenableWorker.Result>().invoke(response) } every { transferDB.getTransferRecordById(any()) }.answers { transferRecord } - every { transferStatusUpdater.updateProgress(1, any(), any(), true) }.answers { } + every { transferStatusUpdater.updateProgress(1, any(), any(), true, false) }.answers { } + every { transferStatusUpdater.updateProgress(1, any(), any(), true, true) }.answers { } val worker = DownloadWorker(s3Client, transferDB, transferStatusUpdater, context, workerParameters) val result = worker.doWork() - verify(atLeast = 1) { transferStatusUpdater.updateProgress(1, 1000, 1000, true) } + verify(atLeast = 1) { transferStatusUpdater.updateProgress(1, 10 * 1024 * 1024, 10 * 1024 * 1024, true, true) } val expectedResult = ListenableWorker.Result.success(workDataOf(BaseTransferWorker.OUTPUT_TRANSFER_RECORD_ID to 1)) assertEquals(expectedResult, result) @@ -121,7 +122,15 @@ internal class DownloadWorkerTest { val worker = DownloadWorker(s3Client, transferDB, transferStatusUpdater, context, workerParameters) val result = worker.doWork() - verify(exactly = 0) { transferStatusUpdater.updateProgress(1, 1000, 1000, true) } + verify(exactly = 0) { + transferStatusUpdater.updateProgress( + 1, + 1000, + 1000, + notifyListener = true, + updateDB = true + ) + } val expectedResult = ListenableWorker.Result.failure(workDataOf(BaseTransferWorker.OUTPUT_TRANSFER_RECORD_ID to 1)) assertEquals(expectedResult, result) diff --git a/core/src/main/java/com/amplifyframework/storage/operation/StorageTransferOperation.java b/core/src/main/java/com/amplifyframework/storage/operation/StorageTransferOperation.java index 450ce84afd..0e68814c22 100644 --- a/core/src/main/java/com/amplifyframework/storage/operation/StorageTransferOperation.java +++ b/core/src/main/java/com/amplifyframework/storage/operation/StorageTransferOperation.java @@ -236,7 +236,9 @@ private class InternalOnError implements Consumer { @Override public void accept(@NonNull StorageException value) { setError(value); - onError.accept(value); + if (onError != null) { + onError.accept(value); + } } } } From af1693d2fdc149badb28611479042ee29548c445 Mon Sep 17 00:00:00 2001 From: Tyler Roach Date: Mon, 14 Nov 2022 16:40:41 -0500 Subject: [PATCH 17/36] fix(auth): Fix authFlowType getter annotation and correct for null safety (#2109) * Fix authFlowType getter annotation and correct for null safety --- .../auth/cognito/RealAWSCognitoAuthPlugin.kt | 2 +- .../options/AWSCognitoAuthSignInOptions.java | 5 +-- .../options/AWSCognitoAuthSignUpOptions.kt | 34 +++++++++++++++++-- .../options/FederateToIdentityPoolOptions.kt | 6 ++-- .../codegen/data/AuthConfiguration.kt | 4 +-- 5 files changed, 40 insertions(+), 11 deletions(-) diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPlugin.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPlugin.kt index eaf569ee53..b9c3afe5d4 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPlugin.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPlugin.kt @@ -521,7 +521,7 @@ internal class RealAWSCognitoAuthPlugin( } }, { - val signInData = when (options.authFlowType) { + val signInData = when (options.authFlowType ?: configuration.authFlowType) { AuthFlowType.USER_SRP_AUTH -> { SignInData.SRPSignInData(username, password, options.metadata) } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthSignInOptions.java b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthSignInOptions.java index 8d7808d07d..287560916b 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthSignInOptions.java +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthSignInOptions.java @@ -16,6 +16,7 @@ package com.amplifyframework.auth.cognito.options; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.core.util.ObjectsCompat; import com.amplifyframework.auth.options.AuthSignInOptions; @@ -39,7 +40,7 @@ public final class AWSCognitoAuthSignInOptions extends AuthSignInOptions { * @param authFlowType AuthFlowType to be used by signIn API */ protected AWSCognitoAuthSignInOptions( - Map metadata, + @NonNull Map metadata, AuthFlowType authFlowType ) { this.metadata = metadata; @@ -61,7 +62,7 @@ public Map getMetadata() { * * @return authFlowType to be sent to the signIn api */ - @NonNull + @Nullable public AuthFlowType getAuthFlowType() { return authFlowType; } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthSignUpOptions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthSignUpOptions.kt index a4de408074..ca2afd6331 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthSignUpOptions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthSignUpOptions.kt @@ -14,6 +14,7 @@ */ package com.amplifyframework.auth.cognito.options +import androidx.core.util.ObjectsCompat import com.amplifyframework.auth.AuthUserAttribute import com.amplifyframework.auth.options.AuthSignUpOptions import com.amplifyframework.util.Immutable @@ -21,7 +22,7 @@ import com.amplifyframework.util.Immutable /** * Cognito extension of sign up options to add the platform specific fields. */ -data class AWSCognitoAuthSignUpOptions +class AWSCognitoAuthSignUpOptions /** * Advanced options for signing in. * @param userAttributes Additional user attributes which should be associated with this user on registration @@ -29,7 +30,7 @@ data class AWSCognitoAuthSignUpOptions * @param clientMetadata Additional custom attributes to be sent to the service such as information about the client */ internal constructor( - val attributes: List, + userAttributes: List, /** * Get a map of custom key/values to be sent as part of the sign up process. * @return a map of custom key/values to be sent as part of the sign up process @@ -40,7 +41,7 @@ internal constructor( * @return a map of additional custom attributes to be sent to the service such as information about the client */ val clientMetadata: Map -) : AuthSignUpOptions(attributes) { +) : AuthSignUpOptions(userAttributes) { /** * The builder for this class. @@ -115,4 +116,31 @@ internal constructor( CognitoBuilder() .apply(block).build() } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass || other !is AWSCognitoAuthSignUpOptions) return false + if (!super.equals(other)) return false + + if (validationData != other.validationData) return false + if (clientMetadata != other.clientMetadata) return false + + return true + } + + override fun hashCode(): Int { + return ObjectsCompat.hash( + userAttributes, + validationData, + clientMetadata + ) + } + + override fun toString(): String { + return "AuthSignUpOptions{" + + "userAttributes=" + userAttributes + + "validationData=" + validationData + + "clientMetaData=" + clientMetadata + + '}' + } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/FederateToIdentityPoolOptions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/FederateToIdentityPoolOptions.kt index 6f1be47c01..699b52f736 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/FederateToIdentityPoolOptions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/FederateToIdentityPoolOptions.kt @@ -28,11 +28,11 @@ data class FederateToIdentityPoolOptions internal constructor(val developerProvi /** * Set the developerProvidedIdentityId field for the object being built. - * @param _developerProvidedIdentityId Provide identity id for federation to Cognito Identity Provider + * @param developerProvidedIdentityId Provide identity id for federation to Cognito Identity Provider * @return The builder object to continue building. */ - fun developerProvidedIdentityId(_developerProvidedIdentityId: String): Builder { - this.developerProvidedIdentityId = _developerProvidedIdentityId + fun developerProvidedIdentityId(developerProvidedIdentityId: String): Builder { + this.developerProvidedIdentityId = developerProvidedIdentityId return this } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/data/AuthConfiguration.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/data/AuthConfiguration.kt index ec8242adf1..e354ef05e7 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/data/AuthConfiguration.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/data/AuthConfiguration.kt @@ -51,14 +51,14 @@ internal data class AuthConfiguration internal constructor( ?.optJSONObject("OAuth")?.let { OauthConfiguration.fromJson(it) }, - authFlowType = getAutheticationFlowType( + authFlowType = getAuthenticationFlowType( pluginJson.optJSONObject("Auth") ?.optJSONObject(configName) ?.optString("authenticationFlowType") ) ) } - private fun getAutheticationFlowType(authType: String?): AuthFlowType { + private fun getAuthenticationFlowType(authType: String?): AuthFlowType { return if (!authType.isNullOrEmpty() && AuthFlowType.values().any { it.name == authType }) AuthFlowType.valueOf(authType) else From 5c635666cf540eb27974a86e7daf1fd3745e3db2 Mon Sep 17 00:00:00 2001 From: Divyesh Chitroda Date: Tue, 15 Nov 2022 07:00:53 -0800 Subject: [PATCH 18/36] fix(auth): add missing client and analytics metadata (#2110) * fix(auth): add missing client and analytics metadata * fix options classes and add java options tests * fix test * fix after rebase * add inline builders and kotlin options tests --- .../auth/cognito/RealAWSCognitoAuthPlugin.kt | 4 +- .../actions/DeviceSRPCognitoSignInActions.kt | 12 +- .../actions/FetchAuthSessionCognitoActions.kt | 5 +- .../actions/MigrateAuthCognitoActions.kt | 2 + .../auth/cognito/actions/SRPCognitoActions.kt | 18 +-- .../actions/SignInChallengeCognitoActions.kt | 6 +- .../cognito/actions/SignInCognitoActions.kt | 4 +- .../actions/SignInCustomCognitoActions.kt | 3 + ...SCognitoAuthConfirmResetPasswordOptions.kt | 6 +- .../AWSCognitoAuthConfirmSignInOptions.kt | 91 +++--------- .../AWSCognitoAuthConfirmSignUpOptions.kt | 26 +--- .../AWSCognitoAuthResendSignUpCodeOptions.kt | 2 +- ...ndUserAttributeConfirmationCodeOptions.kt} | 40 +++-- .../AWSCognitoAuthResetPasswordOptions.kt | 49 ++---- .../options/AWSCognitoAuthSignInOptions.java | 17 +-- .../options/AWSCognitoAuthSignOutOptions.java | 10 +- .../options/AWSCognitoAuthSignUpOptions.kt | 99 +++---------- ...WSCognitoAuthUpdateUserAttributeOptions.kt | 42 +++--- ...SCognitoAuthUpdateUserAttributesOptions.kt | 38 ++--- .../options/FederateToIdentityPoolOptions.kt | 10 +- .../codegen/events/DeviceSRPSignInEvent.kt | 7 +- .../statemachine/codegen/events/SRPEvent.kt | 7 +- .../codegen/events/SignInChallengeEvent.kt | 2 +- .../cognito/RealAWSCognitoAuthPluginTest.kt | 4 +- .../auth/cognito/StateTransitionTestBase.kt | 2 +- .../options/APIOptionsContractTest.java | 107 ++++++++++++++ .../options/APIOptionsKotlinContractTest.kt | 139 ++++++++++++++++++ 27 files changed, 423 insertions(+), 329 deletions(-) rename aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/{AWSAuthResendUserAttributeConfirmationCodeOptions.kt => AWSCognitoAuthResendUserAttributeConfirmationCodeOptions.kt} (79%) create mode 100644 aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/options/APIOptionsContractTest.java create mode 100644 aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/options/APIOptionsKotlinContractTest.kt diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPlugin.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPlugin.kt index b9c3afe5d4..191dee1dda 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPlugin.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPlugin.kt @@ -58,11 +58,11 @@ import com.amplifyframework.auth.cognito.helpers.HostedUIHelper import com.amplifyframework.auth.cognito.helpers.SessionHelper import com.amplifyframework.auth.cognito.helpers.SignInChallengeHelper import com.amplifyframework.auth.cognito.helpers.identityProviderName -import com.amplifyframework.auth.cognito.options.AWSAuthResendUserAttributeConfirmationCodeOptions import com.amplifyframework.auth.cognito.options.AWSCognitoAuthConfirmResetPasswordOptions import com.amplifyframework.auth.cognito.options.AWSCognitoAuthConfirmSignInOptions import com.amplifyframework.auth.cognito.options.AWSCognitoAuthConfirmSignUpOptions import com.amplifyframework.auth.cognito.options.AWSCognitoAuthResendSignUpCodeOptions +import com.amplifyframework.auth.cognito.options.AWSCognitoAuthResendUserAttributeConfirmationCodeOptions import com.amplifyframework.auth.cognito.options.AWSCognitoAuthSignInOptions import com.amplifyframework.auth.cognito.options.AWSCognitoAuthSignOutOptions import com.amplifyframework.auth.cognito.options.AWSCognitoAuthSignUpOptions @@ -1400,7 +1400,7 @@ internal class RealAWSCognitoAuthPlugin( onSuccess: Consumer, onError: Consumer ) { - val metadataOptions = options as? AWSAuthResendUserAttributeConfirmationCodeOptions + val metadataOptions = options as? AWSCognitoAuthResendUserAttributeConfirmationCodeOptions authStateMachine.getCurrentState { authState -> when (authState.authNState) { // Check if user signed in diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/DeviceSRPCognitoSignInActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/DeviceSRPCognitoSignInActions.kt index ed9ac2c695..2dd6721c84 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/DeviceSRPCognitoSignInActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/DeviceSRPCognitoSignInActions.kt @@ -52,6 +52,7 @@ internal object DeviceSRPCognitoSignInActions : DeviceSRPSignInActions { val evt = try { val encodedContextData = getUserContextData(username) val deviceMetadata = getDeviceMetadata(username) + val pinpointEndpointId = getPinpointEndpointId() srpHelper = SRPHelper(deviceMetadata?.deviceSecret ?: "") @@ -65,6 +66,8 @@ internal object DeviceSRPCognitoSignInActions : DeviceSRPSignInActions { KEY_DEVICE_KEY to (deviceMetadata?.deviceKey ?: ""), KEY_SRP_A to srpHelper.getPublicA() ) + clientMetadata = event.metadata + pinpointEndpointId?.let { analyticsMetadata { analyticsEndpointId = it } } encodedContextData?.let { userContextData { encodedData = it } } } ) @@ -77,7 +80,10 @@ internal object DeviceSRPCognitoSignInActions : DeviceSRPSignInActions { } DeviceSRPSignInEvent( - DeviceSRPSignInEvent.EventType.RespondDevicePasswordVerifier(challengeParams) + DeviceSRPSignInEvent.EventType.RespondDevicePasswordVerifier( + challengeParams, + event.metadata + ) ) } ?: throw ServiceException( "Challenge params are empty.", @@ -115,6 +121,7 @@ internal object DeviceSRPCognitoSignInActions : DeviceSRPSignInActions { val deviceGroupKey = params.getValue(KEY_DEVICE_GROUP_KEY) val encodedContextData = getUserContextData(username) + val pinpointEndpointId = getPinpointEndpointId() srpHelper.setUserPoolParams(deviceKey, deviceGroupKey) @@ -123,6 +130,7 @@ internal object DeviceSRPCognitoSignInActions : DeviceSRPSignInActions { RespondToAuthChallengeRequest.invoke { challengeName = ChallengeNameType.DevicePasswordVerifier clientId = configuration.userPool?.appClient + challengeResponses = mapOf( KEY_USERNAME to username, KEY_PASSWORD_CLAIM_SECRET_BLOCK to secretBlock, @@ -130,6 +138,8 @@ internal object DeviceSRPCognitoSignInActions : DeviceSRPSignInActions { KEY_PASSWORD_CLAIM_SIGNATURE to srpHelper.getSignature(salt, srpB, secretBlock), KEY_DEVICE_KEY to deviceKey ) + clientMetadata = event.metadata + pinpointEndpointId?.let { analyticsMetadata { analyticsEndpointId = it } } encodedContextData?.let { userContextData { encodedData = it } } } ) diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/FetchAuthSessionCognitoActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/FetchAuthSessionCognitoActions.kt index c5a25c7232..15aa86de6c 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/FetchAuthSessionCognitoActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/FetchAuthSessionCognitoActions.kt @@ -18,7 +18,6 @@ package com.amplifyframework.auth.cognito.actions import aws.sdk.kotlin.services.cognitoidentity.model.GetCredentialsForIdentityRequest import aws.sdk.kotlin.services.cognitoidentity.model.GetIdRequest import aws.sdk.kotlin.services.cognitoidentityprovider.initiateAuth -import aws.sdk.kotlin.services.cognitoidentityprovider.model.AnalyticsMetadataType import aws.sdk.kotlin.services.cognitoidentityprovider.model.AuthFlowType import aws.smithy.kotlin.runtime.time.Instant import com.amplifyframework.auth.cognito.AuthEnvironment @@ -71,9 +70,7 @@ internal object FetchAuthSessionCognitoActions : FetchAuthSessionActions { authFlow = AuthFlowType.RefreshToken clientId = configuration.userPool?.appClient this.authParameters = authParameters - pinpointEndpointId?.let { - this.analyticsMetadata = AnalyticsMetadataType.invoke { analyticsEndpointId = it } - } + pinpointEndpointId?.let { analyticsMetadata { analyticsEndpointId = it } } encodedContextData?.let { userContextData { encodedData = it } } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/MigrateAuthCognitoActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/MigrateAuthCognitoActions.kt index 4f07b07c94..a152e536ed 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/MigrateAuthCognitoActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/MigrateAuthCognitoActions.kt @@ -46,12 +46,14 @@ internal object MigrateAuthCognitoActions : MigrateAuthActions { secretHash?.let { authParams[KEY_SECRET_HASH] = it } val encodedContextData = getUserContextData(event.username) + val pinpointEndpointId = getPinpointEndpointId() val response = cognitoAuthService.cognitoIdentityProviderClient?.initiateAuth { authFlow = AuthFlowType.UserPasswordAuth clientId = configuration.userPool?.appClient authParameters = authParams clientMetadata = event.metadata + pinpointEndpointId?.let { analyticsMetadata { analyticsEndpointId = it } } encodedContextData?.let { userContextData { encodedData = it } } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SRPCognitoActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SRPCognitoActions.kt index 1ba0809a4f..37bc5af8b2 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SRPCognitoActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SRPCognitoActions.kt @@ -16,7 +16,6 @@ package com.amplifyframework.auth.cognito.actions import aws.sdk.kotlin.services.cognitoidentityprovider.initiateAuth -import aws.sdk.kotlin.services.cognitoidentityprovider.model.AnalyticsMetadataType import aws.sdk.kotlin.services.cognitoidentityprovider.model.AuthFlowType import aws.sdk.kotlin.services.cognitoidentityprovider.model.ChallengeNameType import aws.sdk.kotlin.services.cognitoidentityprovider.respondToAuthChallenge @@ -71,9 +70,8 @@ internal object SRPCognitoActions : SRPActions { authFlow = AuthFlowType.UserSrpAuth clientId = configuration.userPool?.appClient authParameters = authParams - pinpointEndpointId?.let { - this.analyticsMetadata = AnalyticsMetadataType.invoke { analyticsEndpointId = it } - } + clientMetadata = event.metadata + pinpointEndpointId?.let { analyticsMetadata { analyticsEndpointId = it } } encodedContextData?.let { userContextData { encodedData = it } } } @@ -83,7 +81,7 @@ internal object SRPCognitoActions : SRPActions { params.plus(KEY_DEVICE_KEY to it) } ?: params - SRPEvent(SRPEvent.EventType.RespondPasswordVerifier(challengeParams)) + SRPEvent(SRPEvent.EventType.RespondPasswordVerifier(challengeParams, event.metadata)) } ?: throw Exception("Auth challenge parameters are empty.") else -> throw Exception("Not yet implemented.") } @@ -126,9 +124,8 @@ internal object SRPCognitoActions : SRPActions { authFlow = AuthFlowType.CustomAuth clientId = configuration.userPool?.appClient authParameters = authParams - pinpointEndpointId?.let { - this.analyticsMetadata = AnalyticsMetadataType.invoke { analyticsEndpointId = it } - } + clientMetadata = event.metadata + pinpointEndpointId?.let { analyticsMetadata { analyticsEndpointId = it } } encodedContextData?.let { userContextData { encodedData = it } } } @@ -139,7 +136,7 @@ internal object SRPCognitoActions : SRPActions { params.plus(KEY_DEVICE_KEY to it) } ?: params - SRPEvent(SRPEvent.EventType.RespondPasswordVerifier(challengeParams)) + SRPEvent(SRPEvent.EventType.RespondPasswordVerifier(challengeParams, event.metadata)) } ?: throw ServiceException( "Auth challenge parameters are empty.", AmplifyException.TODO_RECOVERY_SUGGESTION @@ -189,11 +186,14 @@ internal object SRPCognitoActions : SRPActions { challengeParams[KEY_DEVICE_KEY] = deviceKey val encodedContextData = getUserContextData(username) + val pinpointEndpointId = getPinpointEndpointId() val response = cognitoAuthService.cognitoIdentityProviderClient?.respondToAuthChallenge { challengeName = ChallengeNameType.PasswordVerifier clientId = configuration.userPool.appClient challengeResponses = challengeParams + clientMetadata = event.metadata + pinpointEndpointId?.let { analyticsMetadata { analyticsEndpointId = it } } encodedContextData?.let { userContextData { encodedData = it } } } if (response != null) { diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInChallengeCognitoActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInChallengeCognitoActions.kt index 5520a4f02b..ab85b40d49 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInChallengeCognitoActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInChallengeCognitoActions.kt @@ -47,9 +47,6 @@ internal object SignInChallengeCognitoActions : SignInChallengeActions { getChallengeResponseKey(challenge.challengeName)?.also { responseKey -> challengeResponses[responseKey] = event.answer } - event.options.forEach { (key, value) -> - challengeResponses[key] = value - } val secretHash = AuthHelper.getSecretHash( username, @@ -59,12 +56,15 @@ internal object SignInChallengeCognitoActions : SignInChallengeActions { secretHash?.let { challengeResponses[KEY_SECRET_HASH] = it } val encodedContextData = username?.let { getUserContextData(it) } + val pinpointEndpointId = getPinpointEndpointId() val response = cognitoAuthService.cognitoIdentityProviderClient?.respondToAuthChallenge { clientId = configuration.userPool?.appClient challengeName = ChallengeNameType.fromValue(challenge.challengeName) this.challengeResponses = challengeResponses session = challenge.session + clientMetadata = event.metadata + pinpointEndpointId?.let { analyticsMetadata { analyticsEndpointId = it } } encodedContextData?.let { this.userContextData { encodedData = it } } } response?.let { diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInCognitoActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInCognitoActions.kt index 1e984c1d51..6acfdf7e1f 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInCognitoActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInCognitoActions.kt @@ -75,7 +75,9 @@ internal object SignInCognitoActions : SignInActions { override fun startDeviceSRPAuthAction(event: SignInEvent.EventType.InitiateSignInWithDeviceSRP) = Action("StartDeviceSRPAuth") { id, dispatcher -> logger.verbose("$id Starting execution") - val evt = DeviceSRPSignInEvent(DeviceSRPSignInEvent.EventType.RespondDeviceSRPChallenge(event.username)) + val evt = DeviceSRPSignInEvent( + DeviceSRPSignInEvent.EventType.RespondDeviceSRPChallenge(event.username, event.metadata) + ) logger.verbose("$id Sending event ${evt.type}") dispatcher.send(evt) } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInCustomCognitoActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInCustomCognitoActions.kt index 2ae356e19f..82c9da9391 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInCustomCognitoActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInCustomCognitoActions.kt @@ -49,11 +49,14 @@ internal object SignInCustomCognitoActions : CustomSignInActions { val encodedContextData = getUserContextData(event.username) val deviceMetadata = getDeviceMetadata(event.username) deviceMetadata?.let { authParams[KEY_DEVICE_KEY] = it.deviceKey } + val pinpointEndpointId = getPinpointEndpointId() val initiateAuthResponse = cognitoAuthService.cognitoIdentityProviderClient?.initiateAuth { authFlow = AuthFlowType.CustomAuth clientId = configuration.userPool?.appClient authParameters = authParams + clientMetadata = event.metadata + pinpointEndpointId?.let { analyticsMetadata { analyticsEndpointId = it } } encodedContextData?.let { userContextData { encodedData = it } } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthConfirmResetPasswordOptions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthConfirmResetPasswordOptions.kt index ff72331416..c4b4db911c 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthConfirmResetPasswordOptions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthConfirmResetPasswordOptions.kt @@ -21,9 +21,7 @@ import com.amplifyframework.auth.options.AuthConfirmResetPasswordOptions * Cognito extension of confirm reset password options to add the platform specific fields. */ data class AWSCognitoAuthConfirmResetPasswordOptions - -internal constructor(val metadata: Map) : - AuthConfirmResetPasswordOptions() { +internal constructor(val metadata: Map) : AuthConfirmResetPasswordOptions() { companion object { /** @@ -45,7 +43,7 @@ internal constructor(val metadata: Map) : /** * Custom attributes to be sent to the service such as information about the client. */ - var metadata: Map = mapOf() + private var metadata: Map = mapOf() /** * Returns the type of builder this is to support proper flow with it being an extended class. diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthConfirmSignInOptions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthConfirmSignInOptions.kt index 561f2dc615..88bcc66fc1 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthConfirmSignInOptions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthConfirmSignInOptions.kt @@ -15,15 +15,13 @@ package com.amplifyframework.auth.cognito.options -import androidx.core.util.ObjectsCompat import com.amplifyframework.auth.AuthUserAttribute import com.amplifyframework.auth.options.AuthConfirmSignInOptions -import com.amplifyframework.util.Immutable /** * Cognito extension of confirm sign in options to add the platform specific fields. */ -open class AWSCognitoAuthConfirmSignInOptions protected constructor( +data class AWSCognitoAuthConfirmSignInOptions internal constructor( /** * Get custom attributes to be sent to the service such as information about the client. * @return custom attributes to be sent to the service such as information about the client @@ -33,40 +31,28 @@ open class AWSCognitoAuthConfirmSignInOptions protected constructor( * Get additional user attributes which should be associated with this user on confirmSignIn. * @return additional user attributes which should be associated with this user on confirmSignIn */ - var userAttributes: List + val userAttributes: List ) : AuthConfirmSignInOptions() { - override fun hashCode(): Int { - return ObjectsCompat.hash( - metadata, - userAttributes - ) - } - - override fun equals(obj: Any?): Boolean { - return if (this === obj) { - true - } else if (obj == null || javaClass != obj.javaClass || obj !is AWSCognitoAuthConfirmSignInOptions) { - false - } else { - ObjectsCompat.equals(metadata, obj.metadata) && - ObjectsCompat.equals(userAttributes, obj.userAttributes) + companion object { + /** + * Get a builder object. + * @return a builder object. + */ + @JvmStatic + fun builder(): CognitoBuilder { + return CognitoBuilder() } - } - override fun toString(): String { - return "AWSCognitoAuthConfirmSignInOptions{" + - "userAttributes=" + userAttributes + - ", metadata=" + metadata + - '}' + inline operator fun invoke(block: CognitoBuilder.() -> Unit) = CognitoBuilder().apply(block).build() } /** * The builder for this class. */ class CognitoBuilder : Builder() { - private val metadata: MutableMap - private val userAttributes: MutableList + private var metadata: Map = mapOf() + private var userAttributes: List = listOf() /** * Returns the type of builder this is to support proper flow with it being an extended class. @@ -78,64 +64,23 @@ open class AWSCognitoAuthConfirmSignInOptions protected constructor( /** * Set the metadata field for the object being built. - * @param _metadata Custom user metadata to be sent with the sign in request. + * @param metadata Custom user metadata to be sent with the sign in request. * @return The builder object to continue building. */ - fun metadata(_metadata: Map): CognitoBuilder { - this.metadata.clear() - this.metadata.putAll(_metadata) - return getThis() - } + fun metadata(metadata: Map) = apply { this.metadata = metadata } /** * Set the userAttributes field for the object being built. - * @param _userAttributes A list of additional user attributes which should be + * @param userAttributes A list of additional user attributes which should be * * associated with this user on confirmSignIn. * @return the instance of the builder. */ - fun userAttributes(_userAttributes: List): CognitoBuilder { - this.userAttributes.clear() - this.userAttributes.addAll(_userAttributes) - return getThis() - } + fun userAttributes(userAttributes: List) = apply { this.userAttributes = userAttributes } /** * Construct and return the object with the values set in the builder. * @return a new instance of AWSCognitoAuthConfirmSignInOptions with the values specified in the builder. */ - override fun build(): AuthConfirmSignInOptions { - return AWSCognitoAuthConfirmSignInOptions( - Immutable.of(metadata), - Immutable.of(userAttributes) - ) - } - - /** - * Constructor for the builder. - */ - init { - metadata = HashMap() - userAttributes = ArrayList() - } - } - - companion object { - /** - * Get a builder object. - * @return a builder object. - */ - fun builder(): CognitoBuilder { - return CognitoBuilder() - } - } - - /** - * Advanced options for confirming sign in. - * @param metadata Additional custom attributes to be sent to the service such as information about the client - * @param userAttributes A list of additional user attributes which should be - * associated with this user on confirmSignIn. - */ - init { - userAttributes = userAttributes + override fun build() = AWSCognitoAuthConfirmSignInOptions(metadata, userAttributes) } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthConfirmSignUpOptions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthConfirmSignUpOptions.kt index c2146d1eb3..ca5090dbbe 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthConfirmSignUpOptions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthConfirmSignUpOptions.kt @@ -15,7 +15,6 @@ package com.amplifyframework.auth.cognito.options import com.amplifyframework.auth.options.AuthConfirmSignUpOptions -import com.amplifyframework.util.Immutable /** * Cognito extension of confirm sign up options to add the platform specific fields. @@ -37,16 +36,14 @@ internal constructor(val clientMetadata: Map) : AuthConfirmSignU return CognitoBuilder() } - inline operator fun invoke(block: CognitoBuilder.() -> Unit) = - CognitoBuilder() - .apply(block).build() + inline operator fun invoke(block: CognitoBuilder.() -> Unit) = CognitoBuilder().apply(block).build() } /** * The builder for this class. */ class CognitoBuilder : Builder() { - private val clientMetadata: MutableMap + private var clientMetadata: Map = mapOf() /** * Returns the type of builder this is to support proper flow with it being an extended class. @@ -61,27 +58,12 @@ internal constructor(val clientMetadata: Map) : AuthConfirmSignU * @param clientMetadata Custom user metadata to be sent with the sign up request. * @return The builder object to continue building. */ - fun clientMetadata(clientMetadata: Map): CognitoBuilder { - this.clientMetadata.clear() - this.clientMetadata.putAll(clientMetadata) - return getThis() - } + fun clientMetadata(clientMetadata: Map) = apply { this.clientMetadata = clientMetadata } /** * Construct and return the object with the values set in the builder. * @return a new instance of AWSCognitoAuthConfirmSignUpOptions with the values specified in the builder. */ - override fun build(): AWSCognitoAuthConfirmSignUpOptions { - return AWSCognitoAuthConfirmSignUpOptions( - Immutable.of(clientMetadata) - ) - } - - /** - * Constructor for the builder. - */ - init { - clientMetadata = HashMap() - } + override fun build() = AWSCognitoAuthConfirmSignUpOptions(clientMetadata) } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthResendSignUpCodeOptions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthResendSignUpCodeOptions.kt index 67392e29ca..23ff079466 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthResendSignUpCodeOptions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthResendSignUpCodeOptions.kt @@ -44,7 +44,7 @@ internal constructor(val metadata: Map) : AuthResendSignUpCodeOp * The builder for this class. */ class CognitoBuilder : Builder() { - var metadata: Map = mapOf() + private var metadata: Map = mapOf() /** * Returns the type of builder this is to support proper flow with it being an extended class. diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSAuthResendUserAttributeConfirmationCodeOptions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthResendUserAttributeConfirmationCodeOptions.kt similarity index 79% rename from aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSAuthResendUserAttributeConfirmationCodeOptions.kt rename to aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthResendUserAttributeConfirmationCodeOptions.kt index 4ef47ef3b6..7b90b70722 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSAuthResendUserAttributeConfirmationCodeOptions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthResendUserAttributeConfirmationCodeOptions.kt @@ -16,12 +16,11 @@ package com.amplifyframework.auth.cognito.options import com.amplifyframework.auth.options.AuthResendUserAttributeConfirmationCodeOptions -import com.amplifyframework.util.Immutable /** * Cognito extension of resend user attributes confirmation code options to add the platform specific fields. */ -data class AWSAuthResendUserAttributeConfirmationCodeOptions +data class AWSCognitoAuthResendUserAttributeConfirmationCodeOptions /** * Advanced options for update user attributes. * @param metadata Additional custom attributes to be sent to the service such as information about the client @@ -30,11 +29,24 @@ internal constructor( val metadata: Map ) : AuthResendUserAttributeConfirmationCodeOptions() { + companion object { + /** + * Get a builder object. + * @return a builder object. + */ + @JvmStatic + fun builder(): CognitoBuilder { + return CognitoBuilder() + } + + inline operator fun invoke(block: CognitoBuilder.() -> Unit) = CognitoBuilder().apply(block).build() + } + /** * The builder for this class. */ class CognitoBuilder : Builder() { - private val metadata: MutableMap = HashMap() + private var metadata: Map = mapOf() /** * Returns the type of builder this is to support proper flow with it being an extended class. @@ -49,30 +61,12 @@ internal constructor( * @param metadata Custom user metadata to be sent with the update user attributes request. * @return The builder object to continue building. */ - fun metadata(metadata: Map): CognitoBuilder { - this.metadata.clear() - this.metadata.putAll(metadata) - return getThis() - } + fun metadata(metadata: Map) = apply { this.metadata = metadata } /** * Construct and return the object with the values set in the builder. * @return a new instance of AWSAuthResendUserAttributeConfirmationCodeOptions with the values specified in the builder. */ - override fun build(): AuthResendUserAttributeConfirmationCodeOptions { - return AWSAuthResendUserAttributeConfirmationCodeOptions( - Immutable.of(metadata) - ) - } - } - - companion object { - /** - * Get a builder object. - * @return a builder object. - */ - fun builder(): CognitoBuilder { - return CognitoBuilder() - } + override fun build() = AWSCognitoAuthResendUserAttributeConfirmationCodeOptions(metadata) } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthResetPasswordOptions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthResetPasswordOptions.kt index 101b44993d..90cb9ac003 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthResetPasswordOptions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthResetPasswordOptions.kt @@ -15,7 +15,6 @@ package com.amplifyframework.auth.cognito.options import com.amplifyframework.auth.options.AuthResetPasswordOptions -import com.amplifyframework.util.Immutable /** * Cognito extension of reset password options to add the platform specific fields. @@ -29,11 +28,24 @@ internal constructor( val metadata: Map ) : AuthResetPasswordOptions() { + companion object { + /** + * Get a builder object. + * @return a builder object. + */ + @JvmStatic + fun builder(): CognitoBuilder { + return CognitoBuilder() + } + + inline operator fun invoke(block: CognitoBuilder.() -> Unit) = CognitoBuilder().apply(block).build() + } + /** * The builder for this class. */ class CognitoBuilder : Builder() { - private val metadata: MutableMap + private var metadata: Map = mapOf() /** * Returns the type of builder this is to support proper flow with it being an extended class. @@ -48,41 +60,12 @@ internal constructor( * @param metadata Custom user metadata to be sent with the reset password request. * @return The builder object to continue building. */ - fun metadata(metadata: Map): CognitoBuilder { - this.metadata.clear() - this.metadata.putAll(metadata) - return getThis() - } + fun metadata(metadata: Map) = apply { this.metadata = metadata } /** * Construct and return the object with the values set in the builder. * @return a new instance of AWSCognitoAuthResetPasswordOptions with the values specified in the builder. */ - override fun build(): AWSCognitoAuthResetPasswordOptions { - return AWSCognitoAuthResetPasswordOptions( - Immutable.of(metadata) - ) - } - - /** - * Constructor for the builder. - */ - init { - metadata = HashMap() - } - } - - companion object { - /** - * Get a builder object. - * @return a builder object. - */ - @JvmStatic - fun builder(): CognitoBuilder { - return CognitoBuilder() - } - - inline operator fun invoke(block: CognitoBuilder.() -> Unit) = CognitoBuilder() - .apply(block).build() + override fun build() = AWSCognitoAuthResetPasswordOptions(metadata) } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthSignInOptions.java b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthSignInOptions.java index 287560916b..a10a1b7183 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthSignInOptions.java +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthSignInOptions.java @@ -79,9 +79,7 @@ public static CognitoBuilder builder() { @Override public int hashCode() { - return ObjectsCompat.hash( - getMetadata() - ); + return ObjectsCompat.hash(getMetadata(), getAuthFlowType()); } @Override @@ -92,14 +90,16 @@ public boolean equals(Object obj) { return false; } else { AWSCognitoAuthSignInOptions authSignInOptions = (AWSCognitoAuthSignInOptions) obj; - return ObjectsCompat.equals(getMetadata(), authSignInOptions.getMetadata()); + return ObjectsCompat.equals(getMetadata(), authSignInOptions.getMetadata()) && + ObjectsCompat.equals(getAuthFlowType(), authSignInOptions.getAuthFlowType()); } } @Override public String toString() { return "AWSCognitoAuthSignInOptions{" + - "metadata=" + metadata + + "metadata=" + getMetadata() + + ", authFlowType=" + getAuthFlowType() + '}'; } @@ -107,7 +107,7 @@ public String toString() { * The builder for this class. */ public static final class CognitoBuilder extends Builder { - private Map metadata; + private final Map metadata; private AuthFlowType authFlowType; /** @@ -161,10 +161,7 @@ public CognitoBuilder authFlowType(@NonNull AuthFlowType authFlowType) { */ @NonNull public AWSCognitoAuthSignInOptions build() { - return new AWSCognitoAuthSignInOptions( - Immutable.of(metadata), - authFlowType - ); + return new AWSCognitoAuthSignInOptions(Immutable.of(metadata), authFlowType); } } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthSignOutOptions.java b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthSignOutOptions.java index 9ae43f6beb..1170698202 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthSignOutOptions.java +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthSignOutOptions.java @@ -59,10 +59,7 @@ public static CognitoBuilder builder() { @Override public int hashCode() { - return ObjectsCompat.hash( - isGlobalSignOut(), - getBrowserPackage() - ); + return ObjectsCompat.hash(isGlobalSignOut(), getBrowserPackage()); } @Override @@ -120,10 +117,7 @@ public CognitoBuilder browserPackage(@NonNull String browserPackage) { */ @NonNull public AWSCognitoAuthSignOutOptions build() { - return new AWSCognitoAuthSignOutOptions( - super.isGlobalSignOut(), - browserPackage - ); + return new AWSCognitoAuthSignOutOptions(super.isGlobalSignOut(), browserPackage); } } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthSignUpOptions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthSignUpOptions.kt index ca2afd6331..8ba649fd2d 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthSignUpOptions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthSignUpOptions.kt @@ -12,25 +12,25 @@ * express or implied. See the License for the specific language governing * permissions and limitations under the License. */ + package com.amplifyframework.auth.cognito.options -import androidx.core.util.ObjectsCompat import com.amplifyframework.auth.AuthUserAttribute import com.amplifyframework.auth.options.AuthSignUpOptions -import com.amplifyframework.util.Immutable /** * Cognito extension of sign up options to add the platform specific fields. */ -class AWSCognitoAuthSignUpOptions +data class AWSCognitoAuthSignUpOptions /** * Advanced options for signing in. - * @param userAttributes Additional user attributes which should be associated with this user on registration + * @param attributes Additional user attributes which should be associated with this user on registration * @param validationData A map of custom key/values to be sent as part of the sign up process * @param clientMetadata Additional custom attributes to be sent to the service such as information about the client */ internal constructor( - userAttributes: List, + @get:JvmName("getAttributes") + private val attributes: List, /** * Get a map of custom key/values to be sent as part of the sign up process. * @return a map of custom key/values to be sent as part of the sign up process @@ -41,14 +41,27 @@ internal constructor( * @return a map of additional custom attributes to be sent to the service such as information about the client */ val clientMetadata: Map -) : AuthSignUpOptions(userAttributes) { +) : AuthSignUpOptions(attributes) { + + companion object { + /** + * Get a builder object. + * @return a builder object. + */ + @JvmStatic + fun builder(): CognitoBuilder { + return CognitoBuilder() + } + + inline operator fun invoke(block: CognitoBuilder.() -> Unit) = CognitoBuilder().apply(block).build() + } /** * The builder for this class. */ class CognitoBuilder : Builder() { - private val validationData: MutableMap - private val clientMetadata: MutableMap + private var validationData: Map = mapOf() + private var clientMetadata: Map = mapOf() /** * Gets the type of builder to support proper flow with this being an extended class. @@ -63,11 +76,7 @@ internal constructor( * @param validationData A map of custom data the user can send as part of the sign up process for validation. * @return the instance of the builder. */ - fun validationData(validationData: Map): CognitoBuilder { - this.validationData.clear() - this.validationData.putAll(validationData) - return getThis() - } + fun validationData(validationData: Map) = apply { this.validationData = validationData } /** * A map of additional custom attributes to be sent to the service such as information about the client. @@ -75,72 +84,12 @@ internal constructor( * about the client. * @return the instance of the builder. */ - fun clientMetadata(clientMetadata: Map): CognitoBuilder { - this.clientMetadata.clear() - this.clientMetadata.putAll(clientMetadata) - return getThis() - } + fun clientMetadata(clientMetadata: Map) = apply { this.clientMetadata = clientMetadata } /** * Build the object. * @return a new instance of AWSCognitoAuthSignUpOptions. */ - override fun build(): AWSCognitoAuthSignUpOptions { - return AWSCognitoAuthSignUpOptions( - Immutable.of(super.getUserAttributes()), - Immutable.of(validationData), - Immutable.of(clientMetadata) - ) - } - - /** - * Constructs the builder. - */ - init { - validationData = HashMap() - clientMetadata = HashMap() - } - } - - companion object { - /** - * Get a builder object. - * @return a builder object. - */ - @JvmStatic - fun builder(): CognitoBuilder { - return CognitoBuilder() - } - - inline operator fun invoke(block: CognitoBuilder.() -> Unit) = - CognitoBuilder() - .apply(block).build() - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass || other !is AWSCognitoAuthSignUpOptions) return false - if (!super.equals(other)) return false - - if (validationData != other.validationData) return false - if (clientMetadata != other.clientMetadata) return false - - return true - } - - override fun hashCode(): Int { - return ObjectsCompat.hash( - userAttributes, - validationData, - clientMetadata - ) - } - - override fun toString(): String { - return "AuthSignUpOptions{" + - "userAttributes=" + userAttributes + - "validationData=" + validationData + - "clientMetaData=" + clientMetadata + - '}' + override fun build() = AWSCognitoAuthSignUpOptions(super.getUserAttributes(), validationData, clientMetadata) } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthUpdateUserAttributeOptions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthUpdateUserAttributeOptions.kt index 76d94e13d8..811c9b0122 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthUpdateUserAttributeOptions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthUpdateUserAttributeOptions.kt @@ -16,7 +16,6 @@ package com.amplifyframework.auth.cognito.options import com.amplifyframework.auth.options.AuthUpdateUserAttributeOptions -import com.amplifyframework.util.Immutable /** * Cognito extension of update user attributes options to add the platform specific fields. @@ -26,15 +25,26 @@ data class AWSCognitoAuthUpdateUserAttributeOptions * Advanced options for update user attributes. * @param metadata Additional custom attributes to be sent to the service such as information about the client */ -internal constructor( - val metadata: Map -) : AuthUpdateUserAttributeOptions() { +internal constructor(val metadata: Map) : AuthUpdateUserAttributeOptions() { + + companion object { + /** + * Get a builder object. + * @return a builder object. + */ + @JvmStatic + fun builder(): CognitoBuilder { + return CognitoBuilder() + } + + inline operator fun invoke(block: CognitoBuilder.() -> Unit) = CognitoBuilder().apply(block).build() + } /** * The builder for this class. */ class CognitoBuilder : Builder() { - private val metadata: MutableMap = HashMap() + private var metadata: Map = mapOf() /** * Returns the type of builder this is to support proper flow with it being an extended class. @@ -49,30 +59,12 @@ internal constructor( * @param metadata Custom user metadata to be sent with the update user attributes request. * @return The builder object to continue building. */ - fun metadata(metadata: Map): CognitoBuilder { - this.metadata.clear() - this.metadata.putAll(metadata) - return getThis() - } + fun metadata(metadata: Map) = apply { this.metadata = metadata } /** * Construct and return the object with the values set in the builder. * @return a new instance of AWSCognitoAuthUpdateUserAttributesOptions with the values specified in the builder. */ - override fun build(): AuthUpdateUserAttributeOptions { - return AWSCognitoAuthUpdateUserAttributeOptions( - Immutable.of(metadata) - ) - } - } - - companion object { - /** - * Get a builder object. - * @return a builder object. - */ - fun builder(): CognitoBuilder { - return CognitoBuilder() - } + override fun build() = AWSCognitoAuthUpdateUserAttributeOptions(metadata) } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthUpdateUserAttributesOptions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthUpdateUserAttributesOptions.kt index 04d0705ad5..46df032f55 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthUpdateUserAttributesOptions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/AWSCognitoAuthUpdateUserAttributesOptions.kt @@ -16,7 +16,6 @@ package com.amplifyframework.auth.cognito.options import com.amplifyframework.auth.options.AuthUpdateUserAttributesOptions -import com.amplifyframework.util.Immutable /** * Cognito extension of update user attributes options to add the platform specific fields. @@ -30,11 +29,24 @@ internal constructor( val metadata: Map ) : AuthUpdateUserAttributesOptions() { + companion object { + /** + * Get a builder object. + * @return a builder object. + */ + @JvmStatic + fun builder(): CognitoBuilder { + return CognitoBuilder() + } + + inline operator fun invoke(block: CognitoBuilder.() -> Unit) = CognitoBuilder().apply(block).build() + } + /** * The builder for this class. */ class CognitoBuilder : Builder() { - private val metadata: MutableMap = HashMap() + private var metadata: Map = mapOf() /** * Returns the type of builder this is to support proper flow with it being an extended class. @@ -49,30 +61,12 @@ internal constructor( * @param metadata Custom user metadata to be sent with the update user attributes request. * @return The builder object to continue building. */ - fun metadata(metadata: Map): CognitoBuilder { - this.metadata.clear() - this.metadata.putAll(metadata) - return getThis() - } + fun metadata(metadata: Map) = apply { this.metadata = metadata } /** * Construct and return the object with the values set in the builder. * @return a new instance of AWSCognitoAuthUpdateUserAttributesOptions with the values specified in the builder. */ - override fun build(): AuthUpdateUserAttributesOptions { - return AWSCognitoAuthUpdateUserAttributesOptions( - Immutable.of(metadata) - ) - } - } - - companion object { - /** - * Get a builder object. - * @return a builder object. - */ - fun builder(): CognitoBuilder { - return CognitoBuilder() - } + override fun build() = AWSCognitoAuthUpdateUserAttributesOptions(metadata) } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/FederateToIdentityPoolOptions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/FederateToIdentityPoolOptions.kt index 699b52f736..adedd83ae0 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/FederateToIdentityPoolOptions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/options/FederateToIdentityPoolOptions.kt @@ -23,7 +23,7 @@ data class FederateToIdentityPoolOptions internal constructor(val developerProvi /** * The builder for this class. */ - class Builder { + class CognitoBuilder { private var developerProvidedIdentityId: String? = null /** @@ -31,7 +31,7 @@ data class FederateToIdentityPoolOptions internal constructor(val developerProvi * @param developerProvidedIdentityId Provide identity id for federation to Cognito Identity Provider * @return The builder object to continue building. */ - fun developerProvidedIdentityId(developerProvidedIdentityId: String): Builder { + fun developerProvidedIdentityId(developerProvidedIdentityId: String): CognitoBuilder { this.developerProvidedIdentityId = developerProvidedIdentityId return this } @@ -51,8 +51,10 @@ data class FederateToIdentityPoolOptions internal constructor(val developerProvi * @return a builder object. */ @JvmStatic - fun builder(): Builder { - return Builder() + fun builder(): CognitoBuilder { + return CognitoBuilder() } + + inline operator fun invoke(block: CognitoBuilder.() -> Unit) = CognitoBuilder().apply(block).build() } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/events/DeviceSRPSignInEvent.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/events/DeviceSRPSignInEvent.kt index b03e975ab6..4dfb733daf 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/events/DeviceSRPSignInEvent.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/events/DeviceSRPSignInEvent.kt @@ -20,8 +20,11 @@ import java.util.Date internal class DeviceSRPSignInEvent(val eventType: EventType, override val time: Date? = null) : StateMachineEvent { sealed class EventType { - data class RespondDeviceSRPChallenge(val username: String) : EventType() - data class RespondDevicePasswordVerifier(val challengeParameters: Map) : EventType() + data class RespondDeviceSRPChallenge(val username: String, val metadata: Map) : EventType() + data class RespondDevicePasswordVerifier( + val challengeParameters: Map, + val metadata: Map + ) : EventType() data class FinalizeSignIn(val id: String = "") : EventType() data class ThrowPasswordVerifiedError(val exception: Exception) : EventType() data class ThrowAuthError(val exception: Exception) : EventType() diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/events/SRPEvent.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/events/SRPEvent.kt index 995bd34e6e..c8dd25d6c4 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/events/SRPEvent.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/events/SRPEvent.kt @@ -31,12 +31,13 @@ internal class SRPEvent(val eventType: EventType, override val time: Date? = nul val password: String, val metadata: Map ) : EventType() - data class RespondPasswordVerifier(val challengeParameters: Map) : - EventType() + data class RespondPasswordVerifier( + val challengeParameters: Map, + val metadata: Map + ) : EventType() data class ThrowAuthError(val exception: Exception) : EventType() data class CancelSRPSignIn(val id: String = "") : EventType() - data class RespondNextAuthChallenge(val id: String = "") : EventType() data class ThrowPasswordVerifierError(val exception: Exception) : EventType() data class Reset(val id: String = "") : EventType() } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/events/SignInChallengeEvent.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/events/SignInChallengeEvent.kt index eca3510ba7..82d4d8bd4d 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/events/SignInChallengeEvent.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/events/SignInChallengeEvent.kt @@ -22,7 +22,7 @@ import java.util.Date internal class SignInChallengeEvent(val eventType: EventType, override val time: Date? = null) : StateMachineEvent { sealed class EventType { data class WaitForAnswer(val challenge: AuthChallenge) : EventType() - data class VerifyChallengeAnswer(val answer: String, val options: Map) : EventType() + data class VerifyChallengeAnswer(val answer: String, val metadata: Map) : EventType() data class FinalizeSignIn(val accessToken: String) : EventType() data class Verified(val id: String = "") : EventType() } diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPluginTest.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPluginTest.kt index 8b3d201a7e..022a8bb059 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPluginTest.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPluginTest.kt @@ -47,7 +47,7 @@ import com.amplifyframework.auth.cognito.exceptions.configuration.InvalidUserPoo import com.amplifyframework.auth.cognito.exceptions.invalidstate.SignedInException import com.amplifyframework.auth.cognito.helpers.AuthHelper import com.amplifyframework.auth.cognito.helpers.SRPHelper -import com.amplifyframework.auth.cognito.options.AWSAuthResendUserAttributeConfirmationCodeOptions +import com.amplifyframework.auth.cognito.options.AWSCognitoAuthResendUserAttributeConfirmationCodeOptions import com.amplifyframework.auth.cognito.options.AWSCognitoAuthUpdateUserAttributeOptions import com.amplifyframework.auth.cognito.options.AWSCognitoAuthUpdateUserAttributesOptions import com.amplifyframework.auth.cognito.options.AuthFlowType @@ -1430,7 +1430,7 @@ class RealAWSCognitoAuthPluginTest { listenLatch.countDown() } - val builder = AWSAuthResendUserAttributeConfirmationCodeOptions.builder().metadata( + val builder = AWSCognitoAuthResendUserAttributeConfirmationCodeOptions.builder().metadata( mapOf("x" to "x", "y" to "y", "z" to "z") ) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/StateTransitionTestBase.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/StateTransitionTestBase.kt index 51c5e1004f..a6c01e7b26 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/StateTransitionTestBase.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/StateTransitionTestBase.kt @@ -344,7 +344,7 @@ open class StateTransitionTestBase { Mockito.`when`(mockSRPActions.initiateSRPAuthAction(MockitoHelper.anyObject())) .thenReturn( Action { dispatcher, _ -> - dispatcher.send(SRPEvent(SRPEvent.EventType.RespondPasswordVerifier(mapOf()))) + dispatcher.send(SRPEvent(SRPEvent.EventType.RespondPasswordVerifier(mapOf(), mapOf()))) } ) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/options/APIOptionsContractTest.java b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/options/APIOptionsContractTest.java new file mode 100644 index 0000000000..30b2fee54e --- /dev/null +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/options/APIOptionsContractTest.java @@ -0,0 +1,107 @@ +/* + * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amplifyframework.auth.cognito.options; + +import com.amplifyframework.auth.AuthUserAttribute; +import com.amplifyframework.auth.AuthUserAttributeKey; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +public class APIOptionsContractTest { + + @SuppressWarnings("serial") + private HashMap metadata = new HashMap() { + { + put("testKey", "testValue"); + } + }; + + /** + * test java cognito auth options builders. + */ + @Test + public void testCognitoOptions() { + AWSCognitoAuthResendUserAttributeConfirmationCodeOptions + resendUserAttributeConfirmationCodeOptions = + AWSCognitoAuthResendUserAttributeConfirmationCodeOptions.builder() + .metadata(metadata).build(); + Assert.assertEquals(resendUserAttributeConfirmationCodeOptions.getMetadata(), metadata); + + AWSCognitoAuthConfirmResetPasswordOptions confirmResetPasswordOptions = + AWSCognitoAuthConfirmResetPasswordOptions.builder().metadata(metadata).build(); + Assert.assertEquals(confirmResetPasswordOptions.getMetadata(), metadata); + + AWSCognitoAuthConfirmSignInOptions confirmSignInOptions = + AWSCognitoAuthConfirmSignInOptions.builder().metadata(metadata).build(); + Assert.assertEquals(confirmSignInOptions.getMetadata(), metadata); + + AWSCognitoAuthConfirmSignUpOptions confirmSignUpOptions = + AWSCognitoAuthConfirmSignUpOptions.builder().clientMetadata(metadata).build(); + Assert.assertEquals(confirmSignUpOptions.getClientMetadata(), metadata); + + AWSCognitoAuthResendSignUpCodeOptions resendSignUpCodeOptions = + AWSCognitoAuthResendSignUpCodeOptions.builder().metadata(metadata).build(); + Assert.assertEquals(resendSignUpCodeOptions.getMetadata(), metadata); + + AWSCognitoAuthResetPasswordOptions resetPasswordOptions = + AWSCognitoAuthResetPasswordOptions.builder().metadata(metadata).build(); + Assert.assertEquals(resetPasswordOptions.getMetadata(), metadata); + + AWSCognitoAuthSignInOptions signInOptions = + AWSCognitoAuthSignInOptions.builder().metadata(metadata).build(); + Assert.assertEquals(signInOptions.getMetadata(), metadata); + + AWSCognitoAuthSignOutOptions signOutOptions = + AWSCognitoAuthSignOutOptions.builder().browserPackage("chrome").build(); + Assert.assertEquals(signOutOptions.getBrowserPackage(), "chrome"); + + ArrayList attributes = new ArrayList<>(); + attributes.add(new AuthUserAttribute(AuthUserAttributeKey.email(), "my@email.com")); + attributes.add(new AuthUserAttribute(AuthUserAttributeKey.phoneNumber(), "+15551234567")); + AWSCognitoAuthSignUpOptions signUpOptions = + AWSCognitoAuthSignUpOptions.builder().clientMetadata(metadata) + .userAttributes(attributes).build(); + Assert.assertEquals(signUpOptions.getClientMetadata(), metadata); + Assert.assertEquals(signUpOptions.getUserAttributes(), attributes); + + AWSCognitoAuthUpdateUserAttributeOptions updateUserAttributeOptions = + AWSCognitoAuthUpdateUserAttributeOptions.builder().metadata(metadata).build(); + Assert.assertEquals(updateUserAttributeOptions.getMetadata(), metadata); + + AWSCognitoAuthUpdateUserAttributesOptions updateUserAttributesOptions = + AWSCognitoAuthUpdateUserAttributesOptions.builder().metadata(metadata).build(); + Assert.assertEquals(updateUserAttributesOptions.getMetadata(), metadata); + + List scopes = Arrays.asList("name"); + AWSCognitoAuthWebUISignInOptions webUISignInOptions = + AWSCognitoAuthWebUISignInOptions.builder().browserPackage("chrome") + .scopes(scopes).build(); + Assert.assertEquals(webUISignInOptions.getBrowserPackage(), "chrome"); + Assert.assertEquals(webUISignInOptions.getScopes(), scopes); + + FederateToIdentityPoolOptions federateToIdentityPoolOptions = + FederateToIdentityPoolOptions.builder().developerProvidedIdentityId("test-idp") + .build(); + Assert.assertEquals(federateToIdentityPoolOptions + .getDeveloperProvidedIdentityId(), "test-idp"); + } +} diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/options/APIOptionsKotlinContractTest.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/options/APIOptionsKotlinContractTest.kt new file mode 100644 index 0000000000..179ceb94f5 --- /dev/null +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/options/APIOptionsKotlinContractTest.kt @@ -0,0 +1,139 @@ +package com.amplifyframework.auth.cognito.options + +import com.amplifyframework.auth.AuthUserAttribute +import com.amplifyframework.auth.AuthUserAttributeKey +import org.junit.Assert +import org.junit.Test + +class APIOptionsKotlinContractTest { + private var metadata: Map = mapOf("testKey" to "testValue") + + @Test + fun testCognitoOptions() { + val resendUserAttributeConfirmationCodeOptions = + AWSCognitoAuthResendUserAttributeConfirmationCodeOptions.builder().metadata(metadata).build() + Assert.assertEquals(resendUserAttributeConfirmationCodeOptions.metadata, metadata) + + val confirmResetPasswordOptions = AWSCognitoAuthConfirmResetPasswordOptions.builder().metadata(metadata).build() + Assert.assertEquals(confirmResetPasswordOptions.metadata, metadata) + + val confirmSignInOptions = AWSCognitoAuthConfirmSignInOptions.builder().metadata(metadata).build() + Assert.assertEquals(confirmSignInOptions.metadata, metadata) + + val confirmSignUpOptions = AWSCognitoAuthConfirmSignUpOptions.builder().clientMetadata(metadata).build() + Assert.assertEquals(confirmSignUpOptions.clientMetadata, metadata) + + val resendSignUpCodeOptions = AWSCognitoAuthResendSignUpCodeOptions.builder().metadata(metadata).build() + Assert.assertEquals(resendSignUpCodeOptions.metadata, metadata) + + val resetPasswordOptions = AWSCognitoAuthResetPasswordOptions.builder().metadata(metadata).build() + Assert.assertEquals(resetPasswordOptions.metadata, metadata) + + val signInOptions = AWSCognitoAuthSignInOptions.builder().metadata(metadata).build() + Assert.assertEquals(signInOptions.metadata, metadata) + + val signOutOptions = AWSCognitoAuthSignOutOptions.builder().browserPackage("chrome").build() + Assert.assertEquals(signOutOptions.browserPackage, "chrome") + + val attributes = listOf( + AuthUserAttribute(AuthUserAttributeKey.email(), "my@email.com"), + AuthUserAttribute(AuthUserAttributeKey.phoneNumber(), "+15551234567") + ) + val signUpOptions = AWSCognitoAuthSignUpOptions.builder().clientMetadata(metadata) + .userAttributes(attributes).build() + Assert.assertEquals(signUpOptions.clientMetadata, metadata) + Assert.assertEquals(signUpOptions.userAttributes, attributes) + + val updateUserAttributeOptions = AWSCognitoAuthUpdateUserAttributeOptions.builder().metadata(metadata).build() + Assert.assertEquals(updateUserAttributeOptions.metadata, metadata) + + val updateUserAttributesOptions = AWSCognitoAuthUpdateUserAttributesOptions.builder().metadata(metadata).build() + Assert.assertEquals(updateUserAttributesOptions.metadata, metadata) + + val scopes = listOf("name") + val webUISignInOptions = AWSCognitoAuthWebUISignInOptions.builder().browserPackage("chrome") + .scopes(scopes).build() + Assert.assertEquals(webUISignInOptions.browserPackage, "chrome") + Assert.assertEquals(webUISignInOptions.scopes, scopes) + + val federateToIdentityPoolOptions = FederateToIdentityPoolOptions.builder() + .developerProvidedIdentityId("test-idp") + .build() + Assert.assertEquals(federateToIdentityPoolOptions.developerProvidedIdentityId, "test-idp") + } + + @Test + fun testInlineBuilderCognitoOptions() { + val resendUserAttributeConfirmationCodeOptions = AWSCognitoAuthResendUserAttributeConfirmationCodeOptions { + this.metadata(metadata) + } + Assert.assertEquals(resendUserAttributeConfirmationCodeOptions.metadata, metadata) + + val confirmResetPasswordOptions = AWSCognitoAuthConfirmResetPasswordOptions { + this.metadata(metadata) + } + Assert.assertEquals(confirmResetPasswordOptions.metadata, metadata) + + val confirmSignInOptions = AWSCognitoAuthConfirmSignInOptions { + this.metadata(metadata) + } + Assert.assertEquals(confirmSignInOptions.metadata, metadata) + + val confirmSignUpOptions = AWSCognitoAuthConfirmSignUpOptions { + this.clientMetadata(metadata) + } + Assert.assertEquals(confirmSignUpOptions.clientMetadata, metadata) + + val resendSignUpCodeOptions = AWSCognitoAuthResendSignUpCodeOptions { + this.metadata(metadata) + } + Assert.assertEquals(resendSignUpCodeOptions.metadata, metadata) + + val resetPasswordOptions = AWSCognitoAuthResetPasswordOptions { + this.metadata(metadata) + } + Assert.assertEquals(resetPasswordOptions.metadata, metadata) + + // TODO: add inline builders +// val signInOptions = AWSCognitoAuthSignInOptions { +// this.metadata(metadata) +// } +// Assert.assertEquals(signInOptions.metadata, metadata) + +// val signOutOptions = AWSCognitoAuthSignOutOptions.builder().browserPackage("chrome").build() +// Assert.assertEquals(signOutOptions.browserPackage, "chrome") + + val attributes = listOf( + AuthUserAttribute(AuthUserAttributeKey.email(), "my@email.com"), + AuthUserAttribute(AuthUserAttributeKey.phoneNumber(), "+15551234567") + ) + val signUpOptions = AWSCognitoAuthSignUpOptions { + this.clientMetadata(metadata) + this.userAttributes(attributes) + } + Assert.assertEquals(signUpOptions.clientMetadata, metadata) + Assert.assertEquals(signUpOptions.userAttributes, attributes) + + val updateUserAttributeOptions = AWSCognitoAuthUpdateUserAttributeOptions { + this.metadata(metadata) + } + Assert.assertEquals(updateUserAttributeOptions.metadata, metadata) + + val updateUserAttributesOptions = AWSCognitoAuthUpdateUserAttributesOptions { + this.metadata(metadata) + } + Assert.assertEquals(updateUserAttributesOptions.metadata, metadata) + + // TODO: add inline builders +// val scopes = listOf("name") +// val webUISignInOptions = AWSCognitoAuthWebUISignInOptions.builder().browserPackage("chrome") +// .scopes(scopes).build() +// Assert.assertEquals(webUISignInOptions.browserPackage, "chrome") +// Assert.assertEquals(webUISignInOptions.scopes, scopes) + + val federateToIdentityPoolOptions = FederateToIdentityPoolOptions { + this.developerProvidedIdentityId("test-idp") + } + Assert.assertEquals(federateToIdentityPoolOptions.developerProvidedIdentityId, "test-idp") + } +} From acf89303a80308546a7d097e3fd381166261df84 Mon Sep 17 00:00:00 2001 From: Saijad Dhuka <83975678+sdhuka@users.noreply.github.com> Date: Tue, 15 Nov 2022 15:11:17 -0600 Subject: [PATCH 19/36] fix: callbacks not invoked when attached using getTransfer api (#2111) * fix: listener not invoked when attached using getTransfer api * address PR comments * default state to unknown * add comment * add comment * override getRequest in storage operation & make SocketExcpetion retryable * add nullable annotation * address nullable request Co-authored-by: Tyler Roach --- .../storage/s3/AWSS3StorageUploadTest.java | 144 ++++++++++++++++++ .../storage/s3/AWSS3StoragePlugin.java | 111 +++++++------- .../storage/s3/TransferOperations.kt | 5 +- .../AWSS3StorageDownloadFileOperation.kt | 23 +-- .../AWSS3StorageUploadFileOperation.kt | 31 ++-- .../AWSS3StorageUploadInputStreamOperation.kt | 34 +++-- .../AWSS3StorageDownloadFileRequest.java | 3 + .../AWSS3StorageGetPresignedUrlRequest.java | 3 + .../s3/request/AWSS3StorageListRequest.java | 3 + .../s3/request/AWSS3StorageRemoveRequest.java | 3 + .../s3/request/AWSS3StorageUploadRequest.java | 3 + .../storage/s3/transfer/TransferListener.kt | 3 +- .../storage/s3/transfer/TransferObserver.kt | 2 +- .../s3/transfer/TransferStatusUpdater.kt | 10 +- .../s3/transfer/worker/BaseTransferWorker.kt | 7 +- .../storage/s3/StorageComponentTest.java | 6 +- .../core/async/AmplifyOperation.java | 1 + .../StorageDownloadFileOperation.java | 12 ++ .../operation/StorageUploadOperation.java | 12 ++ 19 files changed, 314 insertions(+), 102 deletions(-) diff --git a/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageUploadTest.java b/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageUploadTest.java index 25d418e62d..9fd05dc57e 100644 --- a/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageUploadTest.java +++ b/aws-storage-s3/src/androidTest/java/com/amplifyframework/storage/s3/AWSS3StorageUploadTest.java @@ -30,7 +30,9 @@ import com.amplifyframework.storage.StorageChannelEventName; import com.amplifyframework.storage.TransferState; import com.amplifyframework.storage.operation.StorageUploadFileOperation; +import com.amplifyframework.storage.operation.StorageUploadInputStreamOperation; import com.amplifyframework.storage.options.StorageUploadFileOptions; +import com.amplifyframework.storage.options.StorageUploadInputStreamOptions; import com.amplifyframework.storage.s3.test.R; import com.amplifyframework.storage.s3.util.WorkmanagerTestUtils; import com.amplifyframework.testutils.random.RandomTempFile; @@ -43,6 +45,7 @@ import org.junit.Test; import java.io.File; +import java.io.FileInputStream; import java.util.HashSet; import java.util.Set; import java.util.concurrent.CountDownLatch; @@ -122,6 +125,21 @@ public void testUploadSmallFile() throws Exception { synchronousStorage.uploadFile(fileName, uploadFile, options); } + /** + * Tests that small file (single-part) uploads using input stream successfully. + * + * @throws Exception if upload fails + */ + @Test + public void testUploadSmallFileStream() throws Exception { + File uploadFile = new RandomTempFile(4 * 1024 * 1024); + String fileName = uploadFile.getName(); + StorageUploadInputStreamOptions options = StorageUploadInputStreamOptions.builder() + .accessLevel(TESTING_ACCESS_LEVEL) + .build(); + synchronousStorage.uploadInputStream(fileName, new FileInputStream(uploadFile), options); + } + /** * Tests that large file (multi-part) uploads successfully. * @@ -234,4 +252,130 @@ public void testUploadFileIsResumable() throws Exception { assertTrue(completed.await(EXTENDED_TIMEOUT_MS, TimeUnit.MILLISECONDS)); assertNull(errorContainer.get()); } + + /** + * Tests that file upload operation can be paused and resumed + * using getTransfer API. + * + * @throws Exception if upload is not paused, resumed, and + * completed successfully before timeout + */ + @SuppressWarnings("unchecked") + @Test + public void testUploadFileGetTransferOnPause() throws Exception { + final CountDownLatch completed = new CountDownLatch(1); + final CountDownLatch resumed = new CountDownLatch(1); + final AtomicReference transferId = new AtomicReference<>(); + final AtomicReference> opContainer = new AtomicReference<>(); + final AtomicReference errorContainer = new AtomicReference<>(); + + // Create a file large enough that transfer won't finish before being paused + File uploadFile = new RandomTempFile(LARGE_FILE_SIZE); + + // Listen to Hub events to resume when operation has been paused + SubscriptionToken resumeToken = Amplify.Hub.subscribe(HubChannel.STORAGE, hubEvent -> { + if (StorageChannelEventName.UPLOAD_STATE.toString().equals(hubEvent.getName())) { + HubEvent stateEvent = (HubEvent) hubEvent; + TransferState state = TransferState.getState(stateEvent.getData()); + if (TransferState.PAUSED.equals(state)) { + opContainer.get().clearAllListeners(); + storageCategory.getTransfer(transferId.get(), + operation -> { + StorageUploadFileOperation getOp = (StorageUploadFileOperation) operation; + getOp.resume(); + resumed.countDown(); + getOp.setOnSuccess(result -> { + completed.countDown(); + }); + }, errorContainer::set); + } + } + }); + subscriptions.add(resumeToken); + + // Begin uploading a large file + StorageUploadFileOperation op = storageCategory.uploadFile( + uploadFile.getName(), + uploadFile, + options, + progress -> { + if (progress.getCurrentBytes() > 0 && resumed.getCount() > 0) { + opContainer.get().pause(); + } + }, + result -> { }, + errorContainer::set + ); + opContainer.set(op); + transferId.set(op.getTransferId()); + + // Assert that all the required conditions have been met + assertTrue(resumed.await(EXTENDED_TIMEOUT_MS, TimeUnit.MILLISECONDS)); + assertTrue(completed.await(EXTENDED_TIMEOUT_MS, TimeUnit.MILLISECONDS)); + assertNull(errorContainer.get()); + } + + /** + * Tests that input stream upload operation can be paused and resumed + * using getTransfer API. + * + * @throws Exception if upload is not paused, resumed, and + * completed successfully before timeout + */ + @SuppressWarnings("unchecked") + @Test + public void testUploadInputStreamGetTransferOnPause() throws Exception { + final CountDownLatch completed = new CountDownLatch(1); + final CountDownLatch resumed = new CountDownLatch(1); + final AtomicReference transferId = new AtomicReference<>(); + final AtomicReference> opContainer = new AtomicReference<>(); + final AtomicReference errorContainer = new AtomicReference<>(); + + // Create a file large enough that transfer won't finish before being paused + File uploadFile = new RandomTempFile(LARGE_FILE_SIZE); + + // Listen to Hub events to resume when operation has been paused + SubscriptionToken resumeToken = Amplify.Hub.subscribe(HubChannel.STORAGE, hubEvent -> { + if (StorageChannelEventName.UPLOAD_STATE.toString().equals(hubEvent.getName())) { + HubEvent stateEvent = (HubEvent) hubEvent; + TransferState state = TransferState.getState(stateEvent.getData()); + if (TransferState.PAUSED.equals(state)) { + opContainer.get().clearAllListeners(); + storageCategory.getTransfer(transferId.get(), + operation -> { + StorageUploadFileOperation getOp = (StorageUploadFileOperation) operation; + getOp.resume(); + resumed.countDown(); + getOp.setOnSuccess(result -> { + completed.countDown(); + }); + }, errorContainer::set); + } + } + }); + subscriptions.add(resumeToken); + StorageUploadInputStreamOptions inputStreamOptions = StorageUploadInputStreamOptions.builder() + .accessLevel(TESTING_ACCESS_LEVEL) + .build(); + // Begin uploading a large file + StorageUploadInputStreamOperation op = storageCategory.uploadInputStream( + uploadFile.getName(), + new FileInputStream(uploadFile), + inputStreamOptions, + progress -> { + if (progress.getCurrentBytes() > 0 && resumed.getCount() > 0) { + opContainer.get().pause(); + } + }, + result -> { }, + errorContainer::set + ); + opContainer.set(op); + transferId.set(op.getTransferId()); + + // Assert that all the required conditions have been met + assertTrue(resumed.await(EXTENDED_TIMEOUT_MS, TimeUnit.MILLISECONDS)); + assertTrue(completed.await(EXTENDED_TIMEOUT_MS, TimeUnit.MILLISECONDS)); + assertNull(errorContainer.get()); + } } diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/AWSS3StoragePlugin.java b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/AWSS3StoragePlugin.java index e27f4938a1..8c7930172c 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/AWSS3StoragePlugin.java +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/AWSS3StoragePlugin.java @@ -25,6 +25,7 @@ import com.amplifyframework.storage.StorageAccessLevel; import com.amplifyframework.storage.StorageException; import com.amplifyframework.storage.StoragePlugin; +import com.amplifyframework.storage.TransferState; import com.amplifyframework.storage.operation.StorageDownloadFileOperation; import com.amplifyframework.storage.operation.StorageGetUrlOperation; import com.amplifyframework.storage.operation.StorageListOperation; @@ -509,61 +510,67 @@ public void getTransfer( @NonNull Consumer> onReceived, @NonNull Consumer onError) { executorService.submit(() -> { - TransferRecord transferRecord = storageService.getTransfer(transferId); - if (transferRecord != null) { - TransferObserver transferObserver = - new TransferObserver( - transferRecord.getId(), - storageService.getTransferManager().getTransferStatusUpdater(), - transferRecord.getBucketName(), - transferRecord.getKey(), - transferRecord.getFile(), - null, - transferRecord.getState()); - TransferType transferType = transferRecord.getType(); - switch (Objects.requireNonNull(transferType)) { - case UPLOAD: - if (transferRecord.getFile().startsWith(TransferStatusUpdater.TEMP_FILE_PREFIX)) { - AWSS3StorageUploadInputStreamOperation operation = - new AWSS3StorageUploadInputStreamOperation( - transferId, - storageService, - executorService, - authCredentialsProvider, - awsS3StoragePluginConfiguration, - null, - transferObserver); - onReceived.accept(operation); - } else { - AWSS3StorageUploadFileOperation operation = - new AWSS3StorageUploadFileOperation( - transferId, - storageService, - executorService, - authCredentialsProvider, - awsS3StoragePluginConfiguration, - null, - transferObserver); - onReceived.accept(operation); - } - break; - case DOWNLOAD: - AWSS3StorageDownloadFileOperation - downloadFileOperation = new AWSS3StorageDownloadFileOperation( - transferId, - new File(transferRecord.getFile()), - storageService, - executorService, - authCredentialsProvider, - awsS3StoragePluginConfiguration, + try { + TransferRecord transferRecord = storageService.getTransfer(transferId); + if (transferRecord != null) { + TransferObserver transferObserver = + new TransferObserver( + transferRecord.getId(), + storageService.getTransferManager().getTransferStatusUpdater(), + transferRecord.getBucketName(), + transferRecord.getKey(), + transferRecord.getFile(), null, - transferObserver); - onReceived.accept(downloadFileOperation); - break; - default: + transferRecord.getState() != null ? transferRecord.getState() : TransferState.UNKNOWN); + TransferType transferType = transferRecord.getType(); + switch (Objects.requireNonNull(transferType)) { + case UPLOAD: + if (transferRecord.getFile().startsWith(TransferStatusUpdater.TEMP_FILE_PREFIX)) { + AWSS3StorageUploadInputStreamOperation operation = + new AWSS3StorageUploadInputStreamOperation( + transferId, + storageService, + executorService, + authCredentialsProvider, + awsS3StoragePluginConfiguration, + null, + transferObserver); + onReceived.accept(operation); + } else { + AWSS3StorageUploadFileOperation operation = + new AWSS3StorageUploadFileOperation( + transferId, + storageService, + executorService, + authCredentialsProvider, + awsS3StoragePluginConfiguration, + null, + transferObserver); + onReceived.accept(operation); + } + break; + case DOWNLOAD: + AWSS3StorageDownloadFileOperation + downloadFileOperation = new AWSS3StorageDownloadFileOperation( + transferId, + new File(transferRecord.getFile()), + storageService, + executorService, + authCredentialsProvider, + awsS3StoragePluginConfiguration, + null, + transferObserver); + onReceived.accept(downloadFileOperation); + break; + default: + } + } else { + onError.accept(new StorageException("Get transfer failed", + "Please verify that the transfer id is valid and the transfer is not completed")); } - } else { + } catch (Exception exception) { onError.accept(new StorageException("Get transfer failed", + exception, "Please verify that the transfer id is valid and the transfer is not completed")); } }); diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/TransferOperations.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/TransferOperations.kt index b116d3df2b..6ec103dc00 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/TransferOperations.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/TransferOperations.kt @@ -114,10 +114,13 @@ internal object TransferOperations { workManager: WorkManager ): Boolean { if (!TransferState.isInTerminalState(transferRecord.state)) { - val nextState: TransferState = TransferState.PENDING_CANCEL + var nextState: TransferState = TransferState.PENDING_CANCEL if (TransferState.isPaused(transferRecord.state)) { if (transferRecord.isMultipart == 1) { abortMultipartUploadRequest(transferRecord, pluginKey, workManager) + } else { + // transfer is paused so directly mark it as canceled + nextState = TransferState.CANCELED } } else { workManager.cancelUniqueWork(transferRecord.id.toString()) diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageDownloadFileOperation.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageDownloadFileOperation.kt index 5b3aa3db8e..79720f01e5 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageDownloadFileOperation.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageDownloadFileOperation.kt @@ -14,7 +14,6 @@ */ package com.amplifyframework.storage.s3.operation -import android.util.Log import com.amplifyframework.auth.AuthCredentialsProvider import com.amplifyframework.core.Amplify import com.amplifyframework.core.Consumer @@ -53,14 +52,7 @@ class AWSS3StorageDownloadFileOperation @JvmOverloads internal constructor( ) : StorageDownloadFileOperation(request, transferId, onProgress, onSuccess, onError) { init { - transferObserver?.let { - val listener = DownloadTransferListener() - Log.d( - "AWSS3StorageDownloadFileOperation", - "Setting up new transfer listener ${listener.hashCode()} for operation ${hashCode()}" - ) - it.setTransferListener(listener) - } + transferObserver?.setTransferListener(DownloadTransferListener()) } constructor( @@ -88,18 +80,19 @@ class AWSS3StorageDownloadFileOperation @JvmOverloads internal constructor( override fun start() { // Only start if it hasn't already been started - if (transferObserver != null || request == null) { + if (transferObserver != null) { return } + val downloadRequest = request ?: return executorService.submit( Runnable { awsS3StoragePluginConfiguration.getAWSS3PluginPrefixResolver(authCredentialsProvider).resolvePrefix( - request.accessLevel, - request.targetIdentityId, + downloadRequest.accessLevel, + downloadRequest.targetIdentityId, Consumer { prefix: String -> try { - val serviceKey = prefix + request.key - this.file = request.local + val serviceKey = prefix + downloadRequest.key + this.file = downloadRequest.local transferObserver = storageService.downloadToFile(transferId, serviceKey, file) transferObserver?.setTransferListener(DownloadTransferListener()) } catch (exception: Exception) { @@ -188,7 +181,7 @@ class AWSS3StorageDownloadFileOperation @JvmOverloads internal constructor( } inner class DownloadTransferListener : TransferListener { - override fun onStateChanged(transferId: Int, state: TransferState) { + override fun onStateChanged(transferId: Int, state: TransferState, key: String) { Amplify.Hub.publish( HubChannel.STORAGE, HubEvent.create(StorageChannelEventName.DOWNLOAD_STATE, state.name) diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadFileOperation.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadFileOperation.kt index ac714252e7..4d8bf235c7 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadFileOperation.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadFileOperation.kt @@ -74,28 +74,33 @@ class AWSS3StorageUploadFileOperation @JvmOverloads internal constructor( onError ) + init { + transferObserver?.setTransferListener(UploadTransferListener()) + } + override fun start() { // Only start if it hasn't already been started - if (transferObserver != null || request == null) { + if (transferObserver != null) { return } + val uploadRequest = request ?: return executorService.submit( Runnable { awsS3StoragePluginConfiguration.getAWSS3PluginPrefixResolver(authCredentialsProvider).resolvePrefix( - request.accessLevel, - request.targetIdentityId, + uploadRequest.accessLevel, + uploadRequest.targetIdentityId, Consumer { prefix: String -> try { - val serviceKey = prefix + request.key + val serviceKey = prefix + uploadRequest.key // Grab the file to upload... - val file = request.local + val file = uploadRequest.local // Set up the metadata val objectMetadata = ObjectMetadata() - objectMetadata.userMetadata = request.metadata - objectMetadata.metaData[ObjectMetadata.CONTENT_TYPE] = request.contentType + objectMetadata.userMetadata = uploadRequest.metadata + objectMetadata.metaData[ObjectMetadata.CONTENT_TYPE] = uploadRequest.contentType val storageServerSideEncryption = - request.serverSideEncryption + uploadRequest.serverSideEncryption if (ServerSideEncryption.NONE != storageServerSideEncryption) { objectMetadata.metaData[ObjectMetadata.SERVER_SIDE_ENCRYPTION] = storageServerSideEncryption.getName() @@ -181,20 +186,22 @@ class AWSS3StorageUploadFileOperation @JvmOverloads internal constructor( override fun setOnSuccess(onSuccess: Consumer?) { super.setOnSuccess(onSuccess) - if (transferState == TransferState.COMPLETED) { - onSuccess?.accept(StorageUploadFileResult.fromKey(request.key)) + request?.let { + if (transferState == TransferState.COMPLETED) { + onSuccess?.accept(StorageUploadFileResult.fromKey(it.key)) + } } } private inner class UploadTransferListener : TransferListener { - override fun onStateChanged(transferId: Int, state: TransferState) { + override fun onStateChanged(transferId: Int, state: TransferState, key: String) { Amplify.Hub.publish( HubChannel.STORAGE, HubEvent.create(StorageChannelEventName.UPLOAD_STATE, state.name) ) when (state) { TransferState.COMPLETED -> { - onSuccess?.accept(StorageUploadFileResult.fromKey(request.key)) + onSuccess?.accept(StorageUploadFileResult.fromKey(key)) return } TransferState.FAILED -> {} diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadInputStreamOperation.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadInputStreamOperation.kt index db0216c3ca..9289b3398d 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadInputStreamOperation.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/operation/AWSS3StorageUploadInputStreamOperation.kt @@ -81,29 +81,33 @@ class AWSS3StorageUploadInputStreamOperation @JvmOverloads internal constructor( onError ) - override fun start() { - // Only start if it hasn't already been started + init { + transferObserver?.setTransferListener(UploadTransferListener()) + } + override fun start() { // Only start if it hasn't already been started - if (transferObserver != null || request == null) { + if (transferObserver != null) { return } + + val uploadRequest = request ?: return executorService.submit( Runnable { awsS3StoragePluginConfiguration.getAWSS3PluginPrefixResolver(authCredentialsProvider).resolvePrefix( - request.accessLevel, - request.targetIdentityId, + uploadRequest.accessLevel, + uploadRequest.targetIdentityId, Consumer { prefix: String -> try { - val serviceKey = prefix + request.key + val serviceKey = prefix + uploadRequest.key // Grab the inputStream to upload... - val inputStream = request.local + val inputStream = uploadRequest.local // Set up the metadata val objectMetadata = ObjectMetadata() - objectMetadata.userMetadata = request.metadata - objectMetadata.metaData[ObjectMetadata.CONTENT_TYPE] = request.contentType + objectMetadata.userMetadata = uploadRequest.metadata + objectMetadata.metaData[ObjectMetadata.CONTENT_TYPE] = uploadRequest.contentType val storageServerSideEncryption = - request.serverSideEncryption + uploadRequest.serverSideEncryption if (ServerSideEncryption.NONE != storageServerSideEncryption) { objectMetadata.metaData[ObjectMetadata.SERVER_SIDE_ENCRYPTION] = storageServerSideEncryption.getName() @@ -194,20 +198,22 @@ class AWSS3StorageUploadInputStreamOperation @JvmOverloads internal constructor( override fun setOnSuccess(onSuccess: Consumer?) { super.setOnSuccess(onSuccess) - if (transferState == TransferState.COMPLETED) { - onSuccess?.accept(StorageUploadInputStreamResult.fromKey(request.key)) + request?.let { + if (transferState == TransferState.COMPLETED) { + onSuccess?.accept(StorageUploadInputStreamResult.fromKey(it.key)) + } } } private inner class UploadTransferListener : TransferListener { - override fun onStateChanged(transferId: Int, state: TransferState) { + override fun onStateChanged(transferId: Int, state: TransferState, key: String) { Amplify.Hub.publish( HubChannel.STORAGE, HubEvent.create(StorageChannelEventName.UPLOAD_STATE, state.name) ) when (state) { TransferState.COMPLETED -> { - onSuccess?.accept(StorageUploadInputStreamResult.fromKey(request.key)) + onSuccess?.accept(StorageUploadInputStreamResult.fromKey(key)) return } TransferState.FAILED -> { diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageDownloadFileRequest.java b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageDownloadFileRequest.java index e22fcd3480..0e1e89bb32 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageDownloadFileRequest.java +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageDownloadFileRequest.java @@ -34,6 +34,9 @@ public final class AWSS3StorageDownloadFileRequest { /** * Constructs a new AWSS3StorageDownloadFileRequest. + * Although this has public access, it is intended for internal use and should not be used directly by host + * applications. The behavior of this may change without warning. + * * @param key key for item to download * @param local Target file for the downloaded file to be saved to * @param accessLevel Storage access level diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageGetPresignedUrlRequest.java b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageGetPresignedUrlRequest.java index be54ffa5ab..9c54976eee 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageGetPresignedUrlRequest.java +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageGetPresignedUrlRequest.java @@ -32,6 +32,9 @@ public final class AWSS3StorageGetPresignedUrlRequest { /** * Constructs a new AWSS3StorageGetUrlRequest. + * Although this has public access, it is intended for internal use and should not be used directly by host + * applications. The behavior of this may change without warning. + * * @param key key for item to obtain URL for * @param accessLevel Storage access level * @param targetIdentityId If set, this should override the current user's identity ID. diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageListRequest.java b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageListRequest.java index c91b1bd04e..238b0636a3 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageListRequest.java +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageListRequest.java @@ -30,6 +30,9 @@ public final class AWSS3StorageListRequest { /** * Constructs a new AWSS3StorageListRequest. + * Although this has public access, it is intended for internal use and should not be used directly by host + * applications. The behavior of this may change without warning. + * * @param path the path in S3 to list items from * @param accessLevel Storage access level * @param targetIdentityId If set, this should override the current user's identity ID. diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageRemoveRequest.java b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageRemoveRequest.java index f2811c7521..627e440c10 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageRemoveRequest.java +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageRemoveRequest.java @@ -30,6 +30,9 @@ public final class AWSS3StorageRemoveRequest { /** * Constructs a new AWSS3StorageRemoveRequest. + * Although this has public access, it is intended for internal use and should not be used directly by host + * applications. The behavior of this may change without warning. + * * @param key key for item to download * @param accessLevel Storage access level * @param targetIdentityId If set, this should override the current user's identity ID. diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageUploadRequest.java b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageUploadRequest.java index 9c2c988f44..d5838d741d 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageUploadRequest.java +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/request/AWSS3StorageUploadRequest.java @@ -39,6 +39,9 @@ public final class AWSS3StorageUploadRequest { /** * Constructs a new AWSS3StorageUploadRequest. + * Although this has public access, it is intended for internal use and should not be used directly by host + * applications. The behavior of this may change without warning. + * * @param key key for item to upload * @param local object to upload (e.g. File or InputStream) * @param accessLevel Storage access level diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferListener.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferListener.kt index 466d82a181..2674200417 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferListener.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferListener.kt @@ -27,8 +27,9 @@ internal interface TransferListener { * * @param id The id of the transfer record. * @param state The new state of the transfer. + * @param key The key of the transfer */ - fun onStateChanged(id: Int, state: TransferState) + fun onStateChanged(id: Int, state: TransferState, key: String) /** * Called when more bytes are transferred. diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferObserver.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferObserver.kt index eccc837b99..021e06a5b8 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferObserver.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferObserver.kt @@ -71,7 +71,7 @@ internal data class TransferObserver @JvmOverloads constructor( totalBytes = bytesTotal } - override fun onStateChanged(id: Int, state: TransferState) { + override fun onStateChanged(id: Int, state: TransferState, key: String) { transferState = state } } diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferStatusUpdater.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferStatusUpdater.kt index ef180800c5..aa696afce2 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferStatusUpdater.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/TransferStatusUpdater.kt @@ -110,7 +110,15 @@ internal class TransferStatusUpdater private constructor( } transferStatusListenerMap[transferRecord.id]?.forEach { listener -> - mainHandler.post { listener.onStateChanged(transferRecord.id, newState) } + mainHandler.post { + transferRecord.key?.let { key -> + listener.onStateChanged( + transferRecord.id, + newState, + key + ) + } + } } if (TransferState.isInTerminalState(newState)) { diff --git a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/BaseTransferWorker.kt b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/BaseTransferWorker.kt index de399907fa..67fb649352 100644 --- a/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/BaseTransferWorker.kt +++ b/aws-storage-s3/src/main/java/com/amplifyframework/storage/s3/transfer/worker/BaseTransferWorker.kt @@ -49,6 +49,7 @@ import com.amplifyframework.storage.s3.transfer.TransferRecord import com.amplifyframework.storage.s3.transfer.TransferStatusUpdater import java.io.File import java.lang.Exception +import java.net.SocketException import java.nio.ByteBuffer import kotlinx.coroutines.CancellationException @@ -111,7 +112,7 @@ internal abstract class BaseTransferWorker( } else -> { val ex = result.exceptionOrNull() - logger.error("${this.javaClass.simpleName} failed with exception: $ex, stacktrace: ${ex?.stackTrace}") + logger.error("${this.javaClass.simpleName} failed with exception: $ex") if (isRetryableError(ex)) { Result.retry() } else { @@ -151,7 +152,9 @@ internal abstract class BaseTransferWorker( return isStopped || !isNetworkAvailable(applicationContext) || runAttemptCount < maxRetryCount || - e is CancellationException + e is CancellationException || + // SocketException is thrown when download is terminated due to network disconnection. + e is SocketException } @RequiresApi(Build.VERSION_CODES.O) diff --git a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/StorageComponentTest.java b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/StorageComponentTest.java index 1486e1f282..91fb399ec8 100644 --- a/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/StorageComponentTest.java +++ b/aws-storage-s3/src/test/java/com/amplifyframework/storage/s3/StorageComponentTest.java @@ -179,7 +179,7 @@ public void testDownloadToFileGetsFile() throws Exception { // callback, as part of our "happy path" test. doAnswer(invocation -> { TransferListener listener = invocation.getArgument(0); - listener.onStateChanged(0, TransferState.COMPLETED); + listener.onStateChanged(0, TransferState.COMPLETED, fromRemoteKey); return null; }).when(observer) .setTransferListener(any(TransferListener.class)); @@ -256,7 +256,7 @@ public void testUploadFileGetsKey() throws Exception { doAnswer(invocation -> { TransferListener listener = invocation.getArgument(0); - listener.onStateChanged(0, TransferState.COMPLETED); + listener.onStateChanged(0, TransferState.COMPLETED, toRemoteKey); return null; }).when(observer) .setTransferListener(any(com.amplifyframework.storage.s3.transfer.TransferListener.class)); @@ -297,7 +297,7 @@ public void testUploadInputStreamGetsKey() throws Exception { doAnswer(invocation -> { TransferListener listener = invocation.getArgument(0); - listener.onStateChanged(0, TransferState.COMPLETED); + listener.onStateChanged(0, TransferState.COMPLETED, toRemoteKey); return null; }).when(observer) .setTransferListener(any(TransferListener.class)); diff --git a/core/src/main/java/com/amplifyframework/core/async/AmplifyOperation.java b/core/src/main/java/com/amplifyframework/core/async/AmplifyOperation.java index f4ab3c2c42..8f7b3fa207 100644 --- a/core/src/main/java/com/amplifyframework/core/async/AmplifyOperation.java +++ b/core/src/main/java/com/amplifyframework/core/async/AmplifyOperation.java @@ -62,6 +62,7 @@ public final CategoryType getCategoryType() { /** * Gets the request object. + * * @return the request object */ public R getRequest() { diff --git a/core/src/main/java/com/amplifyframework/storage/operation/StorageDownloadFileOperation.java b/core/src/main/java/com/amplifyframework/storage/operation/StorageDownloadFileOperation.java index d2e80f15d5..35330a90b2 100644 --- a/core/src/main/java/com/amplifyframework/storage/operation/StorageDownloadFileOperation.java +++ b/core/src/main/java/com/amplifyframework/storage/operation/StorageDownloadFileOperation.java @@ -67,5 +67,17 @@ protected StorageDownloadFileOperation( public void setOnSuccess(@Nullable Consumer onSuccess) { super.setOnSuccess(onSuccess); } + + /** + * Request will be null if the operation is returned by + * {@link com.amplifyframework.storage.s3.AWSS3StoragePlugin} getTransfer api. + * + * @return the request object + */ + @Override + @Nullable + public R getRequest() { + return super.getRequest(); + } } diff --git a/core/src/main/java/com/amplifyframework/storage/operation/StorageUploadOperation.java b/core/src/main/java/com/amplifyframework/storage/operation/StorageUploadOperation.java index 684ba35308..e31629717d 100644 --- a/core/src/main/java/com/amplifyframework/storage/operation/StorageUploadOperation.java +++ b/core/src/main/java/com/amplifyframework/storage/operation/StorageUploadOperation.java @@ -68,5 +68,17 @@ protected StorageUploadOperation( public void setOnSuccess(@Nullable Consumer onSuccess) { super.setOnSuccess(onSuccess); } + + /** + * Request will be null if the operation is returned by + * {@link com.amplifyframework.storage.s3.AWSS3StoragePlugin} getTransfer api. + * + * @return the request object + */ + @Override + @Nullable + public R getRequest() { + return super.getRequest(); + } } From 1bbdc486011093dcece1d49afc39296086ad4654 Mon Sep 17 00:00:00 2001 From: Tyler Roach Date: Tue, 15 Nov 2022 17:10:34 -0500 Subject: [PATCH 20/36] Prevent attempting to read backed up EncryptedSharedPreferences that are no longer readable (#2113) --- .../data/EncryptedKeyValueRepository.kt | 69 +++++++++++++++---- .../data/EncryptedKeyValueRepositoryTest.kt | 4 +- 2 files changed, 59 insertions(+), 14 deletions(-) diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/EncryptedKeyValueRepository.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/EncryptedKeyValueRepository.kt index d4be967b38..6993e92063 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/EncryptedKeyValueRepository.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/EncryptedKeyValueRepository.kt @@ -22,36 +22,81 @@ import androidx.security.crypto.EncryptedSharedPreferences import androidx.security.crypto.EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV import androidx.security.crypto.EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM import androidx.security.crypto.MasterKeys +import java.io.File +import java.util.UUID internal class EncryptedKeyValueRepository( private val context: Context, private val sharedPreferencesName: String, ) : KeyValueRepository { + @VisibleForTesting + internal val sharedPreferences: SharedPreferences by lazy { + EncryptedSharedPreferences.create( + "$sharedPreferencesName.${getInstallationIdentifier(context, sharedPreferencesName)}", + MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC), + context, + AES256_SIV, + AES256_GCM + ) + } + + @VisibleForTesting + internal val editor: SharedPreferences.Editor by lazy { + sharedPreferences.edit() + } + override fun put(dataKey: String, value: String?) { - with(getSharedPreferences().edit()) { + with(editor) { putString(dataKey, value) apply() } } - override fun get(dataKey: String): String? = getSharedPreferences().getString(dataKey, null) + override fun get(dataKey: String): String? = sharedPreferences.getString(dataKey, null) override fun remove(dataKey: String) { - with(getSharedPreferences().edit()) { + with(editor) { remove(dataKey) apply() } } - @VisibleForTesting - fun getSharedPreferences(): SharedPreferences { - return EncryptedSharedPreferences.create( - sharedPreferencesName, - MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC), - context, - AES256_SIV, - AES256_GCM - ) + /** + * EncryptedSharedPreferences may have been backed up by the application, but will be unreadable due to the + * KeyStore record being lost. To prevent an unreadable EncryptedSharedPreferences, we append a suffix to the name + * with a UUID created in the noBackupFilesDir + */ + @Synchronized + private fun getInstallationIdentifier(context: Context, keyValueRepoID: String): String { + val identifierFile = File(context.noBackupFilesDir, "$keyValueRepoID.installationIdentifier") + val previousIdentifier = getExistingInstallationIdentifier(identifierFile) + + return previousIdentifier ?: createInstallationIdentifier(identifierFile) + } + + /** + * Gets the existing installation identifier (if exists) + */ + private fun getExistingInstallationIdentifier(identifierFile: File): String? { + return if (identifierFile.exists()) { + val identifier = identifierFile.readText() + identifier.ifBlank { null } + } else { + null + } + } + + /** + * Creates a new installation identifier for the install + */ + private fun createInstallationIdentifier(identifierFile: File): String { + val newIdentifier = UUID.randomUUID().toString() + try { + identifierFile.writeText(newIdentifier) + } catch (e: Exception) { + // Failed to write identifier to file, session will be forced to be in memory + } + return newIdentifier } } diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/data/EncryptedKeyValueRepositoryTest.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/data/EncryptedKeyValueRepositoryTest.kt index 2cbd1e0ad9..94a4ff4fec 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/data/EncryptedKeyValueRepositoryTest.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/data/EncryptedKeyValueRepositoryTest.kt @@ -49,8 +49,8 @@ class EncryptedKeyValueRepositoryTest { @Before fun setup() { - Mockito.`when`(repository.getSharedPreferences()).thenReturn(mockPrefs) - Mockito.`when`(mockPrefs.edit()).thenReturn(mockPrefsEditor) + Mockito.`when`(repository.sharedPreferences).thenReturn(mockPrefs) + Mockito.`when`(repository.editor).thenReturn(mockPrefsEditor) } @Test From e69c4253384ebb292bfddc208b1539740606847e Mon Sep 17 00:00:00 2001 From: Divyesh Chitroda Date: Tue, 15 Nov 2022 15:04:44 -0800 Subject: [PATCH 21/36] fix(auth): device metadata migration (#2114) --- .../actions/CredentialStoreCognitoActions.kt | 16 ++++++++-------- .../data/AWSCognitoLegacyCredentialStore.kt | 10 +++++++++- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/CredentialStoreCognitoActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/CredentialStoreCognitoActions.kt index 407792655c..5a634c4914 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/CredentialStoreCognitoActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/CredentialStoreCognitoActions.kt @@ -34,15 +34,15 @@ internal object CredentialStoreCognitoActions : CredentialStoreActions { // migrate credentials credentialStore.saveCredential(credentials) legacyCredentialStore.deleteCredential() + } - // migrate device data - if (credentials is AmplifyCredential.UserPoolTypeCredential) { - val username = credentials.signedInData.username - val deviceMetaData = legacyCredentialStore.retrieveDeviceMetadata(username) - if (deviceMetaData != DeviceMetadata.Empty) { - credentialStore.saveDeviceMetadata(username, deviceMetaData) - legacyCredentialStore.deleteDeviceKeyCredential(username) - } + // migrate device data + val lastAuthUserId = legacyCredentialStore.retrieveLastAuthUserId() + lastAuthUserId?.let { + val deviceMetaData = legacyCredentialStore.retrieveDeviceMetadata(lastAuthUserId) + if (deviceMetaData != DeviceMetadata.Empty) { + credentialStore.saveDeviceMetadata(lastAuthUserId, deviceMetaData) + legacyCredentialStore.deleteDeviceKeyCredential(lastAuthUserId) } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/AWSCognitoLegacyCredentialStore.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/AWSCognitoLegacyCredentialStore.kt index 5df12d4cff..90edd67aa9 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/AWSCognitoLegacyCredentialStore.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/AWSCognitoLegacyCredentialStore.kt @@ -91,6 +91,12 @@ internal class AWSCognitoLegacyCredentialStore( override fun saveDeviceMetadata(username: String, deviceMetadata: DeviceMetadata) = Unit override fun saveASFDevice(device: AmplifyCredential.ASFDevice) = Unit + @Synchronized + fun retrieveLastAuthUserId(): String? { + val keys = getTokenKeys() + return keys[APP_LAST_AUTH_USER]?.let { tokensKeyValue.get(it) } + } + @Synchronized override fun retrieveCredential(): AmplifyCredential { val signedInData = retrieveSignedInData() @@ -133,6 +139,9 @@ internal class AWSCognitoLegacyCredentialStore( } override fun deleteDeviceKeyCredential(username: String) { + val keys = getTokenKeys() + keys[APP_LAST_AUTH_USER]?.let { tokensKeyValue.remove(it) } + deviceKeyValue.apply { remove(DEVICE_KEY) remove(DEVICE_GROUP_KEY) @@ -147,7 +156,6 @@ internal class AWSCognitoLegacyCredentialStore( private fun deleteCognitoUserPoolTokens() { val keys = getTokenKeys() - keys[APP_LAST_AUTH_USER]?.let { tokensKeyValue.remove(it) } keys[TOKEN_TYPE_ID]?.let { tokensKeyValue.remove(it) } keys[TOKEN_TYPE_ACCESS]?.let { tokensKeyValue.remove(it) } keys[TOKEN_TYPE_REFRESH]?.let { tokensKeyValue.remove(it) } From 17ca43a97dc1a90646dad32a5411d69a97190b33 Mon Sep 17 00:00:00 2001 From: Thomas Leing Date: Tue, 15 Nov 2022 17:23:20 -0800 Subject: [PATCH 22/36] Number of attributes being too high is not retryable (#2112) * Number of attributes being too high is not retryable * Match iOS at not retrying bad request error -- covering multiple 400 errors * Fix lint * Fix lint * Update Kotlin SDK version Co-authored-by: Thomas Leing --- .../analytics/pinpoint/EventRecorder.kt | 12 +++++++----- build.gradle | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/aws-analytics-pinpoint/src/main/java/com/amplifyframework/analytics/pinpoint/EventRecorder.kt b/aws-analytics-pinpoint/src/main/java/com/amplifyframework/analytics/pinpoint/EventRecorder.kt index 3706734c1f..36e0556cf6 100644 --- a/aws-analytics-pinpoint/src/main/java/com/amplifyframework/analytics/pinpoint/EventRecorder.kt +++ b/aws-analytics-pinpoint/src/main/java/com/amplifyframework/analytics/pinpoint/EventRecorder.kt @@ -57,6 +57,7 @@ internal class EventRecorder( private val defaultMaxSubmissionAllowed = 3 private val defaultMaxSubmissionSize = 1024 * 100 private val serviceDefinedMaxEventsPerBatch: Int = 100 + private val badRequestCode = 400 internal suspend fun recordEvent(pinpointEvent: PinpointEvent): Uri? { return withContext(coroutineDispatcher) { val result = runCatching { @@ -178,7 +179,7 @@ internal class EventRecorder( logger.info("Successfully submitted event with eventId ${pinpointEvent.eventId}") eventIdToDelete.add(pinpointEvent) } else { - if (isRetryableError(message)) { + if (isRetryableError(message, pinpointEventResponse.statusCode)) { logger.error( "Failed to deliver event with ${pinpointEvent.eventId}," + " will be re-delivered later" @@ -194,11 +195,12 @@ internal class EventRecorder( return eventIdToDelete } - private fun isRetryableError(responseCode: String): Boolean { + private fun isRetryableError(message: String, code: Int): Boolean { return !( - responseCode.equals("ValidationException", ignoreCase = true) || - responseCode.equals("SerializationException", ignoreCase = true) || - responseCode.equals("BadRequestException", ignoreCase = true) + message.equals("ValidationException", ignoreCase = true) || + message.equals("SerializationException", ignoreCase = true) || + message.equals("BadRequestException", ignoreCase = true) || + code == badRequestCode ) } diff --git a/build.gradle b/build.gradle index 547a37374c..ab03c555ce 100644 --- a/build.gradle +++ b/build.gradle @@ -69,7 +69,7 @@ ext { compileSdkVersion = 30 minSdkVersion = 24 targetSdkVersion = 30 - awsKotlinSdkVersion = '0.17.10-beta' + awsKotlinSdkVersion = '0.17.12-beta' fragmentVersion = '1.3.1' navigationVersion = '2.3.4' dependency = [ From d57749fbc6dff619ad3bd081a147658ec9d8154d Mon Sep 17 00:00:00 2001 From: Tyler Roach Date: Wed, 16 Nov 2022 14:05:57 -0500 Subject: [PATCH 23/36] Change errors returned on some apis while federated (#2116) --- .../auth/cognito/RealAWSCognitoAuthPlugin.kt | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPlugin.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPlugin.kt index 191dee1dda..1a32d375ee 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPlugin.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPlugin.kt @@ -971,9 +971,12 @@ internal class RealAWSCognitoAuthPlugin( onError ) } - else -> { + is AuthenticationState.SignedOut -> { onError.accept(SignedOutException()) } + else -> { + onError.accept(InvalidStateException()) + } } } } @@ -1020,9 +1023,12 @@ internal class RealAWSCognitoAuthPlugin( updateDevice(device.id, DeviceRememberedStatusType.NotRemembered, onSuccess, onError) } } - else -> { + is AuthenticationState.SignedOut -> { onError.accept(SignedOutException()) } + else -> { + onError.accept(InvalidStateException()) + } } } } @@ -1036,9 +1042,12 @@ internal class RealAWSCognitoAuthPlugin( is AuthenticationState.SignedIn -> { _fetchDevices(onSuccess, onError) } - else -> { + is AuthenticationState.SignedOut -> { onError.accept(SignedOutException()) } + else -> { + onError.accept(InvalidStateException()) + } } } } @@ -1506,18 +1515,23 @@ internal class RealAWSCognitoAuthPlugin( onError: Consumer ) { authStateMachine.getCurrentState { authState -> - if (authState.authNState !is AuthenticationState.SignedIn) { - onError.accept(SignedOutException()) - return@getCurrentState - } - - GlobalScope.async { - val accessToken = getSession().userPoolTokensResult.value?.accessToken - accessToken?.run { - val userid = SessionHelper.getUserSub(accessToken) ?: "" - val username = SessionHelper.getUsername(accessToken) ?: "" - onSuccess.accept(AuthUser(userid, username)) - } ?: onError.accept(InvalidUserPoolConfigurationException()) + when (authState.authNState) { + is AuthenticationState.SignedIn -> { + GlobalScope.async { + val accessToken = getSession().userPoolTokensResult.value?.accessToken + accessToken?.run { + val userid = SessionHelper.getUserSub(accessToken) ?: "" + val username = SessionHelper.getUsername(accessToken) ?: "" + onSuccess.accept(AuthUser(userid, username)) + } ?: onError.accept(InvalidUserPoolConfigurationException()) + } + } + is AuthenticationState.SignedOut -> { + onError.accept(SignedOutException()) + } + else -> { + onError.accept(InvalidStateException()) + } } } } From b4b539baa1ed929a6c044e30496a7adf36da3e1f Mon Sep 17 00:00:00 2001 From: Sunil Timalsina Date: Wed, 16 Nov 2022 12:20:35 -0800 Subject: [PATCH 24/36] release: Amplify Android 2.0.0 (#2115) * release: Amplify Android 2.0.0 * add core-kotlin changelog * add more info in changelog * revert unintended change * remove breaking change for analytics --- CHANGELOG.md | 38 ++++++++++++++++++++++++++++++++++++++ README.md | 12 ++++++------ core-kotlin/CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- rxbindings/README.md | 2 +- 5 files changed, 53 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8cf652f46..d95ab64c52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,41 @@ +## [Release 2.0.0](https://github.com/aws-amplify/amplify-android/releases/tag/release_v2.0.0) + +###Breaking Changes + +#### Android SDK +- Support for **Android SDK API 24: Android 7.0 (Nougat) and higher** + +#### Escape Hatches +- Escape Hatches provide access to AWS SDK for Kotlin instead of `AWSMobileClient` from AWS SDK for Android. + +#### Auth +- `signIn` now returns result with `isSignedIn` instead of `isSignInComplete` +- `confirmResetPassword` API takes additional `username` parameter. +- `signOut` now takes single `onComplete` parameter instead of `onSuccess` and `onError`. +- `fetchAuthSession` now returns `identityIdResult` instead of `identityId`. +- `getCurrentUser` API is now asynchronous and requires `onSuccess` and `onError` parameters. `AuthUser` is returned in `onSuccess` +- The escape hatch now provides access to the underlying `CognitoIdentityProviderClient` and `CognitoIdentityClient` instance. +- Parameters `signInQueryParameters`, `signOutQueryParameters`, and `tokenQueryParameters` are dropped from `AuthWebUISignInOptions`. +- `federationProviderName` has been dropped from `AWSCognitoAuthWebUISignInOptions`. +- `signIn` will now return an error if you attempt to call sign in, while already signed in. + +### Features +Replace underlying AWS SDK with AWS SDK for Kotlin. + +#### Auth +- Federate to Identity Pool +- Custom auth flow now supports without SRP flow +- Supports user migration flow +- Force refresh token. + +#### Storage +- Add support to query local enqueued transfers. + +### Miscellaneous +- All the categories use the same version number + +[See all changes between 2.0.0 and 1.37.6](https://github.com/aws-amplify/amplify-android/compare/release_v1.37.6...release_v2.0.0) + ## [Release 1.37.6](https://github.com/aws-amplify/amplify-android/releases/tag/release_v1.37.6) ### Miscellaneous diff --git a/README.md b/README.md index 07b1513519..f33c7255ca 100644 --- a/README.md +++ b/README.md @@ -69,12 +69,12 @@ dependencies section: ```groovy dependencies { // Only specify modules that provide functionality your app will use - implementation 'com.amplifyframework:aws-analytics-pinpoint:1.37.0-dev-preview.0' - implementation 'com.amplifyframework:aws-api:1.37.0-dev-preview.0' - implementation 'com.amplifyframework:aws-auth-cognito:1.37.0-dev-preview.0' - implementation 'com.amplifyframework:aws-datastore:1.37.0-dev-preview.0' - implementation 'com.amplifyframework:aws-predictions:1.37.0-dev-preview.0' - implementation 'com.amplifyframework:aws-storage-s3:1.37.0-dev-preview.0' + implementation 'com.amplifyframework:aws-analytics-pinpoint:2.0.0' + implementation 'com.amplifyframework:aws-api:2.0.0' + implementation 'com.amplifyframework:aws-auth-cognito:2.0.0' + implementation 'com.amplifyframework:aws-datastore:2.0.0' + implementation 'com.amplifyframework:aws-predictions:2.0.0' + implementation 'com.amplifyframework:aws-storage-s3:2.0.0' } ``` diff --git a/core-kotlin/CHANGELOG.md b/core-kotlin/CHANGELOG.md index dcd39b0929..ba1c18187d 100644 --- a/core-kotlin/CHANGELOG.md +++ b/core-kotlin/CHANGELOG.md @@ -1,3 +1,10 @@ +## [Release 2.0.0](https://github.com/aws-amplify/amplify-android/releases/tag/release_v2.0.0) + +### Miscellaneous +- core-kotlin module release is combined with Amplify release. + +[See all changes between 0.21.6 and 2.0.0](https://github.com/aws-amplify/amplify-android/compare/release-kotlin_v0.21.5...release_v2.0.0) + ## [Release 0.21.6](https://github.com/aws-amplify/amplify-android/releases/tag/release-kotlin_v0.21.6) ### Miscellaneous diff --git a/gradle.properties b/gradle.properties index 5c2b46ff2c..f8678fd73d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,7 +12,7 @@ org.gradle.jvmargs=-Xmx4g # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects org.gradle.parallel=true -VERSION_NAME=2.0.0-SNAPSHOT +VERSION_NAME=2.0.0 POM_GROUP=com.amplifyframework POM_URL=https://github.com/aws-amplify/amplify-android diff --git a/rxbindings/README.md b/rxbindings/README.md index 521684a1bc..f4142ee48e 100644 --- a/rxbindings/README.md +++ b/rxbindings/README.md @@ -24,7 +24,7 @@ library. In your module's `build.gradle`: ```gradle dependencies { // Add this line. - implementation 'com.amplifyframework:rxbindings:1.37.0-dev-preview.0' + implementation 'com.amplifyframework:rxbindings:2.0.0' } ``` From de8631b5e4c5d7a90484b835ccffbdb46e4c75ba Mon Sep 17 00:00:00 2001 From: Banji Jolaoso Date: Wed, 7 Dec 2022 09:17:10 -0800 Subject: [PATCH 25/36] added test case generators for forgot and remember device auth calls --- .../featuretest/generators/JsonGenerator.kt | 6 +- .../ForgetDeviceTestCaseGenerator.kt | 79 +++++++++++++++++++ .../RememberDeviceTestCaseGenerator.kt | 79 +++++++++++++++++++ .../ResetPasswordTestCaseGenerator.kt | 4 +- .../featureTest/utilities/APICaptorFactory.kt | 14 +++- .../utilities/AuthOptionsFactory.kt | 4 +- .../utilities/CognitoMockFactory.kt | 7 ++ 7 files changed, 187 insertions(+), 6 deletions(-) create mode 100644 aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ForgetDeviceTestCaseGenerator.kt create mode 100644 aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/RememberDeviceTestCaseGenerator.kt diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/JsonGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/JsonGenerator.kt index b91a8981bf..f95f03befb 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/JsonGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/JsonGenerator.kt @@ -20,6 +20,8 @@ import com.amplifyframework.auth.cognito.featuretest.generators.authstategenerat import com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators.ConfirmSignInTestCaseGenerator import com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators.DeleteUserTestCaseGenerator import com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators.FetchAuthSessionTestCaseGenerator +import com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators.ForgetDeviceTestCaseGenerator +import com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators.RememberDeviceTestCaseGenerator import com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators.ResetPasswordTestCaseGenerator import com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators.SignInTestCaseGenerator import com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators.SignOutTestCaseGenerator @@ -43,6 +45,8 @@ object JsonGenerator { ConfirmSignInTestCaseGenerator, DeleteUserTestCaseGenerator, FetchAuthSessionTestCaseGenerator, + RememberDeviceTestCaseGenerator, + ForgetDeviceTestCaseGenerator, ) fun generate() { @@ -61,6 +65,6 @@ object JsonGenerator { } fun main() { - cleanDirectory() + //cleanDirectory() JsonGenerator.generate() } diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ForgetDeviceTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ForgetDeviceTestCaseGenerator.kt new file mode 100644 index 0000000000..664ae768ea --- /dev/null +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ForgetDeviceTestCaseGenerator.kt @@ -0,0 +1,79 @@ +package com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators + +import aws.sdk.kotlin.services.cognitoidentityprovider.model.NotAuthorizedException +import com.amplifyframework.auth.cognito.featuretest.API +import com.amplifyframework.auth.cognito.featuretest.AuthAPI +import com.amplifyframework.auth.cognito.featuretest.CognitoType +import com.amplifyframework.auth.cognito.featuretest.ExpectationShapes +import com.amplifyframework.auth.cognito.featuretest.FeatureTestCase +import com.amplifyframework.auth.cognito.featuretest.MockResponse +import com.amplifyframework.auth.cognito.featuretest.PreConditions +import com.amplifyframework.auth.cognito.featuretest.ResponseType +import com.amplifyframework.auth.cognito.featuretest.generators.SerializableProvider +import com.amplifyframework.auth.cognito.featuretest.generators.toJsonElement +import kotlinx.serialization.json.JsonObject + +object ForgetDeviceTestCaseGenerator : SerializableProvider { + private val mockCognitoResponse = MockResponse( + CognitoType.CognitoIdentityProvider, + "updateDeviceStatus", + ResponseType.Success, + JsonObject(emptyMap()) + ) + + private val apiReturnValidation = ExpectationShapes.Amplify( + AuthAPI.forgetDevice, + ResponseType.Success, + JsonObject(emptyMap()), + ) + + private val baseCase = FeatureTestCase( + description = "Test that Cognito is called with given payload and returns successful data", + preConditions = PreConditions( + "authconfiguration.json", + "SignedIn_SessionEstablished.json", + mockedResponses = listOf(mockCognitoResponse) + ), + api = API( + AuthAPI.forgetDevice, + JsonObject(emptyMap()), + JsonObject(emptyMap()) + ), + validations = listOf(apiReturnValidation) + ) + + private val successCase: FeatureTestCase = baseCase.copy( + description = "Nothing is returned when forget device succeeds", + preConditions = baseCase.preConditions.copy(mockedResponses = listOf(mockCognitoResponse)), + validations = baseCase.validations.plus(apiReturnValidation) + ) + + private val errorCase: FeatureTestCase + get() { + val errorResponse = NotAuthorizedException.invoke {} + return baseCase.copy( + description = "AuthException is thrown when forgetDevice API call fails", + preConditions = baseCase.preConditions.copy( + mockedResponses = listOf( + MockResponse( + CognitoType.CognitoIdentityProvider, + "forgetDevice", + ResponseType.Failure, + errorResponse.toJsonElement() + ) + ) + ), + validations = listOf( + ExpectationShapes.Amplify( + AuthAPI.forgetDevice, + ResponseType.Failure, + com.amplifyframework.auth.exceptions.NotAuthorizedException( + cause = errorResponse + ).toJsonElement(), + ) + ) + ) + } + + override val serializables: List = listOf(baseCase, errorCase, successCase) +} diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/RememberDeviceTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/RememberDeviceTestCaseGenerator.kt new file mode 100644 index 0000000000..9101341847 --- /dev/null +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/RememberDeviceTestCaseGenerator.kt @@ -0,0 +1,79 @@ +package com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators + +import aws.sdk.kotlin.services.cognitoidentityprovider.model.NotAuthorizedException +import com.amplifyframework.auth.cognito.featuretest.API +import com.amplifyframework.auth.cognito.featuretest.AuthAPI +import com.amplifyframework.auth.cognito.featuretest.CognitoType +import com.amplifyframework.auth.cognito.featuretest.ExpectationShapes +import com.amplifyframework.auth.cognito.featuretest.FeatureTestCase +import com.amplifyframework.auth.cognito.featuretest.MockResponse +import com.amplifyframework.auth.cognito.featuretest.PreConditions +import com.amplifyframework.auth.cognito.featuretest.ResponseType +import com.amplifyframework.auth.cognito.featuretest.generators.SerializableProvider +import com.amplifyframework.auth.cognito.featuretest.generators.toJsonElement +import kotlinx.serialization.json.JsonObject + +object RememberDeviceTestCaseGenerator : SerializableProvider { + private val mockCognitoResponse = MockResponse( + CognitoType.CognitoIdentityProvider, + "updateDeviceStatus", + ResponseType.Success, + JsonObject(emptyMap()) + ) + + private val apiReturnValidation = ExpectationShapes.Amplify( + AuthAPI.rememberDevice, + ResponseType.Success, + JsonObject(emptyMap()), + ) + + private val baseCase = FeatureTestCase( + description = "Test that Cognito is called with given payload and returns successful data", + preConditions = PreConditions( + "authconfiguration.json", + "SignedIn_SessionEstablished.json", + mockedResponses = listOf(mockCognitoResponse) + ), + api = API( + AuthAPI.rememberDevice, + JsonObject(emptyMap()), + JsonObject(emptyMap()) + ), + validations = listOf(apiReturnValidation) + ) + + private val successCase: FeatureTestCase = baseCase.copy( + description = "Nothing is returned when remember device succeeds", + preConditions = baseCase.preConditions.copy(mockedResponses = listOf(mockCognitoResponse)), + validations = baseCase.validations.plus(apiReturnValidation) + ) + + private val errorCase: FeatureTestCase + get() { + val errorResponse = NotAuthorizedException.invoke {} + return baseCase.copy( + description = "AuthException is thrown when rememberDevice API call fails", + preConditions = baseCase.preConditions.copy( + mockedResponses = listOf( + MockResponse( + CognitoType.CognitoIdentityProvider, + "rememberDevice", + ResponseType.Failure, + errorResponse.toJsonElement() + ) + ) + ), + validations = listOf( + ExpectationShapes.Amplify( + AuthAPI.rememberDevice, + ResponseType.Failure, + com.amplifyframework.auth.exceptions.NotAuthorizedException( + cause = errorResponse + ).toJsonElement(), + ) + ) + ) + } + + override val serializables: List = listOf(baseCase, errorCase, successCase) +} diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ResetPasswordTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ResetPasswordTestCaseGenerator.kt index a371a924ed..250086da42 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ResetPasswordTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ResetPasswordTestCaseGenerator.kt @@ -100,12 +100,12 @@ object ResetPasswordTestCaseGenerator : SerializableProvider { get() { val errorResponse = NotAuthorizedException.invoke { message = "Cognito error message" } return baseCase.copy( - description = "AuthException is thrown when forgotPassword API call fails", + description = "AuthException is thrown when resetPassword API call fails", preConditions = baseCase.preConditions.copy( mockedResponses = listOf( MockResponse( CognitoType.CognitoIdentityProvider, - "forgotPassword", + "resetPassword", ResponseType.Failure, errorResponse.toJsonElement() ) diff --git a/aws-auth-cognito/src/test/java/featureTest/utilities/APICaptorFactory.kt b/aws-auth-cognito/src/test/java/featureTest/utilities/APICaptorFactory.kt index a7a625de8b..6f6bc48c12 100644 --- a/aws-auth-cognito/src/test/java/featureTest/utilities/APICaptorFactory.kt +++ b/aws-auth-cognito/src/test/java/featureTest/utilities/APICaptorFactory.kt @@ -47,7 +47,9 @@ class APICaptorFactory( AuthAPI.signIn to mockk>(), AuthAPI.deleteUser to mockk(), AuthAPI.fetchAuthSession to mockk(), - AuthAPI.getCurrentUser to mockk() + AuthAPI.getCurrentUser to mockk(), + AuthAPI.rememberDevice to mockk(), + AuthAPI.forgetDevice to mockk() ) val onError = mockk>() val onComplete = mapOf( @@ -105,6 +107,16 @@ class APICaptorFactory( every { consumer.call() } answers { latch.countDown() } successCaptors[apiName] = actionCaptor } + AuthAPI.rememberDevice -> { + val consumer = onSuccess[apiName] as Action + every { consumer.call() } answers { latch.countDown() } + successCaptors[apiName] = actionCaptor + } + AuthAPI.forgetDevice -> { + val consumer = onSuccess[apiName] as Action + every { consumer.call() } answers { latch.countDown() } + successCaptors[apiName] = actionCaptor + } else -> throw Error("onSuccess for $authApi is not defined!") } } diff --git a/aws-auth-cognito/src/test/java/featureTest/utilities/AuthOptionsFactory.kt b/aws-auth-cognito/src/test/java/featureTest/utilities/AuthOptionsFactory.kt index 3a80d136f4..99dd74cb1c 100644 --- a/aws-auth-cognito/src/test/java/featureTest/utilities/AuthOptionsFactory.kt +++ b/aws-auth-cognito/src/test/java/featureTest/utilities/AuthOptionsFactory.kt @@ -53,10 +53,10 @@ object AuthOptionsFactory { AuthAPI.fetchAuthSession -> getFetchAuthSessionOptions(optionsData) AuthAPI.fetchDevices -> null AuthAPI.fetchUserAttributes -> TODO() - AuthAPI.forgetDevice -> TODO() + AuthAPI.forgetDevice -> null AuthAPI.getCurrentUser -> null AuthAPI.handleWebUISignInResponse -> TODO() - AuthAPI.rememberDevice -> TODO() + AuthAPI.rememberDevice -> null AuthAPI.resendSignUpCode -> AuthResendSignUpCodeOptions.defaults() AuthAPI.resendUserAttributeConfirmationCode -> AuthResendUserAttributeConfirmationCodeOptions.defaults() signIn -> AuthSignInOptions.defaults() diff --git a/aws-auth-cognito/src/test/java/featureTest/utilities/CognitoMockFactory.kt b/aws-auth-cognito/src/test/java/featureTest/utilities/CognitoMockFactory.kt index a3cb1f065d..c362918d09 100644 --- a/aws-auth-cognito/src/test/java/featureTest/utilities/CognitoMockFactory.kt +++ b/aws-auth-cognito/src/test/java/featureTest/utilities/CognitoMockFactory.kt @@ -32,6 +32,7 @@ import aws.sdk.kotlin.services.cognitoidentityprovider.model.InitiateAuthRespons import aws.sdk.kotlin.services.cognitoidentityprovider.model.RespondToAuthChallengeResponse import aws.sdk.kotlin.services.cognitoidentityprovider.model.RevokeTokenResponse import aws.sdk.kotlin.services.cognitoidentityprovider.model.SignUpResponse +import aws.sdk.kotlin.services.cognitoidentityprovider.model.UpdateDeviceStatusResponse import aws.smithy.kotlin.runtime.time.Instant import com.amplifyframework.auth.cognito.featuretest.CognitoType import com.amplifyframework.auth.cognito.featuretest.MockResponse @@ -141,6 +142,12 @@ class CognitoMockFactory( GlobalSignOutResponse.invoke {} } } + "updateDeviceStatus" -> { + coEvery { mockCognitoIPClient.updateDeviceStatus(any()) } coAnswers { + setupError(mockResponse, responseObject) + UpdateDeviceStatusResponse.invoke { } + } + } else -> throw Error("mock for ${mockResponse.apiName} not defined!") } } From 2eeab447846889c97d9f411fb97835efbc3449d6 Mon Sep 17 00:00:00 2001 From: Banji Jolaoso Date: Sun, 11 Dec 2022 20:31:46 -0800 Subject: [PATCH 26/36] fixed test issue with overloaded auth api functions fixed test issue with auth api parameter type casting added test case generators for forgot device added test case generator for remember device added test case generator for fetch devices added test case generator for fetch user attributes --- .../featuretest/generators/JsonGenerator.kt | 6 +- .../FetchDevicesTestCaseGenerator.kt | 100 ++++++++++++++++++ .../FetchUserAttributesTestCaseGenerator.kt | 97 +++++++++++++++++ .../ForgetDeviceTestCaseGenerator.kt | 16 +-- .../RememberDeviceTestCaseGenerator.kt | 15 +-- .../ResetPasswordTestCaseGenerator.kt | 30 +----- .../java/featureTest/utilities/APIExecutor.kt | 46 +++++--- .../utilities/CognitoMockFactory.kt | 52 ++++++++- ...wn_when_forgotPassword_API_call_fails.json | 42 -------- 9 files changed, 296 insertions(+), 108 deletions(-) create mode 100644 aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchDevicesTestCaseGenerator.kt create mode 100644 aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchUserAttributesTestCaseGenerator.kt delete mode 100644 aws-auth-cognito/src/test/resources/feature-test/testsuites/resetPassword/AuthException_is_thrown_when_forgotPassword_API_call_fails.json diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/JsonGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/JsonGenerator.kt index f95f03befb..7a7910613f 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/JsonGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/JsonGenerator.kt @@ -20,6 +20,8 @@ import com.amplifyframework.auth.cognito.featuretest.generators.authstategenerat import com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators.ConfirmSignInTestCaseGenerator import com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators.DeleteUserTestCaseGenerator import com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators.FetchAuthSessionTestCaseGenerator +import com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators.FetchDevicesTestCaseGenerator +import com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators.FetchUserAttributesTestCaseGenerator import com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators.ForgetDeviceTestCaseGenerator import com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators.RememberDeviceTestCaseGenerator import com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators.ResetPasswordTestCaseGenerator @@ -47,6 +49,8 @@ object JsonGenerator { FetchAuthSessionTestCaseGenerator, RememberDeviceTestCaseGenerator, ForgetDeviceTestCaseGenerator, + FetchDevicesTestCaseGenerator, + FetchUserAttributesTestCaseGenerator, ) fun generate() { @@ -65,6 +69,6 @@ object JsonGenerator { } fun main() { - //cleanDirectory() + // cleanDirectory() JsonGenerator.generate() } diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchDevicesTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchDevicesTestCaseGenerator.kt new file mode 100644 index 0000000000..e4b69a44db --- /dev/null +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchDevicesTestCaseGenerator.kt @@ -0,0 +1,100 @@ +package com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators + +import aws.sdk.kotlin.services.cognitoidentityprovider.model.AttributeType +import aws.sdk.kotlin.services.cognitoidentityprovider.model.DeviceType +import aws.smithy.kotlin.runtime.time.Instant +import com.amplifyframework.auth.AuthDevice +import com.amplifyframework.auth.cognito.featuretest.API +import com.amplifyframework.auth.cognito.featuretest.AuthAPI +import com.amplifyframework.auth.cognito.featuretest.CognitoType +import com.amplifyframework.auth.cognito.featuretest.ExpectationShapes +import com.amplifyframework.auth.cognito.featuretest.FeatureTestCase +import com.amplifyframework.auth.cognito.featuretest.MockResponse +import com.amplifyframework.auth.cognito.featuretest.PreConditions +import com.amplifyframework.auth.cognito.featuretest.ResponseType +import com.amplifyframework.auth.cognito.featuretest.generators.SerializableProvider +import com.amplifyframework.auth.cognito.featuretest.generators.toJsonElement +import com.amplifyframework.auth.exceptions.SignedOutException +import kotlinx.serialization.json.JsonObject + +object FetchDevicesTestCaseGenerator : SerializableProvider { + + private val expectedSuccess = listOf(AuthDevice.fromId("deviceKey")).toJsonElement() + + private val mockCognitoResponse = MockResponse( + CognitoType.CognitoIdentityProvider, + "listDevices", + ResponseType.Success, + mapOf( + "devices" to listOf( + DeviceType.invoke { + deviceAttributes = listOf( + AttributeType.invoke { + name = "name" + value = "value" + } + ) + deviceKey = "deviceKey" + deviceCreateDate = Instant.now() + deviceLastAuthenticatedDate = Instant.now() + deviceLastModifiedDate = Instant.now() + } + ) + ).toJsonElement() + ) + + private val apiReturnValidation = ExpectationShapes.Amplify( + AuthAPI.fetchDevices, + ResponseType.Success, + expectedSuccess, + ) + + private val baseCase = FeatureTestCase( + description = "Test that Cognito is called with given payload and returns successful data", + preConditions = PreConditions( + "authconfiguration.json", + "SignedIn_SessionEstablished.json", + mockedResponses = listOf(mockCognitoResponse) + ), + api = API( + AuthAPI.fetchDevices, + JsonObject(emptyMap()), + JsonObject(emptyMap()), + ), + validations = listOf(apiReturnValidation) + ) + + private val successCase: FeatureTestCase = baseCase.copy( + description = "List of devices returned when fetch devices API succeeds", + preConditions = baseCase.preConditions.copy(mockedResponses = listOf(mockCognitoResponse)), + validations = baseCase.validations.plus(apiReturnValidation) + ) + + private val errorCase: FeatureTestCase + get() { + val errorResponse = SignedOutException() + return baseCase.copy( + description = "AuthException is thrown when forgetDevice API is called without signing in", + preConditions = baseCase.preConditions.copy( + state = "SignedOut_Configured.json", + mockedResponses = listOf( + MockResponse( + CognitoType.CognitoIdentityProvider, + "forgetDevice", + ResponseType.Failure, + errorResponse.toJsonElement() + ) + ) + ), + validations = listOf( + ExpectationShapes.Amplify( + AuthAPI.forgetDevice, + ResponseType.Failure, + com.amplifyframework.auth.exceptions.SignedOutException().toJsonElement(), + ) + ) + ) + } + + override val serializables: List = listOf(baseCase, errorCase, successCase) +} diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchUserAttributesTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchUserAttributesTestCaseGenerator.kt new file mode 100644 index 0000000000..379ae8a3c8 --- /dev/null +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchUserAttributesTestCaseGenerator.kt @@ -0,0 +1,97 @@ +package com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators +import aws.sdk.kotlin.services.cognitoidentityprovider.model.AttributeType +import com.amplifyframework.auth.AuthUserAttribute +import com.amplifyframework.auth.AuthUserAttributeKey +import com.amplifyframework.auth.cognito.featuretest.API +import com.amplifyframework.auth.cognito.featuretest.AuthAPI +import com.amplifyframework.auth.cognito.featuretest.CognitoType +import com.amplifyframework.auth.cognito.featuretest.ExpectationShapes +import com.amplifyframework.auth.cognito.featuretest.FeatureTestCase +import com.amplifyframework.auth.cognito.featuretest.MockResponse +import com.amplifyframework.auth.cognito.featuretest.PreConditions +import com.amplifyframework.auth.cognito.featuretest.ResponseType +import com.amplifyframework.auth.cognito.featuretest.generators.SerializableProvider +import com.amplifyframework.auth.cognito.featuretest.generators.toJsonElement +import com.amplifyframework.auth.exceptions.SignedOutException +import kotlinx.serialization.json.JsonObject + +object FetchUserAttributesTestCaseGenerator : SerializableProvider { + + private val expectedSuccess = listOf( + AuthUserAttribute(AuthUserAttributeKey.email(), "email@email.com"), + AuthUserAttribute(AuthUserAttributeKey.phoneNumber(), "000-000-0000") + ).toJsonElement() + + private val mockCognitoResponse = MockResponse( + CognitoType.CognitoIdentityProvider, + "getUser", + ResponseType.Success, + mapOf( + "userAttributes" to listOf( + AttributeType.invoke { + name = "email" + value = "email@email.com" + }, + AttributeType.invoke { + name = "phone" + value = "000-000-0000" + } + ) + ).toJsonElement() + ) + + private val apiReturnValidation = ExpectationShapes.Amplify( + AuthAPI.fetchUserAttributes, + ResponseType.Success, + expectedSuccess, + ) + + private val baseCase = FeatureTestCase( + description = "Test that Cognito is called with given payload and returns successful data", + preConditions = PreConditions( + "authconfiguration.json", + "SignedIn_SessionEstablished.json", + mockedResponses = listOf(mockCognitoResponse) + ), + api = API( + AuthAPI.fetchUserAttributes, + JsonObject(emptyMap()), + JsonObject(emptyMap()), + ), + validations = listOf(apiReturnValidation) + ) + + private val successCase: FeatureTestCase = baseCase.copy( + description = "List of user attributes returned when fetch user attributes API succeeds", + preConditions = baseCase.preConditions.copy(mockedResponses = listOf(mockCognitoResponse)), + validations = baseCase.validations.plus(apiReturnValidation) + ) + + private val errorCase: FeatureTestCase + get() { + val errorResponse = SignedOutException() + return baseCase.copy( + description = "AuthException is thrown when fetchUserAttributes API is called without signing in", + preConditions = baseCase.preConditions.copy( + state = "SignedOut_Configured.json", + mockedResponses = listOf( + MockResponse( + CognitoType.CognitoIdentityProvider, + "getUser", + ResponseType.Failure, + errorResponse.toJsonElement() + ) + ) + ), + validations = listOf( + ExpectationShapes.Amplify( + AuthAPI.fetchUserAttributes, + ResponseType.Failure, + SignedOutException().toJsonElement(), + ) + ) + ) + } + + override val serializables: List = listOf(baseCase, errorCase, successCase) +} diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ForgetDeviceTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ForgetDeviceTestCaseGenerator.kt index 664ae768ea..e988b09d85 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ForgetDeviceTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ForgetDeviceTestCaseGenerator.kt @@ -1,6 +1,6 @@ package com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators -import aws.sdk.kotlin.services.cognitoidentityprovider.model.NotAuthorizedException +import com.amplifyframework.auth.AuthDevice import com.amplifyframework.auth.cognito.featuretest.API import com.amplifyframework.auth.cognito.featuretest.AuthAPI import com.amplifyframework.auth.cognito.featuretest.CognitoType @@ -11,6 +11,7 @@ import com.amplifyframework.auth.cognito.featuretest.PreConditions import com.amplifyframework.auth.cognito.featuretest.ResponseType import com.amplifyframework.auth.cognito.featuretest.generators.SerializableProvider import com.amplifyframework.auth.cognito.featuretest.generators.toJsonElement +import com.amplifyframework.auth.exceptions.SignedOutException import kotlinx.serialization.json.JsonObject object ForgetDeviceTestCaseGenerator : SerializableProvider { @@ -36,8 +37,10 @@ object ForgetDeviceTestCaseGenerator : SerializableProvider { ), api = API( AuthAPI.forgetDevice, + mapOf( + "device" to AuthDevice.fromId("id", "test") + ).toJsonElement(), JsonObject(emptyMap()), - JsonObject(emptyMap()) ), validations = listOf(apiReturnValidation) ) @@ -50,10 +53,11 @@ object ForgetDeviceTestCaseGenerator : SerializableProvider { private val errorCase: FeatureTestCase get() { - val errorResponse = NotAuthorizedException.invoke {} + val errorResponse = SignedOutException() return baseCase.copy( - description = "AuthException is thrown when forgetDevice API call fails", + description = "AuthException is thrown when forgetDevice API is called without signing in", preConditions = baseCase.preConditions.copy( + state = "SignedOut_Configured.json", mockedResponses = listOf( MockResponse( CognitoType.CognitoIdentityProvider, @@ -67,9 +71,7 @@ object ForgetDeviceTestCaseGenerator : SerializableProvider { ExpectationShapes.Amplify( AuthAPI.forgetDevice, ResponseType.Failure, - com.amplifyframework.auth.exceptions.NotAuthorizedException( - cause = errorResponse - ).toJsonElement(), + SignedOutException().toJsonElement(), ) ) ) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/RememberDeviceTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/RememberDeviceTestCaseGenerator.kt index 9101341847..81617a4b2e 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/RememberDeviceTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/RememberDeviceTestCaseGenerator.kt @@ -52,24 +52,15 @@ object RememberDeviceTestCaseGenerator : SerializableProvider { get() { val errorResponse = NotAuthorizedException.invoke {} return baseCase.copy( - description = "AuthException is thrown when rememberDevice API call fails", + description = "AuthException is thrown when rememberDevice API is called without signing in", preConditions = baseCase.preConditions.copy( - mockedResponses = listOf( - MockResponse( - CognitoType.CognitoIdentityProvider, - "rememberDevice", - ResponseType.Failure, - errorResponse.toJsonElement() - ) - ) + state = "SignedOut_Configured.json" ), validations = listOf( ExpectationShapes.Amplify( AuthAPI.rememberDevice, ResponseType.Failure, - com.amplifyframework.auth.exceptions.NotAuthorizedException( - cause = errorResponse - ).toJsonElement(), + com.amplifyframework.auth.exceptions.SignedOutException().toJsonElement(), ) ) ) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ResetPasswordTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ResetPasswordTestCaseGenerator.kt index 250086da42..855f318505 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ResetPasswordTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ResetPasswordTestCaseGenerator.kt @@ -15,7 +15,6 @@ package com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators -import aws.sdk.kotlin.services.cognitoidentityprovider.model.NotAuthorizedException import com.amplifyframework.auth.cognito.featuretest.API import com.amplifyframework.auth.cognito.featuretest.AuthAPI import com.amplifyframework.auth.cognito.featuretest.CognitoType @@ -96,32 +95,5 @@ object ResetPasswordTestCaseGenerator : SerializableProvider { validations = baseCase.validations.plus(apiReturnValidation) ) - private val errorCase: FeatureTestCase - get() { - val errorResponse = NotAuthorizedException.invoke { message = "Cognito error message" } - return baseCase.copy( - description = "AuthException is thrown when resetPassword API call fails", - preConditions = baseCase.preConditions.copy( - mockedResponses = listOf( - MockResponse( - CognitoType.CognitoIdentityProvider, - "resetPassword", - ResponseType.Failure, - errorResponse.toJsonElement() - ) - ) - ), - validations = listOf( - ExpectationShapes.Amplify( - AuthAPI.resetPassword, - ResponseType.Failure, - com.amplifyframework.auth.exceptions.NotAuthorizedException( - cause = errorResponse - ).toJsonElement(), - ) - ) - ) - } - - override val serializables: List = listOf(baseCase, errorCase, successCase) + override val serializables: List = listOf(baseCase, successCase) } diff --git a/aws-auth-cognito/src/test/java/featureTest/utilities/APIExecutor.kt b/aws-auth-cognito/src/test/java/featureTest/utilities/APIExecutor.kt index 32ebde1094..093bced842 100644 --- a/aws-auth-cognito/src/test/java/featureTest/utilities/APIExecutor.kt +++ b/aws-auth-cognito/src/test/java/featureTest/utilities/APIExecutor.kt @@ -22,7 +22,9 @@ import com.amplifyframework.core.Consumer import com.google.gson.Gson import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit +import kotlin.Exception import kotlin.reflect.KClass +import kotlin.reflect.KFunction import kotlin.reflect.KParameter import kotlin.reflect.full.declaredFunctions import kotlinx.serialization.json.JsonObject @@ -34,25 +36,37 @@ internal val apiExecutor: (AWSCognitoAuthPlugin, API) -> Any = { authPlugin: AWS lateinit var result: Any val latch = CountDownLatch(1) + val targetApis = authPlugin::class.declaredFunctions.filter { it.name == api.name.name } - val targetApi = authPlugin::class.declaredFunctions.first { it.name == api.name.name } - - val requiredParams = targetApi.parameters.associateWith { kParam -> - when { - kParam.kind == KParameter.Kind.INSTANCE -> authPlugin - kParam.type.classifier as KClass<*> == Action::class -> Action { - result = Unit - latch.countDown() - } - kParam.type.classifier as KClass<*> == Consumer::class -> Consumer { value -> - result = value - latch.countDown() + var requiredParams: Map? = null + var targetApi: KFunction<*>? = null + for (currentApi in targetApis) { + try { + val currentParams = currentApi.parameters.associateWith { kParam -> + when { + kParam.kind == KParameter.Kind.INSTANCE -> authPlugin + kParam.type.classifier as KClass<*> == Action::class -> Action { + result = Unit + latch.countDown() + } + kParam.type.classifier as KClass<*> == Consumer::class -> Consumer { value -> + result = value + latch.countDown() + } + kParam.name == "options" -> AuthOptionsFactory.create(api.name, api.options as JsonObject) + else -> kParam.name?.let { getParam(it, kParam, api.params as JsonObject) } + } } - kParam.name == "options" -> AuthOptionsFactory.create(api.name, api.options as JsonObject) - else -> kParam.name?.let { getParam(it, api.params as JsonObject) } + targetApi = currentApi + requiredParams = currentParams + break + } catch (ex: Exception) { + print(ex.toString()) } } + if (targetApi == null || requiredParams == null) + throw Exception("No matching api function with required parameters found") targetApi.callBy(requiredParams) latch.await(5, TimeUnit.SECONDS) @@ -62,10 +76,10 @@ internal val apiExecutor: (AWSCognitoAuthPlugin, API) -> Any = { authPlugin: AWS /** * Traverses given json to find value of paramName */ -private inline fun getParam(paramName: String, paramsObject: Map): T { +private inline fun getParam(paramName: String, kParam: KParameter, paramsObject: Map): kotlin.Any { paramsObject.entries.first { it.key == paramName }.apply { - return Gson().fromJson(value.toString(), T::class.java) + return Gson().fromJson(value.toString(), (kParam.type.classifier as KClass<*>).javaObjectType) } } diff --git a/aws-auth-cognito/src/test/java/featureTest/utilities/CognitoMockFactory.kt b/aws-auth-cognito/src/test/java/featureTest/utilities/CognitoMockFactory.kt index c362918d09..0151d81bd3 100644 --- a/aws-auth-cognito/src/test/java/featureTest/utilities/CognitoMockFactory.kt +++ b/aws-auth-cognito/src/test/java/featureTest/utilities/CognitoMockFactory.kt @@ -20,15 +20,21 @@ import aws.sdk.kotlin.services.cognitoidentity.model.Credentials import aws.sdk.kotlin.services.cognitoidentity.model.GetCredentialsForIdentityResponse import aws.sdk.kotlin.services.cognitoidentity.model.GetIdResponse import aws.sdk.kotlin.services.cognitoidentityprovider.CognitoIdentityProviderClient +import aws.sdk.kotlin.services.cognitoidentityprovider.forgetDevice +import aws.sdk.kotlin.services.cognitoidentityprovider.model.AttributeType import aws.sdk.kotlin.services.cognitoidentityprovider.model.AuthenticationResultType import aws.sdk.kotlin.services.cognitoidentityprovider.model.ChallengeNameType import aws.sdk.kotlin.services.cognitoidentityprovider.model.CodeDeliveryDetailsType import aws.sdk.kotlin.services.cognitoidentityprovider.model.ConfirmDeviceResponse import aws.sdk.kotlin.services.cognitoidentityprovider.model.DeleteUserResponse import aws.sdk.kotlin.services.cognitoidentityprovider.model.DeliveryMediumType +import aws.sdk.kotlin.services.cognitoidentityprovider.model.DeviceType +import aws.sdk.kotlin.services.cognitoidentityprovider.model.ForgetDeviceResponse import aws.sdk.kotlin.services.cognitoidentityprovider.model.ForgotPasswordResponse +import aws.sdk.kotlin.services.cognitoidentityprovider.model.GetUserResponse import aws.sdk.kotlin.services.cognitoidentityprovider.model.GlobalSignOutResponse import aws.sdk.kotlin.services.cognitoidentityprovider.model.InitiateAuthResponse +import aws.sdk.kotlin.services.cognitoidentityprovider.model.ListDevicesResponse import aws.sdk.kotlin.services.cognitoidentityprovider.model.RespondToAuthChallengeResponse import aws.sdk.kotlin.services.cognitoidentityprovider.model.RevokeTokenResponse import aws.sdk.kotlin.services.cognitoidentityprovider.model.SignUpResponse @@ -116,6 +122,23 @@ class CognitoMockFactory( } } } + "getUser" -> { + coEvery { mockCognitoIPClient.getUser(any()) } coAnswers { + setupError(mockResponse, responseObject) + GetUserResponse.invoke { + userAttributes = listOf( + AttributeType.invoke { + name = "email" + value = "email@email.com" + }, + AttributeType.invoke { + name = "phone_number" + value = "000-000-0000" + } + ) + } + } + } "getCredentialsForIdentity" -> { coEvery { mockCognitoIdClient.getCredentialsForIdentity(any()) } coAnswers { setupError(mockResponse, responseObject) @@ -145,7 +168,34 @@ class CognitoMockFactory( "updateDeviceStatus" -> { coEvery { mockCognitoIPClient.updateDeviceStatus(any()) } coAnswers { setupError(mockResponse, responseObject) - UpdateDeviceStatusResponse.invoke { } + UpdateDeviceStatusResponse.invoke { } + } + } + "forgetDevice" -> { + coEvery { mockCognitoIPClient.forgetDevice(any()) } coAnswers { + setupError(mockResponse, responseObject) + ForgetDeviceResponse.invoke {} + } + } + "listDevices" -> { + coEvery { mockCognitoIPClient.listDevices(any()) } coAnswers { + setupError(mockResponse, responseObject) + ListDevicesResponse.invoke { + devices = listOf( + DeviceType.invoke { + deviceAttributes = listOf( + AttributeType.invoke { + name = "name" + value = "value" + } + ) + deviceKey = "deviceKey" + deviceCreateDate = Instant.now() + deviceLastAuthenticatedDate = Instant.now() + deviceLastModifiedDate = Instant.now() + } + ) + } } } else -> throw Error("mock for ${mockResponse.apiName} not defined!") diff --git a/aws-auth-cognito/src/test/resources/feature-test/testsuites/resetPassword/AuthException_is_thrown_when_forgotPassword_API_call_fails.json b/aws-auth-cognito/src/test/resources/feature-test/testsuites/resetPassword/AuthException_is_thrown_when_forgotPassword_API_call_fails.json deleted file mode 100644 index d24c0fd052..0000000000 --- a/aws-auth-cognito/src/test/resources/feature-test/testsuites/resetPassword/AuthException_is_thrown_when_forgotPassword_API_call_fails.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "description": "AuthException is thrown when forgotPassword API call fails", - "preConditions": { - "amplify-configuration": "authconfiguration.json", - "state": "SignedOut_Configured.json", - "mockedResponses": [ - { - "type": "cognitoIdentityProvider", - "apiName": "forgotPassword", - "responseType": "failure", - "response": { - "errorType": "NotAuthorizedException", - "errorMessage": "Cognito error message" - } - } - ] - }, - "api": { - "name": "resetPassword", - "params": { - "username": "someUsername" - }, - "options": { - } - }, - "validations": [ - { - "type": "amplify", - "apiName": "resetPassword", - "responseType": "failure", - "response": { - "errorType": "NotAuthorizedException", - "errorMessage": "Failed since user is not authorized.", - "recoverySuggestion": "Check whether the given values are correct and the user is authorized to perform the operation.", - "cause": { - "errorType": "NotAuthorizedException", - "errorMessage": "Cognito error message" - } - } - } - ] -} \ No newline at end of file From 3470e9ee0d760f901b2cb4ab98443f33654fe182 Mon Sep 17 00:00:00 2001 From: Banji Jolaoso Date: Sun, 11 Dec 2022 20:40:49 -0800 Subject: [PATCH 27/36] Added tests to captor factory --- .../java/featureTest/utilities/APICaptorFactory.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/aws-auth-cognito/src/test/java/featureTest/utilities/APICaptorFactory.kt b/aws-auth-cognito/src/test/java/featureTest/utilities/APICaptorFactory.kt index 6f6bc48c12..8fd7d2c25f 100644 --- a/aws-auth-cognito/src/test/java/featureTest/utilities/APICaptorFactory.kt +++ b/aws-auth-cognito/src/test/java/featureTest/utilities/APICaptorFactory.kt @@ -117,6 +117,16 @@ class APICaptorFactory( every { consumer.call() } answers { latch.countDown() } successCaptors[apiName] = actionCaptor } + AuthAPI.fetchDevices -> { + val consumer = onSuccess[apiName] as Action + every { consumer.call() } answers { latch.countDown() } + successCaptors[apiName] = actionCaptor + } + AuthAPI.fetchUserAttributes -> { + val consumer = onSuccess[apiName] as Action + every { consumer.call() } answers { latch.countDown() } + successCaptors[apiName] = actionCaptor + } else -> throw Error("onSuccess for $authApi is not defined!") } } From a0ac6a77cbca114333f05e3b1d0cfd417d1b845f Mon Sep 17 00:00:00 2001 From: Banji Jolaoso Date: Wed, 14 Dec 2022 17:34:09 -0800 Subject: [PATCH 28/36] Added license to classes --- .../FetchAuthSessionTestCaseGenerator.kt | 15 +++++++++++++++ .../FetchDevicesTestCaseGenerator.kt | 15 +++++++++++++++ .../FetchUserAttributesTestCaseGenerator.kt | 15 +++++++++++++++ .../ForgetDeviceTestCaseGenerator.kt | 15 +++++++++++++++ .../GetCurrentUserTestCaseGenerator.kt | 15 +++++++++++++++ .../RememberDeviceTestCaseGenerator.kt | 15 +++++++++++++++ 6 files changed, 90 insertions(+) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt index 02c413dac3..6b22b2051d 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt @@ -1,3 +1,18 @@ +/* + * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + package com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators import com.amplifyframework.auth.AWSCredentials diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchDevicesTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchDevicesTestCaseGenerator.kt index e4b69a44db..d42ad08221 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchDevicesTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchDevicesTestCaseGenerator.kt @@ -1,3 +1,18 @@ +/* + * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + package com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators import aws.sdk.kotlin.services.cognitoidentityprovider.model.AttributeType diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchUserAttributesTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchUserAttributesTestCaseGenerator.kt index 379ae8a3c8..9c8ab072fc 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchUserAttributesTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchUserAttributesTestCaseGenerator.kt @@ -1,3 +1,18 @@ +/* + * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + package com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators import aws.sdk.kotlin.services.cognitoidentityprovider.model.AttributeType import com.amplifyframework.auth.AuthUserAttribute diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ForgetDeviceTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ForgetDeviceTestCaseGenerator.kt index e988b09d85..04aa7f81c3 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ForgetDeviceTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ForgetDeviceTestCaseGenerator.kt @@ -1,3 +1,18 @@ +/* + * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + package com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators import com.amplifyframework.auth.AuthDevice diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/GetCurrentUserTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/GetCurrentUserTestCaseGenerator.kt index 7eebb704b1..df61d83594 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/GetCurrentUserTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/GetCurrentUserTestCaseGenerator.kt @@ -1,3 +1,18 @@ +/* + * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + package com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators import aws.sdk.kotlin.services.cognitoidentityprovider.model.NotAuthorizedException diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/RememberDeviceTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/RememberDeviceTestCaseGenerator.kt index 81617a4b2e..df8870dd8f 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/RememberDeviceTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/RememberDeviceTestCaseGenerator.kt @@ -1,3 +1,18 @@ +/* + * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + package com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators import aws.sdk.kotlin.services.cognitoidentityprovider.model.NotAuthorizedException From 2378ba7c8ff9622130e27e3b722300a6ca4c33eb Mon Sep 17 00:00:00 2001 From: Banji Jolaoso Date: Wed, 14 Dec 2022 17:43:37 -0800 Subject: [PATCH 29/36] Added error case to reset password test case generator --- .../featuretest/generators/JsonGenerator.kt | 2 +- .../ResetPasswordTestCaseGenerator.kt | 30 ++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/JsonGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/JsonGenerator.kt index 7a7910613f..5202ba3951 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/JsonGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/JsonGenerator.kt @@ -69,6 +69,6 @@ object JsonGenerator { } fun main() { - // cleanDirectory() + //cleanDirectory() JsonGenerator.generate() } diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ResetPasswordTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ResetPasswordTestCaseGenerator.kt index 855f318505..a371a924ed 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ResetPasswordTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ResetPasswordTestCaseGenerator.kt @@ -15,6 +15,7 @@ package com.amplifyframework.auth.cognito.featuretest.generators.testcasegenerators +import aws.sdk.kotlin.services.cognitoidentityprovider.model.NotAuthorizedException import com.amplifyframework.auth.cognito.featuretest.API import com.amplifyframework.auth.cognito.featuretest.AuthAPI import com.amplifyframework.auth.cognito.featuretest.CognitoType @@ -95,5 +96,32 @@ object ResetPasswordTestCaseGenerator : SerializableProvider { validations = baseCase.validations.plus(apiReturnValidation) ) - override val serializables: List = listOf(baseCase, successCase) + private val errorCase: FeatureTestCase + get() { + val errorResponse = NotAuthorizedException.invoke { message = "Cognito error message" } + return baseCase.copy( + description = "AuthException is thrown when forgotPassword API call fails", + preConditions = baseCase.preConditions.copy( + mockedResponses = listOf( + MockResponse( + CognitoType.CognitoIdentityProvider, + "forgotPassword", + ResponseType.Failure, + errorResponse.toJsonElement() + ) + ) + ), + validations = listOf( + ExpectationShapes.Amplify( + AuthAPI.resetPassword, + ResponseType.Failure, + com.amplifyframework.auth.exceptions.NotAuthorizedException( + cause = errorResponse + ).toJsonElement(), + ) + ) + ) + } + + override val serializables: List = listOf(baseCase, errorCase, successCase) } From 5cc1ec4a69adb7e5205c68f5b70d1aa3eaf530d6 Mon Sep 17 00:00:00 2001 From: Banji Jolaoso Date: Fri, 16 Dec 2022 22:17:48 -0800 Subject: [PATCH 30/36] fixed lint issue --- .../auth/cognito/featuretest/generators/JsonGenerator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/JsonGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/JsonGenerator.kt index 5202ba3951..7a7910613f 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/JsonGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/JsonGenerator.kt @@ -69,6 +69,6 @@ object JsonGenerator { } fun main() { - //cleanDirectory() + // cleanDirectory() JsonGenerator.generate() } From 2622d8c297440d6b4b90a0d9b7cfb074a68486c1 Mon Sep 17 00:00:00 2001 From: Banji Jolaoso Date: Thu, 22 Dec 2022 10:26:32 -0800 Subject: [PATCH 31/36] added json files --- .../configuration/authconfiguration.json | 36 --------- .../states/CustomSignIn_SigningIn.json | 26 ------- .../SignedIn_UserPoolSessionEstablished.json | 42 ----------- .../SignedOut_IdentityPoolConfigured.json | 34 --------- ...vice_API_is_called_without_signing_in.json | 40 ++++++++++ ...urned_when_fetch_devices_API_succeeds.json | 74 +++++++++++++++++++ ...n_payload_and_returns_successful_data.json | 64 ++++++++++++++++ ...utes_API_is_called_without_signing_in.json | 40 ++++++++++ ...en_fetch_user_attributes_API_succeeds.json | 73 ++++++++++++++++++ ...n_payload_and_returns_successful_data.json | 54 ++++++++++++++ ...vice_API_is_called_without_signing_in.json | 44 +++++++++++ ...vice_API_is_called_without_signing_in.json | 36 +++++++++ ...wn_when_forgotPassword_API_call_fails.json | 42 +++++++++++ 13 files changed, 467 insertions(+), 138 deletions(-) delete mode 100644 aws-auth-cognito/src/test/resources/feature-test/configuration/authconfiguration.json delete mode 100644 aws-auth-cognito/src/test/resources/feature-test/states/CustomSignIn_SigningIn.json delete mode 100644 aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_UserPoolSessionEstablished.json delete mode 100644 aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_IdentityPoolConfigured.json create mode 100644 aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchDevices/AuthException_is_thrown_when_forgetDevice_API_is_called_without_signing_in.json create mode 100644 aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchDevices/List_of_devices_returned_when_fetch_devices_API_succeeds.json create mode 100644 aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchDevices/Test_that_Cognito_is_called_with_given_payload_and_returns_successful_data.json create mode 100644 aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchUserAttributes/AuthException_is_thrown_when_fetchUserAttributes_API_is_called_without_signing_in.json create mode 100644 aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchUserAttributes/List_of_user_attributes_returned_when_fetch_user_attributes_API_succeeds.json create mode 100644 aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchUserAttributes/Test_that_Cognito_is_called_with_given_payload_and_returns_successful_data.json create mode 100644 aws-auth-cognito/src/test/resources/feature-test/testsuites/forgetDevice/AuthException_is_thrown_when_forgetDevice_API_is_called_without_signing_in.json create mode 100644 aws-auth-cognito/src/test/resources/feature-test/testsuites/rememberDevice/AuthException_is_thrown_when_rememberDevice_API_is_called_without_signing_in.json create mode 100644 aws-auth-cognito/src/test/resources/feature-test/testsuites/resetPassword/AuthException_is_thrown_when_forgotPassword_API_call_fails.json diff --git a/aws-auth-cognito/src/test/resources/feature-test/configuration/authconfiguration.json b/aws-auth-cognito/src/test/resources/feature-test/configuration/authconfiguration.json deleted file mode 100644 index cab6a45e13..0000000000 --- a/aws-auth-cognito/src/test/resources/feature-test/configuration/authconfiguration.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "UserAgent": "aws-amplify-cli/2.0", - "Version": "1.0", - "auth": { - "plugins": { - "awsCognitoAuthPlugin": { - "UserAgent": "aws-amplify-cli/0.1.0", - "Version": "0.1.0", - "IdentityManager": { - "Default": {} - }, - "CredentialsProvider": { - "CognitoIdentity": { - "Default": { - "PoolId": "us-east-1_testIdentityPoolId", - "Region": "us-east-1" - } - } - }, - "CognitoUserPool": { - "Default": { - "PoolId": "us-east-1_testUserPoolId", - "AppClientId": "testAppClientId", - "AppClientSecret": "testAppClientSecret", - "Region": "us-east-1" - } - }, - "Auth": { - "Default": { - "authenticationFlowType": "USER_SRP_AUTH" - } - } - } - } - } -} \ No newline at end of file diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/CustomSignIn_SigningIn.json b/aws-auth-cognito/src/test/resources/feature-test/states/CustomSignIn_SigningIn.json deleted file mode 100644 index 5ccb17e359..0000000000 --- a/aws-auth-cognito/src/test/resources/feature-test/states/CustomSignIn_SigningIn.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "type": "AuthState.Configured", - "AuthenticationState": { - "type": "AuthenticationState.SigningIn", - "SignInState": { - "type": "SignInState.ResolvingChallenge", - "SignInChallengeState": { - "type": "SignInChallengeState.WaitingForAnswer", - "authChallenge": { - "challengeName": "CUSTOM_CHALLENGE", - "username": "username", - "session": "someSession", - "parameters": { - "SALT": "abc", - "SECRET_BLOCK": "secretBlock", - "SRP_B": "def", - "USERNAME": "username" - } - } - } - } - }, - "AuthorizationState": { - "type": "AuthorizationState.SigningIn" - } -} diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_UserPoolSessionEstablished.json b/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_UserPoolSessionEstablished.json deleted file mode 100644 index 93bbd31c57..0000000000 --- a/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_UserPoolSessionEstablished.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "type": "AuthState.Configured", - "AuthenticationState": { - "type": "AuthenticationState.SignedIn", - "signedInData": { - "userId": "userId", - "username": "username", - "signedInDate": 0, - "signInMethod": { - "type": "SignInMethod.ApiBased", - "authType": "USER_SRP_AUTH" - }, - "cognitoUserPoolTokens": { - "idToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", - "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", - "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", - "expiration": 300 - } - } - }, - "AuthorizationState": { - "type": "AuthorizationState.SessionEstablished", - "amplifyCredential": { - "type": "userPool", - "signedInData": { - "userId": "userId", - "username": "username", - "signedInDate": 0, - "signInMethod": { - "type": "SignInMethod.ApiBased", - "authType": "USER_SRP_AUTH" - }, - "cognitoUserPoolTokens": { - "idToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", - "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", - "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", - "expiration": 300 - } - } - } - } -} \ No newline at end of file diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_IdentityPoolConfigured.json b/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_IdentityPoolConfigured.json deleted file mode 100644 index 028d2d4bd1..0000000000 --- a/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_IdentityPoolConfigured.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "type": "AuthState.Configured", - "AuthenticationState": { - "type": "AuthenticationState.SignedIn", - "signedInData": { - "userId": "userId", - "username": "username", - "signedInDate": 0, - "signInMethod": { - "type": "SignInMethod.ApiBased", - "authType": "USER_SRP_AUTH" - }, - "cognitoUserPoolTokens": { - "idToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", - "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", - "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", - "expiration": 300 - } - } - }, - "AuthorizationState": { - "type": "AuthorizationState.SessionEstablished", - "amplifyCredential": { - "type": "identityPool", - "identityId": "someIdentityId", - "credentials": { - "accessKeyId": "someAccessKey", - "secretAccessKey": "someSecretKey", - "sessionToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", - "expiration": 2342134 - } - } - } -} \ No newline at end of file diff --git a/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchDevices/AuthException_is_thrown_when_forgetDevice_API_is_called_without_signing_in.json b/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchDevices/AuthException_is_thrown_when_forgetDevice_API_is_called_without_signing_in.json new file mode 100644 index 0000000000..7f79fddd9f --- /dev/null +++ b/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchDevices/AuthException_is_thrown_when_forgetDevice_API_is_called_without_signing_in.json @@ -0,0 +1,40 @@ +{ + "description": "AuthException is thrown when forgetDevice API is called without signing in", + "preConditions": { + "amplify-configuration": "authconfiguration.json", + "state": "SignedOut_Configured.json", + "mockedResponses": [ + { + "type": "cognitoIdentityProvider", + "apiName": "forgetDevice", + "responseType": "failure", + "response": { + "errorType": "SignedOutException", + "errorMessage": "You are currently signed out.", + "recoverySuggestion": "Please sign in and reattempt the operation.", + "cause": null + } + } + ] + }, + "api": { + "name": "fetchDevices", + "params": { + }, + "options": { + } + }, + "validations": [ + { + "type": "amplify", + "apiName": "forgetDevice", + "responseType": "failure", + "response": { + "errorType": "SignedOutException", + "errorMessage": "You are currently signed out.", + "recoverySuggestion": "Please sign in and reattempt the operation.", + "cause": null + } + } + ] +} \ No newline at end of file diff --git a/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchDevices/List_of_devices_returned_when_fetch_devices_API_succeeds.json b/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchDevices/List_of_devices_returned_when_fetch_devices_API_succeeds.json new file mode 100644 index 0000000000..1d0f571325 --- /dev/null +++ b/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchDevices/List_of_devices_returned_when_fetch_devices_API_succeeds.json @@ -0,0 +1,74 @@ +{ + "description": "List of devices returned when fetch devices API succeeds", + "preConditions": { + "amplify-configuration": "authconfiguration.json", + "state": "SignedIn_SessionEstablished.json", + "mockedResponses": [ + { + "type": "cognitoIdentityProvider", + "apiName": "listDevices", + "responseType": "success", + "response": { + "devices": [ + { + "deviceAttributes": [ + { + "name": "name", + "value": "value" + } + ], + "deviceCreateDate": { + "value": { + "seconds": 1.671733506E9, + "nanos": 9.95178E8 + } + }, + "deviceKey": "deviceKey", + "deviceLastAuthenticatedDate": { + "value": { + "seconds": 1.671733506E9, + "nanos": 9.95186E8 + } + }, + "deviceLastModifiedDate": { + "value": { + "seconds": 1.671733506E9, + "nanos": 9.95188E8 + } + } + } + ] + } + } + ] + }, + "api": { + "name": "fetchDevices", + "params": { + }, + "options": { + } + }, + "validations": [ + { + "type": "amplify", + "apiName": "fetchDevices", + "responseType": "success", + "response": [ + { + "id": "deviceKey" + } + ] + }, + { + "type": "amplify", + "apiName": "fetchDevices", + "responseType": "success", + "response": [ + { + "id": "deviceKey" + } + ] + } + ] +} \ No newline at end of file diff --git a/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchDevices/Test_that_Cognito_is_called_with_given_payload_and_returns_successful_data.json b/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchDevices/Test_that_Cognito_is_called_with_given_payload_and_returns_successful_data.json new file mode 100644 index 0000000000..1290b9a458 --- /dev/null +++ b/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchDevices/Test_that_Cognito_is_called_with_given_payload_and_returns_successful_data.json @@ -0,0 +1,64 @@ +{ + "description": "Test that Cognito is called with given payload and returns successful data", + "preConditions": { + "amplify-configuration": "authconfiguration.json", + "state": "SignedIn_SessionEstablished.json", + "mockedResponses": [ + { + "type": "cognitoIdentityProvider", + "apiName": "listDevices", + "responseType": "success", + "response": { + "devices": [ + { + "deviceAttributes": [ + { + "name": "name", + "value": "value" + } + ], + "deviceCreateDate": { + "value": { + "seconds": 1.671733506E9, + "nanos": 9.95178E8 + } + }, + "deviceKey": "deviceKey", + "deviceLastAuthenticatedDate": { + "value": { + "seconds": 1.671733506E9, + "nanos": 9.95186E8 + } + }, + "deviceLastModifiedDate": { + "value": { + "seconds": 1.671733506E9, + "nanos": 9.95188E8 + } + } + } + ] + } + } + ] + }, + "api": { + "name": "fetchDevices", + "params": { + }, + "options": { + } + }, + "validations": [ + { + "type": "amplify", + "apiName": "fetchDevices", + "responseType": "success", + "response": [ + { + "id": "deviceKey" + } + ] + } + ] +} \ No newline at end of file diff --git a/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchUserAttributes/AuthException_is_thrown_when_fetchUserAttributes_API_is_called_without_signing_in.json b/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchUserAttributes/AuthException_is_thrown_when_fetchUserAttributes_API_is_called_without_signing_in.json new file mode 100644 index 0000000000..3fae2bff15 --- /dev/null +++ b/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchUserAttributes/AuthException_is_thrown_when_fetchUserAttributes_API_is_called_without_signing_in.json @@ -0,0 +1,40 @@ +{ + "description": "AuthException is thrown when fetchUserAttributes API is called without signing in", + "preConditions": { + "amplify-configuration": "authconfiguration.json", + "state": "SignedOut_Configured.json", + "mockedResponses": [ + { + "type": "cognitoIdentityProvider", + "apiName": "getUser", + "responseType": "failure", + "response": { + "errorType": "SignedOutException", + "errorMessage": "You are currently signed out.", + "recoverySuggestion": "Please sign in and reattempt the operation.", + "cause": null + } + } + ] + }, + "api": { + "name": "fetchUserAttributes", + "params": { + }, + "options": { + } + }, + "validations": [ + { + "type": "amplify", + "apiName": "fetchUserAttributes", + "responseType": "failure", + "response": { + "errorType": "SignedOutException", + "errorMessage": "You are currently signed out.", + "recoverySuggestion": "Please sign in and reattempt the operation.", + "cause": null + } + } + ] +} \ No newline at end of file diff --git a/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchUserAttributes/List_of_user_attributes_returned_when_fetch_user_attributes_API_succeeds.json b/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchUserAttributes/List_of_user_attributes_returned_when_fetch_user_attributes_API_succeeds.json new file mode 100644 index 0000000000..f29bc29423 --- /dev/null +++ b/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchUserAttributes/List_of_user_attributes_returned_when_fetch_user_attributes_API_succeeds.json @@ -0,0 +1,73 @@ +{ + "description": "List of user attributes returned when fetch user attributes API succeeds", + "preConditions": { + "amplify-configuration": "authconfiguration.json", + "state": "SignedIn_SessionEstablished.json", + "mockedResponses": [ + { + "type": "cognitoIdentityProvider", + "apiName": "getUser", + "responseType": "success", + "response": { + "userAttributes": [ + { + "name": "email", + "value": "email@email.com" + }, + { + "name": "phone", + "value": "000-000-0000" + } + ] + } + } + ] + }, + "api": { + "name": "fetchUserAttributes", + "params": { + }, + "options": { + } + }, + "validations": [ + { + "type": "amplify", + "apiName": "fetchUserAttributes", + "responseType": "success", + "response": [ + { + "key": { + "attributeKey": "email" + }, + "value": "email@email.com" + }, + { + "key": { + "attributeKey": "phone_number" + }, + "value": "000-000-0000" + } + ] + }, + { + "type": "amplify", + "apiName": "fetchUserAttributes", + "responseType": "success", + "response": [ + { + "key": { + "attributeKey": "email" + }, + "value": "email@email.com" + }, + { + "key": { + "attributeKey": "phone_number" + }, + "value": "000-000-0000" + } + ] + } + ] +} \ No newline at end of file diff --git a/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchUserAttributes/Test_that_Cognito_is_called_with_given_payload_and_returns_successful_data.json b/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchUserAttributes/Test_that_Cognito_is_called_with_given_payload_and_returns_successful_data.json new file mode 100644 index 0000000000..0dcda9da81 --- /dev/null +++ b/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchUserAttributes/Test_that_Cognito_is_called_with_given_payload_and_returns_successful_data.json @@ -0,0 +1,54 @@ +{ + "description": "Test that Cognito is called with given payload and returns successful data", + "preConditions": { + "amplify-configuration": "authconfiguration.json", + "state": "SignedIn_SessionEstablished.json", + "mockedResponses": [ + { + "type": "cognitoIdentityProvider", + "apiName": "getUser", + "responseType": "success", + "response": { + "userAttributes": [ + { + "name": "email", + "value": "email@email.com" + }, + { + "name": "phone", + "value": "000-000-0000" + } + ] + } + } + ] + }, + "api": { + "name": "fetchUserAttributes", + "params": { + }, + "options": { + } + }, + "validations": [ + { + "type": "amplify", + "apiName": "fetchUserAttributes", + "responseType": "success", + "response": [ + { + "key": { + "attributeKey": "email" + }, + "value": "email@email.com" + }, + { + "key": { + "attributeKey": "phone_number" + }, + "value": "000-000-0000" + } + ] + } + ] +} \ No newline at end of file diff --git a/aws-auth-cognito/src/test/resources/feature-test/testsuites/forgetDevice/AuthException_is_thrown_when_forgetDevice_API_is_called_without_signing_in.json b/aws-auth-cognito/src/test/resources/feature-test/testsuites/forgetDevice/AuthException_is_thrown_when_forgetDevice_API_is_called_without_signing_in.json new file mode 100644 index 0000000000..8b9afeaafd --- /dev/null +++ b/aws-auth-cognito/src/test/resources/feature-test/testsuites/forgetDevice/AuthException_is_thrown_when_forgetDevice_API_is_called_without_signing_in.json @@ -0,0 +1,44 @@ +{ + "description": "AuthException is thrown when forgetDevice API is called without signing in", + "preConditions": { + "amplify-configuration": "authconfiguration.json", + "state": "SignedOut_Configured.json", + "mockedResponses": [ + { + "type": "cognitoIdentityProvider", + "apiName": "forgetDevice", + "responseType": "failure", + "response": { + "errorType": "SignedOutException", + "errorMessage": "You are currently signed out.", + "recoverySuggestion": "Please sign in and reattempt the operation.", + "cause": null + } + } + ] + }, + "api": { + "name": "forgetDevice", + "params": { + "device": { + "id": "id", + "name": "test" + } + }, + "options": { + } + }, + "validations": [ + { + "type": "amplify", + "apiName": "forgetDevice", + "responseType": "failure", + "response": { + "errorType": "SignedOutException", + "errorMessage": "You are currently signed out.", + "recoverySuggestion": "Please sign in and reattempt the operation.", + "cause": null + } + } + ] +} \ No newline at end of file diff --git a/aws-auth-cognito/src/test/resources/feature-test/testsuites/rememberDevice/AuthException_is_thrown_when_rememberDevice_API_is_called_without_signing_in.json b/aws-auth-cognito/src/test/resources/feature-test/testsuites/rememberDevice/AuthException_is_thrown_when_rememberDevice_API_is_called_without_signing_in.json new file mode 100644 index 0000000000..012c0b52dd --- /dev/null +++ b/aws-auth-cognito/src/test/resources/feature-test/testsuites/rememberDevice/AuthException_is_thrown_when_rememberDevice_API_is_called_without_signing_in.json @@ -0,0 +1,36 @@ +{ + "description": "AuthException is thrown when rememberDevice API is called without signing in", + "preConditions": { + "amplify-configuration": "authconfiguration.json", + "state": "SignedOut_Configured.json", + "mockedResponses": [ + { + "type": "cognitoIdentityProvider", + "apiName": "updateDeviceStatus", + "responseType": "success", + "response": { + } + } + ] + }, + "api": { + "name": "rememberDevice", + "params": { + }, + "options": { + } + }, + "validations": [ + { + "type": "amplify", + "apiName": "rememberDevice", + "responseType": "failure", + "response": { + "errorType": "SignedOutException", + "errorMessage": "You are currently signed out.", + "recoverySuggestion": "Please sign in and reattempt the operation.", + "cause": null + } + } + ] +} \ No newline at end of file diff --git a/aws-auth-cognito/src/test/resources/feature-test/testsuites/resetPassword/AuthException_is_thrown_when_forgotPassword_API_call_fails.json b/aws-auth-cognito/src/test/resources/feature-test/testsuites/resetPassword/AuthException_is_thrown_when_forgotPassword_API_call_fails.json new file mode 100644 index 0000000000..d24c0fd052 --- /dev/null +++ b/aws-auth-cognito/src/test/resources/feature-test/testsuites/resetPassword/AuthException_is_thrown_when_forgotPassword_API_call_fails.json @@ -0,0 +1,42 @@ +{ + "description": "AuthException is thrown when forgotPassword API call fails", + "preConditions": { + "amplify-configuration": "authconfiguration.json", + "state": "SignedOut_Configured.json", + "mockedResponses": [ + { + "type": "cognitoIdentityProvider", + "apiName": "forgotPassword", + "responseType": "failure", + "response": { + "errorType": "NotAuthorizedException", + "errorMessage": "Cognito error message" + } + } + ] + }, + "api": { + "name": "resetPassword", + "params": { + "username": "someUsername" + }, + "options": { + } + }, + "validations": [ + { + "type": "amplify", + "apiName": "resetPassword", + "responseType": "failure", + "response": { + "errorType": "NotAuthorizedException", + "errorMessage": "Failed since user is not authorized.", + "recoverySuggestion": "Check whether the given values are correct and the user is authorized to perform the operation.", + "cause": { + "errorType": "NotAuthorizedException", + "errorMessage": "Cognito error message" + } + } + } + ] +} \ No newline at end of file From 4cdedf69d7a0e09115cb96777b55af7e8b9399f6 Mon Sep 17 00:00:00 2001 From: Banji Jolaoso Date: Thu, 22 Dec 2022 11:00:53 -0800 Subject: [PATCH 32/36] added missing json files --- .../configuration/authconfiguration.json | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 aws-auth-cognito/src/test/resources/feature-test/configuration/authconfiguration.json diff --git a/aws-auth-cognito/src/test/resources/feature-test/configuration/authconfiguration.json b/aws-auth-cognito/src/test/resources/feature-test/configuration/authconfiguration.json new file mode 100644 index 0000000000..cab6a45e13 --- /dev/null +++ b/aws-auth-cognito/src/test/resources/feature-test/configuration/authconfiguration.json @@ -0,0 +1,36 @@ +{ + "UserAgent": "aws-amplify-cli/2.0", + "Version": "1.0", + "auth": { + "plugins": { + "awsCognitoAuthPlugin": { + "UserAgent": "aws-amplify-cli/0.1.0", + "Version": "0.1.0", + "IdentityManager": { + "Default": {} + }, + "CredentialsProvider": { + "CognitoIdentity": { + "Default": { + "PoolId": "us-east-1_testIdentityPoolId", + "Region": "us-east-1" + } + } + }, + "CognitoUserPool": { + "Default": { + "PoolId": "us-east-1_testUserPoolId", + "AppClientId": "testAppClientId", + "AppClientSecret": "testAppClientSecret", + "Region": "us-east-1" + } + }, + "Auth": { + "Default": { + "authenticationFlowType": "USER_SRP_AUTH" + } + } + } + } + } +} \ No newline at end of file From 55ab30df8c07d71d6832c631e0926d9c0db4ed15 Mon Sep 17 00:00:00 2001 From: Banji Jolaoso Date: Thu, 22 Dec 2022 11:04:51 -0800 Subject: [PATCH 33/36] added missing json files --- .../states/CustomSignIn_SigningIn.json | 26 ++++++++++++ .../SignedIn_UserPoolSessionEstablished.json | 42 +++++++++++++++++++ .../SignedOut_IdentityPoolConfigured.json | 34 +++++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 aws-auth-cognito/src/test/resources/feature-test/states/CustomSignIn_SigningIn.json create mode 100644 aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_UserPoolSessionEstablished.json create mode 100644 aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_IdentityPoolConfigured.json diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/CustomSignIn_SigningIn.json b/aws-auth-cognito/src/test/resources/feature-test/states/CustomSignIn_SigningIn.json new file mode 100644 index 0000000000..e69e8f6662 --- /dev/null +++ b/aws-auth-cognito/src/test/resources/feature-test/states/CustomSignIn_SigningIn.json @@ -0,0 +1,26 @@ +{ + "type": "AuthState.Configured", + "AuthenticationState": { + "type": "AuthenticationState.SigningIn", + "SignInState": { + "type": "SignInState.ResolvingChallenge", + "SignInChallengeState": { + "type": "SignInChallengeState.WaitingForAnswer", + "authChallenge": { + "challengeName": "CUSTOM_CHALLENGE", + "username": "username", + "session": null, + "parameters": { + "SALT": "abc", + "SECRET_BLOCK": "secretBlock", + "SRP_B": "def", + "USERNAME": "username" + } + } + } + } + }, + "AuthorizationState": { + "type": "AuthorizationState.SigningIn" + } +} diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_UserPoolSessionEstablished.json b/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_UserPoolSessionEstablished.json new file mode 100644 index 0000000000..93bbd31c57 --- /dev/null +++ b/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_UserPoolSessionEstablished.json @@ -0,0 +1,42 @@ +{ + "type": "AuthState.Configured", + "AuthenticationState": { + "type": "AuthenticationState.SignedIn", + "signedInData": { + "userId": "userId", + "username": "username", + "signedInDate": 0, + "signInMethod": { + "type": "SignInMethod.ApiBased", + "authType": "USER_SRP_AUTH" + }, + "cognitoUserPoolTokens": { + "idToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "expiration": 300 + } + } + }, + "AuthorizationState": { + "type": "AuthorizationState.SessionEstablished", + "amplifyCredential": { + "type": "userPool", + "signedInData": { + "userId": "userId", + "username": "username", + "signedInDate": 0, + "signInMethod": { + "type": "SignInMethod.ApiBased", + "authType": "USER_SRP_AUTH" + }, + "cognitoUserPoolTokens": { + "idToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "expiration": 300 + } + } + } + } +} \ No newline at end of file diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_IdentityPoolConfigured.json b/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_IdentityPoolConfigured.json new file mode 100644 index 0000000000..028d2d4bd1 --- /dev/null +++ b/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_IdentityPoolConfigured.json @@ -0,0 +1,34 @@ +{ + "type": "AuthState.Configured", + "AuthenticationState": { + "type": "AuthenticationState.SignedIn", + "signedInData": { + "userId": "userId", + "username": "username", + "signedInDate": 0, + "signInMethod": { + "type": "SignInMethod.ApiBased", + "authType": "USER_SRP_AUTH" + }, + "cognitoUserPoolTokens": { + "idToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "expiration": 300 + } + } + }, + "AuthorizationState": { + "type": "AuthorizationState.SessionEstablished", + "amplifyCredential": { + "type": "identityPool", + "identityId": "someIdentityId", + "credentials": { + "accessKeyId": "someAccessKey", + "secretAccessKey": "someSecretKey", + "sessionToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "expiration": 2342134 + } + } + } +} \ No newline at end of file From a951cb3c50f48ddc93416a1c9b5267ebf616c054 Mon Sep 17 00:00:00 2001 From: Banji Jolaoso Date: Thu, 5 Jan 2023 09:39:01 -0800 Subject: [PATCH 34/36] empty From b93fa7c544076ed076d7666880a77f6b4ed051b5 Mon Sep 17 00:00:00 2001 From: Banji Jolaoso Date: Mon, 9 Jan 2023 07:41:36 -0800 Subject: [PATCH 35/36] empty commit From 4272a445e25077f3a79a8cd122ae6c55eb2541a3 Mon Sep 17 00:00:00 2001 From: Banji Jolaoso Date: Tue, 31 Jan 2023 16:26:10 -0800 Subject: [PATCH 36/36] Updated year in new files --- .../testcasegenerators/FetchAuthSessionTestCaseGenerator.kt | 2 +- .../testcasegenerators/FetchDevicesTestCaseGenerator.kt | 2 +- .../testcasegenerators/FetchUserAttributesTestCaseGenerator.kt | 2 +- .../testcasegenerators/ForgetDeviceTestCaseGenerator.kt | 2 +- .../testcasegenerators/GetCurrentUserTestCaseGenerator.kt | 2 +- .../testcasegenerators/RememberDeviceTestCaseGenerator.kt | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt index 6b22b2051d..b825671f42 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchDevicesTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchDevicesTestCaseGenerator.kt index d42ad08221..f87c12db89 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchDevicesTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchDevicesTestCaseGenerator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchUserAttributesTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchUserAttributesTestCaseGenerator.kt index 9c8ab072fc..1688bf9b50 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchUserAttributesTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchUserAttributesTestCaseGenerator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ForgetDeviceTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ForgetDeviceTestCaseGenerator.kt index 04aa7f81c3..52151d2322 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ForgetDeviceTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/ForgetDeviceTestCaseGenerator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/GetCurrentUserTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/GetCurrentUserTestCaseGenerator.kt index df61d83594..36c8dfbb12 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/GetCurrentUserTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/GetCurrentUserTestCaseGenerator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/RememberDeviceTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/RememberDeviceTestCaseGenerator.kt index df8870dd8f..377d787195 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/RememberDeviceTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/RememberDeviceTestCaseGenerator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License.