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 gstools.py and 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 gstools | |
19 import upload_to_google_storage | |
20 import download_from_google_storage | |
21 | |
22 # ../third_party/gsutil/gsutil | |
23 GSUTIL_DEFAULT_PATH = os.path.join( | |
24 os.path.dirname(os.path.dirname(os.path.abspath(__file__))), | |
25 'third_party', 'gsutil', 'gsutil') | |
26 | |
M-A Ruel
2013/02/27 21:52:07
2 lines
Ryan Tseng
2013/02/27 23:34:41
Done.
| |
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 = gstools.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 = gstools.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 6783bc26b80c538a136ba5392d44b0e3 (OK)') | |
81 | |
82 def test_get_sha1(self): | |
83 lorem_ipsum = os.path.join(self.base_path, 'lorem_ipsum.txt') | |
84 self.assertEquals( | |
85 gstools.GetSHA1(lorem_ipsum), | |
86 '7871c8e24da15bad8b0be2c36edc9dc77e37727f') | |
87 | |
88 def test_get_md5(self): | |
89 lorem_ipsum = os.path.join(self.base_path, 'lorem_ipsum.txt') | |
90 lock = threading.Lock() | |
91 self.assertEquals( | |
92 gstools.GetMD5(lorem_ipsum, lock), | |
93 '634d7c1ed3545383837428f031840a1e') | |
94 | |
95 def test_get_md5_cached_read(self): | |
96 lorem_ipsum = os.path.join(self.base_path, 'lorem_ipsum.txt') | |
97 lock = threading.Lock() | |
98 # Use a fake 'stale' MD5 sum. Expected behavior is to return stale sum. | |
99 self.assertEquals( | |
100 gstools.GetMD5Cached(lorem_ipsum, lock), | |
101 '734d7c1ed3545383837428f031840a1e') | |
102 | |
103 def test_get_md5_cached_write(self): | |
104 lorem_ipsum2 = os.path.join(self.base_path, 'lorem_ipsum2.txt') | |
105 lorem_ipsum2_md5 = os.path.join(self.base_path, 'lorem_ipsum2.txt.md5') | |
106 if os.path.exists(lorem_ipsum2_md5): | |
107 os.remove(lorem_ipsum2_md5) | |
108 lock = threading.Lock() | |
109 # Use a fake 'stale' MD5 sum. Expected behavior is to return stale sum. | |
110 self.assertEquals( | |
111 gstools.GetMD5Cached(lorem_ipsum2, lock), | |
112 '4c02d1eb455a0f22c575265d17b84b6d') | |
113 self.assertTrue(os.path.exists(lorem_ipsum2_md5)) | |
114 self.assertEquals( | |
115 open(lorem_ipsum2_md5, 'rb').read(), | |
116 '4c02d1eb455a0f22c575265d17b84b6d') | |
117 os.remove(lorem_ipsum2_md5) # Clean up. | |
118 self.assertFalse(os.path.exists(lorem_ipsum2_md5)) | |
119 | |
120 | |
121 class UploadTests(unittest.TestCase): | |
122 def setUp(self): | |
123 self.gsutil = GsutilMock(GSUTIL_DEFAULT_PATH) | |
124 self.base_path = os.path.join( | |
125 os.path.dirname(os.path.abspath(__file__)), 'gstools') | |
126 self.base_url = 'gs://sometesturl' | |
127 self.parser = optparse.OptionParser() | |
128 self.options = self.parser.parse_args()[0] | |
129 self.options.num_threads = 1 | |
130 self.options.force = False | |
131 self.options.use_md5 = False | |
132 self.options.use_null_terminator = False | |
133 self.lorem_ipsum = os.path.join(self.base_path, 'lorem_ipsum.txt') | |
134 self.lorem_ipsum_sha1 = '7871c8e24da15bad8b0be2c36edc9dc77e37727f' | |
135 | |
136 def test_upload_single_file(self): | |
137 filenames = [self.lorem_ipsum] | |
138 output_filename = '%s.sha1' % self.lorem_ipsum | |
139 if os.path.exists(output_filename): | |
140 os.remove(output_filename) | |
141 self.options.force = True | |
142 upload_to_google_storage.upload_to_google_storage( | |
143 filenames, | |
144 self.base_url, | |
145 self.gsutil, | |
146 self.options) | |
147 self.assertEquals( | |
148 self.gsutil.history, | |
149 [('check_call', | |
150 ('ls', '%s/%s' % (self.base_url, self.lorem_ipsum_sha1))), | |
151 ('call', | |
152 ('cp', '-q', filenames[0], '%s/%s' % (self.base_url, | |
153 self.lorem_ipsum_sha1)))]) | |
154 self.assertTrue(os.path.exists(output_filename)) | |
155 self.assertEquals( | |
156 open(output_filename, 'rb').read(), | |
157 '7871c8e24da15bad8b0be2c36edc9dc77e37727f') | |
158 os.remove(output_filename) | |
159 | |
160 def test_upload_single_file_remote_exists(self): | |
161 filenames = [self.lorem_ipsum] | |
162 output_filename = '%s.sha1' % self.lorem_ipsum | |
163 etag_string = 'ETag: 634d7c1ed3545383837428f031840a1e' | |
164 if os.path.exists(output_filename): | |
165 os.remove(output_filename) | |
166 self.gsutil.add_expected(0, '', '') | |
167 self.gsutil.add_expected(0, etag_string, '') | |
168 upload_to_google_storage.upload_to_google_storage( | |
169 filenames, | |
170 self.base_url, | |
171 self.gsutil, | |
172 self.options) | |
173 self.assertEquals( | |
174 self.gsutil.history, | |
175 [('check_call', | |
176 ('ls', '%s/%s' % (self.base_url, self.lorem_ipsum_sha1))), | |
177 ('check_call', | |
178 ('ls', '-L', '%s/%s' % (self.base_url, self.lorem_ipsum_sha1)))]) | |
179 self.assertTrue(os.path.exists(output_filename)) | |
180 self.assertEquals( | |
181 open(output_filename, 'rb').read(), | |
182 '7871c8e24da15bad8b0be2c36edc9dc77e37727f') | |
183 os.remove(output_filename) | |
184 | |
185 def test_skip_hashing(self): | |
186 filenames = [self.lorem_ipsum] | |
187 output_filename = '%s.sha1' % self.lorem_ipsum | |
188 fake_hash = '6871c8e24da15bad8b0be2c36edc9dc77e37727f' | |
189 with open(output_filename, 'wb') as f: | |
190 f.write(fake_hash) # Fake hash. | |
191 self.options.skip_hashing = True | |
192 upload_to_google_storage.upload_to_google_storage( | |
193 filenames, | |
194 self.base_url, | |
195 self.gsutil, | |
196 self.options) | |
197 self.assertEquals( | |
198 self.gsutil.history, | |
199 [('check_call', | |
200 ('ls', '%s/%s' % (self.base_url, fake_hash))), | |
201 ('check_call', | |
202 ('ls', '-L', '%s/%s' % (self.base_url, fake_hash))), | |
203 ('call', | |
204 ('cp', '-q', filenames[0], '%s/%s' % (self.base_url, fake_hash)))]) | |
205 self.assertEquals( | |
206 open(output_filename, 'rb').read(), fake_hash) | |
207 os.remove(output_filename) | |
208 | |
209 def test_get_targets_no_args(self): | |
210 try: | |
211 upload_to_google_storage.get_targets(self.options, [], self.parser) | |
212 except SystemExit, e: | |
213 self.assertEquals(type(e), type(SystemExit())) | |
214 self.assertEquals(e.code, 2) | |
215 except Exception, e: | |
216 self.fail('unexpected exception: %s' % e) | |
217 else: | |
218 self.fail('SystemExit exception expected') | |
219 | |
220 def test_get_targets_passthrough(self): | |
221 result = upload_to_google_storage.get_targets( | |
222 self.options, | |
223 ['a', 'b', 'c', 'd', 'e'], | |
224 self.parser) | |
225 self.assertEquals(result, ['a', 'b', 'c', 'd', 'e']) | |
226 | |
227 def test_get_targets_multiple_stdin(self): | |
228 inputs = ['a', 'b', 'c', 'd', 'e'] | |
229 sys.stdin = StringIO.StringIO(os.linesep.join(inputs)) | |
230 result = upload_to_google_storage.get_targets( | |
231 self.options, | |
232 ['-'], | |
233 self.parser) | |
234 self.assertEquals(result, inputs) | |
235 | |
236 def test_get_targets_multiple_stdin_null(self): | |
237 inputs = ['a', 'b', 'c', 'd', 'e'] | |
238 sys.stdin = StringIO.StringIO('\0'.join(inputs)) | |
239 self.options.use_null_terminator = True | |
240 result = upload_to_google_storage.get_targets( | |
241 self.options, | |
242 ['-'], | |
243 self.parser) | |
244 self.assertEquals(result, inputs) | |
245 | |
246 | |
247 class DownloadTests(unittest.TestCase): | |
248 def setUp(self): | |
249 self.gsutil = GsutilMock(GSUTIL_DEFAULT_PATH) | |
250 self.base_path = os.path.join( | |
251 os.path.dirname(os.path.abspath(__file__)), | |
252 'gstools', | |
253 'download_test_data') | |
254 self.base_url = 'gs://sometesturl' | |
255 self.parser = optparse.OptionParser() | |
256 self.options = self.parser.parse_args()[0] | |
257 self.options.recursive = False | |
258 self.options.force = False | |
259 self.options.directory = False | |
260 self.queue = Queue.Queue() | |
261 self.lorem_ipsum = os.path.join(self.base_path, 'lorem_ipsum.txt') | |
262 self.lorem_ipsum_sha1 = '7871c8e24da15bad8b0be2c36edc9dc77e37727f' | |
263 self.maxDiff = None | |
264 | |
265 def test_enumerate_files_non_recursive(self): | |
266 self.options.directory = True | |
267 queue_size = download_from_google_storage.enumerate_work_queue( | |
268 self.base_path, self.queue, self.options) | |
269 result = list(self.queue.queue) | |
270 self.assertEquals( | |
271 result, | |
272 [('e6c4fbd4fe7607f3e6ebf68b2ea4ef694da7b4fe', | |
273 os.path.join(self.base_path, 'rootfolder_text.txt')), | |
274 ('7871c8e24da15bad8b0be2c36edc9dc77e37727f', | |
275 os.path.join(self.base_path, 'uploaded_lorem_ipsum.txt'))]) | |
276 self.assertEquals(queue_size, 2) | |
277 | |
278 def test_enumerate_files_recursive(self): | |
279 self.options.directory = True | |
280 self.options.recursive = True | |
281 queue_size = download_from_google_storage.enumerate_work_queue( | |
282 self.base_path, self.queue, self.options) | |
283 result = list(self.queue.queue) | |
284 self.assertEquals( | |
285 result, | |
286 [('e6c4fbd4fe7607f3e6ebf68b2ea4ef694da7b4fe', | |
287 os.path.join(self.base_path, 'rootfolder_text.txt')), | |
288 ('7871c8e24da15bad8b0be2c36edc9dc77e37727f', | |
289 os.path.join(self.base_path, 'uploaded_lorem_ipsum.txt')), | |
290 ('b5415aa0b64006a95c0c409182e628881d6d6463', | |
291 os.path.join(self.base_path, 'subfolder', 'subfolder_text.txt'))]) | |
292 self.assertEquals(queue_size, 3) | |
293 | |
294 def test_download_worker_single_file(self): | |
295 sha1_hash = '7871c8e24da15bad8b0be2c36edc9dc77e37727f' | |
296 input_filename = '%s/%s' % (self.base_url, sha1_hash) | |
297 output_filename = os.path.join(self.base_path, 'uploaded_lorem_ipsum.txt') | |
298 self.queue.put((sha1_hash, output_filename)) | |
299 self.queue.put((None, None)) | |
300 stdout_queue = Queue.Queue() | |
301 # pylint: disable=W0212 | |
302 download_from_google_storage._downloader_worker_thread( | |
303 0, self.queue, self.options, self.base_url, self.gsutil, stdout_queue) | |
304 expected_calls = [ | |
305 ('check_call', | |
306 ('ls', input_filename)), | |
307 ('call', | |
308 ('cp', '-q', input_filename, output_filename))] | |
309 expected_output = [ | |
310 'Downloading %s to %s...' % (input_filename, output_filename), | |
311 'Thread 0 is done'] | |
312 self.assertEquals(list(stdout_queue.queue), expected_output) | |
313 self.assertEquals(self.gsutil.history, expected_calls) | |
314 | |
315 def test_download_worker_skips_file(self): | |
316 sha1_hash = 'e6c4fbd4fe7607f3e6ebf68b2ea4ef694da7b4fe' | |
317 output_filename = os.path.join(self.base_path, 'rootfolder_text.txt') | |
318 self.queue.put((sha1_hash, output_filename)) | |
319 self.queue.put((None, None)) | |
320 stdout_queue = Queue.Queue() | |
321 # pylint: disable=W0212 | |
322 download_from_google_storage._downloader_worker_thread( | |
323 0, self.queue, self.options, self.base_url, self.gsutil, stdout_queue) | |
324 expected_output = [ | |
325 'File %s exists and SHA1 sum (%s) matches. Skipping.' % | |
326 (output_filename, sha1_hash), | |
327 'Thread 0 is done' | |
328 ] | |
329 self.assertEquals(list(stdout_queue.queue), expected_output) | |
330 self.assertEquals(self.gsutil.history, []) | |
331 | |
332 def test_download_worker_skips_not_found_file(self): | |
333 sha1_hash = '7871c8e24da15bad8b0be2c36edc9dc77e37727f' | |
334 input_filename = '%s/%s' % (self.base_url, sha1_hash) | |
335 output_filename = os.path.join(self.base_path, 'uploaded_lorem_ipsum.txt') | |
336 self.queue.put((sha1_hash, output_filename)) | |
337 self.queue.put((None, None)) | |
338 stdout_queue = Queue.Queue() | |
339 self.gsutil.add_expected(1, '', '') # Return error when 'ls' is called. | |
340 # pylint: disable=W0212 | |
341 download_from_google_storage._downloader_worker_thread( | |
342 0, self.queue, self.options, self.base_url, self.gsutil, stdout_queue) | |
343 expected_output = [ | |
344 'File %s for %s does not exist, skipping.' % ( | |
345 input_filename, output_filename), | |
346 'Thread 0 is done' | |
347 ] | |
348 expected_calls = [ | |
349 ('check_call', | |
350 ('ls', input_filename)) | |
351 ] | |
352 self.assertEquals(list(stdout_queue.queue), expected_output) | |
353 self.assertEquals(self.gsutil.history, expected_calls) | |
354 | |
355 | |
356 if __name__ == '__main__': | |
357 unittest.main() | |
OLD | NEW |