Add unit tests to importer
+ small refactorings and 2 bug fixes Bug: v8:14002 Change-Id: I52fa159e84690d6e5d5340e8331e2766a15fa1a4 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5185494 Commit-Queue: Liviu Rau <liviurau@google.com> Reviewed-by: Michael Achenbach <machenbach@chromium.org> Cr-Commit-Position: refs/heads/main@{#91775}
This commit is contained in:
@ -96,3 +96,7 @@ wheel: <
|
||||
name: "infra/python/wheels/charset_normalizer-py3"
|
||||
version: "version:2.0.4"
|
||||
>
|
||||
wheel: <
|
||||
name: "infra/python/wheels/pyfakefs-py2_py3"
|
||||
version: "version:3.7.2"
|
||||
>
|
@ -39,9 +39,21 @@ def _CheckLint(input_api, output_api):
|
||||
]
|
||||
|
||||
|
||||
def _PyUnitTest(input_api, output_api):
|
||||
return input_api.RunTests(
|
||||
input_api.canned_checks.GetUnitTestsRecursively(
|
||||
input_api,
|
||||
output_api,
|
||||
input_api.os_path.join(input_api.PresubmitLocalPath()),
|
||||
files_to_check=[r'.+_test\.py$'],
|
||||
files_to_skip=[],
|
||||
run_on_python2=False,
|
||||
))
|
||||
|
||||
def _CommonChecks(input_api, output_api):
|
||||
checks = [
|
||||
_CheckLint,
|
||||
_PyUnitTest,
|
||||
]
|
||||
return sum([check(input_api, output_api) for check in checks], [])
|
||||
|
||||
|
59
test/test262/tools/mocks.py
Normal file
59
test/test262/tools/mocks.py
Normal file
@ -0,0 +1,59 @@
|
||||
# Copyright 2024 the V8 project authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
"""Contains empty mocks for all blinkpy dependencies. When importing this module
|
||||
all the necessary blinkpy imports are resolved to these mocks."""
|
||||
|
||||
import sys
|
||||
|
||||
sys.modules['blinkpy.w3c.local_wpt'] = __import__('mocks')
|
||||
|
||||
|
||||
class LocalRepo:
|
||||
pass
|
||||
|
||||
|
||||
sys.modules['blinkpy.w3c.wpt_github'] = __import__('mocks')
|
||||
|
||||
|
||||
class GitHubRepo:
|
||||
pass
|
||||
|
||||
|
||||
PROVISIONAL_PR_LABEL = 'provisional'
|
||||
|
||||
sys.modules['blinkpy.w3c.chromium_finder'] = __import__('mocks')
|
||||
|
||||
|
||||
def absolute_chromium_dir():
|
||||
pass
|
||||
|
||||
|
||||
sys.modules['blinkpy.w3c.chromium_configs'] = __import__('mocks')
|
||||
|
||||
|
||||
class ProjectConfig:
|
||||
pass
|
||||
|
||||
|
||||
sys.modules['blinkpy.common.system.log_utils'] = __import__('mocks')
|
||||
|
||||
|
||||
def configure_logging():
|
||||
pass
|
||||
|
||||
|
||||
sys.modules['blinkpy.w3c.common'] = __import__('mocks')
|
||||
|
||||
|
||||
def read_credentials():
|
||||
pass
|
||||
|
||||
|
||||
sys.modules['blinkpy.w3c.test_importer'] = __import__('mocks')
|
||||
|
||||
|
||||
class TestImporter:
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
pass
|
@ -16,6 +16,7 @@ from blinkpy.w3c.test_importer import TestImporter
|
||||
|
||||
TEST_FILE_REFERENCE_IN_STATUS_FILE = re.compile("^\s*'(.*)':.*,$")
|
||||
TEST262_FAILURE_LINE = re.compile("=== test262/(.*) ===")
|
||||
TEST262_PATTERN = re.compile('^test/(.*)\.js$')
|
||||
TEST262_REPO_URL = 'https://chromium.googlesource.com/external/github.com/tc39/test262'
|
||||
V8_TEST262_ROLLS_META_BUG = 'v8:7834'
|
||||
|
||||
@ -175,7 +176,8 @@ class V8TestImporter(TestImporter):
|
||||
return GitFileStatus(status_line[0][0])
|
||||
|
||||
def update_file(self, local_file, status, source_file):
|
||||
if status in GitFileStatus:
|
||||
gfs = GitFileStatus
|
||||
if status in [gfs.ADDED, gfs.DELETED, gfs.MODIFIED]:
|
||||
_log.info(f'{local_file} has counterpart in Test262. Deleting.')
|
||||
local_file.unlink()
|
||||
else:
|
||||
@ -217,7 +219,7 @@ class V8TestImporter(TestImporter):
|
||||
updated_status = self.remove_deleted_tests(v8_test262_revision,
|
||||
test262_revision)
|
||||
|
||||
added_lines = self.detected_fail_lines(failure_lines)
|
||||
added_lines = self.failed_tests_to_status_lines(failure_lines)
|
||||
if added_lines:
|
||||
updated_status = self.rewrite_status_file_content(updated_status,
|
||||
added_lines,
|
||||
@ -227,6 +229,7 @@ class V8TestImporter(TestImporter):
|
||||
w_file.writelines(updated_status)
|
||||
|
||||
def remove_deleted_tests(self, v8_test262_revision, test262_revision):
|
||||
# Remove deleted tests from the status file.
|
||||
_log.info(f'Remove deleted tests references from status file')
|
||||
updated_status = []
|
||||
deleted_tests = self.get_updated_tests(
|
||||
@ -236,15 +239,17 @@ class V8TestImporter(TestImporter):
|
||||
result = TEST_FILE_REFERENCE_IN_STATUS_FILE.match(line)
|
||||
if result and (result.group(1) in deleted_tests):
|
||||
_log.info(f'... removing {result.group(1)}')
|
||||
else:
|
||||
updated_status.append(line)
|
||||
continue
|
||||
updated_status.append(line)
|
||||
return updated_status
|
||||
|
||||
def detected_fail_lines(self, failure_lines):
|
||||
return [f" '{test}': [FAIL],\n" for test in failure_lines]
|
||||
def failed_tests_to_status_lines(self, failed_tests):
|
||||
# Transform the list of failed tests into a list of status file lines.
|
||||
return [f" '{test}': [FAIL],\n" for test in failed_tests]
|
||||
|
||||
def rewrite_status_file_content(self, updated_status, added_lines,
|
||||
v8_test262_revision, test262_revision):
|
||||
# Reassemble the status file with the new tests added.
|
||||
# TODO(liviurau): This is easy to unit test. Add unit tests.
|
||||
status_lines_before_eof = updated_status[:-2]
|
||||
eof_status_lines = updated_status[-2:]
|
||||
@ -252,7 +257,7 @@ class V8TestImporter(TestImporter):
|
||||
'\n', ']\n'
|
||||
], f'Unexpected status file eof. {eof_status_lines}'
|
||||
import_header_lines = [
|
||||
'\n####', f'# Import test262@{test262_revision[:8]}\n',
|
||||
'\n####\n', f'# Import test262@{test262_revision[:8]}\n',
|
||||
f'# {TEST262_REPO_URL}/+log/{v8_test262_revision[:8]}..{test262_revision[:8]}\n'
|
||||
]
|
||||
new_failing_tests_lines = ['[ALWAYS, {\n'] + added_lines + [
|
||||
@ -270,9 +275,9 @@ class V8TestImporter(TestImporter):
|
||||
v8_test262_revision, test262_revision, '--', 'test'
|
||||
]).splitlines()
|
||||
return [
|
||||
re.sub(r'^test/(.*)\.js$', r'\1', line)
|
||||
re.sub(TEST262_PATTERN, r'\1', line)
|
||||
for line in lines
|
||||
if line.strip()
|
||||
if line.strip() and TEST262_PATTERN.match(line)
|
||||
]
|
||||
|
||||
|
||||
|
165
test/test262/tools/v8_importer_test.py
Normal file
165
test/test262/tools/v8_importer_test.py
Normal file
@ -0,0 +1,165 @@
|
||||
# Copyright 2024 the V8 project 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 mocks
|
||||
import textwrap
|
||||
import unittest
|
||||
|
||||
from pyfakefs import fake_filesystem_unittest
|
||||
from v8_importer import V8TestImporter, GitFileStatus
|
||||
from v8configs import to_object
|
||||
|
||||
fake_host = to_object({
|
||||
'project_config': {
|
||||
'project_root':
|
||||
'.',
|
||||
'paths_to_sync': [{
|
||||
"source": "test/staging",
|
||||
"destination": "test/test262/local-tests/test/staging"
|
||||
}]
|
||||
},
|
||||
})
|
||||
V8_REVISION = 'abcdef123456'
|
||||
TEST262_REVISION = '123456abcdef'
|
||||
|
||||
class Test_TestV8Importer(fake_filesystem_unittest.TestCase):
|
||||
|
||||
def test_phases(self):
|
||||
importer = V8TestImporter('ALL', fake_host)
|
||||
self.assertTrue(importer.run_prebuild_phase())
|
||||
self.assertTrue(importer.run_build_phase())
|
||||
self.assertTrue(importer.run_postbuild_phase())
|
||||
self.assertTrue(importer.run_upload_phase())
|
||||
|
||||
importer = V8TestImporter('PREBUILD', fake_host)
|
||||
self.assertTrue(importer.run_prebuild_phase())
|
||||
self.assertFalse(importer.run_build_phase())
|
||||
self.assertFalse(importer.run_postbuild_phase())
|
||||
self.assertFalse(importer.run_upload_phase())
|
||||
|
||||
importer = V8TestImporter('POSTBUILD', fake_host)
|
||||
self.assertFalse(importer.run_prebuild_phase())
|
||||
self.assertFalse(importer.run_build_phase())
|
||||
self.assertTrue(importer.run_postbuild_phase())
|
||||
self.assertFalse(importer.run_upload_phase())
|
||||
|
||||
importer = V8TestImporter('UPLOAD', fake_host)
|
||||
self.assertFalse(importer.run_prebuild_phase())
|
||||
self.assertFalse(importer.run_build_phase())
|
||||
self.assertFalse(importer.run_postbuild_phase())
|
||||
self.assertTrue(importer.run_upload_phase())
|
||||
|
||||
def test_sync_folders(self):
|
||||
self.setUpPyfakefs(allow_root_user=True)
|
||||
|
||||
destination = 'test/test262/local-tests/test/staging'
|
||||
self.fs.create_file(f'{destination}/test1.js')
|
||||
self.fs.create_file(f'{destination}/features.txt')
|
||||
self.fs.create_file(f'{destination}/f1/test1.js')
|
||||
self.fs.create_file(f'{destination}/f1/test2.js')
|
||||
|
||||
def get_git_file_status(*args):
|
||||
path = str(args[2])
|
||||
self.assertFalse(path.endswith('features.txt'))
|
||||
return GitFileStatus.ADDED if path.endswith(
|
||||
'test1.js') else GitFileStatus.UNKNOWN
|
||||
|
||||
importer = V8TestImporter('X', fake_host)
|
||||
importer.local_test262 = to_object({
|
||||
'path': '.',
|
||||
})
|
||||
importer.get_git_file_status = get_git_file_status
|
||||
|
||||
importer.sync_folders(V8_REVISION, TEST262_REVISION)
|
||||
|
||||
self.assertFalse(self.fs.exists(f'{destination}/test1.js'))
|
||||
self.assertTrue(self.fs.exists(f'{destination}/features.txt'))
|
||||
self.assertFalse(self.fs.exists(f'{destination}/f1/test1.js'))
|
||||
self.assertTrue(self.fs.exists(f'{destination}/f1/test2.js'))
|
||||
|
||||
def test_remove_deleted_tests(self):
|
||||
self.setUpPyfakefs(allow_root_user=True)
|
||||
self.fs.create_file(
|
||||
'test/test262/test262.status',
|
||||
contents=textwrap.dedent("""\
|
||||
n'importe quoi
|
||||
...
|
||||
'folder1/sometest1': [FAIL],
|
||||
'deleted_testname': [FAIL],
|
||||
'folder2/sometest1': [FAIL],
|
||||
'folder2/sometest2': [FAIL],
|
||||
...
|
||||
"""))
|
||||
|
||||
importer = V8TestImporter('X', fake_host)
|
||||
importer.test262_git = to_object({
|
||||
'run': lambda *args: 'test/deleted_testname.js\n',
|
||||
})
|
||||
|
||||
tests = importer.remove_deleted_tests(V8_REVISION, TEST262_REVISION)
|
||||
|
||||
self.assertEquals(textwrap.dedent("""\
|
||||
n'importe quoi
|
||||
...
|
||||
'folder1/sometest1': [FAIL],
|
||||
'folder2/sometest1': [FAIL],
|
||||
'folder2/sometest2': [FAIL],
|
||||
...
|
||||
"""), ''.join(tests))
|
||||
|
||||
def test_failed_tests_to_status_lines(self):
|
||||
importer = V8TestImporter('X', fake_host)
|
||||
result = importer.failed_tests_to_status_lines(['test1', 'test2'])
|
||||
self.assertSequenceEqual([" 'test1': [FAIL],\n", " 'test2': [FAIL],\n"],
|
||||
result)
|
||||
|
||||
def test_rewrite_status_file_content(self):
|
||||
# Below \n is used inside the text block to avoid a trailing whitespace
|
||||
# check
|
||||
updated_status = textwrap.dedent("""\
|
||||
some_testname
|
||||
some random line
|
||||
some other testname\n
|
||||
]
|
||||
""")
|
||||
updated_status = updated_status.splitlines(keepends=True)
|
||||
added_lines = [' new test 1\n', ' new test 2\n']
|
||||
|
||||
importer = V8TestImporter('X', fake_host)
|
||||
result = importer.rewrite_status_file_content(updated_status, added_lines,
|
||||
V8_REVISION, TEST262_REVISION)
|
||||
|
||||
self.assertEquals(textwrap.dedent("""\
|
||||
some_testname
|
||||
some random line
|
||||
some other testname\n
|
||||
####
|
||||
# Import test262@123456ab
|
||||
# https://chromium.googlesource.com/external/github.com/tc39/test262/+log/abcdef12..123456ab
|
||||
[ALWAYS, {
|
||||
new test 1
|
||||
new test 2
|
||||
}],
|
||||
# End import test262@123456ab
|
||||
####\n
|
||||
]
|
||||
"""), ''.join(result))
|
||||
|
||||
def test_get_updated_tests(self):
|
||||
importer = V8TestImporter('X', fake_host)
|
||||
importer.test262_git = to_object({
|
||||
'run': lambda *args: textwrap.dedent("""\
|
||||
test/should_not_match.js extra garbage
|
||||
test/should_not_match2.js
|
||||
test/some_testname.js
|
||||
practically garbage
|
||||
"""),
|
||||
})
|
||||
|
||||
tests = importer.get_updated_tests('a', 'b')
|
||||
self.assertEquals(['some_testname'], tests)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -9,7 +9,6 @@ from functools import cached_property
|
||||
|
||||
from blinkpy.w3c.local_wpt import LocalRepo
|
||||
from blinkpy.w3c.wpt_github import GitHubRepo, PROVISIONAL_PR_LABEL
|
||||
from blinkpy.w3c.chromium_finder import absolute_chromium_dir
|
||||
from blinkpy.w3c.chromium_configs import ProjectConfig
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user