chromium/third_party/blink/tools/blinkpy/w3c/directory_owners_extractor_unittest.py

# Copyright 2017 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import json
import unittest

from blinkpy.common.host_mock import MockHost
from blinkpy.common.path_finder import RELATIVE_WEB_TESTS
from blinkpy.common.system.executive_mock import MockExecutive
from blinkpy.common.system.filesystem_mock import MockFileSystem
from blinkpy.w3c.directory_owners_extractor import DirectoryOwnersExtractor

MOCK_WEB_TESTS = '/mock-checkout/' + RELATIVE_WEB_TESTS
MOCK_WEB_TESTS_WITHOUT_SLASH = MOCK_WEB_TESTS[:-1]
ABS_WPT_BASE = MOCK_WEB_TESTS + 'external/wpt'
REL_WPT_BASE = RELATIVE_WEB_TESTS + 'external/wpt'


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':
            b'[email protected]'
        })
        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.items():
            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), {
                ('[email protected]', '[email protected]'):
                ['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),
            {('[email protected]', ): ['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),
            {('[email protected]', ): ['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':
            '[email protected]',
        })
        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': '[email protected]'})
        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': '[email protected]',
            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: '[email protected]',
            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_web_test(self):
        self._write_files({
            '/mock-checkout/' + RELATIVE_WEB_TESTS + 'other/OWNERS':
            '',
            '/mock-checkout/' + RELATIVE_WEB_TESTS + 'OWNERS':
            '',
            '/not/in/chromium/src/OWNERS':
            '',
        })
        self.assertEqual(
            self.extractor.find_owners_file(RELATIVE_WEB_TESTS + 'other'),
            '/mock-checkout/' + RELATIVE_WEB_TESTS + 'other/OWNERS')
        self.assertIsNone(self.extractor.find_owners_file(RELATIVE_WEB_TESTS))
        self.assertIsNone(
            self.extractor.find_owners_file('/not/in/chromium/src'))

    def test_extract_owners(self):
        fs = self.host.filesystem
        fs.write_text_file(fs.join(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'),
            ['[email protected]', '[email protected]'])

    def test_is_wpt_notify_enabled(self):
        data = json.dumps({
            'dirs': {
                'third_party/blink/web_tests/a/b': {
                    'wpt': {
                        'notify': 'YES',
                    },
                },
            },
        })
        self.host.executive = MockExecutive(output=data)
        extractor = DirectoryOwnersExtractor(self.host)

        self.assertTrue(
            extractor.read_dir_metadata(MOCK_WEB_TESTS + 'a/b').should_notify)

    def test_is_wpt_notify_disabled(self):
        data = json.dumps({
            'dirs': {
                'third_party/blink/web_tests/a/b': {
                    'wpt': {
                        'notify': 'NO',
                    },
                },
            },
        })
        self.host.executive = MockExecutive(output=data)
        extractor = DirectoryOwnersExtractor(self.host)

        self.assertFalse(
            extractor.read_dir_metadata(MOCK_WEB_TESTS + 'a/b').should_notify)

    def test_is_wpt_notify_enabled_error(self):
        self.host.executive = MockExecutive(output='error')
        extractor = DirectoryOwnersExtractor(self.host)

        self.assertIsNone(extractor.read_dir_metadata(ABS_WPT_BASE + '/foo'))

    def test_extract_component(self):
        data = json.dumps({
            'dirs': {
                'third_party/blink/web_tests/a/b': {
                    'buganizerPublic': {
                        'componentId': '999',
                    },
                    'wpt': {
                        'notify': 'YES',
                    },
                },
            },
        })
        self.host.executive = MockExecutive(output=data)
        extractor = DirectoryOwnersExtractor(self.host)

        metadata = extractor.read_dir_metadata(MOCK_WEB_TESTS + 'a/b')
        self.assertEqual(metadata.buganizer_public_component, '999')

    def test_read_dir_metadata_success(self):
        data = json.dumps({
            'dirs': {
                'third_party/blink/web_tests/a/b': {
                    'buganizerPublic': {
                        'componentId': '999',
                    },
                    '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')

        self.assertEqual(self.host.executive.full_calls[0].args, [
            'dirmd', 'read', '-form', 'sparse', 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.buganizer_public_component, '999')

    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')

        self.assertEqual(self.host.executive.full_calls[0].args, [
            'dirmd', 'read', '-form', 'sparse', MOCK_WEB_TESTS + 'a/b'
        ])
        self.assertEqual(wpt_dir_metadata, None)

    def test_read_dir_empty_content(self):
        empty_data = '{"dirs":{"third_party/blink/web_tests/a/b":{}}}'
        self.host.executive = MockExecutive(output=empty_data)
        extractor = DirectoryOwnersExtractor(self.host)

        wpt_dir_metadata = extractor.read_dir_metadata(MOCK_WEB_TESTS + 'a/b')
        self.assertIsNone(wpt_dir_metadata.team_email)
        self.assertTrue(wpt_dir_metadata.should_notify)
        self.assertIsNone(wpt_dir_metadata.buganizer_public_component)

    def test_read_dir_empty_wpt(self):
        data = json.dumps({
            'dirs': {
                'third_party/blink/web_tests/a/b': {
                    'buganizerPublic': {
                        'componentId': '999',
                    },
                    'teamEmail': 'bar',
                },
            },
        })
        self.host.executive = MockExecutive(output=data)
        extractor = DirectoryOwnersExtractor(self.host)

        wpt_dir_metadata = extractor.read_dir_metadata(MOCK_WEB_TESTS + 'a/b')
        self.assertEqual(wpt_dir_metadata.team_email, 'bar')
        self.assertTrue(wpt_dir_metadata.should_notify)
        self.assertEqual(wpt_dir_metadata.buganizer_public_component, '999')