Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: tools/isolate/isolate_smoke_test.py

Issue 10019014: Convert isolate.py to exclusively use .isolate files. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Reduce copy pasted constants Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 import cStringIO 6 import cStringIO
7 import hashlib 7 import hashlib
8 import json 8 import json
9 import logging 9 import logging
10 import os 10 import os
11 import re 11 import re
12 import shutil 12 import shutil
13 import subprocess 13 import subprocess
14 import sys 14 import sys
15 import tempfile 15 import tempfile
16 import unittest 16 import unittest
17 17
18 import isolate
19
18 ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) 20 ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
19 VERBOSE = False 21 VERBOSE = False
20 FILENAME = os.path.basename(__file__) 22
21 23
22 24
23 class CalledProcessError(subprocess.CalledProcessError): 25 class CalledProcessError(subprocess.CalledProcessError):
24 """Makes 2.6 version act like 2.7""" 26 """Makes 2.6 version act like 2.7"""
25 def __init__(self, returncode, cmd, output, cwd): 27 def __init__(self, returncode, cmd, output, cwd):
26 super(CalledProcessError, self).__init__(returncode, cmd) 28 super(CalledProcessError, self).__init__(returncode, cmd)
27 self.output = output 29 self.output = output
28 self.cwd = cwd 30 self.cwd = cwd
29 31
30 def __str__(self): 32 def __str__(self):
31 return super(CalledProcessError, self).__str__() + ( 33 return super(CalledProcessError, self).__str__() + (
32 '\n' 34 '\n'
33 'cwd=%s\n%s') % (self.cwd, self.output) 35 'cwd=%s\n%s') % (self.cwd, self.output)
34 36
35 37
36 class Isolate(unittest.TestCase): 38 class Isolate(unittest.TestCase):
37 def setUp(self): 39 def setUp(self):
38 # The reason is that FILENAME --ok is run in a temporary directory
39 # without access to isolate.py
40 import isolate
41 self.isolate = isolate
42 self.tempdir = tempfile.mkdtemp() 40 self.tempdir = tempfile.mkdtemp()
43 self.result = os.path.join(self.tempdir, 'result') 41 self.result = os.path.join(self.tempdir, 'result')
42 self.child = os.path.join('data', 'isolate', 'child.py')
44 if VERBOSE: 43 if VERBOSE:
45 print 44 print
45 self.files = [
46 self.child,
47 os.path.join('data', 'isolate', 'files1', 'test_file1.txt'),
48 os.path.join('data', 'isolate', 'files1', 'test_file2.txt'),
49 ]
46 50
47 def tearDown(self): 51 def tearDown(self):
48 shutil.rmtree(self.tempdir) 52 shutil.rmtree(self.tempdir)
49 53
50 def _expected_tree(self, files): 54 def _expected_tree(self, files):
51 self.assertEquals(sorted(files), sorted(os.listdir(self.tempdir))) 55 self.assertEquals(sorted(files), sorted(os.listdir(self.tempdir)))
52 56
53 def _expected_result(self, with_hash, files, args, read_only): 57 def _expected_result(self, with_hash, files, args, read_only):
54 if sys.platform == 'win32': 58 if sys.platform == 'win32':
55 mode = lambda _: 420 59 mode = lambda _: 420
56 else: 60 else:
57 # 4 modes are supported, 0755 (rwx), 0644 (rw), 0555 (rx), 0444 (r) 61 # 4 modes are supported, 0755 (rwx), 0644 (rw), 0555 (rx), 0444 (r)
58 min_mode = 0444 62 min_mode = 0444
59 if not read_only: 63 if not read_only:
60 min_mode |= 0200 64 min_mode |= 0200
61 def mode(filename): 65 def mode(filename):
62 return (min_mode | 0111) if filename.endswith('.py') else min_mode 66 return (min_mode | 0111) if filename.endswith('.py') else min_mode
67
68 if not isinstance(files, dict):
69 # Update files to dict.
70 files = dict((unicode(f), {u'mode': mode(f)}) for f in files)
71 # Add size and timestamp.
72 files = files.copy()
73 for k, v in files.iteritems():
74 if v:
75 filestats = os.stat(k)
76 v[u'size'] = filestats.st_size
77 # Used the skip recalculating the hash. Use the most recent update
78 # time.
79 v[u'timestamp'] = int(round(
80 max(filestats.st_mtime, filestats.st_ctime)))
81
63 expected = { 82 expected = {
64 u'command': 83 u'files': files,
65 [unicode(sys.executable)] + 84 u'relative_cwd': u'data/isolate',
66 [unicode(x) for x in args], 85 u'read_only': None,
67 u'files': dict((unicode(f), {u'mode': mode(f)}) for f in files),
68 u'relative_cwd': u'.',
69 u'read_only': False,
70 } 86 }
87 if args:
88 expected[u'command'] = [u'python'] + [unicode(x) for x in args]
89 else:
90 expected[u'command'] = []
71 if with_hash: 91 if with_hash:
72 for filename in expected[u'files']: 92 for filename in expected[u'files']:
73 # Calculate our hash. 93 # Calculate our hash.
74 h = hashlib.sha1() 94 h = hashlib.sha1()
75 h.update(open(os.path.join(ROOT_DIR, filename), 'rb').read()) 95 h.update(open(os.path.join(ROOT_DIR, filename), 'rb').read())
76 expected[u'files'][filename][u'sha-1'] = h.hexdigest() 96 expected[u'files'][filename][u'sha-1'] = unicode(h.hexdigest())
77 97
78 actual = json.load(open(self.result, 'rb')) 98 actual = json.load(open(self.result, 'rb'))
79 self.assertEquals(expected, actual) 99 self.assertEquals(expected, actual)
80 return expected 100 return expected
81 101
82 def _execute(self, args, need_output=False): 102 def _execute(self, filename, args, need_output=False):
83 cmd = [ 103 cmd = [
84 sys.executable, os.path.join(ROOT_DIR, 'isolate.py'), 104 sys.executable, os.path.join(ROOT_DIR, 'isolate.py'),
85 '--root', ROOT_DIR, 105 '--variable', 'DEPTH=%s' % ROOT_DIR,
86 '--result', self.result, 106 '--result', self.result,
87 ] 107 os.path.join(ROOT_DIR, 'data', 'isolate', filename),
108 ] + args
109 env = os.environ.copy()
110 if 'ISOLATE_DEBUG' in env:
111 del env['ISOLATE_DEBUG']
88 if need_output or not VERBOSE: 112 if need_output or not VERBOSE:
89 stdout = subprocess.PIPE 113 stdout = subprocess.PIPE
90 stderr = subprocess.STDOUT 114 stderr = subprocess.STDOUT
91 else: 115 else:
92 cmd.extend(['-v'] * 3) 116 cmd.extend(['-v'] * 3)
93 stdout = None 117 stdout = None
94 stderr = None 118 stderr = None
95 cwd = ROOT_DIR 119 cwd = ROOT_DIR
96 p = subprocess.Popen( 120 p = subprocess.Popen(
97 cmd + args, 121 cmd + args,
98 stdout=stdout, 122 stdout=stdout,
99 stderr=stderr, 123 stderr=stderr,
100 cwd=cwd, 124 cwd=cwd,
125 env=env,
101 universal_newlines=True) 126 universal_newlines=True)
102 out = p.communicate()[0] 127 out = p.communicate()[0]
103 if p.returncode: 128 if p.returncode:
104 raise CalledProcessError(p.returncode, cmd, out, cwd) 129 raise CalledProcessError(p.returncode, cmd, out, cwd)
105 return out 130 return out
106 131
107 def test_help_modes(self): 132 def test_help_modes(self):
108 # Check coherency in the help and implemented modes. 133 # Check coherency in the help and implemented modes.
109 p = subprocess.Popen( 134 p = subprocess.Popen(
110 [sys.executable, os.path.join(ROOT_DIR, 'isolate.py'), '--help'], 135 [sys.executable, os.path.join(ROOT_DIR, 'isolate.py'), '--help'],
111 stdout=subprocess.PIPE, 136 stdout=subprocess.PIPE,
112 stderr=subprocess.STDOUT, 137 stderr=subprocess.STDOUT,
113 cwd=ROOT_DIR) 138 cwd=ROOT_DIR)
114 out = p.communicate()[0].splitlines() 139 out = p.communicate()[0].splitlines()
115 self.assertEquals(0, p.returncode) 140 self.assertEquals(0, p.returncode)
116 out = out[out.index('') + 1:] 141 out = out[out.index('') + 1:]
117 out = out[:out.index('')] 142 out = out[:out.index('')]
118 modes = [re.match(r'^ (\w+) .+', l) for l in out] 143 modes = [re.match(r'^ (\w+) .+', l) for l in out]
119 modes = tuple(m.group(1) for m in modes if m) 144 modes = tuple(m.group(1) for m in modes if m)
120 # Keep the list hard coded. 145 # Keep the list hard coded.
121 expected = ('check', 'hashtable', 'remap', 'run', 'trace') 146 expected = ('check', 'hashtable', 'remap', 'run', 'trace')
122 self.assertEquals(expected, modes) 147 self.assertEquals(expected, modes)
123 self.assertEquals(expected, modes) 148 self.assertEquals(expected, modes)
124 for mode in modes: 149 for mode in modes:
125 self.assertTrue(hasattr(self, 'test_%s' % mode), mode) 150 self.assertTrue(hasattr(self, 'test_%s' % mode), mode)
126 self._expected_tree([]) 151 self._expected_tree([])
127 152
128 def test_check(self): 153 def test_check(self):
129 cmd = [ 154 self._execute('fail.isolate', ['--mode', 'check'])
130 '--mode', 'check',
131 FILENAME,
132 ]
133 self._execute(cmd)
134 self._expected_tree(['result']) 155 self._expected_tree(['result'])
135 self._expected_result( 156 self._expected_result(
136 False, 157 False, dict((f, {}) for f in self.files), ['child.py', '--fail'], False)
137 [FILENAME],
138 [os.path.join('.', FILENAME)],
139 False)
140 158
141 def test_check_non_existant(self): 159 def test_check_no_run(self):
142 cmd = [ 160 self._execute('no_run.isolate', ['--mode', 'check'])
143 '--mode', 'check', 161 self._expected_tree(['result'])
144 'NonExistentFile', 162 self._expected_result(
145 ] 163 False, dict((f, {}) for f in self.files), None, False)
164
165 def test_check_non_existent(self):
146 try: 166 try:
147 self._execute(cmd) 167 self._execute('non_existent.isolate', ['--mode', 'check'])
148 self.fail() 168 self.fail()
149 except subprocess.CalledProcessError: 169 except subprocess.CalledProcessError:
150 pass 170 pass
151 self._expected_tree([]) 171 self._expected_tree([])
152 172
153 def test_check_directory_no_slash(self): 173 def test_check_directory_no_slash(self):
154 cmd = [
155 '--mode', 'check',
156 # Trailing slash missing.
157 os.path.join('data', 'isolate'),
158 ]
159 try: 174 try:
160 self._execute(cmd) 175 self._execute('missing_trailing_slash.isolate', ['--mode', 'check'])
161 self.fail() 176 self.fail()
162 except subprocess.CalledProcessError: 177 except subprocess.CalledProcessError:
163 pass 178 pass
164 self._expected_tree([]) 179 self._expected_tree([])
165 180
166 def test_check_abs_path(self):
167 cmd = [
168 '--mode', 'check',
169 FILENAME,
170 '--',
171 os.path.join(ROOT_DIR, FILENAME),
172 ]
173 self._execute(cmd)
174 self._expected_tree(['result'])
175 self._expected_result(
176 False, [FILENAME], [FILENAME], False)
177
178 def test_hashtable(self): 181 def test_hashtable(self):
179 cmd = [ 182 cmd = [
180 '--mode', 'hashtable', 183 '--mode', 'hashtable',
181 '--outdir', self.tempdir, 184 '--outdir', self.tempdir,
182 FILENAME,
183 os.path.join('data', 'isolate') + os.path.sep,
184 ] 185 ]
185 self._execute(cmd) 186 self._execute('no_run.isolate', cmd)
186 files = [ 187 data = self._expected_result(True, self.files, None, False)
187 FILENAME,
188 os.path.join('data', 'isolate', 'test_file1.txt'),
189 os.path.join('data', 'isolate', 'test_file2.txt'),
190 ]
191 data = self._expected_result(
192 True, files, [os.path.join('.', FILENAME)], False)
193 self._expected_tree( 188 self._expected_tree(
194 [f['sha-1'] for f in data['files'].itervalues()] + ['result']) 189 [f['sha-1'] for f in data['files'].itervalues()] + ['result'])
195 190
196 def test_remap(self): 191 def test_remap(self):
197 cmd = [ 192 cmd = [
198 '--mode', 'remap', 193 '--mode', 'remap',
199 '--outdir', self.tempdir, 194 '--outdir', self.tempdir,
200 FILENAME,
201 ] 195 ]
202 self._execute(cmd) 196 self._execute('no_run.isolate', cmd)
203 self._expected_tree([FILENAME, 'result']) 197 self._expected_tree(['data', 'result'])
204 self._expected_result( 198 self._expected_result(
205 False, 199 False,
206 [FILENAME], 200 self.files,
207 [os.path.join('.', FILENAME)], 201 None,
208 False) 202 False)
209 203
210 def test_run(self): 204 def test_run(self):
211 cmd = [ 205 self._execute('ok.isolate', ['--mode', 'run'])
212 '--mode', 'run',
213 FILENAME,
214 '--',
215 sys.executable, FILENAME, '--ok',
216 ]
217 self._execute(cmd)
218 self._expected_tree(['result']) 206 self._expected_tree(['result'])
219 # cmd[0] is not generated from infiles[0] so it's not using a relative path. 207 # cmd[0] is not generated from infiles[0] so it's not using a relative path.
220 self._expected_result( 208 self._expected_result(
221 False, [FILENAME], [FILENAME, '--ok'], False) 209 False, self.files, ['child.py', '--ok'], False)
222 210
223 def test_run_fail(self): 211 def test_run_fail(self):
224 cmd = [
225 '--mode', 'run',
226 FILENAME,
227 '--',
228 sys.executable, FILENAME, '--fail',
229 ]
230 try: 212 try:
231 self._execute(cmd) 213 self._execute('fail.isolate', ['--mode', 'run'])
232 self.fail() 214 self.fail()
233 except subprocess.CalledProcessError: 215 except subprocess.CalledProcessError:
234 pass 216 pass
235 self._expected_tree([]) 217 self._expected_tree(['result'])
236 218
237 def test_trace(self): 219 def test_trace(self):
238 cmd = [ 220 out = self._execute('ok.isolate', ['--mode', 'trace'], True)
239 '--mode', 'trace', 221 self._expected_tree(['result', 'result.log'])
240 FILENAME,
241 '--',
242 sys.executable, os.path.join(ROOT_DIR, FILENAME), '--ok',
243 ]
244 out = self._execute(cmd, True)
245 expected_tree = ['result', 'result.log']
246 if sys.platform == 'win32':
247 expected_tree.append('result.log.etl')
248 self._expected_tree(expected_tree)
249 # The 'result.log' log is OS-specific so we can't read it but we can read 222 # The 'result.log' log is OS-specific so we can't read it but we can read
250 # the gyp result. 223 # the gyp result.
251 # cmd[0] is not generated from infiles[0] so it's not using a relative path. 224 # cmd[0] is not generated from infiles[0] so it's not using a relative path.
252 self._expected_result( 225 self._expected_result(
253 False, [FILENAME], [FILENAME, '--ok'], False) 226 False, self.files, ['child.py', '--ok'], False)
254 227
255 expected_value = { 228 expected_value = {
256 'conditions': [ 229 'conditions': [
257 ['OS=="%s"' % self.isolate.trace_inputs.get_flavor(), { 230 ['OS=="%s"' % isolate.trace_inputs.get_flavor(), {
258 'variables': { 231 'variables': {
259 'isolate_files': [ 232 isolate.trace_inputs.KEY_TRACKED: [
260 '<(DEPTH)/%s' % FILENAME, 233 'child.py',
234 ],
235 isolate.trace_inputs.KEY_UNTRACKED: [
236 'files1/',
261 ], 237 ],
262 }, 238 },
263 }], 239 }],
264 ], 240 ],
265 } 241 }
266 expected_buffer = cStringIO.StringIO() 242 expected_buffer = cStringIO.StringIO()
267 self.isolate.trace_inputs.pretty_print(expected_value, expected_buffer) 243 isolate.trace_inputs.pretty_print(expected_value, expected_buffer)
268 self.assertEquals(expected_buffer.getvalue(), out) 244 self.assertEquals(expected_buffer.getvalue(), out)
269 245
270 246
271 def main():
272 global VERBOSE
273 VERBOSE = '-v' in sys.argv
274 level = logging.DEBUG if VERBOSE else logging.ERROR
275 logging.basicConfig(level=level)
276 if len(sys.argv) == 1:
277 unittest.main()
278 if sys.argv[1] == '--ok':
279 return 0
280 if sys.argv[1] == '--fail':
281 return 1
282
283 unittest.main()
284
285 247
286 if __name__ == '__main__': 248 if __name__ == '__main__':
287 sys.exit(main()) 249 VERBOSE = '-v' in sys.argv
250 logging.basicConfig(level=logging.DEBUG if VERBOSE else logging.ERROR)
251 unittest.main()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698