blob: 6786e2b582fa2a6a181ec24a7caca6608e474996 [file] [log] [blame]
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -04001#!/usr/bin/python
2# Copyright (c) 2013 The Chromium OS 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
Mike Frysingereb753bf2013-11-22 16:05:35 -05006"""Unittests for upload_symbols.py"""
7
Mike Frysinger7f9be142014-01-15 02:16:42 -05008from __future__ import print_function
9
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040010import ctypes
11import logging
Mike Frysinger0c0efa22014-02-09 23:32:23 -050012import multiprocessing
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040013import os
14import sys
Aviv Keshetd1f04632014-05-09 11:33:46 -070015import time
Mike Frysinger094a2172013-08-14 12:54:35 -040016import urllib2
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040017
18sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)),
19 '..', '..'))
Mike Frysinger02e92402013-11-22 16:22:02 -050020from chromite.lib import cros_build_lib
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040021from chromite.lib import cros_test_lib
22from chromite.lib import osutils
23from chromite.lib import parallel
24from chromite.lib import parallel_unittest
Mike Frysinger5e30a4b2014-02-12 20:23:04 -050025from chromite.scripts import cros_generate_breakpad_symbols
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040026from chromite.scripts import upload_symbols
27
Mike Frysinger0c0efa22014-02-09 23:32:23 -050028# TODO(build): Finish test wrapper (http://crosbug.com/37517).
29# Until then, this has to be after the chromite imports.
30import isolateserver
31import mock
32
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040033
34class UploadSymbolsTest(cros_test_lib.MockTempDirTestCase):
Mike Frysingerc4ab5782013-10-02 18:14:22 -040035 """Tests for UploadSymbols()"""
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040036
37 def setUp(self):
38 for d in ('foo', 'bar', 'some/dir/here'):
39 d = os.path.join(self.tempdir, d)
40 osutils.SafeMakedirs(d)
41 for f in ('ignored', 'real.sym', 'no.sym.here'):
42 f = os.path.join(d, f)
43 osutils.Touch(f)
Mike Frysingerd41938e2014-02-10 06:37:55 -050044 self.sym_paths = [
45 'bar/real.sym',
46 'foo/real.sym',
47 'some/dir/here/real.sym',
48 ]
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040049
Mike Frysinger5e30a4b2014-02-12 20:23:04 -050050 self.upload_mock = self.PatchObject(upload_symbols, 'UploadSymbol')
51 self.PatchObject(cros_generate_breakpad_symbols, 'ReadSymsHeader',
52 return_value=cros_generate_breakpad_symbols.SymbolHeader(
53 os='os', cpu='cpu', id='id', name='name'))
54
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040055 def _testUploadURL(self, official, expected_url):
56 """Helper for checking the url used"""
Mike Frysinger5e30a4b2014-02-12 20:23:04 -050057 self.upload_mock.return_value = 0
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040058 with parallel_unittest.ParallelMock():
Mike Frysinger02e92402013-11-22 16:22:02 -050059 ret = upload_symbols.UploadSymbols('', official=official, retry=False,
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040060 breakpad_dir=self.tempdir, sleep=0)
61 self.assertEqual(ret, 0)
Mike Frysinger5e30a4b2014-02-12 20:23:04 -050062 self.assertEqual(self.upload_mock.call_count, 3)
63 for call_args in self.upload_mock.call_args_list:
Mike Frysinger0c0efa22014-02-09 23:32:23 -050064 url, sym_item = call_args[0]
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040065 self.assertEqual(url, expected_url)
Mike Frysinger0c0efa22014-02-09 23:32:23 -050066 self.assertTrue(sym_item.sym_file.endswith('.sym'))
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040067
68 def testOfficialUploadURL(self):
69 """Verify we upload to the real crash server for official builds"""
70 self._testUploadURL(True, upload_symbols.OFFICIAL_UPLOAD_URL)
71
72 def testUnofficialUploadURL(self):
73 """Verify we upload to the staging crash server for unofficial builds"""
74 self._testUploadURL(False, upload_symbols.STAGING_UPLOAD_URL)
75
76 def testUploadSymbolFailureSimple(self):
77 """Verify that when UploadSymbol fails, the error count is passed up"""
78 def UploadSymbol(*_args, **kwargs):
79 kwargs['num_errors'].value = 4
Mike Frysinger5e30a4b2014-02-12 20:23:04 -050080 self.upload_mock.side_effect = UploadSymbol
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040081 with parallel_unittest.ParallelMock():
Mike Frysinger02e92402013-11-22 16:22:02 -050082 ret = upload_symbols.UploadSymbols('', breakpad_dir=self.tempdir, sleep=0,
83 retry=False)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040084 self.assertEquals(ret, 4)
85
86 def testUploadCount(self):
87 """Verify we can limit the number of uploaded symbols"""
Mike Frysinger5e30a4b2014-02-12 20:23:04 -050088 self.upload_mock.return_value = 0
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040089 for c in xrange(3):
Mike Frysinger5e30a4b2014-02-12 20:23:04 -050090 self.upload_mock.reset_mock()
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040091 with parallel_unittest.ParallelMock():
92 ret = upload_symbols.UploadSymbols('', breakpad_dir=self.tempdir,
Mike Frysinger8ec8c502014-02-10 00:19:13 -050093 sleep=0, upload_limit=c)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040094 self.assertEquals(ret, 0)
Mike Frysinger5e30a4b2014-02-12 20:23:04 -050095 self.assertEqual(self.upload_mock.call_count, c)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040096
Mike Frysinger7f9be142014-01-15 02:16:42 -050097 def testFailedFileList(self):
98 """Verify the failed file list is populated with the right content"""
99 def UploadSymbol(*args, **kwargs):
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500100 kwargs['failed_queue'].put(args[1].sym_file)
Mike Frysinger7f9be142014-01-15 02:16:42 -0500101 kwargs['num_errors'].value = 4
Mike Frysinger5e30a4b2014-02-12 20:23:04 -0500102 self.upload_mock.side_effect = UploadSymbol
Mike Frysinger7f9be142014-01-15 02:16:42 -0500103 with parallel_unittest.ParallelMock():
104 failed_list = os.path.join(self.tempdir, 'list')
105 ret = upload_symbols.UploadSymbols('', breakpad_dir=self.tempdir, sleep=0,
106 retry=False, failed_list=failed_list)
107 self.assertEquals(ret, 4)
108
109 # Need to sort the output as parallel/fs discovery can be unordered.
110 got_list = sorted(osutils.ReadFile(failed_list).splitlines())
Mike Frysingerd41938e2014-02-10 06:37:55 -0500111 self.assertEquals(self.sym_paths, got_list)
112
113 def _testUpload(self, inputs, sym_paths=None):
114 """Helper for testing uploading of specific paths"""
115 if sym_paths is None:
116 sym_paths = inputs
117
118 self.upload_mock.return_value = 0
119 with parallel_unittest.ParallelMock():
120 ret = upload_symbols.UploadSymbols(sym_paths=inputs, sleep=0,
121 retry=False)
122 self.assertEquals(ret, 0)
123 self.assertEquals(self.upload_mock.call_count, len(sym_paths))
124
125 # Since upload order is arbitrary, we have to do a manual scan for each
126 # path ourselves against the uploaded file list.
127 found_syms = [x[0][1].sym_file for x in self.upload_mock.call_args_list]
128 for found_sym in found_syms:
129 for path in sym_paths:
130 if found_sym.endswith(path):
131 break
132 else:
133 raise AssertionError('Could not locate %s in %r' % (path, found_syms))
134
135 def testUploadFiles(self):
136 """Test uploading specific symbol files"""
137 sym_paths = (
138 os.path.join(self.tempdir, 'bar', 'real.sym'),
139 os.path.join(self.tempdir, 'foo', 'real.sym'),
140 )
141 self._testUpload(sym_paths)
142
143 def testUploadDirectory(self):
144 """Test uploading directory of symbol files"""
145 self._testUpload([self.tempdir], sym_paths=self.sym_paths)
146
147 def testUploadLocalTarball(self):
148 """Test uploading symbols contains in a local tarball"""
149 tarball = os.path.join(self.tempdir, 'syms.tar.gz')
150 cros_build_lib.CreateTarball(
151 'syms.tar.gz', self.tempdir, compression=cros_build_lib.COMP_GZIP,
152 inputs=('foo', 'bar', 'some'))
153 self._testUpload([tarball], sym_paths=self.sym_paths)
154
155 def testUploadRemoteTarball(self):
156 """Test uploading symbols contains in a remote tarball"""
157 # TODO: Need to figure out how to mock out lib.cache.TarballCache.
Mike Frysinger7f9be142014-01-15 02:16:42 -0500158
Mike Frysinger58312e92014-03-18 04:18:36 -0400159 def testDedupeNotifyFailure(self):
160 """Test that a dedupe server failure midway doesn't wedge things"""
161 api_mock = mock.MagicMock()
162
163 def _Contains(items):
164 """Do not dedupe anything"""
165 return items
166 api_mock.contains.side_effect = _Contains
167
168 # Use a list so the closure below can modify the value.
169 item_count = [0]
170 # Pick a number big enough to trigger a hang normally, but not so
171 # big it adds a lot of overhead.
172 item_limit = 50
173 def _Push(*_args):
174 """Die in the middle of the push list"""
175 item_count[0] += 1
176 if item_count[0] > (item_limit / 10):
177 raise ValueError('time to die')
178 api_mock.push.side_effect = _Push
179
180 self.PatchObject(isolateserver, 'get_storage_api', return_value=api_mock)
181
182 def _Uploader(*args, **kwargs):
183 """Pass the uploaded symbol to the deduper"""
184 sym_item = args[1]
185 passed_queue = kwargs['passed_queue']
186 passed_queue.put(sym_item)
187 self.upload_mock.side_effect = _Uploader
188
189 self.upload_mock.return_value = 0
190 with parallel_unittest.ParallelMock():
191 ret = upload_symbols.UploadSymbols(
192 '', sym_paths=[self.tempdir] * item_limit, sleep=0,
193 dedupe_namespace='inva!id name$pace')
194 self.assertEqual(ret, 0)
195 # This test normally passes by not hanging.
196
Aviv Keshetd1f04632014-05-09 11:33:46 -0700197 def testSlowDedupeSystem(self):
198 """Verify a slow-to-join process doesn't break things when dedupe is off"""
199 # The sleep value here is inherently a little racy, but seems to be good
200 # enough to trigger the bug on a semi-regular basis on developer systems.
201 self.PatchObject(upload_symbols, 'SymbolDeduplicatorNotify',
202 side_effect=lambda *args: time.sleep(1))
203 # Test passing means the code didn't throw an exception.
204 upload_symbols.UploadSymbols(sym_paths=[self.tempdir])
205
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400206
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500207class SymbolDeduplicatorNotifyTest(cros_test_lib.MockTestCase):
208 """Tests for SymbolDeduplicatorNotify()"""
209
210 def setUp(self):
211 self.storage_mock = self.PatchObject(isolateserver, 'get_storage_api')
212
213 def testSmoke(self):
214 """Basic run through the system."""
215 q = mock.MagicMock()
216 q.get.side_effect = (upload_symbols.FakeItem(), None,)
217 upload_symbols.SymbolDeduplicatorNotify('name', q)
218
219 def testStorageException(self):
220 """We want to just warn & move on when dedupe server fails"""
221 log_mock = self.PatchObject(cros_build_lib, 'Warning')
222 q = mock.MagicMock()
223 q.get.side_effect = (upload_symbols.FakeItem(), None,)
224 self.storage_mock.side_effect = Exception
225 upload_symbols.SymbolDeduplicatorNotify('name', q)
226 self.assertEqual(log_mock.call_count, 1)
227
228
229class SymbolDeduplicatorTest(cros_test_lib.MockTestCase):
230 """Tests for SymbolDeduplicator()"""
231
232 def setUp(self):
233 self.storage_mock = mock.MagicMock()
234 self.header_mock = self.PatchObject(
235 cros_generate_breakpad_symbols, 'ReadSymsHeader',
236 return_value=cros_generate_breakpad_symbols.SymbolHeader(
237 os='os', cpu='cpu', id='id', name='name'))
238
239 def testNoStorageOrPaths(self):
240 """We don't want to talk to the server if there's no storage or files"""
241 upload_symbols.SymbolDeduplicator(None, [])
242 upload_symbols.SymbolDeduplicator(self.storage_mock, [])
243 self.assertEqual(self.storage_mock.call_count, 0)
244 self.assertEqual(self.header_mock.call_count, 0)
245
246 def testStorageException(self):
247 """We want to just warn & move on when dedupe server fails"""
248 log_mock = self.PatchObject(cros_build_lib, 'Warning')
249 self.storage_mock.contains.side_effect = Exception('storage error')
250 sym_paths = ['/a', '/bbbbbb', '/cc.c']
251 ret = upload_symbols.SymbolDeduplicator(self.storage_mock, sym_paths)
252 self.assertEqual(log_mock.call_count, 1)
253 self.assertEqual(self.storage_mock.contains.call_count, 1)
254 self.assertEqual(self.header_mock.call_count, len(sym_paths))
255 self.assertEqual(len(ret), len(sym_paths))
256
257
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400258class UploadSymbolTest(cros_test_lib.MockTempDirTestCase):
Mike Frysingerc4ab5782013-10-02 18:14:22 -0400259 """Tests for UploadSymbol()"""
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400260
261 def setUp(self):
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400262 self.sym_file = os.path.join(self.tempdir, 'foo.sym')
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500263 self.sym_item = upload_symbols.FakeItem(sym_file=self.sym_file)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400264 self.url = 'http://eatit'
Mike Frysinger5e30a4b2014-02-12 20:23:04 -0500265 self.upload_mock = self.PatchObject(upload_symbols, 'SymUpload')
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400266
267 def testUploadSymbolNormal(self):
268 """Verify we try to upload on a normal file"""
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400269 osutils.Touch(self.sym_file)
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500270 ret = upload_symbols.UploadSymbol(self.url, self.sym_item)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400271 self.assertEqual(ret, 0)
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500272 self.upload_mock.assert_called_with(self.url, self.sym_item)
Mike Frysinger5e30a4b2014-02-12 20:23:04 -0500273 self.assertEqual(self.upload_mock.call_count, 1)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400274
275 def testUploadSymbolErrorCountExceeded(self):
276 """Verify that when the error count gets too high, we stop uploading"""
277 errors = ctypes.c_int(10000)
278 # Pass in garbage values so that we crash if num_errors isn't handled.
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500279 ret = upload_symbols.UploadSymbol(None, self.sym_item, sleep=None,
280 num_errors=errors)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400281 self.assertEqual(ret, 0)
282
Mike Frysingerc4ab5782013-10-02 18:14:22 -0400283 def testUploadRetryErrors(self, side_effect=None):
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400284 """Verify that we retry errors (and eventually give up)"""
Mike Frysingerc4ab5782013-10-02 18:14:22 -0400285 if not side_effect:
286 side_effect = urllib2.HTTPError('http://', 400, 'fail', {}, None)
Mike Frysinger5e30a4b2014-02-12 20:23:04 -0500287 self.upload_mock.side_effect = side_effect
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400288 errors = ctypes.c_int()
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500289 item = upload_symbols.FakeItem(sym_file='/dev/null')
290 ret = upload_symbols.UploadSymbol(self.url, item, num_errors=errors)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400291 self.assertEqual(ret, 1)
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500292 self.upload_mock.assert_called_with(self.url, item)
Mike Frysinger5e30a4b2014-02-12 20:23:04 -0500293 self.assertTrue(self.upload_mock.call_count >= upload_symbols.MAX_RETRIES)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400294
Mike Frysingerc4ab5782013-10-02 18:14:22 -0400295 def testConnectRetryErrors(self):
296 """Verify that we retry errors (and eventually give up) w/connect errors"""
297 side_effect = urllib2.URLError('foo')
298 self.testUploadRetryErrors(side_effect=side_effect)
299
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400300 def testTruncateTooBigFiles(self):
301 """Verify we shrink big files"""
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500302 def SymUpload(_url, sym_item):
303 content = osutils.ReadFile(sym_item.sym_file)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400304 self.assertEqual(content, 'some junk\n')
Mike Frysinger5e30a4b2014-02-12 20:23:04 -0500305 self.upload_mock.upload_mock.side_effect = SymUpload
306 content = '\n'.join((
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400307 'STACK CFI 1234',
308 'some junk',
309 'STACK CFI 1234',
Mike Frysinger5e30a4b2014-02-12 20:23:04 -0500310 ))
311 osutils.WriteFile(self.sym_file, content)
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500312 ret = upload_symbols.UploadSymbol(self.url, self.sym_item, file_limit=1)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400313 self.assertEqual(ret, 0)
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500314 # Make sure the item passed to the upload has a temp file and not the
315 # original -- only the temp one has been stripped down.
316 temp_item = self.upload_mock.call_args[0][1]
317 self.assertNotEqual(temp_item.sym_file, self.sym_item.sym_file)
Mike Frysinger5e30a4b2014-02-12 20:23:04 -0500318 self.assertEqual(self.upload_mock.call_count, 1)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400319
320 def testTruncateReallyLargeFiles(self):
321 """Verify we try to shrink really big files"""
Mike Frysinger02e92402013-11-22 16:22:02 -0500322 warn_mock = self.PatchObject(cros_build_lib, 'PrintBuildbotStepWarnings')
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400323 with open(self.sym_file, 'w+b') as f:
324 f.truncate(upload_symbols.CRASH_SERVER_FILE_LIMIT + 100)
325 f.seek(0)
326 f.write('STACK CFI 1234\n\n')
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500327 ret = upload_symbols.UploadSymbol(self.url, self.sym_item)
Mike Frysinger02e92402013-11-22 16:22:02 -0500328 self.assertEqual(ret, 0)
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500329 # Make sure the item passed to the upload has a temp file and not the
330 # original -- only the temp one has been truncated.
331 temp_item = self.upload_mock.call_args[0][1]
332 self.assertNotEqual(temp_item.sym_file, self.sym_item.sym_file)
Mike Frysinger5e30a4b2014-02-12 20:23:04 -0500333 self.assertEqual(self.upload_mock.call_count, 1)
Mike Frysinger02e92402013-11-22 16:22:02 -0500334 self.assertEqual(warn_mock.call_count, 1)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400335
336
Mike Frysinger094a2172013-08-14 12:54:35 -0400337class SymUploadTest(cros_test_lib.MockTempDirTestCase):
Mike Frysingerc4ab5782013-10-02 18:14:22 -0400338 """Tests for SymUpload()"""
Mike Frysinger094a2172013-08-14 12:54:35 -0400339
340 SYM_URL = 'http://localhost/post/it/here'
341 SYM_CONTENTS = """MODULE Linux arm 123-456 blkid
342PUBLIC 1471 0 main"""
343
344 def setUp(self):
345 self.sym_file = os.path.join(self.tempdir, 'test.sym')
346 osutils.WriteFile(self.sym_file, self.SYM_CONTENTS)
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500347 self.sym_item = upload_symbols.SymbolItem(self.sym_file)
Mike Frysinger094a2172013-08-14 12:54:35 -0400348
349 def testPostUpload(self):
350 """Verify HTTP POST has all the fields we need"""
351 m = self.PatchObject(urllib2, 'urlopen', autospec=True)
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500352 upload_symbols.SymUpload(self.SYM_URL, self.sym_item)
Mike Frysinger094a2172013-08-14 12:54:35 -0400353 self.assertEquals(m.call_count, 1)
354 req = m.call_args[0][0]
355 self.assertEquals(req.get_full_url(), self.SYM_URL)
356 data = ''.join([x for x in req.get_data()])
357
358 fields = {
359 'code_file': 'blkid',
360 'debug_file': 'blkid',
361 'debug_identifier': '123456',
362 'os': 'Linux',
363 'cpu': 'arm',
364 }
365 for key, val in fields.iteritems():
366 line = 'Content-Disposition: form-data; name="%s"\r\n' % key
367 self.assertTrue(line in data)
368 line = '%s\r\n' % val
369 self.assertTrue(line in data)
370 line = ('Content-Disposition: form-data; name="symbol_file"; '
371 'filename="test.sym"\r\n')
372 self.assertTrue(line in data)
373 self.assertTrue(self.SYM_CONTENTS in data)
374
Mike Frysinger71046662014-09-12 18:15:15 -0700375 def testTimeout(self):
376 """Verify timeouts scale based on filesize"""
377 m = self.PatchObject(urllib2, 'urlopen', autospec=True)
378 size = self.PatchObject(os.path, 'getsize')
379
380 tests = (
381 # Small files should get rounded up to the minimum timeout.
382 (10, upload_symbols.UPLOAD_MIN_TIMEOUT),
383 # A 50MiB file should take like ~4 minutes.
384 (50 * 1024 * 1024, 257),
385 )
386 for size.return_value, timeout in tests:
387 upload_symbols.SymUpload(self.SYM_URL, self.sym_item)
388 self.assertEqual(m.call_args[1]['timeout'], timeout)
389
Mike Frysinger094a2172013-08-14 12:54:35 -0400390
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500391class UtilTest(cros_test_lib.TempDirTestCase):
392 """Various tests for utility funcs."""
393
394 def testWriteQueueToFile(self):
395 """Basic test for WriteQueueToFile."""
396 listing = os.path.join(self.tempdir, 'list')
397 exp_list = [
398 'b/c.txt',
399 'foo.log',
400 'there/might/be/giants',
401 ]
402 relpath = '/a'
403
404 q = multiprocessing.Queue()
405 for f in exp_list:
406 q.put(os.path.join(relpath, f))
Mike Frysinger5e6dd712014-03-07 22:21:17 -0500407 q.put(None)
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500408 upload_symbols.WriteQueueToFile(listing, q, '/a')
409
410 got_list = osutils.ReadFile(listing).splitlines()
411 self.assertEquals(exp_list, got_list)
412
413
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400414if __name__ == '__main__':
415 # pylint: disable=W0212
416 # Set timeouts small so that if the unit test hangs, it won't hang for long.
417 parallel._BackgroundTask.STARTUP_TIMEOUT = 5
418 parallel._BackgroundTask.EXIT_TIMEOUT = 5
419
420 # We want to test retry behavior, so make sure we don't sleep.
421 upload_symbols.INITIAL_RETRY_DELAY = 0
422
423 # Run the tests.
424 cros_test_lib.main(level=logging.INFO)