v8/v8
0

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:
Liviu Rau
2024-01-10 17:14:48 +01:00
committed by V8 LUCI CQ
parent 85616782bb
commit 95b9f93234
6 changed files with 254 additions and 10 deletions

@ -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], [])

@ -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)
]

@ -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