From ca01a559b34d4b039d742d3651999d40bfa56c83 Mon Sep 17 00:00:00 2001 From: tjroach Date: Tue, 2 Jul 2024 13:42:18 -0400 Subject: [PATCH 1/5] Remove ignored tests --- .../api/aws/RestApiInstrumentationTest.java | 50 -- .../api/aws/AWSApiPluginTest.java | 51 -- .../auth/cognito/AuthCanaryTest.kt | 101 --- .../auth/cognito/AuthCanaryTestGen2.kt | 101 --- ...ialStoreStateMachineInstrumentationTest.kt | 62 -- .../cognito/RealAWSCognitoAuthPluginTest.kt | 31 - .../data/AWSCognitoAuthCredentialStoreTest.kt | 25 - .../statemachine/StateMachineTests.kt | 24 - .../BasicCloudSyncInstrumentationTest.java | 63 -- ...ultiAuthSyncEngineInstrumentationTest.java | 56 -- ...thSyncEngineNoAuthInstrumentationTest.java | 16 - .../datastore/AWSDataStorePluginTest.java | 621 ------------------ .../datastore/MutationProcessorRetryTest.java | 260 -------- .../aws/http/LivenessWebSocketTest.kt | 26 - .../pinpoint/NotificationsCanaryTest.kt | 165 ----- 15 files changed, 1652 deletions(-) delete mode 100644 aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/CredentialStoreStateMachineInstrumentationTest.kt delete mode 100644 aws-datastore/src/test/java/com/amplifyframework/datastore/AWSDataStorePluginTest.java delete mode 100644 aws-datastore/src/test/java/com/amplifyframework/datastore/MutationProcessorRetryTest.java delete mode 100644 aws-push-notifications-pinpoint/src/androidTest/java/com/amplifyframework/pushnotifications/pinpoint/NotificationsCanaryTest.kt diff --git a/aws-api/src/androidTest/java/com/amplifyframework/api/aws/RestApiInstrumentationTest.java b/aws-api/src/androidTest/java/com/amplifyframework/api/aws/RestApiInstrumentationTest.java index b58c866d34..4481a6cd15 100644 --- a/aws-api/src/androidTest/java/com/amplifyframework/api/aws/RestApiInstrumentationTest.java +++ b/aws-api/src/androidTest/java/com/amplifyframework/api/aws/RestApiInstrumentationTest.java @@ -31,14 +31,11 @@ import org.json.JSONObject; import org.junit.AfterClass; import org.junit.BeforeClass; -import org.junit.Ignore; import org.junit.Test; -import java.util.Collections; import static androidx.test.core.app.ApplicationProvider.getApplicationContext; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -134,53 +131,6 @@ public void getRequestWithApiKey() throws JSONException, ApiException { ); } - /** - * Test whether we can make api Rest call in IAM as auth type. - * @throws ApiException On failure to obtain a valid response from API endpoint - */ - @Test - @Ignore("Relies on an AWS account which is no longer active. Resources need to be regenerated.") - public void getRequestWithIAM() throws ApiException { - final RestOptions options = RestOptions.builder() - .addPath("/items") - .addQueryParameters(Collections.singletonMap("key", "value")) - .build(); - final RestResponse response = api.get("iamAuthApi", options); - assertNotNull("Should return non-null data", response.getData()); - assertTrue("Response should be successful", response.getCode().isSuccessful()); - } - - /** - * Test whether we can make POST request with empty body and IAM as auth type. - * @throws ApiException On failure to obtain a valid response from API endpoint - */ - @Test - @Ignore("fix in dev-preview") - public void postRequestEmptyBodyWithIAM() throws ApiException { - final RestOptions options = RestOptions.builder() - .addPath("/items") - .addBody("".getBytes()) - .build(); - final RestResponse response = api.post("iamAuthApi", options); - assertNotNull("Should return non-null data", response.getData()); - assertTrue("Response should be successful", response.getCode().isSuccessful()); - } - - /** - * Test whether we can get failed response for access denied. - * @throws ApiException On failure to obtain a valid response from API endpoint - */ - @Test - @Ignore("Relies on an AWS account which is no longer active. Resources need to be regenerated.") - public void getRequestWithIAMFailedAccess() throws ApiException { - final RestOptions options = RestOptions.builder() - .addPath("/invalidPath") - .build(); - final RestResponse response = api.get("iamAuthApi", options); - assertNotNull("Should return non-null data", response.getData()); - assertFalse("Response should be unsuccessful", response.getCode().isSuccessful()); - } - /** * Reset all the static fields. */ diff --git a/aws-api/src/test/java/com/amplifyframework/api/aws/AWSApiPluginTest.java b/aws-api/src/test/java/com/amplifyframework/api/aws/AWSApiPluginTest.java index c1fed48e5e..f2e3447121 100644 --- a/aws-api/src/test/java/com/amplifyframework/api/aws/AWSApiPluginTest.java +++ b/aws-api/src/test/java/com/amplifyframework/api/aws/AWSApiPluginTest.java @@ -21,8 +21,6 @@ import com.amplifyframework.api.ApiException; import com.amplifyframework.api.aws.auth.DummyCredentialsProvider; import com.amplifyframework.api.aws.sigv4.CognitoUserPoolsAuthProvider; -import com.amplifyframework.api.events.ApiChannelEventName; -import com.amplifyframework.api.events.ApiEndpointStatusChangeEvent; import com.amplifyframework.api.graphql.GraphQLRequest; import com.amplifyframework.api.graphql.GraphQLResponse; import com.amplifyframework.api.graphql.PaginatedResult; @@ -31,11 +29,8 @@ import com.amplifyframework.api.graphql.model.ModelPagination; import com.amplifyframework.api.graphql.model.ModelQuery; import com.amplifyframework.core.Consumer; -import com.amplifyframework.hub.HubChannel; -import com.amplifyframework.hub.HubEvent; import com.amplifyframework.testmodels.commentsblog.BlogOwner; import com.amplifyframework.testutils.Await; -import com.amplifyframework.testutils.HubAccumulator; import com.amplifyframework.testutils.Latch; import com.amplifyframework.testutils.Resources; import com.amplifyframework.testutils.random.RandomString; @@ -45,7 +40,6 @@ import org.json.JSONObject; import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @@ -233,51 +227,6 @@ public void graphQlPaginatedQueryRendersExpectedResponse() throws ApiException { assertNotNull(actualResponse.getData().getRequestForNextResult()); } - /** - * It should be possible to perform a successful call to - * {@link AWSApiPlugin#mutate(GraphQLRequest, Consumer, Consumer)}. - * When the server returns a valid response, then the mutate methods should - * emit content via their value consumer. - * @throws ApiException If call to mutate(...) itself emits such an exception - * @throws JSONException On failure to arrange response JSON - */ - @Test - @Ignore("fix") - public void graphQlMutationGetsResponse() throws JSONException, ApiException { - HubAccumulator networkStatusObserver = - HubAccumulator.create(HubChannel.API, ApiChannelEventName.API_ENDPOINT_STATUS_CHANGED, 1) - .start(); - // Arrange a response from the "server" - String expectedName = RandomString.string(); - webServer.enqueue(new MockResponse().setBody(new JSONObject() - .put("data", new JSONObject() - .put("createBlogOwner", new JSONObject() - .put("name", expectedName) - ) - ) - .toString() - )); - - // Try to perform a mutation. - BlogOwner tony = BlogOwner.builder() - .name(expectedName) - .build(); - GraphQLResponse actualResponse = - Await., ApiException>result(((onResult, onError) -> - plugin.mutate(ModelMutation.create(tony), onResult, onError) - )); - - // Assert that the expected response was received - assertEquals(expectedName, actualResponse.getData().getName()); - - // Verify that the expected hub event fired. - HubEvent event = networkStatusObserver.awaitFirst(); - assertNotNull(event); - assertTrue(event.getData() instanceof ApiEndpointStatusChangeEvent); - ApiEndpointStatusChangeEvent eventData = (ApiEndpointStatusChangeEvent) event.getData(); - assertEquals(ApiEndpointStatusChangeEvent.ApiEndpointStatus.REACHABLE, eventData.getCurrentStatus()); - } - /** * When the server returns a client error code in response to calling * {@link AWSApiPlugin#mutate(GraphQLRequest, Consumer, Consumer)}. diff --git a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AuthCanaryTest.kt b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AuthCanaryTest.kt index f576a6d11d..2b1c50474c 100644 --- a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AuthCanaryTest.kt +++ b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AuthCanaryTest.kt @@ -21,7 +21,6 @@ import androidx.test.core.app.ApplicationProvider import com.amplifyframework.AmplifyException import com.amplifyframework.api.aws.AWSApiPlugin import com.amplifyframework.api.rest.RestOptions -import com.amplifyframework.auth.AuthProvider import com.amplifyframework.auth.AuthUserAttribute import com.amplifyframework.auth.AuthUserAttributeKey import com.amplifyframework.auth.cognito.options.AWSCognitoAuthSignInOptions @@ -44,7 +43,6 @@ import org.junit.Assert.assertTrue import org.junit.Assert.fail import org.junit.Before import org.junit.BeforeClass -import org.junit.Ignore import org.junit.Test class AuthCanaryTest { @@ -137,19 +135,6 @@ class AuthCanaryTest { assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) } - @Test - @Ignore("Sending sign up confirmation code is disabled in the user pool.") - fun resendSignUpCode() { - signUpUser(tempUsername, tempPassword) - val latch = CountDownLatch(1) - Amplify.Auth.resendSignUpCode( - tempUsername, - { latch.countDown() }, - { fail("Failed to confirm sign up: $it") } - ) - assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) - } - @Test fun signIn() { val latch = CountDownLatch(1) @@ -170,14 +155,6 @@ class AuthCanaryTest { assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) } - @Test - @Ignore("Test will require UI. Implementation is TODO.") - fun signInWithWebUI() { } - - @Test - @Ignore("Test will require UI. Implementation is TODO.") - fun signInWithSocialWebUi() { } - // Test requires confirmation code, testing onError call @Test fun confirmSignIn() { @@ -214,30 +191,6 @@ class AuthCanaryTest { assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) } - @Test - @Ignore("Test fails with missing device key error. Ignoring test pending investigation.") - fun rememberDevice() { - signInUser(username, password) - val latch = CountDownLatch(1) - Amplify.Auth.rememberDevice( - { latch.countDown() }, - { fail("Remember device failed: $it") } - ) - assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) - } - - @Test - @Ignore("Test fails with missing device key error. Ignoring test pending investigation.") - fun forgetDevice() { - signInUser(username, password) - val latch = CountDownLatch(1) - Amplify.Auth.forgetDevice( - { latch.countDown() }, - { fail("Forget device failed with error: $it") } - ) - assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) - } - @Test fun fetchDevices() { signInUser(username, password) @@ -249,21 +202,6 @@ class AuthCanaryTest { assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) } - @Test - @Ignore("Test requires a temporary user with a confirmed email.") - fun resetPassword() { - signUpUser(tempUsername, tempPassword) - confirmTemporaryUserSignUp(tempUsername) - signInUser(tempUsername, tempPassword) - val latch = CountDownLatch(1) - Amplify.Auth.resetPassword( - tempUsername, - { latch.countDown() }, - { fail("Reset password failed: $it") } - ) - assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) - } - // Test requires confirmation code, testing onError call @Test fun confirmResetPassword() { @@ -345,19 +283,6 @@ class AuthCanaryTest { assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) } - @Test - @Ignore("Test fails when run too frequently due to resend confirmation code limit exceeded.") - fun resendUserAttributeConfirmationCode() { - signInUser(username, password) - val latch = CountDownLatch(1) - Amplify.Auth.resendUserAttributeConfirmationCode( - AuthUserAttributeKey.email(), - { latch.countDown() }, - { fail("Failed to resend code: $it") } - ) - assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) - } - @Test fun getCurrentUser() { signInUser(username, password) @@ -438,32 +363,6 @@ class AuthCanaryTest { assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) } - @Test - @Ignore("OAuth flows not set up.") - fun testFederateToIdentityPool() { - signInUser(username, password) - val latch = CountDownLatch(1) - auth.federateToIdentityPool( - "YOUR_TOKEN", - AuthProvider.facebook(), - { latch.countDown() }, - { fail("Failed to federate to Identity Pool: $it") } - ) - assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) - } - - @Test - @Ignore("OAuth flows not set up.") - fun testClearFederateToIdentityPool() { - signInUser(username, password) - val latch = CountDownLatch(1) - auth.clearFederationToIdentityPool( - { latch.countDown() }, - { fail("Failed to clear federation: $it") } - ) - assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) - } - private fun signUpUser(user: String, pass: String) { val latch = CountDownLatch(1) val options = AuthSignUpOptions.builder() diff --git a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AuthCanaryTestGen2.kt b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AuthCanaryTestGen2.kt index e7d59cc387..28544d96f0 100644 --- a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AuthCanaryTestGen2.kt +++ b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AuthCanaryTestGen2.kt @@ -21,7 +21,6 @@ import androidx.test.core.app.ApplicationProvider import com.amplifyframework.AmplifyException import com.amplifyframework.api.aws.AWSApiPlugin import com.amplifyframework.api.rest.RestOptions -import com.amplifyframework.auth.AuthProvider import com.amplifyframework.auth.AuthUserAttribute import com.amplifyframework.auth.AuthUserAttributeKey import com.amplifyframework.auth.cognito.options.AWSCognitoAuthSignInOptions @@ -47,7 +46,6 @@ import org.junit.Assert.assertTrue import org.junit.Assert.fail import org.junit.Before import org.junit.BeforeClass -import org.junit.Ignore import org.junit.Test class AuthCanaryTestGen2 { @@ -147,19 +145,6 @@ class AuthCanaryTestGen2 { assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) } - @Test - @Ignore("Sending sign up confirmation code is disabled in the user pool.") - fun resendSignUpCode() { - signUpUser(tempUsername, tempPassword) - val latch = CountDownLatch(1) - Amplify.Auth.resendSignUpCode( - tempUsername, - { latch.countDown() }, - { fail("Failed to confirm sign up: $it") } - ) - assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) - } - @Test fun signIn() { val latch = CountDownLatch(1) @@ -180,14 +165,6 @@ class AuthCanaryTestGen2 { assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) } - @Test - @Ignore("Test will require UI. Implementation is TODO.") - fun signInWithWebUI() { } - - @Test - @Ignore("Test will require UI. Implementation is TODO.") - fun signInWithSocialWebUi() { } - // Test requires confirmation code, testing onError call @Test fun confirmSignIn() { @@ -224,30 +201,6 @@ class AuthCanaryTestGen2 { assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) } - @Test - @Ignore("Test fails with missing device key error. Ignoring test pending investigation.") - fun rememberDevice() { - signInUser(username, password) - val latch = CountDownLatch(1) - Amplify.Auth.rememberDevice( - { latch.countDown() }, - { fail("Remember device failed: $it") } - ) - assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) - } - - @Test - @Ignore("Test fails with missing device key error. Ignoring test pending investigation.") - fun forgetDevice() { - signInUser(username, password) - val latch = CountDownLatch(1) - Amplify.Auth.forgetDevice( - { latch.countDown() }, - { fail("Forget device failed with error: $it") } - ) - assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) - } - @Test fun fetchDevices() { signInUser(username, password) @@ -259,21 +212,6 @@ class AuthCanaryTestGen2 { assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) } - @Test - @Ignore("Test requires a temporary user with a confirmed email.") - fun resetPassword() { - signUpUser(tempUsername, tempPassword) - confirmTemporaryUserSignUp(tempUsername) - signInUser(tempUsername, tempPassword) - val latch = CountDownLatch(1) - Amplify.Auth.resetPassword( - tempUsername, - { latch.countDown() }, - { fail("Reset password failed: $it") } - ) - assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) - } - // Test requires confirmation code, testing onError call @Test fun confirmResetPassword() { @@ -355,19 +293,6 @@ class AuthCanaryTestGen2 { assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) } - @Test - @Ignore("Test fails when run too frequently due to resend confirmation code limit exceeded.") - fun resendUserAttributeConfirmationCode() { - signInUser(username, password) - val latch = CountDownLatch(1) - Amplify.Auth.resendUserAttributeConfirmationCode( - AuthUserAttributeKey.email(), - { latch.countDown() }, - { fail("Failed to resend code: $it") } - ) - assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) - } - @Test fun getCurrentUser() { signInUser(username, password) @@ -448,32 +373,6 @@ class AuthCanaryTestGen2 { assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) } - @Test - @Ignore("OAuth flows not set up.") - fun testFederateToIdentityPool() { - signInUser(username, password) - val latch = CountDownLatch(1) - auth.federateToIdentityPool( - "YOUR_TOKEN", - AuthProvider.facebook(), - { latch.countDown() }, - { fail("Failed to federate to Identity Pool: $it") } - ) - assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) - } - - @Test - @Ignore("OAuth flows not set up.") - fun testClearFederateToIdentityPool() { - signInUser(username, password) - val latch = CountDownLatch(1) - auth.clearFederationToIdentityPool( - { latch.countDown() }, - { fail("Failed to clear federation: $it") } - ) - assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) - } - private fun signUpUser(user: String, pass: String) { val latch = CountDownLatch(1) val options = AuthSignUpOptions.builder() diff --git a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/CredentialStoreStateMachineInstrumentationTest.kt b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/CredentialStoreStateMachineInstrumentationTest.kt deleted file mode 100644 index bf0b73ad4a..0000000000 --- a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/CredentialStoreStateMachineInstrumentationTest.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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 - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.platform.app.InstrumentationRegistry -import com.amplifyframework.auth.cognito.data.AWSCognitoAuthCredentialStore -import com.amplifyframework.auth.cognito.testutils.AuthConfigurationProvider -import com.amplifyframework.auth.cognito.testutils.CredentialStoreUtil -import com.google.gson.Gson -import org.json.JSONObject -import org.junit.Before -import org.junit.Ignore -import org.junit.Test -import org.junit.runner.RunWith - -@Ignore("This class only has 1 test that was ignored hence ignoring the entire class") -@RunWith(AndroidJUnit4::class) -class CredentialStoreStateMachineInstrumentationTest { - private val context = InstrumentationRegistry.getInstrumentation().context - - private val configuration = AuthConfigurationProvider.getAuthConfigurationObject() - private val userPoolId = configuration.userPool.userPool.PoolId - private val identityPoolId = configuration.credentials.cognitoIdentity.identityData.PoolId - private val userPoolAppClientId = configuration.userPool.userPool.AppClientId - - private val credential = CredentialStoreUtil.getDefaultCredential() - - @Before - fun setup() { - CredentialStoreUtil.setupLegacyStore(context, userPoolAppClientId, userPoolId, identityPoolId) - } - - private val authConfigJson = JSONObject(Gson().toJson(configuration)) - - @Ignore("Test needs to be changed as credential store is not publicly accessible anymore") - @Test - fun test_CredentialStore_Migration_Succeeds_On_Plugin_Configuration() { - AWSCognitoAuthPlugin().configure(authConfigJson, context) - - val credentialStore = AWSCognitoAuthCredentialStore( - context, - AuthConfiguration.fromJson(authConfigJson) - ) - val creds = credentialStore.retrieveCredential() - - assert(creds == credential) - } -} 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 291c2db0b9..87c1381965 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 @@ -65,7 +65,6 @@ import com.amplifyframework.auth.cognito.options.AWSCognitoAuthUpdateUserAttribu import com.amplifyframework.auth.cognito.options.AWSCognitoAuthUpdateUserAttributesOptions import com.amplifyframework.auth.cognito.options.AWSCognitoAuthVerifyTOTPSetupOptions import com.amplifyframework.auth.cognito.options.AuthFlowType -import com.amplifyframework.auth.cognito.usecases.ResetPasswordUseCase import com.amplifyframework.auth.exceptions.InvalidStateException import com.amplifyframework.auth.exceptions.SignedOutException import com.amplifyframework.auth.options.AuthConfirmResetPasswordOptions @@ -96,13 +95,11 @@ import com.amplifyframework.statemachine.codegen.states.AuthenticationState import com.amplifyframework.statemachine.codegen.states.AuthorizationState import featureTest.utilities.APICaptorFactory.Companion.onError import io.mockk.coEvery -import io.mockk.coJustRun import io.mockk.coVerify import io.mockk.every import io.mockk.invoke import io.mockk.justRun import io.mockk.mockk -import io.mockk.mockkConstructor import io.mockk.mockkObject import io.mockk.mockkStatic import io.mockk.slot @@ -117,7 +114,6 @@ import kotlin.test.assertNull import kotlin.test.assertTrue import org.json.JSONObject import org.junit.Before -import org.junit.Ignore import org.junit.Test class RealAWSCognitoAuthPluginTest { @@ -412,33 +408,6 @@ class RealAWSCognitoAuthPluginTest { assertEquals(expectedAuthError.toString(), errorCaptor.captured.toString()) } - @Ignore("Test fails in build server") - @Test - fun `reset password executes ResetPasswordUseCase if required params are set`() { - // GIVEN - val onSuccess = mockk>() - val onError = mockk>() - val options = mockk() - val username = "user" - val pinpointAppId = "abc" - - mockkConstructor(ResetPasswordUseCase::class) - - every { authService.cognitoIdentityProviderClient } returns mockk() - every { authConfiguration.userPool } returns UserPoolConfiguration.invoke { appClientId = "app Client Id" } - coJustRun { - anyConstructed().execute(username, options, any(), pinpointAppId, onSuccess, onError) - } - - // WHEN - plugin.resetPassword(username, options, onSuccess, onError) - - // THEN - coVerify { - anyConstructed().execute(username, options, any(), pinpointAppId, onSuccess, onError) - } - } - @Test fun `fetch user attributes with success`() { // GIVEN diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/data/AWSCognitoAuthCredentialStoreTest.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/data/AWSCognitoAuthCredentialStoreTest.kt index 8dcec34356..d1d6e19ba6 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/data/AWSCognitoAuthCredentialStoreTest.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/data/AWSCognitoAuthCredentialStoreTest.kt @@ -31,7 +31,6 @@ import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import org.junit.Assert import org.junit.Before -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock @@ -146,30 +145,6 @@ class AWSCognitoAuthCredentialStoreTest { assertEquals(AmplifyCredential.Empty, store.retrieveCredential()) } - @Test - @Ignore("fix as per new store format") - fun testCognitoUserPoolTokensIsReturnedAsNullIfAllItsFieldsAreNull() { - val credential = getCredential() - - setStoreCredentials(credential) - - val actual = persistentStore.retrieveCredential() - - Assert.assertEquals(AmplifyCredential.Empty, actual) - } - - @Test - @Ignore("fix as per new store format") - fun testAWSCredentialsIsReturnedAsNullIfAllItsFieldsAreNull() { - val credential = getCredential() - - setStoreCredentials(credential) - - val actual = persistentStore.retrieveCredential() - - Assert.assertEquals(AmplifyCredential.Empty, actual) - } - private fun setStoreCredentials(credential: AmplifyCredential) { Mockito.`when`(mockKeyValue.get(Mockito.anyString())).thenReturn(serialized(credential)) diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/statemachine/StateMachineTests.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/statemachine/StateMachineTests.kt index 1d56e544cc..5afb7a2169 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/statemachine/StateMachineTests.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/statemachine/StateMachineTests.kt @@ -21,12 +21,9 @@ import com.amplifyframework.statemachine.state.Counter import com.amplifyframework.statemachine.state.CounterStateMachine import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit -import kotlin.test.Ignore import kotlin.test.assertEquals import kotlin.test.assertTrue import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch import kotlinx.coroutines.newSingleThreadContext import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.setMain @@ -74,27 +71,6 @@ class StateMachineTests { assertTrue { testLatch.await(5, TimeUnit.SECONDS) } } - @Test - @Ignore("Fails randomly, needs fixing") - fun testConcurrentReceive() { - val testMachine = CounterStateMachine() - val increment = Counter.Event("increment", Counter.Event.EventType.Increment) - val decrement = Counter.Event("decrement", Counter.Event.EventType.Decrement) - (1..1000) - .map { i -> - GlobalScope.launch { - // TODO: need atomic updates - if (i % 2 == 0) testMachine.send(increment) else testMachine.send(decrement) - } - } - val testLatch = CountDownLatch(1) - testMachine.getCurrentState { - assertEquals(0, it.value) - testLatch.countDown() - } - assertTrue { testLatch.await(5, TimeUnit.SECONDS) } - } - @Test fun testConcurrentReceiveAndRead() { val testLatch = CountDownLatch(10) diff --git a/aws-datastore/src/androidTest/java/com/amplifyframework/datastore/BasicCloudSyncInstrumentationTest.java b/aws-datastore/src/androidTest/java/com/amplifyframework/datastore/BasicCloudSyncInstrumentationTest.java index 8db39009c3..e6e123acdd 100644 --- a/aws-datastore/src/androidTest/java/com/amplifyframework/datastore/BasicCloudSyncInstrumentationTest.java +++ b/aws-datastore/src/androidTest/java/com/amplifyframework/datastore/BasicCloudSyncInstrumentationTest.java @@ -53,7 +53,6 @@ import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; -import org.junit.Ignore; import org.junit.Test; import java.util.ArrayList; @@ -386,68 +385,6 @@ public void createWaitThenUpdateDifferentField() throws DataStoreException, ApiE ModelAssert.assertEqualsIgnoringTimestamps(updatedOwner, remoteOwner); } - /** - * Verify that updating a different field of the last created shortly after creating two items succeeds. - * @throws DataStoreException On failure to save or query items from DataStore. - * @throws ApiException On failure to query the API. - */ - @Ignore("Test passes locally but fails inconsistently on CI. Ignoring the test pending further investigation.") - @Test - public void create1ThenCreate2ThenUpdate2() throws DataStoreException, ApiException { - // Setup - BlogOwner owner = BlogOwner.builder() - .name("Jean") - .build(); - BlogOwner anotherOwner = BlogOwner.builder() - .name("Richard") - .build(); - BlogOwner updatedOwner = anotherOwner.copyOfBuilder() - .wea("pon") - .build(); - String modelName = BlogOwner.class.getSimpleName(); - - // Expect two mutations to be published to AppSync. - HubAccumulator accumulator = - HubAccumulator.create(HubChannel.DATASTORE, publicationOf(modelName, anotherOwner.getId()), 2) - .start(); - - // Create an item, then update it with different field and save it again. - dataStore.save(owner); - dataStore.save(anotherOwner); - dataStore.save(updatedOwner); - - // Verify that 2 mutations were published. - accumulator.await(TIMEOUT_SECONDS, TimeUnit.SECONDS); - - // Verify that the updatedOwner is saved in the DataStore. - BlogOwner localOwner = dataStore.get(BlogOwner.class, anotherOwner.getId()); - ModelAssert.assertEqualsIgnoringTimestamps(updatedOwner, localOwner); - - // Verify that the updatedOwner is saved on the backend. - BlogOwner remoteOwner = api.get(BlogOwner.class, anotherOwner.getId()); - ModelAssert.assertEqualsIgnoringTimestamps(updatedOwner, remoteOwner); - } - - /** - * Verify that creating a new item, then immediately deleting succeeds. - * @throws DataStoreException On failure to save or query items from DataStore. - * @throws ApiException On failure to query the API. - */ - @Test - @Ignore("Inconsistent Test. Needs investigation") - public void createThenDelete() throws DataStoreException, ApiException { - // Setup - BlogOwner owner = BlogOwner.builder() - .name("Jean") - .build(); - - dataStore.save(owner); - dataStore.delete(owner); - - // Verify that the owner is deleted from the local data store. - assertThrows(NoSuchElementException.class, () -> dataStore.get(BlogOwner.class, owner.getId())); - } - /** * Verify that creating a new item, waiting for it to post, then immediately delete succeeds. * @throws DataStoreException On failure to save or query items from DataStore. diff --git a/aws-datastore/src/androidTest/java/com/amplifyframework/datastore/MultiAuthSyncEngineInstrumentationTest.java b/aws-datastore/src/androidTest/java/com/amplifyframework/datastore/MultiAuthSyncEngineInstrumentationTest.java index ee9b392773..8616c22534 100644 --- a/aws-datastore/src/androidTest/java/com/amplifyframework/datastore/MultiAuthSyncEngineInstrumentationTest.java +++ b/aws-datastore/src/androidTest/java/com/amplifyframework/datastore/MultiAuthSyncEngineInstrumentationTest.java @@ -43,7 +43,6 @@ import com.amplifyframework.datastore.storage.sqlite.TestStorageAdapter; import com.amplifyframework.hub.HubChannel; import com.amplifyframework.logging.Logger; -import com.amplifyframework.testmodels.commentsblog.Author; import com.amplifyframework.testmodels.multiauth.GroupPrivatePublicUPIAMAPIPost; import com.amplifyframework.testmodels.multiauth.GroupPrivateUPIAMPost; import com.amplifyframework.testmodels.multiauth.GroupPublicUPAPIPost; @@ -82,7 +81,6 @@ import org.json.JSONObject; import org.junit.AfterClass; import org.junit.BeforeClass; -import org.junit.Ignore; import org.junit.Test; import java.io.IOException; @@ -144,24 +142,6 @@ public static void setup() throws AmplifyException, InterruptedException { new AWSCognitoAuthPlugin()); } - /** - * Class name: Author. - * Signed in with user pools: false. - * Signed in with OIDC: false. - * Expected result: AuthorizationType.API_KEY. - * @throws AmplifyException Not expected. - * @throws IOException Not expected. - */ - @Test - @Ignore("fix on dev-preview") - public void testAuthorAnonymous() throws IOException, AmplifyException { - verifyScenario(Author.class, - false, - false, - AuthorizationType.API_KEY - ); - } - /** * Class name: OwnerUPPost. * Signed in with user pools: true. @@ -349,24 +329,6 @@ public void testGroupPrivateUPIAMPostAuthenticated() throws IOException, Amplify ); } - /** - * Class name: GroupPrivateUPIAMPost. - * Signed in with user pools: false. - * Signed in with OIDC: false. - * Expected result: No matching auth types. - * @throws AmplifyException Not expected. - * @throws IOException Not expected. - */ - @Test - @Ignore("Test is inconsistent, needs further investigation") - public void testGroupPrivateUPIAMPostAnonymous() throws IOException, AmplifyException { - verifyScenario(GroupPrivateUPIAMPost.class, - false, - false, - null - ); - } - /** * Class name: GroupPublicUPAPIPost. * Signed in with user pools: true. @@ -452,24 +414,6 @@ public void testPrivatePrivateUPIAMPostAuthenticated() throws IOException, Ampli ); } - /** - * Class name: PrivatePrivateUPIAMPost. - * Signed in with user pools: false. - * Signed in with OIDC: false. - * Expected result: No matching auth types. - * @throws AmplifyException Not expected. - * @throws IOException Not expected. - */ - @Test - @Ignore("Test is inconsistent, needs further investigation") - public void testPrivatePrivateUPIAMPostAnonymous() throws IOException, AmplifyException { - verifyScenario(PrivatePrivateUPIAMPost.class, - false, - false, - null - ); - } - /** * Class name: PrivatePublicUPAPIPost. * Signed in with user pools: true. diff --git a/aws-datastore/src/androidTest/java/com/amplifyframework/datastore/MultiAuthSyncEngineNoAuthInstrumentationTest.java b/aws-datastore/src/androidTest/java/com/amplifyframework/datastore/MultiAuthSyncEngineNoAuthInstrumentationTest.java index af549c258b..592bd8785a 100644 --- a/aws-datastore/src/androidTest/java/com/amplifyframework/datastore/MultiAuthSyncEngineNoAuthInstrumentationTest.java +++ b/aws-datastore/src/androidTest/java/com/amplifyframework/datastore/MultiAuthSyncEngineNoAuthInstrumentationTest.java @@ -51,8 +51,6 @@ import org.json.JSONException; import org.json.JSONObject; import org.junit.AfterClass; -import org.junit.Ignore; -import org.junit.Test; import java.io.IOException; import java.util.Collections; @@ -89,20 +87,6 @@ public final class MultiAuthSyncEngineNoAuthInstrumentationTest { private SynchronousDataStore dataStore; private HttpRequestInterceptor requestInterceptor; - /** - * Class name: Author. - * Signed in with user pools: false. - * Signed in with OIDC: false. - * Expected result: AuthorizationType.API_KEY. - * @throws AmplifyException Not expected. - * @throws IOException Not expected. - */ - @Test - @Ignore("fix in dev-preview") - public void testAuthorAnonymous() throws IOException, AmplifyException { - verifyScenario(); - } - /** * Method used to configure each scenario. * @throws AmplifyException No expected. diff --git a/aws-datastore/src/test/java/com/amplifyframework/datastore/AWSDataStorePluginTest.java b/aws-datastore/src/test/java/com/amplifyframework/datastore/AWSDataStorePluginTest.java deleted file mode 100644 index 4939704d08..0000000000 --- a/aws-datastore/src/test/java/com/amplifyframework/datastore/AWSDataStorePluginTest.java +++ /dev/null @@ -1,621 +0,0 @@ -/* - * Copyright 2020 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.datastore; - -import android.content.Context; -import androidx.annotation.NonNull; - -import com.amplifyframework.AmplifyException; -import com.amplifyframework.api.ApiCategory; -import com.amplifyframework.api.ApiCategoryConfiguration; -import com.amplifyframework.api.ApiException; -import com.amplifyframework.api.ApiPlugin; -import com.amplifyframework.api.events.ApiChannelEventName; -import com.amplifyframework.api.events.ApiEndpointStatusChangeEvent; -import com.amplifyframework.api.graphql.GraphQLOperation; -import com.amplifyframework.api.graphql.GraphQLRequest; -import com.amplifyframework.api.graphql.GraphQLResponse; -import com.amplifyframework.api.graphql.PaginatedResult; -import com.amplifyframework.api.graphql.SubscriptionType; -import com.amplifyframework.core.Action; -import com.amplifyframework.core.Amplify; -import com.amplifyframework.core.Consumer; -import com.amplifyframework.core.InitializationStatus; -import com.amplifyframework.core.category.CategoryType; -import com.amplifyframework.core.model.ModelProvider; -import com.amplifyframework.core.model.temporal.Temporal; -import com.amplifyframework.datastore.appsync.ModelMetadata; -import com.amplifyframework.datastore.appsync.ModelWithMetadata; -import com.amplifyframework.datastore.model.SimpleModelProvider; -import com.amplifyframework.hub.HubChannel; -import com.amplifyframework.hub.HubEvent; -import com.amplifyframework.logging.Logger; -import com.amplifyframework.testmodels.personcar.AmplifyCliGeneratedModelProvider; -import com.amplifyframework.testmodels.personcar.Person; -import com.amplifyframework.testutils.HubAccumulator; -import com.amplifyframework.testutils.random.RandomString; -import com.amplifyframework.testutils.sync.SynchronousDataStore; - -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentMatcher; -import org.robolectric.RobolectricTestRunner; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import io.reactivex.rxjava3.core.Observable; - -import static androidx.test.core.app.ApplicationProvider.getApplicationContext; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockingDetails; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -@SuppressWarnings("SameParameterValue") -@RunWith(RobolectricTestRunner.class) -@Ignore("Test class is unstable on CI - to be enabled after investigation") -public final class AWSDataStorePluginTest { - private static final Logger LOG = Amplify.Logging.logger(CategoryType.DATASTORE, "amplify:datastore:test"); - private static final long TIMEOUT_MS = TimeUnit.SECONDS.toMillis(1); - - private static final String MOCK_API_PLUGIN_NAME = "MockApiPlugin"; - private Context context; - private ModelProvider modelProvider; - private AtomicInteger subscriptionStartedCounter; - private AtomicInteger subscriptionCancelledCounter; - private int modelCount; - - /** - * Sets up the test. The {@link SimpleModelProvider} is spy'd, so that - * we can check if the SyncProcessor queries it. If it does, that means - * the SyncProcessor is running. Otherwise, either the SyncProcessor is *not* - * running, or it is running but not functioning as we expect it to. - */ - @Before - public void setup() { - this.context = getApplicationContext(); - modelProvider = spy(AmplifyCliGeneratedModelProvider.singletonInstance()); - subscriptionCancelledCounter = new AtomicInteger(); - subscriptionStartedCounter = new AtomicInteger(); - modelCount = modelProvider.modelNames().size(); - } - - /** - * Configuring and initializing the plugin succeeds without freezing or crashing the calling thread. Basic. 🙄 - * @throws AmplifyException On failure to configure or initialize plugin. - */ - @Test - public void configureAndInitialize() throws AmplifyException { - //Configure DataStore with an empty config (All defaults) - ApiCategory emptyApiCategory = spy(ApiCategory.class); - AWSDataStorePlugin standAloneDataStorePlugin = AWSDataStorePlugin.builder() - .modelProvider(modelProvider) - .apiCategory(emptyApiCategory) - .build(); - standAloneDataStorePlugin.configure(new JSONObject(), context); - standAloneDataStorePlugin.initialize(context); - } - - /** - * Starting the plugin in local mode (no API plugin) works without freezing or crashing the calling thread. - * @throws AmplifyException Not expected; on failure to configure of initialize plugin. - */ - @Test - public void startInLocalMode() throws AmplifyException { - // Configure DataStore with an empty config (All defaults) - HubAccumulator dataStoreReadyObserver = - HubAccumulator.create(HubChannel.DATASTORE, DataStoreChannelEventName.READY, 1) - .start(); - ApiCategory emptyApiCategory = spy(ApiCategory.class); - AWSDataStorePlugin standAloneDataStorePlugin = AWSDataStorePlugin.builder() - .modelProvider(modelProvider) - .apiCategory(emptyApiCategory) - .build(); - SynchronousDataStore synchronousDataStore = SynchronousDataStore.delegatingTo(standAloneDataStorePlugin); - standAloneDataStorePlugin.configure(new JSONObject(), context); - standAloneDataStorePlugin.initialize(context); - // Trick the DataStore since it's not getting initialized as part of the Amplify.initialize call chain - Amplify.Hub.publish(HubChannel.DATASTORE, HubEvent.create(InitializationStatus.SUCCEEDED)); - - synchronousDataStore.start(); - - dataStoreReadyObserver.await(); - assertSyncProcessorNotStarted(emptyApiCategory); - - Person person1 = createPerson("Test", "Dummy I"); - synchronousDataStore.save(person1); - assertNotNull(person1.getId()); - Person person1FromDb = synchronousDataStore.get(Person.class, person1.getPrimaryKeyString()); - assertEquals(person1, person1FromDb); - } - - /** - * Starting the plugin when in API sync mode succeeds without freezing or crashing the calling thread. - * @throws JSONException on failure to arrange plugin config - * @throws AmplifyException on failure to arrange API plugin via Amplify facade - */ - @Test - public void startInApiMode() throws JSONException, AmplifyException { - HubAccumulator dataStoreReadyObserver = - HubAccumulator.create(HubChannel.DATASTORE, DataStoreChannelEventName.READY, 1) - .start(); - HubAccumulator subscriptionsEstablishedObserver = - HubAccumulator.create(HubChannel.DATASTORE, DataStoreChannelEventName.SUBSCRIPTIONS_ESTABLISHED, 1) - .start(); - HubAccumulator networkStatusObserver = - HubAccumulator.create(HubChannel.DATASTORE, DataStoreChannelEventName.NETWORK_STATUS, 1) - .start(); - ApiCategory mockApiCategory = mockApiCategoryWithGraphQlApi(); - JSONObject dataStorePluginJson = new JSONObject() - .put("syncIntervalInMinutes", 60); - AWSDataStorePlugin awsDataStorePlugin = AWSDataStorePlugin.builder() - .modelProvider(modelProvider) - .apiCategory(mockApiCategory) - .build(); - SynchronousDataStore synchronousDataStore = SynchronousDataStore.delegatingTo(awsDataStorePlugin); - awsDataStorePlugin.configure(dataStorePluginJson, context); - awsDataStorePlugin.initialize(context); - // Trick the DataStore since it's not getting initialized as part of the Amplify.initialize call chain - Amplify.Hub.publish(HubChannel.DATASTORE, HubEvent.create(InitializationStatus.SUCCEEDED)); - - synchronousDataStore.start(); - - dataStoreReadyObserver.await(); - subscriptionsEstablishedObserver.await(); - - assertRemoteSubscriptionsStarted(); - } - - /** - * Verify that when the clear method is called, the following happens - * - All remote synchronization processes are stopped - * - The database is deleted. - * - On the next interaction with the DataStore, the synchronization processes are restarted. - * @throws JSONException on failure to arrange plugin config - * @throws AmplifyException on failure to arrange API plugin via Amplify facade - */ - @Test - public void clearStopsSyncAndDeletesDatabase() throws AmplifyException, JSONException { - ApiCategory mockApiCategory = mockApiCategoryWithGraphQlApi(); - ApiPlugin mockApiPlugin = mockApiCategory.getPlugin(MOCK_API_PLUGIN_NAME); - JSONObject dataStorePluginJson = new JSONObject() - .put("syncIntervalInMinutes", 60); - AWSDataStorePlugin awsDataStorePlugin = AWSDataStorePlugin.builder() - .modelProvider(modelProvider) - .apiCategory(mockApiCategory) - .build(); - SynchronousDataStore synchronousDataStore = SynchronousDataStore.delegatingTo(awsDataStorePlugin); - awsDataStorePlugin.configure(dataStorePluginJson, context); - awsDataStorePlugin.initialize(context); - - // Trick the DataStore since it's not getting initialized as part of the Amplify.initialize call chain - Amplify.Hub.publish(HubChannel.DATASTORE, HubEvent.create(InitializationStatus.SUCCEEDED)); - - // Setup objects - Person person1 = createPerson("Test", "Dummy I"); - Person person2 = createPerson("Test", "Dummy II"); - - // Mock responses for person 1 - doAnswer(invocation -> { - int indexOfResponseConsumer = 1; - Consumer>> onResponse = - invocation.getArgument(indexOfResponseConsumer); - ModelMetadata modelMetadata = new ModelMetadata(person1.getId(), false, 1, Temporal.Timestamp.now()); - ModelWithMetadata modelWithMetadata = new ModelWithMetadata<>(person1, modelMetadata); - onResponse.accept(new GraphQLResponse<>(modelWithMetadata, Collections.emptyList())); - return mock(GraphQLOperation.class); - }).when(mockApiPlugin).mutate(any(), any(), any()); - - HubAccumulator apiInteractionObserver = - HubAccumulator.create(HubChannel.DATASTORE, DataStoreChannelEventName.OUTBOX_MUTATION_PROCESSED, 1) - .start(); - - // Save person 1 - synchronousDataStore.save(person1); - Person result1 = synchronousDataStore.get(Person.class, person1.getPrimaryKeyString()); - assertEquals(person1, result1); - - apiInteractionObserver.await(15, TimeUnit.SECONDS); - verify(mockApiCategory).mutate(argThat(getMatcherFor(person1)), any(), any()); - - // Mock responses for person 2 - doAnswer(invocation -> { - int indexOfResponseConsumer = 1; - Consumer>> onResponse = - invocation.getArgument(indexOfResponseConsumer); - ModelMetadata modelMetadata = new ModelMetadata(person2.getId(), false, 1, - Temporal.Timestamp.now()); - ModelWithMetadata modelWithMetadata = new ModelWithMetadata<>(person2, modelMetadata); - onResponse.accept(new GraphQLResponse<>(modelWithMetadata, Collections.emptyList())); - return mock(GraphQLOperation.class); - }).when(mockApiPlugin).mutate(any(), any(), any()); - - // Do the thing! - synchronousDataStore.clear(); - - assertRemoteSubscriptionsCancelled(); - - apiInteractionObserver = - HubAccumulator.create(HubChannel.DATASTORE, DataStoreChannelEventName.OUTBOX_MUTATION_PROCESSED, 1) - .start(); - HubAccumulator orchestratorInitObserver = - HubAccumulator.create(HubChannel.DATASTORE, DataStoreChannelEventName.READY, 1) - .start(); - - // Interact with the DataStore after the clear - synchronousDataStore.save(person2); - - // Verify person 2 was published to the cloud - apiInteractionObserver.await(); - - // Verify the orchestrator started back up and subscriptions are active. - orchestratorInitObserver.await(); - assertRemoteSubscriptionsStarted(); - - Person result2 = synchronousDataStore.get(Person.class, person2.getPrimaryKeyString()); - assertEquals(person2, result2); - - verify(mockApiCategory, atLeastOnce()) - .mutate(argThat(getMatcherFor(person2)), any(), any()); - } - - /** - * Verify that when the stop method is called, the following happens - * - All remote synchronization processes are stopped - * - On the next interaction with the DataStore, the synchronization processes are restarted. - * @throws JSONException on failure to arrange plugin config - * @throws AmplifyException on failure to arrange API plugin via Amplify facade - */ - @Test - public void stopStopsSyncUntilNextInteraction() throws AmplifyException, JSONException { - ApiCategory mockApiCategory = mockApiCategoryWithGraphQlApi(); - ApiPlugin mockApiPlugin = mockApiCategory.getPlugin(MOCK_API_PLUGIN_NAME); - JSONObject dataStorePluginJson = new JSONObject() - .put("syncIntervalInMinutes", 60); - AWSDataStorePlugin awsDataStorePlugin = AWSDataStorePlugin.builder() - .modelProvider(modelProvider) - .apiCategory(mockApiCategory) - .build(); - SynchronousDataStore synchronousDataStore = SynchronousDataStore.delegatingTo(awsDataStorePlugin); - awsDataStorePlugin.configure(dataStorePluginJson, context); - awsDataStorePlugin.initialize(context); - - // Trick the DataStore since it's not getting initialized as part of the Amplify.initialize call chain - Amplify.Hub.publish(HubChannel.DATASTORE, HubEvent.create(InitializationStatus.SUCCEEDED)); - - // Setup objects - Person person1 = createPerson("Test", "Dummy I"); - Person person2 = createPerson("Test", "Dummy II"); - - // Mock responses for person 1 - doAnswer(invocation -> { - int indexOfResponseConsumer = 1; - Consumer>> onResponse = - invocation.getArgument(indexOfResponseConsumer); - ModelMetadata modelMetadata = new ModelMetadata(person1.getPrimaryKeyString(), false, 1, - Temporal.Timestamp.now()); - ModelWithMetadata modelWithMetadata = new ModelWithMetadata<>(person1, modelMetadata); - onResponse.accept(new GraphQLResponse<>(modelWithMetadata, Collections.emptyList())); - return mock(GraphQLOperation.class); - }).when(mockApiPlugin).mutate(any(), any(), any()); - - HubAccumulator apiInteractionObserver = - HubAccumulator.create(HubChannel.DATASTORE, DataStoreChannelEventName.OUTBOX_MUTATION_PROCESSED, 1) - .start(); - - // Save person 1 - synchronousDataStore.save(person1); - Person result1 = synchronousDataStore.get(Person.class, person1.getPrimaryKeyString()); - assertEquals(person1, result1); - - apiInteractionObserver.await(); - verify(mockApiCategory).mutate(argThat(getMatcherFor(person1)), any(), any()); - - // Mock responses for person 2 - doAnswer(invocation -> { - int indexOfResponseConsumer = 1; - Consumer>> onResponse = - invocation.getArgument(indexOfResponseConsumer); - ModelMetadata modelMetadata = new ModelMetadata(person2.getPrimaryKeyString(), false, 1, - Temporal.Timestamp.now()); - ModelWithMetadata modelWithMetadata = new ModelWithMetadata<>(person2, modelMetadata); - onResponse.accept(new GraphQLResponse<>(modelWithMetadata, Collections.emptyList())); - return mock(GraphQLOperation.class); - }).when(mockApiPlugin).mutate(any(), any(), any()); - - // Do the thing! - synchronousDataStore.stop(); - - assertRemoteSubscriptionsCancelled(); - - apiInteractionObserver = - HubAccumulator.create(HubChannel.DATASTORE, DataStoreChannelEventName.OUTBOX_MUTATION_PROCESSED, 1) - .start(); - HubAccumulator orchestratorInitObserver = - HubAccumulator.create(HubChannel.DATASTORE, DataStoreChannelEventName.READY, 1) - .start(); - - // Interact with the DataStore after the stop - synchronousDataStore.save(person2); - - // Verify person 2 was published to the cloud - apiInteractionObserver.await(); - - // Verify the orchestrator started back up and subscriptions are active. - orchestratorInitObserver.await(); - assertRemoteSubscriptionsStarted(); - - // Verify person 1 and 2 are in the DataStore - List results = synchronousDataStore.list(Person.class); - assertEquals(Arrays.asList(person1, person2), results); - - verify(mockApiCategory, atLeastOnce()) - .mutate(argThat(getMatcherFor(person2)), any(), any()); - } - - private void assertRemoteSubscriptionsCancelled() { - // Check that we've had active subscriptions - assertTrue(subscriptionStartedCounter.get() > 0); - // And the number of started and cancelled are the same - assertEquals(subscriptionStartedCounter.get(), subscriptionCancelledCounter.get()); - } - - private void assertRemoteSubscriptionsStarted() { - // For each model, there should be 3 subscriptions setup. - // If subscriptions are active, the active counters should be: - // activeCount - cancelledCount = modelCount * 3 - // The difference between active and cancelled should always be at most modelCount * 3 - final int diffTypesOfSubscriptions = SubscriptionType.values().length; - assertEquals( - modelCount * diffTypesOfSubscriptions, - subscriptionStartedCounter.get() - subscriptionCancelledCounter.get() - ); - } - - /** - * Check that the SyncProcessor did not start by asserting that the - * only interaction with the API category was triggered by the getPlugins - * method. - * @param mockApi Mock or spy of the ApiCategory being used for the test. - */ - private void assertSyncProcessorNotStarted(ApiCategory mockApi) { - Long callsToApiCategory = Observable.fromIterable(mockingDetails(mockApi).getInvocations()) - .filter(invocation -> !"getPlugins".equals(invocation.getMethod().getName())) - .count() - .blockingGet(); - assertEquals(Long.valueOf(0), callsToApiCategory); - } - - @SuppressWarnings("unchecked") - private ApiCategory mockApiCategoryWithGraphQlApi() throws AmplifyException { - ApiCategory mockApiCategory = spy(ApiCategory.class); - ApiPlugin mockApiPlugin = mock(ApiPlugin.class); - when(mockApiPlugin.getPluginKey()).thenReturn(MOCK_API_PLUGIN_NAME); - when(mockApiPlugin.getCategoryType()).thenReturn(CategoryType.API); - - ApiEndpointStatusChangeEvent eventData = - new ApiEndpointStatusChangeEvent(ApiEndpointStatusChangeEvent.ApiEndpointStatus.REACHABLE, - ApiEndpointStatusChangeEvent.ApiEndpointStatus.UNKOWN); - HubEvent hubEvent = - HubEvent.create(ApiChannelEventName.API_ENDPOINT_STATUS_CHANGED, eventData); - - // Make believe that queries return response immediately - doAnswer(invocation -> { - // Mock the API emitting an ApiEndpointStatusChangeEvent event. - Amplify.Hub.publish(HubChannel.API, hubEvent); - int indexOfResponseConsumer = 1; - Consumer>>> onResponse = - invocation.getArgument(indexOfResponseConsumer); - PaginatedResult> data = new PaginatedResult<>(Collections.emptyList(), null); - onResponse.accept(new GraphQLResponse<>(data, Collections.emptyList())); - return null; - }).when(mockApiPlugin).query(any(GraphQLRequest.class), any(Consumer.class), any(Consumer.class)); - - // Make believe that subscriptions return response immediately - doAnswer(invocation -> { - int indexOfStartConsumer = 1; - Consumer onStart = invocation.getArgument(indexOfStartConsumer); - GraphQLOperation mockOperation = mock(GraphQLOperation.class); - doAnswer(opAnswer -> { - this.subscriptionCancelledCounter.incrementAndGet(); - return null; - }).when(mockOperation).cancel(); - - this.subscriptionStartedCounter.incrementAndGet(); - // Trigger the subscription start event. - onStart.accept(RandomString.string()); - return mockOperation; - }).when(mockApiPlugin).subscribe( - any(GraphQLRequest.class), - any(Consumer.class), - any(Consumer.class), - any(Consumer.class), - any(Action.class) - ); - mockApiCategory.addPlugin(mockApiPlugin); - mockApiCategory.configure(new ApiCategoryConfiguration(), getApplicationContext()); - mockApiCategory.initialize(getApplicationContext()); - return mockApiCategory; - } - - /** - * Almost the same as mockApiCategoryWithGraphQlApi, but it calls the onError callback instead. - * - * @return A mock version of the API Category. - * @throws AmplifyException Throw if an error happens when adding the plugin. - */ - @SuppressWarnings("unchecked") - private static ApiCategory mockApiPluginWithExceptions() throws AmplifyException { - ApiCategory mockApiCategory = spy(ApiCategory.class); - ApiPlugin mockApiPlugin = mock(ApiPlugin.class); - when(mockApiPlugin.getPluginKey()).thenReturn(MOCK_API_PLUGIN_NAME); - when(mockApiPlugin.getCategoryType()).thenReturn(CategoryType.API); - - doAnswer(invocation -> { - int indexOfErrorConsumer = 2; - Consumer onError = invocation.getArgument(indexOfErrorConsumer); - onError.accept(new ApiException("Fake exception thrown from the API.query method", "Just retry")); - return null; - }).when(mockApiPlugin).query(any(GraphQLRequest.class), any(Consumer.class), any(Consumer.class)); - - doAnswer(invocation -> { - int indexOfErrorConsumer = 2; - Consumer onError = invocation.getArgument(indexOfErrorConsumer); - onError.accept(new ApiException("Fake exception thrown from the API.mutate method", "Just retry")); - return null; - }).when(mockApiPlugin).mutate(any(GraphQLRequest.class), any(Consumer.class), any(Consumer.class)); - - doAnswer(invocation -> { - int indexOfErrorConsumer = 3; - Consumer onError = invocation.getArgument(indexOfErrorConsumer); - ApiException apiException = - new ApiException("Fake exception thrown from the API.subscribe method", "Just retry"); - onError.accept(apiException); - return null; - }).when(mockApiPlugin).subscribe( - any(GraphQLRequest.class), - any(Consumer.class), - any(Consumer.class), - any(Consumer.class), - any(Action.class) - ); - mockApiCategory.addPlugin(mockApiPlugin); - return mockApiCategory; - } - - /** - * Verify that the observe api returns itemChanged which matches the predicate. - * - * @throws JSONException on failure to arrange plugin config. - * @throws AmplifyException on failure to arrange API plugin via Amplify facade. - * @throws InterruptedException If interrupted while test observer awaits terminal result. - */ - @Test - public void observeWithMatchingPredicate() throws InterruptedException, AmplifyException, JSONException { - AWSDataStorePlugin awsDataStorePlugin = AWSDataStorePlugin.builder() - .modelProvider(modelProvider) - .build(); - JSONObject dataStorePluginJson = new JSONObject() - .put("syncIntervalInMinutes", 60); - awsDataStorePlugin.configure(dataStorePluginJson, context); - awsDataStorePlugin.initialize(context); - Amplify.Hub.publish(HubChannel.DATASTORE, HubEvent.create(InitializationStatus.SUCCEEDED)); - SynchronousDataStore synchronousDataStore = SynchronousDataStore.delegatingTo(awsDataStorePlugin); - final CountDownLatch latch = new CountDownLatch(1); - Person expectedResult = createPerson("Test", "Dummy I"); - final Person[] actualResult = {null}; - Consumer> onObserveResult = spy(new Consumer>() { - @Override - public void accept(@NonNull DataStoreItemChange value) { - latch.countDown(); - actualResult[0] = value.item(); - } - }); - awsDataStorePlugin.observe(Person.class, - Person.FIRST_NAME.eq("Test"), - value -> { }, - onObserveResult, - error -> { - LOG.error("Error: " + error); - }, - () -> { } - ); - synchronousDataStore.save(expectedResult); - latch.await(TIMEOUT_MS, TimeUnit.SECONDS); - verify(onObserveResult).accept(any()); - assertEquals(actualResult[0], expectedResult); - } - - /** - * Verify that the observe api is not invoke when the item changed does not match the predicate. - * - * @throws JSONException on failure to arrange plugin config. - * @throws AmplifyException on failure to arrange API plugin via Amplify facade. - * @throws InterruptedException If interrupted while test observer awaits terminal result. - */ - @Test - public void observeWithoutMatchingPredicate() throws InterruptedException, AmplifyException, JSONException { - AWSDataStorePlugin awsDataStorePlugin = AWSDataStorePlugin.builder() - .modelProvider(modelProvider) - .build(); - JSONObject dataStorePluginJson = new JSONObject() - .put("syncIntervalInMinutes", 60); - awsDataStorePlugin.configure(dataStorePluginJson, context); - awsDataStorePlugin.initialize(context); - Amplify.Hub.publish(HubChannel.DATASTORE, HubEvent.create(InitializationStatus.SUCCEEDED)); - SynchronousDataStore synchronousDataStore = SynchronousDataStore.delegatingTo(awsDataStorePlugin); - Person expectedResult = createPerson("Test", "Dummy I"); - final Person[] actualResult = {null}; - Consumer> onObserveResult = spy(new Consumer>() { - @Override - public void accept(@NonNull DataStoreItemChange value) { - actualResult[0] = value.item(); - } - }); - awsDataStorePlugin.observe(Person.class, - Person.FIRST_NAME.eq("NO MATCH"), - value -> { }, - onObserveResult, - error -> { - LOG.error("Error: " + error); - }, - () -> { } - ); - synchronousDataStore.save(expectedResult); - Thread.sleep(1000L); - verify(onObserveResult, never()).accept(any()); - } - - private Person createPerson(String firstName, String lastName) { - return Person.builder() - .firstName(firstName) - .lastName(lastName) - .age(41) - .build(); - } - - private static ArgumentMatcher>> getMatcherFor(Person person) { - return graphQLRequest -> { - try { - JSONObject payload = new JSONObject(graphQLRequest.getContent()); - String modelIdInRequest = payload.getJSONObject("variables").getJSONObject("input").getString("id"); - return person.getId().equals(modelIdInRequest); - } catch (JSONException exception) { - fail("Invalid GraphQLRequest payload." + exception.getMessage()); - } - return false; - }; - } -} diff --git a/aws-datastore/src/test/java/com/amplifyframework/datastore/MutationProcessorRetryTest.java b/aws-datastore/src/test/java/com/amplifyframework/datastore/MutationProcessorRetryTest.java deleted file mode 100644 index 36501655e1..0000000000 --- a/aws-datastore/src/test/java/com/amplifyframework/datastore/MutationProcessorRetryTest.java +++ /dev/null @@ -1,260 +0,0 @@ -/* - * 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.datastore; - -import android.content.Context; - -import com.amplifyframework.AmplifyException; -import com.amplifyframework.api.ApiCategory; -import com.amplifyframework.api.ApiCategoryConfiguration; -import com.amplifyframework.api.ApiException; -import com.amplifyframework.api.ApiPlugin; -import com.amplifyframework.api.events.ApiChannelEventName; -import com.amplifyframework.api.events.ApiEndpointStatusChangeEvent; -import com.amplifyframework.api.graphql.GraphQLOperation; -import com.amplifyframework.api.graphql.GraphQLRequest; -import com.amplifyframework.api.graphql.GraphQLResponse; -import com.amplifyframework.api.graphql.PaginatedResult; -import com.amplifyframework.core.Action; -import com.amplifyframework.core.Amplify; -import com.amplifyframework.core.Consumer; -import com.amplifyframework.core.InitializationStatus; -import com.amplifyframework.core.category.CategoryType; -import com.amplifyframework.core.model.ModelProvider; -import com.amplifyframework.core.model.temporal.Temporal; -import com.amplifyframework.datastore.appsync.ModelMetadata; -import com.amplifyframework.datastore.appsync.ModelWithMetadata; -import com.amplifyframework.hub.HubChannel; -import com.amplifyframework.hub.HubEvent; -import com.amplifyframework.testmodels.personcar.AmplifyCliGeneratedModelProvider; -import com.amplifyframework.testmodels.personcar.Car; -import com.amplifyframework.testmodels.personcar.Person; -import com.amplifyframework.testutils.random.RandomString; -import com.amplifyframework.testutils.sync.SynchronousDataStore; - -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentMatcher; -import org.robolectric.RobolectricTestRunner; - -import java.util.Collections; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import io.reactivex.rxjava3.core.Completable; - -import static androidx.test.core.app.ApplicationProvider.getApplicationContext; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.atLeast; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -@RunWith(RobolectricTestRunner.class) -public final class MutationProcessorRetryTest { - private static final String MOCK_API_PLUGIN_NAME = "MockApiPlugin"; - private Context context; - private ModelProvider modelProvider; - - /** - * Wire up dependencies for the Datastore, and build one for testing. - * @throws AmplifyException On failure to load models into registry - */ - @Before - public void setup() throws AmplifyException { - this.context = getApplicationContext(); - this.modelProvider = spy(AmplifyCliGeneratedModelProvider.singletonInstance()); - } - - /** - * When {@link Completable} completes, - * If a mutation fails it is retried. - * @throws AmplifyException On failure interacting with storage adapter - * @throws InterruptedException If interrupted while awaiting terminal result in test observer - * @throws JSONException If unable to parse the JSON. - */ - @SuppressWarnings("unchecked") // Varied types in Observable.fromArray(...). - @Test - @Ignore("Test is inconsistent, needs further investigation") - public void testMutationProcessorRetriesFailedRequestsBecauseOfARecoverableError() - throws AmplifyException, JSONException, InterruptedException { - CountDownLatch latch = new CountDownLatch(4); - // Setup Mock Api - ApiCategory mockApiCategory = mockApiCategoryWithGraphQlApi(); - Person person1 = setupApiMock(latch, mockApiCategory); - - JSONObject dataStorePluginJson = new JSONObject() - .put("syncIntervalInMinutes", 60); - AWSDataStorePlugin awsDataStorePlugin = AWSDataStorePlugin.builder() - .modelProvider(modelProvider) - .apiCategory(mockApiCategory) - .dataStoreConfiguration(DataStoreConfiguration.builder() - .conflictHandler(DataStoreConflictHandler.alwaysRetryLocal()) - .build()) - .build(); - SynchronousDataStore synchronousDataStore = SynchronousDataStore.delegatingTo(awsDataStorePlugin); - awsDataStorePlugin.configure(dataStorePluginJson, context); - awsDataStorePlugin.initialize(context); - awsDataStorePlugin.start(() -> { }, (onError) -> { }); - - // Trick the DataStore since it's not getting initialized as part of the Amplify.initialize call chain - Amplify.Hub.publish(HubChannel.DATASTORE, HubEvent.create(InitializationStatus.SUCCEEDED)); - - // Save person 1 - synchronousDataStore.save(person1); - Person result1 = synchronousDataStore.get(Person.class, person1.getId()); - assertTrue(latch.await(700, TimeUnit.SECONDS)); - assertEquals(person1, result1); - } - - @SuppressWarnings("unchecked") - private Person setupApiMock(CountDownLatch latch, ApiCategory mockApiCategory) { - Person person1 = createPerson("Test", "Dummy I"); - //Mock success on subscription. - doAnswer(invocation -> { - int indexOfStartConsumer = 1; - Consumer onStart = invocation.getArgument(indexOfStartConsumer); - GraphQLOperation mockOperation = mock(GraphQLOperation.class); - doAnswer(opAnswer -> { - return null; - }).when(mockOperation).cancel(); - - // Trigger the subscription start event. - onStart.accept(RandomString.string()); - return mockOperation; - }).when(mockApiCategory).subscribe( - any(GraphQLRequest.class), - any(Consumer.class), - any(Consumer.class), - any(Consumer.class), - any(Action.class) - ); - - //When mutate is called on the appsync for the first time a recoverable error is returned. - doAnswer(invocation -> { - int indexOfResponseConsumer = 2; - Consumer onError = - invocation.getArgument(indexOfResponseConsumer); - - onError.accept(new ApiException("Error", "Network error")); - // latch makes sure error response is returned. - latch.countDown(); - return mock(GraphQLOperation.class); - }).doAnswer(invocation -> { - //When mutate is called on the appsync for the second time success response is returned - int indexOfResponseConsumer = 1; - Consumer>> onResponse = - invocation.getArgument(indexOfResponseConsumer); - ModelMetadata modelMetadata = new ModelMetadata(person1.getId(), false, 1, Temporal.Timestamp.now()); - ModelWithMetadata modelWithMetadata = new ModelWithMetadata<>(person1, modelMetadata); - onResponse.accept(new GraphQLResponse<>(modelWithMetadata, Collections.emptyList())); - verify(mockApiCategory, atLeast(2)).mutate(argThat(getMatcherFor(person1)), - any(), - any()); - // latch makes sure success response is returned. - latch.countDown(); - return mock(GraphQLOperation.class); - }).when(mockApiCategory).mutate(any(), any(), any()); - - // Setup to mimic successful sync - doAnswer(invocation -> { - int indexOfResponseConsumer = 1; - ModelMetadata modelMetadata = new ModelMetadata(person1.getId(), false, 1, - Temporal.Timestamp.now()); - ModelWithMetadata modelWithMetadata = new ModelWithMetadata<>(person1, modelMetadata); - // Mock the API emitting an ApiEndpointStatusChangeEvent event. - Consumer>>> onResponse = - invocation.getArgument(indexOfResponseConsumer); - PaginatedResult> data = - new PaginatedResult<>(Collections.singletonList(modelWithMetadata), null); - onResponse.accept(new GraphQLResponse<>(data, Collections.emptyList())); - latch.countDown(); - return mock(GraphQLOperation.class); - - }).doAnswer(invocation -> { - int indexOfResponseConsumer = 1; - Car car = Car.builder().build(); - ModelMetadata modelMetadata = new ModelMetadata(car.getId(), false, 1, Temporal.Timestamp.now()); - ModelWithMetadata modelWithMetadata = new ModelWithMetadata<>(car, modelMetadata); - Consumer>>> onResponse = - invocation.getArgument(indexOfResponseConsumer); - PaginatedResult> data = - new PaginatedResult<>(Collections.singletonList(modelWithMetadata), null); - onResponse.accept(new GraphQLResponse<>(data, Collections.emptyList())); - latch.countDown(); - return mock(GraphQLOperation.class); - }).when(mockApiCategory).query(any(), any(), any()); - return person1; - } - - private static ArgumentMatcher>> getMatcherFor(Person person) { - return graphQLRequest -> { - try { - JSONObject payload = new JSONObject(graphQLRequest.getContent()); - String modelIdInRequest = payload.getJSONObject("variables").getJSONObject("input").getString("id"); - return person.getId().equals(modelIdInRequest); - } catch (JSONException exception) { - fail("Invalid GraphQLRequest payload." + exception.getMessage()); - } - return false; - }; - } - - private Person createPerson(String firstName, String lastName) { - return Person.builder() - .firstName(firstName) - .lastName(lastName) - .build(); - } - - @SuppressWarnings("unchecked") - private ApiCategory mockApiCategoryWithGraphQlApi() throws AmplifyException { - ApiCategory mockApiCategory = spy(ApiCategory.class); - ApiPlugin mockApiPlugin = mock(ApiPlugin.class); - when(mockApiPlugin.getPluginKey()).thenReturn(MOCK_API_PLUGIN_NAME); - when(mockApiPlugin.getCategoryType()).thenReturn(CategoryType.API); - ApiEndpointStatusChangeEvent eventData = - new ApiEndpointStatusChangeEvent(ApiEndpointStatusChangeEvent.ApiEndpointStatus.REACHABLE, - ApiEndpointStatusChangeEvent.ApiEndpointStatus.UNKOWN); - HubEvent hubEvent = - HubEvent.create(ApiChannelEventName.API_ENDPOINT_STATUS_CHANGED, eventData); - // Make believe that queries return response immediately - doAnswer(invocation -> { - // Mock the API emitting an ApiEndpointStatusChangeEvent event. - Amplify.Hub.publish(HubChannel.API, hubEvent); - int indexOfResponseConsumer = 1; - Consumer>>> onResponse = - invocation.getArgument(indexOfResponseConsumer); - PaginatedResult> data = new PaginatedResult<>(Collections.emptyList(), null); - onResponse.accept(new GraphQLResponse<>(data, Collections.emptyList())); - return null; - }).when(mockApiPlugin).query(any(GraphQLRequest.class), any(Consumer.class), any(Consumer.class)); - mockApiCategory.addPlugin(mockApiPlugin); - mockApiCategory.configure(new ApiCategoryConfiguration(), getApplicationContext()); - mockApiCategory.initialize(getApplicationContext()); - return mockApiCategory; - } -} diff --git a/aws-predictions/src/test/java/com/amplifyframework/predictions/aws/http/LivenessWebSocketTest.kt b/aws-predictions/src/test/java/com/amplifyframework/predictions/aws/http/LivenessWebSocketTest.kt index 29fde33290..a761a29b5a 100644 --- a/aws-predictions/src/test/java/com/amplifyframework/predictions/aws/http/LivenessWebSocketTest.kt +++ b/aws-predictions/src/test/java/com/amplifyframework/predictions/aws/http/LivenessWebSocketTest.kt @@ -69,7 +69,6 @@ import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Before -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner @@ -425,31 +424,6 @@ internal class LivenessWebSocketTest { assertEquals("AWS4-HMAC-SHA256", reconnectRequest.url.queryParameter("X-Amz-Algorithm")) } - @Test - @Ignore("Need to work on parsing the onMessage byteString from ServerWebSocketListener") - fun `sendInitialFaceDetectedEvent test`() { - } - - @Test - @Ignore("Need to work on parsing the onMessage byteString from ServerWebSocketListener") - fun `sendFinalEvent test`() { - } - - @Test - @Ignore("Need to work on parsing the onMessage byteString from ServerWebSocketListener") - fun `sendColorDisplayedEvent test`() { - } - - @Test - @Ignore("Need to work on parsing the onMessage byteString from ServerWebSocketListener") - fun `sendClientInfoEvent test`() { - } - - @Test - @Ignore("Need to work on parsing the onMessage byteString from ServerWebSocketListener") - fun `sendVideoEvent test`() { - } - private fun createLivenessWebSocket( livenessVersion: String? = null ) = LivenessWebSocket( diff --git a/aws-push-notifications-pinpoint/src/androidTest/java/com/amplifyframework/pushnotifications/pinpoint/NotificationsCanaryTest.kt b/aws-push-notifications-pinpoint/src/androidTest/java/com/amplifyframework/pushnotifications/pinpoint/NotificationsCanaryTest.kt deleted file mode 100644 index d4aa3af530..0000000000 --- a/aws-push-notifications-pinpoint/src/androidTest/java/com/amplifyframework/pushnotifications/pinpoint/NotificationsCanaryTest.kt +++ /dev/null @@ -1,165 +0,0 @@ -/* - * 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. - * 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.pushnotifications.pinpoint - -import android.util.Log -import androidx.test.core.app.ApplicationProvider -import com.amplifyframework.AmplifyException -import com.amplifyframework.auth.cognito.AWSCognitoAuthPlugin -import com.amplifyframework.core.Amplify -import com.amplifyframework.notifications.pushnotifications.NotificationContentProvider -import com.amplifyframework.notifications.pushnotifications.NotificationPayload -import java.util.concurrent.CountDownLatch -import java.util.concurrent.TimeUnit -import org.junit.Assert -import org.junit.Assert.fail -import org.junit.BeforeClass -import org.junit.Ignore -import org.junit.Test - -@Ignore("Tests require push notification services to be set up.") -class NotificationsCanaryTest { - companion object { - private const val TIMEOUT_S = 20L - private val TAG = NotificationsCanaryTest::class.simpleName - - @BeforeClass - @JvmStatic - fun setup() { - try { - Amplify.addPlugin(AWSCognitoAuthPlugin()) - Amplify.addPlugin(AWSPinpointPushNotificationsPlugin()) - Amplify.configure(ApplicationProvider.getApplicationContext()) - Log.i(TAG, "Initialized Amplify") - } catch (error: AmplifyException) { - Log.e(TAG, "Could not initialize Amplify", error) - } - } - } - - @Test - fun identifyUser() { - val latch = CountDownLatch(1) - var userId = "" - Amplify.Auth.getCurrentUser( - { authUser -> userId = authUser.userId }, - { Log.e(TAG, "Error getting current user", it) } - ) - - try { - Amplify.Notifications.Push.identifyUser( - userId, - { - Log.i(TAG, "Identified user successfully") - latch.countDown() - }, - { - Log.e(TAG, "Error identifying user", it) - fail() - } - ) - } catch (e: Exception) { - fail(e.toString()) - } - Assert.assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) - } - - @Test - fun registerDevice() { - val latch = CountDownLatch(1) - try { - Amplify.Notifications.Push.registerDevice( - "token", - { - Log.i(TAG, "Registered device with token") - latch.countDown() - }, - { - Log.e(TAG, "Failed to register device", it) - fail() - } - ) - } catch (error: Exception) { - Log.e(TAG, error.toString()) - } - Assert.assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) - } - - @Test - fun recordNotificationReceived() { - val latch = CountDownLatch(1) - val payload = NotificationPayload(NotificationContentProvider.FCM(mapOf())) - try { - Amplify.Notifications.Push.recordNotificationReceived( - payload, - { - Log.i(TAG, "Successfully registered notification received") - latch.countDown() - }, - { - Log.e(TAG, "Failed to register notification received", it) - fail() - } - ) - } catch (error: Exception) { - Log.e(TAG, error.toString()) - } - Assert.assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) - } - - @Test - fun recordNotificationOpened() { - val latch = CountDownLatch(1) - val payload = NotificationPayload(NotificationContentProvider.FCM(mapOf())) - try { - Amplify.Notifications.Push.recordNotificationOpened( - payload, - { - Log.i(TAG, "Successfully registered notification opened") - latch.countDown() - }, - { - Log.e(TAG, "Failed to register notification opened", it) - fail() - } - ) - } catch (error: Exception) { - Log.e(TAG, error.toString()) - } - Assert.assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) - } - - @Test - fun handleNotificationReceived() { - val latch = CountDownLatch(1) - val payload = NotificationPayload(NotificationContentProvider.FCM(mapOf())) - try { - Amplify.Notifications.Push.handleNotificationReceived( - payload, - { - Log.i(TAG, "Successfully handled notification") - latch.countDown() - }, - { - Log.e(TAG, "Failed to handle notification", it) - fail() - } - ) - } catch (error: Exception) { - Log.e(TAG, error.toString()) - } - Assert.assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) - } -} From a375ebb454e1bb182ca32a0a659ed30f2adcc095 Mon Sep 17 00:00:00 2001 From: tjroach Date: Tue, 2 Jul 2024 13:45:53 -0400 Subject: [PATCH 2/5] checkstyle --- .../com/amplifyframework/api/aws/RestApiInstrumentationTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/aws-api/src/androidTest/java/com/amplifyframework/api/aws/RestApiInstrumentationTest.java b/aws-api/src/androidTest/java/com/amplifyframework/api/aws/RestApiInstrumentationTest.java index 4481a6cd15..3cdec19452 100644 --- a/aws-api/src/androidTest/java/com/amplifyframework/api/aws/RestApiInstrumentationTest.java +++ b/aws-api/src/androidTest/java/com/amplifyframework/api/aws/RestApiInstrumentationTest.java @@ -33,7 +33,6 @@ import org.junit.BeforeClass; import org.junit.Test; - import static androidx.test.core.app.ApplicationProvider.getApplicationContext; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; From f7aa456f8ed59da5e0ebd02e7965e06232619565 Mon Sep 17 00:00:00 2001 From: tjroach Date: Tue, 2 Jul 2024 14:25:54 -0400 Subject: [PATCH 3/5] fix test --- .../cognito/RealAWSCognitoAuthPluginTest.kt | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) 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 87c1381965..9ab7a83f23 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 @@ -65,6 +65,7 @@ import com.amplifyframework.auth.cognito.options.AWSCognitoAuthUpdateUserAttribu import com.amplifyframework.auth.cognito.options.AWSCognitoAuthUpdateUserAttributesOptions import com.amplifyframework.auth.cognito.options.AWSCognitoAuthVerifyTOTPSetupOptions import com.amplifyframework.auth.cognito.options.AuthFlowType +import com.amplifyframework.auth.cognito.usecases.ResetPasswordUseCase import com.amplifyframework.auth.exceptions.InvalidStateException import com.amplifyframework.auth.exceptions.SignedOutException import com.amplifyframework.auth.options.AuthConfirmResetPasswordOptions @@ -95,11 +96,13 @@ import com.amplifyframework.statemachine.codegen.states.AuthenticationState import com.amplifyframework.statemachine.codegen.states.AuthorizationState import featureTest.utilities.APICaptorFactory.Companion.onError import io.mockk.coEvery +import io.mockk.coJustRun import io.mockk.coVerify import io.mockk.every import io.mockk.invoke import io.mockk.justRun import io.mockk.mockk +import io.mockk.mockkConstructor import io.mockk.mockkObject import io.mockk.mockkStatic import io.mockk.slot @@ -407,6 +410,47 @@ class RealAWSCognitoAuthPluginTest { verify(exactly = 0) { onSuccess.accept(any()) } assertEquals(expectedAuthError.toString(), errorCaptor.captured.toString()) } + @Test + fun `reset password executes ResetPasswordUseCase if required params are set`() { + // GIVEN + val onSuccess = mockk>() + val onError = mockk>() + val options = mockk() + val username = "user" + val pinpointAppId = "abc" + val encodedData = "encodedData" + + coEvery { + authEnvironment.getUserContextData(username) + } returns encodedData + + every { + authEnvironment.getPinpointEndpointId() + } returns pinpointAppId + + mockkConstructor(ResetPasswordUseCase::class) + + every { authService.cognitoIdentityProviderClient } returns mockk() + every { authConfiguration.userPool } returns UserPoolConfiguration.invoke { appClientId = "app Client Id" } + coJustRun { + anyConstructed().execute( + username, + options, + encodedData, + pinpointAppId, + onSuccess, + onError + ) + } + + // WHEN + plugin.resetPassword(username, options, onSuccess, onError) + + // THEN + coVerify { + anyConstructed().execute(username, options, any(), pinpointAppId, onSuccess, onError) + } + } @Test fun `fetch user attributes with success`() { From 966c33bd7b718252a5d359742492517899ef82f1 Mon Sep 17 00:00:00 2001 From: tjroach Date: Tue, 2 Jul 2024 14:56:14 -0400 Subject: [PATCH 4/5] fix test --- ...ialStoreStateMachineInstrumentationTest.kt | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/CredentialStoreStateMachineInstrumentationTest.kt diff --git a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/CredentialStoreStateMachineInstrumentationTest.kt b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/CredentialStoreStateMachineInstrumentationTest.kt new file mode 100644 index 0000000000..2e0985320c --- /dev/null +++ b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/CredentialStoreStateMachineInstrumentationTest.kt @@ -0,0 +1,61 @@ +/* + * 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 + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import com.amplifyframework.auth.cognito.data.AWSCognitoAuthCredentialStore +import com.amplifyframework.auth.cognito.testutils.AuthConfigurationProvider +import com.amplifyframework.auth.cognito.testutils.CredentialStoreUtil +import com.google.gson.Gson +import junit.framework.TestCase.assertEquals +import org.json.JSONObject +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class CredentialStoreStateMachineInstrumentationTest { + private val context = InstrumentationRegistry.getInstrumentation().context + + private val configuration = AuthConfigurationProvider.getAuthConfigurationObject() + private val userPoolId = configuration.userPool.userPool.PoolId + private val identityPoolId = configuration.credentials.cognitoIdentity.identityData.PoolId + private val userPoolAppClientId = configuration.userPool.userPool.AppClientId + + private val credential = CredentialStoreUtil.getDefaultCredential() + + @Before + fun setup() { + CredentialStoreUtil.setupLegacyStore(context, userPoolAppClientId, userPoolId, identityPoolId) + } + + private val authConfigJson = JSONObject(Gson().toJson(configuration)) + + @Test + fun test_CredentialStore_Migration_Succeeds_On_Plugin_Configuration() { + val plugin = AWSCognitoAuthPlugin() + plugin.configure(authConfigJson, context) + plugin.initialize(context) + + val receivedCredentials = AWSCognitoAuthCredentialStore( + context, + AuthConfiguration.fromJson(authConfigJson) + ).retrieveCredential() + + assertEquals(credential, receivedCredentials) + } +} From 159134a689e8e4700bcc8e26bd9119adc778e1d5 Mon Sep 17 00:00:00 2001 From: tjroach Date: Tue, 2 Jul 2024 15:05:24 -0400 Subject: [PATCH 5/5] fix test --- .../auth/cognito/AuthCanaryTest.kt | 22 +++++++++++++++++++ .../auth/cognito/AuthCanaryTestGen2.kt | 22 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AuthCanaryTest.kt b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AuthCanaryTest.kt index 2b1c50474c..0058fb5c0f 100644 --- a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AuthCanaryTest.kt +++ b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AuthCanaryTest.kt @@ -191,6 +191,28 @@ class AuthCanaryTest { assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) } + @Test + fun rememberDevice() { + signInUser(username, password) + val latch = CountDownLatch(1) + Amplify.Auth.rememberDevice( + { latch.countDown() }, + { fail("Remember device failed: $it") } + ) + assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) + } + + @Test + fun forgetDevice() { + signInUser(username, password) + val latch = CountDownLatch(1) + Amplify.Auth.forgetDevice( + { latch.countDown() }, + { fail("Forget device failed with error: $it") } + ) + assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) + } + @Test fun fetchDevices() { signInUser(username, password) diff --git a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AuthCanaryTestGen2.kt b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AuthCanaryTestGen2.kt index 28544d96f0..4bdf413eea 100644 --- a/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AuthCanaryTestGen2.kt +++ b/aws-auth-cognito/src/androidTest/java/com/amplifyframework/auth/cognito/AuthCanaryTestGen2.kt @@ -201,6 +201,28 @@ class AuthCanaryTestGen2 { assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) } + @Test + fun rememberDevice() { + signInUser(username, password) + val latch = CountDownLatch(1) + Amplify.Auth.rememberDevice( + { latch.countDown() }, + { fail("Remember device failed: $it") } + ) + assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) + } + + @Test + fun forgetDevice() { + signInUser(username, password) + val latch = CountDownLatch(1) + Amplify.Auth.forgetDevice( + { latch.countDown() }, + { fail("Forget device failed with error: $it") } + ) + assertTrue(latch.await(TIMEOUT_S, TimeUnit.SECONDS)) + } + @Test fun fetchDevices() { signInUser(username, password)