Skip to content

Commit

Permalink
feat(Storage): Adding integration tests for getURL, remove and list (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
harsh62 authored and lawmicha committed Apr 16, 2024
1 parent d7b6413 commit 16eb6f7
Show file tree
Hide file tree
Showing 4 changed files with 449 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

@testable import Amplify

import AWSS3StoragePlugin
import ClientRuntime
import AWSClientRuntime
import CryptoKit
import XCTest
import AWSS3

class AWSS3StoragePluginGetURLIntegrationTests: AWSS3StoragePluginTestBase {

/// Given: An object in storage
/// When: Call the getURL API
/// Then: The operation completes successfully with the URL retrieved
func testGetRemoteURL() async throws {
let key = "public/" + UUID().uuidString
try await uploadData(key: key, dataString: key)
_ = try await Amplify.Storage.uploadData(
path: .fromString(key),
data: Data(key.utf8),
options: .init())

let remoteURL = try await Amplify.Storage.getURL(path: .fromString(key))

// The presigned URL generation does not result in an SDK or HTTP call.
XCTAssertEqual(requestRecorder.sdkRequests.map { $0.method} , [])

let (data, response) = try await URLSession.shared.data(from: remoteURL)
let httpResponse = try XCTUnwrap(response as? HTTPURLResponse)
XCTAssertEqual(httpResponse.statusCode, 200)

let dataString = try XCTUnwrap(String(data: data, encoding: .utf8))
XCTAssertEqual(dataString, key)

_ = try await Amplify.Storage.remove(path: .fromString(key))
}

/// - Given: A key for a non-existent S3 object
/// - When: A pre-signed URL is requested for that key with `validateObjectExistence = true`
/// - Then: A StorageError.keyNotFound error is thrown
func testGetURLForUnknownKeyWithValidation() async throws {
let unknownKey = "public/" + UUID().uuidString
do {
let url = try await Amplify.Storage.getURL(
path: .fromString(unknownKey),
options: .init(
pluginOptions: AWSStorageGetURLOptions(validateObjectExistence: true)
)
)
XCTFail("Expecting failure but got url: \(url)")
} catch StorageError.keyNotFound(let key, _, _, _) {
XCTAssertTrue(key.contains(unknownKey))
}

// A S3 HeadObject call is expected
XCTAssert(requestRecorder.sdkRequests.map(\.method).allSatisfy { $0 == .head })

XCTAssertEqual(requestRecorder.urlRequests.map { $0.httpMethod }, [])
}

/// - Given: A key for a non-existent S3 object
/// - When: A pre-signed URL is requested for that key with `validateObjectExistence = false`
/// - Then: A pre-signed URL is returned
func testGetURLForUnknownKeyWithoutValidation() async throws {
let unknownKey = UUID().uuidString
let url = try await Amplify.Storage.getURL(
path: .fromString(unknownKey),
options: .init(
pluginOptions: AWSStorageGetURLOptions(validateObjectExistence: false)
)
)
XCTAssertNotNil(url)

// No SDK or URLRequest calls expected
XCTAssertEqual(requestRecorder.sdkRequests.map { $0.method} , [])
XCTAssertEqual(requestRecorder.urlRequests.map { $0.httpMethod }, [])
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

@testable import Amplify

import AWSS3StoragePlugin
import ClientRuntime
import AWSClientRuntime
import CryptoKit
import XCTest
import AWSS3

class AWSS3StoragePluginListObjectsIntegrationTests: AWSS3StoragePluginTestBase {

/// Given: Multiple data object which is uploaded to a public path
/// When: `Amplify.Storage.list` is run
/// Then: The API should execute successfully and list objects for path
func testListObjectsUploadedPublicData() async throws {
let key = UUID().uuidString
let data = Data(key.utf8)
let uniqueStringPath = "public/\(key)"

_ = try await Amplify.Storage.uploadData(path: .fromString(uniqueStringPath + "/test1"), data: data, options: nil).value

let firstListResult = try await Amplify.Storage.list(path: .fromString(uniqueStringPath))

// Validate the item was uploaded.
XCTAssertEqual(firstListResult.items.filter({ $0.path == uniqueStringPath}).count, 1)

_ = try await Amplify.Storage.uploadData(path: .fromString(uniqueStringPath + "/test2"), data: data, options: nil).value

let secondListResult = try await Amplify.Storage.list(path: .fromString(uniqueStringPath))

// Validate the item was uploaded.
XCTAssertEqual(secondListResult.items.filter({ $0.path == uniqueStringPath}).count, 2)

// Clean up
_ = try await Amplify.Storage.remove(path: .fromString(uniqueStringPath + "/test1"))
_ = try await Amplify.Storage.remove(path: .fromString(uniqueStringPath + "/test2"))
}

/// Given: Multiple data object which is uploaded to a protected path
/// When: `Amplify.Storage.list` is run
/// Then: The API should execute successfully and list objects for path
func testListObjectsUploadedProtectedData() async throws {
let key = UUID().uuidString
let data = Data(key.utf8)
var uniqueStringPath = ""

// Sign in
_ = try await Amplify.Auth.signIn(username: Self.user1, password: Self.password)

_ = try await Amplify.Storage.uploadData(
path: .fromIdentityID({ identityId in
uniqueStringPath = "protected/\(identityId)/\(key)"
return uniqueStringPath + "test1"
}),
data: data,
options: nil).value

let firstListResult = try await Amplify.Storage.list(path: .fromString(uniqueStringPath))

// Validate the item was uploaded.
XCTAssertEqual(firstListResult.items.filter({ $0.path == uniqueStringPath}).count, 1)

_ = try await Amplify.Storage.uploadData(
path: .fromIdentityID({ identityId in
uniqueStringPath = "protected/\(identityId)/\(key)"
return uniqueStringPath + "test2"
}),
data: data,
options: nil).value

let secondListResult = try await Amplify.Storage.list(path: .fromString(uniqueStringPath))

// Validate the item was uploaded.
XCTAssertEqual(secondListResult.items.filter({ $0.path == uniqueStringPath}).count, 2)

// clean up
_ = try await Amplify.Storage.remove(path: .fromString(uniqueStringPath + "test1"))
_ = try await Amplify.Storage.remove(path: .fromString(uniqueStringPath + "test2"))

}

/// Given: Multiple data object which is uploaded to a private path
/// When: `Amplify.Storage.list` is run
/// Then: The API should execute successfully and list objects for path
func testListObjectsUploadedPrivateData() async throws {
let key = UUID().uuidString
let data = Data(key.utf8)
var uniqueStringPath = ""

// Sign in
_ = try await Amplify.Auth.signIn(username: Self.user1, password: Self.password)

_ = try await Amplify.Storage.uploadData(
path: .fromIdentityID({ identityId in
uniqueStringPath = "private/\(identityId)/\(key)"
return uniqueStringPath + "test1"
}),
data: data,
options: nil).value

let firstListResult = try await Amplify.Storage.list(path: .fromString(uniqueStringPath))

// Validate the item was uploaded.
XCTAssertEqual(firstListResult.items.filter({ $0.path == uniqueStringPath}).count, 1)

_ = try await Amplify.Storage.uploadData(
path: .fromIdentityID({ identityId in
uniqueStringPath = "private/\(identityId)/\(key)"
return uniqueStringPath + "test2"
}),
data: data,
options: nil).value

let secondListResult = try await Amplify.Storage.list(path: .fromString(uniqueStringPath))

// Validate the item was uploaded.
XCTAssertEqual(secondListResult.items.filter({ $0.path == uniqueStringPath}).count, 2)

// clean up
_ = try await Amplify.Storage.remove(path: .fromString(uniqueStringPath + "test1"))
_ = try await Amplify.Storage.remove(path: .fromString(uniqueStringPath + "test2"))

}

/// Given: Give a unique key that does not exist
/// When: `Amplify.Storage.list` is run
/// Then: The API should execute and throw an error
func testRemoveKeyDoesNotExist() async throws {
let key = UUID().uuidString
let uniqueStringPath = "public/\(key)"

do {
_ = try await Amplify.Storage.list(path: .fromString(uniqueStringPath))
}
catch {
guard let storageError = error as? StorageError else {
XCTFail("Error should be of type StorageError but got \(error)")
return
}
guard case .keyNotFound(_, _, _, let underlyingError) = storageError else {
XCTFail("Error should be of type keyNotFound but got \(error)")
return
}

guard underlyingError is AWSS3.NotFound else {
XCTFail("Underlying error should be of type AWSS3.NotFound but got \(error)")
return
}
}
}

/// Given: Give a unique key where is user is NOT logged in
/// When: `Amplify.Storage.list` is run
/// Then: The API should execute and throw an error
func testRemoveKeyWhenNotSignedInForPrivateKey() async throws {
let key = UUID().uuidString
let uniqueStringPath = "private/\(key)"

do {
_ = try await Amplify.Storage.list(path: .fromString(uniqueStringPath))
}
catch {
guard let storageError = error as? StorageError else {
XCTFail("Error should be of type StorageError but got \(error)")
return
}
guard case .accessDenied(_, _, let underlyingError) = storageError else {
XCTFail("Error should be of type keyNotFound but got \(error)")
return
}

guard underlyingError is UnknownAWSHTTPServiceError else {
XCTFail("Underlying error should be of type UnknownAWSHTTPServiceError but got \(error)")
return
}
}
}

}
Loading

0 comments on commit 16eb6f7

Please sign in to comment.