1package s3_test 2 3import ( 4 "encoding/json" 5 "net/url" 6 "os" 7 "path/filepath" 8 "strings" 9 "testing" 10 11 "github.com/aws/aws-sdk-go/aws" 12 "github.com/aws/aws-sdk-go/aws/awserr" 13 "github.com/aws/aws-sdk-go/aws/endpoints" 14 "github.com/aws/aws-sdk-go/awstesting/unit" 15 "github.com/aws/aws-sdk-go/service/s3" 16) 17 18type s3BucketTest struct { 19 bucket string 20 url string 21 errCode string 22} 23 24var ( 25 sslTests = []s3BucketTest{ 26 {"abc", "https://abc.s3.mock-region.amazonaws.com/", ""}, 27 {"a$b$c", "https://s3.mock-region.amazonaws.com/a%24b%24c", ""}, 28 {"a.b.c", "https://s3.mock-region.amazonaws.com/a.b.c", ""}, 29 {"a..bc", "https://s3.mock-region.amazonaws.com/a..bc", ""}, 30 } 31 32 nosslTests = []s3BucketTest{ 33 {"a.b.c", "http://a.b.c.s3.mock-region.amazonaws.com/", ""}, 34 {"a..bc", "http://s3.mock-region.amazonaws.com/a..bc", ""}, 35 } 36 37 forcepathTests = []s3BucketTest{ 38 {"abc", "https://s3.mock-region.amazonaws.com/abc", ""}, 39 {"a$b$c", "https://s3.mock-region.amazonaws.com/a%24b%24c", ""}, 40 {"a.b.c", "https://s3.mock-region.amazonaws.com/a.b.c", ""}, 41 {"a..bc", "https://s3.mock-region.amazonaws.com/a..bc", ""}, 42 } 43 44 accelerateTests = []s3BucketTest{ 45 {"abc", "https://abc.s3-accelerate.amazonaws.com/", ""}, 46 {"a.b.c", "https://s3.mock-region.amazonaws.com/%7BBucket%7D", "InvalidParameterException"}, 47 {"a$b$c", "https://s3.mock-region.amazonaws.com/%7BBucket%7D", "InvalidParameterException"}, 48 } 49 50 accelerateNoSSLTests = []s3BucketTest{ 51 {"abc", "http://abc.s3-accelerate.amazonaws.com/", ""}, 52 {"a.b.c", "http://a.b.c.s3-accelerate.amazonaws.com/", ""}, 53 {"a$b$c", "http://s3.mock-region.amazonaws.com/%7BBucket%7D", "InvalidParameterException"}, 54 } 55 56 accelerateDualstack = []s3BucketTest{ 57 {"abc", "https://abc.s3-accelerate.dualstack.amazonaws.com/", ""}, 58 {"a.b.c", "https://s3.dualstack.mock-region.amazonaws.com/%7BBucket%7D", "InvalidParameterException"}, 59 {"a$b$c", "https://s3.dualstack.mock-region.amazonaws.com/%7BBucket%7D", "InvalidParameterException"}, 60 } 61) 62 63func runTests(t *testing.T, svc *s3.S3, tests []s3BucketTest) { 64 for i, test := range tests { 65 req, _ := svc.ListObjectsRequest(&s3.ListObjectsInput{Bucket: &test.bucket}) 66 req.Build() 67 if e, a := test.url, req.HTTPRequest.URL.String(); e != a { 68 t.Errorf("%d, expect url %s, got %s", i, e, a) 69 } 70 if test.errCode != "" { 71 if err := req.Error; err == nil { 72 t.Fatalf("%d, expect no error", i) 73 } 74 if a, e := req.Error.(awserr.Error).Code(), test.errCode; !strings.Contains(a, e) { 75 t.Errorf("%d, expect error code to contain %q, got %q", i, e, a) 76 } 77 } 78 } 79} 80 81func TestAccelerateBucketBuild(t *testing.T) { 82 s := s3.New(unit.Session, &aws.Config{S3UseAccelerate: aws.Bool(true)}) 83 runTests(t, s, accelerateTests) 84} 85 86func TestAccelerateNoSSLBucketBuild(t *testing.T) { 87 s := s3.New(unit.Session, &aws.Config{S3UseAccelerate: aws.Bool(true), DisableSSL: aws.Bool(true)}) 88 runTests(t, s, accelerateNoSSLTests) 89} 90 91func TestAccelerateDualstackBucketBuild(t *testing.T) { 92 s := s3.New(unit.Session, &aws.Config{ 93 S3UseAccelerate: aws.Bool(true), 94 UseDualStack: aws.Bool(true), 95 }) 96 runTests(t, s, accelerateDualstack) 97} 98 99func TestHostStyleBucketBuild(t *testing.T) { 100 s := s3.New(unit.Session) 101 runTests(t, s, sslTests) 102} 103 104func TestHostStyleBucketBuildNoSSL(t *testing.T) { 105 s := s3.New(unit.Session, &aws.Config{DisableSSL: aws.Bool(true)}) 106 runTests(t, s, nosslTests) 107} 108 109func TestPathStyleBucketBuild(t *testing.T) { 110 s := s3.New(unit.Session, &aws.Config{S3ForcePathStyle: aws.Bool(true)}) 111 runTests(t, s, forcepathTests) 112} 113 114func TestHostStyleBucketGetBucketLocation(t *testing.T) { 115 s := s3.New(unit.Session) 116 req, _ := s.GetBucketLocationRequest(&s3.GetBucketLocationInput{ 117 Bucket: aws.String("bucket"), 118 }) 119 120 req.Build() 121 if req.Error != nil { 122 t.Fatalf("expect no error, got %v", req.Error) 123 } 124 u, _ := url.Parse(req.HTTPRequest.URL.String()) 125 if e, a := "bucket", u.Host; strings.Contains(a, e) { 126 t.Errorf("expect %s to not be in %s", e, a) 127 } 128 if e, a := "bucket", u.Path; !strings.Contains(a, e) { 129 t.Errorf("expect %s to be in %s", e, a) 130 } 131} 132 133func TestVirtualHostStyleSuite(t *testing.T) { 134 f, err := os.Open(filepath.Join("testdata", "virtual_host.json")) 135 if err != nil { 136 t.Fatalf("expect no error, %v", err) 137 } 138 139 cases := []struct { 140 Bucket string 141 Region string 142 UseDualStack bool 143 UseS3Accelerate bool 144 S3UsEast1RegionalEndpoint string 145 ConfiguredAddressingStyle string 146 147 ExpectedURI string 148 }{} 149 150 decoder := json.NewDecoder(f) 151 if err := decoder.Decode(&cases); err != nil { 152 t.Fatalf("expect no error, %v", err) 153 } 154 155 const testPathStyle = "path" 156 for i, c := range cases { 157 svc := s3.New(unit.Session, &aws.Config{ 158 Region: &c.Region, 159 UseDualStack: &c.UseDualStack, 160 S3UseAccelerate: &c.UseS3Accelerate, 161 S3ForcePathStyle: aws.Bool(c.ConfiguredAddressingStyle == testPathStyle), 162 S3UsEast1RegionalEndpoint: func() endpoints.S3UsEast1RegionalEndpoint { 163 if len(c.S3UsEast1RegionalEndpoint) == 0 { 164 return endpoints.UnsetS3UsEast1Endpoint 165 } 166 v, err := endpoints.GetS3UsEast1RegionalEndpoint(c.S3UsEast1RegionalEndpoint) 167 if err != nil { 168 t.Fatalf("unexpected error, %v", err) 169 } 170 return v 171 }(), 172 }) 173 174 req, _ := svc.HeadBucketRequest(&s3.HeadBucketInput{ 175 Bucket: &c.Bucket, 176 }) 177 req.Build() 178 if req.Error != nil { 179 t.Fatalf("expect no error, got %v", req.Error) 180 } 181 182 // Trim trailing '/' that are added by the SDK but not in the tests. 183 actualURI := strings.TrimRightFunc( 184 req.HTTPRequest.URL.String(), 185 func(r rune) bool { return r == '/' }, 186 ) 187 if e, a := c.ExpectedURI, actualURI; e != a { 188 t.Errorf("%d URLs do not match\nexpect: %s\nactual: %s", i, e, a) 189 } 190 } 191} 192