def testCleaningFalse(self, gen_mock): """Verify behavior of clean_breakpad=False""" with parallel_unittest.ParallelMock(): # Dir does not exist, and then does. self.assertNotExists(self.breakpad_dir) ret = cros_generate_breakpad_symbols.GenerateBreakpadSymbols( self.board, sysroot=self.board_dir, generate_count=1, clean_breakpad=False) self.assertEquals(ret, 0) self.assertEquals(gen_mock.call_count, 1) self.assertExists(self.breakpad_dir) # Dir exists before & after. # File exists before & after. dummy_file = os.path.join(self.breakpad_dir, 'fooooooooo') osutils.Touch(dummy_file) ret = cros_generate_breakpad_symbols.GenerateBreakpadSymbols( self.board, sysroot=self.board_dir, generate_count=1, clean_breakpad=False) self.assertEquals(ret, 0) self.assertEquals(gen_mock.call_count, 2) self.assertExists(dummy_file)
def testGenLimit(self, gen_mock): """Verify generate_count arg works""" with parallel_unittest.ParallelMock(): # Generate nothing! ret = cros_generate_breakpad_symbols.GenerateBreakpadSymbols( self.board, sysroot=self.board_dir, breakpad_dir=self.breakpad_dir, generate_count=0) self.assertEquals(ret, 0) self.assertEquals(gen_mock.call_count, 0) # Generate just one. ret = cros_generate_breakpad_symbols.GenerateBreakpadSymbols( self.board, sysroot=self.board_dir, breakpad_dir=self.breakpad_dir, generate_count=1) self.assertEquals(ret, 0) self.assertEquals(gen_mock.call_count, 1) # The largest ELF should be processed first. call1 = (os.path.join(self.board_dir, 'iii/large-elf'), os.path.join(self.debug_dir, 'iii/large-elf.debug')) self.assertEquals(gen_mock.call_args_list[0][0], call1)
def testFileList(self, gen_mock): """Verify that file_list restricts the symbols generated""" with parallel_unittest.ParallelMock(): call1 = (os.path.join(self.board_dir, 'usr/sbin/elf'), os.path.join(self.debug_dir, 'usr/sbin/elf.debug')) # Filter with elf path. ret = cros_generate_breakpad_symbols.GenerateBreakpadSymbols( self.board, sysroot=self.board_dir, breakpad_dir=self.breakpad_dir, file_list=[os.path.join(self.board_dir, 'usr', 'sbin', 'elf')]) self.assertEquals(ret, 0) self.assertEquals(gen_mock.call_count, 1) self.assertEquals(gen_mock.call_args_list[0][0], call1) # Filter with debug symbols file path. gen_mock.reset_mock() ret = cros_generate_breakpad_symbols.GenerateBreakpadSymbols( self.board, sysroot=self.board_dir, breakpad_dir=self.breakpad_dir, file_list=[ os.path.join(self.debug_dir, 'usr', 'sbin', 'elf.debug') ]) self.assertEquals(ret, 0) self.assertEquals(gen_mock.call_count, 1) self.assertEquals(gen_mock.call_args_list[0][0], call1)
def testExclusionList(self, gen_mock): """Verify files in directories of the exclusion list are excluded""" exclude_dirs = ['bin', 'usr', 'fake/dir/fake'] with parallel_unittest.ParallelMock(): ret = cros_generate_breakpad_symbols.GenerateBreakpadSymbols( self.board, sysroot=self.board_dir, exclude_dirs=exclude_dirs) self.assertEquals(ret, 0) self.assertEquals(gen_mock.call_count, 1)
def testGenErrors(self, gen_mock): """Verify we handle errors from generation correctly""" def _SetError(*_args, **kwargs): kwargs['num_errors'].value += 1 return 1 gen_mock.side_effect = _SetError with parallel_unittest.ParallelMock(): ret = cros_generate_breakpad_symbols.GenerateBreakpadSymbols( self.board, sysroot=self.board_dir) self.assertEqual(ret, 3) self.assertEqual(gen_mock.call_count, 3)
def testNormal(self, gen_mock): """Verify all the files we expect to get generated do""" with parallel_unittest.ParallelMock(): ret = cros_generate_breakpad_symbols.GenerateBreakpadSymbols( self.board, sysroot=self.board_dir) self.assertEquals(ret, 0) self.assertEquals(gen_mock.call_count, 3) # The largest ELF should be processed first. call1 = (os.path.join(self.board_dir, 'iii/large-elf'), os.path.join(self.debug_dir, 'iii/large-elf.debug')) self.assertEquals(gen_mock.call_args_list[0][0], call1) # The other ELFs can be called in any order. call2 = (os.path.join(self.board_dir, 'bin/elf'), os.path.join(self.debug_dir, 'bin/elf.debug')) call3 = (os.path.join(self.board_dir, 'usr/sbin/elf'), os.path.join(self.debug_dir, 'usr/sbin/elf.debug')) exp_calls = set((call2, call3)) actual_calls = set( (gen_mock.call_args_list[1][0], gen_mock.call_args_list[2][0])) self.assertEquals(exp_calls, actual_calls)
def main(argv): parser = commandline.ArgumentParser(description=__doc__) # TODO: Make sym_paths, breakpad_root, and root exclusive. parser.add_argument('sym_paths', type='path_or_uri', nargs='*', default=None, help='symbol file or directory or URL or tarball') parser.add_argument('--board', default=None, help='Used to find default breakpad_root.') parser.add_argument('--breakpad_root', type='path', default=None, help='full path to the breakpad symbol directory') parser.add_argument('--root', type='path', default=None, help='full path to the chroot dir') parser.add_argument('--official_build', action='store_true', default=False, help='point to official symbol server') parser.add_argument('--server', type=str, default=None, help='URI for custom symbol server') parser.add_argument('--regenerate', action='store_true', default=False, help='regenerate all symbols') parser.add_argument('--upload-limit', type=int, help='only upload # number of symbols') parser.add_argument('--strip_cfi', type=int, default=DEFAULT_FILE_LIMIT, help='strip CFI data for files above this size') parser.add_argument('--failed-list', type='path', help='where to save a list of failed symbols') parser.add_argument('--dedupe', action='store_true', default=False, help='use the swarming service to avoid re-uploading') parser.add_argument('--yes', action='store_true', default=False, help='answer yes to all prompts') parser.add_argument('--product_name', type=str, default='ChromeOS', help='Produce Name for breakpad stats.') opts = parser.parse_args(argv) opts.Freeze() # Figure out the symbol files/directories to upload. if opts.sym_paths: sym_paths = opts.sym_paths elif opts.breakpad_root: sym_paths = [opts.breakpad_root] elif opts.root: if not opts.board: raise ValueError('--board must be set if --root is used.') breakpad_dir = cros_generate_breakpad_symbols.FindBreakpadDir( opts.board) sym_paths = [os.path.join(opts.root, breakpad_dir.lstrip('/'))] else: raise ValueError( '--sym_paths, --breakpad_root, or --root must be set.') if opts.sym_paths or opts.breakpad_root: if opts.regenerate: cros_build_lib.Die( '--regenerate may not be used with specific files, ' 'or breakpad_root') else: if opts.board is None: cros_build_lib.Die('--board is required') # Figure out the dedupe namespace. dedupe_namespace = None if opts.dedupe: if opts.official_build: dedupe_namespace = OFFICIAL_DEDUPE_NAMESPACE_TMPL % opts.product_name else: dedupe_namespace = STAGING_DEDUPE_NAMESPACE_TMPL % opts.product_name # Figure out which crash server to upload too. upload_url = opts.server if not upload_url: if opts.official_build: upload_url = OFFICIAL_UPLOAD_URL else: logging.warning('unofficial builds upload to the staging server') upload_url = STAGING_UPLOAD_URL # Confirm we really want the long upload. if not opts.yes: prolog = '\n'.join( textwrap.wrap( textwrap.dedent(""" Uploading symbols for an entire Chromium OS build is really only necessary for release builds and in a few cases for developers to debug problems. It will take considerable time to run. For developer debugging purposes, consider instead passing specific files to upload. """), 80)).strip() if not cros_build_lib.BooleanPrompt( prompt='Are you sure you want to upload all build symbols', default=False, prolog=prolog): cros_build_lib.Die('better safe than sorry') ret = 0 # Regenerate symbols from binaries. if opts.regenerate: ret += cros_generate_breakpad_symbols.GenerateBreakpadSymbols( opts.board, breakpad_dir=opts.breakpad_root) # Do the upload. ret += UploadSymbols(sym_paths=sym_paths, upload_url=upload_url, product_name=opts.product_name, dedupe_namespace=dedupe_namespace, failed_list=opts.failed_list, upload_limit=opts.upload_limit, strip_cfi=opts.strip_cfi) if ret: logging.error('encountered %i problem(s)', ret) # Since exit(status) gets masked, clamp it to 1 so we don't inadvertently # return 0 in case we are a multiple of the mask. return 1
def main(argv): parser = commandline.ArgumentParser(description=__doc__) parser.add_argument('sym_files', type='path', nargs='*', default=None) parser.add_argument('--board', default=None, help='board to build packages for') parser.add_argument('--breakpad_root', type='path', default=None, help='root directory for breakpad symbols') parser.add_argument('--official_build', action='store_true', default=False, help='point to official symbol server') parser.add_argument('--regenerate', action='store_true', default=False, help='regenerate all symbols') parser.add_argument('--upload-count', type=int, default=None, help='only upload # number of symbols') parser.add_argument('--strip_cfi', type=int, default=CRASH_SERVER_FILE_LIMIT - (10 * 1024 * 1024), help='strip CFI data for files above this size') parser.add_argument('--testing', action='store_true', default=False, help='run in testing mode') parser.add_argument('--yes', action='store_true', default=False, help='answer yes to all prompts') opts = parser.parse_args(argv) if opts.sym_files: if opts.regenerate: cros_build_lib.Die( '--regenerate may not be used with specific files') else: if opts.board is None: cros_build_lib.Die('--board is required') if opts.breakpad_root and opts.regenerate: cros_build_lib.Die('--regenerate may not be used with --breakpad_root') if opts.testing: # TODO(build): Kill off --testing mode once unittests are up-to-snuff. cros_build_lib.Info('running in testing mode') # pylint: disable=W0601,W0603 global INITIAL_RETRY_DELAY, SymUpload, DEFAULT_SLEEP_DELAY INITIAL_RETRY_DELAY = DEFAULT_SLEEP_DELAY = 0 SymUpload = TestingSymUpload if not opts.yes: query = textwrap.wrap( textwrap.dedent(""" Uploading symbols for an entire Chromium OS build is really only necessary for release builds and in a few cases for developers to debug problems. It will take considerable time to run. For developer debugging purposes, consider instead passing specific files to upload. """), 80) cros_build_lib.Warning('\n%s', '\n'.join(query)) if not cros_build_lib.BooleanPrompt( prompt='Are you sure you want to upload all build symbols', default=False): cros_build_lib.Die('better safe than sorry') ret = 0 if opts.regenerate: ret += cros_generate_breakpad_symbols.GenerateBreakpadSymbols( opts.board, breakpad_dir=opts.breakpad_root) ret += UploadSymbols(opts.board, official=opts.official_build, breakpad_dir=opts.breakpad_root, file_limit=opts.strip_cfi, sleep=DEFAULT_SLEEP_DELAY, upload_count=opts.upload_count, sym_files=opts.sym_files) if ret: cros_build_lib.Error('encountered %i problem(s)', ret) # Since exit(status) gets masked, clamp it to 1 so we don't inadvertently # return 0 in case we are a multiple of the mask. ret = 1 return ret
def main(argv): parser = commandline.ArgumentParser(description=__doc__) parser.add_argument('sym_paths', type='path_or_uri', nargs='*', default=None, help='symbol file or directory or URL or tarball') parser.add_argument('--board', default=None, help='Used to find default breakpad_root.') parser.add_argument('--breakpad_root', type='path', default=None, help='full path to the breakpad symbol directory') parser.add_argument('--root', type='path', default=None, help='full path to the chroot dir') parser.add_argument('--official_build', action='store_true', default=False, help='point to official symbol server') parser.add_argument('--server', type=str, default=None, help='URI for custom symbol server') parser.add_argument('--regenerate', action='store_true', default=False, help='regenerate all symbols') parser.add_argument('--upload-limit', type=int, default=None, help='only upload # number of symbols') parser.add_argument('--strip_cfi', type=int, default=CRASH_SERVER_FILE_LIMIT - (10 * 1024 * 1024), help='strip CFI data for files above this size') parser.add_argument('--failed-list', type='path', help='where to save a list of failed symbols') parser.add_argument('--dedupe', action='store_true', default=False, help='use the swarming service to avoid re-uploading') parser.add_argument('--testing', action='store_true', default=False, help='run in testing mode') parser.add_argument('--yes', action='store_true', default=False, help='answer yes to all prompts') parser.add_argument('--product_name', type=str, default='ChromeOS', help='Produce Name for breakpad stats.') opts = parser.parse_args(argv) opts.Freeze() if opts.sym_paths or opts.breakpad_root: if opts.regenerate: cros_build_lib.Die( '--regenerate may not be used with specific files, ' 'or breakpad_root') else: if opts.board is None: cros_build_lib.Die('--board is required') if opts.testing: # TODO(build): Kill off --testing mode once unittests are up-to-snuff. logging.info('running in testing mode') # pylint: disable=W0601,W0603 global INITIAL_RETRY_DELAY, SymUpload, DEFAULT_SLEEP_DELAY INITIAL_RETRY_DELAY = DEFAULT_SLEEP_DELAY = 0 SymUpload = TestingSymUpload dedupe_namespace = None if opts.dedupe: if opts.official_build and not opts.testing: dedupe_namespace = OFFICIAL_DEDUPE_NAMESPACE_TMPL % opts.product_name else: dedupe_namespace = STAGING_DEDUPE_NAMESPACE_TMPL % opts.product_name if not opts.yes: prolog = '\n'.join( textwrap.wrap( textwrap.dedent(""" Uploading symbols for an entire Chromium OS build is really only necessary for release builds and in a few cases for developers to debug problems. It will take considerable time to run. For developer debugging purposes, consider instead passing specific files to upload. """), 80)).strip() if not cros_build_lib.BooleanPrompt( prompt='Are you sure you want to upload all build symbols', default=False, prolog=prolog): cros_build_lib.Die('better safe than sorry') ret = 0 if opts.regenerate: ret += cros_generate_breakpad_symbols.GenerateBreakpadSymbols( opts.board, breakpad_dir=opts.breakpad_root) ret += UploadSymbols(opts.board, official=opts.official_build, server=opts.server, breakpad_dir=opts.breakpad_root, file_limit=opts.strip_cfi, sleep=DEFAULT_SLEEP_DELAY, upload_limit=opts.upload_limit, sym_paths=opts.sym_paths, failed_list=opts.failed_list, root=opts.root, dedupe_namespace=dedupe_namespace, product_name=opts.product_name) if ret: logging.error('encountered %i problem(s)', ret) # Since exit(status) gets masked, clamp it to 1 so we don't inadvertently # return 0 in case we are a multiple of the mask. ret = 1 return ret