def test_init_missing_required_fields(self): with self.assertRaises(AssertionError): MonorailIssue('', summary='test', status='Untriaged') with self.assertRaises(AssertionError): MonorailIssue('chromium', summary='', status='Untriaged') with self.assertRaises(AssertionError): MonorailIssue('chromium', summary='test', status='')
def test_init_string_passed_for_list_fields(self): with self.assertRaises(AssertionError): MonorailIssue('chromium', summary='test', status='Untriaged', cc='*****@*****.**') with self.assertRaises(AssertionError): MonorailIssue('chromium', summary='test', status='Untriaged', components='Infra') with self.assertRaises(AssertionError): MonorailIssue('chromium', summary='test', status='Untriaged', labels='Flaky')
def test_init_succeeds(self): # Minimum example. MonorailIssue('chromium', summary='test', status='Untriaged') # All fields. MonorailIssue('chromium', summary='test', status='Untriaged', description='body', cc=['*****@*****.**'], labels=['Flaky'], components=['Infra'])
def test_new_chromium_issue(self): issue = MonorailIssue.new_chromium_issue( 'test', description='body', cc=['*****@*****.**'], components=['Infra']) self.assertEqual(issue.project_id, 'chromium') self.assertEqual(issue.body['summary'], 'test') self.assertEqual(issue.body['description'], 'body') self.assertEqual(issue.body['cc'], ['*****@*****.**']) self.assertEqual(issue.body['components'], ['Infra'])
def test_str(self): issue = MonorailIssue('chromium', summary='test', status='Untriaged', description='body', cc=['*****@*****.**', '*****@*****.**'], labels=['Flaky'], components=['Infra']) self.assertEqual(str(issue), ('Monorail issue in project chromium\n' 'Summary: test\n' 'Status: Untriaged\n' 'CC: [email protected], [email protected]\n' 'Components: Infra\n' 'Labels: Flaky\n' 'Description:\nbody\n'))
def create_bugs_from_new_failures(self, wpt_revision_start, wpt_revision_end, gerrit_url): """Files bug reports for new failures. Args: wpt_revision_start: The start of the imported WPT revision range (exclusive), i.e. the last imported revision. wpt_revision_end: The end of the imported WPT revision range (inclusive), i.e. the current imported revision. gerrit_url: Gerrit URL of the CL. Return: A list of MonorailIssue objects that should be filed. """ imported_commits = self.local_wpt.commits_in_range(wpt_revision_start, wpt_revision_end) bugs = [] for directory, failures in self.new_failures_by_directory.iteritems(): summary = '[WPT] New failures introduced in {} by import {}'.format(directory, gerrit_url) full_directory = self.host.filesystem.join(self.finder.layout_tests_dir(), directory) owners_file = self.host.filesystem.join(full_directory, 'OWNERS') is_wpt_notify_enabled = self.owners_extractor.is_wpt_notify_enabled(owners_file) owners = self.owners_extractor.extract_owners(owners_file) # owners may be empty but not None. cc = owners + ['*****@*****.**'] component = self.owners_extractor.extract_component(owners_file) # component could be None. components = [component] if component else None prologue = ('WPT import {} introduced new failures in {}:\n\n' 'List of new failures:\n'.format(gerrit_url, directory)) failure_list = '' for failure in failures: failure_list += str(failure) + '\n' epilogue = '\nThis import contains upstream changes from {} to {}:\n'.format( wpt_revision_start, wpt_revision_end ) commit_list = self.format_commit_list(imported_commits, full_directory) description = prologue + failure_list + epilogue + commit_list bug = MonorailIssue.new_chromium_issue(summary, description, cc, components) _log.info(unicode(bug)) if is_wpt_notify_enabled: _log.info("WPT-NOTIFY enabled in this directory; adding the bug to the pending list.") bugs.append(bug) else: _log.info("WPT-NOTIFY disabled in this directory; discarding the bug.") return bugs
def create_bugs_for_product(self, wpt_revision_start, wpt_revision_end, gerrit_url, product, expectation_lines): """Files bug reports for new failures per product Args: wpt_revision_start: The start of the imported WPT revision range (exclusive), i.e. the last imported revision. wpt_revision_end: The end of the imported WPT revision range (inclusive), i.e. the current imported revision. gerrit_url: Gerrit URL of the CL. product: the product for which to file bugs for. expectation_lines: list of new expectations for this product Return: A MonorailIssue object that should be filed. """ bugs = [] summary = '[WPT] New failures introduced by import {}'.format(gerrit_url) prologue = ('WPT import {} introduced new failures:\n\n' 'List of new failures:\n'.format(gerrit_url)) failure_list = '' for _, failure in expectation_lines.items(): failure_list += str(failure) + '\n' expectations_statement = ( '\nExpectations have been automatically added for ' 'the failing results to keep the bots green. Please ' 'investigate the new failures and triage as appropriate.\n') range_statement = '\nThis import contains upstream changes from {} to {}:\n'.format( wpt_revision_start, wpt_revision_end) description = (prologue + failure_list + expectations_statement + range_statement) bug = MonorailIssue.new_chromium_issue( summary, description, cc=[], components=self.components_for_product[product], labels=self.labels_for_product[product]) bugs.append(bug) return bugs
def file_bugs(self, bugs, dry_run, service_account_key_json=None): """Files a list of bugs to Monorail. Args: bugs: A list of MonorailIssue objects. dry_run: A boolean, whether we are in dry run mode. service_account_key_json: Optional, see docs for main(). """ # TODO(robertma): Better error handling in this method. if dry_run: _log.info('[dry_run] Would have filed the %d bugs in the pending list.', len(bugs)) return _log.info('Filing %d bugs in the pending list to Monorail', len(bugs)) api = self._get_monorail_api(service_account_key_json) for index, bug in enumerate(bugs, start=1): response = api.insert_issue(bug) _log.info('[%d] Filed bug: %s', index, MonorailIssue.crbug_link(response['id']))
def test_unicode(self): issue = MonorailIssue( 'chromium', summary=u'test', status='Untriaged', description= u'ABC~‾¥≈¤・・•∙·☼★星🌟星★☼·∙•・・¤≈¥‾~XYZ', cc=['*****@*****.**', '*****@*****.**'], labels=['Flaky'], components=['Infra']) self.assertEqual(type(unicode(issue)), unicode) self.assertEqual(unicode(issue), ( u'Monorail issue in project chromium\n' u'Summary: test\n' u'Status: Untriaged\n' u'CC: [email protected], [email protected]\n' u'Components: Infra\n' u'Labels: Flaky\n' u'Description:\nABC~‾¥≈¤・・•∙·☼★星🌟星★☼·∙•・・¤≈¥‾~XYZ\n' ))
def create_bugs_from_new_failures(self, wpt_revision_start, wpt_revision_end, gerrit_url): """Files bug reports for new failures. Args: wpt_revision_start: The start of the imported WPT revision range (exclusive), i.e. the last imported revision. wpt_revision_end: The end of the imported WPT revision range (inclusive), i.e. the current imported revision. gerrit_url: Gerrit URL of the CL. Return: A list of MonorailIssue objects that should be filed. """ imported_commits = self.local_wpt.commits_in_range( wpt_revision_start, wpt_revision_end) bugs = [] for directory, failures in self.new_failures_by_directory.items(): summary = '[WPT] New failures introduced in {} by import {}'.format( directory, gerrit_url) full_directory = self.host.filesystem.join( self.finder.web_tests_dir(), directory) owners_file = self.host.filesystem.join(full_directory, 'OWNERS') metadata_file = self.host.filesystem.join(full_directory, 'DIR_METADATA') is_wpt_notify_enabled = False try: is_wpt_notify_enabled = self.owners_extractor.is_wpt_notify_enabled( metadata_file) except KeyError: _log.info('KeyError when parsing %s' % metadata_file) if not is_wpt_notify_enabled: _log.info("WPT-NOTIFY disabled in %s." % full_directory) continue owners = self.owners_extractor.extract_owners(owners_file) # owners may be empty but not None. cc = owners component = self.owners_extractor.extract_component(metadata_file) # component could be None. components = [component] if component else None prologue = ('WPT import {} introduced new failures in {}:\n\n' 'List of new failures:\n'.format( gerrit_url, directory)) failure_list = '' for failure in failures: failure_list += str(failure) + '\n' expectations_statement = ( '\nExpectations or baseline files [0] have been automatically ' 'added for the failing results to keep the bots green. Please ' 'investigate the new failures and triage as appropriate.\n') range_statement = '\nThis import contains upstream changes from {} to {}:\n'.format( wpt_revision_start, wpt_revision_end) commit_list = self.format_commit_list(imported_commits, full_directory) links_list = '\n[0]: https://chromium.googlesource.com/chromium/src/+/HEAD/docs/testing/web_test_expectations.md\n' description = (prologue + failure_list + expectations_statement + range_statement + commit_list + links_list) bug = MonorailIssue.new_chromium_issue(summary, description, cc, components, labels=['Test-WebTest']) _log.info(bug) _log.info("WPT-NOTIFY enabled in %s; adding the bug to the pending list." % full_directory) bugs.append(bug) return bugs
def test_crbug_link(self): self.assertEqual(MonorailIssue.crbug_link(12345), 'https://crbug.com/12345')
def test_init_unknown_status(self): with self.assertRaises(AssertionError): MonorailIssue('chromium', summary='test', status='unknown')
def test_init_unknown_fields(self): with self.assertRaises(AssertionError): MonorailIssue('chromium', component='foo')
def test_init_fills_project_id(self): issue = MonorailIssue('chromium', summary='test', status='Untriaged') self.assertEqual(issue.body['projectId'], 'chromium')