blob: 1eb532446a0d14d04e09015ad9396680091c26d5 [file] [log] [blame]
# -*- coding: utf-8 -*-
# Copyright 2017 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import unittest
from blinkpy.common.checkout.git_mock import MockGit
from blinkpy.common.host_mock import MockHost
from blinkpy.common.path_finder import RELATIVE_WEB_TESTS
from blinkpy.common.system.executive_mock import mock_git_commands
from blinkpy.common.system.filesystem_mock import MockFileSystem
from blinkpy.w3c.local_wpt_mock import MockLocalWPT
from blinkpy.w3c.import_notifier import ImportNotifier, TestFailure
from blinkpy.w3c.wpt_expectations_updater import WPTExpectationsUpdater
UMBRELLA_BUG = WPTExpectationsUpdater.UMBRELLA_BUG
MOCK_WEB_TESTS = '/mock-checkout/' + RELATIVE_WEB_TESTS
class ImportNotifierTest(unittest.TestCase):
def setUp(self):
self.host = MockHost()
# Mock a virtual test suite at virtual/gpu/external/wpt/foo.
self.host.filesystem = MockFileSystem({
MOCK_WEB_TESTS + 'VirtualTestSuites':
'[{"prefix": "gpu", "bases": ["external/wpt/foo"], "args": ["--foo"]}]'
})
self.git = self.host.git()
self.local_wpt = MockLocalWPT()
self.notifier = ImportNotifier(self.host, self.git, self.local_wpt)
def test_find_changed_baselines_of_tests(self):
changed_files = [
RELATIVE_WEB_TESTS + 'external/wpt/foo/bar.html',
RELATIVE_WEB_TESTS + 'external/wpt/foo/bar-expected.txt',
RELATIVE_WEB_TESTS +
'platform/linux/external/wpt/foo/bar-expected.txt',
RELATIVE_WEB_TESTS + 'external/wpt/random_stuff.html',
]
self.git.changed_files = lambda: changed_files
self.assertEqual(
self.notifier.find_changed_baselines_of_tests(
['external/wpt/foo/bar.html']),
{
'external/wpt/foo/bar.html': [
RELATIVE_WEB_TESTS + 'external/wpt/foo/bar-expected.txt',
RELATIVE_WEB_TESTS +
'platform/linux/external/wpt/foo/bar-expected.txt',
]
})
self.assertEqual(
self.notifier.find_changed_baselines_of_tests(set()), {})
def test_more_failures_in_baseline_more_fails(self):
# Replacing self.host.executive won't work here, because ImportNotifier
# has been instantiated with a MockGit backed by an empty MockExecutive.
executive = mock_git_commands({
'diff': ('diff --git a/foo-expected.txt b/foo-expected.txt\n'
'--- a/foo-expected.txt\n'
'+++ b/foo-expected.txt\n'
'-FAIL an old failure\n'
'+FAIL new failure 1\n'
'+FAIL new failure 2\n')
})
self.notifier.git = MockGit(executive=executive)
self.assertTrue(
self.notifier.more_failures_in_baseline('foo-expected.txt'))
self.assertEqual(
executive.calls,
[['git', 'diff', '-U0', 'origin/master', '--', 'foo-expected.txt']
])
def test_more_failures_in_baseline_fewer_fails(self):
executive = mock_git_commands({
'diff': ('diff --git a/foo-expected.txt b/foo-expected.txt\n'
'--- a/foo-expected.txt\n'
'+++ b/foo-expected.txt\n'
'-FAIL an old failure\n'
'-FAIL new failure 1\n'
'+FAIL new failure 2\n')
})
self.notifier.git = MockGit(executive=executive)
self.assertFalse(
self.notifier.more_failures_in_baseline('foo-expected.txt'))
def test_more_failures_in_baseline_same_fails(self):
executive = mock_git_commands({
'diff': ('diff --git a/foo-expected.txt b/foo-expected.txt\n'
'--- a/foo-expected.txt\n'
'+++ b/foo-expected.txt\n'
'-FAIL an old failure\n'
'+FAIL a new failure\n')
})
self.notifier.git = MockGit(executive=executive)
self.assertFalse(
self.notifier.more_failures_in_baseline('foo-expected.txt'))
def test_more_failures_in_baseline_new_error(self):
executive = mock_git_commands({
'diff': ('diff --git a/foo-expected.txt b/foo-expected.txt\n'
'--- a/foo-expected.txt\n'
'+++ b/foo-expected.txt\n'
'-PASS an existing pass\n'
'+Harness Error. harness_status.status = 1 , harness_status.message = bad\n')
})
self.notifier.git = MockGit(executive=executive)
self.assertTrue(
self.notifier.more_failures_in_baseline('foo-expected.txt'))
def test_more_failures_in_baseline_remove_error(self):
executive = mock_git_commands({
'diff': ('diff --git a/foo-expected.txt b/foo-expected.txt\n'
'--- a/foo-expected.txt\n'
'+++ b/foo-expected.txt\n'
'-Harness Error. harness_status.status = 1 , harness_status.message = bad\n'
'+PASS a new pass\n')
})
self.notifier.git = MockGit(executive=executive)
self.assertFalse(
self.notifier.more_failures_in_baseline('foo-expected.txt'))
def test_more_failures_in_baseline_changing_error(self):
executive = mock_git_commands({
'diff': ('diff --git a/foo-expected.txt b/foo-expected.txt\n'
'--- a/foo-expected.txt\n'
'+++ b/foo-expected.txt\n'
'-Harness Error. harness_status.status = 1 , harness_status.message = bad\n'
'+Harness Error. new text, still an error\n')
})
self.notifier.git = MockGit(executive=executive)
self.assertFalse(
self.notifier.more_failures_in_baseline('foo-expected.txt'))
def test_more_failures_in_baseline_fail_to_error(self):
executive = mock_git_commands({
'diff': ('diff --git a/foo-expected.txt b/foo-expected.txt\n'
'--- a/foo-expected.txt\n'
'+++ b/foo-expected.txt\n'
'-FAIL a previous failure\n'
'+Harness Error. harness_status.status = 1 , harness_status.message = bad\n')
})
self.notifier.git = MockGit(executive=executive)
self.assertTrue(
self.notifier.more_failures_in_baseline('foo-expected.txt'))
def test_more_failures_in_baseline_error_to_fail(self):
executive = mock_git_commands({
'diff': ('diff --git a/foo-expected.txt b/foo-expected.txt\n'
'--- a/foo-expected.txt\n'
'+++ b/foo-expected.txt\n'
'-Harness Error. harness_status.status = 1 , harness_status.message = bad\n'
'+FAIL a new failure\n')
})
self.notifier.git = MockGit(executive=executive)
self.assertTrue(
self.notifier.more_failures_in_baseline('foo-expected.txt'))
def test_examine_baseline_changes(self):
self.host.filesystem.write_text_file(
MOCK_WEB_TESTS + 'external/wpt/foo/OWNERS', 'test@chromium.org')
changed_test_baselines = {
'external/wpt/foo/bar.html': [
RELATIVE_WEB_TESTS + 'external/wpt/foo/bar-expected.txt',
RELATIVE_WEB_TESTS +
'platform/linux/external/wpt/foo/bar-expected.txt',
]
}
gerrit_url_with_ps = 'https://crrev.com/c/12345/3/'
self.notifier.more_failures_in_baseline = lambda _: True
self.notifier.examine_baseline_changes(changed_test_baselines,
gerrit_url_with_ps)
self.assertEqual(
self.notifier.new_failures_by_directory, {
'external/wpt/foo': [
TestFailure(
TestFailure.BASELINE_CHANGE,
'external/wpt/foo/bar.html',
baseline_path=RELATIVE_WEB_TESTS +
'external/wpt/foo/bar-expected.txt',
gerrit_url_with_ps=gerrit_url_with_ps),
TestFailure(
TestFailure.BASELINE_CHANGE,
'external/wpt/foo/bar.html',
baseline_path=RELATIVE_WEB_TESTS +
'platform/linux/external/wpt/foo/bar-expected.txt',
gerrit_url_with_ps=gerrit_url_with_ps),
]
})
def test_examine_new_test_expectations(self):
self.host.filesystem.write_text_file(
MOCK_WEB_TESTS + 'external/wpt/foo/OWNERS', 'test@chromium.org')
test_expectations = {
'external/wpt/foo/bar.html': [
'crbug.com/12345 [ Linux ] external/wpt/foo/bar.html [ Fail ]',
'crbug.com/12345 [ Win ] external/wpt/foo/bar.html [ Timeout ]',
]
}
self.notifier.examine_new_test_expectations(test_expectations)
self.assertEqual(
self.notifier.new_failures_by_directory, {
'external/wpt/foo': [
TestFailure(
TestFailure.NEW_EXPECTATION,
'external/wpt/foo/bar.html',
expectation_line=
'crbug.com/12345 [ Linux ] external/wpt/foo/bar.html [ Fail ]'
),
TestFailure(
TestFailure.NEW_EXPECTATION,
'external/wpt/foo/bar.html',
expectation_line=
'crbug.com/12345 [ Win ] external/wpt/foo/bar.html [ Timeout ]'
),
]
})
self.notifier.new_failures_by_directory = {}
self.notifier.examine_new_test_expectations({})
self.assertEqual(self.notifier.new_failures_by_directory, {})
def test_format_commit_list(self):
imported_commits = [
('SHA1', 'Subject 1'),
# Use non-ASCII chars to really test Unicode handling.
('SHA2', u'ABC~‾¥≈¤・・•∙·☼★星🌟星★☼·∙•・・¤≈¥‾~XYZ')
]
def _is_commit_affecting_directory(commit, directory):
self.assertIn(commit, ('SHA1', 'SHA2'))
self.assertEqual(directory, 'foo')
return commit == 'SHA1'
self.local_wpt.is_commit_affecting_directory = _is_commit_affecting_directory
self.assertEqual(
self.notifier.format_commit_list(
imported_commits, MOCK_WEB_TESTS + 'external/wpt/foo'),
u'Subject 1: https://github.com/web-platform-tests/wpt/commit/SHA1 [affecting this directory]\n'
u'ABC~‾¥≈¤・・•∙·☼★星🌟星★☼·∙•・・¤≈¥‾~XYZ: https://github.com/web-platform-tests/wpt/commit/SHA2\n'
)
def test_find_owned_directory_non_virtual(self):
self.host.filesystem.write_text_file(
MOCK_WEB_TESTS + 'external/wpt/foo/OWNERS', 'test@chromium.org')
self.assertEqual(
self.notifier.find_owned_directory('external/wpt/foo/bar.html'),
'external/wpt/foo')
self.assertEqual(
self.notifier.find_owned_directory(
'external/wpt/foo/bar/baz.html'), 'external/wpt/foo')
def test_find_owned_directory_virtual(self):
self.host.filesystem.write_text_file(
MOCK_WEB_TESTS + 'external/wpt/foo/OWNERS', 'test@chromium.org')
self.assertEqual(
self.notifier.find_owned_directory(
'virtual/gpu/external/wpt/foo/bar.html'), 'external/wpt/foo')
def test_create_bugs_from_new_failures(self):
self.host.filesystem.write_text_file(
MOCK_WEB_TESTS + 'external/wpt/foo/OWNERS',
'# COMPONENT: Blink>Infra>Ecosystem\n'
'# WPT-NOTIFY: true\n'
'foolip@chromium.org\n')
self.host.filesystem.write_text_file(
MOCK_WEB_TESTS + 'external/wpt/bar/OWNERS', 'test@chromium.org')
self.notifier.new_failures_by_directory = {
'external/wpt/foo': [
TestFailure(
TestFailure.NEW_EXPECTATION,
'external/wpt/foo/baz.html',
expectation_line=
'crbug.com/12345 external/wpt/foo/baz.html [ Fail ]')
],
'external/wpt/bar': [
TestFailure(
TestFailure.NEW_EXPECTATION,
'external/wpt/bar/baz.html',
expectation_line=
'crbug.com/12345 external/wpt/bar/baz.html [ Fail ]')
]
}
bugs = self.notifier.create_bugs_from_new_failures(
'SHA_START', 'SHA_END', 'https://crrev.com/c/12345')
# Only one directory has WPT-NOTIFY enabled.
self.assertEqual(len(bugs), 1)
# The formatting of imported commits and new failures are already tested.
self.assertEqual(bugs[0].body['cc'], ['foolip@chromium.org'])
self.assertEqual(bugs[0].body['components'], ['Blink>Infra>Ecosystem'])
self.assertEqual(
bugs[0].body['summary'],
'[WPT] New failures introduced in external/wpt/foo by import https://crrev.com/c/12345'
)
def test_no_bugs_filed_in_dry_run(self):
def unreachable(_):
self.fail('MonorailAPI should not be instantiated in dry_run.')
self.notifier._get_monorail_api = unreachable # pylint: disable=protected-access
self.notifier.file_bugs([], True)
def test_file_bugs_calls_luci_auth(self):
test = self
class FakeAPI(object):
def __init__(self,
service_account_key_json=None,
access_token=None):
test.assertIsNone(service_account_key_json)
test.assertEqual(access_token, 'MOCK output of child process')
self.notifier._monorail_api = FakeAPI # pylint: disable=protected-access
self.notifier.file_bugs([], False)
self.assertEqual(self.host.executive.calls, [['luci-auth', 'token']])
class TestFailureTest(unittest.TestCase):
def test_test_failure_to_str_baseline_change(self):
failure = TestFailure(
TestFailure.BASELINE_CHANGE,
'external/wpt/foo/bar.html',
baseline_path=RELATIVE_WEB_TESTS +
'external/wpt/foo/bar-expected.txt',
gerrit_url_with_ps='https://crrev.com/c/12345/3/')
self.assertEqual(
str(failure),
'external/wpt/foo/bar.html new failing tests: https://crrev.com/c/12345/3/'
+ RELATIVE_WEB_TESTS + 'external/wpt/foo/bar-expected.txt')
platform_failure = TestFailure(
TestFailure.BASELINE_CHANGE,
'external/wpt/foo/bar.html',
baseline_path=RELATIVE_WEB_TESTS +
'platform/linux/external/wpt/foo/bar-expected.txt',
gerrit_url_with_ps='https://crrev.com/c/12345/3/')
self.assertEqual(
str(platform_failure),
'[ Linux ] external/wpt/foo/bar.html new failing tests: https://crrev.com/c/12345/3/'
+ RELATIVE_WEB_TESTS +
'platform/linux/external/wpt/foo/bar-expected.txt')
def test_test_failure_to_str_new_expectation(self):
failure = TestFailure(
TestFailure.NEW_EXPECTATION,
'external/wpt/foo/bar.html',
expectation_line=
'crbug.com/12345 [ Linux ] external/wpt/foo/bar.html [ Fail ]')
self.assertEqual(
str(failure),
'crbug.com/12345 [ Linux ] external/wpt/foo/bar.html [ Fail ]')
failure_with_umbrella_bug = TestFailure(
TestFailure.NEW_EXPECTATION,
'external/wpt/foo/bar.html',
expectation_line=UMBRELLA_BUG +
' external/wpt/foo/bar.html [ Fail ]')
self.assertEqual(
str(failure_with_umbrella_bug),
'external/wpt/foo/bar.html [ Fail ]')