class DirectoryOwnersExtractorTest(unittest.TestCase): def setUp(self): # We always have an OWNERS file at web_tests/external. self.host = MockHost() self.host.filesystem = MockFileSystem(files={ MOCK_WEB_TESTS + 'external/OWNERS': '*****@*****.**' }) self.extractor = DirectoryOwnersExtractor(self.host) def _write_files(self, files): # Use write_text_file instead of directly assigning to filesystem.files # so that intermediary directories are correctly created, too. for path, contents in files.iteritems(): self.host.filesystem.write_text_file(path, contents) def test_list_owners_combines_same_owners(self): self._write_files({ ABS_WPT_BASE + '/foo/x.html': '', ABS_WPT_BASE + '/foo/OWNERS': '[email protected]\[email protected]\n', ABS_WPT_BASE + '/bar/x/y.html': '', ABS_WPT_BASE + '/bar/OWNERS': '[email protected]\[email protected]\n', }) changed_files = [ REL_WPT_BASE + '/foo/x.html', REL_WPT_BASE + '/bar/x/y.html', ] self.assertEqual( self.extractor.list_owners(changed_files), { ('*****@*****.**', '*****@*****.**'): ['external/wpt/bar', 'external/wpt/foo'] }) def test_list_owners_combines_same_directory(self): self._write_files({ ABS_WPT_BASE + '/baz/x/y.html': '', ABS_WPT_BASE + '/baz/x/y/z.html': '', ABS_WPT_BASE + '/baz/x/OWNERS': '[email protected]\n', }) changed_files = [ REL_WPT_BASE + '/baz/x/y.html', REL_WPT_BASE + '/baz/x/y/z.html', ] self.assertEqual( self.extractor.list_owners(changed_files), {('*****@*****.**', ): ['external/wpt/baz/x']}) def test_list_owners_skips_empty_owners(self): self._write_files({ ABS_WPT_BASE + '/baz/x/y/z.html': '', ABS_WPT_BASE + '/baz/x/y/OWNERS': '# Some comments\n', ABS_WPT_BASE + '/baz/x/OWNERS': '[email protected]\n', }) changed_files = [ REL_WPT_BASE + '/baz/x/y/z.html', ] self.assertEqual( self.extractor.list_owners(changed_files), {('*****@*****.**', ): ['external/wpt/baz/x']}) def test_list_owners_not_found(self): self._write_files({ # Although web_tests/external/OWNERS exists, it should not be listed. ABS_WPT_BASE + '/foo/bar.html': '', # Files out of external. '/mock-checkout/' + RELATIVE_WEB_TESTS + 'TestExpectations': '', '/mock-checkout/' + RELATIVE_WEB_TESTS + 'OWNERS': '*****@*****.**', }) changed_files = [ REL_WPT_BASE + '/foo/bar.html', RELATIVE_WEB_TESTS + 'TestExpectations', ] self.assertEqual(self.extractor.list_owners(changed_files), {}) def test_find_owners_file_at_current_dir(self): self._write_files({ABS_WPT_BASE + '/foo/OWNERS': '*****@*****.**'}) self.assertEqual( self.extractor.find_owners_file(REL_WPT_BASE + '/foo'), ABS_WPT_BASE + '/foo/OWNERS') def test_find_owners_file_at_ancestor(self): self._write_files({ ABS_WPT_BASE + '/x/OWNERS': '*****@*****.**', ABS_WPT_BASE + '/x/y/z.html': '', }) self.assertEqual( self.extractor.find_owners_file(REL_WPT_BASE + '/x/y'), ABS_WPT_BASE + '/x/OWNERS') def test_find_owners_file_stops_at_external_root(self): self._write_files({ ABS_WPT_BASE + '/x/y/z.html': '', }) self.assertEqual( self.extractor.find_owners_file(REL_WPT_BASE + '/x/y'), MOCK_WEB_TESTS + 'external/OWNERS') def test_find_owners_file_takes_four_kinds_of_paths(self): owners_path = ABS_WPT_BASE + '/foo/OWNERS' self._write_files({ owners_path: '*****@*****.**', ABS_WPT_BASE + '/foo/bar.html': '', }) # Absolute paths of directories. self.assertEqual( self.extractor.find_owners_file(ABS_WPT_BASE + '/foo'), owners_path) # Relative paths of directories. self.assertEqual( self.extractor.find_owners_file(REL_WPT_BASE + '/foo'), owners_path) # Absolute paths of files. self.assertEqual( self.extractor.find_owners_file(ABS_WPT_BASE + '/foo/bar.html'), owners_path) # Relative paths of files. self.assertEqual( self.extractor.find_owners_file(REL_WPT_BASE + '/foo/bar.html'), owners_path) def test_find_owners_file_out_of_external(self): self._write_files({ '/mock-checkout/' + RELATIVE_WEB_TESTS + 'OWNERS': '*****@*****.**', '/mock-checkout/' + RELATIVE_WEB_TESTS + 'other/some_file': '', }) self.assertIsNone( self.extractor.find_owners_file(RELATIVE_WEB_TESTS[:-1])) self.assertIsNone( self.extractor.find_owners_file(RELATIVE_WEB_TESTS + 'other')) self.assertIsNone(self.extractor.find_owners_file('third_party')) def test_extract_owners(self): self.host.filesystem.files = { ABS_WPT_BASE + '/foo/OWNERS': '#This is a comment\n' '*\n' '[email protected]\n' '[email protected]\n' 'foobar\n' '#[email protected]\n' '# TEAM: [email protected]\n' '# COMPONENT: Blink>Layout\n' } self.assertEqual( self.extractor.extract_owners(ABS_WPT_BASE + '/foo/OWNERS'), ['*****@*****.**', '*****@*****.**']) def test_extract_component(self): self.host.filesystem.files = { ABS_WPT_BASE + '/foo/OWNERS': '# TEAM: [email protected]\n' '# COMPONENT: Blink>Layout\n' } self.assertEqual( self.extractor.extract_component(ABS_WPT_BASE + '/foo/OWNERS'), 'Blink>Layout') def test_is_wpt_notify_enabled_true(self): self.host.filesystem.files = { ABS_WPT_BASE + '/foo/OWNERS': '# COMPONENT: Blink>Layout\n' '# WPT-NOTIFY: true\n' } self.assertTrue( self.extractor.is_wpt_notify_enabled(ABS_WPT_BASE + '/foo/OWNERS')) def test_is_wpt_notify_enabled_false(self): self.host.filesystem.files = { ABS_WPT_BASE + '/foo/OWNERS': '# COMPONENT: Blink>Layout\n' '# WPT-NOTIFY: false\n' } self.assertFalse( self.extractor.is_wpt_notify_enabled(ABS_WPT_BASE + '/foo/OWNERS')) def test_is_wpt_notify_enabled_absence_is_false(self): self.host.filesystem.files = { ABS_WPT_BASE + '/foo/OWNERS': '# TEAM: [email protected]\n' '# COMPONENT: Blink>Layout\n' } self.assertFalse( self.extractor.is_wpt_notify_enabled(ABS_WPT_BASE + '/foo/OWNERS')) def test_is_wpt_notify_enabled_with_dir_metadata(self): self.host.filesystem.files = { ABS_WPT_BASE + '/foo/OWNERS': '# TEAM: [email protected]\n' '# COMPONENT: Blink>Layout\n' '# WPT-NOTIFY: true\n' } data = ( '{"dirs":{"a/b":{"monorail":' '{"component":"foo"},"teamEmail":"bar","wpt":{"notify":"YES"}}}}') self.host.executive = MockExecutive(output=data) extractor = DirectoryOwnersExtractor(self.host) self.assertTrue( extractor.is_wpt_notify_enabled(MOCK_WEB_TESTS + 'a/b/OWNERS')) def test_is_wpt_notify_enabled_with_dir_metadata_none(self): self.host.filesystem.files = { ABS_WPT_BASE + '/foo/OWNERS': '# COMPONENT: Blink>Layout\n' '# WPT-NOTIFY: true\n' } self.host.executive = MockExecutive(output='error') extractor = DirectoryOwnersExtractor(self.host) self.assertTrue( extractor.is_wpt_notify_enabled(ABS_WPT_BASE + '/foo/OWNERS')) def test_extract_component_with_dir_metadata(self): data = ( '{"dirs":{"a/b":{"monorail":' '{"component":"foo"},"teamEmail":"bar","wpt":{"notify":"YES"}}}}') self.host.executive = MockExecutive(output=data) extractor = DirectoryOwnersExtractor(self.host) self.assertEqual( extractor.extract_component(MOCK_WEB_TESTS + 'a/b/OWNERS'), 'foo') def test_read_dir_metadata_success(self): data = ( '{"dirs":{"a/b":{"monorail":' '{"component":"foo"},"teamEmail":"bar","wpt":{"notify":"YES"}}}}') self.host.executive = MockExecutive(output=data) extractor = DirectoryOwnersExtractor(self.host) wpt_dir_metadata = extractor._read_dir_metadata(MOCK_WEB_TESTS + 'a/b/OWNERS') self.assertEqual(self.host.executive.full_calls[0].args, [ 'dirmd', 'compute', '-root', MOCK_WEB_TESTS_WITHOUT_SLASH, MOCK_WEB_TESTS + 'a/b' ]) self.assertEqual(wpt_dir_metadata.team_email, 'bar') self.assertEqual(wpt_dir_metadata.should_notify, True) self.assertEqual(wpt_dir_metadata.component, 'foo') def test_read_dir_metadata_none(self): self.host.executive = MockExecutive(output='error') extractor = DirectoryOwnersExtractor(self.host) wpt_dir_metadata = extractor._read_dir_metadata(MOCK_WEB_TESTS + 'a/b/OWNERS') self.assertEqual(self.host.executive.full_calls[0].args, [ 'dirmd', 'compute', '-root', MOCK_WEB_TESTS_WITHOUT_SLASH, MOCK_WEB_TESTS + 'a/b' ]) self.assertEqual(wpt_dir_metadata, None)
def get_directory_owners(self): """Returns a mapping of email addresses to owners of changed tests.""" _log.info('Gathering directory owners emails to CC.') changed_files = self.chromium_git.changed_files() extractor = DirectoryOwnersExtractor(self.host) return extractor.list_owners(changed_files)
class DirectoryOwnersExtractorTest(unittest.TestCase): def setUp(self): # We always have an OWNERS file at LayoutTests/external. self.filesystem = MockFileSystem( files={ '/mock-checkout/third_party/WebKit/LayoutTests/external/OWNERS': '*****@*****.**' }) self.extractor = DirectoryOwnersExtractor(self.filesystem) def _write_files(self, files): # Use write_text_file instead of directly assigning to filesystem.files # so that intermediary directories are correctly created, too. for path, contents in files.iteritems(): self.filesystem.write_text_file(path, contents) def test_list_owners_combines_same_owners(self): self._write_files({ ABS_WPT_BASE + '/foo/x.html': '', ABS_WPT_BASE + '/foo/OWNERS': '[email protected]\[email protected]\n', ABS_WPT_BASE + '/bar/x/y.html': '', ABS_WPT_BASE + '/bar/OWNERS': '[email protected]\[email protected]\n', }) changed_files = [ REL_WPT_BASE + '/foo/x.html', REL_WPT_BASE + '/bar/x/y.html', ] self.assertEqual( self.extractor.list_owners(changed_files), { ('*****@*****.**', '*****@*****.**'): ['external/wpt/bar', 'external/wpt/foo'] }) def test_list_owners_combines_same_directory(self): self._write_files({ ABS_WPT_BASE + '/baz/x/y.html': '', ABS_WPT_BASE + '/baz/x/y/z.html': '', ABS_WPT_BASE + '/baz/x/OWNERS': '[email protected]\n', }) changed_files = [ REL_WPT_BASE + '/baz/x/y.html', REL_WPT_BASE + '/baz/x/y/z.html', ] self.assertEqual(self.extractor.list_owners(changed_files), {('*****@*****.**', ): ['external/wpt/baz/x']}) def test_list_owners_skips_empty_owners(self): self._write_files({ ABS_WPT_BASE + '/baz/x/y/z.html': '', ABS_WPT_BASE + '/baz/x/y/OWNERS': '# Some comments\n', ABS_WPT_BASE + '/baz/x/OWNERS': '[email protected]\n', }) changed_files = [ REL_WPT_BASE + '/baz/x/y/z.html', ] self.assertEqual(self.extractor.list_owners(changed_files), {('*****@*****.**', ): ['external/wpt/baz/x']}) def test_list_owners_not_found(self): self._write_files({ # Although LayoutTests/external/OWNERS exists, it should not be listed. ABS_WPT_BASE + '/foo/bar.html': '', # Files out of external. '/mock-checkout/third_party/WebKit/LayoutTests/TestExpectations': '', '/mock-checkout/third_party/WebKit/LayoutTests/OWNERS': '*****@*****.**', }) changed_files = [ REL_WPT_BASE + '/foo/bar.html', 'third_party/WebKit/LayoutTests/TestExpectations', ] self.assertEqual(self.extractor.list_owners(changed_files), {}) def test_find_owners_file_at_current_dir(self): self._write_files({ABS_WPT_BASE + '/foo/OWNERS': '*****@*****.**'}) self.assertEqual( self.extractor.find_owners_file(REL_WPT_BASE + '/foo'), ABS_WPT_BASE + '/foo/OWNERS') def test_find_owners_file_at_ancestor(self): self._write_files({ ABS_WPT_BASE + '/x/OWNERS': '*****@*****.**', ABS_WPT_BASE + '/x/y/z.html': '', }) self.assertEqual( self.extractor.find_owners_file(REL_WPT_BASE + '/x/y'), ABS_WPT_BASE + '/x/OWNERS') def test_find_owners_file_stops_at_external_root(self): self._write_files({ ABS_WPT_BASE + '/x/y/z.html': '', }) self.assertEqual( self.extractor.find_owners_file(REL_WPT_BASE + '/x/y'), '/mock-checkout/third_party/WebKit/LayoutTests/external/OWNERS') def test_find_owners_file_takes_four_kinds_of_paths(self): owners_path = ABS_WPT_BASE + '/foo/OWNERS' self._write_files({ owners_path: '*****@*****.**', ABS_WPT_BASE + '/foo/bar.html': '', }) # Absolute paths of directories. self.assertEqual( self.extractor.find_owners_file(ABS_WPT_BASE + '/foo'), owners_path) # Relative paths of directories. self.assertEqual( self.extractor.find_owners_file(REL_WPT_BASE + '/foo'), owners_path) # Absolute paths of files. self.assertEqual( self.extractor.find_owners_file(ABS_WPT_BASE + '/foo/bar.html'), owners_path) # Relative paths of files. self.assertEqual( self.extractor.find_owners_file(REL_WPT_BASE + '/foo/bar.html'), owners_path) def test_find_owners_file_out_of_external(self): self._write_files({ '/mock-checkout/third_party/WebKit/LayoutTests/OWNERS': '*****@*****.**', '/mock-checkout/third_party/WebKit/LayoutTests/other/some_file': '', }) self.assertIsNone( self.extractor.find_owners_file('third_party/WebKit/LayoutTests')) self.assertIsNone( self.extractor.find_owners_file( 'third_party/WebKit/LayoutTests/other')) self.assertIsNone(self.extractor.find_owners_file('third_party')) def test_extract_owners(self): self.filesystem.files = { ABS_WPT_BASE + '/foo/OWNERS': '#This is a comment\n' '*\n' '[email protected]\n' '[email protected]\n' 'foobar\n' '#[email protected]\n' '# TEAM: [email protected]\n' '# COMPONENT: Blink>Layout\n' } self.assertEqual( self.extractor.extract_owners(ABS_WPT_BASE + '/foo/OWNERS'), ['*****@*****.**', '*****@*****.**']) def test_extract_component(self): self.filesystem.files = { ABS_WPT_BASE + '/foo/OWNERS': '# TEAM: [email protected]\n' '# COMPONENT: Blink>Layout\n' } self.assertEqual( self.extractor.extract_component(ABS_WPT_BASE + '/foo/OWNERS'), 'Blink>Layout') def test_is_wpt_notify_enabled_true(self): self.filesystem.files = { ABS_WPT_BASE + '/foo/OWNERS': '# COMPONENT: Blink>Layout\n' '# WPT-NOTIFY: true\n' } self.assertTrue( self.extractor.is_wpt_notify_enabled(ABS_WPT_BASE + '/foo/OWNERS')) def test_is_wpt_notify_enabled_false(self): self.filesystem.files = { ABS_WPT_BASE + '/foo/OWNERS': '# COMPONENT: Blink>Layout\n' '# WPT-NOTIFY: false\n' } self.assertFalse( self.extractor.is_wpt_notify_enabled(ABS_WPT_BASE + '/foo/OWNERS')) def test_is_wpt_notify_enabled_absence_is_false(self): self.filesystem.files = { ABS_WPT_BASE + '/foo/OWNERS': '# TEAM: [email protected]\n' '# COMPONENT: Blink>Layout\n' } self.assertFalse( self.extractor.is_wpt_notify_enabled(ABS_WPT_BASE + '/foo/OWNERS'))