Skip to content

Commit bc1758d

Browse files
authored
test(Storage): Adding unit and integration tests (#3829)
1 parent 6e19413 commit bc1758d

File tree

10 files changed

+847
-19
lines changed

10 files changed

+847
-19
lines changed

AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Tasks/AWSS3StorageListObjectsTask.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class AWSS3StorageListObjectsTask: StorageListObjectsTask, DefaultLogger {
5656
}
5757
return StorageListResult.Item(
5858
path: path,
59+
size: s3Object.size,
5960
eTag: s3Object.eTag,
6061
lastModified: s3Object.lastModified
6162
)
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
//
2+
// Copyright Amazon.com Inc. or its affiliates.
3+
// All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
import XCTest
9+
@_spi(InternalAmplifyConfiguration) @testable import Amplify
10+
@testable import AWSS3StoragePlugin
11+
@testable import AWSPluginsTestCommon
12+
13+
class AWSS3StoragePluginStorageBucketTests: XCTestCase {
14+
private var storagePlugin: AWSS3StoragePlugin!
15+
private var defaultService: MockAWSS3StorageService!
16+
private var authService: MockAWSAuthService!
17+
private var queue: OperationQueue!
18+
private let defaultBucketInfo = BucketInfo(
19+
bucketName: "bucketName",
20+
region: "us-east-1"
21+
)
22+
private let additionalBucketInfo = BucketInfo(
23+
bucketName: "anotherBucketName",
24+
region: "us-east-2"
25+
)
26+
27+
private var additionalS3Bucket: AmplifyOutputsData.Storage.Bucket {
28+
return .init(
29+
name: "anotherBucket",
30+
bucketName: additionalBucketInfo.bucketName,
31+
awsRegion: additionalBucketInfo.region
32+
)
33+
}
34+
35+
override func setUp() {
36+
storagePlugin = AWSS3StoragePlugin()
37+
defaultService = MockAWSS3StorageService()
38+
authService = MockAWSAuthService()
39+
queue = OperationQueue()
40+
storagePlugin.configure(
41+
defaultBucket: .fromBucketInfo(defaultBucketInfo),
42+
storageService: defaultService,
43+
authService: authService,
44+
defaultAccessLevel: .guest,
45+
queue: queue
46+
)
47+
}
48+
49+
override func tearDown() async throws {
50+
try await Task.sleep(seconds: 0.1) // This is unfortunate but necessary to give the DB time to recover the URLSession tasks
51+
await storagePlugin.reset()
52+
queue.cancelAllOperations()
53+
storagePlugin = nil
54+
defaultService = nil
55+
authService = nil
56+
queue = nil
57+
}
58+
59+
/// Given: A configured AWSS3StoragePlugin
60+
/// When: storageService(for:) is invoked with nil
61+
/// Then: The default storage service should be returned
62+
func testStorageService_withNil_shouldReturnDefaultService() throws {
63+
let storageService = try storagePlugin.storageService(for: nil)
64+
guard let mockService = storageService as? MockAWSS3StorageService else {
65+
XCTFail("Expected a MockAWSS3StorageService, got \(type(of: storageService))")
66+
return
67+
}
68+
XCTAssertTrue(mockService === defaultService)
69+
}
70+
71+
/// Given: A AWSS3StoragePlugin configured with additional bucket names
72+
/// When: storageService(for:) is invoked with .fromOutputs with an existing value
73+
/// Then: A valid AWSS3StorageService should be returned pointing to that bucket
74+
func testStorageService_withBucketFromOutputs_shouldReturnStorageService() throws {
75+
storagePlugin.additionalBucketsByName = [
76+
additionalS3Bucket.name: additionalS3Bucket
77+
]
78+
let storageService = try storagePlugin.storageService(for: .fromOutputs(name: additionalS3Bucket.name))
79+
guard let newService = storageService as? AWSS3StorageService else {
80+
XCTFail("Expected a AWSS3StorageService, got \(type(of: storageService))")
81+
return
82+
}
83+
XCTAssertFalse(newService === defaultService)
84+
XCTAssertEqual(newService.bucket, additionalS3Bucket.bucketName)
85+
}
86+
87+
/// Given: A AWSS3StoragePlugin configured without additional buckets (i.e. no AmplifyOutputs)
88+
/// When: storageService(for:) is invoked with .fromOutputs
89+
/// Then: A StorageError.validation error is thrown
90+
func testStorageService_withBucketFromOutputs_withoutConfiguringOutputs_shouldThrowValidationException() {
91+
storagePlugin.additionalBucketsByName = nil
92+
do {
93+
_ = try storagePlugin.storageService(for: .fromOutputs(name: "anotherBucket"))
94+
XCTFail("Expected StorageError.validation to be thrown")
95+
} catch {
96+
guard let storageError = error as? StorageError,
97+
case .validation(let field, _, _, _) = storageError else {
98+
XCTFail("Expected StorageError.validation, got \(error)")
99+
return
100+
}
101+
XCTAssertEqual(field, "bucket")
102+
}
103+
}
104+
105+
/// Given: A AWSS3StoragePlugin configured with additional bucket names
106+
/// When: storageService(for:) is invoked with .fromOutputs with a non-existing value
107+
/// Then: A StorageError.validation error is thrown
108+
func testStorageService_withInvalidBucketFromOutputs_shouldThrowValidationException() {
109+
storagePlugin.additionalBucketsByName = [
110+
additionalS3Bucket.name: additionalS3Bucket
111+
]
112+
do {
113+
_ = try storagePlugin.storageService(for: .fromOutputs(name: "invalidBucket"))
114+
XCTFail("Expected StorageError.validation to be thrown")
115+
} catch {
116+
guard let storageError = error as? StorageError,
117+
case .validation(let field, _, _, _) = storageError else {
118+
XCTFail("Expected StorageError.validation, got \(error)")
119+
return
120+
}
121+
XCTAssertEqual(field, "bucket")
122+
}
123+
}
124+
125+
/// Given: A configured AWSS3StoragePlugin
126+
/// When: storageService(for:) is invoked with .fromBucketInfo
127+
/// Then: A valid AWSS3StorageService should be returned pointing to that bucket
128+
func testStorageService_withBucketFromBucketInfo_shouldReturnStorageService() throws {
129+
let storageService = try storagePlugin.storageService(for: .fromBucketInfo(additionalBucketInfo))
130+
guard let newService = storageService as? AWSS3StorageService else {
131+
XCTFail("Expected a AWSS3StorageService, got \(type(of: storageService))")
132+
return
133+
}
134+
XCTAssertFalse(newService === defaultService)
135+
XCTAssertEqual(newService.bucket, additionalBucketInfo.bucketName)
136+
}
137+
138+
/// Given: A configured AWSS3StoragePlugin
139+
/// When: storageService(for:) is invoked with an invalid instance that conforms to StorageBucket
140+
/// Then: A StorageError.validation error is thrown
141+
func testStorageService_withInvalidStorageBucket_shouldThrowValidationException() {
142+
do {
143+
_ = try storagePlugin.storageService(for: InvalidBucket())
144+
XCTFail("Expected StorageError.validation to be thrown")
145+
} catch {
146+
guard let storageError = error as? StorageError,
147+
case .validation(let field, _, _, _) = storageError else {
148+
XCTFail("Expected StorageError.validation, got \(error)")
149+
return
150+
}
151+
XCTAssertEqual(field, "bucket")
152+
}
153+
}
154+
155+
/// Given: A configured AWSS3StoragePlugin
156+
/// When: storageService(for:) is invoked for a bucket that was not accessed before (i.e. a new one)
157+
/// Then: A new Storage Service should be created
158+
func testStorageService_withNewBucket_shouldReturnNewService() throws {
159+
XCTAssertEqual(storagePlugin.storageServicesByBucket.count, 1)
160+
_ = try storagePlugin.storageService(for: .fromBucketInfo(additionalBucketInfo))
161+
XCTAssertEqual(storagePlugin.storageServicesByBucket.count, 2)
162+
}
163+
164+
/// Given: A configured AWSS3StoragePlugin
165+
/// When: storageService(for:) is invoked for a bucket that was accessed before (e.g. the default one)
166+
/// Then: A new Storage Service should not be created
167+
func testStorageService_withPreviouslyAccessedBucket_shouldReturnExistingService() throws {
168+
XCTAssertEqual(storagePlugin.storageServicesByBucket.count, 1)
169+
_ = try storagePlugin.storageService(for: .fromBucketInfo(defaultBucketInfo))
170+
XCTAssertEqual(storagePlugin.storageServicesByBucket.count, 1)
171+
}
172+
173+
private struct InvalidBucket: StorageBucket {}
174+
}

0 commit comments

Comments
 (0)