Skip to content

Commit 94c7ed6

Browse files
committedFeb 1, 2023
chore(Storage): Simplify Storage.getURL
1 parent f7d9cc1 commit 94c7ed6

17 files changed

+325
-357
lines changed
 

‎AmplifyPlugins/Core/AWSPluginsTestCommon/MockAWSAuthService.swift

+7
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import AWSPluginsCore
1212

1313
public class MockAWSAuthService: AWSAuthServiceBehavior {
1414

15+
var interactions: [String] = []
1516
var getIdentityIdError: AuthError?
1617
var getTokenError: AuthError?
1718
var getTokenClaimsError: AuthError?
@@ -20,17 +21,21 @@ public class MockAWSAuthService: AWSAuthServiceBehavior {
2021
var tokenClaims: [String: AnyObject]?
2122

2223
public func configure() {
24+
interactions.append(#function)
2325
}
2426

2527
public func reset() {
28+
interactions.append(#function)
2629
}
2730

2831
public func getCredentialsProvider() -> CredentialsProvider {
32+
interactions.append(#function)
2933
let cognitoCredentialsProvider = MyCustomCredentialsProvider()
3034
return cognitoCredentialsProvider
3135
}
3236

3337
public func getIdentityID() async throws -> String {
38+
interactions.append(#function)
3439
if let error = getIdentityIdError {
3540
throw error
3641
}
@@ -39,6 +44,7 @@ public class MockAWSAuthService: AWSAuthServiceBehavior {
3944
}
4045

4146
public func getUserPoolAccessToken() async throws -> String {
47+
interactions.append(#function)
4248
if let error = getTokenError {
4349
throw error
4450
} else {
@@ -47,6 +53,7 @@ public class MockAWSAuthService: AWSAuthServiceBehavior {
4753
}
4854

4955
public func getTokenClaims(tokenString: String) -> Result<[String: AnyObject], AuthError> {
56+
interactions.append(#function)
5057
if let error = getTokenClaimsError {
5158
return .failure(error)
5259
}

‎AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/AWSS3StoragePlugin+AsyncClientBehavior.swift

+15-8
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,21 @@ extension AWSS3StoragePlugin {
2020
) async throws -> URL {
2121
let options = options ?? StorageGetURLRequest.Options()
2222
let request = StorageGetURLRequest(key: key, options: options)
23-
let operation = AWSS3StorageGetURLOperation(request,
24-
storageConfiguration: storageConfiguration,
25-
storageService: storageService,
26-
authService: authService)
27-
let taskAdapter = AmplifyOperationTaskAdapter(operation: operation)
28-
queue.addOperation(operation)
29-
30-
return try await taskAdapter.value
23+
if let error = request.validate() {
24+
throw error
25+
}
26+
let prefixResolver = storageConfiguration.prefixResolver ?? StorageAccessLevelAwarePrefixResolver(authService: authService)
27+
let prefix = try await prefixResolver.resolvePrefix(for: options.accessLevel,
28+
targetIdentityId: options.targetIdentityId)
29+
let serviceKey = prefix + request.key
30+
let result = try await storageService.getPreSignedURL(serviceKey: serviceKey,
31+
signingOperation: .getObject,
32+
expires: options.expires)
33+
34+
let channel = HubChannel(from: categoryType)
35+
let payload = HubPayload(eventName: HubPayload.EventName.Storage.getURL, context: options, data: result)
36+
Amplify.Hub.dispatch(to: channel, payload: payload)
37+
return result
3138
}
3239

3340
@discardableResult

‎AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/AWSS3PreSignedURLBuilderBehavior.swift

-12
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,3 @@ protocol AWSS3PreSignedURLBuilderBehavior {
2323
/// - Returns: Pre-Signed URL
2424
func getPreSignedURL(key: String, signingOperation: AWSS3SigningOperation, expires: Int64?) async throws -> URL
2525
}
26-
27-
extension AWSS3PreSignedURLBuilderBehavior {
28-
29-
func getPreSignedURL(key: String, signingOperation: AWSS3SigningOperation, expires: Int64? = nil) async throws -> URL {
30-
try await getPreSignedURL(key: key, signingOperation: signingOperation, expires: expires)
31-
}
32-
33-
func getPreSignedURL(key: String, expires: Int64? = nil) async throws -> URL {
34-
try await getPreSignedURL(key: key, signingOperation: .getObject, expires: expires)
35-
}
36-
37-
}

‎AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Operation/AWSS3StorageGetURLOperation.swift

-99
This file was deleted.

‎AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+DownloadBehavior.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ extension AWSS3StorageService {
2727

2828
Task {
2929
do {
30-
let preSignedURL = try await preSignedURLBuilder.getPreSignedURL(key: serviceKey)
30+
let preSignedURL = try await preSignedURLBuilder.getPreSignedURL(key: serviceKey, signingOperation: .getObject, expires: nil)
3131
startDownload(preSignedURL: preSignedURL, transferTask: transferTask)
3232
} catch {
3333
onEvent(.failed(StorageError.unknown("Failed to get pre-signed URL", nil)))

‎AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+GetPreSignedURLBehavior.swift

+3-11
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,8 @@ import Amplify
1111
extension AWSS3StorageService {
1212

1313
func getPreSignedURL(serviceKey: String,
14-
signingOperation: AWSS3SigningOperation = .getObject,
15-
expires: Int,
16-
onEvent: @escaping StorageServiceGetPreSignedURLEventHandler) {
17-
Task {
18-
do {
19-
onEvent(.completed(try await preSignedURLBuilder.getPreSignedURL(key: serviceKey,
20-
expires: Int64(expires))))
21-
} catch {
22-
onEvent(.failed(StorageError.unknown("Failed to get pre-signed URL", nil)))
23-
}
24-
}
14+
signingOperation: AWSS3SigningOperation,
15+
expires: Int) async throws -> URL {
16+
return try await preSignedURLBuilder.getPreSignedURL(key: serviceKey, signingOperation: signingOperation, expires: Int64(expires))
2517
}
2618
}

‎AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+UploadBehavior.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ extension AWSS3StorageService {
3434

3535
do {
3636
let preSignedURL = try await preSignedURLBuilder.getPreSignedURL(key: serviceKey,
37-
signingOperation: .putObject)
37+
signingOperation: .putObject,
38+
expires: nil)
3839
startUpload(preSignedURL: preSignedURL,
3940
fileURL: uploadFileURL,
4041
contentType: contentType,

‎AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageServiceBehaviour.swift

+1-10
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,7 @@ protocol AWSS3StorageServiceBehaviour {
4343

4444
func getPreSignedURL(serviceKey: String,
4545
signingOperation: AWSS3SigningOperation,
46-
expires: Int,
47-
onEvent: @escaping StorageServiceGetPreSignedURLEventHandler)
46+
expires: Int) async throws -> URL
4847

4948
func upload(serviceKey: String,
5049
uploadSource: UploadSource,
@@ -64,11 +63,3 @@ protocol AWSS3StorageServiceBehaviour {
6463
func delete(serviceKey: String,
6564
onEvent: @escaping StorageServiceDeleteEventHandler)
6665
}
67-
68-
extension AWSS3StorageServiceBehaviour {
69-
func getPreSignedURL(serviceKey: String,
70-
expires: Int,
71-
onEvent: @escaping StorageServiceGetPreSignedURLEventHandler) {
72-
getPreSignedURL(serviceKey: serviceKey, signingOperation: .getObject, expires: expires, onEvent: onEvent)
73-
}
74-
}

‎AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageMultipartUploadClient.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ class DefaultStorageMultipartUploadClient: StorageMultipartUploadClient {
128128
let operation = AWSS3SigningOperation.uploadPart(partNumber: partNumber, uploadId: uploadId)
129129
let preSignedURL = try await serviceProxy.preSignedURLBuilder.getPreSignedURL(
130130
key: self.key,
131-
signingOperation: operation
131+
signingOperation: operation,
132+
expires: nil
132133
)
133134
startUploadPart(partialFileURL, preSignedURL)
134135
} catch {

‎AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/AWSS3StoragePluginAsyncBehaviorTests.swift

-15
Original file line numberDiff line numberDiff line change
@@ -47,21 +47,6 @@ class AWSS3StoragePluginAsyncBehaviorTests: XCTestCase {
4747
queue = nil
4848
}
4949

50-
func testPluginGetURLAsync() async throws {
51-
let done = asyncExpectation(description: "done")
52-
let input = URL(string: "https://bucket.aws.amazon.com/\(testKey ?? "")")!
53-
54-
Task {
55-
storageService.storageServiceGetPreSignedURLEvents = [.completed(input)]
56-
let output = try await storagePlugin.getURL(key: testKey, options: nil)
57-
XCTAssertEqual(input, output)
58-
XCTAssertEqual(1, storageService.getPreSignedURLCalled)
59-
await done.fulfill()
60-
}
61-
62-
await waitForExpectations([done], timeout: 3.0)
63-
}
64-
6550
func testPluginDownloadDataAsync() async throws {
6651
let input = "AWS".data(using: .utf8)!
6752
storageService.storageServiceDownloadEvents = [.completed(input)]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
////
2+
// Copyright Amazon.com Inc. or its affiliates.
3+
// All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
@testable import AWSS3StoragePlugin
9+
@testable import AmplifyTestCommon
10+
@testable import AWSPluginsTestCommon
11+
12+
import Amplify
13+
import XCTest
14+
15+
final class AWSS3StoragePluginGetPresignedUrlTests: XCTestCase {
16+
17+
var systemUnderTest: AWSS3StoragePlugin!
18+
var storageService: MockAWSS3StorageService!
19+
var authService: MockAWSAuthService!
20+
var testKey: String!
21+
var testURL: URL!
22+
var testData: Data!
23+
var queue: OperationQueue!
24+
25+
let defaultAccessLevel: StorageAccessLevel = .guest
26+
27+
override func setUpWithError() throws {
28+
storageService = MockAWSS3StorageService()
29+
authService = MockAWSAuthService()
30+
testKey = UUID().uuidString
31+
testURL = URL(fileURLWithPath: NSTemporaryDirectory().appendingPathComponent(UUID().uuidString))
32+
testData = Data(UUID().uuidString.utf8)
33+
queue = OperationQueue()
34+
systemUnderTest = AWSS3StoragePlugin()
35+
systemUnderTest.configure(storageService: storageService,
36+
authService: authService,
37+
defaultAccessLevel: defaultAccessLevel,
38+
queue: queue)
39+
let url = try XCTUnwrap(testURL)
40+
storageService.getPreSignedURLHandler = { (_, _, _) in
41+
return url
42+
}
43+
}
44+
45+
override func tearDownWithError() throws {
46+
queue.cancelAllOperations()
47+
48+
storageService = nil
49+
authService = nil
50+
testKey = nil
51+
testURL = nil
52+
testData = nil
53+
queue = nil
54+
systemUnderTest = nil
55+
}
56+
57+
/// - Given: A valid object key
58+
/// - When: An attempt to generate a pre-signed URL for it is performed
59+
/// - Then: The underlying auth service and storage services are used to build it
60+
func testPluginGetURLAsync() async throws {
61+
let output = try await systemUnderTest.getURL(key: testKey, options: nil)
62+
XCTAssertEqual(testURL, output)
63+
XCTAssertEqual(authService.interactions, [
64+
"getIdentityID()"
65+
])
66+
let expectedServiceKey = "public/" + testKey
67+
XCTAssertEqual(storageService.interactions, [
68+
"getPreSignedURL(serviceKey:signingOperation:expires:) \(expectedServiceKey) getObject 18000"
69+
])
70+
}
71+
72+
/// - Given: An empty string as an object key
73+
/// - When: An attempt to generate a pre-signed URL for it is performed
74+
/// - Then: A StorageError.validation is thrown
75+
func testGetURLOperationValidationError() async throws {
76+
let options = StorageGetURLRequest.Options(expires: 0)
77+
do {
78+
_ = try await systemUnderTest.getURL(key: "", options: options)
79+
XCTFail("Expecting error")
80+
} catch StorageError.validation(let field, let description, let recovery, _){
81+
XCTAssertEqual(field, "key")
82+
XCTAssertEqual(recovery, "Specify a non-empty key.")
83+
XCTAssertEqual(description, "The `key` is specified but is empty.")
84+
}
85+
}
86+
87+
/// - Given: An auth service in an invalid state
88+
/// - When: An attempt to generate a pre-signed URL is performed
89+
/// - Then: A StorageError.authError is thrown
90+
func testGetURLOperationGetIdentityIdError() async throws {
91+
let authError = AuthError.service(UUID().uuidString, UUID().uuidString, UUID().uuidString)
92+
authService.getIdentityIdError = authError
93+
let testExpires = Int(Date.distantFuture.timeIntervalSince1970)
94+
let options = StorageGetURLRequest.Options(expires: testExpires)
95+
96+
do {
97+
_ = try await systemUnderTest.getURL(key: testKey, options: options)
98+
XCTFail("Expecting error")
99+
} catch StorageError.authError(let description, let recovery, _) {
100+
XCTAssertEqual(description, authError.errorDescription)
101+
XCTAssertEqual(recovery, authError.recoverySuggestion)
102+
}
103+
}
104+
105+
/// - Given: A newly-configured storage plugin
106+
/// - When: An attempt to generate a pre-signed URL is performed using a `protected` access level
107+
/// - Then: A service key with `protected` in its path is passed to the storage service to generate the URL
108+
func testGetOperationGetPresignedURL() async throws {
109+
let testIdentityId = UUID().uuidString
110+
authService.identityId = testIdentityId
111+
let expectedExpires = Int.random(in: 100..<200)
112+
113+
let options = StorageGetURLRequest.Options(accessLevel: .protected, expires: expectedExpires)
114+
let output = try await systemUnderTest.getURL(key: testKey, options: options)
115+
116+
XCTAssertEqual(testURL, output)
117+
XCTAssertEqual(authService.interactions, [
118+
"getIdentityID()"
119+
])
120+
121+
let expectedServiceKey = StorageAccessLevel.protected.rawValue + "/" + testIdentityId + "/" + testKey
122+
XCTAssertEqual(storageService.interactions, [
123+
"getPreSignedURL(serviceKey:signingOperation:expires:) \(expectedServiceKey) getObject \(expectedExpires)"
124+
])
125+
}
126+
127+
/// - Given: An storage service in an invalid state
128+
/// - When: An attempt to generate a pre-signed URL is performed
129+
/// - Then: A StorageError.service is thrown
130+
func testGetOperationGetPresignedURLFailed() async throws {
131+
let testIdentityId = UUID().uuidString
132+
authService.identityId = testIdentityId
133+
134+
let error = StorageError.service(UUID().uuidString, UUID().uuidString)
135+
storageService.getPreSignedURLHandler = { (_,_,_) in
136+
throw error
137+
}
138+
139+
let expectedExpires = 100
140+
let options = StorageGetURLRequest.Options(accessLevel: .protected, expires: expectedExpires)
141+
do {
142+
_ = try await systemUnderTest.getURL(key: testKey, options: options)
143+
XCTFail("Expecting error")
144+
} catch StorageError.service(let description, let suggestion, _) {
145+
XCTAssertEqual(description, error.errorDescription)
146+
XCTAssertEqual(suggestion, error.recoverySuggestion)
147+
}
148+
149+
XCTAssertEqual(authService.interactions, [
150+
"getIdentityID()"
151+
])
152+
153+
let expectedServiceKey = StorageAccessLevel.protected.rawValue + "/" + testIdentityId + "/" + testKey
154+
XCTAssertEqual(storageService.interactions, [
155+
"getPreSignedURL(serviceKey:signingOperation:expires:) \(expectedServiceKey) getObject \(expectedExpires)"
156+
])
157+
}
158+
159+
/// - Given: A newly-configured storage plugin
160+
/// - When: An attempt to generate a pre-signed URL is performed using a `targetIdentityId` value
161+
/// - Then: A service key with that includes the given identity in its path is passed to the storage service to generate the URL
162+
func testGetOperationGetPresignedURLFromTargetIdentityId() async throws {
163+
let testIdentityId = UUID().uuidString
164+
authService.identityId = testIdentityId
165+
166+
let options = StorageGetURLRequest.Options(accessLevel: .protected, targetIdentityId: testIdentityId)
167+
let output = try await systemUnderTest.getURL(key: testKey, options: options)
168+
XCTAssertEqual(testURL, output)
169+
XCTAssertEqual(authService.interactions, [
170+
"getIdentityID()"
171+
])
172+
173+
let expectedExpires = 18000
174+
let expectedServiceKey = StorageAccessLevel.protected.rawValue + "/" + testIdentityId + "/" + testKey
175+
XCTAssertEqual(storageService.interactions, [
176+
"getPreSignedURL(serviceKey:signingOperation:expires:) \(expectedServiceKey) getObject \(expectedExpires)"
177+
])
178+
}
179+
}

‎AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Mocks/MockAWSS3PreSignedURLBuilder.swift

+12-5
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,22 @@
55
// SPDX-License-Identifier: Apache-2.0
66
//
77

8-
/*
98
import Foundation
109
@testable import AWSS3StoragePlugin
1110
import AWSS3
1211

13-
public class MockAWSS3PreSignedURLBuilder: AWSS3PreSignedURLBuilderBehavior {
14-
public func getPreSignedURL(_ getPreSignedURLRequest: AWSS3GetPreSignedURLRequest) -> AWSTask<NSURL> {
15-
return AWSTask()
12+
final class MockAWSS3PreSignedURLBuilder {
13+
14+
var interactions: [String] = []
15+
16+
var getPreSignedURLHandler: (String, AWSS3SigningOperation, Int64?) async throws -> URL = { (_,_,_) in
17+
return URL(fileURLWithPath: NSTemporaryDirectory())
1618
}
19+
}
1720

21+
extension MockAWSS3PreSignedURLBuilder: AWSS3PreSignedURLBuilderBehavior {
22+
func getPreSignedURL(key: String, signingOperation: AWSS3SigningOperation, expires: Int64?) async throws -> URL {
23+
interactions.append("\(#function) \(key) \(signingOperation) \(String(describing: expires))")
24+
return try await getPreSignedURLHandler(key, signingOperation, expires)
25+
}
1826
}
19-
*/

‎AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Mocks/MockAWSS3StorageService.swift

+6-25
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ public class MockAWSS3StorageService: AWSS3StorageServiceBehaviour {
1616
// MARK: method call counts
1717
var interactions: [String] = []
1818
var downloadCalled = 0
19-
var getPreSignedURLCalled = 0
2019
var uploadCalled = 0
2120
var multiPartUploadCalled = 0
2221
var deleteCalled = 0
@@ -26,9 +25,6 @@ public class MockAWSS3StorageService: AWSS3StorageServiceBehaviour {
2625
var downloadServiceKey: String?
2726
var downloadFileURL: URL?
2827

29-
var getPreSignedURLServiceKey: String?
30-
var getPreSignedURLExpires: Int?
31-
3228
var uploadServiceKey: String?
3329
var uploadUploadSource: UploadSource?
3430
var uploadContentType: String?
@@ -45,7 +41,6 @@ public class MockAWSS3StorageService: AWSS3StorageServiceBehaviour {
4541

4642
// array of StorageEvents to be mocked as the stream of events.
4743
var storageServiceDownloadEvents: [StorageServiceDownloadEvent]?
48-
var storageServiceGetPreSignedURLEvents: [StorageServiceGetPreSignedURLEvent]?
4944
var storageServiceUploadEvents: [StorageServiceUploadEvent]?
5045
var storageServiceMultiPartUploadEvents: [StorageServiceMultiPartUploadEvent]?
5146
var storageServiceDeleteEvents: [StorageServiceDeleteEvent]?
@@ -76,19 +71,13 @@ public class MockAWSS3StorageService: AWSS3StorageServiceBehaviour {
7671
}
7772
}
7873

79-
public func getPreSignedURL(serviceKey: String,
80-
signingOperation: AWSS3SigningOperation = .getObject,
81-
expires: Int,
82-
onEvent: @escaping StorageServiceGetPreSignedURLEventHandler) {
83-
interactions.append(#function)
84-
getPreSignedURLCalled += 1
85-
86-
getPreSignedURLServiceKey = serviceKey
87-
getPreSignedURLExpires = expires
74+
var getPreSignedURLHandler: (String, AWSS3SigningOperation, Int) async throws -> URL = { (_, _, _) in
75+
return URL(fileURLWithPath: NSTemporaryDirectory())
76+
}
8877

89-
for event in storageServiceGetPreSignedURLEvents ?? [] {
90-
onEvent(event)
91-
}
78+
public func getPreSignedURL(serviceKey: String, signingOperation: AWSS3SigningOperation, expires: Int) async throws -> URL {
79+
interactions.append("\(#function) \(serviceKey) \(signingOperation) \(expires)")
80+
return try await getPreSignedURLHandler(serviceKey, signingOperation, expires)
9281
}
9382

9483
public func upload(serviceKey: String,
@@ -163,14 +152,6 @@ public class MockAWSS3StorageService: AWSS3StorageServiceBehaviour {
163152
XCTAssertEqual(downloadFileURL, fileURL)
164153
}
165154

166-
public func verifyGetPreSignedURL(serviceKey: String,
167-
expires: Int?) {
168-
getPreSignedURLCalled += 1
169-
170-
XCTAssertEqual(getPreSignedURLServiceKey, serviceKey)
171-
XCTAssertEqual(getPreSignedURLExpires, expires)
172-
}
173-
174155
public func verifyUpload(serviceKey: String,
175156
key: String,
176157
uploadSource: UploadSource,

‎AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Operation/AWSS3StorageGetURLOperationTests.swift

-162
This file was deleted.

‎AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Service/Storage/AWSS3StorageServiceGetPreSignedURLBehaviorTests.swift

+85-3
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,93 @@
55
// SPDX-License-Identifier: Apache-2.0
66
//
77

8+
@testable import AWSS3StoragePlugin
9+
@testable import AWSPluginsTestCommon
10+
@testable import AmplifyTestCommon
811
import XCTest
912

1013
// swiftlint:disable:next type_name
11-
class AWSS3StorageServiceGetPreSignedURLBehaviorTests: AWSS3StorageServiceTestBase {
12-
func testClassMustNotBeEmpty() {
13-
// Swift format crashes if a test class is empty
14+
class AWSS3StorageServiceGetPreSignedURLBehaviorTests: XCTestCase {
15+
16+
var systemUnderTest: AWSS3StorageService!
17+
var authService: MockAWSAuthService!
18+
var database: MockStorageTransferDatabase!
19+
var builder: MockAWSS3PreSignedURLBuilder!
20+
var region: String!
21+
var bucket: String!
22+
var serviceKey: String!
23+
var presignedURL: URL!
24+
var expires: Int!
25+
26+
override func setUpWithError() throws {
27+
authService = MockAWSAuthService()
28+
database = MockStorageTransferDatabase()
29+
builder = MockAWSS3PreSignedURLBuilder()
30+
region = UUID().uuidString
31+
bucket = UUID().uuidString
32+
serviceKey = UUID().uuidString
33+
presignedURL = URL(fileURLWithPath: NSTemporaryDirectory().appendingPathComponent(serviceKey))
34+
expires = Int(Date.distantFuture.timeIntervalSince1970)
35+
systemUnderTest = try AWSS3StorageService(authService: authService,
36+
region: region,
37+
bucket: bucket,
38+
storageTransferDatabase: database)
39+
systemUnderTest.preSignedURLBuilder = builder
40+
41+
let url = try XCTUnwrap(presignedURL)
42+
builder.getPreSignedURLHandler = { (_,_,_) in
43+
return url
44+
}
45+
}
46+
47+
override func tearDownWithError() throws {
48+
authService = nil
49+
builder = nil
50+
region = nil
51+
bucket = nil
52+
serviceKey = nil
53+
presignedURL = nil
54+
expires = nil
55+
systemUnderTest = nil
56+
}
57+
58+
/// - Given: A storage service configured to use a AWSS3PreSignedURLBuilder
59+
/// - When: A presigned URL is requested for a **AWSS3SigningOperation.getObject** operation
60+
/// - Then: A valid URL is returned
61+
func testForGetObject() async throws {
62+
let url = try await systemUnderTest.getPreSignedURL(serviceKey: serviceKey,
63+
signingOperation: .getObject,
64+
expires: expires)
65+
XCTAssertEqual(url, presignedURL)
66+
XCTAssertEqual(builder.interactions, [
67+
"getPreSignedURL(key:signingOperation:expires:) \(serviceKey ?? "") \(AWSS3SigningOperation.getObject) \(String(describing: expires))"
68+
])
69+
}
70+
71+
/// - Given: A storage service configured to use a AWSS3PreSignedURLBuilder
72+
/// - When: A presigned URL is requested for a **AWSS3SigningOperation.putObject** operation
73+
/// - Then: A valid URL is returned
74+
func testForPutObject() async throws {
75+
let url = try await systemUnderTest.getPreSignedURL(serviceKey: serviceKey,
76+
signingOperation: .putObject,
77+
expires: expires)
78+
XCTAssertEqual(url, presignedURL)
79+
XCTAssertEqual(builder.interactions, [
80+
"getPreSignedURL(key:signingOperation:expires:) \(serviceKey ?? "") \(AWSS3SigningOperation.putObject) \(String(describing: expires))"
81+
])
82+
}
83+
84+
/// - Given: A storage service configured to use a AWSS3PreSignedURLBuilder
85+
/// - When: A presigned URL is requested for a **AWSS3SigningOperation.uploadPart** operation
86+
/// - Then: A valid URL is returned
87+
func testForUploadPart() async throws {
88+
let operation = AWSS3SigningOperation.uploadPart(partNumber: 0, uploadId: UUID().uuidString)
89+
let url = try await systemUnderTest.getPreSignedURL(serviceKey: serviceKey,
90+
signingOperation: operation,
91+
expires: expires)
92+
XCTAssertEqual(url, presignedURL)
93+
XCTAssertEqual(builder.interactions, [
94+
"getPreSignedURL(key:signingOperation:expires:) \(serviceKey ?? "") \(operation) \(String(describing: expires))"
95+
])
1496
}
1597
}

‎AmplifyPlugins/Storage/Tests/StorageHostApp/AWSS3StoragePluginIntegrationTests/AWSS3StoragePluginOptionsUsabilityTests.swift

+10-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ import AWSS3StoragePlugin
1111
import AWSS3
1212

1313
class AWSS3StoragePluginOptionsUsabilityTests: AWSS3StoragePluginTestBase {
14+
15+
override func setUpWithError() throws {
16+
self.continueAfterFailure = false
17+
}
1418

1519
/// Given: An object in storage
1620
/// When: Call the GetURL API with 10 second expiry time
@@ -28,6 +32,9 @@ class AWSS3StoragePluginOptionsUsabilityTests: AWSS3StoragePluginTestBase {
2832

2933
let dataTaskCompleteInvoked = expectation(description: "Completion of retrieving data at URL is invoked")
3034
let task = URLSession.shared.dataTask(with: remoteURL) { data, response, error in
35+
defer {
36+
dataTaskCompleteInvoked.fulfill()
37+
}
3138
if let error = error {
3239
XCTFail("Failed to received data from url with error \(error)")
3340
return
@@ -45,7 +52,6 @@ class AWSS3StoragePluginOptionsUsabilityTests: AWSS3StoragePluginTestBase {
4552

4653
let dataString = String(data: data, encoding: .utf8)!
4754
XCTAssertEqual(dataString, key)
48-
dataTaskCompleteInvoked.fulfill()
4955
}
5056
task.resume()
5157
await waitForExpectations(timeout: TestCommonConstants.networkTimeout)
@@ -54,6 +60,9 @@ class AWSS3StoragePluginOptionsUsabilityTests: AWSS3StoragePluginTestBase {
5460

5561
let urlExpired = expectation(description: "Retrieving expired url should have bad response")
5662
let task2 = URLSession.shared.dataTask(with: remoteURL) { _, response, error in
63+
defer {
64+
urlExpired.fulfill()
65+
}
5766
if let error = error {
5867
XCTFail("Failed to received data from url with error \(error)")
5968
return
@@ -65,7 +74,6 @@ class AWSS3StoragePluginOptionsUsabilityTests: AWSS3StoragePluginTestBase {
6574
}
6675

6776
XCTAssertEqual(response.statusCode, 403)
68-
urlExpired.fulfill()
6977
}
7078
task2.resume()
7179
await waitForExpectations(timeout: TestCommonConstants.networkTimeout)

‎AmplifyPlugins/Storage/Tests/StorageHostApp/StorageHostApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
"kind" : "remoteSourceControl",
66
"location" : "https://github.com/aws-amplify/aws-appsync-realtime-client-ios.git",
77
"state" : {
8-
"revision" : "da88cf1cab82e281e7277cd9feb9efc87a057041",
9-
"version" : "2.1.1"
8+
"revision" : "3de274c68a3cb60c8aec18b5bc0a8c07860219cd",
9+
"version" : "3.0.0"
1010
}
1111
},
1212
{

0 commit comments

Comments
 (0)
Please sign in to comment.