run-tests.py
12bc8cc8
 #!/usr/bin/env python2
f11319be
 # -*- coding=utf-8 -*-
330c51eb
 
 ## Amazon S3cmd - testsuite
 ## Author: Michal Ludvig <michal@logix.cz>
 ##         http://www.logix.cz/michal
 ## License: GPL Version 2
afd51b6c
 ## Copyright: TGRMN Software and contributors
330c51eb
 
 import sys
9856527a
 import os
330c51eb
 import re
f886eda4
 import time
330c51eb
 from subprocess import Popen, PIPE, STDOUT
f891a814
 import locale
4459b9ad
 import getpass
e14a7511
 import S3.Exceptions
 import S3.Config
8214d4f0
 from S3.ExitCodes import *
330c51eb
 
 count_pass = 0
 count_fail = 0
ca86524c
 count_skip = 0
 
 test_counter = 0
 run_tests = []
 exclude_tests = []
 
3677a3ba
 verbose = False
ec5e518c
 configfile = None
3677a3ba
 
ca86524c
 if os.name == "posix":
d439efb4
     have_wget = True
ca86524c
 elif os.name == "nt":
d439efb4
     have_wget = False
ca86524c
 else:
d439efb4
     print "Unknown platform: %s" % os.name
     sys.exit(1)
330c51eb
 
e14a7511
 config_file = None
 if os.getenv("HOME"):
     config_file = os.path.join(os.getenv("HOME"), ".s3cfg")
 elif os.name == "nt" and os.getenv("USERPROFILE"):
58431bc5
     config_file = os.path.join(os.getenv("USERPROFILE").decode('mbcs'), os.getenv("APPDATA").decode('mbcs') or 'Application Data', "s3cmd.ini")
e14a7511
 
 cfg = S3.Config.Config(config_file)
 
96222f57
 ## Unpack testsuite/ directory
 if not os.path.isdir('testsuite') and os.path.isfile('testsuite.tar.gz'):
d439efb4
     os.system("tar -xz -f testsuite.tar.gz")
96222f57
 if not os.path.isdir('testsuite'):
d439efb4
     print "Something went wrong while unpacking testsuite.tar.gz"
     sys.exit(1)
96222f57
 
1ba1f69a
 os.system("tar -xf testsuite/checksum.tar -C testsuite")
 if not os.path.isfile('testsuite/checksum/cksum33.txt'):
d439efb4
     print "Something went wrong while unpacking testsuite/checkum.tar"
     sys.exit(1)
 
96222f57
 ## Fix up permissions for permission-denied tests
 os.chmod("testsuite/permission-tests/permission-denied-dir", 0444)
 os.chmod("testsuite/permission-tests/permission-denied.txt", 0000)
 
4986ae85
 ## Patterns for Unicode tests
 patterns = {}
 patterns['UTF-8'] = u"ŪņЇЌœđЗ/☺ unicode € rocks ™"
 patterns['GBK'] = u"12月31日/1-特色條目"
 
 encoding = locale.getpreferredencoding()
 if not encoding:
d439efb4
     print "Guessing current system encoding failed. Consider setting $LANG variable."
     sys.exit(1)
5f7a2d5f
 else:
d439efb4
     print "System encoding: " + encoding
4986ae85
 
 have_encoding = os.path.isdir('testsuite/encodings/' + encoding)
 if not have_encoding and os.path.isfile('testsuite/encodings/%s.tar.gz' % encoding):
d439efb4
     os.system("tar xvz -C testsuite/encodings -f testsuite/encodings/%s.tar.gz" % encoding)
     have_encoding = os.path.isdir('testsuite/encodings/' + encoding)
4986ae85
 
 if have_encoding:
d439efb4
     #enc_base_remote = "%s/xyz/%s/" % (pbucket(1), encoding)
     enc_pattern = patterns[encoding]
5f7a2d5f
 else:
d439efb4
     print encoding + " specific files not found."
4986ae85
 
76ce6441
 if not os.path.isdir('testsuite/crappy-file-name'):
d439efb4
     os.system("tar xvz -C testsuite -f testsuite/crappy-file-name.tar.gz")
     # TODO: also unpack if the tarball is newer than the directory timestamp
     #       for instance when a new version was pulled from SVN.
76ce6441
 
e64678ae
 def test(label, cmd_args = [], retcode = 0, must_find = [], must_not_find = [], must_find_re = [], must_not_find_re = [], stdin = None):
d439efb4
     def command_output():
         print "----"
ba59d366
         print " ".join([" " in arg and "'%s'" % arg or arg for arg in cmd_args])
d439efb4
         print "----"
         print stdout
         print "----"
 
     def failure(message = ""):
         global count_fail
         if message:
             message = "  (%r)" % message
         print "\x1b[31;1mFAIL%s\x1b[0m" % (message)
         count_fail += 1
         command_output()
         #return 1
         sys.exit(1)
     def success(message = ""):
         global count_pass
         if message:
             message = "  (%r)" % message
         print "\x1b[32;1mOK\x1b[0m%s" % (message)
         count_pass += 1
         if verbose:
             command_output()
         return 0
     def skip(message = ""):
         global count_skip
         if message:
             message = "  (%r)" % message
         print "\x1b[33;1mSKIP\x1b[0m%s" % (message)
         count_skip += 1
         return 0
     def compile_list(_list, regexps = False):
         if regexps == False:
             _list = [re.escape(item.encode(encoding, "replace")) for item in _list]
 
         return [re.compile(item, re.MULTILINE) for item in _list]
 
     global test_counter
     test_counter += 1
     print ("%3d  %s " % (test_counter, label)).ljust(30, "."),
     sys.stdout.flush()
 
     if run_tests.count(test_counter) == 0 or exclude_tests.count(test_counter) > 0:
         return skip()
 
     if not cmd_args:
         return skip()
 
e64678ae
     p = Popen(cmd_args, stdin = stdin, stdout = PIPE, stderr = STDOUT, universal_newlines = True, close_fds = True)
d439efb4
     stdout, stderr = p.communicate()
547c1ba1
     if type(retcode) not in [list, tuple]: retcode = [retcode]
     if p.returncode not in retcode:
         return failure("retcode: %d, expected one of: %s" % (p.returncode, retcode))
d439efb4
 
     if type(must_find) not in [ list, tuple ]: must_find = [must_find]
     if type(must_find_re) not in [ list, tuple ]: must_find_re = [must_find_re]
     if type(must_not_find) not in [ list, tuple ]: must_not_find = [must_not_find]
     if type(must_not_find_re) not in [ list, tuple ]: must_not_find_re = [must_not_find_re]
 
     find_list = []
     find_list.extend(compile_list(must_find))
     find_list.extend(compile_list(must_find_re, regexps = True))
     find_list_patterns = []
     find_list_patterns.extend(must_find)
     find_list_patterns.extend(must_find_re)
 
     not_find_list = []
     not_find_list.extend(compile_list(must_not_find))
     not_find_list.extend(compile_list(must_not_find_re, regexps = True))
     not_find_list_patterns = []
     not_find_list_patterns.extend(must_not_find)
     not_find_list_patterns.extend(must_not_find_re)
 
     for index in range(len(find_list)):
         match = find_list[index].search(stdout)
         if not match:
             return failure("pattern not found: %s" % find_list_patterns[index])
     for index in range(len(not_find_list)):
         match = not_find_list[index].search(stdout)
         if match:
             return failure("pattern found: %s (match: %s)" % (not_find_list_patterns[index], match.group(0)))
 
     return success()
330c51eb
 
 def test_s3cmd(label, cmd_args = [], **kwargs):
d439efb4
     if not cmd_args[0].endswith("s3cmd"):
12bc8cc8
         cmd_args.insert(0, "python2")
d439efb4
         cmd_args.insert(1, "s3cmd")
ec5e518c
         if configfile:
             cmd_args.insert(2, "-c")
             cmd_args.insert(3, configfile)
9856527a
 
d439efb4
     return test(label, cmd_args, **kwargs)
330c51eb
 
ca86524c
 def test_mkdir(label, dir_name):
d439efb4
     if os.name in ("posix", "nt"):
         cmd = ['mkdir', '-p']
     else:
         print "Unknown platform: %s" % os.name
         sys.exit(1)
     cmd.append(dir_name)
     return test(label, cmd)
ca86524c
 
 def test_rmdir(label, dir_name):
d439efb4
     if os.path.isdir(dir_name):
         if os.name == "posix":
             cmd = ['rm', '-rf']
         elif os.name == "nt":
             cmd = ['rmdir', '/s/q']
         else:
             print "Unknown platform: %s" % os.name
             sys.exit(1)
         cmd.append(dir_name)
         return test(label, cmd)
     else:
         return test(label, [])
ca86524c
 
3894a49a
 def test_flushdir(label, dir_name):
d439efb4
     test_rmdir(label + "(rm)", dir_name)
     return test_mkdir(label + "(mk)", dir_name)
ca86524c
 
2d067a6d
 def test_copy(label, src_file, dst_file):
d439efb4
     if os.name == "posix":
         cmd = ['cp', '-f']
     elif os.name == "nt":
         cmd = ['copy']
     else:
         print "Unknown platform: %s" % os.name
         sys.exit(1)
     cmd.append(src_file)
     cmd.append(dst_file)
     return test(label, cmd)
2d067a6d
 
68f43b60
 def test_wget_HEAD(label, src_file, **kwargs):
     cmd = ['wget', '-q', '-S', '--method=HEAD']
f5ed9c91
     cmd.append(src_file)
     return test(label, cmd, **kwargs)
 
4459b9ad
 bucket_prefix = u"%s-" % getpass.getuser()
96222f57
 print "Using bucket prefix: '%s'" % bucket_prefix
 
ca86524c
 argv = sys.argv[1:]
 while argv:
d439efb4
     arg = argv.pop(0)
     if arg.startswith('--bucket-prefix='):
         print "Usage: '--bucket-prefix PREFIX', not '--bucket-prefix=PREFIX'"
         sys.exit(0)
     if arg in ("-h", "--help"):
         print "%s A B K..O -N" % sys.argv[0]
         print "Run tests number A, B and K through to O, except for N"
         sys.exit(0)
ec5e518c
 
     if arg in ("-c", "--config"):
         configfile = argv.pop(0)
         continue
d439efb4
     if arg in ("-l", "--list"):
         exclude_tests = range(0, 999)
         break
     if arg in ("-v", "--verbose"):
         verbose = True
         continue
     if arg in ("-p", "--bucket-prefix"):
         try:
             bucket_prefix = argv.pop(0)
         except IndexError:
             print "Bucket prefix option must explicitly supply a bucket name prefix"
             sys.exit(0)
         continue
ba59d366
     if ".." in arg:
d439efb4
         range_idx = arg.find("..")
         range_start = arg[:range_idx] or 0
         range_end = arg[range_idx+2:] or 999
         run_tests.extend(range(int(range_start), int(range_end) + 1))
     elif arg.startswith("-"):
         exclude_tests.append(int(arg[1:]))
     else:
         run_tests.append(int(arg))
ca86524c
 
 if not run_tests:
d439efb4
     run_tests = range(0, 999)
ca86524c
 
31fadab3
 # helper functions for generating bucket names
 def bucket(tail):
         '''Test bucket name'''
2895644c
         label = 'autotest'
         if str(tail) == '3':
                 label = 'Autotest'
         return '%ss3cmd-%s-%s' % (bucket_prefix, label, tail)
96222f57
 
31fadab3
 def pbucket(tail):
         '''Like bucket(), but prepends "s3://" for you'''
         return 's3://' + bucket(tail)
 
ca86524c
 ## ====== Remove test buckets
d56fa83a
 test_s3cmd("Remove test buckets", ['rb', '-r', '--force', pbucket(1), pbucket(2), pbucket(3)])
 
 ## ====== verify they were removed
 test_s3cmd("Verify no test buckets", ['ls'],
            must_not_find = [pbucket(1), pbucket(2), pbucket(3)])
f11319be
 
ca86524c
 
 ## ====== Create one bucket (EU)
d439efb4
 test_s3cmd("Create one bucket (EU)", ['mb', '--bucket-location=EU', pbucket(1)],
     must_find = "Bucket '%s/' created" % pbucket(1))
330c51eb
 
ca86524c
 
 
 ## ====== Create multiple buckets
d439efb4
 test_s3cmd("Create multiple buckets", ['mb', pbucket(2), pbucket(3)],
     must_find = [ "Bucket '%s/' created" % pbucket(2), "Bucket '%s/' created" % pbucket(3)])
330c51eb
 
ca86524c
 
 ## ====== Invalid bucket name
d439efb4
 test_s3cmd("Invalid bucket name", ["mb", "--bucket-location=EU", pbucket('EU')],
8214d4f0
     retcode = EX_USAGE,
d439efb4
     must_find = "ERROR: Parameter problem: Bucket name '%s' contains disallowed character" % bucket('EU'),
     must_not_find_re = "Bucket.*created")
330c51eb
 
ca86524c
 
 ## ====== Buckets list
d439efb4
 test_s3cmd("Buckets list", ["ls"],
     must_find = [ "autotest-1", "autotest-2", "Autotest-3" ], must_not_find_re = "autotest-EU")
f11319be
 
ca86524c
 
 ## ====== Sync to S3
96222f57
 test_s3cmd("Sync to S3", ['sync', 'testsuite/', pbucket(1) + '/xyz/', '--exclude', 'demo/*', '--exclude', '*.png', '--no-encrypt', '--exclude-from', 'testsuite/exclude.encodings' ],
d439efb4
     must_find = [ "WARNING: 32 non-printable characters replaced in: crappy-file-name/non-printables ^A^B^C^D^E^F^G^H^I^J^K^L^M^N^O^P^Q^R^S^T^U^V^W^X^Y^Z^[^\^]^^^_^? +-[\]^<>%%\"'#{}`&?.end",
                   "WARNING: File can not be uploaded: testsuite/permission-tests/permission-denied.txt: Permission denied",
                   "stored as '%s/xyz/crappy-file-name/non-printables ^A^B^C^D^E^F^G^H^I^J^K^L^M^N^O^P^Q^R^S^T^U^V^W^X^Y^Z^[^\^]^^^_^? +-[\\]^<>%%%%\"'#{}`&?.end'" % pbucket(1) ],
     must_not_find_re = [ "demo/", "\.png$", "permission-denied-dir" ])
4986ae85
 
 if have_encoding:
d439efb4
     ## ====== Sync UTF-8 / GBK / ... to S3
     test_s3cmd("Sync %s to S3" % encoding, ['sync', 'testsuite/encodings/' + encoding, '%s/xyz/encodings/' % pbucket(1), '--exclude', 'demo/*', '--no-encrypt' ],
         must_find = [ u"File 'testsuite/encodings/%(encoding)s/%(pattern)s' stored as '%(pbucket)s/xyz/encodings/%(encoding)s/%(pattern)s'" % { 'encoding' : encoding, 'pattern' : enc_pattern , 'pbucket' : pbucket(1)} ])
9856527a
 
 
ca86524c
 ## ====== List bucket content
31fadab3
 test_s3cmd("List bucket content", ['ls', '%s/xyz/' % pbucket(1) ],
87cd83e8
     must_find_re = [ u"DIR +%s/xyz/binary/$" % pbucket(1) , u"DIR +%s/xyz/etc/$" % pbucket(1) ],
d439efb4
     must_not_find = [ u"random-crap.md5", u"/demo" ])
9856527a
 
 
ca86524c
 ## ====== List bucket recursive
31fadab3
 must_find = [ u"%s/xyz/binary/random-crap.md5" % pbucket(1) ]
4986ae85
 if have_encoding:
d439efb4
     must_find.append(u"%(pbucket)s/xyz/encodings/%(encoding)s/%(pattern)s" % { 'encoding' : encoding, 'pattern' : enc_pattern, 'pbucket' : pbucket(1) })
96222f57
 
31fadab3
 test_s3cmd("List bucket recursive", ['ls', '--recursive', pbucket(1)],
d439efb4
     must_find = must_find,
     must_not_find = [ "logo.png" ])
9856527a
 
ca86524c
 ## ====== FIXME
31fadab3
 # test_s3cmd("Recursive put", ['put', '--recursive', 'testsuite/etc', '%s/xyz/' % pbucket(1) ])
9856527a
 
f11319be
 
3894a49a
 ## ====== Clean up local destination dir
 test_flushdir("Clean testsuite-out/", "testsuite-out")
f11319be
 
f4e85335
 ## ====== Put from stdin
e64678ae
 f = open('testsuite/single-file/single-file.txt', 'r')
 test_s3cmd("Put from stdin", ['put', '-', '%s/single-file/single-file.txt' % pbucket(1)],
            must_find = ["File '-' stored as '%s/single-file/single-file.txt'" % pbucket(1)],
            stdin = f)
 f.close()
f11319be
 
0699fa23
 ## ====== Multipart put
e64678ae
 os.system('dd if=/dev/urandom of=testsuite-out/urandom.bin bs=1M count=16 > /dev/null 2>&1')
0699fa23
 test_s3cmd("Put multipart", ['put', '--multipart-chunk-size-mb=5', 'testsuite-out/urandom.bin', '%s/urandom.bin' % pbucket(1)],
e64678ae
            must_not_find = ['abortmp'])
0699fa23
 
5d7af455
 ## ====== Multipart put from stdin
e64678ae
 f = open('testsuite-out/urandom.bin', 'r')
 test_s3cmd("Multipart large put from stdin", ['put', '--multipart-chunk-size-mb=5', '-', '%s/urandom2.bin' % pbucket(1)],
            must_find = ['%s/urandom2.bin' % pbucket(1)],
            must_not_find = ['abortmp'],
            stdin = f)
 f.close()
5d7af455
 
0699fa23
 ## ====== Clean up local destination dir
 test_flushdir("Clean testsuite-out/", "testsuite-out")
 
ca86524c
 ## ====== Sync from S3
31fadab3
 must_find = [ "File '%s/xyz/binary/random-crap.md5' stored as 'testsuite-out/xyz/binary/random-crap.md5'" % pbucket(1) ]
4986ae85
 if have_encoding:
d439efb4
     must_find.append(u"File '%(pbucket)s/xyz/encodings/%(encoding)s/%(pattern)s' stored as 'testsuite-out/xyz/encodings/%(encoding)s/%(pattern)s' " % { 'encoding' : encoding, 'pattern' : enc_pattern, 'pbucket' : pbucket(1) })
31fadab3
 test_s3cmd("Sync from S3", ['sync', '%s/xyz' % pbucket(1), 'testsuite-out'],
d439efb4
     must_find = must_find)
f11319be
 
 
73bf1c4d
 ## ====== Remove 'demo' directory
96222f57
 test_rmdir("Remove 'dir-test/'", "testsuite-out/xyz/dir-test/")
73bf1c4d
 
 
 ## ====== Create dir with name of a file
96222f57
 test_mkdir("Create file-dir dir", "testsuite-out/xyz/dir-test/file-dir")
73bf1c4d
 
 
 ## ====== Skip dst dirs
 test_s3cmd("Skip over dir", ['sync', '%s/xyz' % pbucket(1), 'testsuite-out'],
d439efb4
     must_find = "WARNING: testsuite-out/xyz/dir-test/file-dir is a directory - skipping over")
73bf1c4d
 
 
3894a49a
 ## ====== Clean up local destination dir
 test_flushdir("Clean testsuite-out/", "testsuite-out")
 
 
e3244a8c
 ## ====== Put public, guess MIME
31fadab3
 test_s3cmd("Put public, guess MIME", ['put', '--guess-mime-type', '--acl-public', 'testsuite/etc/logo.png', '%s/xyz/etc/logo.png' % pbucket(1)],
d439efb4
     must_find = [ "stored as '%s/xyz/etc/logo.png'" % pbucket(1) ])
e3244a8c
 
 
ca86524c
 ## ====== Retrieve from URL
 if have_wget:
e14a7511
     test("Retrieve from URL", ['wget', '-O', 'testsuite-out/logo.png', 'http://%s.%s/xyz/etc/logo.png' % (bucket(1), cfg.host_base)],
d439efb4
         must_find_re = [ 'logo.png.*saved \[22059/22059\]' ])
e3244a8c
 
 
 ## ====== Change ACL to Private
31fadab3
 test_s3cmd("Change ACL to Private", ['setacl', '--acl-private', '%s/xyz/etc/l*.png' % pbucket(1)],
d439efb4
     must_find = [ "logo.png: ACL set to Private" ])
e3244a8c
 
 
 ## ====== Verify Private ACL
 if have_wget:
e14a7511
     test("Verify Private ACL", ['wget', '-O', 'testsuite-out/logo.png', 'http://%s.%s/xyz/etc/logo.png' % (bucket(1), cfg.host_base)],
547c1ba1
          retcode = [1, 8],
          must_find_re = [ 'ERROR 403: Forbidden' ])
e3244a8c
 
 
 ## ====== Change ACL to Public
31fadab3
 test_s3cmd("Change ACL to Public", ['setacl', '--acl-public', '--recursive', '%s/xyz/etc/' % pbucket(1) , '-v'],
d439efb4
     must_find = [ "logo.png: ACL set to Public" ])
e3244a8c
 
 
 ## ====== Verify Public ACL
 if have_wget:
e14a7511
     test("Verify Public ACL", ['wget', '-O', 'testsuite-out/logo.png', 'http://%s.%s/xyz/etc/logo.png' % (bucket(1), cfg.host_base)],
d439efb4
         must_find_re = [ 'logo.png.*saved \[22059/22059\]' ])
ca86524c
 
f11319be
 
ca86524c
 ## ====== Sync more to S3
31fadab3
 test_s3cmd("Sync more to S3", ['sync', 'testsuite/', 's3://%s/xyz/' % bucket(1), '--no-encrypt' ],
d439efb4
     must_find = [ "File 'testsuite/demo/some-file.xml' stored as '%s/xyz/demo/some-file.xml' " % pbucket(1) ],
     must_not_find = [ "File 'testsuite/etc/linked.png' stored as '%s/xyz/etc/linked.png" % pbucket(1) ])
 
f11319be
 
1ba1f69a
 ## ====== Don't check MD5 sum on Sync
 test_copy("Change file cksum1.txt", "testsuite/checksum/cksum2.txt", "testsuite/checksum/cksum1.txt")
 test_copy("Change file cksum33.txt", "testsuite/checksum/cksum2.txt", "testsuite/checksum/cksum33.txt")
 test_s3cmd("Don't check MD5", ['sync', 'testsuite/', 's3://%s/xyz/' % bucket(1), '--no-encrypt', '--no-check-md5'],
d439efb4
     must_find = [ "cksum33.txt" ],
     must_not_find = [ "cksum1.txt" ])
1ba1f69a
 
 
 ## ====== Check MD5 sum on Sync
 test_s3cmd("Check MD5", ['sync', 'testsuite/', 's3://%s/xyz/' % bucket(1), '--no-encrypt', '--check-md5'],
d439efb4
     must_find = [ "cksum1.txt" ])
1ba1f69a
 
 
ca86524c
 ## ====== Rename within S3
31fadab3
 test_s3cmd("Rename within S3", ['mv', '%s/xyz/etc/logo.png' % pbucket(1), '%s/xyz/etc2/Logo.PNG' % pbucket(1)],
d439efb4
     must_find = [ 'File %s/xyz/etc/logo.png moved to %s/xyz/etc2/Logo.PNG' % (pbucket(1), pbucket(1))])
f11319be
 
ca86524c
 
 ## ====== Rename (NoSuchKey)
31fadab3
 test_s3cmd("Rename (NoSuchKey)", ['mv', '%s/xyz/etc/logo.png' % pbucket(1), '%s/xyz/etc2/Logo.PNG' % pbucket(1)],
f05fb73f
     retcode = EX_NOTFOUND,
d439efb4
     must_find_re = [ 'ERROR:.*NoSuchKey' ],
     must_not_find = [ 'File %s/xyz/etc/logo.png moved to %s/xyz/etc2/Logo.PNG' % (pbucket(1), pbucket(1)) ])
f11319be
 
248a3fa4
 ## ====== Sync more from S3 (invalid src)
 test_s3cmd("Sync more from S3 (invalid src)", ['sync', '--delete-removed', '%s/xyz/DOESNOTEXIST' % pbucket(1), 'testsuite-out'],
     must_not_find = [ "deleted: testsuite-out/logo.png" ])
ca86524c
 
257d6321
 ## ====== Sync more from S3
31fadab3
 test_s3cmd("Sync more from S3", ['sync', '--delete-removed', '%s/xyz' % pbucket(1), 'testsuite-out'],
d439efb4
     must_find = [ "deleted: testsuite-out/logo.png",
                   "File '%s/xyz/etc2/Logo.PNG' stored as 'testsuite-out/xyz/etc2/Logo.PNG' (22059 bytes" % pbucket(1),
                   "File '%s/xyz/demo/some-file.xml' stored as 'testsuite-out/xyz/demo/some-file.xml' " % pbucket(1) ],
     must_not_find_re = [ "not-deleted.*etc/logo.png" ])
257d6321
 
 
ca86524c
 ## ====== Make dst dir for get
 test_rmdir("Remove dst dir for get", "testsuite-out")
 
 
 ## ====== Get multiple files
31fadab3
 test_s3cmd("Get multiple files", ['get', '%s/xyz/etc2/Logo.PNG' % pbucket(1), '%s/xyz/etc/AtomicClockRadio.ttf' % pbucket(1), 'testsuite-out'],
8214d4f0
     retcode = EX_USAGE,
2933252b
     must_find = [ 'Destination must be a directory or stdout when downloading multiple sources.' ])
ca86524c
 
cd76140b
 ## ====== put/get non-ASCII filenames
 test_s3cmd("Put unicode filenames", ['put', u'testsuite/encodings/UTF-8/ŪņЇЌœđЗ/Žůžo',  u'%s/xyz/encodings/UTF-8/ŪņЇЌœđЗ/Žůžo' % pbucket(1)],
            retcode = 0,
            must_find = [ 'stored as' ])
 
ca86524c
 
 ## ====== Make dst dir for get
 test_mkdir("Make dst dir for get", "testsuite-out")
 
 
cd76140b
 ## ====== put/get non-ASCII filenames
 test_s3cmd("Get unicode filenames", ['get', u'%s/xyz/encodings/UTF-8/ŪņЇЌœđЗ/Žůžo' % pbucket(1), 'testsuite-out'],
            retcode = 0,
            must_find = [ 'saved as' ])
 
 
ca86524c
 ## ====== Get multiple files
31fadab3
 test_s3cmd("Get multiple files", ['get', '%s/xyz/etc2/Logo.PNG' % pbucket(1), '%s/xyz/etc/AtomicClockRadio.ttf' % pbucket(1), 'testsuite-out'],
d439efb4
     must_find = [ u"saved as 'testsuite-out/Logo.PNG'", u"saved as 'testsuite-out/AtomicClockRadio.ttf'" ])
ca86524c
 
dc1c96cf
 ## ====== Upload files differing in capitalisation
31fadab3
 test_s3cmd("blah.txt / Blah.txt", ['put', '-r', 'testsuite/blahBlah', pbucket(1)],
d439efb4
     must_find = [ '%s/blahBlah/Blah.txt' % pbucket(1), '%s/blahBlah/blah.txt' % pbucket(1)])
ca86524c
 
e0b946c0
 ## ====== Copy between buckets
31fadab3
 test_s3cmd("Copy between buckets", ['cp', '%s/xyz/etc2/Logo.PNG' % pbucket(1), '%s/xyz/etc2/logo.png' % pbucket(3)],
d439efb4
     must_find = [ "File %s/xyz/etc2/Logo.PNG copied to %s/xyz/etc2/logo.png" % (pbucket(1), pbucket(3)) ])
e0b946c0
 
 ## ====== Recursive copy
13fc0d5f
 test_s3cmd("Recursive copy, set ACL", ['cp', '-r', '--acl-public', '%s/xyz/' % pbucket(1), '%s/copy' % pbucket(2), '--exclude', 'demo/dir?/*.txt', '--exclude', 'non-printables*'],
d439efb4
     must_find = [ "File %s/xyz/etc2/Logo.PNG copied to %s/copy/etc2/Logo.PNG" % (pbucket(1), pbucket(2)),
                   "File %s/xyz/blahBlah/Blah.txt copied to %s/copy/blahBlah/Blah.txt" % (pbucket(1), pbucket(2)),
                   "File %s/xyz/blahBlah/blah.txt copied to %s/copy/blahBlah/blah.txt" % (pbucket(1), pbucket(2)) ],
     must_not_find = [ "demo/dir1/file1-1.txt" ])
13fc0d5f
 
 ## ====== Verify ACL and MIME type
 test_s3cmd("Verify ACL and MIME type", ['info', '%s/copy/etc2/Logo.PNG' % pbucket(2) ],
d439efb4
     must_find_re = [ "MIME type:.*image/png",
                      "ACL:.*\*anon\*: READ",
e14a7511
                      "URL:.*http://%s.%s/copy/etc2/Logo.PNG" % (bucket(2), cfg.host_base) ])
13fc0d5f
 
61cddf01
 ## ====== modify MIME type
da091eee
 test_s3cmd("Modify MIME type", ['modify', '--mime-type=binary/octet-stream', '%s/copy/etc2/Logo.PNG' % pbucket(2) ])
61cddf01
 
 test_s3cmd("Verify ACL and MIME type", ['info', '%s/copy/etc2/Logo.PNG' % pbucket(2) ],
     must_find_re = [ "MIME type:.*binary/octet-stream",
                      "ACL:.*\*anon\*: READ",
                      "URL:.*http://%s.%s/copy/etc2/Logo.PNG" % (bucket(2), cfg.host_base) ])
 
da091eee
 test_s3cmd("Modify MIME type back", ['modify', '--mime-type=image/png', '%s/copy/etc2/Logo.PNG' % pbucket(2) ])
61cddf01
 
 test_s3cmd("Verify ACL and MIME type", ['info', '%s/copy/etc2/Logo.PNG' % pbucket(2) ],
     must_find_re = [ "MIME type:.*image/png",
                      "ACL:.*\*anon\*: READ",
                      "URL:.*http://%s.%s/copy/etc2/Logo.PNG" % (bucket(2), cfg.host_base) ])
 
a6366f8d
 test_s3cmd("Add cache-control header", ['modify', '--add-header=cache-control: max-age=3600, public', '%s/copy/etc2/Logo.PNG' % pbucket(2) ],
f5ed9c91
     must_find_re = [ "File .* modified" ])
 
68f43b60
 if have_wget:
     test_wget_HEAD("HEAD check Cache-Control present", 'http://%s.%s/copy/etc2/Logo.PNG' % (bucket(2), cfg.host_base),
                    must_find_re = [ "Cache-Control: max-age=3600" ])
f5ed9c91
 
 test_s3cmd("Remove cache-control header", ['modify', '--remove-header=cache-control', '%s/copy/etc2/Logo.PNG' % pbucket(2) ],
     must_find_re = [ "File .* modified" ])
 
68f43b60
 if have_wget:
     test_wget_HEAD("HEAD check Cache-Control not present", 'http://%s.%s/copy/etc2/Logo.PNG' % (bucket(2), cfg.host_base),
                    must_not_find_re = [ "Cache-Control: max-age=3600" ])
f5ed9c91
 
f886eda4
 ## ====== sign
 test_s3cmd("sign string", ['sign', 's3cmd'], must_find_re = ["Signature:"])
 test_s3cmd("signurl time", ['signurl', '%s/copy/etc2/Logo.PNG' % pbucket(2), str(int(time.time()) + 60)], must_find_re = ["http://"])
 test_s3cmd("signurl time offset", ['signurl', '%s/copy/etc2/Logo.PNG' % pbucket(2), '+60'], must_find_re = ["http://"])
61cddf01
 
13fc0d5f
 ## ====== Rename within S3
 test_s3cmd("Rename within S3", ['mv', '%s/copy/etc2/Logo.PNG' % pbucket(2), '%s/copy/etc/logo.png' % pbucket(2)],
d439efb4
     must_find = [ 'File %s/copy/etc2/Logo.PNG moved to %s/copy/etc/logo.png' % (pbucket(2), pbucket(2))])
13fc0d5f
 
 ## ====== Sync between buckets
 test_s3cmd("Sync remote2remote", ['sync', '%s/xyz/' % pbucket(1), '%s/copy/' % pbucket(2), '--delete-removed', '--exclude', 'non-printables*'],
d439efb4
     must_find = [ "File %s/xyz/demo/dir1/file1-1.txt copied to %s/copy/demo/dir1/file1-1.txt" % (pbucket(1), pbucket(2)),
c64a06aa
                   "remote copy: etc/logo.png -> etc2/Logo.PNG",
d56fa83a
                   "File %s/copy/etc/logo.png deleted" % pbucket(2) ],
d439efb4
     must_not_find = [ "blah.txt" ])
e0b946c0
 
8ab3c3ac
 ## ====== Don't Put symbolic link
6332b625
 test_s3cmd("Don't put symbolic links", ['put', 'testsuite/etc/linked1.png', 's3://%s/xyz/' % bucket(1),],
81e3842f
            retcode = EX_USAGE,
            must_not_find_re = [ "linked1.png"])
8ab3c3ac
 
8c3bd026
 ## ====== Put symbolic link
 test_s3cmd("Put symbolic links", ['put', 'testsuite/etc/linked1.png', 's3://%s/xyz/' % bucket(1),'--follow-symlinks' ],
6332b625
            must_find = [ "File 'testsuite/etc/linked1.png' stored as '%s/xyz/linked1.png'" % pbucket(1)])
8c3bd026
 
7b5df262
 ## ====== Sync symbolic links
 test_s3cmd("Sync symbolic links", ['sync', 'testsuite/', 's3://%s/xyz/' % bucket(1), '--no-encrypt', '--follow-symlinks' ],
eb04bc15
     must_find = ["remote copy: etc2/Logo.PNG -> etc/linked.png"],
6332b625
            # Don't want to recursively copy linked directories!
            must_not_find_re = ["etc/more/linked-dir/more/give-me-more.txt",
                                "etc/brokenlink.png"],
            )
7b5df262
 
e0b946c0
 ## ====== Multi source move
31fadab3
 test_s3cmd("Multi-source move", ['mv', '-r', '%s/copy/blahBlah/Blah.txt' % pbucket(2), '%s/copy/etc/' % pbucket(2), '%s/moved/' % pbucket(2)],
d439efb4
     must_find = [ "File %s/copy/blahBlah/Blah.txt moved to %s/moved/Blah.txt" % (pbucket(2), pbucket(2)),
                   "File %s/copy/etc/AtomicClockRadio.ttf moved to %s/moved/AtomicClockRadio.ttf" % (pbucket(2), pbucket(2)),
                   "File %s/copy/etc/TypeRa.ttf moved to %s/moved/TypeRa.ttf" % (pbucket(2), pbucket(2)) ],
     must_not_find = [ "blah.txt" ])
e0b946c0
 
 ## ====== Verify move
31fadab3
 test_s3cmd("Verify move", ['ls', '-r', pbucket(2)],
d439efb4
     must_find = [ "%s/moved/Blah.txt" % pbucket(2),
                   "%s/moved/AtomicClockRadio.ttf" % pbucket(2),
                   "%s/moved/TypeRa.ttf" % pbucket(2),
                   "%s/copy/blahBlah/blah.txt" % pbucket(2) ],
     must_not_find = [ "%s/copy/blahBlah/Blah.txt" % pbucket(2),
                       "%s/copy/etc/AtomicClockRadio.ttf" % pbucket(2),
                       "%s/copy/etc/TypeRa.ttf" % pbucket(2) ])
e0b946c0
 
57e3e414
 ## ====== List all
 test_s3cmd("List all", ['la'],
            must_find = [ "%s/urandom.bin" % pbucket(1)])
 
ca86524c
 ## ====== Simple delete
31fadab3
 test_s3cmd("Simple delete", ['del', '%s/xyz/etc2/Logo.PNG' % pbucket(1)],
d439efb4
     must_find = [ "File %s/xyz/etc2/Logo.PNG deleted" % pbucket(1) ])
f11319be
 
7268831a
 ## ====== Simple delete with rm
 test_s3cmd("Simple delete with rm", ['rm', '%s/xyz/test_rm/TypeRa.ttf' % pbucket(1)],
     must_find = [ "File %s/xyz/test_rm/TypeRa.ttf deleted" % pbucket(1) ])
 
9384a2d5
 ## ====== Create expiration rule with days and prefix
 test_s3cmd("Create expiration rule with days and prefix", ['expire', pbucket(1), '--expiry-days=365', '--expiry-prefix=log/'],
     must_find = [ "Bucket '%s/': expiration configuration is set." % pbucket(1)])
 
 ## ====== Create expiration rule with date and prefix
 test_s3cmd("Create expiration rule with date and prefix", ['expire', pbucket(1), '--expiry-date=2012-12-31T00:00:00.000Z', '--expiry-prefix=log/'],
     must_find = [ "Bucket '%s/': expiration configuration is set." % pbucket(1)])
 
 ## ====== Create expiration rule with days only
 test_s3cmd("Create expiration rule with days only", ['expire', pbucket(1), '--expiry-days=365'],
     must_find = [ "Bucket '%s/': expiration configuration is set." % pbucket(1)])
 
 ## ====== Create expiration rule with date only
 test_s3cmd("Create expiration rule with date only", ['expire', pbucket(1), '--expiry-date=2012-12-31T00:00:00.000Z'],
     must_find = [ "Bucket '%s/': expiration configuration is set." % pbucket(1)])
 
 ## ====== Get current expiration setting
 test_s3cmd("Get current expiration setting", ['info', pbucket(1)],
     must_find = [ "Expiration Rule: all objects in this bucket will expire in '2012-12-31T00:00:00.000Z'"])
 
 ## ====== Delete expiration rule
 test_s3cmd("Delete expiration rule", ['expire', pbucket(1)],
     must_find = [ "Bucket '%s/': expiration configuration is deleted." % pbucket(1)])
f11319be
 
f230f799
 ## ====== Recursive delete maximum exceeed
 test_s3cmd("Recursive delete maximum exceeded", ['del', '--recursive', '--max-delete=1', '--exclude', 'Atomic*', '%s/xyz/etc' % pbucket(1)],
     must_not_find = [ "File %s/xyz/etc/TypeRa.ttf deleted" % pbucket(1) ])
 
ca86524c
 ## ====== Recursive delete
31fadab3
 test_s3cmd("Recursive delete", ['del', '--recursive', '--exclude', 'Atomic*', '%s/xyz/etc' % pbucket(1)],
d439efb4
     must_find = [ "File %s/xyz/etc/TypeRa.ttf deleted" % pbucket(1) ],
     must_find_re = [ "File .*/etc/logo.png deleted" ],
     must_not_find = [ "AtomicClockRadio.ttf" ])
ca86524c
 
7268831a
 ## ====== Recursive delete with rm
 test_s3cmd("Recursive delete with rm", ['rm', '--recursive', '--exclude', 'Atomic*', '%s/xyz/test_rm' % pbucket(1)],
     must_find = [ "File %s/xyz/test_rm/more/give-me-more.txt deleted" % pbucket(1) ],
     must_find_re = [ "File .*/test_rm/logo.png deleted" ],
     must_not_find = [ "AtomicClockRadio.ttf" ])
 
ca86524c
 ## ====== Recursive delete all
31fadab3
 test_s3cmd("Recursive delete all", ['del', '--recursive', '--force', pbucket(1)],
d439efb4
     must_find_re = [ "File .*binary/random-crap deleted" ])
f11319be
 
ca86524c
 ## ====== Remove empty bucket
31fadab3
 test_s3cmd("Remove empty bucket", ['rb', pbucket(1)],
d439efb4
     must_find = [ "Bucket '%s/' removed" % pbucket(1) ])
330c51eb
 
ca86524c
 ## ====== Remove remaining buckets
31fadab3
 test_s3cmd("Remove remaining buckets", ['rb', '--recursive', pbucket(2), pbucket(3)],
d439efb4
     must_find = [ "Bucket '%s/' removed" % pbucket(2),
               "Bucket '%s/' removed" % pbucket(3) ])
 
 # vim:et:ts=4:sts=4:ai