storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/gateway/azure/gateway-azure_test.go (about) 1 /* 2 * MinIO Cloud Storage, (C) 2017 MinIO, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package azure 18 19 import ( 20 "encoding/base64" 21 "fmt" 22 "net/http" 23 "reflect" 24 "testing" 25 26 "github.com/Azure/azure-storage-blob-go/azblob" 27 28 minio "storj.io/minio/cmd" 29 ) 30 31 func TestParseStorageEndpoint(t *testing.T) { 32 testCases := []struct { 33 host string 34 accountName string 35 expectedURL string 36 expectedErr error 37 }{ 38 { 39 "", "myaccount", "https://myaccount.blob.core.windows.net", nil, 40 }, 41 { 42 "myaccount.blob.core.usgovcloudapi.net", "myaccount", "https://myaccount.blob.core.usgovcloudapi.net", nil, 43 }, 44 { 45 "http://localhost:10000", "myaccount", "http://localhost:10000/myaccount", nil, 46 }, 47 } 48 for i, testCase := range testCases { 49 endpointURL, err := parseStorageEndpoint(testCase.host, testCase.accountName) 50 if err != testCase.expectedErr { 51 t.Errorf("Test %d: Expected error %s, got %s", i+1, testCase.expectedErr, err) 52 } 53 if endpointURL.String() != testCase.expectedURL { 54 t.Errorf("Test %d: Expected URL %s, got %s", i+1, testCase.expectedURL, endpointURL.String()) 55 } 56 } 57 } 58 59 // Test canonical metadata. 60 func TestS3MetaToAzureProperties(t *testing.T) { 61 headers := map[string]string{ 62 "accept-encoding": "gzip", 63 "content-encoding": "gzip", 64 "cache-control": "age: 3600", 65 "content-disposition": "dummy", 66 "content-length": "10", 67 "content-type": "application/javascript", 68 "X-Amz-Meta-Hdr": "value", 69 "X-Amz-Meta-X_test_key": "value", 70 "X-Amz-Meta-X__test__key": "value", 71 "X-Amz-Meta-X-Test__key": "value", 72 "X-Amz-Meta-X-Amz-Key": "hu3ZSqtqwn+aL4V2VhAeov4i+bG3KyCtRMSXQFRHXOk=", 73 "X-Amz-Meta-X-Amz-Matdesc": "{}", 74 "X-Amz-Meta-X-Amz-Iv": "eWmyryl8kq+EVnnsE7jpOg==", 75 } 76 // Only X-Amz-Meta- prefixed entries will be returned in 77 // Metadata (without the prefix!) 78 expectedHeaders := map[string]string{ 79 "Hdr": "value", 80 "X__test__key": "value", 81 "X____test____key": "value", 82 "X_Test____key": "value", 83 "X_Amz_Key": "hu3ZSqtqwn+aL4V2VhAeov4i+bG3KyCtRMSXQFRHXOk=", 84 "X_Amz_Matdesc": "{}", 85 "X_Amz_Iv": "eWmyryl8kq+EVnnsE7jpOg==", 86 } 87 meta, _, err := s3MetaToAzureProperties(minio.GlobalContext, headers) 88 if err != nil { 89 t.Fatalf("Test failed, with %s", err) 90 } 91 if !reflect.DeepEqual(map[string]string(meta), expectedHeaders) { 92 t.Fatalf("Test failed, expected %#v, got %#v", expectedHeaders, meta) 93 } 94 headers = map[string]string{ 95 "invalid--meta": "value", 96 } 97 _, _, err = s3MetaToAzureProperties(minio.GlobalContext, headers) 98 if err != nil { 99 if _, ok := err.(minio.UnsupportedMetadata); !ok { 100 t.Fatalf("Test failed with unexpected error %s, expected UnsupportedMetadata", err) 101 } 102 } 103 104 headers = map[string]string{ 105 "content-md5": "Dce7bmCX61zvxzP5QmfelQ==", 106 } 107 _, props, err := s3MetaToAzureProperties(minio.GlobalContext, headers) 108 if err != nil { 109 t.Fatalf("Test failed, with %s", err) 110 } 111 if base64.StdEncoding.EncodeToString(props.ContentMD5) != headers["content-md5"] { 112 t.Fatalf("Test failed, expected %s, got %s", headers["content-md5"], props.ContentMD5) 113 } 114 } 115 116 func TestAzurePropertiesToS3Meta(t *testing.T) { 117 // Just one testcase. Adding more test cases does not add value to the testcase 118 // as azureToS3Metadata() just adds a prefix. 119 metadata := map[string]string{ 120 "first_name": "myname", 121 "x_test_key": "value", 122 "x_test__key": "value", 123 "x__test__key": "value", 124 "x____test____key": "value", 125 "x_amz_key": "hu3ZSqtqwn+aL4V2VhAeov4i+bG3KyCtRMSXQFRHXOk=", 126 "x_amz_matdesc": "{}", 127 "x_amz_iv": "eWmyryl8kq+EVnnsE7jpOg==", 128 } 129 expectedMeta := map[string]string{ 130 "X-Amz-Meta-First-Name": "myname", 131 "X-Amz-Meta-X-Test-Key": "value", 132 "X-Amz-Meta-X-Test_key": "value", 133 "X-Amz-Meta-X_test_key": "value", 134 "X-Amz-Meta-X__test__key": "value", 135 "X-Amz-Meta-X-Amz-Key": "hu3ZSqtqwn+aL4V2VhAeov4i+bG3KyCtRMSXQFRHXOk=", 136 "X-Amz-Meta-X-Amz-Matdesc": "{}", 137 "X-Amz-Meta-X-Amz-Iv": "eWmyryl8kq+EVnnsE7jpOg==", 138 "Cache-Control": "max-age: 3600", 139 "Content-Disposition": "dummy", 140 "Content-Encoding": "gzip", 141 "Content-Length": "10", 142 "Content-MD5": base64.StdEncoding.EncodeToString([]byte("base64-md5")), 143 "Content-Type": "application/javascript", 144 } 145 actualMeta := azurePropertiesToS3Meta(metadata, azblob.BlobHTTPHeaders{ 146 CacheControl: "max-age: 3600", 147 ContentDisposition: "dummy", 148 ContentEncoding: "gzip", 149 ContentMD5: []byte("base64-md5"), 150 ContentType: "application/javascript", 151 }, 10) 152 if !reflect.DeepEqual(actualMeta, expectedMeta) { 153 t.Fatalf("Test failed, expected %#v, got %#v", expectedMeta, actualMeta) 154 } 155 } 156 157 // Add tests for azure to object error (top level). 158 func TestAzureToObjectError(t *testing.T) { 159 testCases := []struct { 160 actualErr error 161 expectedErr error 162 bucket, object string 163 }{ 164 { 165 nil, nil, "", "", 166 }, 167 { 168 fmt.Errorf("Non azure error"), 169 fmt.Errorf("Non azure error"), "", "", 170 }, 171 } 172 for i, testCase := range testCases { 173 if err := azureToObjectError(testCase.actualErr, testCase.bucket, testCase.object); err != nil { 174 if err.Error() != testCase.expectedErr.Error() { 175 t.Errorf("Test %d: Expected error %s, got %s", i+1, testCase.expectedErr, err) 176 } 177 } else { 178 if testCase.expectedErr != nil { 179 t.Errorf("Test %d expected an error but one was not produced", i+1) 180 } 181 } 182 } 183 } 184 185 // Add tests for azure to object error (internal). 186 func TestAzureCodesToObjectError(t *testing.T) { 187 testCases := []struct { 188 originalErr error 189 actualServiceCode string 190 actualStatusCode int 191 expectedErr error 192 bucket, object string 193 }{ 194 { 195 nil, "ContainerAlreadyExists", 0, 196 minio.BucketExists{Bucket: "bucket"}, "bucket", "", 197 }, 198 { 199 nil, "InvalidResourceName", 0, 200 minio.BucketNameInvalid{Bucket: "bucket."}, "bucket.", "", 201 }, 202 { 203 nil, "RequestBodyTooLarge", 0, 204 minio.PartTooBig{}, "", "", 205 }, 206 { 207 nil, "InvalidMetadata", 0, 208 minio.UnsupportedMetadata{}, "", "", 209 }, 210 { 211 nil, "", http.StatusNotFound, 212 minio.ObjectNotFound{ 213 Bucket: "bucket", 214 Object: "object", 215 }, "bucket", "object", 216 }, 217 { 218 nil, "", http.StatusNotFound, 219 minio.BucketNotFound{Bucket: "bucket"}, "bucket", "", 220 }, 221 { 222 nil, "", http.StatusBadRequest, 223 minio.BucketNameInvalid{Bucket: "bucket."}, "bucket.", "", 224 }, 225 { 226 fmt.Errorf("unhandled azure error"), "", http.StatusForbidden, 227 fmt.Errorf("unhandled azure error"), "", "", 228 }, 229 } 230 for i, testCase := range testCases { 231 if err := azureCodesToObjectError(testCase.originalErr, testCase.actualServiceCode, testCase.actualStatusCode, testCase.bucket, testCase.object); err != nil { 232 if err.Error() != testCase.expectedErr.Error() { 233 t.Errorf("Test %d: Expected error %s, got %s", i+1, testCase.expectedErr, err) 234 } 235 } else { 236 if testCase.expectedErr != nil { 237 t.Errorf("Test %d expected an error but one was not produced", i+1) 238 } 239 } 240 } 241 } 242 243 func TestCheckAzureUploadID(t *testing.T) { 244 invalidUploadIDs := []string{ 245 "123456789abcdefg", 246 "hello world", 247 "0x1234567890", 248 "1234567890abcdef1234567890abcdef", 249 } 250 251 for _, uploadID := range invalidUploadIDs { 252 if err := checkAzureUploadID(minio.GlobalContext, uploadID); err == nil { 253 t.Fatalf("%s: expected: <error>, got: <nil>", uploadID) 254 } 255 } 256 257 validUploadIDs := []string{ 258 "1234567890abcdef", 259 "1122334455667788", 260 } 261 262 for _, uploadID := range validUploadIDs { 263 if err := checkAzureUploadID(minio.GlobalContext, uploadID); err != nil { 264 t.Fatalf("%s: expected: <nil>, got: %s", uploadID, err) 265 } 266 } 267 }