1module remote23import time4567891011121314fn example_time() time.Time {15 return time.Time{16 year: 201517 month: 818 day: 3019 hour: 1220 minute: 3621 second: 022 is_local: false23 }24}2526fn test_the_official_aws_get_vanilla_vector() {27 signer := Signer{28 access_key: 'AKIDEXAMPLE'29 secret_key: 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY'30 region: 'us-east-1'31 service: 'service'32 sign_payload: false33 }34 headers := signer.sign('GET', 'https://example.amazonaws.com/', '', map[string]string{},35 []u8{}, example_time())36 assert headers['authorization'] == 'AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5fa00fa31553b73ebf1942676e86291e8372ff2a2260956d9b8aae1d763fbf31'37 assert headers['host'] == 'example.amazonaws.com'38 assert headers['x-amz-date'] == '20150830T123600Z'39}4041fn test_an_s3_conditional_put_signs_the_payload_and_the_condition() {42 signer := Signer{43 access_key: 'SCWACCESSKEY'44 secret_key: 'scw-secret-key'45 region: 'fr-par'46 service: s3_service47 }48 headers := signer.sign('PUT', 'https://s3.fr-par.scw.cloud/bucket/repo/objects/abc', '', {49 'If-None-Match': '*'50 }, 'compressed-bytes'.bytes(), time.Time{51 year: 202652 month: 953 day: 2354 hour: 1255 minute: 056 second: 057 is_local: false58 })59 assert headers['authorization'] == 'AWS4-HMAC-SHA256 Credential=SCWACCESSKEY/20260923/fr-par/s3/aws4_request, SignedHeaders=host;if-none-match;x-amz-content-sha256;x-amz-date, Signature=9790aa767fc3e4c36fce70c92476933a90b401200068f06c340bf1108435580a'60 61 other := signer.sign('PUT', 'https://s3.fr-par.scw.cloud/bucket/repo/objects/abc', '', {62 'If-None-Match': '*'63 }, 'different-bytes'.bytes(), time.Time{64 year: 202665 month: 966 day: 2367 hour: 1268 minute: 069 second: 070 is_local: false71 })72 assert other['authorization'] != headers['authorization']73}7475fn test_urls_are_split_into_host_and_encoded_path() {76 parts := split_url('https://s3.fr-par.scw.cloud/bucket/repo/objects/abc')77 assert parts.host == 's3.fr-par.scw.cloud'78 assert parts.path == '/bucket/repo/objects/abc'7980 81 82 spaces := split_url('https://example.com/bucket/a%20file.txt')83 assert spaces.path == '/bucket/a%20file.txt'8485 86 87 s3 := new_s3('https://s3.fr-par.scw.cloud', 'bucket', 'fr-par', 'key', 'secret')!88 assert split_url(s3.url_for('my repo/head', '')).path == '/bucket/my%20repo/head'8990 91 prefixed := split_url('https://example.com/prefix/bucket/key?x=1')92 assert prefixed.host == 'example.com'93 assert prefixed.path == '/prefix/bucket/key'94}9596fn test_canonical_query_is_sorted_and_encoded() {97 assert canonical_query('') == ''98 99 assert canonical_query('prefix=b/a&list-type=2') == 'list-type=2&prefix=b%2Fa'100 assert canonical_query('prefix=repo/objects/x&continuation-token=a=b') == 'continuation-token=a%3Db&prefix=repo%2Fobjects%2Fx'101 assert canonical_query('prefix=a b') == 'prefix=a%20b'102}103104fn test_etags_lose_their_quotes() {105 assert clean_etag('"3b1f"') == '3b1f'106 assert clean_etag(' "abc123" ') == 'abc123'107 assert clean_etag('abc123') == 'abc123'108 assert clean_etag('') == ''109}110111fn test_list_objects_responses_are_read() {112 body := '<ListBucketResult><IsTruncated>false</IsTruncated>' +113 '<Contents><Key>repo/objects/aaa</Key></Contents>' +114 '<Contents><Key>repo/objects/bbb</Key></Contents></ListBucketResult>'115 assert elements(body, 'Key') == ['repo/objects/aaa', 'repo/objects/bbb']116 assert first_element(body, 'NextContinuationToken') == none117 assert !body.contains('<IsTruncated>true</IsTruncated>')118119 paged := '<ListBucketResult><IsTruncated>true</IsTruncated>' +120 '<NextContinuationToken>aGVsbG8=</NextContinuationToken>' +121 '<Contents><Key>repo/objects/c&c</Key></Contents></ListBucketResult>'122 assert first_element(paged, 'NextContinuationToken') or { '' } == 'aGVsbG8='123 assert elements(paged, 'Key') == ['repo/objects/c&c']124 assert paged.contains('<IsTruncated>true</IsTruncated>')125}126127fn test_the_constructor_refuses_settings_that_cannot_work() {128 if _ := new_s3('', 'bucket', 'region', 'ak', 'sk') {129 assert false, 'a missing endpoint must be refused'130 }131 if _ := new_s3('s3.fr-par.scw.cloud', 'bucket', 'region', 'ak', 'sk') {132 assert false, 'an endpoint without a scheme must be refused'133 }134 if _ := new_s3('https://s3.fr-par.scw.cloud', 'bucket', 'region', '', '') {135 assert false, 'missing keys must be refused'136 }137 backend := new_s3('https://s3.fr-par.scw.cloud/', 'bucket', 'fr-par', 'ak', 'sk')!138 assert backend.root == 'https://s3.fr-par.scw.cloud'139 assert backend.url_for('repo/objects/abc', '') == 'https://s3.fr-par.scw.cloud/bucket/repo/objects/abc'140 assert backend.url_for('', 'list-type=2&prefix=x') == 'https://s3.fr-par.scw.cloud/bucket?list-type=2&prefix=x'141}