diff --git a/AmplifyPlugins/Auth/AWSCognitoAuthPlugin.xcodeproj/project.pbxproj b/AmplifyPlugins/Auth/AWSCognitoAuthPlugin.xcodeproj/project.pbxproj index e8a9823920..1377be67fc 100644 --- a/AmplifyPlugins/Auth/AWSCognitoAuthPlugin.xcodeproj/project.pbxproj +++ b/AmplifyPlugins/Auth/AWSCognitoAuthPlugin.xcodeproj/project.pbxproj @@ -149,6 +149,7 @@ B4F3EA4F243A782700F23296 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4F3EA4C243A782700F23296 /* ViewController.swift */; }; B4F3EA50243A782700F23296 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4F3EA4D243A782700F23296 /* AppDelegate.swift */; }; B4F3EA51243A782700F23296 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4F3EA4E243A782700F23296 /* SceneDelegate.swift */; }; + D828362C2590527F0016173F /* BaseUserBehaviorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D828362B2590527F0016173F /* BaseUserBehaviorTest.swift */; }; D87D5864257EF27E004617B3 /* BaseAuthDeviceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D87D5863257EF27E004617B3 /* BaseAuthDeviceTest.swift */; }; FA1C817D25868C46006160E9 /* AWSCognitoAuthPluginAmplifyVersionableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA1C817C25868C46006160E9 /* AWSCognitoAuthPluginAmplifyVersionableTests.swift */; }; FA6B0EA8249443C90062AA59 /* AWSCognitoAuthPluginConfigTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA6B0EA7249443C90062AA59 /* AWSCognitoAuthPluginConfigTests.swift */; }; @@ -350,6 +351,7 @@ B4F3EA4E243A782700F23296 /* SceneDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; C49A4C812B0F973F5536DCC8 /* Pods-AWSAuthPlugin.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AWSAuthPlugin.release.xcconfig"; path = "Target Support Files/Pods-AWSAuthPlugin/Pods-AWSAuthPlugin.release.xcconfig"; sourceTree = ""; }; C5E50D8021B9740CB511898D /* Pods-AWSAuthPlugin.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AWSAuthPlugin.debug.xcconfig"; path = "Target Support Files/Pods-AWSAuthPlugin/Pods-AWSAuthPlugin.debug.xcconfig"; sourceTree = ""; }; + D828362B2590527F0016173F /* BaseUserBehaviorTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseUserBehaviorTest.swift; sourceTree = ""; }; D87D5863257EF27E004617B3 /* BaseAuthDeviceTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseAuthDeviceTest.swift; sourceTree = ""; }; E9289652B314AA0AA1F31BC8 /* Pods-HostApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HostApp.release.xcconfig"; path = "Target Support Files/Pods-HostApp/Pods-HostApp.release.xcconfig"; sourceTree = ""; }; FA1C817C25868C46006160E9 /* AWSCognitoAuthPluginAmplifyVersionableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AWSCognitoAuthPluginAmplifyVersionableTests.swift; sourceTree = ""; }; @@ -537,6 +539,7 @@ B4136E6B256D7AF30011210B /* UserBehaviorFetchAttributeTests.swift */, B4136E7B256D7B240011210B /* UserBehaviorResendCodeTests.swift */, B4136E75256D7B090011210B /* UserBehaviorUpdateAttributeTests.swift */, + D828362B2590527F0016173F /* BaseUserBehaviorTest.swift */, ); path = AuthUserBehaviorTests; sourceTree = ""; @@ -1529,6 +1532,7 @@ B4136E20256D757C0011210B /* AuthenticationProviderConfirmSignupTests.swift in Sources */, B4136E3E256D76960011210B /* AuthenticationProviderSignoutTests.swift in Sources */, B4136E5E256D7A690011210B /* AuthorizationProviderSessionSignInTests.swift in Sources */, + D828362C2590527F0016173F /* BaseUserBehaviorTest.swift in Sources */, B43B4E242565FEC3008F345D /* AWSCognitoAuthUserBehaviorTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/AuthUserBehaviorTests/BaseUserBehaviorTest.swift b/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/AuthUserBehaviorTests/BaseUserBehaviorTest.swift new file mode 100644 index 0000000000..fca5f16d45 --- /dev/null +++ b/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/AuthUserBehaviorTests/BaseUserBehaviorTest.swift @@ -0,0 +1,36 @@ +// +// Copyright 2018-2020 Amazon.com, +// Inc. or its affiliates. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import XCTest +@testable import Amplify +@testable import AWSCognitoAuthPlugin +@testable import AWSMobileClient + +class BaseUserBehaviorTest: XCTestCase { + + let apiTimeout = 2.0 + var authUserService: AuthUserServiceAdapter! + var mockAWSMobileClient: MockAWSMobileClient! + var plugin: AWSCognitoAuthPlugin! + + override func setUp() { + mockAWSMobileClient = MockAWSMobileClient() + authUserService = AuthUserServiceAdapter(awsMobileClient: mockAWSMobileClient!) + plugin = AWSCognitoAuthPlugin() + plugin?.configure(authenticationProvider: MockAuthenticationProviderBehavior(), + authorizationProvider: MockAuthorizationProviderBehavior(), + userService: authUserService, + deviceService: MockAuthDeviceServiceBehavior(), + hubEventHandler: MockAuthHubEventBehavior()) + } + + override func tearDown() { + plugin = nil + mockAWSMobileClient = nil + authUserService = nil + } +} diff --git a/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/AuthUserBehaviorTests/UserBehaviorChangePasswordTests.swift b/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/AuthUserBehaviorTests/UserBehaviorChangePasswordTests.swift index 5f45b136e9..49d7df4ab2 100644 --- a/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/AuthUserBehaviorTests/UserBehaviorChangePasswordTests.swift +++ b/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/AuthUserBehaviorTests/UserBehaviorChangePasswordTests.swift @@ -12,20 +12,6 @@ import XCTest @testable import AWSCognitoAuthPlugin @testable import AWSMobileClient -class UserBehaviorChangePasswordTests: XCTestCase { +class UserBehaviorChangePasswordTests: BaseUserBehaviorTest { - var authenticationProvider: AuthenticationProviderAdapter! - var mockAWSMobileClient: MockAWSMobileClient! - var plugin: AWSCognitoAuthPlugin! - - override func setUp() { - mockAWSMobileClient = MockAWSMobileClient() - authenticationProvider = AuthenticationProviderAdapter(awsMobileClient: mockAWSMobileClient!) - plugin = AWSCognitoAuthPlugin() - plugin?.configure(authenticationProvider: authenticationProvider, - authorizationProvider: MockAuthorizationProviderBehavior(), - userService: MockAuthUserServiceBehavior(), - deviceService: MockAuthDeviceServiceBehavior(), - hubEventHandler: MockAuthHubEventBehavior()) - } } diff --git a/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/AuthUserBehaviorTests/UserBehaviorConfirmAttributeTests.swift b/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/AuthUserBehaviorTests/UserBehaviorConfirmAttributeTests.swift index cb97268a60..211694e6ca 100644 --- a/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/AuthUserBehaviorTests/UserBehaviorConfirmAttributeTests.swift +++ b/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/AuthUserBehaviorTests/UserBehaviorConfirmAttributeTests.swift @@ -5,27 +5,438 @@ // SPDX-License-Identifier: Apache-2.0 // -import Foundation - import XCTest @testable import Amplify @testable import AWSCognitoAuthPlugin @testable import AWSMobileClient -class UserBehaviorConfirmAttributeTests: XCTestCase { - - var authenticationProvider: AuthenticationProviderAdapter! - var mockAWSMobileClient: MockAWSMobileClient! - var plugin: AWSCognitoAuthPlugin! - - override func setUp() { - mockAWSMobileClient = MockAWSMobileClient() - authenticationProvider = AuthenticationProviderAdapter(awsMobileClient: mockAWSMobileClient!) - plugin = AWSCognitoAuthPlugin() - plugin?.configure(authenticationProvider: authenticationProvider, - authorizationProvider: MockAuthorizationProviderBehavior(), - userService: MockAuthUserServiceBehavior(), - deviceService: MockAuthDeviceServiceBehavior(), - hubEventHandler: MockAuthHubEventBehavior()) +// swiftlint:disable file_length +// swiftlint:disable type_body_length +class UserBehaviorConfirmAttributeTests: BaseUserBehaviorTest { + + /// Test a successful confirmUpdateUserAttributes call + /// + /// - Given: an auth plugin with mocked service. Mocked service calls should mock a successul response + /// - When: + /// - I invoke confirmUpdateUserAttributes with confirmation code + /// - Then: + /// - I should get a successful result + /// + func testSuccessfulConfirmUpdateUserAttributes() { + + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.confirm(userAttribute: .email, confirmationCode: "code") { result in + switch result { + case .success: + resultExpectation.fulfill() + case .failure(let error): + XCTFail("Received failure with error \(error)") + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + // MARK: Service error handling test + + /// Test a confirmUpdateUserAttributes call with CodeMismatchException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// CodeMismatchException response + /// - When: + /// - I invoke confirmUpdateUserAttributes with confirmation code + /// - Then: + /// - I should get a .service error with .codeMismatch as underlyingError + /// + func testConfirmUpdateUserAttributesWithCodeMismatchException() { + + mockAWSMobileClient?.confirmUserAttributeMockResult = + AWSMobileClientError.codeMismatch(message: "Error") + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.confirm(userAttribute: .email, confirmationCode: "code") { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .codeMismatch = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be codeMismatch \(error)") + return + } + + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a confirmUpdateUserAttributes call with CodeExpiredException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// CodeExpiredException response + /// - When: + /// - I invoke confirmUpdateUserAttributes with confirmation code + /// - Then: + /// - I should get a .service error with .codeExpired as underlyingError + /// + func testConfirmUpdateUserAttributesWithExpiredCodeException() { + + mockAWSMobileClient?.confirmUserAttributeMockResult = + AWSMobileClientError.expiredCode(message: "Error") + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.confirm(userAttribute: .email, confirmationCode: "code") { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .codeExpired = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be codeExpired \(error)") + return + } + + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a confirmUpdateUserAttributes call with InternalErrorException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a InternalErrorException response + /// - When: + /// - I invoke confirmUpdateUserAttributes with confirmation code + /// - Then: + /// - I should get an .unknown error + /// + func testcConfirmUpdateUserAttributesWithInternalErrorException() { + + mockAWSMobileClient?.confirmUserAttributeMockResult = + AWSMobileClientError.internalError(message: "Error") + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.confirm(userAttribute: .email, confirmationCode: "code") { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .unknown = error else { + XCTFail("Should produce an unknown error instead of \(error)") + return + } + + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a confirmUpdateUserAttributes call with InvalidParameterException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// InvalidParameterException response + /// + /// - When: + /// - I invoke confirmUpdateUserAttributes with confirmation code + /// - Then: + /// - I should get a .service error with .invalidParameter as underlyingError + /// + func testConfirmUpdateUserAttributesWithInvalidParameterException() { + + mockAWSMobileClient?.confirmUserAttributeMockResult = + AWSMobileClientError.invalidParameter(message: "Error") + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.confirm(userAttribute: .email, confirmationCode: "code") { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .invalidParameter = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be invalidParameter \(error)") + return + } + + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a confirmUpdateUserAttributes call with LimitExceededException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// LimitExceededException response + /// + /// - When: + /// - I invoke confirmUpdateUserAttributes with confirmation code + /// - Then: + /// - I should get a .requestLimitExceeded error + /// + func testConfirmUpdateUserAttributesWithLimitExceededException() { + + mockAWSMobileClient?.confirmUserAttributeMockResult = + AWSMobileClientError.limitExceeded(message: "Error") + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.confirm(userAttribute: .email, confirmationCode: "code") { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .requestLimitExceeded = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be requestLimitExceeded \(error)") + return + } + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a confirmUpdateUserAttributes call with NotAuthorizedException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// NotAuthorizedException response + /// + /// - When: + /// - I invoke confirmUpdateUserAttributes with confirmation code + /// - Then: + /// - I should get a .notAuthorized error + /// + func testConfirmUpdateUserAttributesWithNotAuthorizedException() { + + mockAWSMobileClient?.confirmUserAttributeMockResult = + AWSMobileClientError.notAuthorized(message: "Error") + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.confirm(userAttribute: .email, confirmationCode: "code") { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .notAuthorized = error else { + XCTFail("Should produce notAuthorized error instead of \(error)") + return + } + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a confirmUpdateUserAttributes call with PasswordResetRequiredException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// PasswordResetRequiredException response + /// + /// - When: + /// - I invoke confirmUpdateUserAttributes with confirmation code + /// - Then: + /// - I should get a .service error with .passwordResetRequired as underlyingError + /// + func testConfirmUpdateUserAttributesWithPasswordResetRequiredException() { + + mockAWSMobileClient?.confirmUserAttributeMockResult = + AWSMobileClientError.passwordResetRequired(message: "Error") + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.confirm(userAttribute: .email, confirmationCode: "code") { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .passwordResetRequired = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be passwordResetRequired \(error)") + return + } + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a confirmUpdateUserAttributes call with ResourceNotFoundException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// ResourceNotFoundException response + /// + /// - When: + /// - I invoke confirmUpdateUserAttributes with confirmation code + /// - Then: + /// - I should get a .service error with .resourceNotFound as underlyingError + /// + func testConfirmUpdateUserAttributesWithResourceNotFoundException() { + + mockAWSMobileClient?.confirmUserAttributeMockResult = + AWSMobileClientError.resourceNotFound(message: "Error") + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.confirm(userAttribute: .email, confirmationCode: "code") { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .resourceNotFound = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be resourceNotFound \(error)") + return + } + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a confirmUpdateUserAttributes call with TooManyRequestsException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// TooManyRequestsException response + /// + /// - When: + /// - I invoke confirmUpdateUserAttributes with confirmation code + /// - Then: + /// - I should get a .service error with .requestLimitExceeded as underlyingError + /// + func testConfirmUpdateUserAttributesWithTooManyRequestsException() { + + mockAWSMobileClient?.confirmUserAttributeMockResult = + AWSMobileClientError.tooManyRequests(message: "Error") + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.confirm(userAttribute: .email, confirmationCode: "code") { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .requestLimitExceeded = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be requestLimitExceeded \(error)") + return + } + + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a confirmUpdateUserAttributes call with UserNotFound response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// UserNotConfirmedException response + /// + /// - When: + /// - I invoke confirmUpdateUserAttributes with confirmation code + /// - Then: + /// - I should get a .service error with .userNotConfirmed as underlyingError + /// + func testConfirmUpdateUserAttributesWithUserNotConfirmedException() { + + mockAWSMobileClient?.confirmUserAttributeMockResult = + AWSMobileClientError.userNotConfirmed(message: "Error") + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.confirm(userAttribute: .email, confirmationCode: "code") { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .userNotConfirmed = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be userNotConfirmed \(error)") + return + } + + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a confirmUpdateUserAttributes call with UserNotFound response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// UserNotFoundException response + /// + /// - When: + /// - I invoke confirmUpdateUserAttributes with confirmation code + /// - Then: + /// - I should get a .userNotFound error + /// + func testConfirmUpdateUserAttributesWithUserNotFoundException() { + + mockAWSMobileClient?.confirmUserAttributeMockResult = + AWSMobileClientError.userNotFound(message: "Error") + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.confirm(userAttribute: .email, confirmationCode: "code") { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .userNotFound = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be userNotFound \(error)") + return + } + + } + } + wait(for: [resultExpectation], timeout: apiTimeout) } } diff --git a/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/AuthUserBehaviorTests/UserBehaviorFetchAttributeTests.swift b/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/AuthUserBehaviorTests/UserBehaviorFetchAttributeTests.swift index 6f8bfdc613..537a9a7fa3 100644 --- a/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/AuthUserBehaviorTests/UserBehaviorFetchAttributeTests.swift +++ b/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/AuthUserBehaviorTests/UserBehaviorFetchAttributeTests.swift @@ -5,27 +5,352 @@ // SPDX-License-Identifier: Apache-2.0 // -import Foundation - import XCTest @testable import Amplify @testable import AWSCognitoAuthPlugin @testable import AWSMobileClient -class UserBehaviorFetchAttributeTests: XCTestCase { - - var authenticationProvider: AuthenticationProviderAdapter! - var mockAWSMobileClient: MockAWSMobileClient! - var plugin: AWSCognitoAuthPlugin! - - override func setUp() { - mockAWSMobileClient = MockAWSMobileClient() - authenticationProvider = AuthenticationProviderAdapter(awsMobileClient: mockAWSMobileClient!) - plugin = AWSCognitoAuthPlugin() - plugin?.configure(authenticationProvider: authenticationProvider, - authorizationProvider: MockAuthorizationProviderBehavior(), - userService: MockAuthUserServiceBehavior(), - deviceService: MockAuthDeviceServiceBehavior(), - hubEventHandler: MockAuthHubEventBehavior()) +class UserBehaviorFetchAttributesTests: BaseUserBehaviorTest { + + /// Test a successful fetchUserAttributes call with .done as next step + /// + /// - Given: an auth plugin with mocked service. Mocked service calls should mock a successul response + /// - When: + /// - I invoke fetchUserAttributes + /// - Then: + /// - I should get a successful result + /// + func testSuccessfulFetchUserAttributes() { + + mockAWSMobileClient?.getUserAttributeMockResult = .success(["email": "Amplify@amazon.com"]) + + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.fetchUserAttributes { result in + defer { + resultExpectation.fulfill() + } + switch result { + case .success(let attributes): + XCTAssertEqual(attributes[0].key, AuthUserAttributeKey(rawValue: "email")) + XCTAssertEqual(attributes[0].value, "Amplify@amazon.com") + case .failure(let error): + XCTFail("Received failure with error \(error)") + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a fetchUserAttributes call with invalid result + /// + /// - Given: an auth plugin with mocked service. Mocked service calls should mock an invalid response + /// - When: + /// - I invoke fetchUserAttributes + /// - Then: + /// - I should get an .unknown error + /// + func testFetchUserAttributesWithInvalidResult() { + + mockAWSMobileClient?.getUserAttributeMockResult = nil + + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.fetchUserAttributes { result in + defer { + resultExpectation.fulfill() + } + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .unknown = error else { + XCTFail("Should produce an unknown error") + return + } + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + // MARK: Service error handling test + + /// Test a fetchUserAttributes call with InternalErrorException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a InternalErrorException response + /// - When: + /// - I invoke fetchUserAttributes + /// - Then: + /// - I should get an .unknown error + /// + func testFetchUserAttributesWithInternalErrorException() { + + mockAWSMobileClient?.getUserAttributeMockResult = + .failure(AWSMobileClientError.internalError(message: "Error")) + + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.fetchUserAttributes { result in + defer { + resultExpectation.fulfill() + } + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .unknown = error else { + XCTFail("Should produce an unknown error instead of \(error)") + return + } + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a fetchUserAttributes call with InvalidParameterException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a InvalidParameterException response + /// - When: + /// - I invoke fetchUserAttributes + /// - Then: + /// - I should get a .service error with .invalidParameter as underlyingError + /// + func testFetchUserAttributesWithInvalidParameterException() { + + mockAWSMobileClient?.getUserAttributeMockResult = + .failure(AWSMobileClientError.invalidParameter(message: "Error")) + + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.fetchUserAttributes { result in + defer { + resultExpectation.fulfill() + } + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .invalidParameter = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be invalidParameter \(error)") + return + } + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a fetchUserAttributes call with InvalidParameterException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a NotAuthorizedException response + /// - When: + /// - I invoke fetchUserAttributes + /// - Then: + /// - I should get a .service error with .notAuthorized as underlyingError + /// + func testFetchUserAttributesWithNotAuthorizedException() { + + mockAWSMobileClient?.getUserAttributeMockResult = + .failure(AWSMobileClientError.notAuthorized(message: "Error")) + + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.fetchUserAttributes { result in + defer { + resultExpectation.fulfill() + } + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .notAuthorized = error else { + XCTFail("Should produce notAuthorized error instead of \(error)") + return + } + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a fetchUserAttributes call with PasswordResetRequiredException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// PasswordResetRequiredException response + /// + /// - When: + /// - I invoke fetchUserAttributes + /// - Then: + /// - I should get a .service error with .passwordResetRequired as underlyingError + /// + func testFetchUserAttributesWithPasswordResetRequiredException() { + + mockAWSMobileClient?.getUserAttributeMockResult = + .failure(AWSMobileClientError.passwordResetRequired(message: "Error")) + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.fetchUserAttributes { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .passwordResetRequired = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be passwordResetRequired \(error)") + return + } + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a fetchUserAttributes call with ResourceNotFoundException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// ResourceNotFoundException response + /// + /// - When: + /// - I invoke fetchUserAttributes + /// - Then: + /// - I should get a .service error with .resourceNotFound as underlyingError + /// + func testFetchUserAttributesWithResourceNotFoundException() { + + mockAWSMobileClient?.getUserAttributeMockResult = + .failure(AWSMobileClientError.resourceNotFound(message: "Error")) + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.fetchUserAttributes { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .resourceNotFound = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be passwordResetRequired \(error)") + return + } + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a fetchUserAttributes call with TooManyRequestsException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// TooManyRequestsException response + /// + /// - When: + /// - I invoke fetchUserAttributes + /// - Then: + /// - I should get a .service error with .requestLimitExceeded as underlyingError + /// + func testFetchUserAttributesWithTooManyRequestsException() { + + mockAWSMobileClient?.getUserAttributeMockResult = + .failure(AWSMobileClientError.tooManyRequests(message: "Error")) + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.fetchUserAttributes { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .requestLimitExceeded = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be requestLimitExceeded \(error)") + return + } + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a fetchUserAttributes call with UserNotConfirmedException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// UserNotConfirmedException response + /// + /// - When: + /// - I invoke fetchUserAttributes + /// - Then: + /// - I should get a .service error with .userNotConfirmed as underlyingError + /// + func testFetchUserAttributesWithUserNotConfirmedException() { + + mockAWSMobileClient?.getUserAttributeMockResult = + .failure(AWSMobileClientError.userNotConfirmed(message: "Error")) + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.fetchUserAttributes { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .userNotConfirmed = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be userNotConfirmed \(error)") + return + } + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a fetchUserAttributes call with UserNotFoundException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// UserNotFoundException response + /// + /// - When: + /// - I invoke fetchUserAttributes + /// - Then: + /// - I should get a .service error with .userNotFound as underlyingError + /// + func testFetchUserAttributesWithUserNotFoundException() { + + mockAWSMobileClient?.getUserAttributeMockResult = + .failure(AWSMobileClientError.userNotFound(message: "Error")) + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.fetchUserAttributes { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .userNotFound = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be userNotFound \(error)") + return + } + } + } + wait(for: [resultExpectation], timeout: apiTimeout) } } diff --git a/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/AuthUserBehaviorTests/UserBehaviorResendCodeTests.swift b/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/AuthUserBehaviorTests/UserBehaviorResendCodeTests.swift index b822842a84..1928bd7668 100644 --- a/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/AuthUserBehaviorTests/UserBehaviorResendCodeTests.swift +++ b/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/AuthUserBehaviorTests/UserBehaviorResendCodeTests.swift @@ -12,20 +12,6 @@ import XCTest @testable import AWSCognitoAuthPlugin @testable import AWSMobileClient -class UserBehaviorResendCodeTests: XCTestCase { +class UserBehaviorResendCodeTests: BaseUserBehaviorTest { - var authenticationProvider: AuthenticationProviderAdapter! - var mockAWSMobileClient: MockAWSMobileClient! - var plugin: AWSCognitoAuthPlugin! - - override func setUp() { - mockAWSMobileClient = MockAWSMobileClient() - authenticationProvider = AuthenticationProviderAdapter(awsMobileClient: mockAWSMobileClient!) - plugin = AWSCognitoAuthPlugin() - plugin?.configure(authenticationProvider: authenticationProvider, - authorizationProvider: MockAuthorizationProviderBehavior(), - userService: MockAuthUserServiceBehavior(), - deviceService: MockAuthDeviceServiceBehavior(), - hubEventHandler: MockAuthHubEventBehavior()) - } } diff --git a/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/AuthUserBehaviorTests/UserBehaviorUpdateAttributeTests.swift b/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/AuthUserBehaviorTests/UserBehaviorUpdateAttributeTests.swift index 89a57dc46c..76d0c92942 100644 --- a/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/AuthUserBehaviorTests/UserBehaviorUpdateAttributeTests.swift +++ b/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/AuthUserBehaviorTests/UserBehaviorUpdateAttributeTests.swift @@ -5,27 +5,667 @@ // SPDX-License-Identifier: Apache-2.0 // -import Foundation - import XCTest @testable import Amplify @testable import AWSCognitoAuthPlugin @testable import AWSMobileClient -class UserBehaviorUpdateAttributeTests: XCTestCase { +// swiftlint:disable file_length +// swiftlint:disable type_body_length +class UserBehaviorUpdateAttributesTests: BaseUserBehaviorTest { + + /// Test a successful updateUserAttributes call with .done as next step + /// + /// - Given: an auth plugin with mocked service. Mocked service calls should mock a successul response + /// - When: + /// - I invoke updateUserAttributes with AuthUserAttribute + /// - Then: + /// - I should get a successful result with .done as the next step + /// + func testSuccessfulUpdateUserAttributes() { + + mockAWSMobileClient?.updateUserAttributesMockResult = + .success([UserCodeDeliveryDetails(deliveryMedium: .email, + destination: "destination", + attributeName: "attributeName")]) + + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.update(userAttribute: AuthUserAttribute(.email, value: "Amplify@amazon.com")) { result in + defer { + resultExpectation.fulfill() + } + switch result { + case .success(let attributes): + guard case .done = attributes.nextStep else { + XCTFail("Result should be .done for next step") + return + } + case .failure(let error): + XCTFail("Received failure with error \(error)") + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a updateUserAttributes call with invalid result + /// + /// - Given: an auth plugin with mocked service. Mocked service calls should mock a invalid response + /// - When: + /// - I invoke updateUserAttributes with AuthUserAttribute + /// - Then: + /// - I should get an .unknown error + /// + func testUpdateUserAttributesWithInvalidResult() { + + mockAWSMobileClient?.updateUserAttributesMockResult = nil + + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.update(userAttribute: AuthUserAttribute(.email, value: "Amplify@amazon.com")) { result in + defer { + resultExpectation.fulfill() + } + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .unknown = error else { + XCTFail("Should produce an unknown error") + return + } + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + // MARK: Service error handling test + + /// Test a updateUserAttributes call with aliasExistsException response from service + /// + /// - Given: Given an auth plugin with mocked service. Mocked service should mock a + /// aliasExistsException response + /// - When: + /// - I invoke updateUserAttributes with AuthUserAttribute + /// - Then: + /// - I should get a .service error with .aliasExists as underlyingError + /// + func testUpdateUserAttributesWithAliasExistsException() { + + mockAWSMobileClient?.updateUserAttributesMockResult = + .failure(AWSMobileClientError.aliasExists(message: "Error")) + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.update(userAttribute: AuthUserAttribute(.email, value: "Amplify@amazon.com")) { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .aliasExists = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be aliasExists \(error)") + return + } + + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a updateUserAttributes call with CodeDeliveryFailureException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// CodeDeliveryException response + /// - When: + /// - I invoke updateUserAttributes with AuthUserAttribute + /// - Then: + /// - I should get a .service error with .codeDelivery as underlyingError + /// + func testUpdateUserAttributesWithCodeDeliveryFailureException() { + + mockAWSMobileClient?.updateUserAttributesMockResult = + .failure(AWSMobileClientError.codeDeliveryFailure(message: "Error")) + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.update(userAttribute: AuthUserAttribute(.email, value: "Amplify@amazon.com")) { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .codeDelivery = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be codeDelivery \(error)") + return + } + + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a updateUserAttributes call with CodeMismatchException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// CodeMismatchException response + /// - When: + /// - I invoke updateUserAttributes with AuthUserAttribute + /// - Then: + /// - I should get a .service error with .codeMismatch as underlyingError + /// + func testUpdateUserAttributesWithCodeMismatchException() { + + mockAWSMobileClient?.updateUserAttributesMockResult = + .failure(AWSMobileClientError.codeMismatch(message: "Error")) + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.update(userAttribute: AuthUserAttribute(.email, value: "Amplify@amazon.com")) { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .codeMismatch = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be codeMismatch \(error)") + return + } + + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a updateUserAttributes call with CodeExpiredException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// CodeExpiredException response + /// - When: + /// - I invoke updateUserAttributes with AuthUserAttribute + /// - Then: + /// - I should get a .service error with .codeExpired as underlyingError + /// + func testUpdateUserAttributesWithExpiredCodeException() { + + mockAWSMobileClient?.updateUserAttributesMockResult = + .failure(AWSMobileClientError.expiredCode(message: "Error")) + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.update(userAttribute: AuthUserAttribute(.email, value: "Amplify@amazon.com")) { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .codeExpired = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be codeExpired \(error)") + return + } + + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a updateUserAttributes call with InternalErrorException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a InternalErrorException response + /// - When: + /// - I invoke updateUserAttributes with AuthUserAttribute + /// - Then: + /// - I should get an .unknown error + /// + func testUpdateUserAttributesWithInternalErrorException() { + + mockAWSMobileClient?.signupMockResult = + .failure(AWSMobileClientError.internalError(message: "Error")) + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.update(userAttribute: AuthUserAttribute(.email, value: "Amplify@amazon.com")) { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .unknown = error else { + XCTFail("Should produce an unknown error instead of \(error)") + return + } + + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a updateUserAttributes call with InvalidEmailRoleAccessPolicy response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// CodeDeliveryFailureException response + /// - When: + /// - I invoke updateUserAttributes with AuthUserAttribute + /// - Then: + /// - I should get a -- + /// + func testUpdateUserAttributesWithInvalidEmailRoleAccessPolicyException() { + // TODO: Not implemented. + } + + /// Test a updateUserAttributes call with InvalidLambdaResponseException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// InvalidLambdaResponseException response + /// - When: + /// - I invoke updateUserAttributes with AuthUserAttribute + /// - Then: + /// - I should get a .service error with .lambda as underlyingError + /// + func testUpdateUserAttributesWithInvalidLambdaResponseException() { + mockAWSMobileClient?.updateUserAttributesMockResult = + .failure(AWSMobileClientError.invalidLambdaResponse(message: "Error")) + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.update(userAttribute: AuthUserAttribute(.email, value: "Amplify@amazon.com")) { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .lambda = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be lambda \(error)") + return + } + + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a updateUserAttributes call with InvalidParameterException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// InvalidParameterException response + /// + /// - When: + /// - I invoke updateUserAttributes with AuthUserAttribute + /// - Then: + /// - I should get a .service error with .invalidParameter as underlyingError + /// + func testUpdateUserAttributesWithInvalidParameterException() { + + mockAWSMobileClient?.updateUserAttributesMockResult = .failure(AWSMobileClientError.invalidParameter(message: "Error")) + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.update(userAttribute: AuthUserAttribute(.email, value: "Amplify@amazon.com")) { result in + defer { + resultExpectation.fulfill() + } - var authenticationProvider: AuthenticationProviderAdapter! - var mockAWSMobileClient: MockAWSMobileClient! - var plugin: AWSCognitoAuthPlugin! + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .invalidParameter = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be invalidParameter \(error)") + return + } - override func setUp() { - mockAWSMobileClient = MockAWSMobileClient() - authenticationProvider = AuthenticationProviderAdapter(awsMobileClient: mockAWSMobileClient!) - plugin = AWSCognitoAuthPlugin() - plugin?.configure(authenticationProvider: authenticationProvider, - authorizationProvider: MockAuthorizationProviderBehavior(), - userService: MockAuthUserServiceBehavior(), - deviceService: MockAuthDeviceServiceBehavior(), - hubEventHandler: MockAuthHubEventBehavior()) + } + } + wait(for: [resultExpectation], timeout: apiTimeout) } + + /// Test a updateUserAttributes call with InvalidSmsRoleAccessPolicy response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// CodeDeliveryFailureException response + /// - When: + /// - I invoke updateUserAttributes with AuthUserAttribute + /// - Then: + /// - I should get a -- + /// + func testUpdateUserAttributesWithinvalidSmsRoleAccessPolicyException() { + // TODO: Not implemented. + } + + /// Test a updateUserAttributes call with InvalidSmsRoleTrustRelationship response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// CodeDeliveryFailureException response + /// - When: + /// - I invoke updateUserAttributes with AuthUserAttribute + /// - Then: + /// - I should get a -- + /// + func testUpdateUserAttributesCodeWithInvalidSmsRoleTrustRelationshipException() { + // TODO: Not implemented. + } + + /// Test a updateUserAttributes call with NotAuthorizedException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// NotAuthorizedException response + /// + /// - When: + /// - I invoke updateUserAttributes with AuthUserAttribute + /// - Then: + /// - I should get a .notAuthorized error + /// + func testUpdateUserAttributesWithNotAuthorizedException() { + + mockAWSMobileClient?.updateUserAttributesMockResult = + .failure(AWSMobileClientError.notAuthorized(message: "Error")) + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.update(userAttribute: AuthUserAttribute(.email, value: "Amplify@amazon.com")) { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .notAuthorized = error else { + XCTFail("Should produce notAuthorized error instead of \(error)") + return + } + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a updateUserAttributes call with PasswordResetRequiredException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// PasswordResetRequiredException response + /// + /// - When: + /// - I invoke updateUserAttributes with AuthUserAttribute + /// - Then: + /// - I should get a .service error with .passwordResetRequired as underlyingError + /// + func testUpdateUserAttributesWithPasswordResetRequiredException() { + + mockAWSMobileClient?.updateUserAttributesMockResult = + .failure(AWSMobileClientError.passwordResetRequired(message: "Error")) + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.update(userAttribute: AuthUserAttribute(.email, value: "Amplify@amazon.com")) { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .passwordResetRequired = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be passwordResetRequired \(error)") + return + } + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a updateUserAttributes call with ResourceNotFoundException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// ResourceNotFoundException response + /// + /// - When: + /// - I invoke updateUserAttributes with AuthUserAttribute + /// - Then: + /// - I should get a .service error with .resourceNotFound as underlyingError + /// + func testUpdateUserAttributesWithResourceNotFoundException() { + + mockAWSMobileClient?.updateUserAttributesMockResult = + .failure(AWSMobileClientError.resourceNotFound(message: "Error")) + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.update(userAttribute: AuthUserAttribute(.email, value: "Amplify@amazon.com")) { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .resourceNotFound = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be resourceNotFound \(error)") + return + } + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a updateUserAttributes call with TooManyRequestsException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// TooManyRequestsException response + /// + /// - When: + /// - I invoke updateUserAttributes with AuthUserAttribute + /// - Then: + /// - I should get a .service error with .requestLimitExceeded as underlyingError + /// + func testUpdateUserAttributesWithTooManyRequestsException() { + + mockAWSMobileClient?.updateUserAttributesMockResult = + .failure(AWSMobileClientError.tooManyRequests(message: "Error")) + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.update(userAttribute: AuthUserAttribute(.email, value: "Amplify@amazon.com")) { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .requestLimitExceeded = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be requestLimitExceeded \(error)") + return + } + + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a updateUserAttributes call with UnexpectedLambdaException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// UnexpectedLambdaException response + /// + /// - When: + /// - I invoke updateUserAttributes with AuthUserAttribute + /// - Then: + /// - I should get a .service error with .lambda as underlyingError + /// + func testUpdateUserAttributesWithUnexpectedLambdaException() { + + mockAWSMobileClient?.updateUserAttributesMockResult = + .failure(AWSMobileClientError.unexpectedLambda(message: "Error")) + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.update(userAttribute: AuthUserAttribute(.email, value: "Amplify@amazon.com")) { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .lambda = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be lambda \(error)") + return + } + + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a updateUserAttributes call with UserLambdaValidationException response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// UserLambdaValidationException response + /// + /// - When: + /// - I invoke updateUserAttributes with AuthUserAttribute + /// - Then: + /// - I should get a .service error with .lambda as underlyingError + /// + func testUpdateUserAttributesWithUserLambdaValidationException() { + + mockAWSMobileClient?.updateUserAttributesMockResult = + .failure(AWSMobileClientError.userLambdaValidation(message: "Error")) + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.update(userAttribute: AuthUserAttribute(.email, value: "Amplify@amazon.com")) { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .lambda = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be lambda \(error)") + return + } + + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a updateUserAttributes call with UserNotFound response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// UserNotConfirmedException response + /// + /// - When: + /// - I invoke updateUserAttributes with AuthUserAttribute + /// - Then: + /// - I should get a .service error with .userNotConfirmed as underlyingError + /// + func testUpdateUserAttributesWithUserNotConfirmedException() { + + mockAWSMobileClient?.updateUserAttributesMockResult = .failure( + AWSMobileClientError.userNotConfirmed(message: "Error")) + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.update(userAttribute: AuthUserAttribute(.email, value: "Amplify@amazon.com")) { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .userNotConfirmed = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be userNotConfirmed \(error)") + return + } + + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + + /// Test a updateUserAttributes call with UserNotFound response from service + /// + /// - Given: an auth plugin with mocked service. Mocked service should mock a + /// UserNotFoundException response + /// + /// - When: + /// - I invoke updateUserAttributes with AuthUserAttribute + /// - Then: + /// - I should get a .userNotFound error + /// + func testUpdateUserAttributesWithUserNotFoundException() { + + mockAWSMobileClient?.updateUserAttributesMockResult = + .failure(AWSMobileClientError.userNotFound(message: "Error")) + let resultExpectation = expectation(description: "Should receive a result") + _ = plugin.update(userAttribute: AuthUserAttribute(.email, value: "Amplify@amazon.com")) { result in + defer { + resultExpectation.fulfill() + } + + switch result { + case .success: + XCTFail("Should return an error if the result from service is invalid") + case .failure(let error): + guard case .service(_, _, let underlyingError) = error else { + XCTFail("Should produce service error instead of \(error)") + return + } + guard case .userNotFound = (underlyingError as? AWSCognitoAuthError) else { + XCTFail("Underlying error should be userNotFound \(error)") + return + } + + } + } + wait(for: [resultExpectation], timeout: apiTimeout) + } + } diff --git a/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/Mocks/MockAWSMobileClient.swift b/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/Mocks/MockAWSMobileClient.swift index 2125e438a7..abc08cefbc 100644 --- a/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/Mocks/MockAWSMobileClient.swift +++ b/AmplifyPlugins/Auth/AWSCognitoAuthPluginTests/Mocks/MockAWSMobileClient.swift @@ -24,7 +24,7 @@ class MockAWSMobileClient: AWSMobileClientBehavior { var verifyUserAttributeMockResult: Result? var updateUserAttributesMockResult: Result<[UserCodeDeliveryDetails], Error>? var getUserAttributeMockResult: Result<[String: String], Error>? - var confirmUserAttributeMockResult: Result? + var confirmUserAttributeMockResult: Error? var changePasswordMockResult: Result? var forgotPasswordMockResult: Result? var confirmForgotPasswordMockResult: Result? @@ -132,7 +132,7 @@ class MockAWSMobileClient: AWSMobileClientBehavior { func confirmUpdateUserAttributes(attributeName: String, code: String, completionHandler: @escaping ((Error?) -> Void)) { - fatalError() + completionHandler(confirmUserAttributeMockResult) } func changePassword(currentPassword: String,