diff --git a/AmplifyPlugins/API/Sources/AWSAPIPlugin/Interceptor/RequestInterceptor/IAMURLRequestInterceptor.swift b/AmplifyPlugins/API/Sources/AWSAPIPlugin/Interceptor/RequestInterceptor/IAMURLRequestInterceptor.swift index 5b354abb1d..534f70f5da 100644 --- a/AmplifyPlugins/API/Sources/AWSAPIPlugin/Interceptor/RequestInterceptor/IAMURLRequestInterceptor.swift +++ b/AmplifyPlugins/API/Sources/AWSAPIPlugin/Interceptor/RequestInterceptor/IAMURLRequestInterceptor.swift @@ -9,7 +9,8 @@ import Amplify import AWSPluginsCore import InternalAmplifyCredentials import Foundation -import ClientRuntime +import SmithyHTTPAPI +import Smithy typealias AWSRegionType = String @@ -41,12 +42,12 @@ struct IAMURLRequestInterceptor: URLRequestInterceptor { request.setValue(userAgent, forHTTPHeaderField: URLRequestConstants.Header.userAgent) let httpMethod = (request.httpMethod?.uppercased()) - .flatMap(HttpMethodType.init(rawValue:)) ?? .get + .flatMap(HTTPMethodType.init(rawValue:)) ?? .get let queryItems = URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems? - .map { ClientRuntime.SDKURLQueryItem(name: $0.name, value: $0.value)} ?? [] + .map { URIQueryItem(name: $0.name, value: $0.value)} ?? [] - let requestBuilder = SdkHttpRequestBuilder() + let requestBuilder = HTTPRequestBuilder() .withHost(host) .withPath(url.path) .withQueryItems(queryItems) @@ -66,7 +67,7 @@ struct IAMURLRequestInterceptor: URLRequestInterceptor { guard let urlRequest = try await AmplifyAWSSignatureV4Signer().sigV4SignedRequest( requestBuilder: requestBuilder, - credentialsProvider: iamCredentialsProvider.getCredentialsProvider(), + credentialIdentityResolver: iamCredentialsProvider.getCredentialIdentityResolver(), signingName: signingName, signingRegion: region, date: Date() diff --git a/AmplifyPlugins/API/Sources/AWSAPIPlugin/Interceptor/SubscriptionInterceptor/IAMAuthInterceptor.swift b/AmplifyPlugins/API/Sources/AWSAPIPlugin/Interceptor/SubscriptionInterceptor/IAMAuthInterceptor.swift index cd023676c7..675bdca4ee 100644 --- a/AmplifyPlugins/API/Sources/AWSAPIPlugin/Interceptor/SubscriptionInterceptor/IAMAuthInterceptor.swift +++ b/AmplifyPlugins/API/Sources/AWSAPIPlugin/Interceptor/SubscriptionInterceptor/IAMAuthInterceptor.swift @@ -9,15 +9,15 @@ import Foundation @_spi(WebSocket) import AWSPluginsCore import InternalAmplifyCredentials import Amplify -import AWSClientRuntime -import ClientRuntime +import SmithyHTTPAPI +import SmithyIdentity class IAMAuthInterceptor { - let authProvider: CredentialsProviding + let authProvider: any AWSCredentialIdentityResolver let region: AWSRegionType - init(_ authProvider: CredentialsProviding, region: AWSRegionType) { + init(_ authProvider: some AWSCredentialIdentityResolver, region: AWSRegionType) { self.authProvider = authProvider self.region = region } @@ -35,7 +35,7 @@ class IAMAuthInterceptor { /// /// 1. A request is created with the IAM based auth headers (date, accept, content encoding, content type, and /// additional headers. - let requestBuilder = SdkHttpRequestBuilder() + let requestBuilder = HTTPRequestBuilder() .withHost(host) .withPath(endpoint.path) .withMethod(.post) @@ -51,7 +51,7 @@ class IAMAuthInterceptor { /// the request headers as authorization and security token. do { guard let urlRequest = try await signer.sigV4SignedRequest(requestBuilder: requestBuilder, - credentialsProvider: authProvider, + credentialIdentityResolver: authProvider, signingName: "appsync", signingRegion: region, date: Date()) else { diff --git a/AmplifyPlugins/API/Sources/AWSAPIPlugin/SubscriptionFactory/AppSyncRealTimeClientFactory.swift b/AmplifyPlugins/API/Sources/AWSAPIPlugin/SubscriptionFactory/AppSyncRealTimeClientFactory.swift index 57a3708e1e..61b4fb67ac 100644 --- a/AmplifyPlugins/API/Sources/AWSAPIPlugin/SubscriptionFactory/AppSyncRealTimeClientFactory.swift +++ b/AmplifyPlugins/API/Sources/AWSAPIPlugin/SubscriptionFactory/AppSyncRealTimeClientFactory.swift @@ -101,8 +101,8 @@ actor AppSyncRealTimeClientFactory: AppSyncRealTimeClientFactoryProtocol { let provider = AWSOIDCAuthProvider(authService: authService) return AuthTokenInterceptor(getLatestAuthToken: provider.getLatestAuthToken) case .awsIAM(let awsIAMConfiguration): - return IAMAuthInterceptor(authService.getCredentialsProvider(), - region: awsIAMConfiguration.region) + return IAMAuthInterceptor(authService.getCredentialIdentityResolver(), + region: awsIAMConfiguration.region) case .openIDConnect: guard let oidcAuthProvider = apiAuthProviderFactory.oidcAuthProvider() else { throw APIError.invalidConfiguration( diff --git a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginConfigureTests.swift b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginConfigureTests.swift index 4c14742004..83de1f08d4 100644 --- a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginConfigureTests.swift +++ b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginConfigureTests.swift @@ -14,7 +14,7 @@ import XCTest class AWSPinpointAnalyticsPluginConfigureTests: AWSPinpointAnalyticsPluginTestBase { override func setUp() async throws { - AWSPinpointFactory.credentialsProvider = MockCredentialsProvider() + AWSPinpointFactory.credentialIdentityResolver = MockCredentialsProvider() try await super.setUp() } diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+AppSyncSigner.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+AppSyncSigner.swift index b77c3ad92e..51f3e66db4 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+AppSyncSigner.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+AppSyncSigner.swift @@ -8,9 +8,13 @@ import Foundation import Amplify // Amplify.Auth import AWSPluginsCore // AuthAWSCredentialsProvider -import AWSClientRuntime // AWSClientRuntime.CredentialsProviding -import ClientRuntime // SdkHttpRequestBuilder import AwsCommonRuntimeKit // CommonRuntimeKit.initialize() +import AWSSDKHTTPAuth // AWSSigV4Signer +import Smithy // URIQueryItem +import SmithyHTTPAPI +import SmithyHTTPAuth +import SmithyHTTPAuthAPI +import SmithyIdentity // AWSCredentialIdentity extension AWSCognitoAuthPlugin { @@ -29,11 +33,15 @@ extension AWSCognitoAuthPlugin { region: region) } } - + + private static var signer = { + return AWSSigV4Signer() + }() + static func signAppSyncRequest(_ urlRequest: URLRequest, region: Swift.String, signingName: Swift.String = "appsync", - date: ClientRuntime.Date = Date()) async throws -> URLRequest { + date: Date = Date()) async throws -> URLRequest { CommonRuntimeKit.initialize() // Convert URLRequest to SDK's HTTPRequest @@ -43,11 +51,11 @@ extension AWSCognitoAuthPlugin { } // Retrieve the credentials from credentials provider - let credentials: AWSClientRuntime.AWSCredentials + let credentials: AWSCredentialIdentity let authSession = try await Amplify.Auth.fetchAuthSession() if let awsCredentialsProvider = authSession as? AuthAWSCredentialsProvider { let awsCredentials = try awsCredentialsProvider.getAWSCredentials().get() - credentials = awsCredentials.toAWSSDKCredentials() + credentials = try awsCredentials.toAWSSDKCredentials() } else { let error = AuthError.unknown("Auth session does not include AWS credentials information") throw error @@ -70,7 +78,7 @@ extension AWSCognitoAuthPlugin { signingAlgorithm: .sigv4) // Sign request - guard let httpRequest = await AWSSigV4Signer.sigV4SignedRequest( + guard let httpRequest = await signer.sigV4SignedRequest( requestBuilder: requestBuilder, signingConfig: signingConfig @@ -82,7 +90,7 @@ extension AWSCognitoAuthPlugin { return setHeaders(from: httpRequest, to: urlRequest) } - static func setHeaders(from sdkRequest: SdkHttpRequest, to urlRequest: URLRequest) -> URLRequest { + static func setHeaders(from sdkRequest: SmithyHTTPAPI.HTTPRequest, to urlRequest: URLRequest) -> URLRequest { var urlRequest = urlRequest for header in sdkRequest.headers.headers { urlRequest.setValue(header.value.joined(separator: ","), forHTTPHeaderField: header.name) @@ -90,7 +98,7 @@ extension AWSCognitoAuthPlugin { return urlRequest } - static func createAppSyncSdkHttpRequestBuilder(urlRequest: URLRequest) throws -> SdkHttpRequestBuilder? { + static func createAppSyncSdkHttpRequestBuilder(urlRequest: URLRequest) throws -> HTTPRequestBuilder? { guard let url = urlRequest.url, let host = url.host else { @@ -101,12 +109,12 @@ extension AWSCognitoAuthPlugin { headers.updateValue(host, forKey: "host") let httpMethod = (urlRequest.httpMethod?.uppercased()) - .flatMap(HttpMethodType.init(rawValue:)) ?? .get + .flatMap(HTTPMethodType.init(rawValue:)) ?? .get let queryItems = URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems? - .map { ClientRuntime.SDKURLQueryItem(name: $0.name, value: $0.value)} ?? [] + .map { URIQueryItem(name: $0.name, value: $0.value)} ?? [] - let requestBuilder = SdkHttpRequestBuilder() + let requestBuilder = HTTPRequestBuilder() .withHost(host) .withPath(url.path) .withQueryItems(queryItems) @@ -122,19 +130,20 @@ extension AWSCognitoAuthPlugin { extension AWSPluginsCore.AWSCredentials { - func toAWSSDKCredentials() -> AWSClientRuntime.AWSCredentials { + func toAWSSDKCredentials() throws -> AWSCredentialIdentity { if let tempCredentials = self as? AWSTemporaryCredentials { - return AWSClientRuntime.AWSCredentials( + return AWSCredentialIdentity( accessKey: tempCredentials.accessKeyId, secret: tempCredentials.secretAccessKey, - expirationTimeout: tempCredentials.expiration, - sessionToken: tempCredentials.sessionToken) + expiration: tempCredentials.expiration, + sessionToken: tempCredentials.sessionToken + ) } else { - return AWSClientRuntime.AWSCredentials( + return AWSCredentialIdentity( accessKey: accessKeyId, secret: secretAccessKey, - expirationTimeout: Date()) + expiration: nil + ) } - } } diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+Configure.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+Configure.swift index fdcfbf9385..482d266575 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+Configure.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+Configure.swift @@ -14,6 +14,8 @@ import ClientRuntime import AWSClientRuntime @_spi(PluginHTTPClientEngine) import InternalAmplifyCredentials @_spi(InternalHttpEngineProxy) import AWSPluginsCore +import SmithyRetriesAPI +import SmithyRetries extension AWSCognitoAuthPlugin { @@ -91,7 +93,8 @@ extension AWSCognitoAuthPlugin { case .userPools(let userPoolConfig), .userPoolsAndIdentityPools(let userPoolConfig, _): let configuration = try CognitoIdentityProviderClient.CognitoIdentityProviderClientConfiguration( region: userPoolConfig.region, - serviceSpecific: .init(endpointResolver: userPoolConfig.endpoint?.resolver) + signingRegion: userPoolConfig.region, + endpointResolver: userPoolConfig.endpoint?.resolver ) if var httpClientEngineProxy = httpClientEngineProxy { @@ -108,11 +111,14 @@ extension AWSCognitoAuthPlugin { } if let maxRetryUnwrapped = networkPreferences?.maxRetryCount { - configuration.retryStrategyOptions = RetryStrategyOptions(maxRetriesBase: Int(maxRetryUnwrapped)) + configuration.retryStrategyOptions = RetryStrategyOptions( + backoffStrategy: ExponentialBackoffStrategy(), + maxRetriesBase: Int(maxRetryUnwrapped) + ) } let authService = AWSAuthService() - configuration.credentialsProvider = authService.getCredentialsProvider() + configuration.awsCredentialIdentityResolver = authService.getCredentialIdentityResolver() return CognitoIdentityProviderClient(config: configuration) default: @@ -133,11 +139,14 @@ extension AWSCognitoAuthPlugin { } if let maxRetryUnwrapped = networkPreferences?.maxRetryCount { - configuration.retryStrategyOptions = RetryStrategyOptions(maxRetriesBase: Int(maxRetryUnwrapped)) + configuration.retryStrategyOptions = RetryStrategyOptions( + backoffStrategy: ExponentialBackoffStrategy(), + maxRetriesBase: Int(maxRetryUnwrapped) + ) } let authService = AWSAuthService() - configuration.credentialsProvider = authService.getCredentialsProvider() + configuration.awsCredentialIdentityResolver = authService.getCredentialIdentityResolver() return CognitoIdentityClient(config: configuration) default: diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Models/AuthChallengeType.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Models/AuthChallengeType.swift index 499aa62175..272ecc8702 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Models/AuthChallengeType.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Models/AuthChallengeType.swift @@ -26,7 +26,7 @@ enum AuthChallengeType { } -extension CognitoIdentityProviderClientTypes.ChallengeNameType { +extension CognitoIdentityProviderClientTypes.ChallengeNameType: Codable { var authChallengeType: AuthChallengeType { switch self { case .customChallenge: diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Service/ErrorMapping/AWSCongnitoIdentityProvider+AuthErrorConvertible.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Service/ErrorMapping/AWSCongnitoIdentityProvider+AuthErrorConvertible.swift index 0b3f3c2fa4..2328f1da8d 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Service/ErrorMapping/AWSCongnitoIdentityProvider+AuthErrorConvertible.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Service/ErrorMapping/AWSCongnitoIdentityProvider+AuthErrorConvertible.swift @@ -8,7 +8,7 @@ import Foundation import Amplify import AWSCognitoIdentityProvider -import AWSClientRuntime +@_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime extension ForbiddenException: AuthErrorConvertible { var fallbackDescription: String { "Access to the requested resource is forbidden" } diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Service/ErrorMapping/ClientError+AuthErrorConvertible.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Service/ErrorMapping/ClientError+AuthErrorConvertible.swift index 942c410f70..b890ee76be 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Service/ErrorMapping/ClientError+AuthErrorConvertible.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Service/ErrorMapping/ClientError+AuthErrorConvertible.swift @@ -7,18 +7,26 @@ import Foundation import Amplify -import ClientRuntime - -extension ClientError: AuthErrorConvertible { - var fallbackDescription: String { "Client Error" } +import Smithy +import SmithyHTTPAPI +extension SmithyHTTPAPI.HTTPClientError: AuthErrorConvertible { var authError: AuthError { switch self { case .pathCreationFailed(let message), - .queryItemCreationFailed(let message), - .serializationFailed(let message), - .dataNotFound(let message): + .queryItemCreationFailed(let message): return .service(message, "", self) + } + } +} + +extension Smithy.ClientError: AuthErrorConvertible { + var authError: AuthError { + switch self { + case .serializationFailed(let message), + .dataNotFound(let message), + .invalidValue(let message): + return .service(message, "Check the underlying error and try again", self) case .authError(let message): return .notAuthorized( diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Service/SdkTypealiases.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Service/SdkTypealiases.swift index c4328aac58..6baf521d3b 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Service/SdkTypealiases.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Service/SdkTypealiases.swift @@ -8,5 +8,6 @@ import Foundation import AWSClientRuntime import ClientRuntime +import SmithyHTTPAPI -public typealias NetworkResult = (Result) -> Void +public typealias NetworkResult = (Result) -> Void diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/StateMachine/CodeGen/Data/UserPoolConfigurationData.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/StateMachine/CodeGen/Data/UserPoolConfigurationData.swift index ef95993e96..098f8cc299 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/StateMachine/CodeGen/Data/UserPoolConfigurationData.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/StateMachine/CodeGen/Data/UserPoolConfigurationData.swift @@ -7,6 +7,7 @@ import ClientRuntime @_spi(InternalAmplifyConfiguration) import Amplify +import SmithyHTTPAPI struct UserPoolConfigurationData: Equatable { diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/CustomEndpoint/AWSEndpointResolving.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/CustomEndpoint/AWSEndpointResolving.swift index 47c6a89c63..96eb383f00 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/CustomEndpoint/AWSEndpointResolving.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/CustomEndpoint/AWSEndpointResolving.swift @@ -5,22 +5,21 @@ // SPDX-License-Identifier: Apache-2.0 // -import AWSClientRuntime -import ClientRuntime import AWSCognitoIdentityProvider +import SmithyHTTPAPI struct AWSEndpointResolving: AWSCognitoIdentityProvider.EndpointResolver { - func resolve(params: AWSCognitoIdentityProvider.EndpointParams) throws -> ClientRuntime.Endpoint { + func resolve(params: AWSCognitoIdentityProvider.EndpointParams) throws -> SmithyHTTPAPI.Endpoint { try endpoint() } - let endpoint: () throws -> ClientRuntime.Endpoint + let endpoint: () throws -> SmithyHTTPAPI.Endpoint - init(_ endpoint: @escaping () throws -> ClientRuntime.Endpoint) { + init(_ endpoint: @escaping () throws -> SmithyHTTPAPI.Endpoint) { self.endpoint = endpoint } - init(_ endpoint: @escaping @autoclosure () throws -> ClientRuntime.Endpoint) { + init(_ endpoint: @escaping @autoclosure () throws -> SmithyHTTPAPI.Endpoint) { self.endpoint = endpoint } } diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/CustomEndpoint/EndpointResolving.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/CustomEndpoint/EndpointResolving.swift index 3b4dab259c..2caf2826e6 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/CustomEndpoint/EndpointResolving.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/CustomEndpoint/EndpointResolving.swift @@ -6,10 +6,10 @@ // import Foundation -import ClientRuntime +import SmithyHTTPAPI struct EndpointResolving { - let run: (String) throws -> ClientRuntime.Endpoint + let run: (String) throws -> SmithyHTTPAPI.Endpoint } extension EndpointResolving { @@ -37,6 +37,6 @@ extension EndpointResolving { // Finally, let's confirm that the endpoint doesn't contain a path. try validate((components, endpoint), with: .pathIsEmpty()) - return ClientRuntime.Endpoint(host: host) + return SmithyHTTPAPI.Endpoint(host: host) } } diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Utils/HttpClientEngineProxy.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Utils/HttpClientEngineProxy.swift index b3a5edf8d2..2a2fe1153b 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Utils/HttpClientEngineProxy.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/Utils/HttpClientEngineProxy.swift @@ -6,8 +6,8 @@ // @_spi(InternalHttpEngineProxy) @_spi(InternalAmplifyPluginExtension) import InternalAmplifyCredentials -import ClientRuntime import Foundation +import SmithyHTTPAPI protocol HttpClientEngineProxy: HTTPClient { var target: HTTPClient? { get set } diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/AWSCognitoAuthPluginAppSyncSignerTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/AWSCognitoAuthPluginAppSyncSignerTests.swift index 609fe1c774..eedb002b74 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/AWSCognitoAuthPluginAppSyncSignerTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/AWSCognitoAuthPluginAppSyncSignerTests.swift @@ -30,7 +30,7 @@ class AWSCognitoAuthPluginAppSyncSignerTests: XCTestCase { XCTAssertEqual(request.method, .post) XCTAssertEqual(request.endpoint.port, 443) XCTAssertEqual(request.endpoint.protocolType, .https) - XCTAssertEqual(request.endpoint.headers?.headers, [.init(name: "host", value: "graphql.com")]) + XCTAssertEqual(request.endpoint.headers.headers, [.init(name: "host", value: "graphql.com")]) guard case let .data(data) = request.body else { XCTFail("Unexpected body") return diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ActionTests/InitiateAuthSRP/VerifyPasswordSRPTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ActionTests/InitiateAuthSRP/VerifyPasswordSRPTests.swift index 7628638339..062fa9b7bb 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ActionTests/InitiateAuthSRP/VerifyPasswordSRPTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ActionTests/InitiateAuthSRP/VerifyPasswordSRPTests.swift @@ -7,7 +7,7 @@ import XCTest import AWSCognitoIdentityProvider -import AWSClientRuntime +@_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime @testable import AWSPluginsTestCommon @testable import AWSCognitoAuthPlugin diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ActionTests/SignOut/RevokeTokenTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ActionTests/SignOut/RevokeTokenTests.swift index f69a2e7fec..cc6ae2290d 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ActionTests/SignOut/RevokeTokenTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ActionTests/SignOut/RevokeTokenTests.swift @@ -18,7 +18,7 @@ class RevokeTokenTests: XCTestCase { MockIdentityProvider( mockRevokeTokenResponse: { _ in revokeTokenInvoked.fulfill() - return try await RevokeTokenOutput(httpResponse: MockHttpResponse.ok) + return RevokeTokenOutput() } ) } @@ -92,7 +92,7 @@ class RevokeTokenTests: XCTestCase { let identityProviderFactory: BasicUserPoolEnvironment.CognitoUserPoolFactory = { MockIdentityProvider( mockRevokeTokenResponse: { _ in - return try await RevokeTokenOutput(httpResponse: MockHttpResponse.ok) + return RevokeTokenOutput() } ) } diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ActionTests/SignOut/SignOutGloballyTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ActionTests/SignOut/SignOutGloballyTests.swift index 44f7f866d0..92ab3956e4 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ActionTests/SignOut/SignOutGloballyTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ActionTests/SignOut/SignOutGloballyTests.swift @@ -18,7 +18,7 @@ class SignOutGloballyTests: XCTestCase { MockIdentityProvider( mockGlobalSignOutResponse: { _ in globalSignOutInvoked.fulfill() - return try await GlobalSignOutOutput(httpResponse: MockHttpResponse.ok) + return GlobalSignOutOutput() } ) } @@ -88,7 +88,7 @@ class SignOutGloballyTests: XCTestCase { let identityProviderFactory: BasicUserPoolEnvironment.CognitoUserPoolFactory = { MockIdentityProvider( mockGlobalSignOutResponse: { _ in - return try await GlobalSignOutOutput(httpResponse: MockHttpResponse.ok) + return GlobalSignOutOutput() } ) } diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ActionTests/VerifySignInChallenge/VerifySignInChallengeTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ActionTests/VerifySignInChallenge/VerifySignInChallengeTests.swift index 9937d86b74..ba635f3463 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ActionTests/VerifySignInChallenge/VerifySignInChallengeTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ActionTests/VerifySignInChallenge/VerifySignInChallengeTests.swift @@ -7,7 +7,7 @@ import XCTest import AWSCognitoIdentityProvider -import AWSClientRuntime +@_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime @testable import AWSPluginsTestCommon @testable import AWSCognitoAuthPlugin diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ConfigurationTests/ClientSecretConfigurationTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ConfigurationTests/ClientSecretConfigurationTests.swift index 1a3cdea3c7..47c0b7c6f1 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ConfigurationTests/ClientSecretConfigurationTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/ConfigurationTests/ClientSecretConfigurationTests.swift @@ -104,7 +104,7 @@ class ClientSecretConfigurationTests: XCTestCase { mockIdentityProvider = MockIdentityProvider( mockConfirmForgotPasswordOutput: { request in XCTAssertNotNil(request.secretHash) - return try await ConfirmForgotPasswordOutput(httpResponse: MockHttpResponse.ok) + return ConfirmForgotPasswordOutput() } ) try await plugin.confirmResetPassword( diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/HubEventTests/AuthHubEventHandlerTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/HubEventTests/AuthHubEventHandlerTests.swift index 496e7d2331..5dc7ee016a 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/HubEventTests/AuthHubEventHandlerTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/HubEventTests/AuthHubEventHandlerTests.swift @@ -358,12 +358,12 @@ class AuthHubEventHandlerTests: XCTestCase { let mockIdentityProvider = MockIdentityProvider( mockRevokeTokenResponse: { _ in - try await RevokeTokenOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + RevokeTokenOutput() }, mockGlobalSignOutResponse: { _ in - try await GlobalSignOutOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + GlobalSignOutOutput() }, mockDeleteUserOutput: { _ in - try await DeleteUserOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + DeleteUserOutput() } ) @@ -380,10 +380,10 @@ class AuthHubEventHandlerTests: XCTestCase { let mockIdentityProvider = MockIdentityProvider( mockRevokeTokenResponse: { _ in - try await RevokeTokenOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + RevokeTokenOutput() }, mockGlobalSignOutResponse: { _ in - try await GlobalSignOutOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + GlobalSignOutOutput() } ) @@ -418,9 +418,7 @@ class AuthHubEventHandlerTests: XCTestCase { let mockIdentityProvider = MockIdentityProvider( mockInitiateAuthResponse: { _ in - throw try await AWSCognitoIdentityProvider.NotAuthorizedException( - httpResponse: .init(body: .empty, statusCode: .ok) - ) + throw AWSCognitoIdentityProvider.NotAuthorizedException() }) configurePlugin(initialState: initialState, userPoolFactory: mockIdentityProvider) diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/AuthorizationTests/AWSAuthFetchSignInSessionOperationTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/AuthorizationTests/AWSAuthFetchSignInSessionOperationTests.swift index a67aa2522b..0afa434b9c 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/AuthorizationTests/AWSAuthFetchSignInSessionOperationTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/AuthorizationTests/AWSAuthFetchSignInSessionOperationTests.swift @@ -209,9 +209,7 @@ class AWSAuthFetchSignInSessionOperationTests: BaseAuthorizationTests { AmplifyCredentials.testDataWithExpiredTokens)) let initAuth: MockIdentityProvider.MockInitiateAuthResponse = { _ in - throw try await AWSCognitoIdentityProvider.NotAuthorizedException( - httpResponse: MockHttpResponse.ok - ) + throw AWSCognitoIdentityProvider.NotAuthorizedException() } let plugin = configurePluginWith(userPool: { MockIdentityProvider(mockInitiateAuthResponse: initAuth) }, initialState: initialState) @@ -266,9 +264,7 @@ class AWSAuthFetchSignInSessionOperationTests: BaseAuthorizationTests { } let awsCredentials: MockIdentity.MockGetCredentialsResponse = { _ in - throw try await AWSCognitoIdentityProvider.NotAuthorizedException( - httpResponse: MockHttpResponse.ok - ) + throw AWSCognitoIdentityProvider.NotAuthorizedException() } let plugin = configurePluginWith( diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/AuthenticationProviderDeleteUserTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/AuthenticationProviderDeleteUserTests.swift index d7d8080386..fcdd702657 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/AuthenticationProviderDeleteUserTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/AuthenticationProviderDeleteUserTests.swift @@ -13,19 +13,19 @@ import XCTest import AWSCognitoIdentityProvider import ClientRuntime import AwsCommonRuntimeKit -import AWSClientRuntime +@_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime class AuthenticationProviderDeleteUserTests: BasePluginTest { func testDeleteUserSuccess() async { mockIdentityProvider = MockIdentityProvider( mockRevokeTokenResponse: { _ in - try await RevokeTokenOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + RevokeTokenOutput() }, mockGlobalSignOutResponse: { _ in - try await GlobalSignOutOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + GlobalSignOutOutput() }, mockDeleteUserOutput: { _ in - try await DeleteUserOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + DeleteUserOutput() } ) do { @@ -54,7 +54,7 @@ class AuthenticationProviderDeleteUserTests: BasePluginTest { throw AWSCognitoIdentityProvider.InternalErrorException() }, mockDeleteUserOutput: { _ in - try await DeleteUserOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + DeleteUserOutput() } ) do { @@ -79,9 +79,9 @@ class AuthenticationProviderDeleteUserTests: BasePluginTest { func testOfflineDeleteUser() async throws { mockIdentityProvider = MockIdentityProvider( mockRevokeTokenResponse: { _ in - try await RevokeTokenOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + RevokeTokenOutput() }, mockGlobalSignOutResponse: { _ in - try await GlobalSignOutOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + GlobalSignOutOutput() }, mockDeleteUserOutput: { _ in throw CommonRunTimeError.crtError(CRTError(code: 1059)) @@ -113,9 +113,9 @@ class AuthenticationProviderDeleteUserTests: BasePluginTest { func testOfflineDeleteUserAndRetry() async throws { mockIdentityProvider = MockIdentityProvider( mockRevokeTokenResponse: { _ in - try await RevokeTokenOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + RevokeTokenOutput() }, mockGlobalSignOutResponse: { _ in - try await GlobalSignOutOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + GlobalSignOutOutput() }, mockDeleteUserOutput: { _ in throw CommonRunTimeError.crtError(CRTError(code: 1059)) @@ -134,12 +134,12 @@ class AuthenticationProviderDeleteUserTests: BasePluginTest { mockIdentityProvider = MockIdentityProvider( mockRevokeTokenResponse: { _ in - try await RevokeTokenOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + RevokeTokenOutput() }, mockGlobalSignOutResponse: { _ in - try await GlobalSignOutOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + GlobalSignOutOutput() }, mockDeleteUserOutput: { _ in - try await DeleteUserOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + DeleteUserOutput() } ) do { @@ -165,9 +165,9 @@ class AuthenticationProviderDeleteUserTests: BasePluginTest { func testDeleteUserInternalErrorException() async { mockIdentityProvider = MockIdentityProvider( mockRevokeTokenResponse: { _ in - try await RevokeTokenOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + RevokeTokenOutput() }, mockGlobalSignOutResponse: { _ in - try await GlobalSignOutOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + GlobalSignOutOutput() }, mockDeleteUserOutput: { _ in throw AWSClientRuntime.UnknownAWSHTTPServiceError( @@ -203,9 +203,9 @@ class AuthenticationProviderDeleteUserTests: BasePluginTest { func testDeleteUserWithInvalidParameterException() async { mockIdentityProvider = MockIdentityProvider( mockRevokeTokenResponse: { _ in - try await RevokeTokenOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + RevokeTokenOutput() }, mockGlobalSignOutResponse: { _ in - try await GlobalSignOutOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + GlobalSignOutOutput() }, mockDeleteUserOutput: { _ in throw AWSCognitoIdentityProvider.InvalidParameterException() @@ -237,9 +237,9 @@ class AuthenticationProviderDeleteUserTests: BasePluginTest { func testDeleteUserWithNotAuthorizedException() async { mockIdentityProvider = MockIdentityProvider( mockRevokeTokenResponse: { _ in - try await RevokeTokenOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + RevokeTokenOutput() }, mockGlobalSignOutResponse: { _ in - try await GlobalSignOutOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + GlobalSignOutOutput() }, mockDeleteUserOutput: { _ in throw AWSCognitoIdentityProvider.NotAuthorizedException() @@ -270,9 +270,9 @@ class AuthenticationProviderDeleteUserTests: BasePluginTest { func testDeleteUserWithPasswordResetRequiredException() async { mockIdentityProvider = MockIdentityProvider( mockRevokeTokenResponse: { _ in - try await RevokeTokenOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + RevokeTokenOutput() }, mockGlobalSignOutResponse: { _ in - try await GlobalSignOutOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + GlobalSignOutOutput() }, mockDeleteUserOutput: { _ in throw AWSCognitoIdentityProvider.PasswordResetRequiredException() @@ -304,9 +304,9 @@ class AuthenticationProviderDeleteUserTests: BasePluginTest { func testDeleteUserWithResourceNotFoundException() async { mockIdentityProvider = MockIdentityProvider( mockRevokeTokenResponse: { _ in - try await RevokeTokenOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + RevokeTokenOutput() }, mockGlobalSignOutResponse: { _ in - try await GlobalSignOutOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + GlobalSignOutOutput() }, mockDeleteUserOutput: { _ in throw AWSCognitoIdentityProvider.ResourceNotFoundException() @@ -338,9 +338,9 @@ class AuthenticationProviderDeleteUserTests: BasePluginTest { func testDeleteUserWithTooManyRequestsException() async { mockIdentityProvider = MockIdentityProvider( mockRevokeTokenResponse: { _ in - try await RevokeTokenOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + RevokeTokenOutput() }, mockGlobalSignOutResponse: { _ in - try await GlobalSignOutOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + GlobalSignOutOutput() }, mockDeleteUserOutput: { _ in throw AWSCognitoIdentityProvider.TooManyRequestsException() @@ -372,9 +372,9 @@ class AuthenticationProviderDeleteUserTests: BasePluginTest { func testDeleteUserWithUserNotConfirmedException() async { mockIdentityProvider = MockIdentityProvider( mockRevokeTokenResponse: { _ in - try await RevokeTokenOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + RevokeTokenOutput() }, mockGlobalSignOutResponse: { _ in - try await GlobalSignOutOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + GlobalSignOutOutput() }, mockDeleteUserOutput: { _ in throw AWSCognitoIdentityProvider.UserNotConfirmedException() @@ -407,9 +407,9 @@ class AuthenticationProviderDeleteUserTests: BasePluginTest { func testDeleteUserWithUserNotFoundException() async { mockIdentityProvider = MockIdentityProvider( mockRevokeTokenResponse: { _ in - try await RevokeTokenOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + RevokeTokenOutput() }, mockGlobalSignOutResponse: { _ in - try await GlobalSignOutOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + GlobalSignOutOutput() }, mockDeleteUserOutput: { _ in throw AWSCognitoIdentityProvider.UserNotFoundException() diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/ClientBehaviorConfirmResetPasswordTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/ClientBehaviorConfirmResetPasswordTests.swift index b8445af966..e72b5fc73b 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/ClientBehaviorConfirmResetPasswordTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/ClientBehaviorConfirmResetPasswordTests.swift @@ -21,7 +21,7 @@ class ClientBehaviorConfirmResetPasswordTests: AWSCognitoAuthClientBehaviorTests super.setUp() mockIdentityProvider = MockIdentityProvider( mockConfirmForgotPasswordOutput: { _ in - try await ConfirmForgotPasswordOutput(httpResponse: MockHttpResponse.ok) + ConfirmForgotPasswordOutput() } ) } @@ -63,7 +63,7 @@ class ClientBehaviorConfirmResetPasswordTests: AWSCognitoAuthClientBehaviorTests func testSuccessfulConfirmResetPassword() async throws { mockIdentityProvider = MockIdentityProvider( mockConfirmForgotPasswordOutput: { _ in - try await ConfirmForgotPasswordOutput(httpResponse: MockHttpResponse.ok) + ConfirmForgotPasswordOutput() } ) try await plugin.confirmResetPassword(for: "username", with: "newpassword", confirmationCode: "code", options: nil) @@ -81,7 +81,7 @@ class ClientBehaviorConfirmResetPasswordTests: AWSCognitoAuthClientBehaviorTests mockIdentityProvider = MockIdentityProvider( mockConfirmForgotPasswordOutput: { _ in - try await ConfirmForgotPasswordOutput(httpResponse: MockHttpResponse.ok) + ConfirmForgotPasswordOutput() } ) do { @@ -109,7 +109,7 @@ class ClientBehaviorConfirmResetPasswordTests: AWSCognitoAuthClientBehaviorTests mockConfirmForgotPasswordOutput: { request in XCTAssertNoThrow(request.clientMetadata) XCTAssertEqual(request.clientMetadata?["key"], "value") - return try await ConfirmForgotPasswordOutput(httpResponse: MockHttpResponse.ok) + return ConfirmForgotPasswordOutput() } ) let pluginOptions = AWSAuthConfirmResetPasswordOptions(metadata: ["key": "value"]) @@ -131,7 +131,7 @@ class ClientBehaviorConfirmResetPasswordTests: AWSCognitoAuthClientBehaviorTests mockIdentityProvider = MockIdentityProvider( mockConfirmForgotPasswordOutput: { _ in - try await ConfirmForgotPasswordOutput(httpResponse: MockHttpResponse.ok) + ConfirmForgotPasswordOutput() } ) do { @@ -251,9 +251,7 @@ class ClientBehaviorConfirmResetPasswordTests: AWSCognitoAuthClientBehaviorTests func testConfirmResetPasswordWithInvalidLambdaResponseException() async throws { mockIdentityProvider = MockIdentityProvider( mockConfirmForgotPasswordOutput: { _ in - throw try await AWSCognitoIdentityProvider.InvalidLambdaResponseException( - httpResponse: .init(body: .empty, statusCode: .accepted) - ) + throw AWSCognitoIdentityProvider.InvalidLambdaResponseException() } ) do { diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/ClientBehaviorResetPasswordTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/ClientBehaviorResetPasswordTests.swift index e24e688536..40661b0fbc 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/ClientBehaviorResetPasswordTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/ClientBehaviorResetPasswordTests.swift @@ -173,9 +173,7 @@ class ClientBehaviorResetPasswordTests: AWSCognitoAuthClientBehaviorTests { mockIdentityProvider = MockIdentityProvider( mockForgotPasswordOutput: { _ in - throw try await AWSCognitoIdentityProvider.InternalErrorException( - httpResponse: .init(body: .empty, statusCode: .accepted) - ) + throw AWSCognitoIdentityProvider.InternalErrorException() } ) do { diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/MFA/FetchMFAPreferenceTaskTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/MFA/FetchMFAPreferenceTaskTests.swift index e713f439d8..9c63e5088a 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/MFA/FetchMFAPreferenceTaskTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/MFA/FetchMFAPreferenceTaskTests.swift @@ -11,7 +11,7 @@ import XCTest import Amplify @testable import AWSCognitoAuthPlugin import AWSCognitoIdentityProvider -import AWSClientRuntime +@_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime // swiftlint:disable type_body_length // swiftlint:disable file_length diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/MFA/SetUpTOTPTaskTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/MFA/SetUpTOTPTaskTests.swift index 7d21c937a3..9677d365c5 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/MFA/SetUpTOTPTaskTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/MFA/SetUpTOTPTaskTests.swift @@ -11,7 +11,7 @@ import XCTest import Amplify @testable import AWSCognitoAuthPlugin import AWSCognitoIdentityProvider -import AWSClientRuntime +@_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime // swiftlint:disable type_body_length // swiftlint:disable file_length diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/MFA/UpdateMFAPreferenceTaskTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/MFA/UpdateMFAPreferenceTaskTests.swift index a4c6fa9d27..75b367b5c0 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/MFA/UpdateMFAPreferenceTaskTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/MFA/UpdateMFAPreferenceTaskTests.swift @@ -11,7 +11,7 @@ import XCTest import Amplify @testable import AWSCognitoAuthPlugin import AWSCognitoIdentityProvider -import AWSClientRuntime +@_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime // swiftlint:disable type_body_length // swiftlint:disable file_length @@ -41,11 +41,11 @@ class UpdateMFAPreferenceTaskTests: BasePluginTest { }, mockSetUserMFAPreferenceResponse: { request in XCTAssertEqual( - request.smsMfaSettings, - smsPreference.smsSetting()) + request.smsMfaSettings?.preferredMfa, + smsPreference.smsSetting().preferredMfa) XCTAssertEqual( - request.softwareTokenMfaSettings, - totpPreference.softwareTokenSetting()) + request.softwareTokenMfaSettings?.preferredMfa, + totpPreference.softwareTokenSetting().preferredMfa) return .init() }) diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/MFA/VerifyTOTPSetupTaskTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/MFA/VerifyTOTPSetupTaskTests.swift index 0cd03bf4e9..e9b727624b 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/MFA/VerifyTOTPSetupTaskTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/MFA/VerifyTOTPSetupTaskTests.swift @@ -11,7 +11,7 @@ import XCTest import Amplify @testable import AWSCognitoAuthPlugin import AWSCognitoIdentityProvider -import AWSClientRuntime +@_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime // swiftlint:disable type_body_length // swiftlint:disable file_length diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignIn/AWSAuthSignInPluginTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignIn/AWSAuthSignInPluginTests.swift index 1b4a9c973d..22ae40ce2c 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignIn/AWSAuthSignInPluginTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignIn/AWSAuthSignInPluginTests.swift @@ -954,12 +954,7 @@ class AWSAuthSignInPluginTests: BasePluginTest { func testSignInWithPasswordResetRequiredException2() async { self.mockIdentityProvider = MockIdentityProvider(mockInitiateAuthResponse: { _ in - throw try await AWSCognitoIdentityProvider.PasswordResetRequiredException( - httpResponse: .init(body: .empty, statusCode: .badRequest), - decoder: nil, - message: nil, - requestID: nil - ) + throw AWSCognitoIdentityProvider.PasswordResetRequiredException() }) let options = AuthSignInRequest.Options() @@ -1132,9 +1127,7 @@ class AWSAuthSignInPluginTests: BasePluginTest { func testSignInWithUserNotConfirmedException2() async { self.mockIdentityProvider = MockIdentityProvider(mockInitiateAuthResponse: { _ in - throw try await AWSCognitoIdentityProvider.UserNotConfirmedException( - httpResponse: .init(body: .empty, statusCode: .badRequest) - ) + throw AWSCognitoIdentityProvider.UserNotConfirmedException() }) let options = AuthSignInRequest.Options() diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignIn/SignInSetUpTOTPTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignIn/SignInSetUpTOTPTests.swift index 387a70f340..65afb80f8a 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignIn/SignInSetUpTOTPTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignIn/SignInSetUpTOTPTests.swift @@ -10,7 +10,7 @@ import AWSCognitoIdentity @testable import Amplify @testable import AWSCognitoAuthPlugin import AWSCognitoIdentityProvider -import AWSClientRuntime +@_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime class SignInSetUpTOTPTests: BasePluginTest { diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignUp/AWSAuthConfirmSignUpAPITests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignUp/AWSAuthConfirmSignUpAPITests.swift index 92812c342d..0dea576291 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignUp/AWSAuthConfirmSignUpAPITests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignUp/AWSAuthConfirmSignUpAPITests.swift @@ -11,7 +11,7 @@ import AWSCognitoIdentity @testable import AWSCognitoAuthPlugin import AWSCognitoIdentityProvider import ClientRuntime -import AWSClientRuntime +@_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime class AWSAuthConfirmSignUpAPITests: BasePluginTest { @@ -177,9 +177,7 @@ class AWSAuthConfirmSignUpAPITests: BasePluginTest { self.mockIdentityProvider = MockIdentityProvider( mockConfirmSignUpResponse: { _ in - throw try await AWSCognitoIdentityProvider.InternalErrorException( - httpResponse: .init(body: .empty, statusCode: .accepted) - ) + throw AWSCognitoIdentityProvider.InternalErrorException() } ) diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignUp/AWSAuthConfirmSignUpTaskTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignUp/AWSAuthConfirmSignUpTaskTests.swift index 62a488fce2..74eed8cfb8 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignUp/AWSAuthConfirmSignUpTaskTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignUp/AWSAuthConfirmSignUpTaskTests.swift @@ -16,7 +16,7 @@ import XCTest @testable import AWSCognitoAuthPlugin @testable import AWSPluginsTestCommon import ClientRuntime -import AWSClientRuntime +@_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime import AWSCognitoIdentityProvider class AWSAuthConfirmSignUpTaskTests: XCTestCase { @@ -33,7 +33,7 @@ class AWSAuthConfirmSignUpTaskTests: XCTestCase { let functionExpectation = expectation(description: "API call should be invoked") let confirmSignUp: MockIdentityProvider.MockConfirmSignUpResponse = { _ in functionExpectation.fulfill() - return try await .init(httpResponse: MockHttpResponse.ok) + return .init() } let authEnvironment = Defaults.makeDefaultAuthEnvironment( diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignUp/AWSAuthResendSignUpCodeAPITests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignUp/AWSAuthResendSignUpCodeAPITests.swift index 9ad2404e72..492b17f2a8 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignUp/AWSAuthResendSignUpCodeAPITests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignUp/AWSAuthResendSignUpCodeAPITests.swift @@ -148,9 +148,7 @@ class AWSAuthResendSignUpCodeAPITests: AWSCognitoAuthClientBehaviorTests { mockIdentityProvider = MockIdentityProvider( mockResendConfirmationCodeOutput: { _ in - throw try await AWSCognitoIdentityProvider.CodeDeliveryFailureException( - httpResponse: .init(body: .empty, statusCode: .accepted) - ) + throw AWSCognitoIdentityProvider.CodeDeliveryFailureException() } ) do { diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignUp/AWSAuthSignUpAPITests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignUp/AWSAuthSignUpAPITests.swift index 206a32f568..bd44caa089 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignUp/AWSAuthSignUpAPITests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignUp/AWSAuthSignUpAPITests.swift @@ -245,9 +245,7 @@ class AWSAuthSignUpAPITests: BasePluginTest { self.mockIdentityProvider = MockIdentityProvider( mockSignUpResponse: { _ in - throw try await AWSCognitoIdentityProvider.InternalErrorException( - httpResponse: .init(body: .empty, statusCode: .accepted) - ) + throw AWSCognitoIdentityProvider.InternalErrorException() } ) diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignUp/AWSAuthSignUpTaskTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignUp/AWSAuthSignUpTaskTests.swift index df79b450dc..b2192c1357 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignUp/AWSAuthSignUpTaskTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/ClientBehaviorTests/SignUp/AWSAuthSignUpTaskTests.swift @@ -10,7 +10,7 @@ import XCTest @testable import AWSCognitoAuthPlugin @testable import AWSPluginsTestCommon import ClientRuntime -import AWSClientRuntime +@_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime import AWSCognitoIdentityProvider diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/DeviceBehaviorTests/DeviceBehaviorFetchDevicesTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/DeviceBehaviorTests/DeviceBehaviorFetchDevicesTests.swift index b8fc44a77d..a0606fdac9 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/DeviceBehaviorTests/DeviceBehaviorFetchDevicesTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/DeviceBehaviorTests/DeviceBehaviorFetchDevicesTests.swift @@ -20,7 +20,7 @@ class DeviceBehaviorFetchDevicesTests: BasePluginTest { super.setUp() mockIdentityProvider = MockIdentityProvider( mockListDevicesOutput: { _ in - try await ListDevicesOutput(httpResponse: MockHttpResponse.ok) + try ListDevicesOutput() } ) } @@ -147,9 +147,7 @@ class DeviceBehaviorFetchDevicesTests: BasePluginTest { mockIdentityProvider = MockIdentityProvider( mockListDevicesOutput: { _ in - throw try await AWSCognitoIdentityProvider.InternalErrorException( - httpResponse: .init(body: .empty, statusCode: .accepted) - ) + throw AWSCognitoIdentityProvider.InternalErrorException() } ) do { diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/DeviceBehaviorTests/DeviceBehaviorForgetDeviceTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/DeviceBehaviorTests/DeviceBehaviorForgetDeviceTests.swift index a8cc6e99cc..2bceafa709 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/DeviceBehaviorTests/DeviceBehaviorForgetDeviceTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/DeviceBehaviorTests/DeviceBehaviorForgetDeviceTests.swift @@ -20,7 +20,7 @@ class DeviceBehaviorForgetDeviceTests: BasePluginTest { super.setUp() mockIdentityProvider = MockIdentityProvider( mockForgetDeviceResponse: { _ in - try await ForgetDeviceOutput(httpResponse: MockHttpResponse.ok) + ForgetDeviceOutput() } ) } @@ -139,12 +139,7 @@ class DeviceBehaviorForgetDeviceTests: BasePluginTest { mockIdentityProvider = MockIdentityProvider( mockForgetDeviceResponse: { _ in - throw try await AWSCognitoIdentityProvider.InvalidParameterException( - httpResponse: .init(body: .empty, statusCode: .accepted), - decoder: nil, - message: nil, - requestID: nil - ) + throw AWSCognitoIdentityProvider.InvalidParameterException() } ) do { diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/DeviceBehaviorTests/DeviceBehaviorRememberDeviceTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/DeviceBehaviorTests/DeviceBehaviorRememberDeviceTests.swift index 5f92f37bcf..b0d262be4c 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/DeviceBehaviorTests/DeviceBehaviorRememberDeviceTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/DeviceBehaviorTests/DeviceBehaviorRememberDeviceTests.swift @@ -20,9 +20,7 @@ class DeviceBehaviorRememberDeviceTests: BasePluginTest { super.setUp() mockIdentityProvider = MockIdentityProvider( mockRememberDeviceResponse: { _ in - try await UpdateDeviceStatusOutput( - httpResponse: MockHttpResponse.ok - ) + try UpdateDeviceStatusOutput() } ) } @@ -143,12 +141,7 @@ class DeviceBehaviorRememberDeviceTests: BasePluginTest { mockIdentityProvider = MockIdentityProvider( mockRememberDeviceResponse: { _ in - throw try await AWSCognitoIdentityProvider.InvalidUserPoolConfigurationException( - httpResponse: .init(body: .empty, statusCode: .accepted), - decoder: nil, - message: nil, - requestID: nil - ) + throw AWSCognitoIdentityProvider.InvalidUserPoolConfigurationException() } ) do { diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/AWSCognitoAuthUserBehaviorTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/AWSCognitoAuthUserBehaviorTests.swift index 3c3eebe100..b317ebfeca 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/AWSCognitoAuthUserBehaviorTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/AWSCognitoAuthUserBehaviorTests.swift @@ -27,10 +27,10 @@ class AWSCognitoAuthUserBehaviorTests: BasePluginTest { UpdateUserAttributesOutput() }, mockConfirmUserAttributeOutput: { _ in - try await VerifyUserAttributeOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + VerifyUserAttributeOutput() }, mockChangePasswordOutput: { _ in - try await ChangePasswordOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + ChangePasswordOutput() } ) } diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/SendUserAttributeVerificationCodeTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/SendUserAttributeVerificationCodeTests.swift index cf2a4239d9..6271cafa3e 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/SendUserAttributeVerificationCodeTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/SendUserAttributeVerificationCodeTests.swift @@ -76,12 +76,7 @@ class SendUserAttributeVerificationCodeTests: BasePluginTest { func testSendVerificationCodeWithCodeMismatchException() async throws { mockIdentityProvider = MockIdentityProvider(mockGetUserAttributeVerificationCodeOutput: { _ in - throw try await AWSCognitoIdentityProvider.CodeDeliveryFailureException( - httpResponse: .init(body: .empty, statusCode: .accepted), - decoder: nil, - message: nil, - requestID: nil - ) + throw AWSCognitoIdentityProvider.CodeDeliveryFailureException() }) do { _ = try await plugin.sendVerificationCode(forUserAttributeKey: .email) diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/UserBehaviorChangePasswordTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/UserBehaviorChangePasswordTests.swift index 4b17d9d05e..7ce3db71ac 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/UserBehaviorChangePasswordTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/UserBehaviorChangePasswordTests.swift @@ -25,7 +25,7 @@ class UserBehaviorChangePasswordTests: BasePluginTest { /// func testSuccessfulChangePassword() async throws { self.mockIdentityProvider = MockIdentityProvider(mockChangePasswordOutput: { _ in - return try await ChangePasswordOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + return ChangePasswordOutput() }) try await plugin.update(oldPassword: "old password", to: "new password") } @@ -133,12 +133,7 @@ class UserBehaviorChangePasswordTests: BasePluginTest { func testChangePasswordWithLimitExceededException() async throws { self.mockIdentityProvider = MockIdentityProvider(mockChangePasswordOutput: { _ in - throw try await AWSCognitoIdentityProvider.LimitExceededException( - httpResponse: .init(body: .empty, statusCode: .accepted), - decoder: nil, - message: nil, - requestID: nil - ) + throw AWSCognitoIdentityProvider.LimitExceededException() }) do { try await plugin.update(oldPassword: "old password", to: "new password") diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/UserBehaviorConfirmAttributeTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/UserBehaviorConfirmAttributeTests.swift index 870afbbe4f..0a9974552e 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/UserBehaviorConfirmAttributeTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/UserBehaviorConfirmAttributeTests.swift @@ -23,7 +23,7 @@ class UserBehaviorConfirmAttributeTests: BasePluginTest { /// func testSuccessfulConfirmUpdateUserAttributes() async throws { mockIdentityProvider = MockIdentityProvider(mockConfirmUserAttributeOutput: { _ in - try await VerifyUserAttributeOutput(httpResponse: .init(body: .empty, statusCode: .ok)) + VerifyUserAttributeOutput() }) try await plugin.confirm(userAttribute: .email, confirmationCode: "code") } @@ -98,12 +98,7 @@ class UserBehaviorConfirmAttributeTests: BasePluginTest { func testcConfirmUpdateUserAttributesWithInternalErrorException() async throws { mockIdentityProvider = MockIdentityProvider(mockConfirmUserAttributeOutput: { _ in - throw try await AWSCognitoIdentityProvider.InternalErrorException( - httpResponse: .init(body: .empty, statusCode: .accepted), - decoder: nil, - message: nil, - requestID: nil - ) + throw AWSCognitoIdentityProvider.InternalErrorException() }) do { try await plugin.confirm(userAttribute: .email, confirmationCode: "code") diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/UserBehaviorFetchAttributeTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/UserBehaviorFetchAttributeTests.swift index d814fe0090..a34aa32bc9 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/UserBehaviorFetchAttributeTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/UserBehaviorFetchAttributeTests.swift @@ -10,7 +10,7 @@ import XCTest @testable import AWSCognitoAuthPlugin import AWSCognitoIdentityProvider import ClientRuntime -import AWSClientRuntime +@_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime class UserBehaviorFetchAttributesTests: BasePluginTest { @@ -136,12 +136,7 @@ class UserBehaviorFetchAttributesTests: BasePluginTest { func testFetchUserAttributesWithNotAuthorizedException() async throws { mockIdentityProvider = MockIdentityProvider(mockGetUserAttributeResponse: { _ in - throw try await AWSCognitoIdentityProvider.NotAuthorizedException( - httpResponse: .init(body: .empty, statusCode: .accepted), - decoder: nil, - message: nil, - requestID: nil - ) + throw AWSCognitoIdentityProvider.NotAuthorizedException() }) do { diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/UserBehaviorUpdateAttributeTests.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/UserBehaviorUpdateAttributeTests.swift index 75f7d52024..8df4a55b47 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/UserBehaviorUpdateAttributeTests.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/UserBehaviourTests/UserBehaviorUpdateAttributeTests.swift @@ -10,7 +10,7 @@ import XCTest @testable import AWSCognitoAuthPlugin import AWSCognitoIdentityProvider import ClientRuntime -import AWSClientRuntime +@_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime class UserBehaviorUpdateAttributesTests: BasePluginTest { @@ -68,12 +68,7 @@ class UserBehaviorUpdateAttributesTests: BasePluginTest { func testUpdateUserAttributesWithAliasExistsException() async throws { mockIdentityProvider = MockIdentityProvider(mockUpdateUserAttributeResponse: { _ in - throw try await AWSCognitoIdentityProvider.AliasExistsException( - httpResponse: .init(body: .empty, statusCode: .accepted), - decoder: nil, - message: nil, - requestID: nil - ) + throw AWSCognitoIdentityProvider.AliasExistsException() }) do { _ = try await plugin.update(userAttribute: AuthUserAttribute(.email, value: "Amplify@amazon.com")) diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Input/InitiateAuthInput+Codable.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Input/InitiateAuthInput+Codable.swift index b37894ccb8..6aca69ede1 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Input/InitiateAuthInput+Codable.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Input/InitiateAuthInput+Codable.swift @@ -30,3 +30,5 @@ extension InitiateAuthInput: Decodable { clientMetadata: clientMetadata) } } + +extension CognitoIdentityProviderClientTypes.AuthFlowType: Decodable { } diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Response/ChangePasswordOutputResponse+Codable.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Response/ChangePasswordOutputResponse+Codable.swift index ada8712912..a0cc62c640 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Response/ChangePasswordOutputResponse+Codable.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Response/ChangePasswordOutputResponse+Codable.swift @@ -6,7 +6,7 @@ // import AWSCognitoIdentityProvider -import ClientRuntime +import SmithyHTTPAPI extension ChangePasswordOutput: Codable { @@ -16,7 +16,7 @@ extension ChangePasswordOutput: Codable { public init(from decoder: Decoder) throws { let containerValues = try decoder.container(keyedBy: CodingKeys.self) - guard let httpResponse = try containerValues.decodeIfPresent(HttpResponse.self, forKey: .httpResponse) else { + guard let httpResponse = try containerValues.decodeIfPresent(HTTPResponse.self, forKey: .httpResponse) else { fatalError("Unable to decode http response") } self.init() diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Response/ForgotPasswordOutputResponse+Codable.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Response/ForgotPasswordOutputResponse+Codable.swift index ab21746125..0c35be603a 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Response/ForgotPasswordOutputResponse+Codable.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Response/ForgotPasswordOutputResponse+Codable.swift @@ -15,10 +15,13 @@ extension ForgotPasswordOutput: Codable { } public init(from decoder: Swift.Decoder) throws { - self.init() - let containerValues = try decoder.container(keyedBy: CodingKeys.self) - let codeDeliveryDetailsDecoded = try containerValues.decodeIfPresent(CognitoIdentityProviderClientTypes.CodeDeliveryDetailsType.self, forKey: .codeDeliveryDetails) - codeDeliveryDetails = codeDeliveryDetailsDecoded + let container = try decoder.container(keyedBy: CodingKeys.self) + try self.init( + codeDeliveryDetails: container.decodeIfPresent( + CognitoIdentityProviderClientTypes.CodeDeliveryDetailsType.self, + forKey: .codeDeliveryDetails + ) + ) } public func encode(to encoder: Encoder) throws { @@ -26,3 +29,25 @@ extension ForgotPasswordOutput: Codable { } } + +extension CognitoIdentityProviderClientTypes.CodeDeliveryDetailsType: Decodable { + private enum CodingKeys: String, CodingKey { + case attributeName = "AttributeName" + case deliveryMedium = "DeliveryMedium" + case destination = "Destination" + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + try self.init( + attributeName: container.decodeIfPresent(String.self, forKey: .attributeName), + deliveryMedium: container.decodeIfPresent( + CognitoIdentityProviderClientTypes.DeliveryMediumType.self, + forKey: .deliveryMedium + ), + destination: container.decodeIfPresent(String.self, forKey: .destination) + ) + } +} + +extension CognitoIdentityProviderClientTypes.DeliveryMediumType: Decodable {} diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Response/GetCredentialsForIdentityOutputResponse+Codable.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Response/GetCredentialsForIdentityOutputResponse+Codable.swift index 05b56dcaf9..c602cf7108 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Response/GetCredentialsForIdentityOutputResponse+Codable.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Response/GetCredentialsForIdentityOutputResponse+Codable.swift @@ -27,3 +27,22 @@ extension GetCredentialsForIdentityOutput: Codable { fatalError("This implementation is not needed") } } + +extension CognitoIdentityClientTypes.Credentials: Decodable { + private enum CodingKeys: String, CodingKey { + case accessKeyId = "AccessKeyId" + case expiration = "Expiration" + case secretKey = "SecretKey" + case sessionToken = "SessionToken" + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + try self.init( + accessKeyId: container.decodeIfPresent(String.self, forKey: .accessKeyId), + expiration: container.decodeIfPresent(Date.self, forKey: .expiration), + secretKey: container.decodeIfPresent(String.self, forKey: .secretKey), + sessionToken: container.decodeIfPresent(String.self, forKey: .sessionToken) + ) + } +} diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Response/HttpResponse+Codable.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Response/HttpResponse+Codable.swift index 20c6f99f1e..f185186f5b 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Response/HttpResponse+Codable.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Response/HttpResponse+Codable.swift @@ -6,29 +6,31 @@ // import AWSCognitoIdentityProvider -import ClientRuntime +import SmithyHTTPAPI -extension HttpResponse: Codable { } +extension SmithyHTTPAPI.HTTPResponse: Codable { } -enum HttpResponseCodingKeys: String, CodingKey { +enum HTTPResponseCodingKeys: String, CodingKey { case statusCode = "statusCode" } -extension Encodable where Self: HttpResponse { +extension Encodable where Self: SmithyHTTPAPI.HTTPResponse { public func encode(to encoder: Encoder) throws { - - var container = encoder.container(keyedBy: HttpResponseCodingKeys.self) + var container = encoder.container(keyedBy: HTTPResponseCodingKeys.self) try container.encode(statusCode.rawValue, forKey: .statusCode) } } -extension Decodable where Self: HttpResponse { +extension Decodable where Self: SmithyHTTPAPI.HTTPResponse { public init(from decoder: Decoder) throws { - let containerValues = try decoder.container(keyedBy: HttpResponseCodingKeys.self) + let containerValues = try decoder.container(keyedBy: HTTPResponseCodingKeys.self) let httpStatusCode = try containerValues.decodeIfPresent(Int.self, forKey: .statusCode) - self = HttpResponse(body: .empty, statusCode: HttpStatusCode(rawValue: httpStatusCode ?? 404) ?? .notFound) as! Self + self = SmithyHTTPAPI.HTTPResponse( + body: .empty, + statusCode: SmithyHTTPAPI.HTTPStatusCode(rawValue: httpStatusCode ?? 404) ?? .notFound + ) as! Self } } diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Response/InitiateAuthOutputResponse+Codable.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Response/InitiateAuthOutputResponse+Codable.swift index 5e9eae1202..155fd62081 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Response/InitiateAuthOutputResponse+Codable.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/AuthCodableImplementations/Cognito/Response/InitiateAuthOutputResponse+Codable.swift @@ -44,3 +44,44 @@ extension InitiateAuthOutput: Codable { } } + +extension CognitoIdentityProviderClientTypes.AuthenticationResultType: Decodable { + private enum CodingKeys: String, CodingKey { + case accessToken = "AccessToken" + case expiresIn = "ExpiresIn" + case idToken = "IdToken" + case newDeviceMetadata = "NewDeviceMetadata" + case refreshToken = "RefreshToken" + case tokenType = "TokenType" + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + try self.init( + accessToken: container.decodeIfPresent(String.self, forKey: .accessToken), + expiresIn: container.decode(Int.self, forKey: .expiresIn), + idToken: container.decodeIfPresent(String.self, forKey: .idToken), + newDeviceMetadata: container.decodeIfPresent( + CognitoIdentityProviderClientTypes.NewDeviceMetadataType.self, + forKey: .newDeviceMetadata + ), + refreshToken: container.decodeIfPresent(String.self, forKey: .refreshToken), + tokenType: container.decodeIfPresent(String.self, forKey: .tokenType) + ) + } +} + +extension CognitoIdentityProviderClientTypes.NewDeviceMetadataType: Decodable { + private enum CodingKeys: String, CodingKey { + case deviceGroupKey = "DeviceGroupKey" + case deviceKey = "DeviceKey" + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + try self.init( + deviceGroupKey: container.decodeIfPresent(String.self, forKey: .deviceGroupKey), + deviceKey: container.decodeIfPresent(String.self, forKey: .deviceKey) + ) + } +} diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/CognitoAPIDecoding/CognitoAPIDecodingHelper.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/CognitoAPIDecoding/CognitoAPIDecodingHelper.swift index 2c33d8e7ab..6f80804dce 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/CognitoAPIDecoding/CognitoAPIDecodingHelper.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/CognitoAPIDecoding/CognitoAPIDecodingHelper.swift @@ -9,7 +9,7 @@ import AWSCognitoIdentity import AWSCognitoIdentityProvider import AWSPluginsCore import ClientRuntime -import AWSClientRuntime +@_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime @testable import Amplify @testable import AWSCognitoAuthPlugin diff --git a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/Mocks/AuthTestHarnessInput+MockIdentityProvider.swift b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/Mocks/AuthTestHarnessInput+MockIdentityProvider.swift index cca624fbb3..02cd19b66e 100644 --- a/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/Mocks/AuthTestHarnessInput+MockIdentityProvider.swift +++ b/AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TestHarness/Mocks/AuthTestHarnessInput+MockIdentityProvider.swift @@ -34,7 +34,9 @@ extension AuthTestHarnessInput { fatalError("Missing input") } if let request = apiData.expectedInput { - XCTAssertEqual(input, request) + XCTAssertEqual(input.clientId, request.clientId) + XCTAssertEqual(input.clientSecret, request.clientSecret) + XCTAssertEqual(input.token, request.token) } switch apiData.output { @@ -48,7 +50,9 @@ extension AuthTestHarnessInput { fatalError("Missing input") } if let request = apiData.expectedInput { - XCTAssertEqual(input, request) + XCTAssertEqual(input.clientId, request.clientId) + XCTAssertEqual(input.authParameters, request.authParameters) + XCTAssertEqual(input.clientMetadata, request.clientMetadata) } switch apiData.output { @@ -63,7 +67,7 @@ extension AuthTestHarnessInput { fatalError("Missing input") } if let request = apiData.expectedInput { - XCTAssertEqual(input, request) + XCTAssertEqual(input.accessToken, request.accessToken) } switch apiData.output { @@ -78,7 +82,10 @@ extension AuthTestHarnessInput { fatalError("Missing input") } if let request = apiData.expectedInput { - XCTAssertEqual(request, input) + XCTAssertEqual(request.challengeResponses, input.challengeResponses) + XCTAssertEqual(request.clientId, input.clientId) + XCTAssertEqual(request.clientMetadata, input.clientMetadata) + XCTAssertEqual(request.session, input.session) } switch apiData.output { @@ -122,7 +129,10 @@ extension AuthTestHarnessInput { fatalError("Missing input") } if let request = apiData.expectedInput { - XCTAssertEqual(request, input) + XCTAssertEqual(request.accessToken, input.accessToken) + XCTAssertEqual(request.deviceKey, input.deviceKey) + XCTAssertEqual(request.deviceName, input.deviceName) + XCTAssertEqual(request.deviceSecretVerifierConfig?.passwordVerifier, input.deviceSecretVerifierConfig?.passwordVerifier) } switch apiData.output { diff --git a/AmplifyPlugins/Auth/Tests/AuthHostApp/AuthIntegrationTests/AppSyncSignerTests/AppSyncSignerTests.swift b/AmplifyPlugins/Auth/Tests/AuthHostApp/AuthIntegrationTests/AppSyncSignerTests/AppSyncSignerTests.swift index 02cedefdfb..c13675ea17 100644 --- a/AmplifyPlugins/Auth/Tests/AuthHostApp/AuthIntegrationTests/AppSyncSignerTests/AppSyncSignerTests.swift +++ b/AmplifyPlugins/Auth/Tests/AuthHostApp/AuthIntegrationTests/AppSyncSignerTests/AppSyncSignerTests.swift @@ -20,7 +20,7 @@ class AppSyncSignerTests: AWSAuthBaseTest { /// - I should get a signed request. /// func testSignAppSyncRequest() async throws { - let request = URLRequest(url: URL(string: "http://graphql.com")!) + let request = URLRequest(url: URL(string: "http://graphql.com?param=value")!) let signer = AWSCognitoAuthPlugin.createAppSyncSigner(region: "us-east-1") let signedRequest = try await signer(request) guard let headers = signedRequest.allHTTPHeaderFields else { diff --git a/AmplifyPlugins/Auth/Tests/AuthHostApp/AuthIntegrationTests/SignOutTests/AuthSignOutTests.swift b/AmplifyPlugins/Auth/Tests/AuthHostApp/AuthIntegrationTests/SignOutTests/AuthSignOutTests.swift index 2c71d77056..6b69e9d322 100644 --- a/AmplifyPlugins/Auth/Tests/AuthHostApp/AuthIntegrationTests/SignOutTests/AuthSignOutTests.swift +++ b/AmplifyPlugins/Auth/Tests/AuthHostApp/AuthIntegrationTests/SignOutTests/AuthSignOutTests.swift @@ -18,7 +18,7 @@ class AuthSignOutTests: AWSAuthBaseTest { try await super.setUp() AuthSessionHelper.clearSession() if Self.setSDKLogLevelDebug { - await SDKLoggingSystem.initialize(logLevel: .debug) + await SDKLoggingSystem().initialize(logLevel: .debug) Self.setSDKLogLevelDebug = false } } diff --git a/AmplifyPlugins/Core/AWSPluginsCoreTests/WebSocket/WebSocketClientTests.swift b/AmplifyPlugins/Core/AWSPluginsCoreTests/WebSocket/WebSocketClientTests.swift index f3e53669c1..052f79d716 100644 --- a/AmplifyPlugins/Core/AWSPluginsCoreTests/WebSocket/WebSocketClientTests.swift +++ b/AmplifyPlugins/Core/AWSPluginsCoreTests/WebSocket/WebSocketClientTests.swift @@ -211,3 +211,23 @@ fileprivate class MockNetworkMonitor: WebSocketNetworkMonitorProtocol { } + +private extension String { + var hexaData: Data { + .init(hexa) + } + + private var hexa: UnfoldSequence { + sequence(state: startIndex) { startIndex in + // bail if we've reached the end of the string + guard startIndex < self.endIndex else { return nil } + + // get the next two characters + let endIndex = self.index(startIndex, offsetBy: 2, limitedBy: self.endIndex) ?? self.endIndex + defer { startIndex = endIndex } + + // convert the characters to a UInt8 + return UInt8(self[startIndex.. any SmithyIdentity.AWSCredentialIdentityResolver { + interactions.append(#function) + let cognitoCredentialsProvider = MyCustomCredentialsProvider() + return cognitoCredentialsProvider + } + public func getIdentityID() async throws -> String { interactions.append(#function) if let error = getIdentityIdError { @@ -61,11 +68,12 @@ public class MockAWSAuthService: AWSAuthCredentialsProviderBehavior { } } -struct MyCustomCredentialsProvider: CredentialsProviding { - func getCredentials() async throws -> AWSClientRuntime.AWSCredentials { - AWSCredentials( +struct MyCustomCredentialsProvider: CredentialsProviding, AWSCredentialIdentityResolver { + func getCredentials() async throws -> AwsCommonRuntimeKit.Credentials { + try AwsCommonRuntimeKit.Credentials( accessKey: "AKIDEXAMPLE", secret: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", - expirationTimeout: Date().addingTimeInterval(30)) + expiration: Date().addingTimeInterval(30) + ) } } diff --git a/AmplifyPlugins/Core/AWSPluginsTestCommon/MockAWSSignatureV4Signer.swift b/AmplifyPlugins/Core/AWSPluginsTestCommon/MockAWSSignatureV4Signer.swift index abeb670efb..0daae45de4 100644 --- a/AmplifyPlugins/Core/AWSPluginsTestCommon/MockAWSSignatureV4Signer.swift +++ b/AmplifyPlugins/Core/AWSPluginsTestCommon/MockAWSSignatureV4Signer.swift @@ -6,17 +6,18 @@ // import AWSPluginsCore -import ClientRuntime -import AWSClientRuntime +import AwsCommonRuntimeKit import InternalAmplifyCredentials import Foundation +import SmithyHTTPAPI +import SmithyIdentity class MockAWSSignatureV4Signer: AWSSignatureV4Signer { - func sigV4SignedRequest(requestBuilder: SdkHttpRequestBuilder, - credentialsProvider: CredentialsProviding, + func sigV4SignedRequest(requestBuilder: SmithyHTTPAPI.HTTPRequestBuilder, + credentialIdentityResolver: some AWSCredentialIdentityResolver, signingName: String, signingRegion: String, - date: Date) throws -> SdkHttpRequest? { + date: Date) throws -> SmithyHTTPAPI.HTTPRequest? { let originalRequest = requestBuilder.build() return originalRequest } diff --git a/AmplifyPlugins/Core/AWSPluginsTestCommon/MockHttpResponse.swift b/AmplifyPlugins/Core/AWSPluginsTestCommon/MockHttpResponse.swift index 684704a03b..3210b5f59b 100644 --- a/AmplifyPlugins/Core/AWSPluginsTestCommon/MockHttpResponse.swift +++ b/AmplifyPlugins/Core/AWSPluginsTestCommon/MockHttpResponse.swift @@ -5,10 +5,10 @@ // SPDX-License-Identifier: Apache-2.0 // -import ClientRuntime +import SmithyHTTPAPI class MockHttpResponse { - class var ok: HttpResponse { - HttpResponse(body: .empty, statusCode: .ok) + class var ok: SmithyHTTPAPI.HTTPResponse { + SmithyHTTPAPI.HTTPResponse(body: .empty, statusCode: .ok) } } diff --git a/AmplifyPlugins/Core/AmplifyCredentials/AWSAuthCredentialsProviderBehavior.swift b/AmplifyPlugins/Core/AmplifyCredentials/AWSAuthCredentialsProviderBehavior.swift index 6d6cfe9277..04339f6bf0 100644 --- a/AmplifyPlugins/Core/AmplifyCredentials/AWSAuthCredentialsProviderBehavior.swift +++ b/AmplifyPlugins/Core/AmplifyCredentials/AWSAuthCredentialsProviderBehavior.swift @@ -7,11 +7,13 @@ import Foundation import Amplify -import AWSClientRuntime +import AwsCommonRuntimeKit import AWSPluginsCore +import SmithyIdentity public protocol AWSAuthCredentialsProviderBehavior: AWSAuthServiceBehavior { func getCredentialsProvider() -> CredentialsProviding -} + func getCredentialIdentityResolver() -> any AWSCredentialIdentityResolver +} diff --git a/AmplifyPlugins/Core/AmplifyCredentials/AWSAuthService+CredentialsProvider.swift b/AmplifyPlugins/Core/AmplifyCredentials/AWSAuthService+CredentialsProvider.swift index ec8babe3d5..a2a7e58206 100644 --- a/AmplifyPlugins/Core/AmplifyCredentials/AWSAuthService+CredentialsProvider.swift +++ b/AmplifyPlugins/Core/AmplifyCredentials/AWSAuthService+CredentialsProvider.swift @@ -7,11 +7,16 @@ import Foundation import Amplify -import AWSClientRuntime +import AwsCommonRuntimeKit import AWSPluginsCore +import SmithyIdentity extension AWSAuthService: AWSAuthCredentialsProviderBehavior { - public func getCredentialsProvider() -> AWSClientRuntime.CredentialsProviding { + public func getCredentialsProvider() -> AwsCommonRuntimeKit.CredentialsProviding { + return AmplifyAWSCredentialsProvider() + } + + public func getCredentialIdentityResolver() -> any AWSCredentialIdentityResolver { return AmplifyAWSCredentialsProvider() } } diff --git a/AmplifyPlugins/Core/AmplifyCredentials/AmplifyAWSCredentialsProvider.swift b/AmplifyPlugins/Core/AmplifyCredentials/AmplifyAWSCredentialsProvider.swift index 8a45c1d64a..a0d6cc29c6 100644 --- a/AmplifyPlugins/Core/AmplifyCredentials/AmplifyAWSCredentialsProvider.swift +++ b/AmplifyPlugins/Core/AmplifyCredentials/AmplifyAWSCredentialsProvider.swift @@ -6,18 +6,32 @@ // import Amplify -import AWSClientRuntime import AwsCommonRuntimeKit import AWSPluginsCore import Foundation +import Smithy +import SmithyIdentity -public class AmplifyAWSCredentialsProvider: AWSClientRuntime.CredentialsProviding { - - public func getCredentials() async throws -> AWSClientRuntime.AWSCredentials { +public class AmplifyAWSCredentialsProvider: AwsCommonRuntimeKit.CredentialsProviding { + + public func getCredentials() async throws -> AwsCommonRuntimeKit.Credentials { let authSession = try await Amplify.Auth.fetchAuthSession() if let awsCredentialsProvider = authSession as? AuthAWSCredentialsProvider { let credentials = try awsCredentialsProvider.getAWSCredentials().get() - return credentials.toAWSSDKCredentials() + return try credentials.toAWSSDKCredentials() + } else { + let error = AuthError.unknown("Auth session does not include AWS credentials information") + throw error + } + } +} + +extension AmplifyAWSCredentialsProvider: AWSCredentialIdentityResolver { + public func getIdentity(identityProperties: Smithy.Attributes? = nil) async throws -> AWSCredentialIdentity { + let authSession = try await Amplify.Auth.fetchAuthSession() + if let awsCredentialsProvider = authSession as? AuthAWSCredentialsProvider { + let credentials = try awsCredentialsProvider.getAWSCredentials().get() + return try credentials.toAWSCredentialIdentity() } else { let error = AuthError.unknown("Auth session does not include AWS credentials information") throw error @@ -27,19 +41,30 @@ public class AmplifyAWSCredentialsProvider: AWSClientRuntime.CredentialsProvidin extension AWSPluginsCore.AWSCredentials { - func toAWSSDKCredentials() -> AWSClientRuntime.AWSCredentials { + func toAWSSDKCredentials() throws -> AwsCommonRuntimeKit.Credentials { if let tempCredentials = self as? AWSTemporaryCredentials { - return AWSClientRuntime.AWSCredentials( + return try AwsCommonRuntimeKit.Credentials( accessKey: tempCredentials.accessKeyId, secret: tempCredentials.secretAccessKey, - expirationTimeout: tempCredentials.expiration, - sessionToken: tempCredentials.sessionToken) + sessionToken: tempCredentials.sessionToken, + expiration: tempCredentials.expiration + ) } else { - return AWSClientRuntime.AWSCredentials( + return try AwsCommonRuntimeKit.Credentials( accessKey: accessKeyId, secret: secretAccessKey, - expirationTimeout: Date()) + expiration: nil + ) } } + + func toAWSCredentialIdentity() throws -> SmithyIdentity.AWSCredentialIdentity { + return SmithyIdentity.AWSCredentialIdentity( + accessKey: accessKeyId, + secret: secretAccessKey, + expiration: (self as? AWSTemporaryCredentials)?.expiration, + sessionToken: (self as? AWSTemporaryCredentials)?.sessionToken + ) + } } diff --git a/AmplifyPlugins/Core/AmplifyCredentials/AmplifyAWSSignatureV4Signer.swift b/AmplifyPlugins/Core/AmplifyCredentials/AmplifyAWSSignatureV4Signer.swift index 015f2e8395..6182e50802 100644 --- a/AmplifyPlugins/Core/AmplifyCredentials/AmplifyAWSSignatureV4Signer.swift +++ b/AmplifyPlugins/Core/AmplifyCredentials/AmplifyAWSSignatureV4Signer.swift @@ -7,36 +7,41 @@ import Foundation import Amplify -import ClientRuntime -import AWSClientRuntime -import AwsCommonRuntimeKit +import AWSSDKHTTPAuth +import SmithyHTTPAPI +import SmithyHTTPAuthAPI +import SmithyHTTPAuth +import SmithyIdentity public protocol AWSSignatureV4Signer { - func sigV4SignedRequest(requestBuilder: SdkHttpRequestBuilder, - credentialsProvider: AWSClientRuntime.CredentialsProviding, + func sigV4SignedRequest(requestBuilder: SmithyHTTPAPI.HTTPRequestBuilder, + credentialIdentityResolver: some AWSCredentialIdentityResolver, signingName: Swift.String, signingRegion: Swift.String, - date: ClientRuntime.Date) async throws -> SdkHttpRequest? + date: Date) async throws -> SmithyHTTPAPI.HTTPRequest? } public class AmplifyAWSSignatureV4Signer: AWSSignatureV4Signer { - public init() { + private let signer: AWSSigV4Signer + + public init(signer: AWSSigV4Signer = .init()) { + self.signer = signer } - public func sigV4SignedRequest(requestBuilder: SdkHttpRequestBuilder, - credentialsProvider: AWSClientRuntime.CredentialsProviding, + public func sigV4SignedRequest(requestBuilder: SmithyHTTPAPI.HTTPRequestBuilder, + credentialIdentityResolver: some AWSCredentialIdentityResolver, signingName: Swift.String, signingRegion: Swift.String, - date: ClientRuntime.Date) async throws -> SdkHttpRequest? { + date: Date) async throws -> SmithyHTTPAPI.HTTPRequest? { do { - let credentials = try await credentialsProvider.getCredentials() + let credentialIdentity = try await credentialIdentityResolver.getIdentity() let flags = SigningFlags(useDoubleURIEncode: true, shouldNormalizeURIPath: true, omitSessionToken: false) let signedBodyHeader: AWSSignedBodyHeader = .none let signedBodyValue: AWSSignedBodyValue = .empty - let signingConfig = AWSSigningConfig(credentials: credentials, + let signingConfig = AWSSigningConfig(credentials: credentialIdentity, signedBodyHeader: signedBodyHeader, signedBodyValue: signedBodyValue, flags: flags, @@ -46,7 +51,7 @@ public class AmplifyAWSSignatureV4Signer: AWSSignatureV4Signer { signatureType: .requestHeaders, signingAlgorithm: .sigv4) - let httpRequest = await AWSSigV4Signer.sigV4SignedRequest( + let httpRequest = await signer.sigV4SignedRequest( requestBuilder: requestBuilder, signingConfig: signingConfig ) diff --git a/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/ClientRuntimeFoundationBridge.swift b/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/ClientRuntimeFoundationBridge.swift index 18fa1470b2..100fd85a1b 100644 --- a/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/ClientRuntimeFoundationBridge.swift +++ b/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/ClientRuntimeFoundationBridge.swift @@ -6,30 +6,31 @@ // import Foundation -import ClientRuntime +import Smithy +import SmithyHTTPAPI extension Foundation.URLRequest { - init(sdkRequest: ClientRuntime.SdkHttpRequest) async throws { - guard let url = sdkRequest.endpoint.url else { - throw FoundationClientEngineError.invalidRequestURL(sdkRequest: sdkRequest) + init(from smithyRequest: SmithyHTTPAPI.HTTPRequest) async throws { + guard let url = smithyRequest.endpoint.url else { + throw FoundationClientEngineError.invalidRequestURL(smithyRequest: smithyRequest) } self.init(url: url) - httpMethod = sdkRequest.method.rawValue + httpMethod = smithyRequest.method.rawValue - for header in sdkRequest.headers.headers { + for header in smithyRequest.headers.headers { for value in header.value { addValue(value, forHTTPHeaderField: header.name) } } - httpBody = try await sdkRequest.body.readData() + httpBody = try await smithyRequest.body.readData() } } -extension ClientRuntime.HttpResponse { +extension SmithyHTTPAPI.HTTPResponse { private static func headers( from allHeaderFields: [AnyHashable: Any] - ) -> ClientRuntime.Headers { + ) -> SmithyHTTPAPI.Headers { var headers = Headers() for header in allHeaderFields { switch (header.key, header.value) { @@ -47,7 +48,7 @@ extension ClientRuntime.HttpResponse { let headers = Self.headers(from: httpURLResponse.allHeaderFields) let body = ByteStream.data(data) - guard let statusCode = HttpStatusCode(rawValue: httpURLResponse.statusCode) else { + guard let statusCode = HTTPStatusCode(rawValue: httpURLResponse.statusCode) else { // This shouldn't happen, but `HttpStatusCode` only exposes a failable // `init`. The alternative here is force unwrapping, but we can't // make the decision to crash here on behalf on consuming applications. diff --git a/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/FoundationClientEngine.swift b/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/FoundationClientEngine.swift index d8f18fe889..6aa0bf7fee 100644 --- a/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/FoundationClientEngine.swift +++ b/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/FoundationClientEngine.swift @@ -6,13 +6,13 @@ // import Foundation -import ClientRuntime import Amplify +import SmithyHTTPAPI @_spi(FoundationClientEngine) public struct FoundationClientEngine: HTTPClient { - public func send(request: ClientRuntime.SdkHttpRequest) async throws -> ClientRuntime.HttpResponse { - let urlRequest = try await URLRequest(sdkRequest: request) + public func send(request: SmithyHTTPAPI.HTTPRequest) async throws -> SmithyHTTPAPI.HTTPResponse { + let urlRequest = try await URLRequest(from: request) let (data, response) = try await URLSession.shared.data(for: urlRequest) guard let httpURLResponse = response as? HTTPURLResponse else { @@ -22,7 +22,7 @@ public struct FoundationClientEngine: HTTPClient { throw FoundationClientEngineError.invalidURLResponse(urlRequest: response) } - let httpResponse = try HttpResponse( + let httpResponse = try HTTPResponse( httpURLResponse: httpURLResponse, data: data ) diff --git a/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/FoundationClientEngineError.swift b/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/FoundationClientEngineError.swift index 09e6df49ef..098a452431 100644 --- a/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/FoundationClientEngineError.swift +++ b/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/FoundationClientEngineError.swift @@ -7,7 +7,7 @@ import Foundation import Amplify -import ClientRuntime +import SmithyHTTPAPI struct FoundationClientEngineError: AmplifyError { let errorDescription: ErrorDescription @@ -37,11 +37,11 @@ extension FoundationClientEngineError { self.underlyingError = error } - static func invalidRequestURL(sdkRequest: ClientRuntime.SdkHttpRequest) -> Self { + static func invalidRequestURL(smithyRequest: SmithyHTTPAPI.HTTPRequest) -> Self { .init( errorDescription: """ - The SdkHttpRequest generated by ClientRuntime doesn't include a valid URL - - \(sdkRequest) + The HTTPRequest generated by SmithyHTTP doesn't include a valid URL + - \(smithyRequest) """, recoverySuggestion: """ Please open an issue at https://github.com/aws-amplify/amplify-swift diff --git a/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/PluginClientEngine.swift b/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/PluginClientEngine.swift index 6a2e8d7544..964adff859 100644 --- a/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/PluginClientEngine.swift +++ b/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/PluginClientEngine.swift @@ -7,11 +7,11 @@ import Foundation import ClientRuntime -import AWSClientRuntime +import SmithyHTTPAPI @_spi(PluginHTTPClientEngine) public func baseClientEngine( - for configuration: AWSClientConfiguration + for configuration: ClientRuntime.DefaultHttpClientConfiguration ) -> HTTPClient { return FoundationClientEngine() } diff --git a/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/SdkHttpRequest+updatingUserAgent.swift b/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/SdkHttpRequest+updatingUserAgent.swift index 690b8f932f..586a7a9127 100644 --- a/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/SdkHttpRequest+updatingUserAgent.swift +++ b/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/SdkHttpRequest+updatingUserAgent.swift @@ -6,27 +6,22 @@ // import Foundation -import ClientRuntime +import SmithyHTTPAPI @_spi(PluginHTTPClientEngine) -extension SdkHttpRequest { - public func updatingUserAgent(with value: String) -> SdkHttpRequest { +extension HTTPRequest { + public func updatingUserAgent(with value: String) -> HTTPRequest { let userAgentKey = "User-Agent" var headers = headers headers.remove(name: userAgentKey) headers.add(name: userAgentKey, value: value) - let endpoint = ClientRuntime.Endpoint( - host: endpoint.host, - path: endpoint.path, - port: endpoint.port, - queryItems: endpoint.queryItems, - protocolType: endpoint.protocolType, - headers: headers, - properties: endpoint.properties + let endpoint = SmithyHTTPAPI.Endpoint( + uri: endpoint.uri, + headers: headers ) - return SdkHttpRequest( + return HTTPRequest( method: method, endpoint: endpoint, body: body diff --git a/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/UserAgentSettingClientEngine.swift b/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/UserAgentSettingClientEngine.swift index 807403f21a..81eb7f6213 100644 --- a/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/UserAgentSettingClientEngine.swift +++ b/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/UserAgentSettingClientEngine.swift @@ -7,7 +7,7 @@ import Foundation import ClientRuntime -import AWSClientRuntime +import SmithyHTTPAPI @_spi(PluginHTTPClientEngine) public struct UserAgentSettingClientEngine: AWSPluginExtension { @@ -28,7 +28,7 @@ extension UserAgentSettingClientEngine: HTTPClient { // as it's no longer necessary there. var lib: String { AmplifyAWSServiceConfiguration.userAgentLib } - public func send(request: SdkHttpRequest) async throws -> HttpResponse { + public func send(request: HTTPRequest) async throws -> HTTPResponse { let existingUserAgent = request.headers.value(for: userAgentKey) ?? "" let userAgent = "\(existingUserAgent) \(lib)" let updatedRequest = request.updatingUserAgent(with: userAgent) @@ -40,7 +40,7 @@ extension UserAgentSettingClientEngine: HTTPClient { @_spi(PluginHTTPClientEngine) extension HTTPClient where Self == UserAgentSettingClientEngine { public static func userAgentEngine( - for configuration: AWSClientConfiguration + for configuration: ClientRuntime.DefaultHttpClientConfiguration ) -> Self { let baseClientEngine = baseClientEngine(for: configuration) return self.init(target: baseClientEngine) diff --git a/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/UserAgentSuffixAppender.swift b/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/UserAgentSuffixAppender.swift index bb82ae44f3..3e0b5139ff 100644 --- a/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/UserAgentSuffixAppender.swift +++ b/AmplifyPlugins/Core/AmplifyCredentials/CustomHttpClientEngine/UserAgentSuffixAppender.swift @@ -5,7 +5,8 @@ // SPDX-License-Identifier: Apache-2.0 // -import ClientRuntime +import SmithyHTTPAPI +import Smithy @_spi(InternalAmplifyPluginExtension) public class UserAgentSuffixAppender: AWSPluginExtension { @@ -21,9 +22,9 @@ public class UserAgentSuffixAppender: AWSPluginExtension { @_spi(InternalHttpEngineProxy) extension UserAgentSuffixAppender: HTTPClient { - public func send(request: SdkHttpRequest) async throws -> HttpResponse { + public func send(request: SmithyHTTPAPI.HTTPRequest) async throws -> SmithyHTTPAPI.HTTPResponse { guard let target = target else { - throw ClientError.unknownError("HttpClientEngine is not set") + throw Smithy.ClientError.unknownError("HttpClientEngine is not set") } let existingUserAgent = request.headers.value(for: userAgentKey) ?? "" diff --git a/AmplifyPlugins/Core/AmplifyCredentials/IAMCredentialProvider.swift b/AmplifyPlugins/Core/AmplifyCredentials/IAMCredentialProvider.swift index 1265a9130f..ce6617a7be 100644 --- a/AmplifyPlugins/Core/AmplifyCredentials/IAMCredentialProvider.swift +++ b/AmplifyPlugins/Core/AmplifyCredentials/IAMCredentialProvider.swift @@ -7,11 +7,14 @@ import Foundation import Amplify -import AWSClientRuntime +import AwsCommonRuntimeKit import AWSPluginsCore +import SmithyIdentity public protocol IAMCredentialsProvider { func getCredentialsProvider() -> CredentialsProviding + + func getCredentialIdentityResolver() -> any AWSCredentialIdentityResolver } public struct BasicIAMCredentialsProvider: IAMCredentialsProvider { @@ -24,4 +27,8 @@ public struct BasicIAMCredentialsProvider: IAMCredentialsProvider { public func getCredentialsProvider() -> CredentialsProviding { return authService.getCredentialsProvider() } + + public func getCredentialIdentityResolver() -> any AWSCredentialIdentityResolver { + authService.getCredentialIdentityResolver() + } } diff --git a/AmplifyPlugins/Core/AmplifyCredentialsTests/Auth/AWSAuthServiceTests.swift b/AmplifyPlugins/Core/AmplifyCredentialsTests/Auth/AWSAuthServiceTests.swift index abca5ad99c..85c209e12b 100644 --- a/AmplifyPlugins/Core/AmplifyCredentialsTests/Auth/AWSAuthServiceTests.swift +++ b/AmplifyPlugins/Core/AmplifyCredentialsTests/Auth/AWSAuthServiceTests.swift @@ -167,7 +167,7 @@ class AWSAuthServiceTests: XCTestCase { accessKeyId: "accessKeyId", secretAccessKey: "secretAccessKey", expiration: Date().addingTimeInterval(100)) - let sdkCredentials = credentials.toAWSSDKCredentials() + let sdkCredentials = try credentials.toAWSSDKCredentials() XCTAssertNotNil(sdkCredentials) } @@ -181,7 +181,7 @@ class AWSAuthServiceTests: XCTestCase { accessKeyId: "accessKeyId", secretAccessKey: "secretAccessKey", expiration: Date().addingTimeInterval(-100)) - let sdkCredentials = credentials.toAWSSDKCredentials() + let sdkCredentials = try credentials.toAWSSDKCredentials() XCTAssertNotNil(sdkCredentials) } } diff --git a/AmplifyPlugins/Core/AmplifyCredentialsTests/Utils/UserAgentSettingClientEngineTests.swift b/AmplifyPlugins/Core/AmplifyCredentialsTests/Utils/UserAgentSettingClientEngineTests.swift index a6b2d3a800..b5ac23f362 100644 --- a/AmplifyPlugins/Core/AmplifyCredentialsTests/Utils/UserAgentSettingClientEngineTests.swift +++ b/AmplifyPlugins/Core/AmplifyCredentialsTests/Utils/UserAgentSettingClientEngineTests.swift @@ -9,7 +9,7 @@ @_spi(PluginHTTPClientEngine) @_spi(InternalHttpEngineProxy) import InternalAmplifyCredentials -import ClientRuntime +import SmithyHTTPAPI import XCTest class UserAgentSettingClientEngineTestCase: XCTestCase { @@ -19,7 +19,7 @@ class UserAgentSettingClientEngineTestCase: XCTestCase { /// When: A request is invoked **with** an existing User-Agent. /// Then: The `lib` component of the user-agent is added. func test_existingUserAgent_addsLibComponent() async throws { - let request: SdkHttpRequest = .mock + let request: SmithyHTTPAPI.HTTPRequest = .mock let existingUserAgent = "foo/bar/baz" request.withHeader(name: userAgentKey, value: existingUserAgent) @@ -38,7 +38,7 @@ class UserAgentSettingClientEngineTestCase: XCTestCase { /// When: A request is invoked **without** existing User-Agent. /// Then: The `lib` component of the user-agent is added. func test_nonExistingUserAgent_addsLibComponent() async throws { - let request: SdkHttpRequest = .mock + let request: SmithyHTTPAPI.HTTPRequest = .mock let target = MockTargetEngine() let engine = UserAgentSettingClientEngine(target: target) _ = try await engine.send(request: request) @@ -51,7 +51,7 @@ class UserAgentSettingClientEngineTestCase: XCTestCase { /// When: A request is invoked **with** existing User-Agent. /// Then: The `lib` component of the user-agent and the suffix are added. func test_existingUserAgentCombinedWithSuffixAppender_addLibAndSuffix() async throws { - let request: SdkHttpRequest = .mock + let request: SmithyHTTPAPI.HTTPRequest = .mock let existingUserAgent = "foo/bar/baz" request.withHeader(name: userAgentKey, value: existingUserAgent) @@ -73,7 +73,7 @@ class UserAgentSettingClientEngineTestCase: XCTestCase { /// When: A request is invoked **without** existing User-Agent. /// Then: The `lib` component of the user-agent and the suffix are added. func test_nonExistingUserAgentCombinedWithSuffixAppender_addLibAndSuffix() async throws { - let request: SdkHttpRequest = .mock + let request: SmithyHTTPAPI.HTTPRequest = .mock let target = MockTargetEngine() let suffix = "a/b/c" @@ -91,18 +91,18 @@ class UserAgentSettingClientEngineTestCase: XCTestCase { } class MockTargetEngine: HTTPClient { - var request: SdkHttpRequest? + var request: HTTPRequest? func send( - request: SdkHttpRequest - ) async throws -> HttpResponse { + request: HTTPRequest + ) async throws -> HTTPResponse { self.request = request return .init(body: .empty, statusCode: .accepted) } } -extension SdkHttpRequest { - static var mock: SdkHttpRequest { +extension HTTPRequest { + static var mock: HTTPRequest { .init( method: .get, endpoint: .init(host: "amplify") diff --git a/AmplifyPlugins/Core/AmplifyCredentialsTests/Utils/UserAgentSuffixAppenderTests.swift b/AmplifyPlugins/Core/AmplifyCredentialsTests/Utils/UserAgentSuffixAppenderTests.swift index dece4394d4..0d26bb0ddd 100644 --- a/AmplifyPlugins/Core/AmplifyCredentialsTests/Utils/UserAgentSuffixAppenderTests.swift +++ b/AmplifyPlugins/Core/AmplifyCredentialsTests/Utils/UserAgentSuffixAppenderTests.swift @@ -6,7 +6,8 @@ // @_spi(InternalAmplifyPluginExtension) @_spi(InternalHttpEngineProxy) import InternalAmplifyCredentials -import ClientRuntime +import Smithy +import SmithyHTTPAPI import XCTest class UserAgentSuffixAppenderTests: XCTestCase { @@ -73,8 +74,8 @@ class UserAgentSuffixAppenderTests: XCTestCase { } } - private func createRequest() -> SdkHttpRequest { - return SdkHttpRequest( + private func createRequest() -> HTTPRequest { + return HTTPRequest( method: .get, endpoint: .init(host: "customHost") ) @@ -83,8 +84,8 @@ class UserAgentSuffixAppenderTests: XCTestCase { private class MockHttpClientEngine: HTTPClient { var executeCount = 0 - var executeRequest: SdkHttpRequest? - func send(request: SdkHttpRequest) async throws -> HttpResponse { + var executeRequest: HTTPRequest? + func send(request: HTTPRequest) async throws -> HTTPResponse { executeCount += 1 executeRequest = request return .init(body: .empty, statusCode: .accepted) diff --git a/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/AWSLocationGeoPlugin+Configure.swift b/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/AWSLocationGeoPlugin+Configure.swift index 6b194b48af..221d9d9551 100644 --- a/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/AWSLocationGeoPlugin+Configure.swift +++ b/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/AWSLocationGeoPlugin+Configure.swift @@ -36,12 +36,13 @@ extension AWSLocationGeoPlugin { /// Configure AWSLocationPlugin programatically using AWSLocationPluginConfiguration public func configure(using configuration: AWSLocationGeoPluginConfiguration) throws { let authService = AWSAuthService() - let credentialsProvider = authService.getCredentialsProvider() + let credentialsProvider = authService.getCredentialIdentityResolver() let region = configuration.regionName // TODO: FrameworkMetadata Replacement let serviceConfiguration = try LocationClient.LocationClientConfiguration( + awsCredentialIdentityResolver: credentialsProvider, region: region, - credentialsProvider: credentialsProvider + signingRegion: region ) serviceConfiguration.httpClientEngine = .userAgentEngine(for: serviceConfiguration) diff --git a/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/Support/Utils/GeoErrorConvertible.swift b/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/Support/Utils/GeoErrorConvertible.swift index ad35aea33a..f1419059c8 100644 --- a/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/Support/Utils/GeoErrorConvertible.swift +++ b/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/Support/Utils/GeoErrorConvertible.swift @@ -8,7 +8,7 @@ import Amplify import Foundation import AWSLocation -import AWSClientRuntime +@_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime protocol GeoErrorConvertible { var geoError: Geo.Error { get } diff --git a/AmplifyPlugins/Geo/Tests/AWSLocationGeoPluginTests/Mocks/MockAWSClientConfiguration.swift b/AmplifyPlugins/Geo/Tests/AWSLocationGeoPluginTests/Mocks/MockAWSClientConfiguration.swift index ec24a7486d..90031b94ae 100644 --- a/AmplifyPlugins/Geo/Tests/AWSLocationGeoPluginTests/Mocks/MockAWSClientConfiguration.swift +++ b/AmplifyPlugins/Geo/Tests/AWSLocationGeoPluginTests/Mocks/MockAWSClientConfiguration.swift @@ -10,6 +10,8 @@ import ClientRuntime import AWSLocation import Foundation import XCTest +import SmithyHTTPAPI +import Smithy @testable import AWSLocationGeoPlugin @testable import AWSPluginsTestCommon @@ -17,19 +19,17 @@ import XCTest extension LocationClient.LocationClientConfiguration { static func mock(region: String) throws -> LocationClient.LocationClientConfiguration { try .init( + awsCredentialIdentityResolver: MockAWSAuthService().getCredentialIdentityResolver(), + awsRetryMode: .standard, region: region, - credentialsProvider: MockAWSAuthService().getCredentialsProvider(), - serviceSpecific: .init( - endpointResolver: MockEndPointResolver() - ), - signingRegion: "", - retryMode: .standard + signingRegion: "", + endpointResolver: MockEndPointResolver() ) } } class MockEndPointResolver: EndpointResolver { - func resolve(params: AWSLocation.EndpointParams) throws -> ClientRuntime.Endpoint { + func resolve(params: AWSLocation.EndpointParams) throws -> SmithyHTTPAPI.Endpoint { return Endpoint(host: "MockHost") } } diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/ClientError+IsRetryable.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/ClientError+IsRetryable.swift index 77f1cb2c5e..9636e18627 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/ClientError+IsRetryable.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/ClientError+IsRetryable.swift @@ -5,20 +5,24 @@ // SPDX-License-Identifier: Apache-2.0 // -import ClientRuntime import Foundation +import Smithy +import SmithyHTTPAPI -extension ClientError { - // TODO: Should some of these really be retried? +// From an Analytics perspective, a non-retryable error thrown by a PutEvents request +// means that all those events should be immediately pruned from the local database. +// +// Any "transient" error should be retried on the next event submission, +// so only `ClientError.serializationFailed` is considered to be non-retryable. + +extension Smithy.ClientError { var isRetryable: Bool { switch self { case .authError: return true case .dataNotFound: return true - case .pathCreationFailed: - return true - case .queryItemCreationFailed: + case .invalidValue: return true case .serializationFailed: return false @@ -27,3 +31,14 @@ extension ClientError { } } } + +extension SmithyHTTPAPI.HTTPClientError { + var isRetryable: Bool { + switch self { + case .pathCreationFailed: + return true + case .queryItemCreationFailed: + return true + } + } +} diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/EventRecorder.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/EventRecorder.swift index 0291d2f412..7782ddb733 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/EventRecorder.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/EventRecorder.swift @@ -11,6 +11,7 @@ import AWSPinpoint import ClientRuntime import enum AwsCommonRuntimeKit.CommonRunTimeError import Foundation +import SmithyHTTPAPI /// AnalyticsEventRecording saves and submits pinpoint events protocol AnalyticsEventRecording: Actor { @@ -157,7 +158,7 @@ actor EventRecorder: AnalyticsEventRecording { let endpointResponseMap = results.compactMap { $0.value.endpointItemResponse } for endpointResponse in endpointResponseMap { - if HttpStatusCode.accepted.rawValue == endpointResponse.statusCode { + if HTTPStatusCode.accepted.rawValue == endpointResponse.statusCode { log.verbose("EndpointProfile updated successfully.") } else { log.error("Unable to update EndpointProfile. Error: \(endpointResponse.message ?? "Unknown")") @@ -168,13 +169,13 @@ actor EventRecorder: AnalyticsEventRecording { for (eventId, eventResponse) in eventsResponseMap.flatMap({ $0 }) { guard let event = pinpointEventsById[eventId] else { continue } let responseMessage = eventResponse.message ?? "Unknown" - if HttpStatusCode.accepted.rawValue == eventResponse.statusCode, + if HTTPStatusCode.accepted.rawValue == eventResponse.statusCode, Constants.acceptedResponseMessage == responseMessage { // On successful submission, add the event to the list of submitted events and delete it from the local storage log.verbose("Successful submit for event with id \(eventId)") submittedEvents.append(event) deleteEvent(eventId: eventId) - } else if HttpStatusCode.badRequest.rawValue == eventResponse.statusCode { + } else if HTTPStatusCode.badRequest.rawValue == eventResponse.statusCode { // On bad request responses, mark the event as dirty log.error("Server rejected submission of event. Event with id \(eventId) will be discarded. Error: \(responseMessage)") setDirtyEvent(eventId: eventId) diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/AWSPinpointFactory.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/AWSPinpointFactory.swift index 05f64ea9e1..d0b93f647d 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/AWSPinpointFactory.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/AWSPinpointFactory.swift @@ -20,7 +20,7 @@ public class AWSPinpointFactory { private init() {} - static var credentialsProvider = AWSAuthService().getCredentialsProvider() + static var credentialIdentityResolver = AWSAuthService().getCredentialIdentityResolver() static var provisioningProfileReader: ProvisioningProfileReader = .default @@ -46,7 +46,7 @@ public class AWSPinpointFactory { let configuration = PinpointContextConfiguration( appId: appId, region: region, - credentialsProvider: credentialsProvider, + credentialIdentityResolver: credentialIdentityResolver, isDebug: isDebug ) diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/PinpointContext.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/PinpointContext.swift index 4267e99084..dc5a653a7d 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/PinpointContext.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/PinpointContext.swift @@ -10,6 +10,7 @@ import AWSClientRuntime import AWSPinpoint import Foundation @_spi(KeychainStore) import AWSPluginsCore +import SmithyIdentity // MARK: - UserDefaultsBehaviour protocol UserDefaultsBehaviour { @@ -76,18 +77,18 @@ struct PinpointContextConfiguration { /// The Pinpoint region let region: String /// Used to retrieve the proper AWSCredentials when creating the PinpointCLient - let credentialsProvider: CredentialsProviding + let credentialIdentityResolver: any AWSCredentialIdentityResolver /// Indicates if the App is in Debug or Release build. Defaults to `false` /// Setting this flag to true will set the Endpoint Profile to have a channel type of "APNS_SANDBOX". let isDebug: Bool init(appId: String, region: String, - credentialsProvider: CredentialsProviding, + credentialIdentityResolver: some AWSCredentialIdentityResolver, isDebug: Bool = false) { self.appId = appId self.region = region - self.credentialsProvider = credentialsProvider + self.credentialIdentityResolver = credentialIdentityResolver self.isDebug = isDebug } } @@ -124,7 +125,7 @@ class PinpointContext { uniqueId = Self.retrieveUniqueId(applicationId: configuration.appId, storage: storage) let pinpointClient = try PinpointClient(region: configuration.region, - credentialsProvider: configuration.credentialsProvider) + credentialIdentityResolver: configuration.credentialIdentityResolver) endpointClient = EndpointClient(configuration: .init(appId: configuration.appId, uniqueDeviceId: uniqueId, diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/PinpointClientTypes+Codable.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/PinpointClientTypes+Codable.swift new file mode 100644 index 0000000000..c1964cb00b --- /dev/null +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/PinpointClientTypes+Codable.swift @@ -0,0 +1,136 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import AWSPinpoint +import Foundation + +extension PinpointClientTypes.EndpointLocation: Codable, Equatable { + private enum CodingKeys: CodingKey { + case city + case country + case latitude + case longitude + case postalCode + case region + } + + public static func == ( + lhs: PinpointClientTypes.EndpointLocation, + rhs: PinpointClientTypes.EndpointLocation + ) -> Bool { + return lhs.city == rhs.city + && lhs.country == rhs.country + && lhs.latitude == rhs.latitude + && lhs.longitude == rhs.longitude + && lhs.postalCode == rhs.postalCode + && lhs.region == rhs.region + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + try self.init( + city: container.decodeIfPresent(String.self, forKey: .city), + country: container.decodeIfPresent(String.self, forKey: .country), + latitude: container.decodeIfPresent(Double.self, forKey: .latitude), + longitude: container.decodeIfPresent(Double.self, forKey: .longitude), + postalCode: container.decodeIfPresent(String.self, forKey: .postalCode), + region: container.decodeIfPresent(String.self, forKey: .region) + ) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(city, forKey: .city) + try container.encodeIfPresent(country, forKey: .country) + try container.encodeIfPresent(latitude, forKey: .latitude) + try container.encodeIfPresent(longitude, forKey: .longitude) + try container.encodeIfPresent(postalCode, forKey: .postalCode) + try container.encodeIfPresent(region, forKey: .region) + } +} + +extension PinpointClientTypes.EndpointDemographic: Codable, Equatable { + private enum CodingKeys: CodingKey { + case appVersion + case locale + case make + case model + case modelVersion + case platform + case platformVersion + case timezone + } + + public static func == ( + lhs: PinpointClientTypes.EndpointDemographic, + rhs: PinpointClientTypes.EndpointDemographic + ) -> Bool { + return lhs.appVersion == rhs.appVersion + && lhs.locale == rhs.locale + && lhs.make == rhs.make + && lhs.model == rhs.model + && lhs.modelVersion == rhs.modelVersion + && lhs.platform == rhs.platform + && lhs.platformVersion == rhs.platformVersion + && lhs.timezone == rhs.timezone + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + try self.init( + appVersion: container.decodeIfPresent(String.self, forKey: .appVersion), + locale: container.decodeIfPresent(String.self, forKey: .locale), + make: container.decodeIfPresent(String.self, forKey: .make), + model: container.decodeIfPresent(String.self, forKey: .model), + modelVersion: container.decodeIfPresent(String.self, forKey: .modelVersion), + platform: container.decodeIfPresent(String.self, forKey: .platform), + platformVersion: container.decodeIfPresent(String.self, forKey: .platformVersion), + timezone: container.decodeIfPresent(String.self, forKey: .timezone) + ) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(appVersion, forKey: .appVersion) + try container.encodeIfPresent(locale, forKey: .locale) + try container.encodeIfPresent(make, forKey: .make) + try container.encodeIfPresent(model, forKey: .model) + try container.encodeIfPresent(modelVersion, forKey: .modelVersion) + try container.encodeIfPresent(platform, forKey: .platform) + try container.encodeIfPresent(platformVersion, forKey: .platformVersion) + try container.encodeIfPresent(timezone, forKey: .timezone) + } +} + +extension PinpointClientTypes.EndpointUser: Codable, Equatable { + private enum CodingKeys: CodingKey { + case userAttributes + case userId + } + + public static func == ( + lhs: PinpointClientTypes.EndpointUser, + rhs: PinpointClientTypes.EndpointUser + ) -> Bool { + return lhs.userAttributes == rhs.userAttributes + && lhs.userId == rhs.userId + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + try self.init( + userAttributes: container.decodeIfPresent([String: [String]].self, forKey: .userAttributes), + userId: container.decodeIfPresent(String.self, forKey: .userId) + ) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(userAttributes, forKey: .userAttributes) + try container.encodeIfPresent(userId, forKey: .userId) + } +} diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/PinpointClient+CredentialsProvider.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/PinpointClient+CredentialsProvider.swift index 1d7a9d7cd9..15c437b3ea 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/PinpointClient+CredentialsProvider.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/PinpointClient+CredentialsProvider.swift @@ -9,13 +9,15 @@ import AWSClientRuntime import AWSPluginsCore import AWSPinpoint @_spi(PluginHTTPClientEngine) import InternalAmplifyCredentials +import SmithyIdentity extension PinpointClient { - convenience init(region: String, credentialsProvider: CredentialsProviding) throws { + convenience init(region: String, credentialIdentityResolver: some AWSCredentialIdentityResolver) throws { // TODO: FrameworkMetadata Replacement let configuration = try PinpointClientConfiguration( + awsCredentialIdentityResolver: credentialIdentityResolver, region: region, - credentialsProvider: credentialsProvider + signingRegion: region ) configuration.httpClientEngine = .userAgentEngine(for: configuration) diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/SDKModels+AmplifyStringConvertible.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/SDKModels+AmplifyStringConvertible.swift index 3421574914..7ac9d99bfd 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/SDKModels+AmplifyStringConvertible.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/SDKModels+AmplifyStringConvertible.swift @@ -10,30 +10,8 @@ import Foundation extension PutEventsInput: AmplifyStringConvertible {} -extension PutEventsOutput: AmplifyStringConvertible { - enum CodingKeys: Swift.String, Swift.CodingKey { - case eventsResponse = "EventsResponse" - } - - public func encode(to encoder: Encoder) throws { - var encodeContainer = encoder.container(keyedBy: CodingKeys.self) - if let eventsResponse = self.eventsResponse { - try encodeContainer.encode(eventsResponse, forKey: .eventsResponse) - } - } -} +extension PutEventsOutput: AmplifyStringConvertible {} extension UpdateEndpointInput: AmplifyStringConvertible {} -extension UpdateEndpointOutput: AmplifyStringConvertible { - enum CodingKeys: Swift.String, Swift.CodingKey { - case messageBody = "MessageBody" - } - - public func encode(to encoder: Encoder) throws { - var encodeContainer = encoder.container(keyedBy: CodingKeys.self) - if let messageBody = self.messageBody { - try encodeContainer.encode(messageBody, forKey: .messageBody) - } - } -} +extension UpdateEndpointOutput: AmplifyStringConvertible {} diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Support/Utils/AmplifyStringConvertible.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Support/Utils/AmplifyStringConvertible.swift index 6f12af8567..97632cbb29 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Support/Utils/AmplifyStringConvertible.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Support/Utils/AmplifyStringConvertible.swift @@ -7,22 +7,146 @@ import Foundation -protocol AmplifyStringConvertible: CustomStringConvertible, Encodable {} +/// Conforming to this protocol automatically adds support to "prettify" the type when printing its value. +protocol AmplifyStringConvertible: CustomStringConvertible {} extension AmplifyStringConvertible { - private static var jsonEncoder: JSONEncoder { - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .iso8601 - return encoder + public var description: String { + return prettyDescription(for: self) } - public var description: String { - if let data = try? Self.jsonEncoder.encode(self), - let result = String(data: data, encoding: .utf8) { - return result + private func prettyDescription( + for object: Any, + level: UInt = 1 + ) -> String { + return prettyDescription(for: object, level: level) { result, indentation in + switch object { + case let dictionary as Dictionary: + // Dictionaries follow the format: "": + for (key, value) in dictionary { + result.append( + contentsOf: "\n\(indentation)\"\(key)\": \(description(for: value, withLevel: level))," + ) + } + case let collection as any Collection: + // Other collections follow the format: , , ..., + for value in collection { + result.append(contentsOf: "\n\(indentation)\(description(for: value, withLevel: level)),") + } + default: + // Other objects follow the format: : + for child in Mirror(reflecting: object).children { + guard let label = child.label else { continue } + result.append( + contentsOf: "\n\(indentation)\(label): \(description(for: child.value, withLevel: level))," + ) + } + } + } + } + + private func prettyDescription( + for object: Any, + level: UInt = 1, + contentsBuilder: (_ result: inout String, _ indentation: String) -> Void + ) -> String { + var contents = "" + contentsBuilder(&contents, indentation(forLevel: level)) + if contents.isEmpty { + return emptyDescription(for: object) + } + + let tags = tags(for: object) + return appendClosingTag( + tags.closing, + to: tags.opening.appending(contents), + currentLevel: level + ) + } + + private func description( + for value: Any, + withLevel level: UInt + ) -> String { + let unwrappedValue = unwrappedValue(from: value) + switch unwrappedValue { + case let stringValue as String: + return stringValue.quoted + case is Int, is Bool, is Double, is Date, is Float: + return "\(unwrappedValue)" + case is any CaseIterable, is any RawRepresentable: + return ".\(unwrappedValue)" + default: + // When the value is another object, add one level of identation + return prettyDescription(for: unwrappedValue, level: level + 1) + } + } + + private func unwrappedValue(from value: Any) -> Any { + // This is to avoid printing optionals with the "Optional(x)" format, + // instead we just print "nil" or their actual values. + if let optional = value as? _AmplifyOptional { + return optional._amplifyUnwrap() ?? "nil" + } + return value + } + + private func indentation(forLevel level: UInt) -> String { + return String(repeating: " ", count: 4 * Int(level)) + } + + private func tags(for object: Any) -> (opening: String, closing: String) { + switch object { + case is any Collection: + return (opening: "[", closing: "]") + default: + return (opening: "{", closing: "}") + } + } + + private func emptyDescription(for object: Any) -> String { + switch object { + case is Dictionary: + return "[:]" + case is any Collection: + return "[]" + default: + return "{}" } + } + + private func appendClosingTag( + _ tag: String, + to value: String, + currentLevel level: UInt + ) -> String { + // Remove the last comma + let result = value.hasSuffix(",") ? String(value.dropLast()) : value + // As we're adding a closing tag, reduce one indentation level + return result.appending("\n\(indentation(forLevel: level - 1))\(tag)") + } +} + +// swiftlint:disable identifier_name +private protocol _AmplifyOptional { + func _amplifyUnwrap() -> Any? +} + +extension Optional: _AmplifyOptional { + func _amplifyUnwrap() -> Any? { + switch self { + case .none: + return nil + case .some(let wrapped): + return wrapped + } + } +} - return String(describing: self) +private extension String { + var quoted: String { + // Don't quote the String representing nil + if self == "nil" { return self } + return "\"\(self)\"" } } diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Support/Utils/PinpointRequestsRegistry.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Support/Utils/PinpointRequestsRegistry.swift index 9a2b02fa87..8c8f6f6f22 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Support/Utils/PinpointRequestsRegistry.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Support/Utils/PinpointRequestsRegistry.swift @@ -7,8 +7,8 @@ import Foundation import AWSPinpoint -import ClientRuntime @_spi(PluginHTTPClientEngine) import InternalAmplifyCredentials +import SmithyHTTPAPI @globalActor actor PinpointRequestsRegistry { static let shared = PinpointRequestsRegistry() @@ -60,7 +60,7 @@ private struct CustomPinpointHttpClientEngine: HTTPClient { self.httpClientEngine = httpClientEngine } - func send(request: ClientRuntime.SdkHttpRequest) async throws -> ClientRuntime.HttpResponse { + func send(request: HTTPRequest) async throws -> HTTPResponse { guard let url = request.endpoint.url, let pinpointApi = PinpointRequestsRegistry.API(from: url), let userAgentSuffix = await userAgent(for: pinpointApi) else { diff --git a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/AWSPinpointFactoryTests.swift b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/AWSPinpointFactoryTests.swift index e56ffc2670..bdef7cd7c5 100644 --- a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/AWSPinpointFactoryTests.swift +++ b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/AWSPinpointFactoryTests.swift @@ -19,7 +19,7 @@ final class AWSPinpointFactoryTests: XCTestCase { override func setUp() { mockedProfileReader = MockProvisioningProfileReader() AWSPinpointFactory.provisioningProfileReader = mockedProfileReader - AWSPinpointFactory.credentialsProvider = MockCredentialsProvider() + AWSPinpointFactory.credentialIdentityResolver = MockCredentialsProvider() } /// - Given: There is a provisioning profile that set the APS entitlement to production diff --git a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/Mocks/MockEndpointClient.swift b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/Mocks/MockEndpointClient.swift index 4af9110ff9..9955156cdb 100644 --- a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/Mocks/MockEndpointClient.swift +++ b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/Mocks/MockEndpointClient.swift @@ -13,12 +13,6 @@ import Foundation actor MockEndpointClient: EndpointClientBehaviour { let pinpointClient: PinpointClientProtocol = MockPinpointClient() - class MockCredentialsProvider: CredentialsProviding { - func getCredentials() async throws -> AWSCredentials { - return AWSCredentials(accessKey: "", secret: "", expirationTimeout: Date().addingTimeInterval(1000)) - } - } - var updateEndpointProfileCount = 0 func updateEndpointProfile() async throws { updateEndpointProfileCount += 1 diff --git a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/PinpointClientTypesCodableTests.swift b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/PinpointClientTypesCodableTests.swift new file mode 100644 index 0000000000..e46cab176f --- /dev/null +++ b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/PinpointClientTypesCodableTests.swift @@ -0,0 +1,70 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import AWSPinpoint +@testable import InternalAWSPinpoint +import XCTest + +class PinpointClientTypesCodableTests: XCTestCase { + /// Given: Instances of PinpointClient types that conform to Codable + /// When: They are encoded and decoded + /// Then: The encoded data can be decoded, and the decoded data is equal to the original one + func testCodableTypes_shouldEncodeAndDecodeSuccesfully() throws { + let location = PinpointClientTypes.EndpointLocation( + city: "city", + country: "country", + latitude: 10.0, + longitude: 10.0, + postalCode: "postalCode", + region: "region" + ) + + let demographic = PinpointClientTypes.EndpointDemographic( + appVersion: "appVersion", + locale: "locale", + make: "make", + model: "model", + modelVersion: "modelVersion", + platform: "platform", + platformVersion: "platformVersion", + timezone: "timezone" + ) + + let user = PinpointClientTypes.EndpointUser( + userAttributes: [ + "attributes": ["value1", "value2"] + ], + userId: "userId" + ) + + let archiver = AmplifyArchiver() + + // Encode types + let encodedLocation = try archiver.encode(location) + let encodedDemographic = try archiver.encode(demographic) + let encodedUser = try archiver.encode(user) + + // Decode types + let decodedLocation = try archiver.decode( + PinpointClientTypes.EndpointLocation.self, + from: encodedLocation + ) + XCTAssertEqual(decodedLocation, location) + + let decodedDemographic = try archiver.decode( + PinpointClientTypes.EndpointDemographic.self, + from: encodedDemographic + ) + XCTAssertEqual(decodedDemographic, demographic) + + let decodedUser = try archiver.decode( + PinpointClientTypes.EndpointUser.self, + from: encodedUser + ) + XCTAssertEqual(decodedUser, user) + } +} diff --git a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/PinpointRequestsRegistryTests.swift b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/PinpointRequestsRegistryTests.swift index 7b17dd5b74..0cd3feec43 100644 --- a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/PinpointRequestsRegistryTests.swift +++ b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/PinpointRequestsRegistryTests.swift @@ -6,9 +6,10 @@ // import AWSPinpoint -import ClientRuntime @_spi(InternalAWSPinpoint) @testable import InternalAWSPinpoint import XCTest +import SmithyHTTPAPI +import Smithy class PinpointRequestsRegistryTests: XCTestCase { private var mockedHttpSdkClient: MockHttpClientEngine! @@ -70,13 +71,13 @@ class PinpointRequestsRegistryTests: XCTestCase { pinpointConfiguration.httpClientEngine } - private func createSdkRequest(for api: PinpointRequestsRegistry.API?) throws -> SdkHttpRequest { + private func createSdkRequest(for api: PinpointRequestsRegistry.API?) throws -> HTTPRequest { let apiPath = api?.rawValue ?? "otherApi" let endpoint = try Endpoint( urlString: "https://host:42/path/\(apiPath)/suffix", headers: .init(["User-Agent": "mocked_user_agent"]) ) - return SdkHttpRequest( + return HTTPRequest( method: .put, endpoint: endpoint ) @@ -91,9 +92,9 @@ private extension HTTPClient { private class MockHttpClientEngine: HTTPClient { var executeCount = 0 - var request: SdkHttpRequest? + var request: HTTPRequest? - func send(request: SdkHttpRequest) async throws -> HttpResponse { + func send(request: HTTPRequest) async throws -> HTTPResponse { executeCount += 1 self.request = request return .init(body: .empty, statusCode: .accepted) @@ -106,6 +107,6 @@ private class MockLogAgent: LogAgent { let name = "MockLogAgent" var level: LogAgentLevel = .info - func log(level: ClientRuntime.LogAgentLevel, message: String, metadata: [String : String]?, source: String, file: String, function: String, line: UInt) { + func log(level: LogAgentLevel, message: String, metadata: [String : String]?, source: String, file: String, function: String, line: UInt) { } } diff --git a/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingCategoryClient.swift b/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingCategoryClient.swift index 86a63bd956..9a0458f612 100644 --- a/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingCategoryClient.swift +++ b/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingCategoryClient.swift @@ -10,8 +10,8 @@ import Amplify import Combine import Foundation import AWSCloudWatchLogs -import AWSClientRuntime import Network +import SmithyIdentity /// Concrete implementation of /// [LoggingCategoryClientBehavior](x-source-tag://LoggingCategoryClientBehavior) @@ -26,7 +26,7 @@ final class AWSCloudWatchLoggingCategoryClient { private let lock = NSLock() private let logGroupName: String private let region: String - private let credentialsProvider: CredentialsProviding + private let credentialIdentityResolver: any AWSCredentialIdentityResolver private let authentication: AuthCategoryUserBehavior private var loggersByKey: [LoggerKey: AWSCloudWatchLoggingSessionController] = [:] private let localStoreMaxSizeInMB: Int @@ -38,7 +38,7 @@ final class AWSCloudWatchLoggingCategoryClient { init( enable: Bool, - credentialsProvider: CredentialsProviding, + credentialIdentityResolver: some AWSCredentialIdentityResolver, authentication: AuthCategoryUserBehavior, loggingConstraintsResolver: AWSCloudWatchLoggingConstraintsResolver, logGroupName: String, @@ -48,7 +48,7 @@ final class AWSCloudWatchLoggingCategoryClient { networkMonitor: LoggingNetworkMonitor = NWPathMonitor() ) { self.enabled = enable - self.credentialsProvider = credentialsProvider + self.credentialIdentityResolver = credentialIdentityResolver self.authentication = authentication self.logGroupName = logGroupName self.region = region @@ -145,7 +145,7 @@ extension AWSCloudWatchLoggingCategoryClient: LoggingCategoryClientBehavior { return existing } - let controller = AWSCloudWatchLoggingSessionController(credentialsProvider: credentialsProvider, + let controller = AWSCloudWatchLoggingSessionController(credentialIdentityResolver: credentialIdentityResolver, authentication: authentication, logFilter: self.logFilter, category: category, diff --git a/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingPlugin.swift b/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingPlugin.swift index 2271e877d8..ba8721681f 100644 --- a/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingPlugin.swift +++ b/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingPlugin.swift @@ -42,7 +42,7 @@ public class AWSCloudWatchLoggingPlugin: LoggingCategoryPlugin { let authService = AWSAuthService() self.loggingClient = AWSCloudWatchLoggingCategoryClient( enable: configuration.enable, - credentialsProvider: authService.getCredentialsProvider(), + credentialIdentityResolver: authService.getCredentialIdentityResolver(), authentication: Amplify.Auth, loggingConstraintsResolver: AWSCloudWatchLoggingConstraintsResolver(loggingPluginConfiguration: configuration), logGroupName: configuration.logGroupName, @@ -127,7 +127,7 @@ public class AWSCloudWatchLoggingPlugin: LoggingCategoryPlugin { self.loggingClient = AWSCloudWatchLoggingCategoryClient( enable: configuration.enable, - credentialsProvider: authService.getCredentialsProvider(), + credentialIdentityResolver: authService.getCredentialIdentityResolver(), authentication: Amplify.Auth, loggingConstraintsResolver: AWSCloudWatchLoggingConstraintsResolver(loggingPluginConfiguration: configuration), logGroupName: configuration.logGroupName, diff --git a/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingSessionController.swift b/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingSessionController.swift index de5fcd5c7e..85f2d86ed6 100644 --- a/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingSessionController.swift +++ b/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingSessionController.swift @@ -11,8 +11,8 @@ import Amplify import Combine import Foundation import AWSCloudWatchLogs -import AWSClientRuntime import Network +import SmithyIdentity /// Responsible for setting up and tearing-down log sessions for a given category/tag according to changes in /// user authentication sessions. @@ -25,7 +25,7 @@ final class AWSCloudWatchLoggingSessionController { private let logGroupName: String private let region: String private let localStoreMaxSizeInMB: Int - private let credentialsProvider: CredentialsProviding + private let credentialIdentityResolver: any AWSCredentialIdentityResolver private let authentication: AuthCategoryUserBehavior private let category: String private var session: AWSCloudWatchLoggingSession? @@ -59,7 +59,7 @@ final class AWSCloudWatchLoggingSessionController { } /// - Tag: CloudWatchLogSessionController.init - init(credentialsProvider: CredentialsProviding, + init(credentialIdentityResolver: some AWSCredentialIdentityResolver, authentication: AuthCategoryUserBehavior, logFilter: AWSCloudWatchLoggingFilterBehavior, category: String, @@ -71,7 +71,7 @@ final class AWSCloudWatchLoggingSessionController { userIdentifier: String?, networkMonitor: LoggingNetworkMonitor ) { - self.credentialsProvider = credentialsProvider + self.credentialIdentityResolver = credentialIdentityResolver self.authentication = authentication self.logFilter = logFilter self.category = category @@ -104,8 +104,9 @@ final class AWSCloudWatchLoggingSessionController { private func createConsumer() throws -> LogBatchConsumer? { if self.client == nil { let configuration = try CloudWatchLogsClient.CloudWatchLogsClientConfiguration( + awsCredentialIdentityResolver: credentialIdentityResolver, region: region, - credentialsProvider: credentialsProvider + signingRegion: region ) configuration.httpClientEngine = .userAgentEngine(for: configuration) diff --git a/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/Configuration/DefaultRemoteLoggingConstraintsProvider.swift b/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/Configuration/DefaultRemoteLoggingConstraintsProvider.swift index 6a11ded903..4cedbe40f1 100644 --- a/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/Configuration/DefaultRemoteLoggingConstraintsProvider.swift +++ b/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/Configuration/DefaultRemoteLoggingConstraintsProvider.swift @@ -9,13 +9,14 @@ import Foundation import Amplify import AWSPluginsCore import InternalAmplifyCredentials -import AWSClientRuntime -import ClientRuntime +import Smithy +import SmithyIdentity +import SmithyHTTPAPI public class DefaultRemoteLoggingConstraintsProvider: RemoteLoggingConstraintsProvider { public let refreshIntervalInSeconds: Int private let endpoint: URL - private let credentialProvider: CredentialsProviding? + private let credentialProvider: (any AWSCredentialIdentityResolver)? private let region: String private let loggingConstraintsLocalStore: LoggingConstraintsLocalStore = UserDefaults.standard @@ -32,12 +33,12 @@ public class DefaultRemoteLoggingConstraintsProvider: RemoteLoggingConstraintsPr public init( endpoint: URL, region: String, - credentialProvider: CredentialsProviding? = nil, + credentialProvider: (any AWSCredentialIdentityResolver)? = nil, refreshIntervalInSeconds: Int = 1200 ) { self.endpoint = endpoint if credentialProvider == nil { - self.credentialProvider = AWSAuthService().getCredentialsProvider() + self.credentialProvider = AWSAuthService().getCredentialIdentityResolver() } else { self.credentialProvider = credentialProvider } @@ -85,13 +86,13 @@ public class DefaultRemoteLoggingConstraintsProvider: RemoteLoggingConstraintsPr request.setValue(host, forHTTPHeaderField: "host") let httpMethod = (request.httpMethod?.uppercased()) - .flatMap(HttpMethodType.init(rawValue:)) ?? .get + .flatMap(HTTPMethodType.init(rawValue:)) ?? .get let queryItems = URLComponents(url: url, resolvingAgainstBaseURL: false)? .queryItems? - .map { ClientRuntime.SDKURLQueryItem(name: $0.name, value: $0.value) } ?? [] + .map { URIQueryItem(name: $0.name, value: $0.value) } ?? [] - let requestBuilder = SdkHttpRequestBuilder() + let requestBuilder = HTTPRequestBuilder() .withHost(host) .withPath(url.path) .withQueryItems(queryItems) @@ -107,7 +108,7 @@ public class DefaultRemoteLoggingConstraintsProvider: RemoteLoggingConstraintsPr guard let urlRequest = try await AmplifyAWSSignatureV4Signer().sigV4SignedRequest( requestBuilder: requestBuilder, - credentialsProvider: credentialProvider, + credentialIdentityResolver: credentialProvider, signingName: "execute-api", signingRegion: region, date: Date() diff --git a/AmplifyPlugins/Logging/Tests/AWSCloudWatchLoggingPluginTests/AWSCloudWatchLoggingSessionControllerTests.swift b/AmplifyPlugins/Logging/Tests/AWSCloudWatchLoggingPluginTests/AWSCloudWatchLoggingSessionControllerTests.swift index 9457644826..3b768b2735 100644 --- a/AmplifyPlugins/Logging/Tests/AWSCloudWatchLoggingPluginTests/AWSCloudWatchLoggingSessionControllerTests.swift +++ b/AmplifyPlugins/Logging/Tests/AWSCloudWatchLoggingPluginTests/AWSCloudWatchLoggingSessionControllerTests.swift @@ -56,7 +56,7 @@ final class AWSCloudWatchLoggingSessionControllerTests: XCTestCase { contents: Data(bytes), attributes: [FileAttributeKey: Any]()) systemUnderTest = AWSCloudWatchLoggingSessionController( - credentialsProvider: mockCredentialProvider, + credentialIdentityResolver: mockCredentialProvider, authentication: mockAuth, logFilter: mockLoggingFilter, category: category, diff --git a/AmplifyPlugins/Notifications/Push/Sources/AWSPinpointPushNotificationsPlugin/Error/Pinpoint+PushNotificationsErrorConvertible.swift b/AmplifyPlugins/Notifications/Push/Sources/AWSPinpointPushNotificationsPlugin/Error/Pinpoint+PushNotificationsErrorConvertible.swift index 9c3aaf2749..b6203676d0 100644 --- a/AmplifyPlugins/Notifications/Push/Sources/AWSPinpointPushNotificationsPlugin/Error/Pinpoint+PushNotificationsErrorConvertible.swift +++ b/AmplifyPlugins/Notifications/Push/Sources/AWSPinpointPushNotificationsPlugin/Error/Pinpoint+PushNotificationsErrorConvertible.swift @@ -9,7 +9,7 @@ import Foundation import Amplify import AWSPinpoint import ClientRuntime -import AWSClientRuntime +@_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime private func recoverySuggestion(for error: ClientRuntime.ModeledError) -> String { type(of: error).isRetryable diff --git a/AmplifyPlugins/Notifications/Push/Tests/AWSPinpointPushNotificationsPluginUnitTests/AWSPinpointPushNotificationsPluginConfigureTests.swift b/AmplifyPlugins/Notifications/Push/Tests/AWSPinpointPushNotificationsPluginUnitTests/AWSPinpointPushNotificationsPluginConfigureTests.swift index 2c3ce8461c..1543457e97 100644 --- a/AmplifyPlugins/Notifications/Push/Tests/AWSPinpointPushNotificationsPluginUnitTests/AWSPinpointPushNotificationsPluginConfigureTests.swift +++ b/AmplifyPlugins/Notifications/Push/Tests/AWSPinpointPushNotificationsPluginUnitTests/AWSPinpointPushNotificationsPluginConfigureTests.swift @@ -22,7 +22,7 @@ class AWSPinpointPushNotificationsPluginConfigureTests: AWSPinpointPushNotificat override func setUp() async throws { try await super.setUp() - AWSPinpointFactory.credentialsProvider = MockCredentialsProvider() + AWSPinpointFactory.credentialIdentityResolver = MockCredentialsProvider() AmplifyRemoteNotificationsHelper.shared = mockRemoteNotifications } diff --git a/AmplifyPlugins/Notifications/Push/Tests/AWSPinpointPushNotificationsPluginUnitTests/ErrorPushNotificationsTests.swift b/AmplifyPlugins/Notifications/Push/Tests/AWSPinpointPushNotificationsPluginUnitTests/ErrorPushNotificationsTests.swift index fd5c80a93e..7b3a8fbb30 100644 --- a/AmplifyPlugins/Notifications/Push/Tests/AWSPinpointPushNotificationsPluginUnitTests/ErrorPushNotificationsTests.swift +++ b/AmplifyPlugins/Notifications/Push/Tests/AWSPinpointPushNotificationsPluginUnitTests/ErrorPushNotificationsTests.swift @@ -10,6 +10,7 @@ import AWSPinpoint @testable import AWSPinpointPushNotificationsPlugin import Foundation import XCTest +@_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime class ErrorPushNotificationsTests: XCTestCase { /// Given: A NSError error diff --git a/AmplifyPlugins/Predictions/AWSPredictionsPlugin/AWSPredictionsPlugin+Configure.swift b/AmplifyPlugins/Predictions/AWSPredictionsPlugin/AWSPredictionsPlugin+Configure.swift index 42ddda79bb..6989caa06a 100644 --- a/AmplifyPlugins/Predictions/AWSPredictionsPlugin/AWSPredictionsPlugin+Configure.swift +++ b/AmplifyPlugins/Predictions/AWSPredictionsPlugin/AWSPredictionsPlugin+Configure.swift @@ -39,7 +39,7 @@ extension AWSPredictionsPlugin { } let authService = AWSAuthService() - let credentialsProvider = authService.getCredentialsProvider() + let credentialIdentityResolver = authService.getCredentialIdentityResolver() let coremlService: CoreMLPredictionBehavior? #if canImport(Speech) && canImport(Vision) coremlService = try CoreMLPredictionService(configuration: configuration) @@ -49,7 +49,7 @@ extension AWSPredictionsPlugin { let predictionsService = try AWSPredictionsService( configuration: predictionsConfiguration, - credentialsProvider: credentialsProvider, + credentialIdentityResolver: credentialIdentityResolver, identifier: key ) diff --git a/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Dependency/AWSTranscribeStreamingAdapter.swift b/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Dependency/AWSTranscribeStreamingAdapter.swift index 5c70b79948..88d9acd913 100644 --- a/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Dependency/AWSTranscribeStreamingAdapter.swift +++ b/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Dependency/AWSTranscribeStreamingAdapter.swift @@ -9,7 +9,8 @@ import Foundation import Amplify import AWSPluginsCore import AWSTranscribeStreaming -import AWSClientRuntime +import AwsCommonRuntimeKit +import SmithyIdentity class AWSTranscribeStreamingAdapter: AWSTranscribeStreamingBehavior { @@ -22,11 +23,11 @@ class AWSTranscribeStreamingAdapter: AWSTranscribeStreamingBehavior { let mediaSampleRateHertz: Int } - let credentialsProvider: CredentialsProviding + let credentialIdentityResolver: any AWSCredentialIdentityResolver let region: String - init(credentialsProvider: CredentialsProviding, region: String) { - self.credentialsProvider = credentialsProvider + init(credentialIdentityResolver: any AWSCredentialIdentityResolver, region: String) { + self.credentialIdentityResolver = credentialIdentityResolver self.region = region } diff --git a/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Dependency/TranscribeStreamingClientTypes+Decodable.swift b/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Dependency/TranscribeStreamingClientTypes+Decodable.swift new file mode 100644 index 0000000000..7579667a60 --- /dev/null +++ b/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Dependency/TranscribeStreamingClientTypes+Decodable.swift @@ -0,0 +1,169 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import AWSTranscribeStreaming +import Foundation + +extension TranscribeStreamingClientTypes.TranscriptEvent: Decodable { + private enum CodingKeys: String, CodingKey { + case transcript = "Transcript" + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + try self.init( + transcript: container.decode( + TranscribeStreamingClientTypes.Transcript.self, + forKey: .transcript + ) + ) + } +} + +extension TranscribeStreamingClientTypes.Transcript: Decodable { + private enum CodingKeys: String, CodingKey { + case results = "Results" + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + try self.init( + results: container.decode([TranscribeStreamingClientTypes.Result].self, forKey: .results) + ) + } +} + +extension TranscribeStreamingClientTypes.Result: Decodable { + private enum CodingKeys: String, CodingKey { + case alternatives = "Alternatives" + case channelId = "ChannelId" + case endTime = "EndTime" + case isPartial = "IsPartial" + case languageCode = "LanguageCode" + case languageIdentification = "LanguageIdentification" + case resultId = "ResultId" + case startTime = "StartTime" + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + try self.init( + alternatives: container.decodeIfPresent( + [TranscribeStreamingClientTypes.Alternative].self, + forKey: .alternatives + ), + channelId: container.decodeIfPresent(String.self, forKey: .channelId), + endTime: container.decode(Double.self, forKey: .endTime), + isPartial: container.decode(Bool.self, forKey: .isPartial), + languageCode: container.decodeIfPresent( + TranscribeStreamingClientTypes.LanguageCode.self, + forKey: .languageCode + ), + languageIdentification: container.decodeIfPresent( + [TranscribeStreamingClientTypes.LanguageWithScore].self, + forKey: .languageIdentification + ), + resultId: container.decodeIfPresent(String.self, forKey: .resultId), + startTime: container.decode(Double.self, forKey: .startTime) + ) + } +} + +extension TranscribeStreamingClientTypes.Alternative: Decodable { + private enum CodingKeys: String, CodingKey { + case entities = "Entities" + case items = "Items" + case transcript = "Transcript" + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + try self.init( + entities: container.decodeIfPresent( + [TranscribeStreamingClientTypes.Entity].self, + forKey: .entities + ), + items: container.decodeIfPresent( + [TranscribeStreamingClientTypes.Item].self, + forKey: .items + ), + transcript: container.decodeIfPresent(String.self, forKey: .transcript) + ) + } +} + +extension TranscribeStreamingClientTypes.Entity: Decodable { + private enum CodingKeys: String, CodingKey { + case category = "Category" + case confidence = "Confidence" + case content = "Content" + case endTime = "EndTime" + case startTime = "StartTime" + case type = "Type" + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + try self.init( + category: container.decodeIfPresent(String.self, forKey: .category), + confidence: container.decodeIfPresent(Double.self, forKey: .confidence), + content: container.decodeIfPresent(String.self, forKey: .content), + endTime: container.decode(Double.self, forKey: .endTime), + startTime: container.decode(Double.self, forKey: .startTime), + type: container.decodeIfPresent(String.self, forKey: .type) + ) + } +} + +extension TranscribeStreamingClientTypes.Item: Decodable { + private enum CodingKeys: String, CodingKey { + case confidence = "Confidence" + case content = "Content" + case endTime = "EndTime" + case speaker = "Speaker" + case stable = "Stable" + case startTime = "StartTime" + case type = "Type" + case vocabularyFilterMatch = "VocabularyFilterMatch" + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + try self.init( + confidence: container.decodeIfPresent(Double.self, forKey: .confidence), + content: container.decodeIfPresent(String.self, forKey: .content), + endTime: container.decode(Double.self, forKey: .endTime), + speaker: container.decodeIfPresent(String.self, forKey: .speaker), + stable: container.decodeIfPresent(Bool.self, forKey: .stable), + startTime: container.decode(Double.self, forKey: .startTime), + type: container.decodeIfPresent(TranscribeStreamingClientTypes.ItemType.self, forKey: .type), + vocabularyFilterMatch: container.decode(Bool.self, forKey: .vocabularyFilterMatch) + ) + } +} + +extension TranscribeStreamingClientTypes.LanguageWithScore: Decodable { + private enum CodingKeys: String, CodingKey { + case languageCode = "LanguageCode" + case score = "Score" + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + try self.init( + languageCode: container.decodeIfPresent( + TranscribeStreamingClientTypes.LanguageCode.self, + forKey: .languageCode + ), + score: container.decode(Double.self, forKey: .score) + ) + } +} + +extension TranscribeStreamingClientTypes.ItemType: Decodable {} + +extension TranscribeStreamingClientTypes.LanguageCode: Decodable {} diff --git a/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Service/Predictions/AWSPredictionsService.swift b/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Service/Predictions/AWSPredictionsService.swift index 9470da9c2b..1d829747dc 100644 --- a/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Service/Predictions/AWSPredictionsService.swift +++ b/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Service/Predictions/AWSPredictionsService.swift @@ -5,6 +5,7 @@ // SPDX-License-Identifier: Apache-2.0 // +import protocol Amplify.Logger import Amplify import AWSRekognition import AWSTranslate @@ -14,9 +15,9 @@ import AWSPolly import AWSPluginsCore @_spi(PluginHTTPClientEngine) import InternalAmplifyCredentials import Foundation -import ClientRuntime -import AWSClientRuntime +import AwsCommonRuntimeKit import AWSTranscribeStreaming +import SmithyIdentity class AWSPredictionsService { var identifier: String! @@ -31,12 +32,13 @@ class AWSPredictionsService { convenience init( configuration: PredictionsPluginConfiguration, - credentialsProvider: CredentialsProviding, + credentialIdentityResolver: any AWSCredentialIdentityResolver, identifier: String ) throws { let translateClientConfiguration = try TranslateClient.TranslateClientConfiguration( + awsCredentialIdentityResolver: credentialIdentityResolver, region: configuration.convert.region, - credentialsProvider: credentialsProvider + signingRegion: configuration.convert.region ) translateClientConfiguration.httpClientEngine = .userAgentEngine( for: translateClientConfiguration @@ -45,8 +47,9 @@ class AWSPredictionsService { let awsTranslateClient = TranslateClient(config: translateClientConfiguration) let pollyClientConfiguration = try PollyClient.PollyClientConfiguration( + awsCredentialIdentityResolver: credentialIdentityResolver, region: configuration.convert.region, - credentialsProvider: credentialsProvider + signingRegion: configuration.convert.region ) pollyClientConfiguration.httpClientEngine = .userAgentEngine( for: pollyClientConfiguration @@ -54,8 +57,9 @@ class AWSPredictionsService { let awsPollyClient = PollyClient(config: pollyClientConfiguration) let comprehendClientConfiguration = try ComprehendClient.ComprehendClientConfiguration( + awsCredentialIdentityResolver: credentialIdentityResolver, region: configuration.convert.region, - credentialsProvider: credentialsProvider + signingRegion: configuration.convert.region ) comprehendClientConfiguration.httpClientEngine = .userAgentEngine( for: comprehendClientConfiguration @@ -64,8 +68,9 @@ class AWSPredictionsService { let awsComprehendClient = ComprehendClient(config: comprehendClientConfiguration) let rekognitionClientConfiguration = try RekognitionClient.RekognitionClientConfiguration( + awsCredentialIdentityResolver: credentialIdentityResolver, region: configuration.identify.region, - credentialsProvider: credentialsProvider + signingRegion: configuration.convert.region ) rekognitionClientConfiguration.httpClientEngine = .userAgentEngine( for: rekognitionClientConfiguration @@ -73,8 +78,9 @@ class AWSPredictionsService { let awsRekognitionClient = RekognitionClient(config: rekognitionClientConfiguration) let textractClientConfiguration = try TextractClient.TextractClientConfiguration( + awsCredentialIdentityResolver: credentialIdentityResolver, region: configuration.identify.region, - credentialsProvider: credentialsProvider + signingRegion: configuration.convert.region ) textractClientConfiguration.httpClientEngine = .userAgentEngine( for: textractClientConfiguration @@ -82,7 +88,7 @@ class AWSPredictionsService { let awsTextractClient = TextractClient(config: textractClientConfiguration) let awsTranscribeStreamingAdapter = AWSTranscribeStreamingAdapter( - credentialsProvider: credentialsProvider, + credentialIdentityResolver: credentialIdentityResolver, region: configuration.convert.region ) diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/AWSS3PreSignedURLBuilderAdapter.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/AWSS3PreSignedURLBuilderAdapter.swift index b935df2dd0..35c4e6f974 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/AWSS3PreSignedURLBuilderAdapter.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/AWSS3PreSignedURLBuilderAdapter.swift @@ -23,7 +23,6 @@ class AWSS3PreSignedURLBuilderAdapter: AWSS3PreSignedURLBuilderBehavior { let logger: Logger /// Creates a pre-signed URL builder. - /// - Parameter credentialsProvider: Credentials Provider. init(config: S3Client.S3ClientConfiguration, bucket: String, logger: Logger = storageLogger) { self.bucket = bucket self.config = config diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/S3ClientConfiguration+withAccelerate.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/S3ClientConfiguration+withAccelerate.swift index 526b90b1fe..2d87150438 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/S3ClientConfiguration+withAccelerate.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/S3ClientConfiguration+withAccelerate.swift @@ -16,35 +16,42 @@ extension S3Client.S3ClientConfiguration { } // if `shouldAccelerate` isn't `nil` and - // is equal to the exisiting config's `serviceSpecific.accelerate + // is equal to the exisiting config's `accelerate` // we can avoid allocating a new configuration object. - if shouldAccelerate == serviceSpecific.accelerate { + if shouldAccelerate == accelerate { return self } - // This shouldn't happen based on how we're initially - // creating the configuration, but we can't reasonably prove - // it at compile time - so we have to unwrap. - guard let region else { return self } - - // `S3Client.ServiceSpecificConfiguration` is a struct - // so we're copying by value here. - var serviceSpecific = serviceSpecific - serviceSpecific.accelerate = shouldAccelerate - // `S3Client.S3ClientConfiguration` is a `class` so we need to make // a deep copy here as not to change the value of the existing base // configuration. - let copy = try S3Client.S3ClientConfiguration( + let copy = try S3Client.S3ClientConfiguration( + useFIPS: useFIPS, + useDualStack: useDualStack, + appID: appID, + awsCredentialIdentityResolver: awsCredentialIdentityResolver, + awsRetryMode: awsRetryMode, region: region, - credentialsProvider: credentialsProvider, - endpoint: endpoint, - serviceSpecific: serviceSpecific, signingRegion: signingRegion, - useDualStack: useDualStack, - useFIPS: useFIPS, - retryMode: awsRetryMode, - appID: appID + forcePathStyle: forcePathStyle, + useArnRegion: useArnRegion, + disableMultiRegionAccessPoints: disableMultiRegionAccessPoints, + accelerate: shouldAccelerate, + disableS3ExpressSessionAuth: disableS3ExpressSessionAuth, + useGlobalEndpoint: useGlobalEndpoint, + endpointResolver: endpointResolver, + telemetryProvider: telemetryProvider, + retryStrategyOptions: retryStrategyOptions, + clientLogMode: clientLogMode, + endpoint: endpoint, + idempotencyTokenGenerator: idempotencyTokenGenerator, + httpClientEngine: httpClientEngine, + httpClientConfiguration: httpClientConfiguration, + authSchemes: authSchemes, + authSchemeResolver: authSchemeResolver, + bearerTokenIdentityResolver: bearerTokenIdentityResolver, + interceptorProviders: interceptorProviders, + httpInterceptorProviders: httpInterceptorProviders ) return copy diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/S3ClientConfigurationProtocol+Endpoint.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/S3ClientConfigurationProtocol+Endpoint.swift index 5eac989093..9f8c766831 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/S3ClientConfigurationProtocol+Endpoint.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/S3ClientConfigurationProtocol+Endpoint.swift @@ -9,16 +9,16 @@ import AWSS3 extension S3Client.S3ClientConfiguration { func endpointParams(withBucket bucket: String?) -> EndpointParams { EndpointParams( - accelerate: serviceSpecific.accelerate ?? false, + accelerate: accelerate ?? false, bucket: bucket, - disableMultiRegionAccessPoints: serviceSpecific.disableMultiRegionAccessPoints ?? false, + disableMultiRegionAccessPoints: disableMultiRegionAccessPoints ?? false, endpoint: endpoint, - forcePathStyle: serviceSpecific.forcePathStyle ?? false, + forcePathStyle: forcePathStyle ?? false, region: region, - useArnRegion: serviceSpecific.useArnRegion, + useArnRegion: useArnRegion, useDualStack: useDualStack ?? false, useFIPS: useFIPS ?? false, - useGlobalEndpoint: serviceSpecific.useGlobalEndpoint ?? false + useGlobalEndpoint: useGlobalEndpoint ?? false ) } diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/SdkTypealiases.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/SdkTypealiases.swift index d0cdf91669..03a0ea9561 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/SdkTypealiases.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/SdkTypealiases.swift @@ -6,8 +6,7 @@ // import Foundation -import AWSClientRuntime -import ClientRuntime +import SmithyHTTPAPI /// - Tag: NetworkResult -public typealias NetworkResult = (Result) -> Void +public typealias NetworkResult = (Result) -> Void diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/UploadPartInput+presignURL.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/UploadPartInput+presignURL.swift index 6584e766f0..ae89c9359e 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/UploadPartInput+presignURL.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/UploadPartInput+presignURL.swift @@ -5,89 +5,113 @@ // SPDX-License-Identifier: Apache-2.0 import Foundation -import AWSS3 -import ClientRuntime +@testable import AWSS3 +@_spi(SmithyReadWrite) import ClientRuntime import AWSClientRuntime +import Smithy +import SmithyHTTPAPI +import SmithyRetries +// swiftlint:disable identifier_name +// swiftlint:disable line_length extension UploadPartInput { - func customPresignURL(config: S3Client.S3ClientConfiguration, expiration: TimeInterval) async throws -> ClientRuntime.URL? { + func customPresignURL( + config: S3Client.S3ClientConfiguration, + expiration: Foundation.TimeInterval + ) async throws -> Foundation.URL? { let serviceName = "S3" let input = self - let context = ClientRuntime.HttpContextBuilder() + let client: (SmithyHTTPAPI.HTTPRequest, Smithy.Context) async throws -> SmithyHTTPAPI.HTTPResponse = { (_, _) in + throw Smithy.ClientError.unknownError("No HTTP client configured for presigned request") + } + let context = Smithy.ContextBuilder() .withMethod(value: .put) .withServiceName(value: serviceName) .withOperation(value: "uploadPart") .withIdempotencyTokenGenerator(value: config.idempotencyTokenGenerator) .withLogger(value: config.logger) .withPartitionID(value: config.partitionID) - .withCredentialsProvider(value: config.credentialsProvider) + .withAuthSchemes(value: config.authSchemes ?? []) + .withAuthSchemeResolver(value: config.authSchemeResolver) + .withUnsignedPayloadTrait(value: false) + .withSocketTimeout(value: config.httpClientConfiguration.socketTimeout) + .withIdentityResolver(value: config.bearerTokenIdentityResolver, schemeID: "smithy.api#httpBearerAuth") + .withFlowType(value: .PRESIGN_URL) + .withExpiration(value: expiration) + .withIdentityResolver(value: config.awsCredentialIdentityResolver, schemeID: "aws.auth#sigv4") + .withIdentityResolver(value: config.awsCredentialIdentityResolver, schemeID: "aws.auth#sigv4a") .withRegion(value: config.region) .withSigningName(value: "s3") .withSigningRegion(value: config.signingRegion) + .withUnsignedPayloadTrait(value: true) .build() - var operation = ClientRuntime.OperationStack(id: "uploadPart") - operation.initializeStep.intercept( - position: .after, middleware: ClientRuntime.URLPathMiddleware(UploadPartInput.urlPathProvider(_:))) - operation.initializeStep.intercept(position: .after, middleware: ClientRuntime.URLHostMiddleware()) - operation.buildStep.intercept( - position: .before, - middleware: EndpointResolverMiddleware( - endpointResolver: config.serviceSpecific.endpointResolver, - endpointParams: config.endpointParams(withBucket: input.bucket) - ) - ) - operation.serializeStep.intercept( - position: .after, middleware: ClientRuntime.QueryItemMiddleware(UploadPartInput.queryItemProvider(_:))) - operation.finalizeStep.intercept( - position: .after, - middleware: ClientRuntime.RetryMiddleware( - options: config.retryStrategyOptions)) - let sigv4Config = AWSClientRuntime.SigV4Config( - signatureType: .requestQueryParams, - useDoubleURIEncode: false, - expiration: expiration, - unsignedBody: true, - signingAlgorithm: .sigv4) - operation.finalizeStep.intercept( - position: .before, middleware: AWSClientRuntime.SigV4Middleware(config: sigv4Config)) - operation.deserializeStep.intercept( - position: .after, middleware: ClientRuntime.LoggerMiddleware(clientLogMode: config.clientLogMode)) - operation.deserializeStep.intercept( - position: .after, middleware: AWSClientRuntime.AWSS3ErrorWith200StatusXMLMiddleware()) - let presignedRequestBuilder = try await operation.presignedRequest( - context: context, input: input, output: UploadPartOutput(), next: ClientRuntime.NoopHandler()) - guard let builtRequest = presignedRequestBuilder?.build(), let presignedURL = builtRequest.endpoint.url else { - return nil - } - return presignedURL - } - - static func urlPathProvider(_ value: UploadPartInput) -> Swift.String? { - guard let key = value.key else { - return nil + let builder = ClientRuntime.OrchestratorBuilder() + config.interceptorProviders.forEach { provider in + builder.interceptors.add(provider.create()) + } + config.httpInterceptorProviders.forEach { provider in + builder.interceptors.add(provider.create()) } - return "/\(key.urlPercentEncoding(encodeForwardSlash: false))" + builder.interceptors.add(ClientRuntime.URLPathMiddleware(UploadPartInput.urlPathProvider(_:))) + builder.interceptors.add(ClientRuntime.URLHostMiddleware()) + builder.deserialize(ClientRuntime.DeserializeMiddleware(UploadPartOutput.httpOutput(from:), PutObjectOutputError.httpError(from:))) + builder.interceptors.add(ClientRuntime.LoggerMiddleware(clientLogMode: config.clientLogMode)) + builder.retryStrategy(SmithyRetries.DefaultRetryStrategy(options: config.retryStrategyOptions)) + builder.retryErrorInfoProvider(AWSClientRuntime.AWSRetryErrorInfoProvider.errorInfo(for:)) + builder.applySigner(ClientRuntime.SignerMiddleware()) + let endpointParams = EndpointParams(accelerate: config.accelerate ?? false, bucket: input.bucket, disableMultiRegionAccessPoints: config.disableMultiRegionAccessPoints ?? false, disableS3ExpressSessionAuth: config.disableS3ExpressSessionAuth, endpoint: config.endpoint, forcePathStyle: config.forcePathStyle ?? false, key: input.key, region: config.region, useArnRegion: config.useArnRegion, useDualStack: config.useDualStack ?? false, useFIPS: config.useFIPS ?? false, useGlobalEndpoint: config.useGlobalEndpoint ?? false) + context.attributes.set(key: Smithy.AttributeKey(name: "EndpointParams"), value: endpointParams) + builder.applyEndpoint(AWSClientRuntime.EndpointResolverMiddleware(endpointResolverBlock: { [config] in try config.endpointResolver.resolve(params: $0) }, endpointParams: endpointParams)) + builder.selectAuthScheme(ClientRuntime.AuthSchemeMiddleware()) + builder.interceptors.add(AWSClientRuntime.AWSS3ErrorWith200StatusXMLMiddleware()) + builder.interceptors.add(AWSClientRuntime.FlexibleChecksumsRequestMiddleware(checksumAlgorithm: input.checksumAlgorithm?.rawValue)) + builder.serialize(UploadPartPresignedMiddleware()) + var metricsAttributes = Smithy.Attributes() + metricsAttributes.set(key: ClientRuntime.OrchestratorMetricsAttributesKeys.service, value: "S3") + metricsAttributes.set(key: ClientRuntime.OrchestratorMetricsAttributesKeys.method, value: "UploadPart") + let op = builder.attributes(context) + .telemetry(ClientRuntime.OrchestratorTelemetry( + telemetryProvider: config.telemetryProvider, + metricsAttributes: metricsAttributes, + meterScope: serviceName, + tracerScope: serviceName + )) + .executeRequest(client) + .build() + return try await op.presignRequest(input: input).endpoint.url } - } -extension UploadPartInput { +struct UploadPartPresignedMiddleware: Smithy.RequestMessageSerializer { + typealias InputType = UploadPartInput + typealias RequestType = SmithyHTTPAPI.HTTPRequest - static func queryItemProvider(_ value: UploadPartInput) throws -> [ClientRuntime.SDKURLQueryItem] { - var items = [ClientRuntime.SDKURLQueryItem]() - items.append(ClientRuntime.SDKURLQueryItem(name: "x-id", value: "UploadPart")) - guard let partNumber = value.partNumber else { - let message = "Creating a URL Query Item failed. partNumber is required and must not be nil." - throw ClientRuntime.ClientError.unknownError(message) + let id: Swift.String = "UploadPartPresignedMiddleware" + + func apply( + input: InputType, + builder: SmithyHTTPAPI.HTTPRequestBuilder, + attributes: Smithy.Context + ) throws { + builder.withQueryItem(.init( + name: "x-id", + value: "UploadPart") + ) + + guard let partNumber = input.partNumber else { + throw ClientError.invalidValue("partNumber is required and must not be nil.") } - let partNumberQueryItem = ClientRuntime.SDKURLQueryItem(name: "partNumber".urlPercentEncoding(), value: Swift.String(partNumber).urlPercentEncoding()) - items.append(partNumberQueryItem) - guard let uploadId = value.uploadId else { - let message = "Creating a URL Query Item failed. uploadId is required and must not be nil." - throw ClientRuntime.ClientError.unknownError(message) + builder.withQueryItem(.init( + name: "partNumber".urlPercentEncoding(), + value: Swift.String(partNumber).urlPercentEncoding()) + ) + + guard let uploadId = input.uploadId else { + throw ClientError.invalidValue("uploadId is required and must not be nil.") } - let uploadIdQueryItem = ClientRuntime.SDKURLQueryItem(name: "uploadId".urlPercentEncoding(), value: Swift.String(uploadId).urlPercentEncoding()) - items.append(uploadIdQueryItem) - return items + builder.withQueryItem(.init( + name: "uploadId".urlPercentEncoding(), + value: Swift.String(uploadId).urlPercentEncoding()) + ) } } diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Error/AWSS3+StorageErrorConvertible.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Error/AWSS3+StorageErrorConvertible.swift index 8b1e7e316e..41f770bc65 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Error/AWSS3+StorageErrorConvertible.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Error/AWSS3+StorageErrorConvertible.swift @@ -8,7 +8,7 @@ import Foundation import Amplify import AWSS3 -import AWSClientRuntime +@_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime extension AWSS3.NoSuchBucket: StorageErrorConvertible { var storageError: StorageError { diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService.swift index a07858a643..771a80876f 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService.swift @@ -63,11 +63,11 @@ class AWSS3StorageService: AWSS3StorageServiceBehavior, StorageServiceProxy { sessionConfiguration: URLSessionConfiguration? = nil, delegateQueue: OperationQueue? = nil, logger: Logger = storageLogger) throws { - let credentialsProvider = authService.getCredentialsProvider() + let credentialsProvider = authService.getCredentialIdentityResolver() let storageConfiguration = storageConfiguration ?? .init(forBucket: bucket) let clientConfig = try S3Client.S3ClientConfiguration( + awsCredentialIdentityResolver: credentialsProvider, region: region, - credentialsProvider: credentialsProvider, signingRegion: region ) diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/CreateMultipartUploadRequest.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/CreateMultipartUploadRequest.swift index 922acf13f1..ba81b02859 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/CreateMultipartUploadRequest.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/CreateMultipartUploadRequest.swift @@ -11,7 +11,7 @@ struct CreateMultipartUploadRequest { let bucket: String let key: String - let expires: Date? + let expires: String? let cacheControl: String? let contentDisposition: String? let contentEncoding: String? @@ -20,7 +20,7 @@ struct CreateMultipartUploadRequest { let metadata: [String: String]? init(bucket: String, key: String, - expires: Date? = nil, + expires: String? = nil, cacheControl: String? = nil, contentDisposition: String? = nil, contentEncoding: String? = nil, diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageMultipartUploadSession.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageMultipartUploadSession.swift index de59ecc9bb..73fe7bcc67 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageMultipartUploadSession.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageMultipartUploadSession.swift @@ -24,6 +24,7 @@ enum StorageMultipartUploadBehavior { case progressive } +// swiftlint:disable type_body_length class StorageMultipartUploadSession { enum Failure: Error { case invalidStateTransition @@ -43,6 +44,7 @@ class StorageMultipartUploadSession { private let onEvent: AWSS3StorageServiceBehavior.StorageServiceMultiPartUploadEventHandler private let transferTask: StorageTransferTask + private var cancelationError: (any Error)? = nil init(client: StorageMultipartUploadClient, bucket: String, @@ -244,10 +246,11 @@ class StorageMultipartUploadSession { } case .completed: onEvent(.completed(())) - case .aborting: + case .aborting(_, let error): + cancelationError = error try abort() - case .aborted: - onEvent(.completed(())) + case .aborted(_, let error): + onEvent(.failed(StorageError.unknown("Unable to upload", cancelationError ?? error))) case .failed(_, _, let error): onEvent(.failed(StorageError(error: error))) default: @@ -331,6 +334,11 @@ class StorageMultipartUploadSession { let index = partNumber - 1 parts[index] = .pending(bytes: part.bytes) multipartUpload = .parts(uploadId: uploadId, uploadFile: uploadFile, partSize: partSize, parts: parts) + let remainingParts = parts.filter({ $0.inProgress }) + if remainingParts.isEmpty { + // If there are no remaining parts in progress, manually trigger the reupload + try client.uploadPart(partNumber: partNumber, multipartUpload: multipartUpload, subTask: createSubTask(partNumber: partNumber)) + } } else { fatalError("Invalid state") } diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageServiceSessionDelegate.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageServiceSessionDelegate.swift index 1b83d5e17f..58e079b3f7 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageServiceSessionDelegate.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageServiceSessionDelegate.swift @@ -120,6 +120,18 @@ extension StorageServiceSessionDelegate: URLSessionTaskDelegate { if response.isErrorRetriable { logURLSessionActivity("Task can be retried.") } + + // For multipart uploads, we need to handle the upload part failure when the session is not aborted + if case .multiPartUploadPart(let uploadId, let partNumber) = transferTask.transferType, + let multipartUploadSession = storageService.findMultipartUploadSession(uploadId: uploadId), + !multipartUploadSession.isAborted { + multipartUploadSession.handle( + uploadPartEvent: .failed( + partNumber: partNumber, + error: responseError + ) + ) + } return } diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Utils/HttpClientEngineProxy.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Utils/HttpClientEngineProxy.swift index 407dc79756..0bc06facce 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Utils/HttpClientEngineProxy.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Utils/HttpClientEngineProxy.swift @@ -5,8 +5,8 @@ // SPDX-License-Identifier: Apache-2.0 // -import ClientRuntime import Foundation +import SmithyHTTPAPI /// Internal protocol that may be to inspect or decorate /// [ClientRuntime requests](x-source-tag://SdkHttpRequest). diff --git a/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Configuration/S3ClientConfigurationProxyTests.swift b/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Configuration/S3ClientConfigurationProxyTests.swift index 5ac3ba6a9a..62aee4194e 100644 --- a/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Configuration/S3ClientConfigurationProxyTests.swift +++ b/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Configuration/S3ClientConfigurationProxyTests.swift @@ -21,8 +21,8 @@ final class S3ClientConfigurationAccelerateTestCase: XCTestCase { func testPropertyOverrides() async throws { let baseConfiguration = try await configuration(accelerate: true) let sut = try baseConfiguration.withAccelerate(false) - XCTAssertEqual(sut.serviceSpecific.accelerate, false) - XCTAssertEqual(baseConfiguration.serviceSpecific.accelerate, true) + XCTAssertEqual(sut.accelerate, false) + XCTAssertEqual(baseConfiguration.accelerate, true) } /// Given: A client configuration. @@ -61,24 +61,19 @@ final class S3ClientConfigurationAccelerateTestCase: XCTestCase { // Helper configuration method private func configuration(accelerate: Bool) async throws -> S3Client.S3ClientConfiguration { - var serviceSpecific = try S3Client.ServiceSpecificConfiguration() - serviceSpecific.accelerate = accelerate - serviceSpecific.useArnRegion = .random() - serviceSpecific.useGlobalEndpoint = .random() - serviceSpecific.disableMultiRegionAccessPoints = .random() - serviceSpecific.forcePathStyle = .random() - let baseConfiguration = try await S3Client.S3ClientConfiguration( - credentialsProvider: nil, - endpoint: UUID().uuidString, - serviceSpecific: serviceSpecific, + useFIPS: .random(), + useDualStack: .random(), + appID: UUID().uuidString, + awsCredentialIdentityResolver: nil, region: "us-east-1", - regionResolver: nil, signingRegion: UUID().uuidString, - useDualStack: .random(), - useFIPS: .random(), - retryMode: .adaptive, - appID: UUID().uuidString + forcePathStyle: .random(), + useArnRegion: .random(), + disableMultiRegionAccessPoints: .random(), + accelerate: accelerate, + useGlobalEndpoint: .random(), + endpoint: UUID().uuidString ) return baseConfiguration diff --git a/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Service/Storage/AWSS3StorageServiceListTests.swift b/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Service/Storage/AWSS3StorageServiceListTests.swift index 5a4f5dc878..3b183d14a3 100644 --- a/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Service/Storage/AWSS3StorageServiceListTests.swift +++ b/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Service/Storage/AWSS3StorageServiceListTests.swift @@ -8,11 +8,11 @@ import AWSClientRuntime import AWSS3 import Amplify -import ClientRuntime import XCTest -import AWSClientRuntime +@_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime @testable import AWSPluginsTestCommon @testable import AWSS3StoragePlugin +import SmithyHTTPAPI final class AWSS3StorageServiceListTests: XCTestCase { @@ -99,7 +99,7 @@ final class AWSS3StorageServiceListTests: XCTestCase { func testSdkError() async throws { client.listObjectsV2Handler = { _ in throw AWSClientRuntime.UnknownAWSHTTPServiceError( - httpResponse: HttpResponse(body: .empty, statusCode: .forbidden), + httpResponse: HTTPResponse(body: .empty, statusCode: .forbidden), message: nil, requestID: nil, typeName: nil diff --git a/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Service/Storage/AWSS3StorageServiceTests.swift b/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Service/Storage/AWSS3StorageServiceTests.swift index a829dce219..4c11dbf9f6 100644 --- a/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Service/Storage/AWSS3StorageServiceTests.swift +++ b/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Service/Storage/AWSS3StorageServiceTests.swift @@ -8,9 +8,9 @@ @testable import Amplify @testable import AWSPluginsTestCommon @testable import AWSS3StoragePlugin -import ClientRuntime import AWSS3 import XCTest +import SmithyHTTPAPI class AWSS3StorageServiceTests: XCTestCase { private var service: AWSS3StorageService! @@ -340,6 +340,11 @@ class AWSS3StorageServiceTests: XCTestCase { func testUpload_withoutPreSignedURL_shouldSendFailEvent() async { let data = Data("someData".utf8) let expectation = self.expectation(description: "Upload") + let builder = MockAWSS3PreSignedURLBuilder() + builder.getPreSignedURLHandler = {_, _, _ in + throw StorageError.unknown("Unable to create URL", nil) + } + service.preSignedURLBuilder = builder service.upload( serviceKey: "key", uploadSource: .data(data), @@ -388,8 +393,8 @@ private class MockHttpClientEngineProxy: HttpClientEngineProxy { var target: HTTPClient? = nil var executeCount = 0 - var executeRequest: SdkHttpRequest? - func send(request: SdkHttpRequest) async throws -> HttpResponse { + var executeRequest: HTTPRequest? + func send(request: HTTPRequest) async throws -> HTTPResponse { executeCount += 1 executeRequest = request return .init(body: .empty, statusCode: .accepted) diff --git a/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Support/Internal/StorageMultipartUploadSessionTests.swift b/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Support/Internal/StorageMultipartUploadSessionTests.swift index f51f974e34..43e051033e 100644 --- a/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Support/Internal/StorageMultipartUploadSessionTests.swift +++ b/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Support/Internal/StorageMultipartUploadSessionTests.swift @@ -133,9 +133,10 @@ class StorageMultipartUploadSessionTests: XCTestCase { print("Progress: \(String(format: "%.2f", progress.fractionCompleted))") case .failed(let error): print("Error: \(error)") - XCTFail("Must not fail") + completedExp.fulfill() case .completed: print("Completed") + XCTFail("Must not complete") completedExp.fulfill() } } diff --git a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginAccelerateIntegrationTests.swift b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginAccelerateIntegrationTests.swift index 937a239daf..55c15521fe 100644 --- a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginAccelerateIntegrationTests.swift +++ b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginAccelerateIntegrationTests.swift @@ -25,7 +25,9 @@ class AWSS3StoragePluginAccelerateIntegrationTests: AWSS3StoragePluginTestBase { let task = Amplify.Storage.uploadData(key: key, data: data, options: .init(pluginOptions:["useAccelerateEndpoint": useAccelerateEndpoint])) - _ = try await task.value + await wait { + _ = try await task.value + } try await Amplify.Storage.remove(key: key) } @@ -63,7 +65,9 @@ class AWSS3StoragePluginAccelerateIntegrationTests: AWSS3StoragePluginTestBase { let task = Amplify.Storage.uploadFile(key: key, local: fileURL, options: .init(pluginOptions:["useAccelerateEndpoint": useAccelerateEndpoint])) - _ = try await task.value + await wait { + _ = try await task.value + } try await Amplify.Storage.remove(key: key) } @@ -75,7 +79,9 @@ class AWSS3StoragePluginAccelerateIntegrationTests: AWSS3StoragePluginTestBase { let task = Amplify.Storage.uploadData(key: key, data: AWSS3StoragePluginTestBase.largeDataObject, options: .init(pluginOptions:["useAccelerateEndpoint": useAccelerateEndpoint])) - _ = try await task.value + await wait(timeout: 60) { + _ = try await task.value + } try await Amplify.Storage.remove(key: key) } @@ -88,12 +94,16 @@ class AWSS3StoragePluginAccelerateIntegrationTests: AWSS3StoragePluginTestBase { let uploadTask = Amplify.Storage.uploadData(key: key, data: data, options: .init(pluginOptions:["useAccelerateEndpoint": useAccelerateEndpoint])) - _ = try await uploadTask.value + await wait { + _ = try await uploadTask.value + } let downloadTask = Amplify.Storage.downloadData(key: key, options: .init(pluginOptions:["useAccelerateEndpoint": useAccelerateEndpoint])) - let downloadedData = try await downloadTask.value - XCTAssertEqual(downloadedData, data) + await wait { + let downloadedData = try await downloadTask.value + XCTAssertEqual(downloadedData, data) + } try await Amplify.Storage.remove(key: key) } diff --git a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginAccessLevelTests.swift b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginAccessLevelTests.swift index 5a0da31147..0c97e2ce2e 100644 --- a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginAccessLevelTests.swift +++ b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginAccessLevelTests.swift @@ -70,8 +70,10 @@ class AWSS3StoragePluginAccessLevelTests: AWSS3StoragePluginTestBase { do { logger.debug("Upload [\(accessLevel)]") let uploadDataOptions = StorageUploadDataRequest.Options(accessLevel: accessLevel) - let uploadKey = try await Amplify.Storage.uploadData(key: key, data: dataInput, options: uploadDataOptions).value - XCTAssertEqual(key, uploadKey) + await wait { + let uploadKey = try await Amplify.Storage.uploadData(key: key, data: dataInput, options: uploadDataOptions).value + XCTAssertEqual(key, uploadKey) + } logger.debug("Remove [\(accessLevel)]") let removeOptions = StorageRemoveRequest.Options(accessLevel: accessLevel) @@ -120,8 +122,10 @@ class AWSS3StoragePluginAccessLevelTests: AWSS3StoragePluginTestBase { let dataInput = Data(UUID().uuidString.utf8) logger.debug("Upload [\(accessLevel)]") let uploadDataOptions = StorageUploadDataRequest.Options(accessLevel: accessLevel) - let uploadKey = try await Amplify.Storage.uploadData(key: key, data: dataInput, options: uploadDataOptions).value - XCTAssertEqual(key, uploadKey) + await wait { + let uploadKey = try await Amplify.Storage.uploadData(key: key, data: dataInput, options: uploadDataOptions).value + XCTAssertEqual(key, uploadKey) + } logger.debug("List [\(accessLevel)]") let listOptions = StorageListRequest.Options(accessLevel: accessLevel, @@ -182,7 +186,9 @@ class AWSS3StoragePluginAccessLevelTests: AWSS3StoragePluginTestBase { logger.debug("Uploading as user1 with \(testRun.accessLevel) access level") let options = StorageUploadDataRequest.Options(accessLevel: testRun.accessLevel) - _ = try await Amplify.Storage.uploadData(key: testRun.key, data: Data(testRun.key.utf8), options: options).value + await wait { + _ = try await Amplify.Storage.uploadData(key: testRun.key, data: Data(testRun.key.utf8), options: options).value + } logger.debug("Getting list as user1") let listOptions1 = StorageListRequest.Options(accessLevel: testRun.accessLevel, diff --git a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginBasicIntegrationTests.swift b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginBasicIntegrationTests.swift index 8aadc25de6..f14682dea2 100644 --- a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginBasicIntegrationTests.swift +++ b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginBasicIntegrationTests.swift @@ -8,7 +8,7 @@ @testable import Amplify import AWSS3StoragePlugin -import ClientRuntime +import SmithyHTTPAPI import CryptoKit import XCTest @@ -62,8 +62,9 @@ class AWSS3StoragePluginBasicIntegrationTests: AWSS3StoragePluginTestBase { func testUploadData() async throws { let key = UUID().uuidString let data = Data(key.utf8) - - _ = try await Amplify.Storage.uploadData(key: key, data: data, options: nil).value + await wait { + _ = try await Amplify.Storage.uploadData(key: key, data: data, options: nil).value + } _ = try await Amplify.Storage.remove(key: key) // Only the remove operation results in an SDK request @@ -80,7 +81,9 @@ class AWSS3StoragePluginBasicIntegrationTests: AWSS3StoragePluginTestBase { func testUploadEmptyData() async throws { let key = UUID().uuidString let data = Data("".utf8) - _ = try await Amplify.Storage.uploadData(key: key, data: data, options: nil).value + await wait { + _ = try await Amplify.Storage.uploadData(key: key, data: data, options: nil).value + } _ = try await Amplify.Storage.remove(key: key) XCTAssertEqual(requestRecorder.urlRequests.map { $0.httpMethod }, ["PUT"]) @@ -97,7 +100,9 @@ class AWSS3StoragePluginBasicIntegrationTests: AWSS3StoragePluginTestBase { let fileURL = URL(fileURLWithPath: filePath) FileManager.default.createFile(atPath: filePath, contents: Data(key.utf8), attributes: nil) - _ = try await Amplify.Storage.uploadFile(key: key, local: fileURL, options: nil).value + await wait { + _ = try await Amplify.Storage.uploadFile(key: key, local: fileURL, options: nil).value + } _ = try await Amplify.Storage.remove(key: key) // Only the remove operation results in an SDK request @@ -117,7 +122,9 @@ class AWSS3StoragePluginBasicIntegrationTests: AWSS3StoragePluginTestBase { let fileURL = URL(fileURLWithPath: filePath) FileManager.default.createFile(atPath: filePath, contents: Data("".utf8), attributes: nil) - _ = try await Amplify.Storage.uploadFile(key: key, local: fileURL, options: nil).value + await wait { + _ = try await Amplify.Storage.uploadFile(key: key, local: fileURL, options: nil).value + } _ = try await Amplify.Storage.remove(key: key) XCTAssertEqual(requestRecorder.urlRequests.map { $0.httpMethod }, ["PUT"]) @@ -130,10 +137,12 @@ class AWSS3StoragePluginBasicIntegrationTests: AWSS3StoragePluginTestBase { func testUploadLargeData() async throws { let key = UUID().uuidString - let uploadKey = try await Amplify.Storage.uploadData(key: key, - data: AWSS3StoragePluginTestBase.largeDataObject, - options: nil).value - XCTAssertEqual(uploadKey, key) + await wait(timeout: 60) { + let uploadKey = try await Amplify.Storage.uploadData(key: key, + data: AWSS3StoragePluginTestBase.largeDataObject, + options: nil).value + XCTAssertEqual(uploadKey, key) + } try await Amplify.Storage.remove(key: key) @@ -157,7 +166,9 @@ class AWSS3StoragePluginBasicIntegrationTests: AWSS3StoragePluginTestBase { contents: AWSS3StoragePluginTestBase.largeDataObject, attributes: nil) - _ = try await Amplify.Storage.uploadFile(key: key, local: fileURL, options: nil).value + await wait(timeout: 60) { + _ = try await Amplify.Storage.uploadFile(key: key, local: fileURL, options: nil).value + } _ = try await Amplify.Storage.remove(key: key) let userAgents = requestRecorder.urlRequests.compactMap { $0.allHTTPHeaderFields?["User-Agent"] } @@ -436,7 +447,7 @@ class AWSS3StoragePluginBasicIntegrationTests: AWSS3StoragePluginTestBase { } // An SDK call for the ListObjectsV2 call and each deletion is expected - let expectedMethods = [.get] + keys.map {_ in HttpMethodType.delete} + let expectedMethods = [.get] + keys.map {_ in HTTPMethodType.delete} XCTAssertEqual(requestRecorder.sdkRequests.map { $0.method}, expectedMethods) try assertUserAgentComponents(sdkRequests: requestRecorder.sdkRequests) @@ -527,7 +538,7 @@ class AWSS3StoragePluginBasicIntegrationTests: AWSS3StoragePluginTestBase { } } - private func assertUserAgentComponents(sdkRequests: [SdkHttpRequest], file: StaticString = #filePath, line: UInt = #line) throws { + private func assertUserAgentComponents(sdkRequests: [HTTPRequest], file: StaticString = #filePath, line: UInt = #line) throws { for request in sdkRequests { let headers = request.headers.dictionary let userAgent = try XCTUnwrap(headers["User-Agent"]?.joined(separator:",")) diff --git a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginGetURLIntegrationTests.swift b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginGetURLIntegrationTests.swift index f1170140f7..92920ae454 100644 --- a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginGetURLIntegrationTests.swift +++ b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginGetURLIntegrationTests.swift @@ -22,11 +22,13 @@ class AWSS3StoragePluginGetURLIntegrationTests: AWSS3StoragePluginTestBase { func testGetRemoteURL() async throws { let key = "public/" + UUID().uuidString try await uploadData(key: key, dataString: key) - _ = try await Amplify.Storage.uploadData( - path: .fromString(key), - data: Data(key.utf8), - options: .init() - ).value + await wait { + _ = try await Amplify.Storage.uploadData( + path: .fromString(key), + data: Data(key.utf8), + options: .init() + ).value + } let remoteURL = try await Amplify.Storage.getURL(path: .fromString(key)) diff --git a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginListObjectsIntegrationTests.swift b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginListObjectsIntegrationTests.swift index fc806ffc91..fbe51b45d4 100644 --- a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginListObjectsIntegrationTests.swift +++ b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginListObjectsIntegrationTests.swift @@ -9,7 +9,7 @@ import AWSS3StoragePlugin import ClientRuntime -import AWSClientRuntime +@_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime import CryptoKit import XCTest import AWSS3 @@ -24,7 +24,9 @@ class AWSS3StoragePluginListObjectsIntegrationTests: AWSS3StoragePluginTestBase let data = Data(key.utf8) let uniqueStringPath = "public/\(key)" - _ = try await Amplify.Storage.uploadData(path: .fromString(uniqueStringPath + "/test1"), data: data, options: nil).value + await wait { + _ = try await Amplify.Storage.uploadData(path: .fromString(uniqueStringPath + "/test1"), data: data, options: nil).value + } let firstListResult = try await Amplify.Storage.list(path: .fromString(uniqueStringPath)) @@ -32,7 +34,9 @@ class AWSS3StoragePluginListObjectsIntegrationTests: AWSS3StoragePluginTestBase XCTAssertEqual(firstListResult.items.filter({ $0.path.contains(uniqueStringPath) }).count, 1) - _ = try await Amplify.Storage.uploadData(path: .fromString(uniqueStringPath + "/test2"), data: data, options: nil).value + await wait { + _ = try await Amplify.Storage.uploadData(path: .fromString(uniqueStringPath + "/test2"), data: data, options: nil).value + } let secondListResult = try await Amplify.Storage.list(path: .fromString(uniqueStringPath)) @@ -56,13 +60,15 @@ class AWSS3StoragePluginListObjectsIntegrationTests: AWSS3StoragePluginTestBase // Sign in _ = try await Amplify.Auth.signIn(username: Self.user1, password: Self.password) - _ = try await Amplify.Storage.uploadData( - path: .fromIdentityID({ identityId in - uniqueStringPath = "protected/\(identityId)/\(key)" - return uniqueStringPath + "test1" - }), - data: data, - options: nil).value + await wait { + _ = try await Amplify.Storage.uploadData( + path: .fromIdentityID({ identityId in + uniqueStringPath = "protected/\(identityId)/\(key)" + return uniqueStringPath + "test1" + }), + data: data, + options: nil).value + } let firstListResult = try await Amplify.Storage.list(path: .fromString(uniqueStringPath)) @@ -70,13 +76,15 @@ class AWSS3StoragePluginListObjectsIntegrationTests: AWSS3StoragePluginTestBase XCTAssertEqual(firstListResult.items.filter({ $0.path.contains(uniqueStringPath) }).count, 1) - _ = try await Amplify.Storage.uploadData( - path: .fromIdentityID({ identityId in - uniqueStringPath = "protected/\(identityId)/\(key)" - return uniqueStringPath + "test2" - }), - data: data, - options: nil).value + await wait { + _ = try await Amplify.Storage.uploadData( + path: .fromIdentityID({ identityId in + uniqueStringPath = "protected/\(identityId)/\(key)" + return uniqueStringPath + "test2" + }), + data: data, + options: nil).value + } let secondListResult = try await Amplify.Storage.list(path: .fromString(uniqueStringPath)) @@ -101,13 +109,15 @@ class AWSS3StoragePluginListObjectsIntegrationTests: AWSS3StoragePluginTestBase // Sign in _ = try await Amplify.Auth.signIn(username: Self.user1, password: Self.password) - _ = try await Amplify.Storage.uploadData( - path: .fromIdentityID({ identityId in - uniqueStringPath = "private/\(identityId)/\(key)" - return uniqueStringPath + "test1" - }), - data: data, - options: nil).value + await wait { + _ = try await Amplify.Storage.uploadData( + path: .fromIdentityID({ identityId in + uniqueStringPath = "private/\(identityId)/\(key)" + return uniqueStringPath + "test1" + }), + data: data, + options: nil).value + } let firstListResult = try await Amplify.Storage.list(path: .fromString(uniqueStringPath)) @@ -115,13 +125,15 @@ class AWSS3StoragePluginListObjectsIntegrationTests: AWSS3StoragePluginTestBase XCTAssertEqual(firstListResult.items.filter({ $0.path.contains(uniqueStringPath) }).count, 1) - _ = try await Amplify.Storage.uploadData( - path: .fromIdentityID({ identityId in - uniqueStringPath = "private/\(identityId)/\(key)" - return uniqueStringPath + "test2" - }), - data: data, - options: nil).value + await wait { + _ = try await Amplify.Storage.uploadData( + path: .fromIdentityID({ identityId in + uniqueStringPath = "private/\(identityId)/\(key)" + return uniqueStringPath + "test2" + }), + data: data, + options: nil).value + } let secondListResult = try await Amplify.Storage.list(path: .fromString(uniqueStringPath)) @@ -198,10 +210,12 @@ class AWSS3StoragePluginListObjectsIntegrationTests: AWSS3StoragePluginTestBase let uniqueStringPath = "public/\(path)" // Upload data - _ = try await Amplify.Storage.uploadData(path: .fromString(uniqueStringPath + "/test1"), data: data, options: nil).value - _ = try await Amplify.Storage.uploadData(path: .fromString(uniqueStringPath + "/test2"), data: data, options: nil).value - _ = try await Amplify.Storage.uploadData(path: .fromString(uniqueStringPath + "/subpath1/test"), data: data, options: nil).value - _ = try await Amplify.Storage.uploadData(path: .fromString(uniqueStringPath + "/subpath2/test"), data: data, options: nil).value + await wait(timeout: 25) { + _ = try await Amplify.Storage.uploadData(path: .fromString(uniqueStringPath + "/test1"), data: data, options: nil).value + _ = try await Amplify.Storage.uploadData(path: .fromString(uniqueStringPath + "/test2"), data: data, options: nil).value + _ = try await Amplify.Storage.uploadData(path: .fromString(uniqueStringPath + "/subpath1/test"), data: data, options: nil).value + _ = try await Amplify.Storage.uploadData(path: .fromString(uniqueStringPath + "/subpath2/test"), data: data, options: nil).value + } let result = try await Amplify.Storage.list( path: .fromString("\(uniqueStringPath)/"), @@ -232,8 +246,10 @@ class AWSS3StoragePluginListObjectsIntegrationTests: AWSS3StoragePluginTestBase let uniqueStringPath = "public/\(path)" // Upload data - _ = try await Amplify.Storage.uploadData(path: .fromString(uniqueStringPath + "-test"), data: data, options: nil).value - _ = try await Amplify.Storage.uploadData(path: .fromString(uniqueStringPath + "-subpath-test"), data: data, options: nil).value + await wait(timeout: 10) { + _ = try await Amplify.Storage.uploadData(path: .fromString(uniqueStringPath + "-test"), data: data, options: nil).value + _ = try await Amplify.Storage.uploadData(path: .fromString(uniqueStringPath + "-subpath-test"), data: data, options: nil).value + } let result = try await Amplify.Storage.list( path: .fromString("\(uniqueStringPath)-"), diff --git a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginProgressTests.swift b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginProgressTests.swift index 40248845d6..06f782131f 100644 --- a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginProgressTests.swift +++ b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginProgressTests.swift @@ -142,7 +142,9 @@ class AWSS3StoragePluginProgressTests: AWSS3StoragePluginTestBase { key: key, data: .testDataOfSize(.bytes(256)) ) - _ = try await task.value + await wait { + _ = try await task.value + } let progress = await task.progress for await current in progress { XCTFail("Not expecting a current progress value but got: \(current)") diff --git a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginRemoveIntegrationTests.swift b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginRemoveIntegrationTests.swift index 561c1504ba..73490fbd09 100644 --- a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginRemoveIntegrationTests.swift +++ b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginRemoveIntegrationTests.swift @@ -9,7 +9,7 @@ import AWSS3StoragePlugin import ClientRuntime -import AWSClientRuntime +@_spi(UnknownAWSHTTPServiceError) import AWSClientRuntime import CryptoKit import XCTest import AWSS3 @@ -24,7 +24,9 @@ class AWSS3StoragePluginRemoveIntegrationTests: AWSS3StoragePluginTestBase { let data = Data(key.utf8) let uniqueStringPath = "public/\(key)" - _ = try await Amplify.Storage.uploadData(path: .fromString(uniqueStringPath), data: data, options: nil).value + await wait { + _ = try await Amplify.Storage.uploadData(path: .fromString(uniqueStringPath), data: data, options: nil).value + } let firstListResult = try await Amplify.Storage.list(path: .fromString(uniqueStringPath)) @@ -52,13 +54,15 @@ class AWSS3StoragePluginRemoveIntegrationTests: AWSS3StoragePluginTestBase { // Sign in _ = try await Amplify.Auth.signIn(username: Self.user1, password: Self.password) - _ = try await Amplify.Storage.uploadData( - path: .fromIdentityID({ identityId in - uniqueStringPath = "protected/\(identityId)/\(key)" - return uniqueStringPath - }), - data: data, - options: nil).value + await wait { + _ = try await Amplify.Storage.uploadData( + path: .fromIdentityID({ identityId in + uniqueStringPath = "protected/\(identityId)/\(key)" + return uniqueStringPath + }), + data: data, + options: nil).value + } let firstListResult = try await Amplify.Storage.list(path: .fromString(uniqueStringPath)) @@ -86,13 +90,15 @@ class AWSS3StoragePluginRemoveIntegrationTests: AWSS3StoragePluginTestBase { // Sign in _ = try await Amplify.Auth.signIn(username: Self.user1, password: Self.password) - _ = try await Amplify.Storage.uploadData( - path: .fromIdentityID({ identityId in - uniqueStringPath = "private/\(identityId)/\(key)" - return uniqueStringPath - }), - data: data, - options: nil).value + await wait { + _ = try await Amplify.Storage.uploadData( + path: .fromIdentityID({ identityId in + uniqueStringPath = "private/\(identityId)/\(key)" + return uniqueStringPath + }), + data: data, + options: nil).value + } let firstListResult = try await Amplify.Storage.list(path: .fromString(uniqueStringPath)) diff --git a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginRequestRecorder.swift b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginRequestRecorder.swift index 973dead62d..35bae2cc66 100644 --- a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginRequestRecorder.swift +++ b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginRequestRecorder.swift @@ -7,19 +7,20 @@ @testable import AWSS3StoragePlugin -import ClientRuntime import Foundation +import Smithy +import SmithyHTTPAPI class AWSS3StoragePluginRequestRecorder { var target: HTTPClient? = nil - var sdkRequests: [SdkHttpRequest] = [] + var sdkRequests: [HTTPRequest] = [] var urlRequests: [URLRequest] = [] init() { } } extension AWSS3StoragePluginRequestRecorder: HttpClientEngineProxy { - func send(request: SdkHttpRequest) async throws -> HttpResponse { + func send(request: HTTPRequest) async throws -> HTTPResponse { guard let target = target else { throw ClientError.unknownError("HttpClientEngine is not set") } diff --git a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginTestBase.swift b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginTestBase.swift index fde9054957..0ffd3e0930 100644 --- a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginTestBase.swift +++ b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginTestBase.swift @@ -218,6 +218,20 @@ class AWSS3StoragePluginTestBase: XCTestCase { } } + func wait(timeout: TimeInterval = 10, closure: @escaping () async throws -> ()) async { + let expectation = expectation(description: "Tasks completed") + Task { + defer { expectation.fulfill() } + do { + try await closure() + } catch { + XCTFail("Unexpected error: \(error)") + } + } + + await fulfillment(of: [expectation], timeout: timeout) + } + private func invalidateCurrentSession() { Self.logger.debug("Invalidating URLSession") guard let plugin = try? Amplify.Storage.getPlugin(for: "awsS3StoragePlugin") as? AWSS3StoragePlugin else { diff --git a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginUploadIntegrationTests.swift b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginUploadIntegrationTests.swift index 565bee8746..1168226a6a 100644 --- a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginUploadIntegrationTests.swift +++ b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginUploadIntegrationTests.swift @@ -8,7 +8,7 @@ @testable import Amplify import AWSS3StoragePlugin -import ClientRuntime +import SmithyHTTPAPI import CryptoKit import XCTest @@ -63,7 +63,9 @@ class AWSS3StoragePluginUploadIntegrationTests: AWSS3StoragePluginTestBase { let key = UUID().uuidString let data = Data(key.utf8) - _ = try await Amplify.Storage.uploadData(path: .fromString("public/\(key)"), data: data, options: nil).value + await wait { + _ = try await Amplify.Storage.uploadData(path: .fromString("public/\(key)"), data: data, options: nil).value + } _ = try await Amplify.Storage.remove(path: .fromString("public/\(key)")) // Only the remove operation results in an SDK request @@ -80,7 +82,9 @@ class AWSS3StoragePluginUploadIntegrationTests: AWSS3StoragePluginTestBase { func testUploadEmptyData() async throws { let key = UUID().uuidString let data = Data("".utf8) - _ = try await Amplify.Storage.uploadData(path: .fromString("public/\(key)"), data: data, options: nil).value + await wait { + _ = try await Amplify.Storage.uploadData(path: .fromString("public/\(key)"), data: data, options: nil).value + } _ = try await Amplify.Storage.remove(path: .fromString("public/\(key)")) XCTAssertEqual(requestRecorder.urlRequests.map { $0.httpMethod }, ["PUT"]) @@ -97,7 +101,9 @@ class AWSS3StoragePluginUploadIntegrationTests: AWSS3StoragePluginTestBase { let fileURL = URL(fileURLWithPath: filePath) FileManager.default.createFile(atPath: filePath, contents: Data(key.utf8), attributes: nil) - _ = try await Amplify.Storage.uploadFile(path: .fromString("public/\(key)"), local: fileURL, options: nil).value + await wait { + _ = try await Amplify.Storage.uploadFile(path: .fromString("public/\(key)"), local: fileURL, options: nil).value + } _ = try await Amplify.Storage.remove(path: .fromString("public/\(key)")) // Only the remove operation results in an SDK request @@ -117,7 +123,9 @@ class AWSS3StoragePluginUploadIntegrationTests: AWSS3StoragePluginTestBase { let fileURL = URL(fileURLWithPath: filePath) FileManager.default.createFile(atPath: filePath, contents: Data("".utf8), attributes: nil) - _ = try await Amplify.Storage.uploadFile(path: .fromString("public/\(key)"), local: fileURL, options: nil).value + await wait { + _ = try await Amplify.Storage.uploadFile(path: .fromString("public/\(key)"), local: fileURL, options: nil).value + } _ = try await Amplify.Storage.remove(path: .fromString("public/\(key)")) XCTAssertEqual(requestRecorder.urlRequests.map { $0.httpMethod }, ["PUT"]) @@ -130,10 +138,12 @@ class AWSS3StoragePluginUploadIntegrationTests: AWSS3StoragePluginTestBase { func testUploadLargeData() async throws { let key = "public/" + UUID().uuidString - let uploadKey = try await Amplify.Storage.uploadData(path: .fromString(key), - data: AWSS3StoragePluginTestBase.largeDataObject, - options: nil).value - XCTAssertEqual(uploadKey, key) + await wait(timeout: 60) { + let uploadKey = try await Amplify.Storage.uploadData(path: .fromString(key), + data: AWSS3StoragePluginTestBase.largeDataObject, + options: nil).value + XCTAssertEqual(uploadKey, key) + } try await Amplify.Storage.remove(path: .fromString(key)) @@ -157,7 +167,9 @@ class AWSS3StoragePluginUploadIntegrationTests: AWSS3StoragePluginTestBase { contents: AWSS3StoragePluginTestBase.largeDataObject, attributes: nil) - _ = try await Amplify.Storage.uploadFile(path: .fromString("public/\(key)"), local: fileURL, options: nil).value + await wait(timeout: 60) { + _ = try await Amplify.Storage.uploadFile(path: .fromString("public/\(key)"), local: fileURL, options: nil).value + } _ = try await Amplify.Storage.remove(path: .fromString("public/\(key)")) let userAgents = requestRecorder.urlRequests.compactMap { $0.allHTTPHeaderFields?["User-Agent"] } @@ -179,7 +191,7 @@ class AWSS3StoragePluginUploadIntegrationTests: AWSS3StoragePluginTestBase { } } - private func assertUserAgentComponents(sdkRequests: [SdkHttpRequest], file: StaticString = #filePath, line: UInt = #line) throws { + private func assertUserAgentComponents(sdkRequests: [HTTPRequest], file: StaticString = #filePath, line: UInt = #line) throws { for request in sdkRequests { let headers = request.headers.dictionary let userAgent = try XCTUnwrap(headers["User-Agent"]?.joined(separator:",")) diff --git a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginUploadMetadataTestCase.swift b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginUploadMetadataTestCase.swift index 92d6ec8a7a..e178ef9b0f 100644 --- a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginUploadMetadataTestCase.swift +++ b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginUploadMetadataTestCase.swift @@ -27,11 +27,13 @@ class AWSS3StoragePluginUploadMetadataTestCase: AWSS3StoragePluginTestBase { // upload file let key = UUID().uuidString let fileURL = temporaryFile(named: key, data: data(mb: 1)) - _ = try await Amplify.Storage.uploadFile( - key: key, - local: fileURL, - options: options - ).value + await wait { + _ = try await Amplify.Storage.uploadFile( + key: key, + local: fileURL, + options: options + ).value + } // call `HeadObject` through SDK escape hatch let head = try await headObject(key: "public/\(key)") @@ -65,11 +67,13 @@ class AWSS3StoragePluginUploadMetadataTestCase: AWSS3StoragePluginTestBase { // upload file let key = UUID().uuidString let fileURL = temporaryFile(named: key, data: data(mb: 7)) - _ = try await Amplify.Storage.uploadFile( - key: key, - local: fileURL, - options: options - ).value + await wait(timeout: 60) { + _ = try await Amplify.Storage.uploadFile( + key: key, + local: fileURL, + options: options + ).value + } // call `HeadObject` through SDK escape hatch let head = try await headObject(key: "public/\(key)") @@ -102,11 +106,13 @@ class AWSS3StoragePluginUploadMetadataTestCase: AWSS3StoragePluginTestBase { // upload file let key = UUID().uuidString - _ = try await Amplify.Storage.uploadData( - key: key, - data: data(mb: 1), - options: options - ).value + await wait { + _ = try await Amplify.Storage.uploadData( + key: key, + data: self.data(mb: 1), + options: options + ).value + } // call `HeadObject` through SDK escape hatch let head = try await headObject(key: "public/\(key)") @@ -139,11 +145,13 @@ class AWSS3StoragePluginUploadMetadataTestCase: AWSS3StoragePluginTestBase { // upload file let key = UUID().uuidString - _ = try await Amplify.Storage.uploadData( - key: key, - data: data(mb: 7), - options: options - ).value + await wait(timeout: 60) { + _ = try await Amplify.Storage.uploadData( + key: key, + data: self.data(mb: 7), + options: options + ).value + } // call `HeadObject` through SDK escape hatch let head = try await headObject(key: "public/\(key)") @@ -187,11 +195,13 @@ class AWSS3StoragePluginUploadMetadataTestCase: AWSS3StoragePluginTestBase { // upload file let key = UUID().uuidString - _ = try await Amplify.Storage.uploadData( - key: key, - data: data(mb: 1), - options: options - ).value + await wait { + _ = try await Amplify.Storage.uploadData( + key: key, + data: self.data(mb: 1), + options: options + ).value + } // call `HeadObject` through SDK escape hatch let head = try await headObject(key: "public/\(key)") diff --git a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/ResumabilityTests/AWSS3StoragePluginGetDataResumabilityTests.swift b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/ResumabilityTests/AWSS3StoragePluginGetDataResumabilityTests.swift index 40f9e863b9..d1ceae0fcd 100644 --- a/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/ResumabilityTests/AWSS3StoragePluginGetDataResumabilityTests.swift +++ b/AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/ResumabilityTests/AWSS3StoragePluginGetDataResumabilityTests.swift @@ -20,8 +20,11 @@ class AWSS3StoragePluginDownloadDataResumabilityTests: AWSS3StoragePluginTestBas func testDownloadDataAndPause() async throws { let key = UUID().uuidString let data = AWSS3StoragePluginTestBase.smallDataObject - let uploadKey = try await Amplify.Storage.uploadData(key: key, data: data).value - XCTAssertEqual(uploadKey, key) + + await wait { + let uploadKey = try await Amplify.Storage.uploadData(key: key, data: data).value + XCTAssertEqual(uploadKey, key) + } Self.logger.debug("Downloading data") let task = Amplify.Storage.downloadData(key: key) @@ -75,8 +78,11 @@ class AWSS3StoragePluginDownloadDataResumabilityTests: AWSS3StoragePluginTestBas func testDownloadDataAndPauseThenResume() async throws { let key = UUID().uuidString let data = AWSS3StoragePluginTestBase.smallDataObject - let uploadKey = try await Amplify.Storage.uploadData(key: key, data: data).value - XCTAssertEqual(uploadKey, key) + + await wait { + let uploadKey = try await Amplify.Storage.uploadData(key: key, data: data).value + XCTAssertEqual(uploadKey, key) + } let task = Amplify.Storage.downloadData(key: key) @@ -126,8 +132,11 @@ class AWSS3StoragePluginDownloadDataResumabilityTests: AWSS3StoragePluginTestBas func testDownloadDataAndCancel() async throws { let key = UUID().uuidString let data = AWSS3StoragePluginTestBase.smallDataObject - let uploadKey = try await Amplify.Storage.uploadData(key: key, data: data).value - XCTAssertEqual(uploadKey, key) + + await wait { + let uploadKey = try await Amplify.Storage.uploadData(key: key, data: data).value + XCTAssertEqual(uploadKey, key) + } Self.logger.debug("Downloading data") let task = Amplify.Storage.downloadData(key: key) diff --git a/AmplifyTestCommon/Mocks/MockCredentialsProvider.swift b/AmplifyTestCommon/Mocks/MockCredentialsProvider.swift index 5b4f232074..aba5185d25 100644 --- a/AmplifyTestCommon/Mocks/MockCredentialsProvider.swift +++ b/AmplifyTestCommon/Mocks/MockCredentialsProvider.swift @@ -6,15 +6,16 @@ // import AWSPluginsCore -import AWSClientRuntime +import AwsCommonRuntimeKit import Foundation +import SmithyIdentity -class MockCredentialsProvider: AWSClientRuntime.CredentialsProviding { - func getCredentials() async throws -> AWSClientRuntime.AWSCredentials { - return AWSCredentials( +class MockCredentialsProvider: AwsCommonRuntimeKit.CredentialsProviding, AWSCredentialIdentityResolver { + func getCredentials() async throws -> AwsCommonRuntimeKit.Credentials { + return try Credentials( accessKey: "accessKey", secret: "secret", - expirationTimeout: Date().addingTimeInterval(1000) + expiration: Date().addingTimeInterval(1000) ) } } diff --git a/Package.resolved b/Package.resolved index 36c02fdfea..7ba77b8a62 100644 --- a/Package.resolved +++ b/Package.resolved @@ -14,8 +14,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/awslabs/aws-crt-swift", "state" : { - "revision" : "0d0a0cf2e2cb780ceeceac190b4ede94f4f96902", - "version" : "0.26.0" + "revision" : "7b42e0343f28b3451aab20840dc670abd12790bd", + "version" : "0.36.0" } }, { @@ -23,8 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/awslabs/aws-sdk-swift.git", "state" : { - "revision" : "47922c05dd66be717c7bce424651a534456717b7", - "version" : "0.36.2" + "revision" : "828358a2c39d138325b0f87a2d813f4b972e5f4f", + "version" : "1.0.0" } }, { @@ -50,8 +50,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/smithy-lang/smithy-swift", "state" : { - "revision" : "8a5b0105c1b8a1d26a9435fb0af3959a7f5de578", - "version" : "0.41.1" + "revision" : "0ed3440f8c41e27a0937364d5035d2d4fefb8aa3", + "version" : "0.71.0" } }, { diff --git a/Package.swift b/Package.swift index 3a679faade..d0e70eda38 100644 --- a/Package.swift +++ b/Package.swift @@ -9,7 +9,7 @@ let platforms: [SupportedPlatform] = [ .watchOS(.v9) ] let dependencies: [Package.Dependency] = [ - .package(url: "https://github.com/awslabs/aws-sdk-swift.git", exact: "0.36.2"), + .package(url: "https://github.com/awslabs/aws-sdk-swift.git", exact: "1.0.0"), .package(url: "https://github.com/stephencelis/SQLite.swift.git", exact: "0.15.3"), .package(url: "https://github.com/mattgallagher/CwlPreconditionTesting.git", from: "2.1.0"), .package(url: "https://github.com/aws-amplify/amplify-swift-utils-notifications.git", from: "1.1.0")