Skip to content

Commit 540acc2

Browse files
authored
feat(Storage): Adding integration tests for getURL, remove and list (#3584)
1 parent 9e2bc8b commit 540acc2

File tree

4 files changed

+449
-0
lines changed

4 files changed

+449
-0
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
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 Amplify
9+
10+
import AWSS3StoragePlugin
11+
import ClientRuntime
12+
import AWSClientRuntime
13+
import CryptoKit
14+
import XCTest
15+
import AWSS3
16+
17+
class AWSS3StoragePluginGetURLIntegrationTests: AWSS3StoragePluginTestBase {
18+
19+
/// Given: An object in storage
20+
/// When: Call the getURL API
21+
/// Then: The operation completes successfully with the URL retrieved
22+
func testGetRemoteURL() async throws {
23+
let key = "public/" + UUID().uuidString
24+
try await uploadData(key: key, dataString: key)
25+
_ = try await Amplify.Storage.uploadData(
26+
path: .fromString(key),
27+
data: Data(key.utf8),
28+
options: .init())
29+
30+
let remoteURL = try await Amplify.Storage.getURL(path: .fromString(key))
31+
32+
// The presigned URL generation does not result in an SDK or HTTP call.
33+
XCTAssertEqual(requestRecorder.sdkRequests.map { $0.method} , [])
34+
35+
let (data, response) = try await URLSession.shared.data(from: remoteURL)
36+
let httpResponse = try XCTUnwrap(response as? HTTPURLResponse)
37+
XCTAssertEqual(httpResponse.statusCode, 200)
38+
39+
let dataString = try XCTUnwrap(String(data: data, encoding: .utf8))
40+
XCTAssertEqual(dataString, key)
41+
42+
_ = try await Amplify.Storage.remove(path: .fromString(key))
43+
}
44+
45+
/// - Given: A key for a non-existent S3 object
46+
/// - When: A pre-signed URL is requested for that key with `validateObjectExistence = true`
47+
/// - Then: A StorageError.keyNotFound error is thrown
48+
func testGetURLForUnknownKeyWithValidation() async throws {
49+
let unknownKey = "public/" + UUID().uuidString
50+
do {
51+
let url = try await Amplify.Storage.getURL(
52+
path: .fromString(unknownKey),
53+
options: .init(
54+
pluginOptions: AWSStorageGetURLOptions(validateObjectExistence: true)
55+
)
56+
)
57+
XCTFail("Expecting failure but got url: \(url)")
58+
} catch StorageError.keyNotFound(let key, _, _, _) {
59+
XCTAssertTrue(key.contains(unknownKey))
60+
}
61+
62+
// A S3 HeadObject call is expected
63+
XCTAssert(requestRecorder.sdkRequests.map(\.method).allSatisfy { $0 == .head })
64+
65+
XCTAssertEqual(requestRecorder.urlRequests.map { $0.httpMethod }, [])
66+
}
67+
68+
/// - Given: A key for a non-existent S3 object
69+
/// - When: A pre-signed URL is requested for that key with `validateObjectExistence = false`
70+
/// - Then: A pre-signed URL is returned
71+
func testGetURLForUnknownKeyWithoutValidation() async throws {
72+
let unknownKey = UUID().uuidString
73+
let url = try await Amplify.Storage.getURL(
74+
path: .fromString(unknownKey),
75+
options: .init(
76+
pluginOptions: AWSStorageGetURLOptions(validateObjectExistence: false)
77+
)
78+
)
79+
XCTAssertNotNil(url)
80+
81+
// No SDK or URLRequest calls expected
82+
XCTAssertEqual(requestRecorder.sdkRequests.map { $0.method} , [])
83+
XCTAssertEqual(requestRecorder.urlRequests.map { $0.httpMethod }, [])
84+
}
85+
}
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
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 Amplify
9+
10+
import AWSS3StoragePlugin
11+
import ClientRuntime
12+
import AWSClientRuntime
13+
import CryptoKit
14+
import XCTest
15+
import AWSS3
16+
17+
class AWSS3StoragePluginListObjectsIntegrationTests: AWSS3StoragePluginTestBase {
18+
19+
/// Given: Multiple data object which is uploaded to a public path
20+
/// When: `Amplify.Storage.list` is run
21+
/// Then: The API should execute successfully and list objects for path
22+
func testListObjectsUploadedPublicData() async throws {
23+
let key = UUID().uuidString
24+
let data = Data(key.utf8)
25+
let uniqueStringPath = "public/\(key)"
26+
27+
_ = try await Amplify.Storage.uploadData(path: .fromString(uniqueStringPath + "/test1"), data: data, options: nil).value
28+
29+
let firstListResult = try await Amplify.Storage.list(path: .fromString(uniqueStringPath))
30+
31+
// Validate the item was uploaded.
32+
XCTAssertEqual(firstListResult.items.filter({ $0.path == uniqueStringPath}).count, 1)
33+
34+
_ = try await Amplify.Storage.uploadData(path: .fromString(uniqueStringPath + "/test2"), data: data, options: nil).value
35+
36+
let secondListResult = try await Amplify.Storage.list(path: .fromString(uniqueStringPath))
37+
38+
// Validate the item was uploaded.
39+
XCTAssertEqual(secondListResult.items.filter({ $0.path == uniqueStringPath}).count, 2)
40+
41+
// Clean up
42+
_ = try await Amplify.Storage.remove(path: .fromString(uniqueStringPath + "/test1"))
43+
_ = try await Amplify.Storage.remove(path: .fromString(uniqueStringPath + "/test2"))
44+
}
45+
46+
/// Given: Multiple data object which is uploaded to a protected path
47+
/// When: `Amplify.Storage.list` is run
48+
/// Then: The API should execute successfully and list objects for path
49+
func testListObjectsUploadedProtectedData() async throws {
50+
let key = UUID().uuidString
51+
let data = Data(key.utf8)
52+
var uniqueStringPath = ""
53+
54+
// Sign in
55+
_ = try await Amplify.Auth.signIn(username: Self.user1, password: Self.password)
56+
57+
_ = try await Amplify.Storage.uploadData(
58+
path: .fromIdentityID({ identityId in
59+
uniqueStringPath = "protected/\(identityId)/\(key)"
60+
return uniqueStringPath + "test1"
61+
}),
62+
data: data,
63+
options: nil).value
64+
65+
let firstListResult = try await Amplify.Storage.list(path: .fromString(uniqueStringPath))
66+
67+
// Validate the item was uploaded.
68+
XCTAssertEqual(firstListResult.items.filter({ $0.path == uniqueStringPath}).count, 1)
69+
70+
_ = try await Amplify.Storage.uploadData(
71+
path: .fromIdentityID({ identityId in
72+
uniqueStringPath = "protected/\(identityId)/\(key)"
73+
return uniqueStringPath + "test2"
74+
}),
75+
data: data,
76+
options: nil).value
77+
78+
let secondListResult = try await Amplify.Storage.list(path: .fromString(uniqueStringPath))
79+
80+
// Validate the item was uploaded.
81+
XCTAssertEqual(secondListResult.items.filter({ $0.path == uniqueStringPath}).count, 2)
82+
83+
// clean up
84+
_ = try await Amplify.Storage.remove(path: .fromString(uniqueStringPath + "test1"))
85+
_ = try await Amplify.Storage.remove(path: .fromString(uniqueStringPath + "test2"))
86+
87+
}
88+
89+
/// Given: Multiple data object which is uploaded to a private path
90+
/// When: `Amplify.Storage.list` is run
91+
/// Then: The API should execute successfully and list objects for path
92+
func testListObjectsUploadedPrivateData() async throws {
93+
let key = UUID().uuidString
94+
let data = Data(key.utf8)
95+
var uniqueStringPath = ""
96+
97+
// Sign in
98+
_ = try await Amplify.Auth.signIn(username: Self.user1, password: Self.password)
99+
100+
_ = try await Amplify.Storage.uploadData(
101+
path: .fromIdentityID({ identityId in
102+
uniqueStringPath = "private/\(identityId)/\(key)"
103+
return uniqueStringPath + "test1"
104+
}),
105+
data: data,
106+
options: nil).value
107+
108+
let firstListResult = try await Amplify.Storage.list(path: .fromString(uniqueStringPath))
109+
110+
// Validate the item was uploaded.
111+
XCTAssertEqual(firstListResult.items.filter({ $0.path == uniqueStringPath}).count, 1)
112+
113+
_ = try await Amplify.Storage.uploadData(
114+
path: .fromIdentityID({ identityId in
115+
uniqueStringPath = "private/\(identityId)/\(key)"
116+
return uniqueStringPath + "test2"
117+
}),
118+
data: data,
119+
options: nil).value
120+
121+
let secondListResult = try await Amplify.Storage.list(path: .fromString(uniqueStringPath))
122+
123+
// Validate the item was uploaded.
124+
XCTAssertEqual(secondListResult.items.filter({ $0.path == uniqueStringPath}).count, 2)
125+
126+
// clean up
127+
_ = try await Amplify.Storage.remove(path: .fromString(uniqueStringPath + "test1"))
128+
_ = try await Amplify.Storage.remove(path: .fromString(uniqueStringPath + "test2"))
129+
130+
}
131+
132+
/// Given: Give a unique key that does not exist
133+
/// When: `Amplify.Storage.list` is run
134+
/// Then: The API should execute and throw an error
135+
func testRemoveKeyDoesNotExist() async throws {
136+
let key = UUID().uuidString
137+
let uniqueStringPath = "public/\(key)"
138+
139+
do {
140+
_ = try await Amplify.Storage.list(path: .fromString(uniqueStringPath))
141+
}
142+
catch {
143+
guard let storageError = error as? StorageError else {
144+
XCTFail("Error should be of type StorageError but got \(error)")
145+
return
146+
}
147+
guard case .keyNotFound(_, _, _, let underlyingError) = storageError else {
148+
XCTFail("Error should be of type keyNotFound but got \(error)")
149+
return
150+
}
151+
152+
guard underlyingError is AWSS3.NotFound else {
153+
XCTFail("Underlying error should be of type AWSS3.NotFound but got \(error)")
154+
return
155+
}
156+
}
157+
}
158+
159+
/// Given: Give a unique key where is user is NOT logged in
160+
/// When: `Amplify.Storage.list` is run
161+
/// Then: The API should execute and throw an error
162+
func testRemoveKeyWhenNotSignedInForPrivateKey() async throws {
163+
let key = UUID().uuidString
164+
let uniqueStringPath = "private/\(key)"
165+
166+
do {
167+
_ = try await Amplify.Storage.list(path: .fromString(uniqueStringPath))
168+
}
169+
catch {
170+
guard let storageError = error as? StorageError else {
171+
XCTFail("Error should be of type StorageError but got \(error)")
172+
return
173+
}
174+
guard case .accessDenied(_, _, let underlyingError) = storageError else {
175+
XCTFail("Error should be of type keyNotFound but got \(error)")
176+
return
177+
}
178+
179+
guard underlyingError is UnknownAWSHTTPServiceError else {
180+
XCTFail("Underlying error should be of type UnknownAWSHTTPServiceError but got \(error)")
181+
return
182+
}
183+
}
184+
}
185+
186+
}

0 commit comments

Comments
 (0)