Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
32 changes: 32 additions & 0 deletions IntegrationTests/AWSIntegrationTestUtils/String+Identifier.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import struct Foundation.UUID

package extension String {

/// Returns an identifier that contains a UUID and is 63 or less chars in length.
///
/// Size is selected to be compatible with the requirement that bucket names be 63 characters or less.
/// - Parameter service: The name (or abbreviation) of the service being identified.
/// May contain only A-Z, a-z, 0-9, and dash(-). May not be empty. May not be long enough to result in an
/// identifier 64 chars or longer. Uppercase characters in the service will be downcased in the identifier.
/// - Returns: The identifier.
static func uniqueID(service: String) -> String {
let prefix = "sdkinttest-"
guard !service.isEmpty else {
fatalError("Service cannot be empty")
}
guard service.lowercased().allSatisfy({ "abcdefghijklmnopqrstuvwxyz0123456789-".contains($0) }) else {
fatalError("Service cannot contain characters other than alphanumeric & dash")
}
guard prefix.count + service.count + 36 < 64 else {
fatalError("Service name is too long. Limit is \(63 - prefix.count - 36)")
}
return (prefix + service + UUID().uuidString).lowercased()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import ClientRuntime
import AWSClientRuntime
import AWSCloudFront
import AWSCloudFrontKeyValueStore
import AWSIntegrationTestUtils

/// Tests SigV4a signing flow using CloudFrontKeyValueStore.
class CloudFrontKeyValueStoreSigV4ATests: XCTestCase {
Expand All @@ -23,7 +24,7 @@ class CloudFrontKeyValueStoreSigV4ATests: XCTestCase {
private let region = "us-east-1"

// Temporary name of the KVS to use for the test
private let kvsName = "sigv4a-test-kvs-" + UUID().uuidString.split(separator: "-").first!.lowercased()
private let kvsName = String.uniqueID(service: "sigv4a-kvs")

// The Etag to use to call CloudFront::deletKeyValueStore
private var cfEtag: String!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ import AWSSTS
import ClientRuntime
import SmithyWaitersAPI
import XCTest
import AWSIntegrationTestUtils

/// Tests CognitoAWSCredentialIdentityResolver using STS::getCallerIdentity.
class CognitoAWSCredentialIdentityResolverTests: XCTestCase {
private let region = "us-west-2"

private var cognitoIdentityClient: CognitoIdentityClient!
private var iamClient: IAMClient!
private let identityPoolName = "aws-cognito-integration-test-\(UUID().uuidString.split(separator: "-").first!.lowercased())"
private let identityPoolName = String.uniqueID(service: "cognito")
private var identityPoolId: String!
private var roleName: String!

Expand All @@ -38,7 +39,7 @@ class CognitoAWSCredentialIdentityResolverTests: XCTestCase {
)
).identityPoolId
// Create an IAM role for unauthenticated users
roleName = "CognitoUnauth_\(identityPoolName)"
roleName = String.uniqueID(service: "cog-role")
let trustPolicy = """
{
"Version": "2012-10-17",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import AWSClientRuntime
import ClientRuntime
import class SmithyHTTPAPI.HTTPRequest
import class SmithyHTTPAPI.HTTPResponse
import AWSIntegrationTestUtils

/// Tests unauthenciated API using AWSCognitoIdentity::getId
class UnauthenticatedAPITests: XCTestCase {
Expand All @@ -22,7 +23,7 @@ class UnauthenticatedAPITests: XCTestCase {

private var accountID: String!
private var identityPoolID: String!
private let identityPoolName = "idpool" + UUID().uuidString.split(separator: "-").first!.lowercased()
private let identityPoolName = String.uniqueID(service: "idpool")

override func setUp() async throws {
// STS client for getting the account ID, an input parameter for the unauthenticated API, getId().
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import AWSEventBridge
import ClientRuntime
import AWSClientRuntime
import AWSRoute53
import AWSIntegrationTestUtils

/// Tests SigV4a signing flow using EventBridge's global endpoint.
class EventBridgeSigV4ATests: XCTestCase {
Expand All @@ -28,8 +29,8 @@ class EventBridgeSigV4ATests: XCTestCase {
private let secondaryRegion = "us-east-1"

// Name for the EventBridge global endpoint
private let endpointName = "sigv4a-test-global-endpoint-\(UUID().uuidString.split(separator: "-").first!.lowercased())"
private let eventBusName = "sigv4a-integ-test-eventbus-\(UUID().uuidString.split(separator: "-").first!.lowercased())"
private let endpointName = String.uniqueID(service: "eb-globalendpt")
private let eventBusName = String.uniqueID(service: "eb-eventbus")
private var endpointId: String!

private var healthCheckId: String!
Expand Down Expand Up @@ -58,7 +59,7 @@ class EventBridgeSigV4ATests: XCTestCase {
type: .https
)
let createHealthCheckInput = CreateHealthCheckInput(
callerReference: UUID().uuidString.split(separator: "-").first!.lowercased(),
callerReference: String.uniqueID(service: "r53-healthchk"),
healthCheckConfig: healthCheckConfig
)
let healthCheck = try await route53Client.createHealthCheck(input: createHealthCheckInput)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ import AWSGlacier
import AWSSTS
import enum Smithy.ByteStream
import SmithyWaitersAPI
import AWSIntegrationTestUtils

/// Tests that Glacier operations run successfully
class GlacierTests: XCTestCase {
var glacierClient: GlacierClient!
var stsClient: STSClient!
var accountId: String!
var archiveId: String!
let vaultName = UUID().uuidString.split(separator: "-").first!.lowercased() + "integ-test-vault"
let vaultName = String.uniqueID(service: "s3-glacier")

override func setUp() async throws {
stsClient = try STSClient(region: "us-east-1")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import AWSKinesis
import ClientRuntime
import AWSClientRuntime
import SmithyWaitersAPI
import AWSIntegrationTestUtils

class KinesisTests: XCTestCase {

Expand All @@ -23,7 +24,7 @@ class KinesisTests: XCTestCase {
// Client must have AWS credentials set that allow access to the Kinesis service.
// Resources will be cleaned up before the test concludes, pass or fail, unless the test crashes.

let streamName = UUID().uuidString
let streamName = String.uniqueID(service: "kinesis")
let client = try KinesisClient(region: "us-west-2")

do {
Expand All @@ -36,7 +37,7 @@ class KinesisTests: XCTestCase {
let streamARN = stream.streamDescription?.streamARN

// Make a set of 10 records, add them to the stream
var recordStrings = (1...10).map { _ in UUID().uuidString }
var recordStrings = (1...10).map { _ in String.uniqueID(service: "kinesis") }
for record in recordStrings {
let putRecordInput = PutRecordInput(data: record.data(using: .utf8), explicitHashKey: nil, partitionKey: "Test", sequenceNumberForOrdering: nil, streamName: streamName)
let _ = try await client.putRecord(input: putRecordInput)
Expand All @@ -48,7 +49,7 @@ class KinesisTests: XCTestCase {
let shard = shardList.shards?.first!

// Create a consumer for the shard
let consumerName = UUID().uuidString
let consumerName = String.uniqueID(service: "kinesis")
let consumerInput = RegisterStreamConsumerInput(consumerName: consumerName, streamARN: stream.streamDescription?.streamARN)
let consumer = try await client.registerStreamConsumer(input: consumerInput)
let consumerARN = consumer.consumer?.consumerARN
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,18 @@ final class S3ConcurrentTests: S3XCTestCase, @unchecked Sendable {
// Puts data to S3, gets the uploaded file, asserts retrieved data == original data, deletes S3 object
@Sendable
private func getObject(data: Data) async throws {
let objectKey = UUID().uuidString.split(separator: "-").first!.lowercased()
let putObjectInput = PutObjectInput(body: .data(data), bucket: bucketName, key: objectKey)
let objectKey = String.uniqueID(service: "s3")
let putObjectInput = PutObjectInput(body: .data(data), bucket: bucketName, key: objectKey)

_ = try await client.putObject(input: putObjectInput)
_ = try await client.putObject(input: putObjectInput)

let retrievedData = try await client.getObject(input: GetObjectInput(
bucket: bucketName, key: objectKey
)).body?.readData()
let retrievedData = try await client.getObject(input: GetObjectInput(
bucket: bucketName, key: objectKey
)).body?.readData()

XCTAssertEqual(data, retrievedData)
XCTAssertEqual(data, retrievedData)

let deleteObjectInput = DeleteObjectInput(bucket: bucketName, key: objectKey)
_ = try await client.deleteObject(input: deleteObjectInput)
let deleteObjectInput = DeleteObjectInput(bucket: bucketName, key: objectKey)
_ = try await client.deleteObject(input: deleteObjectInput)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ final class S3ContentMD5HeaderTests: S3XCTestCase {
try await super.setUp()
// Generate 3 UUIDs to use as object keys and save them
for _ in 1...3 {
objectKeys.append("key-\(UUID().uuidString.split(separator: "-").first!.lowercased())")
objectKeys.append(String.uniqueID(service: "s3"))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class S3EmptyBody404Tests: S3XCTestCase {

// Perform the S3 HeadObject operation on a nonexistent object.
// This will cause the 404 error without a body.
let input = HeadObjectInput(bucket: bucketName, key: UUID().uuidString)
let input = HeadObjectInput(bucket: bucketName, key: String.uniqueID(service: "s3"))
_ = try await client.headObject(input: input)

// If an error was not thrown by the HeadObject call, fail the test.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ import XCTest
import AWSS3
import AWSClientRuntime
import SmithyIdentity
import AWSIntegrationTestUtils

class S3ErrorTests: S3XCTestCase {

func test_noSuchKey_throwsNoSuchKeyWhenUnknownKeyIsUsed() async throws {
do {
let input = GetObjectInput(bucket: bucketName, key: UUID().uuidString)
let input = GetObjectInput(bucket: bucketName, key: String.uniqueID(service: "s3-error"))
_ = try await client.getObject(input: input)
XCTFail("Request should not have succeeded")
} catch let error as NoSuchKey {
Expand All @@ -42,7 +43,7 @@ class S3ErrorTests: S3XCTestCase {

func test_requestID_hasARequestIDAndRequestID2() async throws {
do {
let input = GetObjectInput(bucket: bucketName, key: UUID().uuidString)
let input = GetObjectInput(bucket: bucketName, key: String.uniqueID(service: "s3-error"))
_ = try await client.getObject(input: input)
XCTFail("Request should not have succeeded")
} catch let error as NoSuchKey {
Expand All @@ -57,7 +58,7 @@ class S3ErrorTests: S3XCTestCase {

func test_InvalidObjectState_hasReadableProperties() async throws {
do {
let key = UUID().uuidString + ".txt"
let key = String.uniqueID(service: "s3-error") + ".txt"
let putInput = PutObjectInput(bucket: bucketName, key: key, storageClass: .glacier)
_ = try await client.putObject(input: putInput)
let getInput = GetObjectInput(bucket: bucketName, key: key)
Expand All @@ -77,7 +78,7 @@ class S3ErrorTests: S3XCTestCase {
let credentials = AWSCredentialIdentity(accessKey: "AKIDEXAMPLE", secret: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY")
let awsCredentialIdentityResolver = StaticAWSCredentialIdentityResolver(credentials)
let config = try await S3Client.S3ClientConfiguration(awsCredentialIdentityResolver: awsCredentialIdentityResolver, region: region)
let input = GetObjectInput(bucket: bucketName, key: UUID().uuidString)
let input = GetObjectInput(bucket: bucketName, key: String.uniqueID(service: "s3-error"))
_ = try await S3Client(config: config).getObject(input: input)
XCTFail("Request should not have succeeded")
} catch let error as InvalidAccessKeyId {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,40 @@ import AWSS3

final class S3ExpressIntegrationTests: S3ExpressXCTestCase {

// The number of buckets to create during the test
let n = 5

// The names of S3 buckets that were created for this test
var buckets = [String]()

// The object key & data contents to put in each bucket
let key = "hello-world.txt"
let originalContents = Data("Hello, World!".utf8)

override func tearDown() async throws {
try await super.tearDown()

// Delete the object from each bucket
for bucket in buckets {
try await deleteObject(bucket: bucket, key: key)
}

// Delete each directory bucket
for bucket in buckets {
try await deleteBucket(bucket: bucket)
}
}

// This test:
// - Creates multiple S3Express ("directory") buckets
// - Puts an object with sample contents to each bucket
// - Reads each object & compares its contents to the original data
// - Deletes the object from each bucket
// - Deletes each S3Express bucket
func test_s3Express_operationalTest() async throws {

// The number of buckets to create
let n = 5

// The object key & data contents to put in each bucket
let key = "text"
let originalContents = Data("Hello, World!".utf8)

// Create the S3Express-enabled directory buckets with random names,
// save the names for later use
var buckets = [String]()
for _ in 1...n {
let baseName = String(UUID().uuidString.prefix(8)).lowercased()
let newBucket = try await createS3ExpressBucket(baseName: baseName)
let newBucket = try await createS3ExpressBucket()
buckets.append(newBucket)
}

Expand All @@ -48,15 +61,5 @@ final class S3ExpressIntegrationTests: S3ExpressXCTestCase {
let retrievedContents = try await output.body!.readData()!
XCTAssertEqual(retrievedContents, originalContents)
}

// Delete the object from each bucket
for bucket in buckets {
try await deleteObject(bucket: bucket, key: key)
}

// Delete each directory bucket
for bucket in buckets {
try await deleteBucket(bucket: bucket)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import XCTest
import AWSS3
import AWSIntegrationTestUtils

class S3ExpressXCTestCase: XCTestCase {
// Region in which to run the test
Expand All @@ -28,10 +29,8 @@ class S3ExpressXCTestCase: XCTestCase {
}

@discardableResult
func createS3ExpressBucket(
baseName: String = String(UUID().uuidString.prefix(8)).lowercased()
) async throws -> String {
let bucket = bucket(baseName: baseName)
func createS3ExpressBucket() async throws -> String {
let bucket = bucket()
let input = CreateBucketInput(
bucket: bucket,
createBucketConfiguration: .init(
Expand All @@ -53,8 +52,8 @@ class S3ExpressXCTestCase: XCTestCase {
_ = try await client.deleteBucket(input: deleteBucketInput)
}

// Helper method to create a S3Express-compliant bucket name
func bucket(baseName: String) -> String {
"a\(baseName)--\(azID)--x-s3"
// Helper method to create a random, S3Express-compliant bucket name
func bucket() -> String {
"inttest-\(UUID().uuidString.lowercased())--\(azID)--x-s3"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import AWSS3Control
import AWSSTS
import ClientRuntime
import AWSClientRuntime
import AWSIntegrationTestUtils

/// Tests SigV4A signing flow using S3's Multi-Region Access Point (MRAP).
class S3SigV4ATests: S3XCTestCase {
Expand All @@ -29,8 +30,8 @@ class S3SigV4ATests: S3XCTestCase {
private var mrapArnFormat = "arn:aws:s3::%@:accesspoint/%@"
private var mrapArn: String!
private var mrapAlias: String!
private let mrapNamePrefix = "aws-sdk-s3-integration-test-"
private let mrapName = "aws-sdk-s3-integration-test-" + UUID().uuidString.split(separator: "-").first!.lowercased()
private let mrapNamePrefix = "sdk-inttest-"
private let mrapName = "sdk-inttest-" + UUID().uuidString.lowercased() // 3-50 chars long
private var mrapConfig: S3ControlClientTypes.CreateMultiRegionAccessPointInput!

// The S3 control client used to create and delete MRAP
Expand All @@ -41,7 +42,7 @@ class S3SigV4ATests: S3XCTestCase {
private var accountId: String!

// Key string used for putting object in tests
private let key = UUID().uuidString.split(separator: "-").first!.lowercased()
private let key = String.uniqueID(service: "s3-sigv4a")

private let NSEC_PER_SEC = 1_000_000_000

Expand Down Expand Up @@ -182,7 +183,7 @@ class S3SigV4ATests: S3XCTestCase {
// Create S3 Multi-Region Access Point (MRAP)
let createMRAPInput = CreateMultiRegionAccessPointInput(
accountId: accountId,
clientToken: UUID().uuidString.split(separator: "-").first!.lowercased(),
clientToken: UUID().uuidString.lowercased(),
details: mrapConfig
)
_ = try await s3ControlClient.createMultiRegionAccessPoint(input: createMRAPInput)
Expand Down
Loading
Loading