Skip to content

Commit d46f1bb

Browse files
authored
Add S3 access point test (#746)
* Add S3 access point test * More virtual addressing fixes
1 parent 3b62b62 commit d46f1bb

File tree

2 files changed

+122
-25
lines changed

2 files changed

+122
-25
lines changed

Tests/SotoTests/Services/S3/S3ExtensionTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,8 +377,8 @@ extension S3Tests {
377377
"https://s3.us-east-1.amazonaws.com/bucket/file%20name",
378378
s3URL: "https://bucket.s3.us-east-1.amazonaws.com/file%20name"
379379
)
380-
try await self.testS3VirtualAddressing("http://localhost:8000/bucket/filename", s3URL: "http://localhost:8000/bucket/filename")
381-
try await self.testS3VirtualAddressing("http://localhost:8000/bucket//filename", s3URL: "http://localhost:8000/bucket//filename")
380+
try await self.testS3VirtualAddressing("http://localhost:8000/bucket1/filename", s3URL: "http://localhost:8000/bucket1/filename")
381+
try await self.testS3VirtualAddressing("http://localhost:8000/bucket2//filename", s3URL: "http://localhost:8000/bucket2//filename")
382382
try await self.testS3VirtualAddressing("https://localhost:8000/bucket/file%20name", s3URL: "https://localhost:8000/bucket/file%20name")
383383

384384
let s3 = Self.s3.with(options: .s3ForceVirtualHost)

Tests/SotoTests/Services/S3/S3Tests.swift

Lines changed: 120 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ import AsyncHTTPClient
1616
import Atomics
1717
import NIOCore
1818
import NIOPosix
19-
import SotoCore
2019
import XCTest
2120

21+
@testable import SotoCore
2222
@testable import SotoS3
2323
@testable import SotoS3Control
2424

@@ -68,7 +68,10 @@ class S3Tests: XCTestCase {
6868
}
6969

7070
static func deleteBucket(name: String, s3: S3) async throws {
71-
let response = try await s3.listObjectsV2(.init(bucket: name), logger: TestEnvironment.logger)
71+
let response = try await s3.listObjectsV2(
72+
.init(bucket: name),
73+
logger: TestEnvironment.logger
74+
)
7275
if let contents = response.contents {
7376
let request = S3.DeleteObjectsRequest(
7477
bucket: name,
@@ -80,7 +83,13 @@ class S3Tests: XCTestCase {
8083
}
8184

8285
/// create S3 bucket with supplied name and run supplied closure
83-
func testBucket(_ name: String, s3: S3? = nil, test: @escaping (String) async throws -> Void) async throws {
86+
func testBucket(
87+
_ name: String,
88+
s3: S3? = nil,
89+
test: @escaping (String) async throws -> Void
90+
)
91+
async throws
92+
{
8493
let s3 = s3 ?? Self.s3!
8594
try await XCTTestAsset {
8695
try await Self.createBucket(name: name, s3: s3)
@@ -93,7 +102,14 @@ class S3Tests: XCTestCase {
93102
}
94103

95104
/// Test putObject to S3 and that getObject returns the same object
96-
func testPutGetObject(bucket: String, filename: String, contents: AWSHTTPBody, s3: S3? = nil) async throws {
105+
func testPutGetObject(
106+
bucket: String,
107+
filename: String,
108+
contents: AWSHTTPBody,
109+
s3: S3? = nil
110+
)
111+
async throws
112+
{
97113
let s3 = s3 ?? Self.s3!
98114
try await self.testBucket(bucket, s3: s3) { name in
99115
let putRequest = S3.PutObjectRequest(
@@ -103,7 +119,9 @@ class S3Tests: XCTestCase {
103119
)
104120
let putResponse = try await s3.putObject(putRequest)
105121
XCTAssertNotNil(putResponse.eTag)
106-
let getResponse = try await s3.getObject(.init(bucket: name, key: filename, responseExpires: Date()))
122+
let getResponse = try await s3.getObject(
123+
.init(bucket: name, key: filename, responseExpires: Date())
124+
)
107125
let requestContents = try await contents.collect(upTo: .max)
108126
let responseContents = try await getResponse.body.collect(upTo: .max)
109127
XCTAssertEqual(responseContents, requestContents)
@@ -150,9 +168,15 @@ class S3Tests: XCTestCase {
150168
)
151169
let putResponse = try await Self.s3.putObject(putRequest)
152170
XCTAssertNotNil(putResponse.eTag)
153-
let copyRequest = S3.CopyObjectRequest(bucket: name, copySource: "\(name)/\(keyName)", key: newKeyName)
171+
let copyRequest = S3.CopyObjectRequest(
172+
bucket: name,
173+
copySource: "\(name)/\(keyName)",
174+
key: newKeyName
175+
)
154176
_ = try await Self.s3.copyObject(copyRequest)
155-
let getResponse = try await Self.s3.getObject(.init(bucket: name, key: newKeyName, responseExpires: Date()))
177+
let getResponse = try await Self.s3.getObject(
178+
.init(bucket: name, key: newKeyName, responseExpires: Date())
179+
)
156180
let responseContents = try await getResponse.body.collect(upTo: .max)
157181
XCTAssertEqual(String(buffer: responseContents), contents)
158182
XCTAssertNotNil(getResponse.lastModified)
@@ -208,7 +232,11 @@ class S3Tests: XCTestCase {
208232
let name = TestEnvironment.generateResourceName()
209233
let contents = "testing S3.ListObjectsV2"
210234
try await self.testBucket(name) { name in
211-
let putRequest = S3.PutObjectRequest(body: .init(string: contents), bucket: name, key: name)
235+
let putRequest = S3.PutObjectRequest(
236+
body: .init(string: contents),
237+
bucket: name,
238+
key: name
239+
)
212240
let putResponse = try await Self.s3.putObject(putRequest)
213241
let eTag = putResponse.eTag
214242
let listResponse = try await Self.s3.listObjectsV2(.init(bucket: name))
@@ -269,7 +297,10 @@ class S3Tests: XCTestCase {
269297
throw Disable100CompleteError(header: request.headers["Expect"].first)
270298
}
271299
}
272-
let s3 = Self.s3.with(middleware: Disable100CompleteMiddleware(), options: .s3Disable100Continue)
300+
let s3 = Self.s3.with(
301+
middleware: Disable100CompleteMiddleware(),
302+
options: .s3Disable100Continue
303+
)
273304
let name = TestEnvironment.generateResourceName()
274305
let byteBuffer = Self.createRandomBuffer(size: 8 * 1024)
275306

@@ -291,7 +322,8 @@ class S3Tests: XCTestCase {
291322
let name = TestEnvironment.generateResourceName()
292323
try await self.testBucket(name) { name in
293324
// set lifecycle rules
294-
let incompleteMultipartUploads = S3.AbortIncompleteMultipartUpload(daysAfterInitiation: 7) // clear incomplete multipart uploads after 7 days
325+
// clear incomplete multipart uploads after 7 days
326+
let incompleteMultipartUploads = S3.AbortIncompleteMultipartUpload(daysAfterInitiation: 7)
295327
let filter = S3.LifecycleRuleFilter(prefix: "") // everything
296328
let transitions = [S3.Transition(days: 14, storageClass: .glacier)] // transition objects to glacier after 14 days
297329
let lifecycleRules = S3.LifecycleRule(
@@ -301,13 +333,19 @@ class S3Tests: XCTestCase {
301333
status: .enabled,
302334
transitions: transitions
303335
)
304-
let request = S3.PutBucketLifecycleConfigurationRequest(bucket: name, lifecycleConfiguration: .init(rules: [lifecycleRules]))
336+
let request = S3.PutBucketLifecycleConfigurationRequest(
337+
bucket: name,
338+
lifecycleConfiguration: .init(rules: [lifecycleRules])
339+
)
305340
_ = try await Self.s3.putBucketLifecycleConfiguration(request)
306341

307342
let getResponse = try await Self.s3.getBucketLifecycleConfiguration(.init(bucket: name))
308343
XCTAssertEqual(getResponse.rules?[0].transitions?[0].storageClass, .glacier)
309344
XCTAssertEqual(getResponse.rules?[0].transitions?[0].days, 14)
310-
XCTAssertEqual(getResponse.rules?[0].abortIncompleteMultipartUpload?.daysAfterInitiation, 7)
345+
XCTAssertEqual(
346+
getResponse.rules?[0].abortIncompleteMultipartUpload?.daysAfterInitiation,
347+
7
348+
)
311349
}
312350
}
313351

@@ -343,7 +381,9 @@ class S3Tests: XCTestCase {
343381
key: name
344382
)
345383
_ = try await Self.s3.putObject(putRequest)
346-
let getACLResponse = try await Self.s3.getObjectAcl(.init(bucket: name, key: name, requestPayer: .requester))
384+
let getACLResponse = try await Self.s3.getObjectAcl(
385+
.init(bucket: name, key: name, requestPayer: .requester)
386+
)
347387
print(getACLResponse)
348388
}
349389
}
@@ -354,7 +394,9 @@ class S3Tests: XCTestCase {
354394
try await _ = (0..<16).concurrentMap {
355395
let body = "testMultipleUpload - " + $0.description
356396
let filename = "file" + $0.description
357-
_ = try await Self.s3.putObject(.init(body: .init(string: body), bucket: name, key: filename))
397+
_ = try await Self.s3.putObject(
398+
.init(body: .init(string: body), bucket: name, key: filename)
399+
)
358400
}
359401

360402
let paginator = Self.s3.listObjectsV2Paginator(.init(bucket: name, maxKeys: 5))
@@ -385,7 +427,10 @@ class S3Tests: XCTestCase {
385427
try await self.testPutGetObject(
386428
bucket: name,
387429
filename: "testfile.txt",
388-
contents: .init(asyncSequence: byteBuffer.asyncSequence(chunkSize: chunkSize), length: byteBuffer.readableBytes),
430+
contents: .init(
431+
asyncSequence: byteBuffer.asyncSequence(chunkSize: chunkSize),
432+
length: byteBuffer.readableBytes
433+
),
389434
s3: s3
390435
)
391436
}
@@ -421,11 +466,17 @@ class S3Tests: XCTestCase {
421466
try XCTSkipIf(TestEnvironment.isUsingLocalstack)
422467

423468
let name = TestEnvironment.generateResourceName()
424-
let s3Url = URL(string: "https://\(name).s3.us-east-1.amazonaws.com/\(name)!=%25+/(*)_.txt")!
469+
let s3Url = URL(
470+
string: "https://\(name).s3.us-east-1.amazonaws.com/\(name)!=%25+/(*)_.txt"
471+
)!
425472

426473
try await testBucket(name) { _ in
427474
let byteBuffer = Self.createRandomBuffer(size: 186)
428-
let putURL = try await Self.s3.signURL(url: s3Url, httpMethod: .PUT, expires: .minutes(5))
475+
let putURL = try await Self.s3.signURL(
476+
url: s3Url,
477+
httpMethod: .PUT,
478+
expires: .minutes(5)
479+
)
429480
var request = HTTPClientRequest(url: putURL.absoluteString)
430481
request.method = .PUT
431482
request.body = .bytes(byteBuffer)
@@ -435,8 +486,15 @@ class S3Tests: XCTestCase {
435486
let listResponse = try await Self.s3.listObjectsV2(.init(bucket: name))
436487
XCTAssertEqual(listResponse.contents?.first?.key, "\(name)!=%+/(*)_.txt")
437488

438-
let getURL = try await Self.s3.signURL(url: s3Url, httpMethod: .GET, expires: .minutes(5))
439-
let getResponse = try await HTTPClient.shared.execute(.init(url: getURL.absoluteString), timeout: .minutes(1))
489+
let getURL = try await Self.s3.signURL(
490+
url: s3Url,
491+
httpMethod: .GET,
492+
expires: .minutes(5)
493+
)
494+
let getResponse = try await HTTPClient.shared.execute(
495+
.init(url: getURL.absoluteString),
496+
timeout: .minutes(1)
497+
)
440498

441499
let getBuffer = try await getResponse.body.collect(upTo: .max)
442500
XCTAssertEqual(response.status, .ok)
@@ -523,7 +581,10 @@ class S3Tests: XCTestCase {
523581
let filename = "testfile.txt"
524582
let contents = "testing S3.PutObject and S3.GetObject"
525583
// set acceleration configuration
526-
let request = S3.PutBucketAccelerateConfigurationRequest(accelerateConfiguration: .init(status: .enabled), bucket: name)
584+
let request = S3.PutBucketAccelerateConfigurationRequest(
585+
accelerateConfiguration: .init(status: .enabled),
586+
bucket: name
587+
)
527588
_ = try await Self.s3.putBucketAccelerateConfiguration(request)
528589

529590
let putRequest = S3.PutObjectRequest(
@@ -533,7 +594,9 @@ class S3Tests: XCTestCase {
533594
)
534595
let putResponse = try await s3Accelerated.putObject(putRequest)
535596
XCTAssertNotNil(putResponse.eTag)
536-
let getResponse = try await s3Accelerated.getObject(.init(bucket: name, key: filename, responseExpires: Date()))
597+
let getResponse = try await s3Accelerated.getObject(
598+
.init(bucket: name, key: filename, responseExpires: Date())
599+
)
537600
let responseContents = try await getResponse.body.collect(upTo: .max)
538601
XCTAssertEqual(String(buffer: responseContents), contents)
539602
XCTAssertNotNil(getResponse.lastModified)
@@ -546,7 +609,9 @@ class S3Tests: XCTestCase {
546609
let filename = "testfile.txt"
547610
let contents = "testing S3.PutObject and S3.GetObject"
548611

549-
_ = try await Self.s3.putObject(.init(body: .init(string: contents), bucket: name, key: filename))
612+
_ = try await Self.s3.putObject(
613+
.init(body: .init(string: contents), bucket: name, key: filename)
614+
)
550615
try await Self.s3.waitUntilObjectExists(.init(bucket: name, key: filename))
551616

552617
_ = try await Self.s3.deleteObject(.init(bucket: name, key: filename))
@@ -577,7 +642,9 @@ class S3Tests: XCTestCase {
577642
throw CancelError()
578643
}
579644
}
580-
let s3Control = S3Control(client: Self.client, region: .euwest1).with(middleware: CheckHostMiddleware())
645+
let s3Control = S3Control(client: Self.client, region: .euwest1).with(
646+
middleware: CheckHostMiddleware()
647+
)
581648
let request = S3Control.ListJobsRequest(accountId: "123456780123")
582649
do {
583650
_ = try await s3Control.listJobs(request)
@@ -636,4 +703,34 @@ class S3Tests: XCTestCase {
636703
}
637704
}
638705
}
706+
707+
/// test S3 control host is prefixed with account id
708+
func testS3AccessPoints() async throws {
709+
// doesnt work with LocalStack
710+
try XCTSkipIf(TestEnvironment.isUsingLocalstack)
711+
guard let accountId = Environment["AWS_ACCOUNT_ID"] else { throw XCTSkip() }
712+
let name = TestEnvironment.generateResourceName()
713+
try await self.testBucket(name) { name in
714+
let s3Control = S3Control(client: Self.client, region: Self.s3.region)
715+
let response = try await s3Control.createAccessPoint(
716+
accountId: accountId,
717+
bucket: name,
718+
name: "test-accesspoint",
719+
logger: TestEnvironment.logger
720+
)
721+
return try await withTeardown {
722+
let accessPointArn = try XCTUnwrap(response.accessPointArn)
723+
let alias = try XCTUnwrap(response.alias)
724+
let string = "testing S3.PutObject and S3.GetObject"
725+
// upload using arn
726+
_ = try await Self.s3.putObject(body: .init(string: string), bucket: accessPointArn, key: name, logger: TestEnvironment.logger)
727+
// download using alias
728+
let getObjectResponse = try await Self.s3.getObject(bucket: alias, key: name, logger: TestEnvironment.logger)
729+
let body = try await getObjectResponse.body.collect(upTo: .max)
730+
XCTAssertEqual(String(buffer: body), string)
731+
} teardown: {
732+
try? await s3Control.deleteAccessPoint(accountId: accountId, name: "test-accesspoint", logger: TestEnvironment.logger)
733+
}
734+
}
735+
}
639736
}

0 commit comments

Comments
 (0)