1#!/bin/bash
2#
3# Copyright (c) 2015-2021 MinIO, Inc.
4#
5# This file is part of MinIO Object Storage stack
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program.  If not, see <http://www.gnu.org/licenses/>.
19#
20
21################################################################################
22#
23# This script is usable by mc functional tests, mint tests and MinIO verification
24# tests.
25#
26# * As mc functional tests, just run this script.  It uses mc executable binary
27#   in current working directory or in the path.  The tests uses play.min.io
28#   as MinIO server.
29#
30# * For other, call this script with environment variables MINT_MODE,
31#   MINT_DATA_DIR, SERVER_ENDPOINT, ACCESS_KEY, SECRET_KEY and ENABLE_HTTPS. It
32#   uses mc executable binary in current working directory and uses given MinIO
33#   server to run tests. MINT_MODE is set by mint to specify what category of
34#   tests to run.
35#
36################################################################################
37
38# Force bytewise sorting for CLI tools
39LANG=C
40
41if [ -n "$MINT_MODE" ]; then
42    if [ -z "${MINT_DATA_DIR+x}" ]; then
43        echo "MINT_DATA_DIR not defined"
44        exit 1
45    fi
46    if [ -z "${SERVER_ENDPOINT+x}" ]; then
47        echo "SERVER_ENDPOINT not defined"
48        exit 1
49    fi
50    if [ -z "${ACCESS_KEY+x}" ]; then
51        echo "ACCESS_KEY not defined"
52        exit 1
53    fi
54    if [ -z "${SECRET_KEY+x}" ]; then
55        echo "SECRET_KEY not defined"
56        exit 1
57    fi
58fi
59
60if [ -z "${SERVER_ENDPOINT+x}" ]; then
61    SERVER_ENDPOINT="play.min.io"
62    ACCESS_KEY="Q3AM3UQ867SPQQA43P2F"
63    SECRET_KEY="zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG"
64    ENABLE_HTTPS=1
65fi
66
67WORK_DIR="$PWD"
68DATA_DIR="$MINT_DATA_DIR"
69if [ -z "$MINT_MODE" ]; then
70    WORK_DIR="$PWD/.run-$RANDOM"
71    DATA_DIR="$WORK_DIR/data"
72fi
73
74FILE_0_B="$DATA_DIR/datafile-0-b"
75FILE_1_MB="$DATA_DIR/datafile-1-MB"
76FILE_65_MB="$DATA_DIR/datafile-65-MB"
77declare FILE_0_B_MD5SUM
78declare FILE_1_MB_MD5SUM
79declare FILE_65_MB_MD5SUM
80
81ENDPOINT="https://$SERVER_ENDPOINT"
82if [ "$ENABLE_HTTPS" != "1" ]; then
83    ENDPOINT="http://$SERVER_ENDPOINT"
84fi
85
86SERVER_ALIAS="myminio"
87SERVER_ALIAS_TLS="myminio-ssl"
88
89BUCKET_NAME="mc-test-bucket-$RANDOM"
90WATCH_OUT_FILE="$WORK_DIR/watch.out-$RANDOM"
91
92MC_CONFIG_DIR="/tmp/.mc-$RANDOM"
93MC="$PWD/mc"
94declare -a MC_CMD
95
96function get_md5sum()
97{
98    filename="$1"
99    out=$(md5sum "$filename" 2>/dev/null)
100    rv=$?
101    if [ "$rv" -eq 0 ]; then
102        echo $(awk '{ print $1 }' <<< "$out")
103    fi
104
105    return "$rv"
106}
107
108function get_time()
109{
110    date +%s%N
111}
112
113function get_duration()
114{
115    start_time=$1
116    end_time=$(get_time)
117
118    echo $(( (end_time - start_time) / 1000000 ))
119}
120
121function log_success()
122{
123    if [ -n "$MINT_MODE" ]; then
124        printf '{"name": "mc", "duration": "%d", "function": "%s", "status": "PASS"}\n' "$(get_duration "$1")" "$2"
125    fi
126}
127
128function show()
129{
130    if [ -z "$MINT_MODE" ]; then
131        func_name="$1"
132        echo "Running $func_name()"
133    fi
134}
135
136function show_on_success()
137{
138    rv="$1"
139    shift
140
141    if [ "$rv" -eq 0 ]; then
142        echo "$@"
143    fi
144
145    return "$rv"
146}
147
148function show_on_failure()
149{
150    rv="$1"
151    shift
152
153    if [ "$rv" -ne 0 ]; then
154        echo "$@"
155    fi
156
157    return "$rv"
158}
159
160function assert()
161{
162    expected_rv="$1"
163    shift
164    start_time="$1"
165    shift
166    func_name="$1"
167    shift
168
169    err=$("$@")
170    rv=$?
171    if [ "$rv" -ne "$expected_rv" ]; then
172        if [ -n "$MINT_MODE" ]; then
173            err=$(printf "$err" | python -c 'import sys,json; print(json.dumps(sys.stdin.read()))')
174            ## err is already JSON string, no need to double quote
175            printf '{"name": "mc", "duration": "%d", "function": "%s", "status": "FAIL", "error": %s}\n' "$(get_duration "$start_time")" "$func_name" "$err"
176        else
177            echo "mc: $func_name: $err"
178        fi
179
180        if [ "$rv" -eq 0 ]; then
181            exit 1
182        fi
183
184        exit "$rv"
185    fi
186
187    return 0
188}
189
190function assert_success() {
191    assert 0 "$@"
192}
193
194function assert_failure() {
195    assert 1 "$@"
196}
197
198function mc_cmd()
199{
200    cmd=( "${MC_CMD[@]}" "$@" )
201    err_file="$WORK_DIR/cmd.out.$RANDOM"
202
203    "${cmd[@]}" >"$err_file" 2>&1
204    rv=$?
205    if [ "$rv" -ne 0 ]; then
206        printf '%q ' "${cmd[@]}"
207        echo " >>> "
208        cat "$err_file"
209    fi
210
211    rm -f "$err_file"
212    return "$rv"
213}
214
215function check_md5sum()
216{
217    expected_checksum="$1"
218    shift
219    filename="$@"
220
221    checksum="$(get_md5sum "$filename")"
222    rv=$?
223    if [ "$rv" -ne 0 ]; then
224        echo "unable to get md5sum for $filename"
225        return "$rv"
226    fi
227
228    if [ "$checksum" != "$expected_checksum" ]; then
229        echo "$filename: md5sum mismatch"
230        return 1
231    fi
232
233    return 0
234}
235
236function test_make_bucket()
237{
238    show "${FUNCNAME[0]}"
239
240    start_time=$(get_time)
241    bucket_name="mc-test-bucket-$RANDOM"
242    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket_name}"
243    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb "${SERVER_ALIAS}/${bucket_name}"
244
245    log_success "$start_time" "${FUNCNAME[0]}"
246}
247
248function test_make_bucket_error() {
249    show "${FUNCNAME[0]}"
250
251    start_time=$(get_time)
252    bucket_name="MC-test%bucket%$RANDOM"
253    assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket_name}"
254
255    log_success "$start_time" "${FUNCNAME[0]}"
256}
257
258function test_rb()
259{
260    show "${FUNCNAME[0]}"
261
262    start_time=$(get_time)
263    bucket1="mc-test-bucket-$RANDOM-1"
264    bucket2="mc-test-bucket-$RANDOM-2"
265    object_name="mc-test-object-$RANDOM"
266
267    # Tets rb when the bucket is empty
268    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket1}"
269    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb "${SERVER_ALIAS}/${bucket1}"
270
271    # Test rb with --force flag when the bucket is not empty
272    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket1}"
273    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${bucket1}/${object_name}"
274    assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd rb "${SERVER_ALIAS}/${bucket1}"
275    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb --force "${SERVER_ALIAS}/${bucket1}"
276
277    # Test rb with --force and --dangerous to remove a site content
278    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket1}"
279    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket2}"
280    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${bucket1}/${object_name}"
281    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${bucket2}/${object_name}"
282    assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd rb --force "${SERVER_ALIAS}/"
283    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb --force --dangerous "${SERVER_ALIAS}"
284
285    log_success "$start_time" "${FUNCNAME[0]}"
286}
287
288function setup()
289{
290    start_time=$(get_time)
291    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${BUCKET_NAME}"
292}
293
294function teardown()
295{
296    start_time=$(get_time)
297    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb --force "${SERVER_ALIAS}/${BUCKET_NAME}"
298}
299
300function test_put_object()
301{
302    show "${FUNCNAME[0]}"
303
304    start_time=$(get_time)
305    object_name="mc-test-object-$RANDOM"
306    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
307    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
308
309    log_success "$start_time" "${FUNCNAME[0]}"
310}
311
312function test_put_object_error()
313{
314    show "${FUNCNAME[0]}"
315    start_time=$(get_time)
316
317    object_long_name=$(printf "mc-test-object-%01100d" 1)
318    assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_long_name}"
319
320    log_success "$start_time" "${FUNCNAME[0]}"
321}
322
323function test_put_object_multipart()
324{
325    show "${FUNCNAME[0]}"
326
327    start_time=$(get_time)
328    object_name="mc-test-object-$RANDOM"
329    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_65_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
330    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
331
332    log_success "$start_time" "${FUNCNAME[0]}"
333}
334
335function test_put_object_0byte()
336{
337    show "${FUNCNAME[0]}"
338
339    start_time=$(get_time)
340    object_name="mc-test-object-$RANDOM"
341    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_0_B}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
342    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}" "${object_name}.downloaded"
343    assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_0_B_MD5SUM" "${object_name}.downloaded"
344    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${object_name}.downloaded" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
345
346    log_success "$start_time" "${FUNCNAME[0]}"
347}
348
349## Test mc cp command with storage-class flag set
350function test_put_object_with_storage_class()
351{
352    show "${FUNCNAME[0]}"
353
354    start_time=$(get_time)
355    object_name="mc-test-object-$RANDOM"
356    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --storage-class REDUCED_REDUNDANCY "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
357    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
358
359    log_success "$start_time" "${FUNCNAME[0]}"
360}
361
362## Test mc cp command with storage-class flag set to incorrect value
363function test_put_object_with_storage_class_error()
364{
365    show "${FUNCNAME[0]}"
366
367    start_time=$(get_time)
368    object_name="mc-test-object-$RANDOM"
369    assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd cp --storage-class REDUCED "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
370
371    log_success "$start_time" "${FUNCNAME[0]}"
372}
373
374## Test mc cp command with valid metadata string
375function test_put_object_with_metadata()
376{
377    show "${FUNCNAME[0]}"
378
379    start_time=$(get_time)
380    object_name="mc-test-object-$RANDOM"
381    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --attr key1=val1\;key2=val2 "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
382    diff -bB <(echo "val1")  <("${MC_CMD[@]}"   --json stat "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"  |  jq -r '.metadata."X-Amz-Meta-Key1"')  >/dev/null 2>&1
383    assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to put object with metadata"
384    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
385    log_success "$start_time" "${FUNCNAME[0]}"
386
387}
388
389function test_get_object()
390{
391    show "${FUNCNAME[0]}"
392
393    start_time=$(get_time)
394    object_name="mc-test-object-$RANDOM"
395    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
396    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}" "${object_name}.downloaded"
397    assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_1_MB_MD5SUM" "${object_name}.downloaded"
398    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${object_name}.downloaded" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
399
400    log_success "$start_time" "${FUNCNAME[0]}"
401}
402
403function test_get_object_multipart()
404{
405    show "${FUNCNAME[0]}"
406
407    start_time=$(get_time)
408    object_name="mc-test-object-$RANDOM"
409    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_65_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
410    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}" "${object_name}.downloaded"
411    assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_65_MB_MD5SUM" "${object_name}.downloaded"
412    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${object_name}.downloaded" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
413
414    log_success "$start_time" "${FUNCNAME[0]}"
415}
416
417function test_presigned_post_policy_error()
418{
419    show "${FUNCNAME[0]}"
420
421    start_time=$(get_time)
422    object_name="mc-test-object-$RANDOM"
423
424    out=$("${MC_CMD[@]}" --json share upload "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}")
425    assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to get presigned post policy and put object url"
426
427    # Support IPv6 address, IPv6 is specifed as [host]:9000 form, we should
428    # replace '['']' with their escaped values as '\[' '\]'.
429    #
430    # Without escaping '['']', 'sed' command interprets them as expressions
431    # which fails our requirement of replacing $endpoint/$bucket URLs in the
432    # subsequent operations.
433    endpoint=$(echo "$ENDPOINT" | sed 's|[][]|\\&|g')
434
435    # Extract share field of json output, and append object name to the URL
436    upload=$(echo "$out" | jq -r .share | sed "s|<FILE>|$FILE_1_MB|g" | sed "s|curl|curl -sSg|g" | sed "s|${endpoint}/${BUCKET_NAME}/|${endpoint}/${BUCKET_NAME}/${object_name}|g")
437
438    # In case of virtual host style URL path, the previous replace would have failed.
439    # One of the following two commands will append the object name in that scenario.
440    upload=$(echo "$upload" | sed "s|http://${BUCKET_NAME}.${SERVER_ENDPOINT}/|http://${BUCKET_NAME}.${SERVER_ENDPOINT}/${object_name}|g")
441    upload=$(echo "$upload" | sed "s|https://${BUCKET_NAME}.${SERVER_ENDPOINT}/|https://${BUCKET_NAME}.${SERVER_ENDPOINT}/${object_name}|g")
442
443    ret=$($upload 2>&1 | grep -oP '(?<=Code>)[^<]+')
444    # Check if the command execution failed.
445    assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unknown failure in upload of $FILE_1_MB using presigned post policy"
446    if [ -z "$ret" ]; then
447
448    # Check if the upload succeeded. We expect it to fail.
449    assert_failure "$start_time" "${FUNCNAME[0]}" show_on_success 0 "upload of $FILE_1_MB using presigned post policy should have failed"
450    fi
451
452    if [ "$ret" != "MethodNotAllowed" ]; then
453    assert_failure "$start_time" "${FUNCNAME[0]}" show_on_success 0 "upload of $FILE_1_MB using presigned post policy should have failed with MethodNotAllowed error, instead failed with $ret error"
454    fi
455    log_success "$start_time" "${FUNCNAME[0]}"
456}
457
458function test_presigned_put_object()
459{
460    show "${FUNCNAME[0]}"
461
462    start_time=$(get_time)
463    object_name="mc-test-object-$RANDOM"
464
465    out=$("${MC_CMD[@]}" --json share upload "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}")
466    assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to get presigned put object url"
467    upload=$(echo "$out" | jq -r .share | sed "s|<FILE>|$FILE_1_MB|g" | sed "s|curl|curl -sSg|g")
468    $upload >/dev/null 2>&1
469    assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to upload $FILE_1_MB presigned put object url"
470
471    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}" "${object_name}.downloaded"
472    assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_1_MB_MD5SUM" "${object_name}.downloaded"
473    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${object_name}.downloaded" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
474
475    log_success "$start_time" "${FUNCNAME[0]}"
476}
477
478function test_presigned_get_object()
479{
480    show "${FUNCNAME[0]}"
481
482    start_time=$(get_time)
483    object_name="mc-test-object-$RANDOM"
484    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
485
486    out=$("${MC_CMD[@]}" --json share download "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}")
487    assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to get presigned get object url"
488    download_url=$(echo "$out" | jq -r .share)
489    curl -sSg --output "${object_name}.downloaded" -X GET "$download_url"
490    assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to download $download_url"
491
492    assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_1_MB_MD5SUM" "${object_name}.downloaded"
493    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${object_name}.downloaded" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
494
495    log_success "$start_time" "${FUNCNAME[0]}"
496}
497
498function test_cat_object()
499{
500    show "${FUNCNAME[0]}"
501
502    start_time=$(get_time)
503    object_name="mc-test-object-$RANDOM"
504    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
505    "${MC_CMD[@]}" cat "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}" > "${object_name}.downloaded"
506    assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to download object using 'mc cat'"
507    assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_1_MB_MD5SUM" "${object_name}.downloaded"
508    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${object_name}.downloaded" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
509
510    log_success "$start_time" "${FUNCNAME[0]}"
511}
512
513function test_cat_stdin()
514{
515    show "${FUNCNAME[0]}"
516
517    start_time=$(get_time)
518    object_name="mc-test-object-$RANDOM"
519    echo "testcontent" | "${MC_CMD[@]}" cat > stdin.output
520    assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to redirect stdin to stdout using 'mc cat'"
521    assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "42ed9fb3563d8e9c7bb522be443033f4" stdin.output
522    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm stdin.output
523
524    log_success "$start_time" "${FUNCNAME[0]}"
525}
526
527
528function test_mirror_list_objects()
529{
530    show "${FUNCNAME[0]}"
531
532    start_time=$(get_time)
533    bucket_name="mc-test-bucket-$RANDOM"
534    object_name="mc-test-object-$RANDOM"
535    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket_name}"
536    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mirror "$DATA_DIR" "${SERVER_ALIAS}/${bucket_name}"
537
538    diff -bB <(ls "$DATA_DIR") <("${MC_CMD[@]}" --json ls "${SERVER_ALIAS}/${bucket_name}/" | jq -r .key) >/dev/null 2>&1
539    assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "mirror and list differs"
540
541    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb --force "${SERVER_ALIAS}/${bucket_name}"
542
543    log_success "$start_time" "${FUNCNAME[0]}"
544}
545
546## Tests mc mirror command with --storage-class flag set
547function test_mirror_list_objects_storage_class()
548{
549    show "${FUNCNAME[0]}"
550
551    start_time=$(get_time)
552    bucket_name="mc-test-bucket-$RANDOM"
553    object_name="mc-test-object-$RANDOM"
554    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket_name}"
555    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mirror --storage-class REDUCED_REDUNDANCY "$DATA_DIR" "${SERVER_ALIAS}/${bucket_name}"
556
557    diff -bB <(ls "$DATA_DIR") <("${MC_CMD[@]}" --json ls "${SERVER_ALIAS}/${bucket_name}/" | jq -r .key) >/dev/null 2>&1
558    assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "mirror and list differs"
559
560    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb --force "${SERVER_ALIAS}/${bucket_name}"
561
562    log_success "$start_time" "${FUNCNAME[0]}"
563}
564
565## Tests find command with --older-than set to 1day, should be empty.
566function test_find_empty() {
567    show "${FUNCNAME[0]}"
568
569    start_time=$(get_time)
570    bucket_name="mc-test-bucket-$RANDOM"
571    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket_name}"
572    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mirror "$DATA_DIR" "${SERVER_ALIAS}/${bucket_name}"
573
574    # find --older-than 1 day should be empty, so we compare with empty string.
575    diff -bB <(echo "") <("${MC_CMD[@]}" find "${SERVER_ALIAS}/${bucket_name}" --json --older-than 1d | jq -r .key | sed "s/${SERVER_ALIAS}\/${bucket_name}\///g") >/dev/null 2>&1
576    assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "mirror and list differs"
577
578    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb --force "${SERVER_ALIAS}/${bucket_name}"
579
580    log_success "$start_time" "${FUNCNAME[0]}"
581}
582
583## Tests find command, should list.
584function test_find() {
585    show "${FUNCNAME[0]}"
586
587    start_time=$(get_time)
588    bucket_name="mc-test-bucket-$RANDOM"
589    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket_name}"
590    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mirror "$DATA_DIR" "${SERVER_ALIAS}/${bucket_name}"
591
592    diff -bB <(ls "$DATA_DIR") <("${MC_CMD[@]}" --json find "${SERVER_ALIAS}/${bucket_name}/" | jq -r .key | sed "s/${SERVER_ALIAS}\/${bucket_name}\///g") >/dev/null 2>&1
593    assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "mirror and list differs"
594
595    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb --force "${SERVER_ALIAS}/${bucket_name}"
596
597    log_success "$start_time" "${FUNCNAME[0]}"
598}
599
600function test_watch_object()
601{
602    show "${FUNCNAME[0]}"
603
604    start_time=$(get_time)
605    bucket_name="mc-test-bucket-$RANDOM"
606    object_name="mc-test-object-$RANDOM"
607    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket_name}"
608
609    # start a process to watch on bucket
610    "${MC_CMD[@]}" --json watch "${SERVER_ALIAS}/${bucket_name}" > "$WATCH_OUT_FILE" &
611    watch_cmd_pid=$!
612    sleep 1
613
614    ( assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${bucket_name}/${object_name}" )
615    rv=$?
616    if [ "$rv" -ne 0 ]; then
617        kill "$watch_cmd_pid"
618        exit "$rv"
619    fi
620
621    sleep 1
622    if ! jq -r .events.type "$WATCH_OUT_FILE" | grep -qi ObjectCreated; then
623        kill "$watch_cmd_pid"
624        assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure 1 "ObjectCreated event not found"
625    fi
626
627    ( assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${SERVER_ALIAS}/${bucket_name}/${object_name}" )
628    rv=$?
629    if [ "$rv" -ne 0 ]; then
630        kill "$watch_cmd_pid"
631        exit "$rv"
632    fi
633
634    sleep 1
635    if ! jq -r .events.type "$WATCH_OUT_FILE" | grep -qi ObjectRemoved; then
636        kill "$watch_cmd_pid"
637        assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure 1 "ObjectRemoved event not found"
638    fi
639
640    kill "$watch_cmd_pid"
641
642    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb --force "${SERVER_ALIAS}/${bucket_name}"
643
644    log_success "$start_time" "${FUNCNAME[0]}"
645}
646
647
648function test_config_host_add()
649{
650    show "${FUNCNAME[0]}"
651    start_time=$(get_time)
652
653    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd alias set "${SERVER_ALIAS}1" "$ENDPOINT" "$ACCESS_KEY" "$SECRET_KEY"
654    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd alias list "${SERVER_ALIAS}1"
655
656    log_success "$start_time" "${FUNCNAME[0]}"
657}
658
659function test_config_host_add_error()
660{
661    show "${FUNCNAME[0]}"
662    start_time=$(get_time)
663
664    out=$("${MC_CMD[@]}" --json alias set "${SERVER_ALIAS}1" "$ENDPOINT" "$ACCESS_KEY" "invalid-secret")
665    assert_failure "$start_time" "${FUNCNAME[0]}" show_on_success $? "adding host should fail"
666    got_code=$(echo "$out" | jq -r .error.cause.error.Code)
667    if [ "${got_code}" != "SignatureDoesNotMatch" ]; then
668        assert_failure "$start_time" "${FUNCNAME[0]}" show_on_failure 1 "incorrect error code ${got_code} returned by server"
669    fi
670
671    log_success "$start_time" "${FUNCNAME[0]}"
672}
673
674function test_put_object_with_sse()
675{
676    show "${FUNCNAME[0]}"
677    start_time=$(get_time)
678    object_name="mc-test-object-$RANDOM"
679    cli_flag="${SERVER_ALIAS}/${BUCKET_NAME}=32byteslongsecretkeymustbegiven1"
680    # put encrypted object; then delete with correct secret key
681    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag}" "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
682    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm --encrypt-key "${cli_flag}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
683    log_success "$start_time" "${FUNCNAME[0]}"
684}
685
686function test_put_object_with_encoded_sse()
687{
688    show "${FUNCNAME[0]}"
689    start_time=$(get_time)
690    object_name="mc-test-object-$RANDOM"
691    cli_flag="${SERVER_ALIAS}/${BUCKET_NAME}=MzJieXRlc2xvbmdzZWNyZWFiY2RlZmcJZ2l2ZW5uMjE="
692    # put encrypted object; then delete with correct secret key
693    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag}" "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
694    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm --encrypt-key "${cli_flag}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
695    log_success "$start_time" "${FUNCNAME[0]}"
696}
697
698function test_put_object_with_sse_error()
699{
700    show "${FUNCNAME[0]}"
701    start_time=$(get_time)
702    object_name="mc-test-object-$RANDOM"
703    cli_flag="${SERVER_ALIAS}/${BUCKET_NAME}=32byteslongsecretkeymustbegiven"
704    # put object with invalid encryption key; should fail
705    assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag}" "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
706    log_success "$start_time" "${FUNCNAME[0]}"
707}
708
709function test_cat_object_with_sse()
710{
711    show "${FUNCNAME[0]}"
712    start_time=$(get_time)
713    object_name="mc-test-object-$RANDOM"
714    cli_flag="${SERVER_ALIAS}/${BUCKET_NAME}=32byteslongsecretkeymustbegiven1"
715    # put encrypted object; then cat object correct secret key
716    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp  --encrypt-key "${cli_flag}" "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
717    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cat --encrypt-key "${cli_flag}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
718    log_success "$start_time" "${FUNCNAME[0]}"
719}
720
721function test_cat_object_with_sse_error()
722{
723    show "${FUNCNAME[0]}"
724    start_time=$(get_time)
725    object_name="mc-test-object-$RANDOM"
726    cli_flag="${SERVER_ALIAS}/${BUCKET_NAME}=32byteslongsecretkeymustbegiven1"
727    # put encrypted object; then cat object with no secret key
728    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp  --encrypt-key "${cli_flag}" "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
729    assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd cat  "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
730    log_success "$start_time" "${FUNCNAME[0]}"
731}
732
733# Test "mc cp -r" command of a directory with and without a leading slash
734function test_copy_directory()
735{
736    show "${FUNCNAME[0]}"
737
738    random_dir="dir-$RANDOM-$RANDOM"
739    tmpdir="$(mktemp -d)"
740
741    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${random_dir}/object-name"
742    assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to upload an object"
743
744    # Copy a directory with a trailing slash
745    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp -r "${SERVER_ALIAS}/${BUCKET_NAME}/${random_dir}/" "${tmpdir}/"
746    assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to copy a directory with a trailing slash"
747    assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_1_MB_MD5SUM" "${tmpdir}/object-name"
748    assert_success "$start_time" "${FUNCNAME[0]}" rm "${tmpdir}/object-name"
749
750    # Copy a directory without a trailing slash
751    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp -r "${SERVER_ALIAS}/${BUCKET_NAME}/${random_dir}" "${tmpdir}/"
752    assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to copy a directory without a trailing slash"
753    assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_1_MB_MD5SUM" "${tmpdir}/${random_dir}/object-name"
754
755    # Cleanup
756    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm -r --force "${SERVER_ALIAS}/${BUCKET_NAME}/${random_dir}/"
757    assert_success "$start_time" "${FUNCNAME[0]}" rm -r "${tmpdir}"
758
759    log_success "$start_time" "${FUNCNAME[0]}"
760}
761
762# Test "mc cp -a" command to see if it preserves file system attributes
763function test_copy_object_preserve_filesystem_attr()
764{
765    show "${FUNCNAME[0]}"
766    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp -a "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
767    diff -bB <("${MC_CMD[@]}"   --json stat "${FILE_1_MB}"  |  jq -r '.metadata."X-Amz-Meta-Mc-Attrs"')  >/dev/null 2>&1 <("${MC_CMD[@]}"   --json stat "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"  |  jq -r '.metadata."X-Amz-Meta-Mc-Attrs"')  >/dev/null 2>&1
768    assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to put object with file system attribute"
769    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
770    log_success "$start_time" "${FUNCNAME[0]}"
771}
772
773function test_copy_object_with_sse_rewrite()
774{
775    # test server side copy and remove operation - target is unencrypted while source is encrypted
776    show "${FUNCNAME[0]}"
777    start_time=$(get_time)
778    prefix="prefix"
779    object_name="mc-test-object-$RANDOM"
780
781    cli_flag="${SERVER_ALIAS}/${BUCKET_NAME}/${prefix}=32byteslongsecretkeymustbegiven1"
782    # create encrypted object on server
783    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag}" "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${prefix}/${object_name}"
784    # now do a server side copy and store it unencrypted.
785    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag}" "${SERVER_ALIAS}/${BUCKET_NAME}/${prefix}/${object_name}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
786    # cat the unencrypted destination object. should return data without any error
787    "${MC_CMD[@]}" cat "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}" >"${object_name}.downloaded"
788    assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to download object using 'mc cat'"
789    assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_1_MB_MD5SUM" "${object_name}.downloaded"
790    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${object_name}.downloaded"
791    # mc rm on with multi-object delete, deletes encrypted object without encryption key.
792    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm --encrypt-key "${cli_flag}" "${SERVER_ALIAS}/${BUCKET_NAME}/${prefix}/${object_name}"
793    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
794
795    log_success "$start_time" "${FUNCNAME[0]}"
796}
797
798function test_copy_object_with_sse_dest()
799{
800    # test server side copy and remove operation - target is encrypted with different key
801    show "${FUNCNAME[0]}"
802    start_time=$(get_time)
803    prefix="prefix"
804    object_name="mc-test-object-$RANDOM"
805
806    cli_flag1="${SERVER_ALIAS}/${BUCKET_NAME}/${prefix}=32byteslongsecretkeymustbegiven1"
807    cli_flag2="${SERVER_ALIAS}/${BUCKET_NAME}=32byteslongsecretkeymustbegiven2"
808
809    # create encrypted object on server
810    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag1}" "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${prefix}/${object_name}"
811    # now do a server side copy and store it eith different encryption key.
812    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag1},${cli_flag2}"  "${SERVER_ALIAS}/${BUCKET_NAME}/${prefix}/${object_name}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
813    # cat the destination object with the new key. should return data without any error
814    "${MC_CMD[@]}" cat --encrypt-key "${cli_flag2}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}" > "${object_name}.downloaded"
815    assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to download object using 'mc cat'"
816    assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_1_MB_MD5SUM" "${object_name}.downloaded"
817    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${object_name}.downloaded"
818    # mc rm on src object with first encryption key should pass
819    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm --encrypt-key "${cli_flag1}" "${SERVER_ALIAS}/${BUCKET_NAME}/${prefix}/${object_name}"
820    # mc rm on encrypted destination object with second encryption key should pass
821    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm  --encrypt-key "${cli_flag2}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
822
823    log_success "$start_time" "${FUNCNAME[0]}"
824}
825
826function test_sse_key_rotation()
827{
828    # test server side copy and remove operation - target is encrypted with different key
829    show "${FUNCNAME[0]}"
830    start_time=$(get_time)
831    prefix="prefix"
832    object_name="mc-test-object-$RANDOM"
833    old_key="32byteslongsecretkeymustbegiven1"
834    new_key="32byteslongsecretkeymustbegiven2"
835    cli_flag1="${SERVER_ALIAS}/${BUCKET_NAME}/${prefix}=${old_key}"
836    cli_flag2="${SERVER_ALIAS_TLS}/${BUCKET_NAME}=${new_key}"
837
838    # create encrypted object on server
839    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag1}" "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${prefix}/${object_name}"
840    # now do a server side copy on same object and do a key rotation
841    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag1},${cli_flag2}"  "${SERVER_ALIAS}/${BUCKET_NAME}/${prefix}/${object_name}" "${SERVER_ALIAS_TLS}/${BUCKET_NAME}/${object_name}"
842    # cat the object with the new key. should return data without any error
843    "${MC_CMD[@]}" cat --encrypt-key "${cli_flag2}" "${SERVER_ALIAS_TLS}/${BUCKET_NAME}/${object_name}" > "${object_name}.downloaded"
844    assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to download object using 'mc cat'"
845    assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_1_MB_MD5SUM" "${object_name}.downloaded"
846    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${object_name}.downloaded"
847    # mc rm on encrypted object with succeed anyways, without encrypted keys.
848    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${SERVER_ALIAS_TLS}/${BUCKET_NAME}/${object_name}"
849
850    log_success "$start_time" "${FUNCNAME[0]}"
851}
852
853function test_mirror_with_sse()
854{
855    # test if mirror operation works with encrypted objects
856    show "${FUNCNAME[0]}"
857
858    start_time=$(get_time)
859    bucket_name="mc-test-bucket-$RANDOM"
860    cli_flag="${SERVER_ALIAS}/${bucket_name}=32byteslongsecretkeymustbegiven1"
861
862    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket_name}"
863    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mirror --encrypt-key "${cli_flag}" "$DATA_DIR" "${SERVER_ALIAS}/${bucket_name}"
864    diff -bB <(ls "$DATA_DIR") <("${MC_CMD[@]}" --json ls "${SERVER_ALIAS}/${bucket_name}/" | jq -r .key) >/dev/null 2>&1
865    assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "mirror and list differs"
866    # Remove the test bucket with its contents
867    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb --force "${SERVER_ALIAS}/${bucket_name}"
868
869    log_success "$start_time" "${FUNCNAME[0]}"
870}
871
872function test_rm_object_with_sse()
873{
874    show "${FUNCNAME[0]}"
875
876    # test whether remove fails for encrypted object if secret key not provided.
877    start_time=$(get_time)
878    object_name="mc-test-object-$RANDOM"
879    cli_flag="${SERVER_ALIAS}/${BUCKET_NAME}=32byteslongsecretkeymustbegiven1"
880
881    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag}" "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
882    # rm will not fail even if the encryption keys are not provided, since mc rm uses multi-object delete.
883    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
884
885    log_success "$start_time" "${FUNCNAME[0]}"
886}
887
888function test_get_object_with_sse()
889{
890    show "${FUNCNAME[0]}"
891
892    start_time=$(get_time)
893    object_name="mc-test-object-$RANDOM"
894    cli_flag="${SERVER_ALIAS}/${BUCKET_NAME}=32byteslongsecretkeymustbegiven1"
895
896    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag}" "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
897    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}" "${object_name}.downloaded"
898    assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_1_MB_MD5SUM" "${object_name}.downloaded"
899    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm --encrypt-key "${cli_flag}" "${object_name}.downloaded" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
900
901    log_success "$start_time" "${FUNCNAME[0]}"
902}
903
904function test_put_object_multipart_sse()
905{
906    show "${FUNCNAME[0]}"
907
908    start_time=$(get_time)
909    object_name="mc-test-object-$RANDOM"
910    cli_flag="${SERVER_ALIAS}/${BUCKET_NAME}=32byteslongsecretkeymustbegiven1"
911
912    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag}" "${FILE_65_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
913    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm --encrypt-key "${cli_flag}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
914
915    log_success "$start_time" "${FUNCNAME[0]}"
916}
917
918function test_admin_users()
919{
920    show "${FUNCNAME[0]}"
921
922    start_time=$(get_time)
923
924    # create a user
925    username=foo
926    password=foobar12345
927    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd admin user add "$SERVER_ALIAS" "$username" "$password"
928
929    # check that user appears in the user list
930    "${MC_CMD[@]}" --json admin user list "${SERVER_ALIAS}" | jq -r '.accessKey' | grep --quiet "^${username}$"
931    rv=$?
932    assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure ${rv} "user ${username} did NOT appear in the list of users returned by server"
933
934    # setup temporary alias to make requests as the created user.
935    scheme="https"
936    if [ "$ENABLE_HTTPS" != "1" ]; then
937        scheme="http"
938    fi
939    object1_name="mc-test-object-$RANDOM"
940    object2_name="mc-test-object-$RANDOM"
941    export MC_HOST_foo=${scheme}://${username}:${password}@${SERVER_ENDPOINT}
942
943    # check that the user can write objects with readwrite policy
944    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd admin policy set "$SERVER_ALIAS" readwrite user="${username}"
945    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "$FILE_1_MB" "foo/${BUCKET_NAME}/${object1_name}"
946
947    # check that the user cannot write objects with readonly policy
948    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd admin policy set "$SERVER_ALIAS" readonly user="$username"
949    assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd cp "$FILE_1_MB" "foo/${BUCKET_NAME}/${object2_name}"
950
951    # check that the user can read with readonly policy
952    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cat "foo/${BUCKET_NAME}/${object1_name}"
953
954    # check that user can delete with readwrite policy
955    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd admin policy set "$SERVER_ALIAS" readwrite user="${username}"
956    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "foo/${BUCKET_NAME}/${object1_name}"
957
958    # check that user cannot perform admin actions with readwrite policy
959    assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd admin info "foo"
960
961    # create object1_name for subsequent tests.
962    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "$FILE_1_MB" "foo/${BUCKET_NAME}/${object1_name}"
963
964    # check that user can be disabled
965    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd admin user disable "$SERVER_ALIAS" "$username"
966
967    # check that disabled cannot perform any action
968    assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd cat "foo/${BUCKET_NAME}/${object1_name}"
969
970    # check that user can be enabled and can then perform an allowed action
971    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd admin user enable "$SERVER_ALIAS" "$username"
972    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cat "foo/${BUCKET_NAME}/${object1_name}"
973
974    # check that user can be removed, and then is no longer available
975    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd admin user remove "$SERVER_ALIAS" "$username"
976    assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd cat "foo/${BUCKET_NAME}/${object1_name}"
977
978    unset MC_HOST_foo
979
980    log_success "$start_time" "${FUNCNAME[0]}"
981}
982
983function run_test()
984{
985    test_make_bucket
986    test_make_bucket_error
987    test_rb
988
989    setup
990    test_put_object
991    test_put_object_error
992    test_put_object_0byte
993    test_put_object_with_storage_class
994    test_put_object_with_storage_class_error
995    test_put_object_with_metadata
996    test_put_object_multipart
997    test_get_object
998    test_get_object_multipart
999    test_presigned_post_policy_error
1000    test_presigned_put_object
1001    test_presigned_get_object
1002    test_cat_object
1003    test_cat_stdin
1004    test_copy_directory
1005    test_mirror_list_objects
1006    test_mirror_list_objects_storage_class
1007    test_copy_object_preserve_filesystem_attr
1008    test_find
1009    test_find_empty
1010    if [ -z "$MINT_MODE" ]; then
1011        test_watch_object
1012    fi
1013
1014    if [ "$ENABLE_HTTPS" == "1" ]; then
1015        test_put_object_with_sse
1016        test_put_object_with_encoded_sse
1017        test_put_object_with_sse_error
1018        test_put_object_multipart_sse
1019        test_get_object_with_sse
1020        test_cat_object_with_sse
1021        test_cat_object_with_sse_error
1022        test_copy_object_with_sse_rewrite
1023        test_copy_object_with_sse_dest
1024        test_sse_key_rotation
1025        test_mirror_with_sse
1026        test_rm_object_with_sse
1027    fi
1028
1029    test_config_host_add
1030    test_config_host_add_error
1031
1032    if [ "$ENABLE_ADMIN" == "1" ]; then
1033        test_admin_users
1034    fi
1035
1036    teardown
1037}
1038
1039function __init__()
1040{
1041    set -e
1042    # For Mint, setup is already done.  For others, setup the environment
1043    if [ -z "$MINT_MODE" ]; then
1044        mkdir -p "$WORK_DIR"
1045        mkdir -p "$DATA_DIR"
1046
1047        # If mc executable binary is not available in current directory, use it in the path.
1048        if [ ! -x "$MC" ]; then
1049            if ! MC=$(which mc 2>/dev/null); then
1050                echo "'mc' executable binary not found in current directory and in path"
1051                exit 1
1052            fi
1053        fi
1054    fi
1055
1056    if [ ! -x "$MC" ]; then
1057        echo "$MC executable binary not found"
1058        exit 1
1059    fi
1060
1061    mkdir -p "$MC_CONFIG_DIR"
1062    MC_CMD=( "${MC}" --config-dir "$MC_CONFIG_DIR" --quiet --no-color )
1063
1064    if [ ! -e "$FILE_0_B" ]; then
1065        base64 /dev/urandom | head -c 0 >"$FILE_0_B"
1066    fi
1067
1068    if [ ! -e "$FILE_1_MB" ]; then
1069        base64 /dev/urandom | head -c 1048576 >"$FILE_1_MB"
1070    fi
1071
1072    if [ ! -e "$FILE_65_MB" ]; then
1073        base64 /dev/urandom | head -c 68157440 >"$FILE_65_MB"
1074    fi
1075
1076    set -E
1077    set -o pipefail
1078
1079    FILE_0_B_MD5SUM="$(get_md5sum "$FILE_0_B")"
1080    if [ $? -ne 0 ]; then
1081        echo "unable to get md5sum of $FILE_0_B"
1082        exit 1
1083    fi
1084
1085    FILE_1_MB_MD5SUM="$(get_md5sum "$FILE_1_MB")"
1086    if [ $? -ne 0 ]; then
1087        echo "unable to get md5sum of $FILE_1_MB"
1088        exit 1
1089    fi
1090
1091    FILE_65_MB_MD5SUM="$(get_md5sum "$FILE_65_MB")"
1092    if [ $? -ne 0 ]; then
1093        echo "unable to get md5sum of $FILE_65_MB"
1094        exit 1
1095    fi
1096    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd alias set "${SERVER_ALIAS}" "$ENDPOINT" "$ACCESS_KEY" "$SECRET_KEY"
1097    assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd alias set "${SERVER_ALIAS_TLS}" "$ENDPOINT" "$ACCESS_KEY" "$SECRET_KEY"
1098
1099    set +e
1100}
1101
1102function main()
1103{
1104    ( run_test )
1105    rv=$?
1106
1107    rm -fr "$MC_CONFIG_DIR" "$WATCH_OUT_FILE"
1108    if [ -z "$MINT_MODE" ]; then
1109        rm -fr "$WORK_DIR" "$DATA_DIR"
1110    fi
1111
1112    exit "$rv"
1113}
1114
1115__init__ "$@"
1116main "$@"
1117