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 ability to run protocol tests as unit tests of a service #1590

Merged
merged 59 commits into from
Jul 5, 2024
Merged
Show file tree
Hide file tree
Changes from 55 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
18bc019
add ability to run protocol tests as unit tests of a service
dayaffe Jun 25, 2024
b718463
Merge branch 'main' into day/enable-s3-tests
dayaffe Jun 25, 2024
b1e5d2d
version bump crt to 0.31
dayaffe Jun 25, 2024
9dfd788
merge 'main' into day/enable-s3-tests
dayaffe Jun 26, 2024
1bc310d
fix failing test
dayaffe Jun 26, 2024
dfaf9d9
try adding fake keys for test configuration
dayaffe Jun 27, 2024
3a3239b
try again
dayaffe Jun 27, 2024
61a49cc
use v4
dayaffe Jun 27, 2024
bd7d092
try adding env directly in the step
dayaffe Jun 27, 2024
cb92276
correctly copy protocol tests
dayaffe Jun 27, 2024
7e24e22
try different example key/secret
dayaffe Jun 27, 2024
e42ac05
update test
dayaffe Jun 27, 2024
a35df4f
try again
dayaffe Jun 27, 2024
aafe8da
try again
dayaffe Jun 27, 2024
f991512
move to right before protocol run
dayaffe Jun 27, 2024
ccbeddb
try directly in the run block
dayaffe Jun 28, 2024
6ddb43a
try again
dayaffe Jun 28, 2024
09cce79
try again
dayaffe Jun 28, 2024
5248527
add back
dayaffe Jun 28, 2024
766f4d3
remove unnecessary space
dayaffe Jun 28, 2024
f900cf3
id-token: write
dayaffe Jun 28, 2024
5e3a95e
switch to key directly
dayaffe Jun 28, 2024
026ada7
add protocol test plan
dayaffe Jun 28, 2024
a145926
also try role arn
dayaffe Jun 28, 2024
a692b03
add default region
dayaffe Jun 28, 2024
8708f5c
modifyBeforeSigning instead of transmit
dayaffe Jun 28, 2024
e4b8379
change to aws-region
dayaffe Jun 29, 2024
f225dd5
change to role arn
dayaffe Jun 29, 2024
c6b9c3a
ls to see files in path
dayaffe Jun 29, 2024
1f8c839
see if we can do showTestPlans
dayaffe Jun 30, 2024
7c4462e
see if we can do showTestPlans
dayaffe Jun 30, 2024
0369dd2
trying moving credentials up
dayaffe Jun 30, 2024
d5cfb50
move back and add fake credentials to codegen
dayaffe Jun 30, 2024
853d1e2
add back showTestPlans
dayaffe Jun 30, 2024
801b0dd
add scheme to git
dayaffe Jun 30, 2024
211bf10
update path
dayaffe Jul 1, 2024
2186c86
-testPlan doesnt need folder name
dayaffe Jul 1, 2024
5e19b27
add fake environment variables to test plan
dayaffe Jul 1, 2024
805f93e
add credentials to codegen
dayaffe Jul 1, 2024
6d15ac4
add token-write permission
dayaffe Jul 1, 2024
052419a
try -env flag
dayaffe Jul 1, 2024
dc284ac
try adding it into jobs env
dayaffe Jul 1, 2024
d0f13c0
try again
dayaffe Jul 1, 2024
9e0a641
use valid dummy creds
dayaffe Jul 1, 2024
4f00274
try role arn
dayaffe Jul 1, 2024
0526c43
try again
dayaffe Jul 1, 2024
2a4e5fa
try again
dayaffe Jul 1, 2024
ab4025d
try adding env directly to step
dayaffe Jul 1, 2024
e36b8a0
try again and again
dayaffe Jul 1, 2024
6f93e8c
try creating a ~/.aws/config with a default profile
dayaffe Jul 1, 2024
06c7a6f
create credentials file too
dayaffe Jul 1, 2024
5006c7a
cleanup workflow files
dayaffe Jul 2, 2024
be7f27b
update codegen tests + use new static endpoint resolver
dayaffe Jul 3, 2024
36f265f
Merge branch 'main' into day/enable-s3-tests
dayaffe Jul 3, 2024
8cc787f
clean up github workflows
dayaffe Jul 3, 2024
6d0c925
add back NSUnbufferedIO=YES
dayaffe Jul 5, 2024
ca4f03d
Merge branch 'main' into day/enable-s3-tests
jbelkins Jul 5, 2024
4607457
try using env creds on linux
dayaffe Jul 5, 2024
482b44e
try using profile creds on linux
dayaffe Jul 5, 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
14 changes: 14 additions & 0 deletions .github/workflows/codegen-build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,19 @@ jobs:
run: ./scripts/ci_steps/codegen_sdk.sh
- name: Build SDK with Unit Tests
run: swift build --build-tests

# Configure credentials for use during special protocol tests run against real clients
# Since environment variables are modified by some tests profiles are used instead
- name: Create AWS config directory
jbelkins marked this conversation as resolved.
Show resolved Hide resolved
run: mkdir -p ~/.aws
- name: Create AWS config file
run: |
echo "[default]" > ~/.aws/config
echo "region=us-west-2" >> ~/.aws/config
- name: Create AWS credentials file
run: |
echo "[default]" > ~/.aws/credentials
echo "aws_access_key_id = test-key-id" >> ~/.aws/credentials
echo "aws_secret_access_key = test-secret-access-key" >> ~/.aws/credentials
- name: Run Unit Tests
run: swift test --skip-build
11 changes: 10 additions & 1 deletion .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ on:
env:
AWS_SWIFT_SDK_USE_LOCAL_DEPS: 1

permissions:
id-token: write

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you sure we can't get rid of these extra permissions in CI? IIRC this is needed to get AWS credentials through OpenID which we don't do in the CI workflow.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the linux side I'm using aws-actions/configure-aws-credentials@v3 still. Would rather I try to change this one to fake credentials?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, let's not get real credentials where fake ones will do

jobs:
apple:
runs-on: ${{ matrix.runner }}
Expand Down Expand Up @@ -109,8 +112,9 @@ jobs:
run: |
cd codegen/
set -o pipefail && \
NSUnbufferedIO=YES xcodebuild \
xcodebuild \
jbelkins marked this conversation as resolved.
Show resolved Hide resolved
-scheme aws-sdk-swift-protocol-tests-Package \
-testPlan ProtocolTestPlan \
-destination '${{ matrix.destination }}' \
test 2>&1 \
| xcbeautify
Expand Down Expand Up @@ -173,6 +177,11 @@ jobs:
run: ./scripts/ci_steps/install_native_linux_dependencies.sh
- name: Tools Versions
run: ./scripts/ci_steps/log_tool_versions.sh
- name: Configure AWS Credentials for Integration Tests
uses: aws-actions/configure-aws-credentials@v3
with:
role-to-assume: ${{ secrets.INTEGRATION_TEST_ROLE_ARN }}
aws-region: us-west-2
jbelkins marked this conversation as resolved.
Show resolved Hide resolved
- name: Prepare Protocol & Unit Tests
run: |
./scripts/ci_steps/prepare_protocol_and_unit_tests.sh
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import AwsCommonRuntimeKit
import ClientRuntime
import SmithyHTTPAPI
import struct Foundation.Data
import struct Smithy.AttributeKey

public struct Sha256TreeHashMiddleware<OperationStackInput, OperationStackOutput>: Middleware {
public let id: String = "Sha256TreeHash"
Expand All @@ -24,11 +25,11 @@ public struct Sha256TreeHashMiddleware<OperationStackInput, OperationStackOutput
Self.MInput == H.Input,
Self.MOutput == H.Output {
let request = input.build()
try await addHashes(request: request, builder: input)
try await addHashes(request: request, builder: input, context: context)
return try await next.handle(context: context, input: input)
}

private func addHashes(request: SdkHttpRequest, builder: SdkHttpRequestBuilder) async throws {
private func addHashes(request: SdkHttpRequest, builder: SdkHttpRequestBuilder, context: Context) async throws {
switch request.body {
case .data(let data):
guard let data = data else {
Expand Down Expand Up @@ -57,7 +58,8 @@ public struct Sha256TreeHashMiddleware<OperationStackInput, OperationStackOutput
let (linearHash, treeHash) = try computeHashes(data: streamBytes)
if let treeHash = treeHash, let linearHash = linearHash {
builder.withHeader(name: X_AMZ_SHA256_TREE_HASH_HEADER_NAME, value: treeHash)
builder.withHeader(name: X_AMZ_CONTENT_SHA256_HEADER_NAME, value: linearHash)
// provide the value but let CRT add the SHA256 header during signing
jbelkins marked this conversation as resolved.
Show resolved Hide resolved
context.attributes.set(key: AttributeKey(name: X_AMZ_CONTENT_SHA256_HEADER_NAME), value: linearHash)
}
case .noStream:
break
Expand Down Expand Up @@ -110,10 +112,10 @@ extension Sha256TreeHashMiddleware: HttpInterceptor {
public typealias InputType = OperationStackInput
public typealias OutputType = OperationStackOutput

public func modifyBeforeTransmit(context: some MutableRequest<Self.InputType, Self.RequestType>) async throws {
public func modifyBeforeSigning(context: some MutableRequest<Self.InputType, Self.RequestType>) async throws {
jbelkins marked this conversation as resolved.
Show resolved Hide resolved
let request = context.getRequest()
let builder = request.toBuilder()
try await addHashes(request: request, builder: builder)
try await addHashes(request: request, builder: builder, context: context.getAttributes())
context.updateRequest(updated: builder.build())
}
}
15 changes: 12 additions & 3 deletions Sources/Core/AWSSDKHTTPAuth/AWSSigV4Signer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,13 @@ public class AWSSigV4Signer: SmithyHTTPAuthAPI.Signer {
// Determine signed body value
let checksumIsPresent = signingProperties.get(key: SigningPropertyKeys.checksum) != nil
let isChunkedEligibleStream = signingProperties.get(key: SigningPropertyKeys.isChunkedEligibleStream) ?? false
let preComputedSha256 = signingProperties.get(key: AttributeKey<String>(name: "SignedBodyValue"))

let signedBodyValue: AWSSignedBodyValue = determineSignedBodyValue(
checksumIsPresent: checksumIsPresent,
isChunkedEligbleStream: isChunkedEligibleStream,
isUnsignedBody: unsignedBody
isUnsignedBody: unsignedBody,
preComputedSha256: preComputedSha256
)

let flags: SigningFlags = SigningFlags(
Expand Down Expand Up @@ -240,11 +242,18 @@ public class AWSSigV4Signer: SmithyHTTPAuthAPI.Signer {
private func determineSignedBodyValue(
checksumIsPresent: Bool,
isChunkedEligbleStream: Bool,
isUnsignedBody: Bool
isUnsignedBody: Bool,
preComputedSha256: String?
) -> AWSSignedBodyValue {
if !isChunkedEligbleStream {
// Normal Payloads, Event Streams, etc.
return isUnsignedBody ? .unsignedPayload : .empty
if isUnsignedBody {
return .unsignedPayload
} else if let sha256 = preComputedSha256 {
return .precomputed(sha256)
} else {
return .empty
}
}

// streaming + eligible for chunked transfer
Expand Down
5 changes: 5 additions & 0 deletions Sources/Services/AWSS3/Sources/AWSS3/Endpoints.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import class ClientRuntime.EndpointsRequestContext
import let AWSClientRuntime.awsPartitionJSON
import protocol ClientRuntime.EndpointsRequestContextProviding
import struct ClientRuntime.DefaultEndpointResolver
import struct ClientRuntime.StaticEndpointResolver
import struct SmithyHTTPAPI.Endpoint

public struct EndpointParams {
Expand Down Expand Up @@ -150,3 +151,7 @@ extension DefaultEndpointResolver {
}

extension DefaultEndpointResolver: EndpointResolver {}

typealias StaticEndpointResolver = ClientRuntime.StaticEndpointResolver<EndpointParams>

extension StaticEndpointResolver: EndpointResolver {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Code generated by smithy-swift-codegen. DO NOT EDIT!

@testable import AWSS3
import ClientRuntime
import Smithy
import SmithyTestUtil
import XCTest


class DeleteObjectTaggingRequestTest: HttpRequestTestBase {
/// S3 clients should escape special characters in Object Keys when the Object Key is used as a URI label binding.
func testProtocol_S3EscapeObjectKeyInUriLabel() async throws {
let urlPrefix = urlPrefixFromHost(host: "s3.us-west-2.amazonaws.com")
let hostOnly = hostOnlyFromHost(host: "s3.us-west-2.amazonaws.com")
let expected = buildExpectedHttpRequest(
method: .delete,
path: "/my%20key.txt",
queryParams: [
"tagging"
],
body: nil,
host: "s3.us-west-2.amazonaws.com",
resolvedHost: "mybucket.s3.us-west-2.amazonaws.com"
)

let config = try await S3Client.S3ClientConfiguration()
config.region = "us-west-2"
config.httpClientEngine = ProtocolTestClient()
config.idempotencyTokenGenerator = ProtocolTestIdempotencyTokenGenerator()
let client = S3Client(config: config)

let input = DeleteObjectTaggingInput(
bucket: "mybucket",
key: "my key.txt"
)
do {
_ = try await client.deleteObjectTagging(input: input)
} catch TestCheckError.actual(let actual) {
try await self.assertEqual(expected, actual)
}
}
/// S3 clients should preserve an Object Key representing a path when the Object Key is used as a URI label binding, but still escape special characters.
func testProtocol_S3EscapePathObjectKeyInUriLabel() async throws {
let urlPrefix = urlPrefixFromHost(host: "s3.us-west-2.amazonaws.com")
let hostOnly = hostOnlyFromHost(host: "s3.us-west-2.amazonaws.com")
let expected = buildExpectedHttpRequest(
method: .delete,
path: "/foo/bar/my%20key.txt",
queryParams: [
"tagging"
],
body: nil,
host: "s3.us-west-2.amazonaws.com",
resolvedHost: "mybucket.s3.us-west-2.amazonaws.com"
)

let config = try await S3Client.S3ClientConfiguration()
config.region = "us-west-2"
config.httpClientEngine = ProtocolTestClient()
config.idempotencyTokenGenerator = ProtocolTestIdempotencyTokenGenerator()
let client = S3Client(config: config)

let input = DeleteObjectTaggingInput(
bucket: "mybucket",
key: "foo/bar/my key.txt"
)
do {
_ = try await client.deleteObjectTagging(input: input)
} catch TestCheckError.actual(let actual) {
try await self.assertEqual(expected, actual)
}
}
}
68 changes: 68 additions & 0 deletions Sources/Services/AWSS3/Tests/AWSS3Tests/GetObjectRequestTest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Code generated by smithy-swift-codegen. DO NOT EDIT!

@testable import AWSS3
import ClientRuntime
import Foundation
import Smithy
import SmithyTestUtil
import XCTest


class GetObjectRequestTest: HttpRequestTestBase {
/// S3 clients should not remove dot segments from request paths.
func testProtocol_S3PreservesLeadingDotSegmentInUriLabel() async throws {
let urlPrefix = urlPrefixFromHost(host: "s3.us-west-2.amazonaws.com")
let hostOnly = hostOnlyFromHost(host: "s3.us-west-2.amazonaws.com")
let expected = buildExpectedHttpRequest(
method: .get,
path: "/../key.txt",
body: nil,
host: "s3.us-west-2.amazonaws.com",
resolvedHost: "mybucket.s3.us-west-2.amazonaws.com"
)

let config = try await S3Client.S3ClientConfiguration()
config.region = "us-west-2"
config.httpClientEngine = ProtocolTestClient()
config.idempotencyTokenGenerator = ProtocolTestIdempotencyTokenGenerator()
let client = S3Client(config: config)

let input = GetObjectInput(
bucket: "mybucket",
key: "../key.txt"
)
do {
_ = try await client.getObject(input: input)
} catch TestCheckError.actual(let actual) {
try await self.assertEqual(expected, actual)
}
}
/// S3 clients should not remove dot segments from request paths.
func testProtocol_S3PreservesEmbeddedDotSegmentInUriLabel() async throws {
let urlPrefix = urlPrefixFromHost(host: "s3.us-west-2.amazonaws.com")
let hostOnly = hostOnlyFromHost(host: "s3.us-west-2.amazonaws.com")
let expected = buildExpectedHttpRequest(
method: .get,
path: "/foo/../key.txt",
body: nil,
host: "s3.us-west-2.amazonaws.com",
resolvedHost: "mybucket.s3.us-west-2.amazonaws.com"
)

let config = try await S3Client.S3ClientConfiguration()
config.region = "us-west-2"
config.httpClientEngine = ProtocolTestClient()
config.idempotencyTokenGenerator = ProtocolTestIdempotencyTokenGenerator()
let client = S3Client(config: config)

let input = GetObjectInput(
bucket: "mybucket",
key: "foo/../key.txt"
)
do {
_ = try await client.getObject(input: input)
} catch TestCheckError.actual(let actual) {
try await self.assertEqual(expected, actual)
}
}
}
81 changes: 81 additions & 0 deletions Tests/AdditionalServiceTests/AWSS3/models/s3-tests.smithy
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
$version: "1.0"

namespace com.amazonaws.s3
use smithy.test#httpRequestTests

apply DeleteObjectTagging @httpRequestTests([
{
"id": "Protocol_S3EscapeObjectKeyInUriLabel",
"documentation": " S3 clients should escape special characters in Object Keys\n when the Object Key is used as a URI label binding.\n",
"protocol": "aws.protocols#restXml",
"method": "DELETE",
"uri": "/my%20key.txt",
"host": "s3.us-west-2.amazonaws.com",
"resolvedHost": "mybucket.s3.us-west-2.amazonaws.com",
"body": "",
"queryParams": [
"tagging"
],
"params": {
"Bucket": "mybucket",
"Key": "my key.txt"
}
},
{
"id": "Protocol_S3EscapePathObjectKeyInUriLabel",
"documentation": " S3 clients should preserve an Object Key representing a path\n when the Object Key is used as a URI label binding, but still\n escape special characters.\n",
"protocol": "aws.protocols#restXml",
"method": "DELETE",
"uri": "/foo/bar/my%20key.txt",
"host": "s3.us-west-2.amazonaws.com",
"resolvedHost": "mybucket.s3.us-west-2.amazonaws.com",
"body": "",
"queryParams": [
"tagging"
],
"params": {
"Bucket": "mybucket",
"Key": "foo/bar/my key.txt"
}
}
])
@http(
method: "DELETE",
uri: "/{Bucket}/{Key+}?tagging",
code: 204
)
operation DeleteObjectTagging {
input: DeleteObjectTaggingRequest
output: DeleteObjectTaggingOutput
}

apply GetObject @httpRequestTests([
{
"id": "Protocol_S3PreservesLeadingDotSegmentInUriLabel",
"documentation": " S3 clients should not remove dot segments from request paths.\n",
"protocol": "aws.protocols#restXml",
"method": "GET",
"uri": "/../key.txt",
"host": "s3.us-west-2.amazonaws.com",
"resolvedHost": "mybucket.s3.us-west-2.amazonaws.com",
"body": "",
"params": {
"Bucket": "mybucket",
"Key": "../key.txt"
}
},
{
"id": "Protocol_S3PreservesEmbeddedDotSegmentInUriLabel",
"documentation": " S3 clients should not remove dot segments from request paths.\n",
"protocol": "aws.protocols#restXml",
"method": "GET",
"uri": "/foo/../key.txt",
"host": "s3.us-west-2.amazonaws.com",
"resolvedHost": "mybucket.s3.us-west-2.amazonaws.com",
"body": "",
"params": {
"Bucket": "mybucket",
"Key": "foo/../key.txt"
}
}
])
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class Sha256TreeHashMiddlewareTests: XCTestCase {
let output = OperationOutput<MockOutput>(httpResponse: mockHttpResponse, output: mockOutput)
stack.finalizeStep.intercept(position: .after, middleware: Sha256TreeHashMiddleware<MockStreamInput, MockOutput>())
_ = try await stack.handleMiddleware(context: context, input: streamInput, next: MockHandler(handleCallback: { context, input in
let linear = input.headers.value(for: "X-Amz-Content-Sha256")
let linear = context.get(key: AttributeKey<String>(name: "X-Amz-Content-Sha256"))
XCTAssertEqual(linear, "733cf513448ce6b20ad1bc5e50eb27c06aefae0c320713a5dd99f4e51bc1ca60")
let treeHash = input.headers.value(for: "X-Amz-Sha256-Tree-Hash")
XCTAssertEqual(treeHash, "a3a82dbe3644dd6046be472f2e3ec1f8ef47f8f3adb86d0de4de7a254f255455")
Expand Down
Loading
Loading