Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add concurrent integration test & utils #1596

Merged
merged 27 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
268afa9
Add concurrent tests
Jun 27, 2024
13732b5
Add missing 100x to a test's name
Jun 27, 2024
fb34981
Merge branch 'main' into feat/concurrent-tests
Jul 5, 2024
25f7f1c
Merge branch 'main' into feat/concurrent-tests
Jul 8, 2024
a1a4e25
Remove 100MiB file and generate file instead.
Jul 8, 2024
648215c
See if using UUID for filename fixes this possibly-concurrency-issue.
Jul 8, 2024
7fa4672
Try temporaryDirectory property.
Jul 9, 2024
d4cf57b
Fix concurrency issue
Jul 9, 2024
390e7a4
Merge branch 'main' into feat/concurrent-tests
Jul 10, 2024
e667d1f
Merge branch 'main' into feat/concurrent-tests
Sep 18, 2024
8930eb4
Comment fixes & remove STS getCallerIdentity concurrent calls.
Sep 18, 2024
2850fdd
Remove unused import
Sep 18, 2024
ec40d7d
Remove concurrent test for event stream output
Sep 18, 2024
324caf0
Refactor tests a bit
Sep 18, 2024
3ed5c58
Use FileStream to write to file
Sep 18, 2024
8871d6b
Swap out filemanager with writing emtpy data approach
Sep 18, 2024
b0ebe87
Tweak a bit
Sep 18, 2024
bb49389
Merge branch 'main' into feat/concurrent-tests
Sep 18, 2024
2857855
Simplify; no need to safe generated dummy data to a file, just use 50…
Sep 18, 2024
3ee9a59
Merge branch 'main' into feat/concurrent-tests
Sep 19, 2024
55add5d
Change from 10x50MB to 100x5MB
Sep 19, 2024
8194103
Merge branch 'main' into feat/concurrent-tests
jbelkins Sep 20, 2024
b5f97f6
Merge branch 'main' into feat/concurrent-tests
Sep 20, 2024
19935c5
Merge branch 'feat/concurrent-tests' of github.com:awslabs/aws-sdk-sw…
Sep 20, 2024
fed7e45
Reduce payload from 5MB to 3MB
Sep 20, 2024
58e1ca2
Reduce payload from 3MB to 1MB.
Sep 20, 2024
a8a31f5
Add test for 1.5 MB to test aws chunked & flexible checksum flow also.
Sep 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

/// Runs a test concurrently for the number of times specified
///
/// The test is run repeatedly using a Swift task group; each test run is performed as a "child task".
/// The function returns when all test runs have completed, and rethrows if a test run throws.
/// - Parameters:
/// - count: The number of test runs
/// - test: A function pointer to the test to be run
/// - Throws: Any error thrown by one of the test runs.
public func repeatConcurrently(count: Int, test: @escaping () async throws -> Void) async throws {
try await withThrowingTaskGroup(of: Void.self) { taskGroup in

Check failure on line 17 in IntegrationTests/AWSIntegrationTestUtils/ConcurrentTestHelper.swift

View workflow job for this annotation

GitHub Actions / apple (macos-14, Xcode_15.4, platform=iOS Simulator,OS=17.5,name=iPhone 15)

test_10x_50MB_getObject, failed: caught error: "Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo={_kCFStreamErrorCodeKey=-2102, NSUnderlyingError=0x600000c7dd10 {Error Domain=kCFErrorDomainCFNetwork Code=-1001 "(null)" UserInfo={_kCFStreamErrorCodeKey=-2102, _kCFStreamErrorDomainKey=4}}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <AECA7B42-3156-449F-B587-C55E81676905>.<11>, _NSURLErrorRelatedURLSessionTaskErrorKey=(
for _ in 0..<count {
taskGroup.addTask {
try await test()
}
}
try await taskGroup.waitForAll()
}
}
10 changes: 10 additions & 0 deletions IntegrationTests/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import PackageDescription
// MARK: - Target dependencies

extension Target.Dependency {
// Test utility module
static var awsIntegrationTestUtils: Self { "AWSIntegrationTestUtils" }

// AWS modules
static var awsClientRuntime: Self { .product(name: "AWSClientRuntime", package: "aws-sdk-swift") }
static var awsSDKCommon: Self { .product(name: "AWSSDKCommon", package: "aws-sdk-swift") }
Expand All @@ -36,6 +39,12 @@ let package = Package(
.iOS(.v13),
.tvOS(.v13),
.watchOS(.v6)
],
targets: [
.target(
name: "AWSIntegrationTestUtils",
path: "./AWSIntegrationTestUtils"
)
]
)

Expand Down Expand Up @@ -119,6 +128,7 @@ func addIntegrationTestTarget(_ name: String) {
.awsSDKIdentity,
.smithyIdentity,
.awsSDKCommon,
.awsIntegrationTestUtils,
.product(name: name, package: "aws-sdk-swift")
] + additionalDependencies.map {
Target.Dependency.product(name: $0, package: "aws-sdk-swift", condition: nil)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//
// File.swift
//
//
// Created by Yoo, Chan on 6/27/24.
//

import Foundation
import Smithy
import XCTest
import AWSS3
import AWSIntegrationTestUtils

class S3ConcurrentTests: S3XCTestCase {
let fileSize = 50_000_000

func test_50MB_putObject() async throws {
let fileURL = getFileURL()
generateDummyTextFile(fileURL: fileURL)
let file = ByteStream.from(
fileHandle: try FileHandle(
forReadingFrom: fileURL
)
)
let objectKey = UUID().uuidString.split(separator: "-").first!.lowercased()
let putObjectInput = PutObjectInput(body: file, bucket: bucketName, key: objectKey)
_ = try await client.putObject(input: putObjectInput)
let headObjectInput = HeadObjectInput(bucket: bucketName, key: objectKey)
let contentLength = try await client.headObject(input: headObjectInput).contentLength
XCTAssertEqual(contentLength, fileSize)
deleteDummyTextFile(fileURL: fileURL)
}

func test_50MB_getObject() async throws {
let fileURL = getFileURL()
generateDummyTextFile(fileURL: fileURL)
let file = ByteStream.from(
fileHandle: try FileHandle(
forReadingFrom: fileURL
)
)
let objectKey = UUID().uuidString.split(separator: "-").first!.lowercased()
let putObjectInput = PutObjectInput(body: file, bucket: bucketName, key: objectKey)
_ = try await client.putObject(input: putObjectInput)
let getObjectInput = GetObjectInput(bucket: bucketName, key: objectKey)
let retrievedData = try await client.getObject(input: getObjectInput).body.unsafelyUnwrapped.readData()
XCTAssertEqual(

Check failure on line 47 in IntegrationTests/Services/AWSS3IntegrationTests/S3ConcurrentTests.swift

View workflow job for this annotation

GitHub Actions / apple (macos-14, Xcode_15.4, platform=iOS Simulator,OS=17.5,name=iPhone 15)

test_10x_50MB_getObject, XCTAssertEqual failed: threw error "Error Domain=NSCocoaErrorDomain Code=260 "The file “50MiB-161cccf3.txt” couldn’t be opened because there is no such file." UserInfo={NSFilePath=/Users/runner/Library/Developer/CoreSimulator/Devices/4158CBF2-3210-494F-942B-604E4900AC23/data/tmp/50MiB-161cccf3.txt, NSUnderlyingError=0x600000c80300 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}"
try Data(contentsOf: fileURL),
retrievedData
)
deleteDummyTextFile(fileURL: fileURL)
}

func test_10x_50MB_putObject() async throws {
try await repeatConcurrently(count: 10, test: test_50MB_putObject)
}

func test_10x_50MB_getObject() async throws {
try await repeatConcurrently(count: 10, test: test_50MB_getObject)
}

// Helper functions

func getFileURL() -> URL {
let tempDirectoryURL = FileManager.default.temporaryDirectory
let uuid = UUID().uuidString.split(separator: "-").first!.lowercased()
return URL(fileURLWithPath: "50MiB-\(uuid)", relativeTo: tempDirectoryURL).appendingPathExtension("txt")
}

func generateDummyTextFile(fileURL: URL) {
let stringSegment = "1234567890abcdefghijklmnopqrstABCDEFGHIJKLMNOPQRST" // 50 char long string
guard let segmentData = stringSegment.data(using: .utf8) else {
jbelkins marked this conversation as resolved.
Show resolved Hide resolved
XCTFail("Unable to convert string to data")
return
}
var wholeData = Data()
jbelkins marked this conversation as resolved.
Show resolved Hide resolved
for _ in 1...1_000_000 {
wholeData.append(segmentData)
}
do {
try wholeData.write(to: fileURL)
} catch {
XCTFail(error.localizedDescription)
}
}

func deleteDummyTextFile(fileURL: URL) {
do {
// Delete the temporarily geenerated file
try FileManager.default.removeItem(at: fileURL)
} catch {
XCTFail(error.localizedDescription)

Check failure on line 92 in IntegrationTests/Services/AWSS3IntegrationTests/S3ConcurrentTests.swift

View workflow job for this annotation

GitHub Actions / apple (macos-14, Xcode_15.4, platform=iOS Simulator,OS=17.5,name=iPhone 15)

test_10x_50MB_getObject, failed - “50MiB-161cccf3.txt” couldn’t be removed.
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import Foundation
import AWSS3
import XCTest
import AWSIntegrationTestUtils

class S3EventStreamTests: S3XCTestCase {
private let objectKey = "integ-test-json-object"
Expand Down Expand Up @@ -59,4 +60,8 @@ class S3EventStreamTests: S3XCTestCase {
let expectedOutput = "{\"id\":\"1\"}\n{\"id\":\"2\"}\n"
XCTAssertEqual(expectedOutput, actualOutput)
}

func test_100x_eventStreamOutput() async throws {
try await repeatConcurrently(count: 100, test: testEventStreamOutput)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import AWSSTS
import ClientRuntime
import AWSClientRuntime
import AWSSDKHTTPAuth
import AWSIntegrationTestUtils

/// Tests presigned request using STS::getCallerIdentity.
class STSPresignedRequestTests: XCTestCase {
Expand All @@ -34,4 +35,8 @@ class STSPresignedRequestTests: XCTestCase {
let httpResponse = try await stsConfig.httpClientEngine.send(request: presignedRequest)
XCTAssertEqual(httpResponse.statusCode.rawValue, 200)
}

func test_100x_getCallerIdentity() async throws {
try await repeatConcurrently(count: 100, test: testGetCallerIdentity)
}
}
Loading