|
| 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 | +} |
0 commit comments