Skip to content

Commit e2e5b33

Browse files
authored
chore: kickoff release
2 parents b955a71 + 50e001f commit e2e5b33

File tree

7 files changed

+203
-7
lines changed

7 files changed

+203
-7
lines changed

AmplifyPlugins/API/Sources/AWSAPIPlugin/Operation/AWSGraphQLSubscriptionTaskRunner.swift

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,31 @@ fileprivate func toAPIError<R: Decodable>(_ errors: [Error], type: R.Type) -> AP
378378
(hasAuthorizationError ? ": \(APIError.UnauthorizedMessageString)" : "")
379379
}
380380

381+
#if swift(<5.8)
382+
if let errors = errors.cast(to: AppSyncRealTimeRequest.Error.self) {
383+
let hasAuthorizationError = errors.contains(where: { $0 == .unauthorized})
384+
return APIError.operationError(
385+
errorDescription(hasAuthorizationError),
386+
"",
387+
errors.first
388+
)
389+
} else if let errors = errors.cast(to: GraphQLError.self) {
390+
let hasAuthorizationError = errors.map(\.extensions)
391+
.compactMap { $0.flatMap { $0["errorType"]?.stringValue } }
392+
.contains(where: { AppSyncErrorType($0) == .unauthorized })
393+
return APIError.operationError(
394+
errorDescription(hasAuthorizationError),
395+
"",
396+
GraphQLResponseError<R>.error(errors)
397+
)
398+
} else {
399+
return APIError.operationError(
400+
errorDescription(),
401+
"",
402+
errors.first
403+
)
404+
}
405+
#else
381406
switch errors {
382407
case let errors as [AppSyncRealTimeRequest.Error]:
383408
let hasAuthorizationError = errors.contains(where: { $0 == .unauthorized})
@@ -402,5 +427,5 @@ fileprivate func toAPIError<R: Decodable>(_ errors: [Error], type: R.Type) -> AP
402427
errors.first
403428
)
404429
}
405-
430+
#endif
406431
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//
2+
// Copyright Amazon.com Inc. or its affiliates.
3+
// All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
9+
import Foundation
10+
11+
@_spi(AmplifyAPI)
12+
extension Array where Element == Error {
13+
func cast<T>(to type: T.Type) -> [T]? {
14+
self.reduce([]) { partialResult, ele in
15+
if let partialResult, let ele = ele as? T {
16+
return partialResult + [ele]
17+
}
18+
return nil
19+
}
20+
}
21+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//
2+
// Copyright Amazon.com Inc. or its affiliates.
3+
// All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
9+
import XCTest
10+
@testable @_spi(AmplifyAPI) import AWSAPIPlugin
11+
12+
class ArrayWithErrorElementExtensionTests: XCTestCase {
13+
14+
/**
15+
Given: errors with generic protocol type
16+
When: cast to the correct underlying concrete type
17+
Then: successfully casted to underlying concrete type
18+
*/
19+
func testCast_toCorrectErrorType_returnCastedErrorType() {
20+
let errors: [Error] = [
21+
Error1(), Error1(), Error1()
22+
]
23+
24+
let error1s = errors.cast(to: Error1.self)
25+
XCTAssertNotNil(error1s)
26+
XCTAssertTrue(!error1s!.isEmpty)
27+
XCTAssertEqual(errors.count, error1s!.count)
28+
}
29+
30+
/**
31+
Given: errors with generic protocol type
32+
When: cast to the wong underlying concrete type
33+
Then: return nil
34+
*/
35+
func testCast_toWrongErrorType_returnNil() {
36+
let errors: [Error] = [
37+
Error1(), Error1(), Error1()
38+
]
39+
40+
let error2s = errors.cast(to: Error2.self)
41+
XCTAssertNil(error2s)
42+
}
43+
44+
/**
45+
Given: errors with generic protocol type
46+
When: some of the elements failed to cast to the underlying concrete type
47+
Then: return nil
48+
*/
49+
50+
func testCast_partiallyToWrongErrorType_returnNil() {
51+
let errors: [Error] = [
52+
Error2(), Error2(), Error1()
53+
]
54+
55+
let error2s = errors.cast(to: Error2.self)
56+
XCTAssertNil(error2s)
57+
}
58+
59+
struct Error1: Error { }
60+
61+
struct Error2: Error { }
62+
}

AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Operations/Helpers/FetchAuthSessionOperationHelper.swift

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,13 +157,21 @@ class FetchAuthSessionOperationHelper: DefaultLogger {
157157
}
158158

159159
case .service(let error):
160-
if let authError = (error as? AuthErrorConvertible)?.authError {
161-
let session = AWSAuthCognitoSession(isSignedIn: isSignedIn,
162-
identityIdResult: .failure(authError),
163-
awsCredentialsResult: .failure(authError),
164-
cognitoTokensResult: .failure(authError))
165-
return session
160+
var authError: AuthError
161+
if let convertedAuthError = (error as? AuthErrorConvertible)?.authError {
162+
authError = convertedAuthError
163+
} else {
164+
authError = AuthError.service(
165+
"Unknown service error occurred",
166+
"See the attached error for more details",
167+
error)
166168
}
169+
let session = AWSAuthCognitoSession(
170+
isSignedIn: isSignedIn,
171+
identityIdResult: .failure(authError),
172+
awsCredentialsResult: .failure(authError),
173+
cognitoTokensResult: .failure(authError))
174+
return session
167175
default: break
168176

169177
}

AmplifyPlugins/Auth/Tests/AWSCognitoAuthPluginUnitTests/TaskTests/AuthorizationTests/AWSAuthFetchSignInSessionOperationTests.swift

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,4 +736,61 @@ class AWSAuthFetchSignInSessionOperationTests: BaseAuthorizationTests {
736736
let identityId = try? (session as? AuthCognitoIdentityProvider)?.getIdentityId().get()
737737
XCTAssertNotNil(identityId)
738738
}
739+
740+
/// Test signedIn session with invalid response for aws credentials
741+
///
742+
/// - Given: Given an auth plugin with signedIn state
743+
/// - When:
744+
/// - I invoke fetchAuthSession and service throws NSError
745+
/// - Then:
746+
/// - I should get an a valid session with the following details:
747+
/// - isSignedIn = true
748+
/// - aws credentails = service error
749+
/// - identity id = service error
750+
/// - cognito tokens = service error
751+
///
752+
func testSignInSessionWithNSError() async throws {
753+
let initialState = AuthState.configured(
754+
AuthenticationState.signedIn(.testData),
755+
AuthorizationState.sessionEstablished(
756+
AmplifyCredentials.testDataWithExpiredTokens))
757+
758+
let initAuth: MockIdentityProvider.MockInitiateAuthResponse = { _ in
759+
return InitiateAuthOutput(authenticationResult: .init(accessToken: "accessToken",
760+
expiresIn: 1000,
761+
idToken: "idToken",
762+
refreshToken: "refreshToke"))
763+
}
764+
765+
let awsCredentials: MockIdentity.MockGetCredentialsResponse = { _ in
766+
throw NSError(domain: NSURLErrorDomain, code: 1, userInfo: nil)
767+
}
768+
let plugin = configurePluginWith(
769+
userPool: { MockIdentityProvider(mockInitiateAuthResponse: initAuth) },
770+
identityPool: { MockIdentity(mockGetCredentialsResponse: awsCredentials) },
771+
initialState: initialState)
772+
773+
let session = try await plugin.fetchAuthSession(options: AuthFetchSessionRequest.Options())
774+
775+
XCTAssertTrue(session.isSignedIn)
776+
let credentialsResult = (session as? AuthAWSCredentialsProvider)?.getAWSCredentials()
777+
guard case .failure(let error) = credentialsResult, case .service = error else {
778+
XCTFail("Should return service error")
779+
return
780+
}
781+
782+
let identityIdResult = (session as? AuthCognitoIdentityProvider)?.getIdentityId()
783+
guard case .failure(let identityIdError) = identityIdResult,
784+
case .service = identityIdError else {
785+
XCTFail("Should return service error")
786+
return
787+
}
788+
789+
let tokensResult = (session as? AuthCognitoTokensProvider)?.getCognitoTokens()
790+
guard case .failure(let tokenError) = tokensResult,
791+
case .service = tokenError else {
792+
XCTFail("Should return service error")
793+
return
794+
}
795+
}
739796
}

AmplifyPlugins/DataStore/Sources/AWSDataStorePlugin/Storage/StorageEngine.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ final class StorageEngine: StorageEngineBehavior {
206206
"Cannot apply a condition on model which does not exist.",
207207
"Save the model instance without a condition first.")
208208
completion(.failure(causedBy: dataStoreError))
209+
return
209210
}
210211

211212
do {

AmplifyPlugins/DataStore/Tests/AWSDataStorePluginTests/Storage/StorageEngineTestsHasOne.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,28 @@ class StorageEngineTestsHasOne: StorageEngineTestsBase {
7070
}
7171
}
7272

73+
/// Given: A model that does not exist
74+
/// When: save is called with a predicate
75+
/// Then: A DataStoreError.invalidCondition error is returned
76+
func testSaveModelWithPredicate_shouldFail() {
77+
let team = Team(name: "Team")
78+
let saveFinished = expectation(description: "Save finished")
79+
storageEngine.save(team, condition: Team.keys.name.beginsWith("T")) { result in
80+
defer {
81+
saveFinished.fulfill()
82+
}
83+
guard case .failure(let error) = result,
84+
case . invalidCondition(let errorDescription, let recoverySuggestion, _) = error else {
85+
XCTFail("Expected failure with .invalidCondition, got \(result)")
86+
return
87+
}
88+
89+
XCTAssertEqual(errorDescription, "Cannot apply a condition on model which does not exist.")
90+
XCTAssertEqual(recoverySuggestion, "Save the model instance without a condition first.")
91+
}
92+
wait(for: [saveFinished], timeout: defaultTimeout)
93+
}
94+
7395
func testBelongsToRelationshipWithoutOwner() {
7496
let teamA = Team(name: "A-Team")
7597
let projectA = Project(name: "ProjectA", team: teamA)

0 commit comments

Comments
 (0)