Skip to content

Commit

Permalink
test(Storage): Adding unit and integration tests (#3829)
Browse files Browse the repository at this point in the history
  • Loading branch information
ruisebas committed Aug 27, 2024
1 parent d53a467 commit ba7021c
Show file tree
Hide file tree
Showing 10 changed files with 847 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class AWSS3StorageListObjectsTask: StorageListObjectsTask, DefaultLogger {
}
return StorageListResult.Item(
path: path,
size: s3Object.size,
eTag: s3Object.eTag,
lastModified: s3Object.lastModified
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import XCTest
@_spi(InternalAmplifyConfiguration) @testable import Amplify
@testable import AWSS3StoragePlugin
@testable import AWSPluginsTestCommon

class AWSS3StoragePluginStorageBucketTests: XCTestCase {
private var storagePlugin: AWSS3StoragePlugin!
private var defaultService: MockAWSS3StorageService!
private var authService: MockAWSAuthService!
private var queue: OperationQueue!
private let defaultBucketInfo = BucketInfo(
bucketName: "bucketName",
region: "us-east-1"
)
private let additionalBucketInfo = BucketInfo(
bucketName: "anotherBucketName",
region: "us-east-2"
)

private var additionalS3Bucket: AmplifyOutputsData.Storage.Bucket {
return .init(
name: "anotherBucket",
bucketName: additionalBucketInfo.bucketName,
awsRegion: additionalBucketInfo.region
)
}

override func setUp() {
storagePlugin = AWSS3StoragePlugin()
defaultService = MockAWSS3StorageService()
authService = MockAWSAuthService()
queue = OperationQueue()
storagePlugin.configure(
defaultBucket: .fromBucketInfo(defaultBucketInfo),
storageService: defaultService,
authService: authService,
defaultAccessLevel: .guest,
queue: queue
)
}

override func tearDown() async throws {
try await Task.sleep(seconds: 0.1) // This is unfortunate but necessary to give the DB time to recover the URLSession tasks
await storagePlugin.reset()
queue.cancelAllOperations()
storagePlugin = nil
defaultService = nil
authService = nil
queue = nil
}

/// Given: A configured AWSS3StoragePlugin
/// When: storageService(for:) is invoked with nil
/// Then: The default storage service should be returned
func testStorageService_withNil_shouldReturnDefaultService() throws {
let storageService = try storagePlugin.storageService(for: nil)
guard let mockService = storageService as? MockAWSS3StorageService else {
XCTFail("Expected a MockAWSS3StorageService, got \(type(of: storageService))")
return
}
XCTAssertTrue(mockService === defaultService)
}

/// Given: A AWSS3StoragePlugin configured with additional bucket names
/// When: storageService(for:) is invoked with .fromOutputs with an existing value
/// Then: A valid AWSS3StorageService should be returned pointing to that bucket
func testStorageService_withBucketFromOutputs_shouldReturnStorageService() throws {
storagePlugin.additionalBucketsByName = [
additionalS3Bucket.name: additionalS3Bucket
]
let storageService = try storagePlugin.storageService(for: .fromOutputs(name: additionalS3Bucket.name))
guard let newService = storageService as? AWSS3StorageService else {
XCTFail("Expected a AWSS3StorageService, got \(type(of: storageService))")
return
}
XCTAssertFalse(newService === defaultService)
XCTAssertEqual(newService.bucket, additionalS3Bucket.bucketName)
}

/// Given: A AWSS3StoragePlugin configured without additional buckets (i.e. no AmplifyOutputs)
/// When: storageService(for:) is invoked with .fromOutputs
/// Then: A StorageError.validation error is thrown
func testStorageService_withBucketFromOutputs_withoutConfiguringOutputs_shouldThrowValidationException() {
storagePlugin.additionalBucketsByName = nil
do {
_ = try storagePlugin.storageService(for: .fromOutputs(name: "anotherBucket"))
XCTFail("Expected StorageError.validation to be thrown")
} catch {
guard let storageError = error as? StorageError,
case .validation(let field, _, _, _) = storageError else {
XCTFail("Expected StorageError.validation, got \(error)")
return
}
XCTAssertEqual(field, "bucket")
}
}

/// Given: A AWSS3StoragePlugin configured with additional bucket names
/// When: storageService(for:) is invoked with .fromOutputs with a non-existing value
/// Then: A StorageError.validation error is thrown
func testStorageService_withInvalidBucketFromOutputs_shouldThrowValidationException() {
storagePlugin.additionalBucketsByName = [
additionalS3Bucket.name: additionalS3Bucket
]
do {
_ = try storagePlugin.storageService(for: .fromOutputs(name: "invalidBucket"))
XCTFail("Expected StorageError.validation to be thrown")
} catch {
guard let storageError = error as? StorageError,
case .validation(let field, _, _, _) = storageError else {
XCTFail("Expected StorageError.validation, got \(error)")
return
}
XCTAssertEqual(field, "bucket")
}
}

/// Given: A configured AWSS3StoragePlugin
/// When: storageService(for:) is invoked with .fromBucketInfo
/// Then: A valid AWSS3StorageService should be returned pointing to that bucket
func testStorageService_withBucketFromBucketInfo_shouldReturnStorageService() throws {
let storageService = try storagePlugin.storageService(for: .fromBucketInfo(additionalBucketInfo))
guard let newService = storageService as? AWSS3StorageService else {
XCTFail("Expected a AWSS3StorageService, got \(type(of: storageService))")
return
}
XCTAssertFalse(newService === defaultService)
XCTAssertEqual(newService.bucket, additionalBucketInfo.bucketName)
}

/// Given: A configured AWSS3StoragePlugin
/// When: storageService(for:) is invoked with an invalid instance that conforms to StorageBucket
/// Then: A StorageError.validation error is thrown
func testStorageService_withInvalidStorageBucket_shouldThrowValidationException() {
do {
_ = try storagePlugin.storageService(for: InvalidBucket())
XCTFail("Expected StorageError.validation to be thrown")
} catch {
guard let storageError = error as? StorageError,
case .validation(let field, _, _, _) = storageError else {
XCTFail("Expected StorageError.validation, got \(error)")
return
}
XCTAssertEqual(field, "bucket")
}
}

/// Given: A configured AWSS3StoragePlugin
/// When: storageService(for:) is invoked for a bucket that was not accessed before (i.e. a new one)
/// Then: A new Storage Service should be created
func testStorageService_withNewBucket_shouldReturnNewService() throws {
XCTAssertEqual(storagePlugin.storageServicesByBucket.count, 1)
_ = try storagePlugin.storageService(for: .fromBucketInfo(additionalBucketInfo))
XCTAssertEqual(storagePlugin.storageServicesByBucket.count, 2)
}

/// Given: A configured AWSS3StoragePlugin
/// When: storageService(for:) is invoked for a bucket that was accessed before (e.g. the default one)
/// Then: A new Storage Service should not be created
func testStorageService_withPreviouslyAccessedBucket_shouldReturnExistingService() throws {
XCTAssertEqual(storagePlugin.storageServicesByBucket.count, 1)
_ = try storagePlugin.storageService(for: .fromBucketInfo(defaultBucketInfo))
XCTAssertEqual(storagePlugin.storageServicesByBucket.count, 1)
}

private struct InvalidBucket: StorageBucket {}
}
Loading

0 comments on commit ba7021c

Please sign in to comment.