17 # with this program; if not, write to the Free Software Foundation, Inc., |
17 # with this program; if not, write to the Free Software Foundation, Inc., |
18 # 51 Franklin Street, 5th Floor, Boston, MA, 02111. |
18 # 51 Franklin Street, 5th Floor, Boston, MA, 02111. |
19 |
19 |
20 import os |
20 import os |
21 import subprocess |
21 import subprocess |
|
22 import syck |
22 import sys |
23 import sys |
23 |
24 |
24 from sets import Set as set |
25 from sets import Set as set |
25 |
|
26 TESTSCRIPT_NAME = 'testscript.sh' |
|
27 SCRIPT_PROLOGUE = """#!/bin/sh |
|
28 set -e |
|
29 """ |
|
30 |
|
31 tests = {'test-1.23.tar': ([], ['tar -xf $1'], []), |
|
32 'test-1.23.tar.gz': ([], ['tar -xzf $1'], []), |
|
33 'test-1.23.tar.bz2': ([], ['mkdir test-1.23', |
|
34 'cd test-1.23', |
|
35 'tar -jxf ../$1'], []), |
|
36 'test-1.23.zip': ([], ['mkdir test-1.23', |
|
37 'cd test-1.23', |
|
38 'unzip -q ../$1'], []), |
|
39 'test-1.23.cpio': ([], ['cpio -i --make-directories \ |
|
40 <$1 2>/dev/null'], []), |
|
41 'test-1.23_all.deb': ([], ['TD=$PWD', |
|
42 'mkdir test-1.23', |
|
43 'cd /tmp', |
|
44 'ar x $TD/$1 data.tar.gz', |
|
45 'cd $TD/test-1.23', |
|
46 'tar -zxf /tmp/data.tar.gz', |
|
47 'rm /tmp/data.tar.gz'], []), |
|
48 'test-recursive-badperms.tar.bz2': ( |
|
49 ['-r'], |
|
50 ['mkdir test-recursive-badperms', |
|
51 'cd test-recursive-badperms', |
|
52 'tar -jxf ../$1', |
|
53 'mkdir test-badperms', |
|
54 'cd test-badperms', |
|
55 'tar -xf ../test-badperms.tar', |
|
56 'chmod 755 testdir'], |
|
57 ['if [ "x`cat test-recursive-badperms/test-badperms/testdir/testfile`" = \ |
|
58 "xhey" ]', |
|
59 'then exit 0; else exit 1; fi'] |
|
60 )} |
|
61 |
26 |
62 if os.path.exists('scripts/x') and os.path.exists('tests'): |
27 if os.path.exists('scripts/x') and os.path.exists('tests'): |
63 os.chdir('tests') |
28 os.chdir('tests') |
64 elif os.path.exists('../scripts/x') and os.path.exists('../tests'): |
29 elif os.path.exists('../scripts/x') and os.path.exists('../tests'): |
65 pass |
30 pass |
66 else: |
31 else: |
67 print "ERROR: Can't run tests in this directory!" |
32 print "ERROR: Can't run tests in this directory!" |
68 sys.exit(2) |
33 sys.exit(2) |
69 |
34 |
|
35 X_SCRIPT = os.path.realpath('../scripts/x') |
|
36 ROOT_DIR = os.path.realpath(os.curdir) |
|
37 OUTCOMES = ['error', 'failed', 'passed'] |
|
38 TESTSCRIPT_NAME = 'testscript.sh' |
|
39 SCRIPT_PROLOGUE = """#!/bin/sh |
|
40 set -e |
|
41 """ |
|
42 |
70 class ExtractorTestError(Exception): |
43 class ExtractorTestError(Exception): |
71 pass |
44 pass |
72 |
45 |
73 |
46 |
74 class ExtractorTest(object): |
47 class ExtractorTest(object): |
75 def __init__(self, directory, archive_filename, info): |
48 def __init__(self, **kwargs): |
76 self.directory = directory |
49 for key in ('name', 'filename', 'baseline'): |
77 self.archive_filename = os.path.join(directory, archive_filename) |
50 setattr(self, key, kwargs[key]) |
78 self.arguments, self.shell_commands, self.shell_test = info |
51 for key in ('directory', 'prerun', 'posttest'): |
|
52 setattr(self, key, kwargs.get(key, None)) |
|
53 for key in ('options',): |
|
54 setattr(self, key, kwargs.get(key, '').split()) |
79 |
55 |
80 def get_results(self, commands): |
56 def get_results(self, commands): |
81 status = subprocess.call(commands) |
57 status = subprocess.call(commands) |
82 if status != 0: |
58 if status != 0: |
83 return None |
59 return None |
87 process.stdout.close() |
63 process.stdout.close() |
88 return set(output.split('\n')) |
64 return set(output.split('\n')) |
89 |
65 |
90 def write_script(self, commands): |
66 def write_script(self, commands): |
91 script = open(TESTSCRIPT_NAME, 'w') |
67 script = open(TESTSCRIPT_NAME, 'w') |
92 script.write("%s%s\n" % (SCRIPT_PROLOGUE, '\n'.join(commands))) |
68 script.write("%s%s\n" % (SCRIPT_PROLOGUE, commands)) |
93 script.close() |
69 script.close() |
94 subprocess.call(['chmod', 'u+w', TESTSCRIPT_NAME]) |
70 subprocess.call(['chmod', 'u+w', TESTSCRIPT_NAME]) |
95 |
71 |
96 def get_shell_results(self): |
72 def get_shell_results(self): |
97 self.write_script(self.shell_commands) |
73 self.write_script(self.baseline) |
98 return self.get_results(['sh', TESTSCRIPT_NAME, self.archive_filename]) |
74 return self.get_results(['sh', TESTSCRIPT_NAME, self.filename]) |
99 |
75 |
100 def get_extractor_results(self): |
76 def get_extractor_results(self): |
101 script = os.path.join(self.directory, '../scripts/x') |
77 if self.prerun: |
102 return self.get_results([script] + self.arguments + |
78 self.write_script(self.prerun) |
103 [self.archive_filename]) |
79 subprocess.call(['sh', TESTSCRIPT_NAME]) |
|
80 return self.get_results([X_SCRIPT] + self.options + [self.filename]) |
104 |
81 |
105 def get_posttest_result(self): |
82 def get_posttest_result(self): |
106 if not self.shell_test: |
83 if not self.posttest: |
107 return 0 |
84 return 0 |
108 self.write_script(self.shell_test) |
85 self.write_script(self.posttest) |
109 return subprocess.call(['sh', TESTSCRIPT_NAME]) |
86 return subprocess.call(['sh', TESTSCRIPT_NAME]) |
110 |
87 |
111 def clean(self): |
88 def clean(self): |
112 status = subprocess.call(['find', '-mindepth', '1', '-maxdepth', '1', |
89 if self.directory: |
113 '-type', 'd', |
90 target = os.path.join(ROOT_DIR, self.directory) |
114 '!', '-name', 'CVS', '!', '-name', '.svn', |
91 extra_options = ['!', '-name', TESTSCRIPT_NAME] |
115 '-exec', 'rm', '-rf', '{}', ';']) |
92 else: |
|
93 target = ROOT_DIR |
|
94 extra_options = ['-type', 'd', |
|
95 '!', '-name', 'CVS', |
|
96 '!', '-name', '.svn'] |
|
97 status = subprocess.call(['find', target, |
|
98 '-mindepth', '1', '-maxdepth', '1'] + |
|
99 extra_options + |
|
100 ['-exec', 'rm', '-rf', '{}', ';']) |
116 if status != 0: |
101 if status != 0: |
117 raise ExtractorTestError("cleanup exited with status code %s" % |
102 raise ExtractorTestError("cleanup exited with status code %s" % |
118 (status,)) |
103 (status,)) |
119 |
104 |
120 def run(self): |
105 def show_status(self, status, message=None): |
|
106 if message is None: |
|
107 last_part = '' |
|
108 else: |
|
109 last_part = ': ' + message |
|
110 print "%7s: %s%s" % (status, self.name, last_part) |
|
111 return status.lower() |
|
112 |
|
113 def compare_results(self): |
121 self.clean() |
114 self.clean() |
122 expected = self.get_shell_results() |
115 expected = self.get_shell_results() |
123 self.clean() |
116 self.clean() |
124 actual = self.get_extractor_results() |
117 actual = self.get_extractor_results() |
125 posttest_result = self.get_posttest_result() |
118 posttest_result = self.get_posttest_result() |
127 if expected is None: |
120 if expected is None: |
128 raise ExtractorTestError("could not get baseline results") |
121 raise ExtractorTestError("could not get baseline results") |
129 elif actual is None: |
122 elif actual is None: |
130 raise ExtractorTestError("could not get extractor results") |
123 raise ExtractorTestError("could not get extractor results") |
131 elif expected != actual: |
124 elif expected != actual: |
132 print "FAILED:", self.archive_filename |
125 result = self.show_status('FAILED') |
133 print "Only in baseline results:" |
126 print "Only in baseline results:" |
134 print '\n'.join(expected.difference(actual)) |
127 print '\n'.join(expected.difference(actual)) |
135 print "Only in actual results:" |
128 print "Only in actual results:" |
136 print '\n'.join(actual.difference(expected)) |
129 print '\n'.join(actual.difference(expected)) |
137 return False |
|
138 elif posttest_result != 0: |
130 elif posttest_result != 0: |
139 print "FAILED:", self.archive_filename |
131 result = self.show_status('FAILED') |
140 print "Posttest returned status code", posttest_result |
132 print "Posttest returned status code", posttest_result |
141 print actual |
|
142 return False |
|
143 else: |
133 else: |
144 print "Passed:", self.archive_filename |
134 result = self.show_status('Passed') |
145 return True |
135 return result |
|
136 |
|
137 def run(self): |
|
138 if self.directory: |
|
139 os.mkdir(self.directory) |
|
140 os.chdir(self.directory) |
|
141 try: |
|
142 result = self.compare_results() |
|
143 except ExtractorTestError, error: |
|
144 result = self.show_status('ERROR', error) |
|
145 if self.directory: |
|
146 os.chdir(ROOT_DIR) |
|
147 subprocess.call(['rm', '-rf', self.directory]) |
|
148 return result |
146 |
149 |
147 |
150 |
148 def run_tests(directory, testnames): |
151 test_db = open('tests.yml') |
149 successes = 0 |
152 test_data = syck.load(test_db.read(-1)) |
150 failures = 0 |
153 test_db.close() |
151 for testname in testnames: |
154 tests = [ExtractorTest(**data) for data in test_data] |
152 test = ExtractorTest(directory, testname, tests[testname]) |
155 for original_data in test_data: |
153 if test.run(): |
156 if original_data.has_key('directory'): |
154 successes += 1 |
157 continue |
155 else: |
158 data = original_data.copy() |
156 failures += 1 |
159 data['name'] += ' in ..' |
157 return successes, failures |
160 data['directory'] = 'inside-dir' |
158 |
161 data['filename'] = os.path.join('..', data['filename']) |
159 results = [] |
162 tests.append(ExtractorTest(**data)) |
160 testnames = tests.keys() |
163 results = [test.run() for test in tests] |
161 testnames.sort() |
164 counts = {} |
162 results.append(run_tests('.', testnames)) |
165 for outcome in OUTCOMES: |
163 os.mkdir('inside-dir') |
166 counts[outcome] = 0 |
164 os.chdir('inside-dir') |
167 for result in results: |
165 results.append(run_tests('..', testnames)) |
168 counts[result] += 1 |
166 os.chdir('..') |
169 print " Totals:", ', '.join(["%s %s" % (counts[key], key) for key in OUTCOMES]) |
167 subprocess.call(['rm', '-rf', 'inside-dir']) |
|
168 print "Totals: %s successes, %s failures" % \ |
|
169 tuple([sum(total) for total in zip(*results)]) |
|