github.com/minio/minio-go/v6@v6.0.57/utils_test.go (about) 1 /* 2 * MinIO Go Library for Amazon S3 Compatible Cloud Storage 3 * Copyright 2015-2017 MinIO, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package minio 19 20 import ( 21 "fmt" 22 "net/url" 23 "testing" 24 "time" 25 26 "github.com/minio/minio-go/v6/pkg/s3utils" 27 ) 28 29 // Tests signature redacting function used 30 // in filtering on-wire Authorization header. 31 func TestRedactSignature(t *testing.T) { 32 testCases := []struct { 33 authValue string 34 expectedRedactedAuthValue string 35 }{ 36 { 37 authValue: "AWS 1231313:888x000231==", 38 expectedRedactedAuthValue: "AWS **REDACTED**:**REDACTED**", 39 }, 40 { 41 authValue: "AWS4-HMAC-SHA256 Credential=12312313/20170613/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=02131231312313213", 42 expectedRedactedAuthValue: "AWS4-HMAC-SHA256 Credential=**REDACTED**/20170613/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=**REDACTED**", 43 }, 44 } 45 46 for i, testCase := range testCases { 47 redactedAuthValue := redactSignature(testCase.authValue) 48 if redactedAuthValue != testCase.expectedRedactedAuthValue { 49 t.Errorf("Test %d: Expected %s, got %s", i+1, testCase.expectedRedactedAuthValue, redactedAuthValue) 50 } 51 } 52 } 53 54 // Tests for 'getEndpointURL(endpoint string, inSecure bool)'. 55 func TestGetEndpointURL(t *testing.T) { 56 testCases := []struct { 57 // Inputs. 58 endPoint string 59 secure bool 60 61 // Expected result. 62 result string 63 err error 64 // Flag indicating whether the test is expected to pass or not. 65 shouldPass bool 66 }{ 67 {"s3.amazonaws.com", true, "https://s3.amazonaws.com", nil, true}, 68 {"s3.cn-north-1.amazonaws.com.cn", true, "https://s3.cn-north-1.amazonaws.com.cn", nil, true}, 69 {"s3.cn-northwest-1.amazonaws.com.cn", true, "https://s3.cn-northwest-1.amazonaws.com.cn", nil, true}, 70 {"s3.amazonaws.com", false, "http://s3.amazonaws.com", nil, true}, 71 {"s3.cn-north-1.amazonaws.com.cn", false, "http://s3.cn-north-1.amazonaws.com.cn", nil, true}, 72 {"s3.cn-northwest-1.amazonaws.com.cn", false, "http://s3.cn-northwest-1.amazonaws.com.cn", nil, true}, 73 {"192.168.1.1:9000", false, "http://192.168.1.1:9000", nil, true}, 74 {"192.168.1.1:9000", true, "https://192.168.1.1:9000", nil, true}, 75 {"s3.amazonaws.com:443", true, "https://s3.amazonaws.com:443", nil, true}, 76 {"13333.123123.-", true, "", ErrInvalidArgument(fmt.Sprintf("Endpoint: %s does not follow ip address or domain name standards.", "13333.123123.-")), false}, 77 {"13333.123123.-", true, "", ErrInvalidArgument(fmt.Sprintf("Endpoint: %s does not follow ip address or domain name standards.", "13333.123123.-")), false}, 78 {"storage.googleapis.com:4000", true, "", ErrInvalidArgument("Google Cloud Storage endpoint should be 'storage.googleapis.com'."), false}, 79 {"s3.aamzza.-", true, "", ErrInvalidArgument(fmt.Sprintf("Endpoint: %s does not follow ip address or domain name standards.", "s3.aamzza.-")), false}, 80 {"", true, "", ErrInvalidArgument("Endpoint: does not follow ip address or domain name standards."), false}, 81 } 82 83 for i, testCase := range testCases { 84 result, err := getEndpointURL(testCase.endPoint, testCase.secure) 85 if err != nil && testCase.shouldPass { 86 t.Errorf("Test %d: Expected to pass, but failed with: <ERROR> %s", i+1, err.Error()) 87 } 88 if err == nil && !testCase.shouldPass { 89 t.Errorf("Test %d: Expected to fail with <ERROR> \"%s\", but passed instead", i+1, testCase.err.Error()) 90 } 91 // Failed as expected, but does it fail for the expected reason. 92 if err != nil && !testCase.shouldPass { 93 if err.Error() != testCase.err.Error() { 94 t.Errorf("Test %d: Expected to fail with error \"%s\", but instead failed with error \"%s\" instead", i+1, testCase.err.Error(), err.Error()) 95 } 96 } 97 98 // Test passes as expected, but the output values are verified for correctness here. 99 if err == nil && testCase.shouldPass { 100 if testCase.result != result.String() { 101 t.Errorf("Test %d: Expected the result Url to be \"%s\", but found \"%s\" instead", i+1, testCase.result, result.String()) 102 } 103 } 104 } 105 } 106 107 // Tests validate end point validator. 108 func TestIsValidEndpointURL(t *testing.T) { 109 testCases := []struct { 110 url string 111 err error 112 // Flag indicating whether the test is expected to pass or not. 113 shouldPass bool 114 }{ 115 {"", ErrInvalidArgument("Endpoint url cannot be empty."), false}, 116 {"/", nil, true}, 117 {"https://s3.amazonaws.com", nil, true}, 118 {"https://s3.cn-north-1.amazonaws.com.cn", nil, true}, 119 {"https://s3-us-gov-west-1.amazonaws.com", nil, true}, 120 {"https://s3-fips-us-gov-west-1.amazonaws.com", nil, true}, 121 {"https://s3.amazonaws.com/", nil, true}, 122 {"https://storage.googleapis.com/", nil, true}, 123 {"https://z3.amazonaws.com", nil, true}, 124 {"https://mybalancer.us-east-1.elb.amazonaws.com", nil, true}, 125 {"192.168.1.1", ErrInvalidArgument("Endpoint url cannot have fully qualified paths."), false}, 126 {"https://amazon.googleapis.com/", ErrInvalidArgument("Google Cloud Storage endpoint should be 'storage.googleapis.com'."), false}, 127 {"https://storage.googleapis.com/bucket/", ErrInvalidArgument("Endpoint url cannot have fully qualified paths."), false}, 128 {"https://s3.amazonaws.com/bucket/object", ErrInvalidArgument("Endpoint url cannot have fully qualified paths."), false}, 129 } 130 131 for i, testCase := range testCases { 132 var u url.URL 133 if testCase.url == "" { 134 u = sentinelURL 135 } else { 136 u1, err := url.Parse(testCase.url) 137 if err != nil { 138 t.Errorf("Test %d: Expected to pass, but failed with: <ERROR> %s", i+1, err) 139 } 140 u = *u1 141 } 142 err := isValidEndpointURL(u) 143 if err != nil && testCase.shouldPass { 144 t.Errorf("Test %d: Expected to pass, but failed with: <ERROR> %s", i+1, err) 145 } 146 if err == nil && !testCase.shouldPass { 147 t.Errorf("Test %d: Expected to fail with <ERROR> \"%s\", but passed instead", i+1, testCase.err) 148 } 149 // Failed as expected, but does it fail for the expected reason. 150 if err != nil && !testCase.shouldPass { 151 if err.Error() != testCase.err.Error() { 152 t.Errorf("Test %d: Expected to fail with error \"%s\", but instead failed with error \"%s\" instead", i+1, testCase.err, err) 153 } 154 } 155 156 } 157 } 158 159 func TestDefaultBucketLocation(t *testing.T) { 160 testCases := []struct { 161 endpointURL url.URL 162 regionOverride string 163 expectedLocation string 164 }{ 165 // Region override is set URL is ignored. - Test 1. 166 { 167 endpointURL: url.URL{Host: "s3-fips-us-gov-west-1.amazonaws.com"}, 168 regionOverride: "us-west-1", 169 expectedLocation: "us-west-1", 170 }, 171 // No region override, url based preferenced is honored - Test 2. 172 { 173 endpointURL: url.URL{Host: "s3-fips-us-gov-west-1.amazonaws.com"}, 174 regionOverride: "", 175 expectedLocation: "us-gov-west-1", 176 }, 177 // Region override is honored - Test 3. 178 { 179 endpointURL: url.URL{Host: "s3.amazonaws.com"}, 180 regionOverride: "us-west-1", 181 expectedLocation: "us-west-1", 182 }, 183 // China region should be honored, region override not provided. - Test 4. 184 { 185 endpointURL: url.URL{Host: "s3.cn-north-1.amazonaws.com.cn"}, 186 regionOverride: "", 187 expectedLocation: "cn-north-1", 188 }, 189 // China region should be honored, region override not provided. - Test 5. 190 { 191 endpointURL: url.URL{Host: "s3.cn-northwest-1.amazonaws.com.cn"}, 192 regionOverride: "", 193 expectedLocation: "cn-northwest-1", 194 }, 195 // No region provided, no standard region strings provided as well. - Test 6. 196 { 197 endpointURL: url.URL{Host: "s3.amazonaws.com"}, 198 regionOverride: "", 199 expectedLocation: "us-east-1", 200 }, 201 } 202 203 for i, testCase := range testCases { 204 retLocation := getDefaultLocation(testCase.endpointURL, testCase.regionOverride) 205 if testCase.expectedLocation != retLocation { 206 t.Errorf("Test %d: Expected location %s, got %s", i+1, testCase.expectedLocation, retLocation) 207 } 208 } 209 } 210 211 // Tests validate the expiry time validator. 212 func TestIsValidExpiry(t *testing.T) { 213 testCases := []struct { 214 // Input. 215 duration time.Duration 216 // Expected result. 217 err error 218 // Flag to indicate whether the test should pass. 219 shouldPass bool 220 }{ 221 {100 * time.Millisecond, ErrInvalidArgument("Expires cannot be lesser than 1 second."), false}, 222 {604801 * time.Second, ErrInvalidArgument("Expires cannot be greater than 7 days."), false}, 223 {0 * time.Second, ErrInvalidArgument("Expires cannot be lesser than 1 second."), false}, 224 {1 * time.Second, nil, true}, 225 {10000 * time.Second, nil, true}, 226 {999 * time.Second, nil, true}, 227 } 228 229 for i, testCase := range testCases { 230 err := isValidExpiry(testCase.duration) 231 if err != nil && testCase.shouldPass { 232 t.Errorf("Test %d: Expected to pass, but failed with: <ERROR> %s", i+1, err.Error()) 233 } 234 if err == nil && !testCase.shouldPass { 235 t.Errorf("Test %d: Expected to fail with <ERROR> \"%s\", but passed instead", i+1, testCase.err.Error()) 236 } 237 // Failed as expected, but does it fail for the expected reason. 238 if err != nil && !testCase.shouldPass { 239 if err.Error() != testCase.err.Error() { 240 t.Errorf("Test %d: Expected to fail with error \"%s\", but instead failed with error \"%s\" instead", i+1, testCase.err.Error(), err.Error()) 241 } 242 } 243 244 } 245 } 246 247 // Tests validate the bucket name validator. 248 func TestIsValidBucketName(t *testing.T) { 249 testCases := []struct { 250 // Input. 251 bucketName string 252 // Expected result. 253 err error 254 // Flag to indicate whether test should Pass. 255 shouldPass bool 256 }{ 257 {".mybucket", ErrInvalidBucketName("Bucket name contains invalid characters"), false}, 258 {"mybucket.", ErrInvalidBucketName("Bucket name contains invalid characters"), false}, 259 {"mybucket-", ErrInvalidBucketName("Bucket name contains invalid characters"), false}, 260 {"my", ErrInvalidBucketName("Bucket name cannot be shorter than 3 characters"), false}, 261 {"", ErrInvalidBucketName("Bucket name cannot be empty"), false}, 262 {"my..bucket", ErrInvalidBucketName("Bucket name contains invalid characters"), false}, 263 {"my.bucket.com", nil, true}, 264 {"my-bucket", nil, true}, 265 {"123my-bucket", nil, true}, 266 } 267 268 for i, testCase := range testCases { 269 err := s3utils.CheckValidBucketName(testCase.bucketName) 270 if err != nil && testCase.shouldPass { 271 t.Errorf("Test %d: Expected to pass, but failed with: <ERROR> %s", i+1, err.Error()) 272 } 273 if err == nil && !testCase.shouldPass { 274 t.Errorf("Test %d: Expected to fail with <ERROR> \"%s\", but passed instead", i+1, testCase.err.Error()) 275 } 276 // Failed as expected, but does it fail for the expected reason. 277 if err != nil && !testCase.shouldPass { 278 if err.Error() != testCase.err.Error() { 279 t.Errorf("Test %d: Expected to fail with error \"%s\", but instead failed with error \"%s\" instead", i+1, testCase.err.Error(), err.Error()) 280 } 281 } 282 283 } 284 285 } 286 287 // Tests if header is standard supported header 288 func TestIsStandardHeader(t *testing.T) { 289 testCases := []struct { 290 // Input. 291 header string 292 // Expected result. 293 expectedValue bool 294 }{ 295 {"content-encoding", true}, 296 {"content-type", true}, 297 {"cache-control", true}, 298 {"content-disposition", true}, 299 {"content-language", true}, 300 {"random-header", false}, 301 } 302 303 for i, testCase := range testCases { 304 actual := isStandardHeader(testCase.header) 305 if actual != testCase.expectedValue { 306 t.Errorf("Test %d: Expected to pass, but failed", i+1) 307 } 308 } 309 310 } 311 312 // Tests if header is server encryption header 313 func TestIsSSEHeader(t *testing.T) { 314 testCases := []struct { 315 // Input. 316 header string 317 // Expected result. 318 expectedValue bool 319 }{ 320 {"x-amz-server-side-encryption", true}, 321 {"x-amz-server-side-encryption-aws-kms-key-id", true}, 322 {"x-amz-server-side-encryption-context", true}, 323 {"x-amz-server-side-encryption-customer-algorithm", true}, 324 {"x-amz-server-side-encryption-customer-key", true}, 325 {"x-amz-server-side-encryption-customer-key-MD5", true}, 326 {"random-header", false}, 327 } 328 329 for i, testCase := range testCases { 330 actual := isSSEHeader(testCase.header) 331 if actual != testCase.expectedValue { 332 t.Errorf("Test %d: Expected to pass, but failed", i+1) 333 } 334 } 335 } 336 337 // Tests if header is x-amz-meta or x-amz-acl 338 func TestIsAmzHeader(t *testing.T) { 339 testCases := []struct { 340 // Input. 341 header string 342 // Expected result. 343 expectedValue bool 344 }{ 345 {"x-amz-iv", false}, 346 {"x-amz-key", false}, 347 {"x-amz-matdesc", false}, 348 {"x-amz-meta-x-amz-iv", true}, 349 {"x-amz-meta-x-amz-key", true}, 350 {"x-amz-meta-x-amz-matdesc", true}, 351 {"x-amz-acl", true}, 352 {"random-header", false}, 353 } 354 355 for i, testCase := range testCases { 356 actual := isAmzHeader(testCase.header) 357 if actual != testCase.expectedValue { 358 t.Errorf("Test %d: Expected to pass, but failed", i+1) 359 } 360 } 361 362 }