diff --git a/Amplify/Core/Support/DeviceInfo.swift b/Amplify/Core/Support/DeviceInfo.swift index c55e0d9baf..86ed7ca257 100644 --- a/Amplify/Core/Support/DeviceInfo.swift +++ b/Amplify/Core/Support/DeviceInfo.swift @@ -28,6 +28,7 @@ import AppKit /// ``` /// /// - Tag: DeviceInfo +@MainActor public struct DeviceInfo { private init() {} diff --git a/Amplify/DevMenu/Data/DeviceInfoHelper.swift b/Amplify/DevMenu/Data/DeviceInfoHelper.swift index 7f686a0a36..d80f74cb2a 100644 --- a/Amplify/DevMenu/Data/DeviceInfoHelper.swift +++ b/Amplify/DevMenu/Data/DeviceInfoHelper.swift @@ -10,6 +10,7 @@ import Foundation import UIKit /// Helper class to fetch information for Device Information Screen +@MainActor struct DeviceInfoHelper { static func getDeviceInformation() -> [DeviceInfoItem] { diff --git a/Amplify/DevMenu/Data/IssueInfo.swift b/Amplify/DevMenu/Data/IssueInfo.swift index 8e17eb4193..527642afd8 100644 --- a/Amplify/DevMenu/Data/IssueInfo.swift +++ b/Amplify/DevMenu/Data/IssueInfo.swift @@ -9,6 +9,7 @@ import Foundation /// Struct consisting of information required to report an issue +@MainActor struct IssueInfo { private var includeEnvironmentInfo: Bool diff --git a/Amplify/DevMenu/Data/IssueInfoHelper.swift b/Amplify/DevMenu/Data/IssueInfoHelper.swift index 4acd436b05..d23489bf00 100644 --- a/Amplify/DevMenu/Data/IssueInfoHelper.swift +++ b/Amplify/DevMenu/Data/IssueInfoHelper.swift @@ -9,6 +9,7 @@ import Foundation /// Helper class to generate markdown text for issue reporting +@MainActor struct IssueInfoHelper { private static let issueDescTitle = "Issue Description" diff --git a/Amplify/DevMenu/Trigger/LongPressGestureRecognizer.swift b/Amplify/DevMenu/Trigger/LongPressGestureRecognizer.swift index 9681a02e64..766f7b7730 100644 --- a/Amplify/DevMenu/Trigger/LongPressGestureRecognizer.swift +++ b/Amplify/DevMenu/Trigger/LongPressGestureRecognizer.swift @@ -47,13 +47,5 @@ class LongPressGestureRecognizer: NSObject, TriggerRecognizer, UIGestureRecogniz uiWindow?.addGestureRecognizer(recognizer) recognizer.delegate = self } - - deinit { - if let window = uiWindow { - window.removeGestureRecognizer(recognizer) - } - uiWindow = nil - triggerDelegate = nil - } } #endif diff --git a/Amplify/DevMenu/View/IssueReporter.swift b/Amplify/DevMenu/View/IssueReporter.swift index 6aa2ee9b6e..937fd49f76 100644 --- a/Amplify/DevMenu/View/IssueReporter.swift +++ b/Amplify/DevMenu/View/IssueReporter.swift @@ -95,36 +95,42 @@ struct IssueReporter: View { /// Open Amplify iOS issue logging screen on Github private func reportToGithub() { - let issueDescriptionMarkdown = - IssueInfoHelper.generateMarkdownForIssue( - issue: IssueInfo(issueDescription: issueDescription, - includeEnvInfo: includeEnvInfo, - includeDeviceInfo: includeDeviceInfo)) - - let urlString = amplifyIosNewIssueUrl + issueDescriptionMarkdown - guard let url = urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { - showAlertIfInvalidURL = true - return - } - guard let urlToOpen = URL(string: url) else { - showAlertIfInvalidURL = true - return + Task { + let issue = await IssueInfo(issueDescription: issueDescription, + includeEnvInfo: includeEnvInfo, + includeDeviceInfo: includeDeviceInfo) + let issueDescriptionMarkdown = + await IssueInfoHelper.generateMarkdownForIssue( + issue: issue) + + let urlString = amplifyIosNewIssueUrl + issueDescriptionMarkdown + guard let url = urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { + showAlertIfInvalidURL = true + return + } + guard let urlToOpen = URL(string: url) else { + showAlertIfInvalidURL = true + return + } + + await UIApplication.shared.open(urlToOpen) } - UIApplication.shared.open(urlToOpen) } /// Copy issue as a markdown string to clipboard private func copyToClipboard() { - let issue = IssueInfo(issueDescription: issueDescription, - includeEnvInfo: includeEnvInfo, - includeDeviceInfo: includeDeviceInfo) - let value = IssueInfoHelper.generateMarkdownForIssue(issue: issue) -#if os(iOS) - UIPasteboard.general.string = value -#elseif canImport(AppKit) - NSPasteboard.general.setString(value, forType: .string) -#endif + Task { + let issue = await IssueInfo(issueDescription: issueDescription, + includeEnvInfo: includeEnvInfo, + includeDeviceInfo: includeDeviceInfo) + let value = await IssueInfoHelper.generateMarkdownForIssue(issue: issue) + #if os(iOS) + UIPasteboard.general.string = value + #elseif canImport(AppKit) + NSPasteboard.general.setString(value, forType: .string) + #endif + } } } @@ -166,6 +172,7 @@ final class MultilineTextField: UIViewRepresentable { return view } + @MainActor @objc func dismissKeyboard() { UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/ASF/ASFDeviceInfo.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/ASF/ASFDeviceInfo.swift index fc6ad66239..ddb5d61259 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/ASF/ASFDeviceInfo.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/ASF/ASFDeviceInfo.swift @@ -8,6 +8,7 @@ import Foundation import Amplify +@MainActor struct ASFDeviceInfo: ASFDeviceBehavior { let id: String diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/ASF/AdvancedSecurityBehavior.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/ASF/AdvancedSecurityBehavior.swift index af6daa65e3..c5c688972b 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/ASF/AdvancedSecurityBehavior.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/ASF/AdvancedSecurityBehavior.swift @@ -15,7 +15,7 @@ protocol AdvancedSecurityBehavior { configuration: UserPoolConfigurationData) throws -> String } -protocol ASFDeviceBehavior { +protocol ASFDeviceBehavior: Sendable { var id: String { get } diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/ASF/CognitoUserPoolASF+KeyChain.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/ASF/CognitoUserPoolASF+KeyChain.swift index d1e9412a22..8949aee102 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/ASF/CognitoUserPoolASF+KeyChain.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/ASF/CognitoUserPoolASF+KeyChain.swift @@ -32,8 +32,8 @@ extension CognitoUserPoolASF { static func encodedContext(username: String, asfDeviceId: String, asfClient: AdvancedSecurityBehavior, - userPoolConfiguration: UserPoolConfigurationData) -> String? { - let deviceInfo: ASFDeviceBehavior = ASFDeviceInfo(id: asfDeviceId) + userPoolConfiguration: UserPoolConfigurationData) async -> String? { + let deviceInfo: ASFDeviceBehavior = await ASFDeviceInfo(id: asfDeviceId) let appInfo: ASFAppInfoBehavior = ASFAppInfo() do { diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/RefreshAuthorizationSession/UserPool/RefreshUserPoolTokens.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/RefreshAuthorizationSession/UserPool/RefreshUserPoolTokens.swift index cbd3fcbd60..a5d180b876 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/RefreshAuthorizationSession/UserPool/RefreshUserPoolTokens.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/RefreshAuthorizationSession/UserPool/RefreshUserPoolTokens.swift @@ -41,7 +41,7 @@ struct RefreshUserPoolTokens: Action { for: existingSignedIndata.username, credentialStoreClient: authEnv.credentialsClient) - let input = InitiateAuthInput.refreshAuthInput( + let input = await InitiateAuthInput.refreshAuthInput( username: existingSignedIndata.username, refreshToken: existingTokens.refreshToken, clientMetadata: [:], diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/ConfirmDevice.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/ConfirmDevice.swift index 889bdb33c8..22da95affb 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/ConfirmDevice.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/ConfirmDevice.swift @@ -36,7 +36,7 @@ struct ConfirmDevice: Action { deviceKey: deviceMetadata.deviceKey, password: deviceMetadata.deviceSecret) - let deviceName = DeviceInfo.current.name + let deviceName = await DeviceInfo.current.name let base64EncodedVerifier = passwordVerifier.passwordVerifier.base64EncodedString() let base64EncodedSalt = passwordVerifier.salt.base64EncodedString() diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/CustomSignIn/InitiateCustomAuth.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/CustomSignIn/InitiateCustomAuth.swift index 0dc41794d9..ff1c572f06 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/CustomSignIn/InitiateCustomAuth.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/CustomSignIn/InitiateCustomAuth.swift @@ -33,7 +33,7 @@ struct InitiateCustomAuth: Action { let asfDeviceId = try await CognitoUserPoolASF.asfDeviceID( for: username, credentialStoreClient: authEnv.credentialsClient) - let request = InitiateAuthInput.customAuth( + let request = await InitiateAuthInput.customAuth( username: username, clientMetadata: clientMetadata, asfDeviceId: asfDeviceId, diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/DeviceSRPAuth/InitiateAuthDeviceSRP.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/DeviceSRPAuth/InitiateAuthDeviceSRP.swift index bc7614301a..fde6beec31 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/DeviceSRPAuth/InitiateAuthDeviceSRP.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/DeviceSRPAuth/InitiateAuthDeviceSRP.swift @@ -45,7 +45,7 @@ struct InitiateAuthDeviceSRP: Action { srpKeyPair: srpKeyPair, clientTimestamp: Date()) - let request = RespondToAuthChallengeInput.deviceSRP( + let request = await RespondToAuthChallengeInput.deviceSRP( username: username, environment: userPoolEnv, deviceMetadata: deviceMetadata, diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/DeviceSRPAuth/VerifyDevicePasswordSRP.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/DeviceSRPAuth/VerifyDevicePasswordSRP.swift index 38b96dac1e..4bfa1397de 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/DeviceSRPAuth/VerifyDevicePasswordSRP.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/DeviceSRPAuth/VerifyDevicePasswordSRP.swift @@ -59,7 +59,7 @@ struct VerifyDevicePasswordSRP: Action { serverPublicBHexString: serverPublicB, srpClient: srpClient) - let request = RespondToAuthChallengeInput.devicePasswordVerifier( + let request = await RespondToAuthChallengeInput.devicePasswordVerifier( username: username, stateData: stateData, session: authResponse.session, diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/HostedUI/InitializeHostedUISignIn.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/HostedUI/InitializeHostedUISignIn.swift index 977c33134f..ca0de00abe 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/HostedUI/InitializeHostedUISignIn.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/HostedUI/InitializeHostedUISignIn.swift @@ -54,7 +54,7 @@ struct InitializeHostedUISignIn: Action { let asfDeviceId = try await CognitoUserPoolASF.asfDeviceID( for: username, credentialStoreClient: environment.credentialsClient) - let encodedData = CognitoUserPoolASF.encodedContext( + let encodedData = await CognitoUserPoolASF.encodedContext( username: username, asfDeviceId: asfDeviceId, asfClient: environment.cognitoUserPoolASFFactory(), diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/MigrateAuth/InitiateMigrateAuth.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/MigrateAuth/InitiateMigrateAuth.swift index ed1c98507f..34cf4ece9d 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/MigrateAuth/InitiateMigrateAuth.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/MigrateAuth/InitiateMigrateAuth.swift @@ -36,7 +36,7 @@ struct InitiateMigrateAuth: Action { let asfDeviceId = try await CognitoUserPoolASF.asfDeviceID( for: username, credentialStoreClient: authEnv.credentialsClient) - let request = InitiateAuthInput.migrateAuth( + let request = await InitiateAuthInput.migrateAuth( username: username, password: password, clientMetadata: clientMetadata, diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/SRPAuth/InitiateAuthSRP.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/SRPAuth/InitiateAuthSRP.swift index a2c2e23f35..b1645d0ee1 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/SRPAuth/InitiateAuthSRP.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/SRPAuth/InitiateAuthSRP.swift @@ -56,7 +56,7 @@ struct InitiateAuthSRP: Action { for: username, credentialStoreClient: authEnv.credentialsClient) - let request = InitiateAuthInput.srpInput( + let request = await InitiateAuthInput.srpInput( username: username, publicSRPAHexValue: srpKeyPair.publicKeyHexValue, authFlowType: authFlowType, diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/SRPAuth/VerifyPasswordSRP.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/SRPAuth/VerifyPasswordSRP.swift index bf09ea4f63..d6687065a7 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/SRPAuth/VerifyPasswordSRP.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/SRPAuth/VerifyPasswordSRP.swift @@ -57,7 +57,7 @@ struct VerifyPasswordSRP: Action { serverPublicBHexString: serverPublicB, srpClient: srpClient, poolId: userPoolEnv.userPoolConfiguration.poolId) - let request = RespondToAuthChallengeInput.passwordVerifier( + let request = await RespondToAuthChallengeInput.passwordVerifier( username: username, stateData: stateData, session: authResponse.session, diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/SoftwareTokenSetup/CompleteTOTPSetup.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/SoftwareTokenSetup/CompleteTOTPSetup.swift index 9b33c77138..ef4a63e26a 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/SoftwareTokenSetup/CompleteTOTPSetup.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/SoftwareTokenSetup/CompleteTOTPSetup.swift @@ -53,7 +53,7 @@ struct CompleteTOTPSetup: Action { credentialStoreClient: authEnv.credentialsClient) var userContextData: CognitoIdentityProviderClientTypes.UserContextDataType? - if let encodedData = CognitoUserPoolASF.encodedContext( + if let encodedData = await CognitoUserPoolASF.encodedContext( username: username, asfDeviceId: asfDeviceId, asfClient: userpoolEnv.cognitoUserPoolASFFactory(), diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/VerifySignInChallenge.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/VerifySignInChallenge.swift index 5761ac2d06..45c6556ce2 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/VerifySignInChallenge.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Actions/SignIn/VerifySignInChallenge.swift @@ -39,7 +39,7 @@ struct VerifySignInChallenge: Action { for: username, with: environment) - let input = RespondToAuthChallengeInput.verifyChallenge( + let input = await RespondToAuthChallengeInput.verifyChallenge( username: username, challengeType: challengeType, session: session, diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/HostedUI/HostedUIASWebAuthenticationSession.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/HostedUI/HostedUIASWebAuthenticationSession.swift index c32f91d089..75f6e44e19 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/HostedUI/HostedUIASWebAuthenticationSession.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/HostedUI/HostedUIASWebAuthenticationSession.swift @@ -110,6 +110,7 @@ class HostedUIASWebAuthenticationSession: NSObject, HostedUISessionBehavior { #if os(iOS) || os(macOS) extension HostedUIASWebAuthenticationSession: ASWebAuthenticationPresentationContextProviding { + @MainActor func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { return webPresentation ?? ASPresentationAnchor() } diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Utils/ConfirmSignUpInput+Amplify.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Utils/ConfirmSignUpInput+Amplify.swift index 12f057a7fb..6d3fea6612 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Utils/ConfirmSignUpInput+Amplify.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Utils/ConfirmSignUpInput+Amplify.swift @@ -15,7 +15,7 @@ extension ConfirmSignUpInput { asfDeviceId: String?, forceAliasCreation: Bool?, environment: UserPoolEnvironment - ) { + ) async { let configuration = environment.userPoolConfiguration let secretHash = ClientSecretHelper.calculateSecretHash( @@ -23,7 +23,7 @@ extension ConfirmSignUpInput { userPoolConfiguration: configuration) var userContextData: CognitoIdentityProviderClientTypes.UserContextDataType? if let asfDeviceId = asfDeviceId, - let encodedData = CognitoUserPoolASF.encodedContext( + let encodedData = await CognitoUserPoolASF.encodedContext( username: username, asfDeviceId: asfDeviceId, asfClient: environment.cognitoUserPoolASFFactory(), diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Utils/InitiateAuthInput+Amplify.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Utils/InitiateAuthInput+Amplify.swift index f42698d5a2..fbda1ffbc0 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Utils/InitiateAuthInput+Amplify.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Utils/InitiateAuthInput+Amplify.swift @@ -16,7 +16,7 @@ extension InitiateAuthInput { clientMetadata: [String: String], asfDeviceId: String, deviceMetadata: DeviceMetadata, - environment: UserPoolEnvironment) -> InitiateAuthInput { + environment: UserPoolEnvironment) async -> InitiateAuthInput { var authParameters = [ "USERNAME": username, "SRP_A": publicSRPAHexValue @@ -28,7 +28,7 @@ extension InitiateAuthInput { authParameters["CHALLENGE_NAME"] = "SRP_A" } - return buildInput(username: username, + return await buildInput(username: username, authFlowType: authFlowType.getClientFlowType(), authParameters: authParameters, clientMetadata: clientMetadata, @@ -41,12 +41,12 @@ extension InitiateAuthInput { clientMetadata: [String: String], asfDeviceId: String, deviceMetadata: DeviceMetadata, - environment: UserPoolEnvironment) -> InitiateAuthInput { + environment: UserPoolEnvironment) async -> InitiateAuthInput { let authParameters = [ "USERNAME": username ] - return buildInput(username: username, + return await buildInput(username: username, authFlowType: .customAuth, authParameters: authParameters, clientMetadata: clientMetadata, @@ -60,13 +60,13 @@ extension InitiateAuthInput { clientMetadata: [String: String], asfDeviceId: String, deviceMetadata: DeviceMetadata, - environment: UserPoolEnvironment) -> InitiateAuthInput { + environment: UserPoolEnvironment) async -> InitiateAuthInput { let authParameters = [ "USERNAME": username, "PASSWORD": password ] - return buildInput(username: username, + return await buildInput(username: username, authFlowType: .userPasswordAuth, authParameters: authParameters, clientMetadata: clientMetadata, @@ -80,13 +80,13 @@ extension InitiateAuthInput { clientMetadata: [String: String], asfDeviceId: String, deviceMetadata: DeviceMetadata, - environment: UserPoolEnvironment) -> InitiateAuthInput { + environment: UserPoolEnvironment) async -> InitiateAuthInput { let authParameters = [ "REFRESH_TOKEN": refreshToken ] - return buildInput(username: username, + return await buildInput(username: username, authFlowType: .refreshTokenAuth, authParameters: authParameters, clientMetadata: clientMetadata, @@ -102,7 +102,7 @@ extension InitiateAuthInput { clientMetadata: [String: String], asfDeviceId: String?, deviceMetadata: DeviceMetadata, - environment: UserPoolEnvironment) -> InitiateAuthInput { + environment: UserPoolEnvironment) async -> InitiateAuthInput { var authParameters = authParameters let configuration = environment.userPoolConfiguration @@ -123,7 +123,7 @@ extension InitiateAuthInput { var userContextData: CognitoIdentityProviderClientTypes.UserContextDataType? if let asfDeviceId = asfDeviceId, - let encodedData = CognitoUserPoolASF.encodedContext( + let encodedData = await CognitoUserPoolASF.encodedContext( username: username, asfDeviceId: asfDeviceId, asfClient: environment.cognitoUserPoolASFFactory(), diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Utils/RespondToAuthChallengeInput+Amplify.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Utils/RespondToAuthChallengeInput+Amplify.swift index 7ee75ff8b8..8132c97e28 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Utils/RespondToAuthChallengeInput+Amplify.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Utils/RespondToAuthChallengeInput+Amplify.swift @@ -19,14 +19,14 @@ extension RespondToAuthChallengeInput { clientMetadata: ClientMetadata, deviceMetadata: DeviceMetadata, asfDeviceId: String?, - environment: UserPoolEnvironment) -> RespondToAuthChallengeInput { + environment: UserPoolEnvironment) async -> RespondToAuthChallengeInput { let dateStr = stateData.clientTimestamp.utcString let challengeResponses = [ "USERNAME": username, "TIMESTAMP": dateStr, "PASSWORD_CLAIM_SECRET_BLOCK": secretBlock, "PASSWORD_CLAIM_SIGNATURE": signature] - return buildInput( + return await buildInput( username: username, challengeType: .passwordVerifier, challengeResponses: challengeResponses, @@ -43,12 +43,12 @@ extension RespondToAuthChallengeInput { deviceMetadata: DeviceMetadata, asfDeviceId: String?, session: String?, - publicHexValue: String) -> RespondToAuthChallengeInput { + publicHexValue: String) async -> RespondToAuthChallengeInput { let challengeResponses = [ "USERNAME": username, "SRP_A": publicHexValue ] - return buildInput( + return await buildInput( username: username, challengeType: .deviceSrpAuth, challengeResponses: challengeResponses, @@ -66,7 +66,7 @@ extension RespondToAuthChallengeInput { signature: String, deviceMetadata: DeviceMetadata, asfDeviceId: String?, - environment: UserPoolEnvironment) + environment: UserPoolEnvironment) async -> RespondToAuthChallengeInput { let dateStr = stateData.clientTimestamp.utcString let challengeResponses = [ @@ -74,7 +74,7 @@ extension RespondToAuthChallengeInput { "TIMESTAMP": dateStr, "PASSWORD_CLAIM_SECRET_BLOCK": secretBlock, "PASSWORD_CLAIM_SIGNATURE": signature] - return buildInput( + return await buildInput( username: username, challengeType: .devicePasswordVerifier, challengeResponses: challengeResponses, @@ -96,7 +96,7 @@ extension RespondToAuthChallengeInput { asfDeviceId: String?, attributes: [String: String], deviceMetadata: DeviceMetadata, - environment: UserPoolEnvironment) -> RespondToAuthChallengeInput { + environment: UserPoolEnvironment) async -> RespondToAuthChallengeInput { var challengeResponses = [ "USERNAME": username, @@ -107,7 +107,7 @@ extension RespondToAuthChallengeInput { attributes.forEach { challengeResponses[$0.key] = $0.value } - return buildInput( + return await buildInput( username: username, challengeType: challengeType, challengeResponses: challengeResponses, @@ -126,7 +126,7 @@ extension RespondToAuthChallengeInput { clientMetadata: ClientMetadata, asfDeviceId: String?, deviceMetadata: DeviceMetadata, - environment: UserPoolEnvironment) -> RespondToAuthChallengeInput { + environment: UserPoolEnvironment) async -> RespondToAuthChallengeInput { var challengeResponses = challengeResponses let userPoolClientId = environment.userPoolConfiguration.clientId if let clientSecret = environment.userPoolConfiguration.clientSecret { @@ -145,7 +145,7 @@ extension RespondToAuthChallengeInput { var userContextData: CognitoIdentityProviderClientTypes.UserContextDataType? if let asfDeviceId = asfDeviceId, - let encodedData = CognitoUserPoolASF.encodedContext( + let encodedData = await CognitoUserPoolASF.encodedContext( username: username, asfDeviceId: asfDeviceId, asfClient: environment.cognitoUserPoolASFFactory(), diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Utils/SignUpInput+Amplify.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Utils/SignUpInput+Amplify.swift index ab7a02c7aa..bec03bab9b 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Utils/SignUpInput+Amplify.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Utils/SignUpInput+Amplify.swift @@ -21,16 +21,16 @@ extension SignUpInput { validationData: [String: String]?, attributes: [String: String], asfDeviceId: String?, - environment: UserPoolEnvironment) { + environment: UserPoolEnvironment) async { let configuration = environment.userPoolConfiguration let secretHash = ClientSecretHelper.calculateSecretHash(username: username, userPoolConfiguration: configuration) - let validationData = Self.getValidationData(with: validationData) + let validationData = await Self.getValidationData(with: validationData) let convertedAttributes = Self.convertAttributes(attributes) var userContextData: CognitoIdentityProviderClientTypes.UserContextDataType? if let asfDeviceId = asfDeviceId, - let encodedData = CognitoUserPoolASF.encodedContext( + let encodedData = await CognitoUserPoolASF.encodedContext( username: username, asfDeviceId: asfDeviceId, asfClient: environment.cognitoUserPoolASFFactory(), @@ -52,41 +52,47 @@ extension SignUpInput { } private static func getValidationData(with devProvidedData: [String: String]?) - -> [CognitoIdentityProviderClientTypes.AttributeType]? { + async -> [CognitoIdentityProviderClientTypes.AttributeType]? { if let devProvidedData = devProvidedData { return devProvidedData.compactMap { (key, value) in return CognitoIdentityProviderClientTypes.AttributeType(name: key, value: value) - } + (cognitoValidationData ?? []) + } + (await cognitoValidationData ?? []) } - return cognitoValidationData + return await cognitoValidationData } private static var cognitoValidationData: [CognitoIdentityProviderClientTypes.AttributeType]? { -#if canImport(WatchKit) - let device = WKInterfaceDevice.current() -#elseif canImport(UIKit) - let device = UIDevice.current -#endif + get async { + #if canImport(WatchKit) + let device = WKInterfaceDevice.current() + #elseif canImport(UIKit) + let device = await UIDevice.current + #endif -#if canImport(WatchKit) || canImport(UIKit) - let bundle = Bundle.main - let bundleVersion = bundle.object(forInfoDictionaryKey: String(kCFBundleVersionKey)) as? String - let bundleShortVersion = bundle.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String - - return [ - .init(name: "cognito:iOSVersion", value: device.systemVersion), - .init(name: "cognito:systemName", value: device.systemName), - .init(name: "cognito:deviceName", value: device.name), - .init(name: "cognito:model", value: device.model), - .init(name: "cognito:idForVendor", value: device.identifierForVendor?.uuidString ?? ""), - .init(name: "cognito:bundleId", value: bundle.bundleIdentifier), - .init(name: "cognito:bundleVersion", value: bundleVersion ?? ""), - .init(name: "cognito:bundleShortV", value: bundleShortVersion ?? "") - ] -#else - return nil -#endif + #if canImport(WatchKit) || canImport(UIKit) + let bundle = Bundle.main + let bundleVersion = bundle.object(forInfoDictionaryKey: String(kCFBundleVersionKey)) as? String + let bundleShortVersion = bundle.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String + let systemVersion = await device.systemVersion + let systemName = await device.systemName + let name = await device.name + let model = await device.model + let idForVendor = await device.identifierForVendor?.uuidString ?? "" + return [ + .init(name: "cognito:iOSVersion", value: systemVersion), + .init(name: "cognito:systemName", value: systemName), + .init(name: "cognito:deviceName", value: name), + .init(name: "cognito:model", value: model), + .init(name: "cognito:idForVendor", value: idForVendor), + .init(name: "cognito:bundleId", value: bundle.bundleIdentifier), + .init(name: "cognito:bundleVersion", value: bundleVersion ?? ""), + .init(name: "cognito:bundleShortV", value: bundleShortVersion ?? "") + ] + #else + return nil + #endif + } } private static func convertAttributes(_ attributes: [String: String]) -> [CognitoIdentityProviderClientTypes.AttributeType] { diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthConfirmResetPasswordTask.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthConfirmResetPasswordTask.swift index a7b1b03e90..ceabc14ed2 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthConfirmResetPasswordTask.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthConfirmResetPasswordTask.swift @@ -62,7 +62,7 @@ class AWSAuthConfirmResetPasswordTask: AuthConfirmResetPasswordTask, DefaultLogg let asfDeviceId = try await CognitoUserPoolASF.asfDeviceID( for: request.username, credentialStoreClient: environment.credentialsClient) - let encodedData = CognitoUserPoolASF.encodedContext( + let encodedData = await CognitoUserPoolASF.encodedContext( username: request.username, asfDeviceId: asfDeviceId, asfClient: environment.cognitoUserPoolASFFactory(), diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthConfirmSignUpTask.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthConfirmSignUpTask.swift index c280dd400d..dbbb086118 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthConfirmSignUpTask.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthConfirmSignUpTask.swift @@ -35,7 +35,7 @@ class AWSAuthConfirmSignUpTask: AuthConfirmSignUpTask, DefaultLogger { let metadata = (request.options.pluginOptions as? AWSAuthConfirmSignUpOptions)?.metadata let forceAliasCreation = (request.options.pluginOptions as? AWSAuthConfirmSignUpOptions)?.forceAliasCreation let client = try userPoolEnvironment.cognitoUserPoolFactory() - let input = ConfirmSignUpInput(username: request.username, + let input = await ConfirmSignUpInput(username: request.username, confirmationCode: request.code, clientMetadata: metadata, asfDeviceId: asfDeviceId, diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthResendSignUpCodeTask.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthResendSignUpCodeTask.swift index 32402637a3..527b796585 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthResendSignUpCodeTask.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthResendSignUpCodeTask.swift @@ -62,7 +62,7 @@ class AWSAuthResendSignUpCodeTask: AuthResendSignUpCodeTask, DefaultLogger { let asfDeviceId = try await CognitoUserPoolASF.asfDeviceID( for: request.username, credentialStoreClient: environment.credentialsClient) - let encodedData = CognitoUserPoolASF.encodedContext( + let encodedData = await CognitoUserPoolASF.encodedContext( username: request.username, asfDeviceId: asfDeviceId, asfClient: environment.cognitoUserPoolASFFactory(), diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthResetPasswordTask.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthResetPasswordTask.swift index 9bf6712a49..823b0178e1 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthResetPasswordTask.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthResetPasswordTask.swift @@ -62,7 +62,7 @@ class AWSAuthResetPasswordTask: AuthResetPasswordTask, DefaultLogger { let asfDeviceId = try await CognitoUserPoolASF.asfDeviceID( for: request.username, credentialStoreClient: environment.credentialsClient) - let encodedData = CognitoUserPoolASF.encodedContext( + let encodedData = await CognitoUserPoolASF.encodedContext( username: request.username, asfDeviceId: asfDeviceId, asfClient: environment.cognitoUserPoolASFFactory(), diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthSignUpTask.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthSignUpTask.swift index a52c369507..9e86b68daf 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthSignUpTask.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/AWSAuthSignUpTask.swift @@ -41,7 +41,7 @@ class AWSAuthSignUpTask: AuthSignUpTask, DefaultLogger { into: [String: String]()) { $0[$1.key.rawValue] = $1.value } ?? [:] - let input = SignUpInput(username: request.username, + let input = await SignUpInput(username: request.username, password: request.password!, clientMetadata: metaData, validationData: validationData, diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/CognitoASFTests/ASFDeviceInfoTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/CognitoASFTests/ASFDeviceInfoTests.swift index f894fd6643..130388d752 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/CognitoASFTests/ASFDeviceInfoTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/CognitoASFTests/ASFDeviceInfoTests.swift @@ -10,9 +10,9 @@ import XCTest class ASFDeviceInfoTests: XCTestCase { - func testdeviceInfo() { - let asf = ASFDeviceInfo(id: "mockID") - let deviceFingerPrint = asf.deviceInfo() + func testdeviceInfo() async { + let asf = await ASFDeviceInfo(id: "mockID") + let deviceFingerPrint = await asf.deviceInfo() XCTAssertNotNil(deviceFingerPrint) } } diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/CognitoASFTests/CognitoUserPoolASFTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/CognitoASFTests/CognitoUserPoolASFTests.swift index 63e72819b2..b5dbf122cf 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/CognitoASFTests/CognitoUserPoolASFTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/CognitoASFTests/CognitoUserPoolASFTests.swift @@ -22,10 +22,11 @@ class CognitoUserPoolASFTests: XCTestCase { /// Given: A CognitoUserPoolASF /// When: userContextData is invoked /// Then: A non-empty string is returned - func testUserContextData_shouldReturnData() throws { + func testUserContextData_shouldReturnData() async throws { + let deviceInfo = await ASFDeviceInfo(id: "mockedDevice") let result = try userPool.userContextData( for: "TestUser", - deviceInfo: ASFDeviceInfo(id: "mockedDevice"), + deviceInfo: deviceInfo, appInfo: ASFAppInfo(), configuration: .testData ) diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ResolverTests/SignUpState/ConfirmSignUpInputTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ResolverTests/SignUpState/ConfirmSignUpInputTests.swift index f926817dc6..406b48a76c 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ResolverTests/SignUpState/ConfirmSignUpInputTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ResolverTests/SignUpState/ConfirmSignUpInputTests.swift @@ -13,7 +13,7 @@ import AWSCognitoIdentityProvider class ConfirmSignUpInputTests: XCTestCase { - func testConfirmSignUpInputWithClientSecretAndAsfDeviceId() throws { + func testConfirmSignUpInputWithClientSecretAndAsfDeviceId() async throws { let username = "jeff" let clientSecret = UUID().uuidString let userPoolConfiguration = UserPoolConfigurationData(poolId: "", @@ -26,7 +26,7 @@ class ConfirmSignUpInputTests: XCTestCase { cognitoUserPoolASFFactory: Defaults.makeDefaultASF, cognitoUserPoolAnalyticsHandlerFactory: Defaults.makeUserPoolAnalytics) - let confirmSignUpInput = ConfirmSignUpInput( + let confirmSignUpInput = await ConfirmSignUpInput( username: username, confirmationCode: "123", clientMetadata: [:], @@ -38,7 +38,7 @@ class ConfirmSignUpInputTests: XCTestCase { XCTAssertNotNil(confirmSignUpInput.userContextData) } - func testConfirmSignUpInputWithoutClientSecretAndAsfDeviceId() throws { + func testConfirmSignUpInputWithoutClientSecretAndAsfDeviceId() async throws { let username = "jeff" let userPoolConfiguration = UserPoolConfigurationData(poolId: "", @@ -51,7 +51,7 @@ class ConfirmSignUpInputTests: XCTestCase { cognitoUserPoolASFFactory: Defaults.makeDefaultASF, cognitoUserPoolAnalyticsHandlerFactory: Defaults.makeUserPoolAnalytics) - let confirmSignUpInput = ConfirmSignUpInput( + let confirmSignUpInput = await ConfirmSignUpInput( username: username, confirmationCode: "123", clientMetadata: [:], diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ResolverTests/SignUpState/RespondToAuthInputTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ResolverTests/SignUpState/RespondToAuthInputTests.swift index 942ea7ed20..4bcbe80f42 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ResolverTests/SignUpState/RespondToAuthInputTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ResolverTests/SignUpState/RespondToAuthInputTests.swift @@ -13,7 +13,7 @@ import AWSCognitoIdentityProvider class RespondToAuthInputTests: XCTestCase { - func testDevicePasswordVerifierInput() throws { + func testDevicePasswordVerifierInput() async throws { let username = "jeff" let clientSecret = UUID().uuidString let userPoolConfiguration = UserPoolConfigurationData(poolId: "", @@ -26,7 +26,7 @@ class RespondToAuthInputTests: XCTestCase { cognitoUserPoolASFFactory: Defaults.makeDefaultASF, cognitoUserPoolAnalyticsHandlerFactory: Defaults.makeUserPoolAnalytics) - let respondToAuthChallengeInput = RespondToAuthChallengeInput.devicePasswordVerifier( + let respondToAuthChallengeInput = await RespondToAuthChallengeInput.devicePasswordVerifier( username: username, stateData: .testData, session: "session", @@ -40,7 +40,7 @@ class RespondToAuthInputTests: XCTestCase { XCTAssertNotNil(respondToAuthChallengeInput.userContextData) } - func testVerifyChallengeInput() throws { + func testVerifyChallengeInput() async throws { let username = "jeff" let clientSecret = UUID().uuidString let userPoolConfiguration = UserPoolConfigurationData(poolId: "", @@ -53,7 +53,7 @@ class RespondToAuthInputTests: XCTestCase { cognitoUserPoolASFFactory: Defaults.makeDefaultASF, cognitoUserPoolAnalyticsHandlerFactory: Defaults.makeUserPoolAnalytics) - let respondToAuthChallengeInput = RespondToAuthChallengeInput.verifyChallenge( + let respondToAuthChallengeInput = await RespondToAuthChallengeInput.verifyChallenge( username: username, challengeType: .smsMfa, session: "session", @@ -69,7 +69,7 @@ class RespondToAuthInputTests: XCTestCase { XCTAssertNotNil(respondToAuthChallengeInput.userContextData) } - func testPasswordVerifierInput() throws { + func testPasswordVerifierInput() async throws { let username = "jeff" let clientSecret = UUID().uuidString let userPoolConfiguration = UserPoolConfigurationData(poolId: "", @@ -82,7 +82,7 @@ class RespondToAuthInputTests: XCTestCase { cognitoUserPoolASFFactory: Defaults.makeDefaultASF, cognitoUserPoolAnalyticsHandlerFactory: Defaults.makeUserPoolAnalytics) - let respondToAuthChallengeInput = RespondToAuthChallengeInput.passwordVerifier( + let respondToAuthChallengeInput = await RespondToAuthChallengeInput.passwordVerifier( username: username, stateData: .testData, session: "session", @@ -98,7 +98,7 @@ class RespondToAuthInputTests: XCTestCase { XCTAssertNotNil(respondToAuthChallengeInput.userContextData) } - func testDeviceSrpInput() throws { + func testDeviceSrpInput() async throws { let username = "jeff" let clientSecret = UUID().uuidString let userPoolConfiguration = UserPoolConfigurationData(poolId: "", @@ -111,7 +111,7 @@ class RespondToAuthInputTests: XCTestCase { cognitoUserPoolASFFactory: Defaults.makeDefaultASF, cognitoUserPoolAnalyticsHandlerFactory: Defaults.makeUserPoolAnalytics) - let respondToAuthChallengeInput = RespondToAuthChallengeInput.deviceSRP( + let respondToAuthChallengeInput = await RespondToAuthChallengeInput.deviceSRP( username: username, environment: environment, deviceMetadata: .metadata(.init(deviceKey: "", deviceGroupKey: "")), diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ResolverTests/SignUpState/SignUpInputTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ResolverTests/SignUpState/SignUpInputTests.swift index 67e9c21add..2e834c6d32 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ResolverTests/SignUpState/SignUpInputTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ResolverTests/SignUpState/SignUpInputTests.swift @@ -13,7 +13,7 @@ import AWSCognitoIdentityProvider class SignUpInputTests: XCTestCase { - func testSignUpInputWithClientSecret() throws { + func testSignUpInputWithClientSecret() async throws { let username = "jeff" let password = "a2z" let clientSecret = UUID().uuidString @@ -26,7 +26,7 @@ class SignUpInputTests: XCTestCase { cognitoUserPoolFactory: Defaults.makeDefaultUserPool, cognitoUserPoolASFFactory: Defaults.makeDefaultASF, cognitoUserPoolAnalyticsHandlerFactory: Defaults.makeUserPoolAnalytics) - let input = SignUpInput(username: username, + let input = await SignUpInput(username: username, password: password, clientMetadata: [:], validationData: [:], @@ -38,7 +38,7 @@ class SignUpInputTests: XCTestCase { XCTAssertNotNil(input.userContextData) } - func testSignUpInputWithoutClientSecret() throws { + func testSignUpInputWithoutClientSecret() async throws { let username = "jeff" let password = "a2z" @@ -51,7 +51,7 @@ class SignUpInputTests: XCTestCase { cognitoUserPoolFactory: Defaults.makeDefaultUserPool, cognitoUserPoolASFFactory: Defaults.makeDefaultASF, cognitoUserPoolAnalyticsHandlerFactory: Defaults.makeUserPoolAnalytics) - let input = SignUpInput(username: username, + let input = await SignUpInput(username: username, password: password, clientMetadata: [:], validationData: [:], @@ -64,7 +64,7 @@ class SignUpInputTests: XCTestCase { } #if canImport(UIKit) - func testSignUpInputValidationData() throws { + func testSignUpInputValidationData() async throws { let username = "jeff" let password = "a2z" let clientSecret = UUID().uuidString @@ -77,7 +77,7 @@ class SignUpInputTests: XCTestCase { cognitoUserPoolFactory: Defaults.makeDefaultUserPool, cognitoUserPoolASFFactory: Defaults.makeDefaultASF, cognitoUserPoolAnalyticsHandlerFactory: Defaults.makeUserPoolAnalytics) - let input = SignUpInput(username: username, + let input = await SignUpInput(username: username, password: password, clientMetadata: [:], validationData: [:], diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AmplifyAuthCognitoPluginTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AmplifyAuthCognitoPluginTests.swift index 064ccb693c..eef6bf85c1 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AmplifyAuthCognitoPluginTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AmplifyAuthCognitoPluginTests.swift @@ -35,71 +35,66 @@ class AmplifyAuthCognitoPluginTests: XCTestCase { subdirectory: "\(AuthTestHarnessConstants.testSuitesPath)/\(directory)" ) let authTestHarness = await AuthTestHarness(featureSpecification: specification) - XCTContext.runActivity(named: testSuiteFile) { activity in - beginTest(for: authTestHarness.plugin, - with: authTestHarness) - } + await beginTest(for: authTestHarness.plugin, with: authTestHarness) } } } func beginTest( for plugin: AWSCognitoAuthPlugin, - with testHarness: AuthTestHarness) { + with testHarness: AuthTestHarness) async { switch testHarness.apiUnderTest { case .resetPassword(let resetPasswordRequest, let expectedOutput): - validateAPI(expectedOutput: expectedOutput) { + await validateAPI(expectedOutput: expectedOutput) { return try await plugin.resetPassword( for: resetPasswordRequest.username, options: resetPasswordRequest.options) } case .signUp(let signUpRequest, let expectedOutput): - validateAPI(expectedOutput: expectedOutput) { + await validateAPI(expectedOutput: expectedOutput) { return try await plugin.signUp( username: signUpRequest.username, password: signUpRequest.password, options: signUpRequest.options) } case .signIn(let request, let expectedOutput): - validateAPI(expectedOutput: expectedOutput) { + await validateAPI(expectedOutput: expectedOutput) { return try await plugin.signIn( username: request.username, password: request.password, options: request.options) } case .fetchAuthSession(let request, let expectedOutput): - validateAPI(expectedOutput: expectedOutput) { + await validateAPI(expectedOutput: expectedOutput) { return try await plugin.fetchAuthSession(options: request.options) as! AWSAuthCognitoSession } case .signOut(let request, let expectedOutput): - validateAPI(expectedOutput: expectedOutput) { + await validateAPI(expectedOutput: expectedOutput) { return await plugin.signOut(options: request.options) as! AWSCognitoSignOutResult } case .deleteUser(_, let expectedOutput): let expectation = expectation(description: "expectation") - Task { - do { - try await plugin.deleteUser() - expectation.fulfill() - } catch let error as AuthError { - if case .failure(let expectedError) = expectedOutput { - XCTAssertEqual(error, expectedError) - } else { - XCTFail("API should not throw AuthError") - } - expectation.fulfill() - } catch { + do { + try await plugin.deleteUser() + expectation.fulfill() + } catch let error as AuthError { + if case .failure(let expectedError) = expectedOutput { + XCTAssertEqual(error, expectedError) + } else { XCTFail("API should not throw AuthError") - expectation.fulfill() } + expectation.fulfill() + } catch { + XCTFail("API should not throw AuthError") + expectation.fulfill() } - wait(for: [expectation], timeout: apiTimeout) + await fulfillment(of: [expectation], timeout: apiTimeout) case .confirmSignIn(let request, expectedOutput: let expectedOutput): - validateAPI(expectedOutput: expectedOutput) { + await validateAPI(expectedOutput: expectedOutput) { return try await plugin.confirmSignIn( challengeResponse: request.challengeResponse, options: request.options) } @@ -111,22 +106,20 @@ class AmplifyAuthCognitoPluginTests: XCTestCase { // Helper to validate API Result func validateAPI( expectedOutput: Result?, - apiCall: @escaping () async throws -> T) { + apiCall: @escaping () async throws -> T) async { let expectation = expectation(description: "expectation") - Task { - do { - let result = try await apiCall() - XCTAssertEqual(expectedOutput, Result.success(result)) - expectation.fulfill() - } catch let error as AuthError { - XCTAssertEqual(expectedOutput, Result.failure(error)) - expectation.fulfill() - } catch { - XCTFail("API should not throw AuthError") - expectation.fulfill() - } + do { + let result = try await apiCall() + XCTAssertEqual(expectedOutput, Result.success(result)) + expectation.fulfill() + } catch let error as AuthError { + XCTAssertEqual(expectedOutput, Result.failure(error)) + expectation.fulfill() + } catch { + XCTFail("API should not throw AuthError") + expectation.fulfill() } - wait(for: [expectation], timeout: apiTimeout) + await fulfillment(of: [expectation], timeout: apiTimeout) } } diff --git a/AmplifyPlugins/Core/AmplifyCredentials/AmplifyAWSServiceConfiguration.swift b/AmplifyPlugins/Core/AmplifyCredentials/AmplifyAWSServiceConfiguration.swift index fd835f7715..cac65bb4f3 100644 --- a/AmplifyPlugins/Core/AmplifyCredentials/AmplifyAWSServiceConfiguration.swift +++ b/AmplifyPlugins/Core/AmplifyCredentials/AmplifyAWSServiceConfiguration.swift @@ -22,5 +22,6 @@ public class AmplifyAWSServiceConfiguration { public static let userAgentLib: String = "lib/\(platformName)#\(amplifyVersion)" + @MainActor public static let userAgentOS: String = "os/\(DeviceInfo.current.operatingSystem.name)#\(DeviceInfo.current.operatingSystem.version)" } diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/PinpointContext.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/PinpointContext.swift index ceeeab6cec..4267e99084 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/PinpointContext.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/PinpointContext.swift @@ -110,7 +110,7 @@ class PinpointContext { private let storage: PinpointContextStorage init(with configuration: PinpointContextConfiguration, - endpointInformation: EndpointInformation = .current, + endpointInformationProvider: EndpointInformationProvider = DefaultEndpointInformationProvider(), userDefaults: UserDefaultsBehaviour = UserDefaults.standard, keychainStore: KeychainStoreBehavior = KeychainStore(service: PinpointContext.Constants.Keychain.service), fileManager: FileManagerBehaviour = FileManager.default, @@ -130,7 +130,7 @@ class PinpointContext { uniqueDeviceId: uniqueId, isDebug: configuration.isDebug), pinpointClient: pinpointClient, - endpointInformation: endpointInformation, + endpointInformationProvider: endpointInformationProvider, userDefaults: userDefaults, keychain: keychainStore, remoteNotificationsHelper: remoteNotificationsHelper) diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/EndpointClient.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/EndpointClient.swift index f2203a7d0c..e89118f4bb 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/EndpointClient.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/EndpointClient.swift @@ -32,7 +32,7 @@ actor EndpointClient: EndpointClientBehaviour { private let configuration: EndpointClient.Configuration private let archiver: AmplifyArchiverBehaviour - private let endpointInformation: EndpointInformation + private let endpointInformationProvider: EndpointInformationProvider private let userDefaults: UserDefaultsBehaviour private let keychain: KeychainStoreBehavior private let remoteNotificationsHelper: RemoteNotificationsBehaviour @@ -43,7 +43,7 @@ actor EndpointClient: EndpointClientBehaviour { init(configuration: EndpointClient.Configuration, pinpointClient: PinpointClientProtocol, archiver: AmplifyArchiverBehaviour = AmplifyArchiver(), - endpointInformation: EndpointInformation = .current, + endpointInformationProvider: EndpointInformationProvider, userDefaults: UserDefaultsBehaviour = UserDefaults.standard, keychain: KeychainStoreBehavior = KeychainStore(service: PinpointContext.Constants.Keychain.service), remoteNotificationsHelper: RemoteNotificationsBehaviour = .default @@ -51,7 +51,7 @@ actor EndpointClient: EndpointClientBehaviour { self.configuration = configuration self.pinpointClient = pinpointClient self.archiver = archiver - self.endpointInformation = endpointInformation + self.endpointInformationProvider = endpointInformationProvider self.userDefaults = userDefaults self.keychain = keychain self.remoteNotificationsHelper = remoteNotificationsHelper @@ -100,6 +100,7 @@ actor EndpointClient: EndpointClientBehaviour { deviceToken = tokenData.asHexString() } + let endpointInformation = await endpointInformationProvider.endpointInfo() endpointProfile.endpointId = configuration.uniqueDeviceId endpointProfile.deviceToken = deviceToken endpointProfile.location = .init() diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/EndpointInformation.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/EndpointInformation.swift index 0c6c920591..399f91f74d 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/EndpointInformation.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/EndpointInformation.swift @@ -8,26 +8,24 @@ import Amplify import Foundation -protocol EndpointInformation { +struct EndpointInformation { typealias Platform = (name: String, version: String) - var model: String { get } - var appVersion: String { get } - var platform: Platform { get } + let model: String + let appVersion: String + let platform: Platform } -extension DeviceInfo: EndpointInformation { - var appVersion: String { - Bundle.main.appVersion - } - - var platform: Platform { - operatingSystem - } +protocol EndpointInformationProvider { + func endpointInfo() async -> EndpointInformation } -extension EndpointInformation where Self == DeviceInfo { - static var current: EndpointInformation { - DeviceInfo.current +struct DefaultEndpointInformationProvider: EndpointInformationProvider { + func endpointInfo() async -> EndpointInformation { + let deviceInfo = await DeviceInfo.current + let model = await deviceInfo.model + let platform = await deviceInfo.operatingSystem + let appVersion = Bundle.main.appVersion + return EndpointInformation(model: model, appVersion: appVersion, platform: platform) } } diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/ActivityTracking/ActivityTracker.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/ActivityTracking/ActivityTracker.swift index 1b64474a61..d85da389d3 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/ActivityTracking/ActivityTracker.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/ActivityTracking/ActivityTracker.swift @@ -81,6 +81,7 @@ class ActivityTracker: ActivityTrackerBehaviour { private let stateMachine: StateMachine private var stateMachineSubscriberToken: StateMachineSubscriberToken? + @MainActor private static let applicationDidMoveToBackgroundNotification: Notification.Name = { #if canImport(WatchKit) WKExtension.applicationDidEnterBackgroundNotification @@ -91,7 +92,8 @@ class ActivityTracker: ActivityTrackerBehaviour { #endif }() - private static let applicationWillMoveToForegoundNotification: Notification.Name = { + @MainActor + private static let applicationWillMoveToForegoundNotification: Notification.Name = { #if canImport(WatchKit) WKExtension.applicationWillEnterForegroundNotification #elseif canImport(UIKit) @@ -101,7 +103,8 @@ class ActivityTracker: ActivityTrackerBehaviour { #endif }() - private static var applicationWillTerminateNotification: Notification.Name = { + @MainActor + private static var applicationWillTerminateNotification: Notification.Name = { #if canImport(WatchKit) // There's no willTerminateNotification on watchOS, so using applicationWillResignActive instead. WKExtension.applicationWillResignActiveNotification @@ -112,7 +115,8 @@ class ActivityTracker: ActivityTrackerBehaviour { #endif }() - private let notifications = [ + @MainActor + private static let notifications = [ applicationDidMoveToBackgroundNotification, applicationWillMoveToForegoundNotification, applicationWillTerminateNotification @@ -123,7 +127,8 @@ class ActivityTracker: ActivityTrackerBehaviour { self.backgroundTrackingTimeout = backgroundTrackingTimeout self.stateMachine = stateMachine ?? StateMachine(initialState: .initializing, resolver: ApplicationState.Resolver.resolve(currentState:event:)) - for notification in notifications { + + for notification in ActivityTracker.notifications { NotificationCenter.default.addObserver(self, selector: #selector(handleApplicationStateChange), name: notification, @@ -132,7 +137,7 @@ class ActivityTracker: ActivityTrackerBehaviour { } deinit { - for notification in notifications { + for notification in ActivityTracker.notifications { NotificationCenter.default.removeObserver(self, name: notification, object: nil) @@ -144,15 +149,16 @@ class ActivityTracker: ActivityTrackerBehaviour { stateMachineSubscriberToken = stateMachine.subscribe(listener) } + @MainActor private func beginBackgroundTracking() { - #if canImport(UIKit) && !os(watchOS) + #if canImport(UIKit) && !os(watchOS) if backgroundTrackingTimeout > 0 { backgroundTask = UIApplication.shared.beginBackgroundTask(withName: Constants.backgroundTask) { [weak self] in self?.stateMachine.process(.backgroundTrackingDidTimeout) self?.stopBackgroundTracking() } } - #endif + #endif guard backgroundTrackingTimeout != .infinity else { return } backgroundTimer = Timer.scheduledTimer(withTimeInterval: backgroundTrackingTimeout, repeats: false) { [weak self] _ in self?.stateMachine.process(.backgroundTrackingDidTimeout) @@ -160,6 +166,7 @@ class ActivityTracker: ActivityTrackerBehaviour { } } + @MainActor private func stopBackgroundTracking() { backgroundTimer = nil #if canImport(UIKit) && !os(watchOS) @@ -171,6 +178,7 @@ class ActivityTracker: ActivityTrackerBehaviour { #endif } + @MainActor @objc private func handleApplicationStateChange(_ notification: Notification) { switch notification.name { case Self.applicationDidMoveToBackgroundNotification: diff --git a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/ActivityTrackerTests.swift b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/ActivityTrackerTests.swift index 6016643f73..8e0820aa39 100644 --- a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/ActivityTrackerTests.swift +++ b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/ActivityTrackerTests.swift @@ -20,6 +20,7 @@ class ActivityTrackerTests: XCTestCase { private var stateMachine: MockStateMachine! private var timeout: TimeInterval = 1 + @MainActor private static let applicationDidMoveToBackgroundNotification: Notification.Name = { #if canImport(WatchKit) WKExtension.applicationDidEnterBackgroundNotification @@ -30,6 +31,7 @@ class ActivityTrackerTests: XCTestCase { #endif }() + @MainActor private static let applicationWillMoveToForegoundNotification: Notification.Name = { #if canImport(WatchKit) WKExtension.applicationWillEnterForegroundNotification @@ -40,6 +42,7 @@ class ActivityTrackerTests: XCTestCase { #endif }() + @MainActor private static var applicationWillTerminateNotification: Notification.Name = { #if canImport(WatchKit) WKExtension.applicationWillResignActiveNotification @@ -79,7 +82,7 @@ class ActivityTrackerTests: XCTestCase { NotificationCenter.default.post(Notification(name: Self.applicationDidMoveToBackgroundNotification)) NotificationCenter.default.post(Notification(name: Self.applicationWillMoveToForegoundNotification)) - NotificationCenter.default.post(Notification(name: Self.applicationWillTerminateNotification)) + await NotificationCenter.default.post(Notification(name: Self.applicationWillTerminateNotification)) await fulfillment(of: [stateMachine.processExpectation!], timeout: 1) XCTAssertTrue(stateMachine.processedEvents.contains(.applicationDidMoveToBackground)) @@ -94,7 +97,7 @@ class ActivityTrackerTests: XCTestCase { NotificationCenter.default.post(Notification(name: Self.applicationDidMoveToBackgroundNotification)) - await fulfillment(of: [stateMachine.processExpectation!], timeout: 2) + await fulfillment(of: [stateMachine.processExpectation!], timeout: 5) XCTAssertTrue(stateMachine.processedEvents.contains(.applicationDidMoveToBackground)) XCTAssertTrue(stateMachine.processedEvents.contains(.backgroundTrackingDidTimeout)) diff --git a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/AwsPinpointAnalyticsKeychainMigrationTests.swift b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/AwsPinpointAnalyticsKeychainMigrationTests.swift index 8eba2b8a4d..24755235a6 100644 --- a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/AwsPinpointAnalyticsKeychainMigrationTests.swift +++ b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/AwsPinpointAnalyticsKeychainMigrationTests.swift @@ -16,7 +16,7 @@ class AWSPinpointAnalyticsKeyValueStoreTests: XCTestCase { private let archiver = AmplifyArchiver() private let userDefaults = UserDefaults.standard private let pinpointClient = MockPinpointClient() - private let endpointInformation = MockEndpointInformation() + private let endpointInformationProvider = MockEndpointInformationProvider() private let currentApplicationId = "applicationId" private let currentEndpointId = "endpointId" @@ -45,7 +45,7 @@ class AWSPinpointAnalyticsKeyValueStoreTests: XCTestCase { isDebug: false), pinpointClient: pinpointClient, archiver: archiver, - endpointInformation: endpointInformation, + endpointInformationProvider: endpointInformationProvider, userDefaults: userDefaults, keychain: keychain) @@ -68,7 +68,7 @@ class AWSPinpointAnalyticsKeyValueStoreTests: XCTestCase { isDebug: false), pinpointClient: pinpointClient, archiver: archiver, - endpointInformation: endpointInformation, + endpointInformationProvider: endpointInformationProvider, userDefaults: userDefaults, keychain: keychain) diff --git a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/EndpointClientTests.swift b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/EndpointClientTests.swift index d1b42f5dfd..693a3b6787 100644 --- a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/EndpointClientTests.swift +++ b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/EndpointClientTests.swift @@ -17,7 +17,7 @@ class EndpointClientTests: XCTestCase { private var archiver: MockArchiver! private var userDefaults: MockUserDefaults! private var pinpointClient: MockPinpointClient! - private var endpointInformation: MockEndpointInformation! + private var endpointInformationProvider: MockEndpointInformationProvider! private var remoteNotificationsHelper: MockRemoteNotifications! private var currentApplicationId = "applicationId" private var currentEndpointId = "endpointId" @@ -26,7 +26,7 @@ class EndpointClientTests: XCTestCase { archiver = MockArchiver() userDefaults = MockUserDefaults() pinpointClient = MockPinpointClient() - endpointInformation = MockEndpointInformation() + endpointInformationProvider = MockEndpointInformationProvider() keychain = MockKeychainStore() remoteNotificationsHelper = MockRemoteNotifications() endpointClient = EndpointClient(configuration: .init(appId: currentApplicationId, @@ -34,7 +34,7 @@ class EndpointClientTests: XCTestCase { isDebug: false), pinpointClient: pinpointClient, archiver: archiver, - endpointInformation: endpointInformation, + endpointInformationProvider: endpointInformationProvider, userDefaults: userDefaults, keychain: keychain, remoteNotificationsHelper: remoteNotificationsHelper) @@ -44,7 +44,7 @@ class EndpointClientTests: XCTestCase { archiver = nil userDefaults = nil pinpointClient = nil - endpointInformation = nil + endpointInformationProvider = nil endpointClient = nil keychain = nil remoteNotificationsHelper = nil @@ -80,10 +80,10 @@ class EndpointClientTests: XCTestCase { XCTAssertEqual(endpointProfile.endpointId, currentEndpointId) XCTAssertEqual(endpointProfile.deviceToken, newToken.asHexString()) XCTAssertNotEqual(endpointProfile.demographic, oldDemographic) - XCTAssertEqual(endpointProfile.demographic.appVersion, endpointInformation.appVersion) + XCTAssertEqual(endpointProfile.demographic.appVersion, endpointInformationProvider.appVersion) XCTAssertEqual(endpointProfile.demographic.make, "apple") - XCTAssertEqual(endpointProfile.demographic.platform, endpointInformation.platform.name) - XCTAssertEqual(endpointProfile.demographic.platformVersion, endpointInformation.platform.version) + XCTAssertEqual(endpointProfile.demographic.platform, endpointInformationProvider.platformName) + XCTAssertEqual(endpointProfile.demographic.platformVersion, endpointInformationProvider.platformVersion) } func testCurrentEndpointProfile_withInvalidStoredProfile_shouldRemoveStored_andReturnNew() async { @@ -110,10 +110,10 @@ class EndpointClientTests: XCTestCase { XCTAssertEqual(endpointProfile.deviceToken, newToken?.asHexString()) XCTAssertNotEqual(endpointProfile.effectiveDate, oldEffectiveDate) XCTAssertNotEqual(endpointProfile.demographic, oldDemographic) - XCTAssertEqual(endpointProfile.demographic.appVersion, endpointInformation.appVersion) + XCTAssertEqual(endpointProfile.demographic.appVersion, endpointInformationProvider.appVersion) XCTAssertEqual(endpointProfile.demographic.make, "apple") - XCTAssertEqual(endpointProfile.demographic.platform, endpointInformation.platform.name) - XCTAssertEqual(endpointProfile.demographic.platformVersion, endpointInformation.platform.version) + XCTAssertEqual(endpointProfile.demographic.platform, endpointInformationProvider.platformName) + XCTAssertEqual(endpointProfile.demographic.platformVersion, endpointInformationProvider.platformVersion) } func testUpdateEndpointProfile_shouldSendUpdateRequestAndSave() async { @@ -182,18 +182,18 @@ class EndpointClientTests: XCTestCase { func testConvertToPublicEndpoint_shouldReturnPublicEndpoint() async { let endpointProfile = await endpointClient.currentEndpointProfile() let publicEndpoint = endpointClient.convertToPublicEndpoint(endpointProfile) - let mockModel = MockEndpointInformation() + let mockModel = MockEndpointInformationProvider() XCTAssertNotNil(publicEndpoint) XCTAssertNil(publicEndpoint.address) XCTAssertEqual(publicEndpoint.attributes?.count, 0) XCTAssertEqual(publicEndpoint.metrics?.count, 0) XCTAssertNil(publicEndpoint.channelType) XCTAssertNil(publicEndpoint.optOut) - XCTAssertEqual(publicEndpoint.demographic?.appVersion, mockModel.appVersion) + XCTAssertEqual(publicEndpoint.demographic?.appVersion, endpointInformationProvider.appVersion) XCTAssertEqual(publicEndpoint.demographic?.make, "apple") - XCTAssertEqual(publicEndpoint.demographic?.model, mockModel.model) - XCTAssertEqual(publicEndpoint.demographic?.platform, mockModel.platform.name) - XCTAssertEqual(publicEndpoint.demographic?.platformVersion, mockModel.platform.version) + XCTAssertEqual(publicEndpoint.demographic?.model, endpointInformationProvider.model) + XCTAssertEqual(publicEndpoint.demographic?.platform, endpointInformationProvider.platformName) + XCTAssertEqual(publicEndpoint.demographic?.platformVersion, endpointInformationProvider.platformVersion) } @discardableResult @@ -208,10 +208,14 @@ class EndpointClientTests: XCTestCase { } } -class MockEndpointInformation: EndpointInformation { - var model: String = "mockModel" - var appVersion: String = "mockAppVersion" - var platform: Platform = (name: "mockPlatformName", version: "mockPlatformVersion") +class MockEndpointInformationProvider: EndpointInformationProvider { + let model = "modelModel" + let appVersion = "mockAppVersion" + let platformName = "mockPlatformName" + let platformVersion = "mockPlatformVersion" + func endpointInfo() async -> InternalAWSPinpoint.EndpointInformation { + return InternalAWSPinpoint.EndpointInformation(model: model, appVersion: appVersion, platform: (name: platformName, version: platformVersion)) + } } class MockRemoteNotifications: RemoteNotificationsBehaviour { diff --git a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/EndpointInformationProviderTests.swift b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/EndpointInformationProviderTests.swift new file mode 100644 index 0000000000..316e6190b8 --- /dev/null +++ b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/EndpointInformationProviderTests.swift @@ -0,0 +1,51 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +@_spi(InternalAWSPinpoint) @testable import InternalAWSPinpoint +import XCTest + +class EndpointInformationProviderTests: XCTestCase { + + /// Given: DefaultEndpointInformationProvider + /// When: endpointInfo() is called + /// Then: endpoint information is returned not nil + func testGetEndpointInformation() async { + let provider = DefaultEndpointInformationProvider() + let endpointInfo = await provider.endpointInfo() + XCTAssertNotNil(endpointInfo) + } + + /// Given: DefaultEndpointInformationProvider + /// When: endpointInfo() is called + /// Then: endpoint information returned contains platform name/version, app version, model, + func testGetEndpointInformationDetails() async { + let provider = DefaultEndpointInformationProvider() + let endpointInfo = await provider.endpointInfo() + let platformName = endpointInfo.platform.name + let platformVersion = endpointInfo.platform.version + let model = endpointInfo.model + let version = endpointInfo.appVersion + + XCTAssertNotNil(platformName) + XCTAssertNotNil(platformVersion) + XCTAssertNotNil(model) + XCTAssertNotNil(version) + + #if os(macOS) + XCTAssertEqual(platformName, "macOS") + #elseif os(iOS) + XCTAssertEqual(platformName, "iOS") + XCTAssertEqual(model, "iPhone") + #elseif os(tvOS) + XCTAssertEqual(platformName, "tvOS") + XCTAssertEqual(model, "Apple TV") + #elseif os(watchOS) + XCTAssertEqual(platformName, "watchOS") + XCTAssertEqual(model, "Apple Watch") + #endif + } +} diff --git a/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingSessionController.swift b/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingSessionController.swift index 733dc11828..de5fcd5c7e 100644 --- a/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingSessionController.swift +++ b/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingSessionController.swift @@ -103,7 +103,6 @@ final class AWSCloudWatchLoggingSessionController { private func createConsumer() throws -> LogBatchConsumer? { if self.client == nil { - // TODO: FrameworkMetadata Replacement let configuration = try CloudWatchLogsClient.CloudWatchLogsClientConfiguration( region: region, credentialsProvider: credentialsProvider @@ -115,9 +114,10 @@ final class AWSCloudWatchLoggingSessionController { } guard let cloudWatchClient = client else { return nil } - return try CloudWatchLoggingConsumer(client: cloudWatchClient, - logGroupName: self.logGroupName, - userIdentifier: self.userIdentifier) + return CloudWatchLoggingConsumer( + client: cloudWatchClient, + logGroupName: self.logGroupName, + userIdentifier: self.userIdentifier) } private func connectProducerAndConsumer() { diff --git a/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/Consumer/CloudWatchLoggingConsumer.swift b/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/Consumer/CloudWatchLoggingConsumer.swift index fd85601d92..3ff0d65068 100644 --- a/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/Consumer/CloudWatchLoggingConsumer.swift +++ b/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/Consumer/CloudWatchLoggingConsumer.swift @@ -14,19 +14,20 @@ import Foundation class CloudWatchLoggingConsumer { private let client: CloudWatchLogsClientProtocol + private let formatter: CloudWatchLoggingStreamNameFormatter private let logGroupName: String - private let logStreamName: String + private var logStreamName: String? private var ensureLogStreamExistsComplete: Bool = false private let encoder = JSONEncoder() + init( client: CloudWatchLogsClientProtocol, logGroupName: String, userIdentifier: String? - ) throws { + ) { self.client = client - let formatter = CloudWatchLoggingStreamNameFormatter(userIdentifier: userIdentifier) + self.formatter = CloudWatchLoggingStreamNameFormatter(userIdentifier: userIdentifier) self.logGroupName = logGroupName - self.logStreamName = formatter.formattedStreamName() } } @@ -75,6 +76,10 @@ extension CloudWatchLoggingConsumer: LogBatchConsumer { ensureLogStreamExistsComplete = true } + if logStreamName == nil { + self.logStreamName = await formatter.formattedStreamName() + } + let stream = try? await self.client.describeLogStreams(input: DescribeLogStreamsInput( logGroupName: self.logGroupName, logStreamNamePrefix: self.logStreamName diff --git a/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/Consumer/CloudWatchLoggingStreamNameFormatter.swift b/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/Consumer/CloudWatchLoggingStreamNameFormatter.swift index d40e0eebe9..94fb9850ba 100644 --- a/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/Consumer/CloudWatchLoggingStreamNameFormatter.swift +++ b/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/Consumer/CloudWatchLoggingStreamNameFormatter.swift @@ -23,22 +23,25 @@ import AppKit struct CloudWatchLoggingStreamNameFormatter { let userIdentifier: String? - let deviceIdentifier: String? + var deviceIdentifier: String? { + get async { + #if canImport(WatchKit) + await WKInterfaceDevice.current().identifierForVendor?.uuidString + #elseif canImport(UIKit) + await UIDevice.current.identifierForVendor?.uuidString + #elseif canImport(AppKit) + Host.current().name + #else + Self.deviceIdentifierFromBundle() + #endif + } + } init(userIdentifier: String? = nil) { self.userIdentifier = userIdentifier - #if canImport(WatchKit) - self.deviceIdentifier = WKInterfaceDevice.current().identifierForVendor?.uuidString - #elseif canImport(UIKit) - self.deviceIdentifier = UIDevice.current.identifierForVendor?.uuidString - #elseif canImport(AppKit) - self.deviceIdentifier = Host.current().name - #else - self.deviceIdentifier = Self.deviceIdentifierFromBundle() - #endif } - func formattedStreamName() -> String { - return "\(deviceIdentifier ?? "").\(userIdentifier ?? "guest")" + func formattedStreamName() async -> String { + return "\(await deviceIdentifier ?? "").\(userIdentifier ?? "guest")" } } diff --git a/AmplifyPlugins/Logging/Tests/AWSCloudWatchLoggingPluginHostApp/AWSCloudWatchLoggingPluginIntegrationTests/AWSCloudWatchLoggingPluginIntegrationTests.swift b/AmplifyPlugins/Logging/Tests/AWSCloudWatchLoggingPluginHostApp/AWSCloudWatchLoggingPluginIntegrationTests/AWSCloudWatchLoggingPluginIntegrationTests.swift index 0685c07358..b19a5cee97 100644 --- a/AmplifyPlugins/Logging/Tests/AWSCloudWatchLoggingPluginHostApp/AWSCloudWatchLoggingPluginIntegrationTests/AWSCloudWatchLoggingPluginIntegrationTests.swift +++ b/AmplifyPlugins/Logging/Tests/AWSCloudWatchLoggingPluginHostApp/AWSCloudWatchLoggingPluginIntegrationTests/AWSCloudWatchLoggingPluginIntegrationTests.swift @@ -60,8 +60,14 @@ class AWSCloudWatchLoggingPluginIntergrationTests: XCTestCase { override func tearDown() async throws { await Amplify.reset() let documents = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.path ?? NSTemporaryDirectory() - let directory = documents.appendingPathComponent("amplify") - .appendingPathComponent("logging") + let directory = documents.appendingPathComponent("amplify").appendingPathComponent("logging") + let fileURLs = try FileManager.default.contentsOfDirectory( + at: URL(string: directory)!, + includingPropertiesForKeys: nil, + options: .skipsHiddenFiles) + for fileURL in fileURLs { + try FileManager.default.removeItem(at: fileURL) + } try FileManager.default.removeItem(atPath: directory) } diff --git a/AmplifyPlugins/Logging/Tests/AWSCloudWatchLoggingPluginTests/CloudWatchLogConsumerTests.swift b/AmplifyPlugins/Logging/Tests/AWSCloudWatchLoggingPluginTests/CloudWatchLogConsumerTests.swift index ac8362bdff..7fdfa20757 100644 --- a/AmplifyPlugins/Logging/Tests/AWSCloudWatchLoggingPluginTests/CloudWatchLogConsumerTests.swift +++ b/AmplifyPlugins/Logging/Tests/AWSCloudWatchLoggingPluginTests/CloudWatchLogConsumerTests.swift @@ -27,7 +27,7 @@ final class CloudWatchLogConsumerTests: XCTestCase { client = MockCloudWatchLogsClient() logGroupName = UUID().uuidString logStreamName = UUID().uuidString - systemUnderTest = try CloudWatchLoggingConsumer(client: client, logGroupName: logGroupName, userIdentifier: "guest") + systemUnderTest = await CloudWatchLoggingConsumer(client: client, logGroupName: logGroupName, userIdentifier: "guest") } override func tearDown() async throws { diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+DownloadBehavior.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+DownloadBehavior.swift index ab7c5849de..63d30facaf 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+DownloadBehavior.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+DownloadBehavior.swift @@ -33,7 +33,7 @@ extension AWSS3StorageService { metadata: nil, accelerate: accelerate, expires: nil) - startDownload(preSignedURL: preSignedURL, transferTask: transferTask) + await startDownload(preSignedURL: preSignedURL, transferTask: transferTask) } catch { onEvent(.failed(StorageError.unknown("Failed to get pre-signed URL", nil))) } @@ -42,14 +42,14 @@ extension AWSS3StorageService { private func startDownload(preSignedURL: URL, transferTask: StorageTransferTask, - startTransfer: Bool = true) { + startTransfer: Bool = true) async { guard case .download = transferTask.transferType else { fatalError("Transfer type must be download") } var request = URLRequest(url: preSignedURL) request.cachePolicy = .reloadIgnoringLocalCacheData request.httpMethod = "GET" - request.setValue(userAgent, forHTTPHeaderField: "User-Agent") + request.setValue(await userAgent, forHTTPHeaderField: "User-Agent") request.setHTTPRequestHeaders(transferTask: transferTask) urlRequestDelegate?.willSend(request: request) diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+UploadBehavior.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+UploadBehavior.swift index 5349e4a6be..bd619202a0 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+UploadBehavior.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+UploadBehavior.swift @@ -39,7 +39,7 @@ extension AWSS3StorageService { metadata: metadata, accelerate: accelerate, expires: nil) - startUpload(preSignedURL: preSignedURL, + await startUpload(preSignedURL: preSignedURL, fileURL: uploadFileURL, contentType: contentType, transferTask: transferTask) @@ -53,7 +53,7 @@ extension AWSS3StorageService { fileURL: URL, contentType: String, transferTask: StorageTransferTask, - startTransfer: Bool = true) { + startTransfer: Bool = true) async { guard case .upload = transferTask.transferType else { fatalError("Transfer type must be upload") } @@ -63,7 +63,7 @@ extension AWSS3StorageService { request.networkServiceType = .responsiveData request.setValue(contentType, forHTTPHeaderField: "Content-Type") - request.setValue(userAgent, forHTTPHeaderField: "User-Agent") + request.setValue(await userAgent, forHTTPHeaderField: "User-Agent") request.setHTTPRequestHeaders(transferTask: transferTask) diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService.swift index a930bb2184..c311eaaeb8 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService.swift @@ -31,7 +31,12 @@ class AWSS3StorageService: AWSS3StorageServiceBehavior, StorageServiceProxy { /// - Tag: AWSS3StorageService.client var client: S3ClientProtocol - let userAgent: String + var userAgent: String { + get async { + "\(AmplifyAWSServiceConfiguration.userAgentLib) \(await AmplifyAWSServiceConfiguration.userAgentOS)" + } + } + let storageConfiguration: StorageConfiguration let sessionConfiguration: URLSessionConfiguration var delegateQueue: OperationQueue? @@ -133,7 +138,6 @@ class AWSS3StorageService: AWSS3StorageServiceBehavior, StorageServiceProxy { self.preSignedURLBuilder = preSignedURLBuilder self.awsS3 = awsS3 self.bucket = bucket - self.userAgent = "\(AmplifyAWSServiceConfiguration.userAgentLib) \(AmplifyAWSServiceConfiguration.userAgentOS)" StorageBackgroundEventsRegistry.register(identifier: identifier) diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageMultipartUploadClient.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageMultipartUploadClient.swift index d189d1d5d9..ac1baacaa6 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageMultipartUploadClient.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageMultipartUploadClient.swift @@ -111,7 +111,7 @@ class DefaultStorageMultipartUploadClient: StorageMultipartUploadClient { fatalError("Part number is required") } - let startUploadPart: (URL, URL) -> Void = { [weak self] partialFileURL, preSignedURL in + let startUploadPart: (URL, URL) async -> Void = { [weak self] partialFileURL, preSignedURL in guard let self = self else { return } var request = URLRequest(url: preSignedURL) request.cachePolicy = .reloadIgnoringLocalCacheData @@ -122,7 +122,7 @@ class DefaultStorageMultipartUploadClient: StorageMultipartUploadClient { // [UploadPart](https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html) // operation, the "MultiPart/UploadPart" suffix is added to the // user agent. - let userAgent = serviceProxy.userAgent.appending(" MultiPart/UploadPart") + let userAgent = await serviceProxy.userAgent.appending(" MultiPart/UploadPart") request.setValue(userAgent, forHTTPHeaderField: "User-Agent") self.serviceProxy?.urlRequestDelegate?.willSend(request: request) @@ -157,7 +157,7 @@ class DefaultStorageMultipartUploadClient: StorageMultipartUploadClient { accelerate: nil, expires: nil ) - startUploadPart(partialFileURL, preSignedURL) + await startUploadPart(partialFileURL, preSignedURL) } catch { self.session?.fail(error: error) } diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageServiceProxy.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageServiceProxy.swift index f2e9c73286..285edcb436 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageServiceProxy.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageServiceProxy.swift @@ -12,7 +12,7 @@ protocol StorageServiceProxy: AnyObject { var preSignedURLBuilder: AWSS3PreSignedURLBuilderBehavior! { get } var awsS3: AWSS3Behavior! { get } var urlSession: URLSession { get } - var userAgent: String { get } + var userAgent: String { get async } var urlRequestDelegate: URLRequestDelegate? { get } func register(task: StorageTransferTask) diff --git a/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Support/Internal/StorageTransferTaskTests.swift b/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Support/Internal/StorageTransferTaskTests.swift index 45529f59a0..2a2ab197e0 100644 --- a/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Support/Internal/StorageTransferTaskTests.swift +++ b/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Support/Internal/StorageTransferTaskTests.swift @@ -123,7 +123,7 @@ class StorageTransferTaskTests: XCTestCase { /// Given: A StorageTransferTask with status not being paused /// When: resume is invoked /// Then: No event is reported and the task is not set to .inProgress - func testResume_withTaskNotPaused_shouldNotCallResume_andNotReportEvent() { + func testResume_withTaskNotPaused_shouldNotCallResume_andNotReportEvent() async { let expectation = expectation(description: "no event is received on resume when the session is not paused") expectation.isInverted = true let task = createTask( @@ -137,7 +137,7 @@ class StorageTransferTaskTests: XCTestCase { XCTAssertEqual(task.status, .unknown) task.resume() - waitForExpectations(timeout: 0.5) + await fulfillment(of: [expectation], timeout: 0.5) XCTAssertEqual(task.status, .unknown) } diff --git a/AmplifyTestCommon/Mocks/MockDevMenuContextProvider.swift b/AmplifyTestCommon/Mocks/MockDevMenuContextProvider.swift index 7ee4f0bd2c..4181cc4f4b 100644 --- a/AmplifyTestCommon/Mocks/MockDevMenuContextProvider.swift +++ b/AmplifyTestCommon/Mocks/MockDevMenuContextProvider.swift @@ -10,6 +10,7 @@ import Amplify import UIKit /// Mock class for presenting UI context to developer menu +@MainActor class MockDevMenuContextProvider: DevMenuPresentationContextProvider { let uiWindow = UIWindow() diff --git a/AmplifyTests/CategoryTests/Hub/HubCategoryConfigurationTests.swift b/AmplifyTests/CategoryTests/Hub/HubCategoryConfigurationTests.swift index 305cd1ef0e..8f894b74e8 100644 --- a/AmplifyTests/CategoryTests/Hub/HubCategoryConfigurationTests.swift +++ b/AmplifyTests/CategoryTests/Hub/HubCategoryConfigurationTests.swift @@ -129,7 +129,7 @@ class HubCategoryConfigurationTests: XCTestCase { XCTAssertNotNil(try Amplify.Hub.getPlugin(for: "MockSecondHubCategoryPlugin")) } - func testCanUseDefaultPluginIfOnlyOnePlugin() throws { + func testCanUseDefaultPluginIfOnlyOnePlugin() async throws { let plugin = MockHubCategoryPlugin() let methodInvokedOnDefaultPlugin = expectation(description: "test method invoked on default plugin") plugin.listeners.append { message in @@ -146,8 +146,7 @@ class HubCategoryConfigurationTests: XCTestCase { let unsubscribeToken = UnsubscribeToken(channel: .storage, id: UUID()) Amplify.Hub.removeListener(unsubscribeToken) - - waitForExpectations(timeout: 1.0) + await fulfillment(of: [methodInvokedOnDefaultPlugin], timeout: 1) } func testPreconditionFailureInvokingWithMultiplePlugins() throws { diff --git a/AmplifyTests/DevMenuTests/DevMenuExtensionTests.swift b/AmplifyTests/DevMenuTests/DevMenuExtensionTests.swift index 1dd81d6b34..146fe9aaa3 100644 --- a/AmplifyTests/DevMenuTests/DevMenuExtensionTests.swift +++ b/AmplifyTests/DevMenuTests/DevMenuExtensionTests.swift @@ -10,11 +10,12 @@ import XCTest @testable import Amplify @testable import AmplifyTestCommon +@MainActor class DevMenuExtensionTests: XCTestCase { let provider = MockDevMenuContextProvider() override func setUp() async throws { do { - await Amplify.enableDevMenu(contextProvider: provider) + Amplify.enableDevMenu(contextProvider: provider) /// After await Amplify.reset() is called in teardown(), Amplify.configure() doesn't /// initialize the plugin for LoggingCategory . This doesn't call Amplify.getLoggingCategoryPlugin() diff --git a/AmplifyTests/DevMenuTests/PersistentLogWrapperTests.swift b/AmplifyTests/DevMenuTests/PersistentLogWrapperTests.swift index 3179e8b6bf..4f66a563c3 100644 --- a/AmplifyTests/DevMenuTests/PersistentLogWrapperTests.swift +++ b/AmplifyTests/DevMenuTests/PersistentLogWrapperTests.swift @@ -10,13 +10,14 @@ import XCTest @testable import Amplify @testable import AmplifyTestCommon +@MainActor class PersistentLogWrapperTests: XCTestCase { let provider = MockDevMenuContextProvider() override func setUp() async throws { do { - await Amplify.enableDevMenu(contextProvider: provider) + Amplify.enableDevMenu(contextProvider: provider) /// After await Amplify.reset() is called in teardown(), Amplify.configure() doesn't /// initialize the plugin for LoggingCategory . This doesn't call Amplify.getLoggingCategoryPlugin() diff --git a/AmplifyTests/DevMenuTests/PersistentLoggingPluginTests.swift b/AmplifyTests/DevMenuTests/PersistentLoggingPluginTests.swift index dd7d283ef0..e873ed6f9a 100644 --- a/AmplifyTests/DevMenuTests/PersistentLoggingPluginTests.swift +++ b/AmplifyTests/DevMenuTests/PersistentLoggingPluginTests.swift @@ -10,13 +10,14 @@ import XCTest @testable import Amplify @testable import AmplifyTestCommon +@MainActor class PersistentLoggingPluginTests: XCTestCase { let provider = MockDevMenuContextProvider() override func setUp() async throws { do { - await Amplify.enableDevMenu(contextProvider: provider) + Amplify.enableDevMenu(contextProvider: provider) /// After await Amplify.reset() is called in teardown(), Amplify.configure() doesn't /// initialize the plugin for LoggingCategory . This doesn't call Amplify.getLoggingCategoryPlugin()