OLD | NEW |
---|---|
(Empty) | |
1 #!/usr/bin/env python | |
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 | |
4 # found in the LICENSE file. | |
5 | |
6 """Unit tests for download_to/upload_from_google_storage.py.""" | |
7 | |
8 import os | |
9 import sys | |
10 import unittest | |
11 import threading | |
12 import StringIO | |
13 import Queue | |
14 import optparse | |
15 | |
16 sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | |
17 | |
18 import upload_to_google_storage | |
19 import download_from_google_storage | |
20 | |
21 # ../third_party/gsutil/gsutil | |
22 GSUTIL_DEFAULT_PATH = os.path.join( | |
23 os.path.dirname(os.path.dirname(os.path.abspath(__file__))), | |
24 'third_party', 'gsutil', 'gsutil') | |
25 | |
26 | |
27 class GsutilMock(object): | |
28 def __init__(self, path, boto_path=None, timeout=None): | |
29 self.path = path | |
30 self.timeout = timeout | |
31 self.boto_path = boto_path | |
32 self.expected = [] | |
33 self.history = [] | |
34 self.lock = threading.Lock() | |
35 | |
36 def add_expected(self, return_code, out, err): | |
37 self.expected.append((return_code, out, err)) | |
38 | |
39 def append_history(self, method, args): | |
40 with self.lock: | |
41 self.history.append((method, args)) | |
42 | |
43 def call(self, *args): | |
44 self.append_history('call', args) | |
45 if self.expected: | |
46 return self.expected.pop(0)[0] | |
47 else: | |
48 return 0 | |
49 | |
50 def check_call(self, *args): | |
51 self.append_history('check_call', args) | |
52 if self.expected: | |
53 return self.expected.pop(0) | |
54 else: | |
55 return (0, '', '') | |
56 | |
57 def clone(self): | |
58 return self | |
59 | |
60 | |
61 class GstoolsUnitTests(unittest.TestCase): | |
62 def setUp(self): | |
63 self.base_path = os.path.join( | |
64 os.path.dirname(os.path.abspath(__file__)), 'gstools') | |
65 | |
66 def test_gsutil(self): | |
67 gsutil = download_from_google_storage.Gsutil(GSUTIL_DEFAULT_PATH) | |
68 self.assertEquals(gsutil.path, GSUTIL_DEFAULT_PATH) | |
69 code, _, err = gsutil.check_call() | |
70 self.assertEquals(code, 0) | |
71 self.assertEquals(err, '') | |
72 | |
73 def test_gsutil_version(self): | |
74 gsutil = download_from_google_storage.Gsutil(GSUTIL_DEFAULT_PATH) | |
75 _, _, err = gsutil.check_call('version') | |
76 err_lines = err.splitlines() | |
77 self.assertEquals(err_lines[0], 'gsutil version 3.25') | |
78 self.assertEquals( | |
79 err_lines[1], | |
80 'checksum ce71ac982f1148315e7fa65cff2f83e8 (OK)') | |
81 | |
82 def test_get_sha1(self): | |
83 lorem_ipsum = os.path.join(self.base_path, 'lorem_ipsum.txt') | |
84 self.assertEquals( | |
85 download_from_google_storage.get_sha1(lorem_ipsum), | |
86 '7871c8e24da15bad8b0be2c36edc9dc77e37727f') | |
87 | |
88 def test_get_md5(self): | |
89 lorem_ipsum = os.path.join(self.base_path, 'lorem_ipsum.txt') | |
90 self.assertEquals( | |
91 upload_to_google_storage.get_md5(lorem_ipsum), | |
92 '634d7c1ed3545383837428f031840a1e') | |
93 | |
94 def test_get_md5_cached_read(self): | |
95 lorem_ipsum = os.path.join(self.base_path, 'lorem_ipsum.txt') | |
96 # Use a fake 'stale' MD5 sum. Expected behavior is to return stale sum. | |
97 self.assertEquals( | |
98 upload_to_google_storage.get_md5_cached(lorem_ipsum), | |
99 '734d7c1ed3545383837428f031840a1e') | |
100 | |
101 def test_get_md5_cached_write(self): | |
102 lorem_ipsum2 = os.path.join(self.base_path, 'lorem_ipsum2.txt') | |
103 lorem_ipsum2_md5 = os.path.join(self.base_path, 'lorem_ipsum2.txt.md5') | |
104 if os.path.exists(lorem_ipsum2_md5): | |
105 os.remove(lorem_ipsum2_md5) | |
106 # Use a fake 'stale' MD5 sum. Expected behavior is to return stale sum. | |
107 self.assertEquals( | |
108 upload_to_google_storage.get_md5_cached(lorem_ipsum2), | |
109 '4c02d1eb455a0f22c575265d17b84b6d') | |
110 self.assertTrue(os.path.exists(lorem_ipsum2_md5)) | |
111 self.assertEquals( | |
112 open(lorem_ipsum2_md5, 'rb').read(), | |
113 '4c02d1eb455a0f22c575265d17b84b6d') | |
114 os.remove(lorem_ipsum2_md5) # Clean up. | |
115 self.assertFalse(os.path.exists(lorem_ipsum2_md5)) | |
116 | |
117 | |
118 class UploadTests(unittest.TestCase): | |
119 def setUp(self): | |
120 self.gsutil = GsutilMock(GSUTIL_DEFAULT_PATH) | |
121 self.base_path = os.path.join( | |
122 os.path.dirname(os.path.abspath(__file__)), 'gstools') | |
123 self.base_url = 'gs://sometesturl' | |
124 self.parser = optparse.OptionParser() | |
125 self.ret_codes = Queue.Queue() | |
126 self.stdout_queue = Queue.Queue() | |
127 self.lorem_ipsum = os.path.join(self.base_path, 'lorem_ipsum.txt') | |
128 self.lorem_ipsum_sha1 = '7871c8e24da15bad8b0be2c36edc9dc77e37727f' | |
129 | |
130 def test_upload_single_file(self): | |
131 filenames = [self.lorem_ipsum] | |
132 output_filename = '%s.sha1' % self.lorem_ipsum | |
133 if os.path.exists(output_filename): | |
134 os.remove(output_filename) | |
135 upload_to_google_storage.upload_to_google_storage( | |
136 filenames, self.base_url, self.gsutil, True, False, 1, False) | |
137 self.assertEquals( | |
138 self.gsutil.history, | |
139 [('check_call', | |
140 ('ls', '%s/%s' % (self.base_url, self.lorem_ipsum_sha1))), | |
141 ('check_call', | |
142 ('cp', '-q', filenames[0], '%s/%s' % (self.base_url, | |
143 self.lorem_ipsum_sha1)))]) | |
144 self.assertTrue(os.path.exists(output_filename)) | |
145 self.assertEquals( | |
146 open(output_filename, 'rb').read(), | |
147 '7871c8e24da15bad8b0be2c36edc9dc77e37727f') | |
148 os.remove(output_filename) | |
149 | |
150 def test_upload_single_file_remote_exists(self): | |
151 filenames = [self.lorem_ipsum] | |
152 output_filename = '%s.sha1' % self.lorem_ipsum | |
153 etag_string = 'ETag: 634d7c1ed3545383837428f031840a1e' | |
154 if os.path.exists(output_filename): | |
155 os.remove(output_filename) | |
156 self.gsutil.add_expected(0, '', '') | |
157 self.gsutil.add_expected(0, etag_string, '') | |
158 upload_to_google_storage.upload_to_google_storage( | |
159 filenames, self.base_url, self.gsutil, False, False, 1, False) | |
160 self.assertEquals( | |
161 self.gsutil.history, | |
162 [('check_call', | |
163 ('ls', '%s/%s' % (self.base_url, self.lorem_ipsum_sha1))), | |
164 ('check_call', | |
165 ('ls', '-L', '%s/%s' % (self.base_url, self.lorem_ipsum_sha1)))]) | |
166 self.assertTrue(os.path.exists(output_filename)) | |
167 self.assertEquals( | |
168 open(output_filename, 'rb').read(), | |
169 '7871c8e24da15bad8b0be2c36edc9dc77e37727f') | |
170 os.remove(output_filename) | |
171 | |
172 def test_upload_worker_errors(self): | |
173 work_queue = Queue.Queue() | |
174 work_queue.put((self.lorem_ipsum, self.lorem_ipsum_sha1)) | |
175 work_queue.put((None, None)) | |
176 self.gsutil.add_expected(1, '', '') # For the first ls call. | |
177 self.gsutil.add_expected(20, '', 'Expected error message') | |
178 # pylint: disable=W0212 | |
179 upload_to_google_storage._upload_worker( | |
180 0, | |
181 work_queue, | |
182 self.base_url, | |
183 self.gsutil, | |
184 threading.Lock(), | |
185 False, | |
186 False, | |
187 self.stdout_queue, | |
188 self.ret_codes) | |
189 expected_ret_codes = [ | |
190 (20, | |
191 'Encountered error on uploading %s to %s/%s\nExpected error message' % | |
192 (self.lorem_ipsum, self.base_url, self.lorem_ipsum_sha1))] | |
193 self.assertEquals(list(self.ret_codes.queue), expected_ret_codes) | |
194 | |
195 | |
196 def test_skip_hashing(self): | |
197 filenames = [self.lorem_ipsum] | |
198 output_filename = '%s.sha1' % self.lorem_ipsum | |
199 fake_hash = '6871c8e24da15bad8b0be2c36edc9dc77e37727f' | |
200 with open(output_filename, 'wb') as f: | |
201 f.write(fake_hash) # Fake hash. | |
202 upload_to_google_storage.upload_to_google_storage( | |
203 filenames, self.base_url, self.gsutil, False, False, 1, True) | |
204 self.assertEquals( | |
205 self.gsutil.history, | |
206 [('check_call', | |
207 ('ls', '%s/%s' % (self.base_url, fake_hash))), | |
208 ('check_call', | |
209 ('ls', '-L', '%s/%s' % (self.base_url, fake_hash))), | |
210 ('check_call', | |
211 ('cp', '-q', filenames[0], '%s/%s' % (self.base_url, fake_hash)))]) | |
212 self.assertEquals( | |
213 open(output_filename, 'rb').read(), fake_hash) | |
214 os.remove(output_filename) | |
215 | |
216 def test_get_targets_no_args(self): | |
217 try: | |
218 upload_to_google_storage.get_targets([], self.parser, False) | |
219 except SystemExit, e: | |
220 self.assertEquals(type(e), type(SystemExit())) | |
221 self.assertEquals(e.code, 2) | |
222 except Exception, e: | |
223 self.fail('unexpected exception: %s' % e) | |
224 else: | |
225 self.fail('SystemExit exception expected') | |
226 | |
227 def test_get_targets_passthrough(self): | |
228 result = upload_to_google_storage.get_targets( | |
229 ['a', 'b', 'c', 'd', 'e'], | |
230 self.parser, | |
231 False) | |
232 self.assertEquals(result, ['a', 'b', 'c', 'd', 'e']) | |
233 | |
234 def test_get_targets_multiple_stdin(self): | |
235 inputs = ['a', 'b', 'c', 'd', 'e'] | |
236 sys.stdin = StringIO.StringIO(os.linesep.join(inputs)) | |
237 result = upload_to_google_storage.get_targets( | |
238 ['-'], | |
239 self.parser, | |
240 False) | |
241 self.assertEquals(result, inputs) | |
242 | |
243 def test_get_targets_multiple_stdin_null(self): | |
244 inputs = ['a', 'b', 'c', 'd', 'e'] | |
245 sys.stdin = StringIO.StringIO('\0'.join(inputs)) | |
246 result = upload_to_google_storage.get_targets( | |
247 ['-'], | |
248 self.parser, | |
249 True) | |
250 self.assertEquals(result, inputs) | |
251 | |
252 | |
253 class DownloadTests(unittest.TestCase): | |
254 def setUp(self): | |
255 self.gsutil = GsutilMock(GSUTIL_DEFAULT_PATH) | |
256 self.base_path = os.path.join( | |
257 os.path.dirname(os.path.abspath(__file__)), | |
258 'gstools', | |
259 'download_test_data') | |
260 self.base_url = 'gs://sometesturl' | |
261 self.parser = optparse.OptionParser() | |
262 self.queue = Queue.Queue() | |
263 self.ret_codes = Queue.Queue() | |
264 self.lorem_ipsum = os.path.join(self.base_path, 'lorem_ipsum.txt') | |
265 self.lorem_ipsum_sha1 = '7871c8e24da15bad8b0be2c36edc9dc77e37727f' | |
266 self.maxDiff = None | |
267 | |
268 def test_enumerate_files_non_recursive(self): | |
269 queue_size = download_from_google_storage.enumerate_work_queue( | |
270 self.base_path, self.queue, True, False, False, None, False) | |
271 result = list(self.queue.queue) | |
272 expected_queue = [ | |
273 ('e6c4fbd4fe7607f3e6ebf68b2ea4ef694da7b4fe', | |
274 os.path.join(self.base_path, 'rootfolder_text.txt')), | |
275 ('7871c8e24da15bad8b0be2c36edc9dc77e37727f', | |
276 os.path.join(self.base_path, 'uploaded_lorem_ipsum.txt'))] | |
277 for item in result: | |
278 self.assertTrue(item in expected_queue) | |
279 self.assertEquals(queue_size, 2) | |
280 | |
281 def test_enumerate_files_recursive(self): | |
282 queue_size = download_from_google_storage.enumerate_work_queue( | |
283 self.base_path, self.queue, True, True, False, None, False) | |
284 expected_queue = [ | |
285 ('e6c4fbd4fe7607f3e6ebf68b2ea4ef694da7b4fe', | |
286 os.path.join(self.base_path, 'rootfolder_text.txt')), | |
287 ('7871c8e24da15bad8b0be2c36edc9dc77e37727f', | |
288 os.path.join(self.base_path, 'uploaded_lorem_ipsum.txt')), | |
289 ('b5415aa0b64006a95c0c409182e628881d6d6463', | |
290 os.path.join(self.base_path, 'subfolder', 'subfolder_text.txt'))] | |
291 result = list(self.queue.queue) | |
292 for item in result: | |
293 self.assertTrue(item in expected_queue) | |
294 self.assertEquals(queue_size, 3) | |
295 | |
296 def test_download_worker_single_file(self): | |
297 sha1_hash = '7871c8e24da15bad8b0be2c36edc9dc77e37727f' | |
298 input_filename = '%s/%s' % (self.base_url, sha1_hash) | |
299 output_filename = os.path.join(self.base_path, 'uploaded_lorem_ipsum.txt') | |
300 self.queue.put((sha1_hash, output_filename)) | |
301 self.queue.put((None, None)) | |
302 stdout_queue = Queue.Queue() | |
303 # pylint: disable=W0212 | |
304 download_from_google_storage._downloader_worker_thread( | |
305 0, self.queue, False, self.base_url, self.gsutil, | |
306 stdout_queue, self.ret_codes) | |
307 expected_calls = [ | |
308 ('check_call', | |
309 ('ls', input_filename)), | |
310 ('check_call', | |
311 ('cp', '-q', input_filename, output_filename))] | |
312 expected_output = [ | |
313 '0> Downloading %s...' % output_filename] | |
314 self.assertEquals(list(stdout_queue.queue), expected_output) | |
315 self.assertEquals(self.gsutil.history, expected_calls) | |
316 | |
317 def test_download_worker_skips_file(self): | |
318 sha1_hash = 'e6c4fbd4fe7607f3e6ebf68b2ea4ef694da7b4fe' | |
319 output_filename = os.path.join(self.base_path, 'rootfolder_text.txt') | |
320 self.queue.put((sha1_hash, output_filename)) | |
321 self.queue.put((None, None)) | |
322 stdout_queue = Queue.Queue() | |
323 # pylint: disable=W0212 | |
324 download_from_google_storage._downloader_worker_thread( | |
325 0, self.queue, False, self.base_url, self.gsutil, | |
326 stdout_queue, self.ret_codes) | |
327 expected_output = [ | |
328 '0> File %s exists and SHA1 matches. Skipping.' % output_filename | |
329 ] | |
330 self.assertEquals(list(stdout_queue.queue), expected_output) | |
331 self.assertEquals(self.gsutil.history, []) | |
332 | |
333 def test_download_worker_skips_not_found_file(self): | |
334 sha1_hash = '7871c8e24da15bad8b0be2c36edc9dc77e37727f' | |
335 input_filename = '%s/%s' % (self.base_url, sha1_hash) | |
336 output_filename = os.path.join(self.base_path, 'uploaded_lorem_ipsum.txt') | |
337 self.queue.put((sha1_hash, output_filename)) | |
338 self.queue.put((None, None)) | |
339 stdout_queue = Queue.Queue() | |
340 self.gsutil.add_expected(1, '', '') # Return error when 'ls' is called. | |
341 # pylint: disable=W0212 | |
342 download_from_google_storage._downloader_worker_thread( | |
343 0, self.queue, False, self.base_url, self.gsutil, | |
344 stdout_queue, self.ret_codes) | |
345 expected_output = [ | |
346 '0> File %s for %s does not exist, skipping.' % ( | |
347 input_filename, output_filename), | |
348 ] | |
349 expected_calls = [ | |
350 ('check_call', | |
351 ('ls', input_filename)) | |
352 ] | |
353 expected_ret_codes = [ | |
354 (1, 'File %s for %s does not exist.' % ( | |
355 input_filename, output_filename)) | |
356 ] | |
357 self.assertEquals(list(stdout_queue.queue), expected_output) | |
358 self.assertEquals(self.gsutil.history, expected_calls) | |
359 self.assertEquals(list(self.ret_codes.queue), expected_ret_codes) | |
360 | |
361 def test_download_cp_fails(self): | |
362 sha1_hash = '7871c8e24da15bad8b0be2c36edc9dc77e37727f' | |
363 input_filename = '%s/%s' % (self.base_url, sha1_hash) | |
364 output_filename = os.path.join(self.base_path, 'uploaded_lorem_ipsum.txt') | |
365 self.gsutil.add_expected(0, '', '') | |
366 self.gsutil.add_expected(101, '', 'Test error message.') | |
367 # pylint: disable=W0212 | |
368 code = download_from_google_storage.download_from_google_storage( | |
369 input_filename=sha1_hash, | |
370 base_url=self.base_url, | |
371 gsutil=self.gsutil, | |
372 num_threads=1, | |
373 directory=False, | |
374 recursive=False, | |
375 force=True, | |
376 output=output_filename, | |
377 ignore_errors=False, | |
378 sha1_file=False) | |
379 expected_calls = [ | |
380 ('check_call', | |
381 ('ls', input_filename)), | |
382 ('check_call', | |
383 ('cp', '-q', input_filename, output_filename)) | |
384 ] | |
385 self.assertEquals(self.gsutil.history, expected_calls) | |
386 self.assertEquals(code, 101) | |
387 | |
388 def test_download_directory_no_recursive_non_force(self): | |
389 sha1_hash = '7871c8e24da15bad8b0be2c36edc9dc77e37727f' | |
390 input_filename = '%s/%s' % (self.base_url, sha1_hash) | |
391 output_filename = os.path.join(self.base_path, 'uploaded_lorem_ipsum.txt') | |
392 download_from_google_storage.download_from_google_storage( | |
M-A Ruel
2013/03/08 13:27:41
You don't check the return code here.
Split this
Ryan Tseng
2013/03/08 23:22:13
Done.
| |
393 input_filename=self.base_path, | |
394 base_url=self.base_url, | |
395 gsutil=self.gsutil, | |
396 num_threads=1, | |
397 directory=True, | |
398 recursive=False, | |
399 force=False, | |
400 output=None, | |
401 ignore_errors=False, | |
402 sha1_file=False) | |
403 expected_calls = [ | |
404 ('check_call', | |
405 ('ls', input_filename)), | |
406 ('check_call', | |
407 ('cp', '-q', input_filename, output_filename))] | |
408 self.assertEquals(self.gsutil.history, expected_calls) | |
409 | |
410 | |
411 if __name__ == '__main__': | |
412 unittest.main() | |
OLD | NEW |