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

add s3 protocol tests #2667

Merged
merged 2 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
8 changes: 8 additions & 0 deletions .changelog/76710fee76664e76989335824a2df29f.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"id": "76710fee-7666-4e76-9893-35824a2df29f",
"type": "bugfix",
"description": "Add S3-specific smithy protocol tests.",
"modules": [
"service/s3"
]
}
315 changes: 315 additions & 0 deletions service/s3/manual_protocol_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,315 @@
package s3

import (
"context"
"net/http"
"strings"
"testing"

"github.com/aws/aws-sdk-go-v2/aws"
)

// This file replicates the tests in https://github.com/smithy-lang/smithy/blob/main/smithy-aws-protocol-tests/model/restXml/services/s3.smithy,
// which we cannot generate through normal protocoltest codegen due to
// requirement on handwritten source in S3.

type capturedRequest struct {
r *http.Request
}

func (cr *capturedRequest) Do(r *http.Request) (*http.Response, error) {
cr.r = r
return &http.Response{ // returns are moot, for request tests only
StatusCode: 400,
Body: http.NoBody,
}, nil
}

func TestS3Protocol_ListObjectsV2_Request(t *testing.T) {
for name, tt := range map[string]struct {
Options func(*Options)
OperationOptions func(*Options)
Input *ListObjectsV2Input

ExpectMethod string
ExpectHost string
ExpectPath string
ExpectQuery []string
}{
"S3DefaultAddressing": {
Options: func(o *Options) {
o.Region = "us-west-2"
},
OperationOptions: func(o *Options) {},
Input: &ListObjectsV2Input{
Bucket: aws.String("mybucket"),
},

ExpectMethod: "GET",
ExpectHost: "mybucket.s3.us-west-2.amazonaws.com",
ExpectPath: "/",
ExpectQuery: []string{"list-type=2"},
},
"S3VirtualHostAddressing": {
Options: func(o *Options) {
o.Region = "us-west-2"
o.UsePathStyle = false
},
OperationOptions: func(o *Options) {},
Input: &ListObjectsV2Input{
Bucket: aws.String("mybucket"),
},

ExpectMethod: "GET",
ExpectHost: "mybucket.s3.us-west-2.amazonaws.com",
ExpectPath: "/",
ExpectQuery: []string{"list-type=2"},
},
"S3PathAddressing": {
Options: func(o *Options) {
o.Region = "us-west-2"
o.UsePathStyle = true
},
OperationOptions: func(o *Options) {},
Input: &ListObjectsV2Input{
Bucket: aws.String("mybucket"),
},

ExpectMethod: "GET",
ExpectHost: "s3.us-west-2.amazonaws.com",
ExpectPath: "/mybucket",
ExpectQuery: []string{"list-type=2"},
},
"S3VirtualHostDualstackAddressing": {
Options: func(o *Options) {
o.Region = "us-west-2"
o.UsePathStyle = false
o.EndpointOptions.UseDualStackEndpoint = aws.DualStackEndpointStateEnabled
},
OperationOptions: func(o *Options) {},
Input: &ListObjectsV2Input{
Bucket: aws.String("mybucket"),
},

ExpectMethod: "GET",
ExpectHost: "mybucket.s3.dualstack.us-west-2.amazonaws.com",
ExpectPath: "/",
ExpectQuery: []string{"list-type=2"},
},
"S3VirtualHostAccelerateAddressing": {
Options: func(o *Options) {
o.Region = "us-west-2"
o.UsePathStyle = false
o.UseAccelerate = true
},
OperationOptions: func(o *Options) {},
Input: &ListObjectsV2Input{
Bucket: aws.String("mybucket"),
},

ExpectMethod: "GET",
ExpectHost: "mybucket.s3-accelerate.amazonaws.com",
ExpectPath: "/",
ExpectQuery: []string{"list-type=2"},
},
"S3VirtualHostDualstackAccelerateAddressing": {
Options: func(o *Options) {
o.Region = "us-west-2"
o.UsePathStyle = false
o.EndpointOptions.UseDualStackEndpoint = aws.DualStackEndpointStateEnabled
o.UseAccelerate = true
},
OperationOptions: func(o *Options) {},
Input: &ListObjectsV2Input{
Bucket: aws.String("mybucket"),
},

ExpectMethod: "GET",
ExpectHost: "mybucket.s3-accelerate.dualstack.amazonaws.com",
ExpectPath: "/",
ExpectQuery: []string{"list-type=2"},
},
"S3OperationAddressingPreferred": {
Options: func(o *Options) {
o.Region = "us-west-2"
o.UsePathStyle = true
},
OperationOptions: func(o *Options) {
o.UsePathStyle = false
},
Input: &ListObjectsV2Input{
Bucket: aws.String("mybucket"),
},

ExpectMethod: "GET",
ExpectHost: "mybucket.s3.us-west-2.amazonaws.com",
ExpectPath: "/",
ExpectQuery: []string{"list-type=2"},
},
} {
t.Run(name, func(t *testing.T) {
var r capturedRequest
svc := New(Options{HTTPClient: &r}, tt.Options)

svc.ListObjectsV2(context.Background(), tt.Input, tt.OperationOptions)
if r.r == nil {
t.Fatal("captured request is nil")
}

if tt.ExpectMethod != r.r.Method {
Copy link
Contributor

Choose a reason for hiding this comment

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

[nit] can we assign a variable to r.r like req so we don't have to r.r our way on all tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do test GetBucketLocationUnwrappedOutput and S3OperationNoErrorWrappingResponse on the protocol test make sense for us?

yes, added them

can we assign a variable to r.r like req

done

t.Errorf("expect method: %v != %v", tt.ExpectMethod, r.r.Method)
}
if tt.ExpectHost != r.r.URL.Host {
t.Errorf("expect host: %v != %v", tt.ExpectHost, r.r.URL.Host)
}
if tt.ExpectPath != r.r.URL.RawPath {
t.Errorf("expect path: %v != %v", tt.ExpectPath, r.r.URL.RawPath)
}
for _, q := range tt.ExpectQuery {
if !strings.Contains(r.r.URL.RawQuery, q) {
t.Errorf("query %v is missing %v", r.r.URL.RawQuery, q)
}
}
})
}
}

func TestS3Protocol_DeleteObjectTagging_Request(t *testing.T) {
for name, tt := range map[string]struct {
ClientOptions func(*Options)
OperationOptions func(*Options)
Input *DeleteObjectTaggingInput

ExpectMethod string
ExpectHost string
ExpectPath string
ExpectQuery []string
}{
"S3EscapeObjectKeyInUriLabel": {
ClientOptions: func(o *Options) {
o.Region = "us-west-2"
},
OperationOptions: func(o *Options) {},
Input: &DeleteObjectTaggingInput{
Bucket: aws.String("mybucket"),
Key: aws.String("my key.txt"),
},

ExpectMethod: "DELETE",
ExpectHost: "mybucket.s3.us-west-2.amazonaws.com",
ExpectPath: "/my%20key.txt",
ExpectQuery: []string{"tagging"},
},
"S3EscapePathObjectKeyInUriLabel": {
ClientOptions: func(o *Options) {
o.Region = "us-west-2"
},
OperationOptions: func(o *Options) {},
Input: &DeleteObjectTaggingInput{
Bucket: aws.String("mybucket"),
Key: aws.String("foo/bar/my key.txt"),
},

ExpectMethod: "DELETE",
ExpectHost: "mybucket.s3.us-west-2.amazonaws.com",
ExpectPath: "/foo/bar/my%20key.txt",
ExpectQuery: []string{"tagging"},
},
} {
t.Run(name, func(t *testing.T) {
var r capturedRequest
svc := New(Options{HTTPClient: &r}, tt.ClientOptions)

svc.DeleteObjectTagging(context.Background(), tt.Input, tt.OperationOptions)
if r.r == nil {
t.Fatal("captured request is nil")
}

if tt.ExpectMethod != r.r.Method {
t.Errorf("expect method: %v != %v", tt.ExpectMethod, r.r.Method)
}
if tt.ExpectHost != r.r.URL.Host {
t.Errorf("expect host: %v != %v", tt.ExpectHost, r.r.URL.Host)
}
if tt.ExpectPath != r.r.URL.RawPath {
t.Errorf("expect path: %v != %v", tt.ExpectPath, r.r.URL.RawPath)
}
for _, q := range tt.ExpectQuery {
if !strings.Contains(r.r.URL.RawQuery, q) {
t.Errorf("query %v is missing %v", r.r.URL.RawQuery, q)
}
}
})
}

}

func TestS3Protocol_GetObject_Request(t *testing.T) {
for name, tt := range map[string]struct {
ClientOptions func(*Options)
OperationOptions func(*Options)
Input *GetObjectInput

ExpectMethod string
ExpectHost string
ExpectPath string
ExpectQuery []string
}{
"S3PreservesLeadingDotSegmentInUriLabel": {
ClientOptions: func(o *Options) {
o.Region = "us-west-2"
o.UsePathStyle = false
},
OperationOptions: func(o *Options) {},
Input: &GetObjectInput{
Bucket: aws.String("mybucket"),
Key: aws.String("../key.txt"),
},

ExpectMethod: "GET",
ExpectHost: "mybucket.s3.us-west-2.amazonaws.com",
ExpectPath: "/../key.txt",
},
"S3PreservesEmbeddedDotSegmentInUriLabel": {
ClientOptions: func(o *Options) {
o.Region = "us-west-2"
o.UsePathStyle = false
},
OperationOptions: func(o *Options) {},
Input: &GetObjectInput{
Bucket: aws.String("mybucket"),
Key: aws.String("foo/../key.txt"),
},

ExpectMethod: "GET",
ExpectHost: "mybucket.s3.us-west-2.amazonaws.com",
ExpectPath: "/foo/../key.txt",
},
} {
t.Run(name, func(t *testing.T) {
var r capturedRequest
svc := New(Options{HTTPClient: &r}, tt.ClientOptions)

svc.GetObject(context.Background(), tt.Input, tt.OperationOptions)
if r.r == nil {
t.Fatal("captured request is nil")
}

if tt.ExpectMethod != r.r.Method {
t.Errorf("expect method: %v != %v", tt.ExpectMethod, r.r.Method)
}
if tt.ExpectHost != r.r.URL.Host {
t.Errorf("expect host: %v != %v", tt.ExpectHost, r.r.URL.Host)
}
if tt.ExpectPath != r.r.URL.RawPath {
t.Errorf("expect path: %v != %v", tt.ExpectPath, r.r.URL.RawPath)
}
for _, q := range tt.ExpectQuery {
if !strings.Contains(r.r.URL.RawQuery, q) {
t.Errorf("query %v is missing %v", r.r.URL.RawQuery, q)
}
}
})
}

}
Loading