Skip to content

Commit 95b9f93

Browse files
Liviu RauV8 LUCI CQ
Liviu Rau
authored and
V8 LUCI CQ
committed
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 <[email protected]> Reviewed-by: Michael Achenbach <[email protected]> Cr-Commit-Position: refs/heads/main@{#91775}
1 parent 8561678 commit 95b9f93

File tree

6 files changed

+254
-10
lines changed

6 files changed

+254
-10
lines changed

.vpython3

+4
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,7 @@ wheel: <
9696
name: "infra/python/wheels/charset_normalizer-py3"
9797
version: "version:2.0.4"
9898
>
99+
wheel: <
100+
name: "infra/python/wheels/pyfakefs-py2_py3"
101+
version: "version:3.7.2"
102+
>

test/test262/PRESUBMIT.py

+12
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,21 @@ def _CheckLint(input_api, output_api):
3939
]
4040

4141

42+
def _PyUnitTest(input_api, output_api):
43+
return input_api.RunTests(
44+
input_api.canned_checks.GetUnitTestsRecursively(
45+
input_api,
46+
output_api,
47+
input_api.os_path.join(input_api.PresubmitLocalPath()),
48+
files_to_check=[r'.+_test\.py$'],
49+
files_to_skip=[],
50+
run_on_python2=False,
51+
))
52+
4253
def _CommonChecks(input_api, output_api):
4354
checks = [
4455
_CheckLint,
56+
_PyUnitTest,
4557
]
4658
return sum([check(input_api, output_api) for check in checks], [])
4759

test/test262/tools/mocks.py

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Copyright 2024 the V8 project authors. All rights reserved.
2+
# Use of this source code is governed by a BSD-style license that can be
3+
# found in the LICENSE file.
4+
"""Contains empty mocks for all blinkpy dependencies. When importing this module
5+
all the necessary blinkpy imports are resolved to these mocks."""
6+
7+
import sys
8+
9+
sys.modules['blinkpy.w3c.local_wpt'] = __import__('mocks')
10+
11+
12+
class LocalRepo:
13+
pass
14+
15+
16+
sys.modules['blinkpy.w3c.wpt_github'] = __import__('mocks')
17+
18+
19+
class GitHubRepo:
20+
pass
21+
22+
23+
PROVISIONAL_PR_LABEL = 'provisional'
24+
25+
sys.modules['blinkpy.w3c.chromium_finder'] = __import__('mocks')
26+
27+
28+
def absolute_chromium_dir():
29+
pass
30+
31+
32+
sys.modules['blinkpy.w3c.chromium_configs'] = __import__('mocks')
33+
34+
35+
class ProjectConfig:
36+
pass
37+
38+
39+
sys.modules['blinkpy.common.system.log_utils'] = __import__('mocks')
40+
41+
42+
def configure_logging():
43+
pass
44+
45+
46+
sys.modules['blinkpy.w3c.common'] = __import__('mocks')
47+
48+
49+
def read_credentials():
50+
pass
51+
52+
53+
sys.modules['blinkpy.w3c.test_importer'] = __import__('mocks')
54+
55+
56+
class TestImporter:
57+
58+
def __init__(self, *args, **kwargs):
59+
pass

test/test262/tools/v8_importer.py

+14-9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
TEST_FILE_REFERENCE_IN_STATUS_FILE = re.compile("^\s*'(.*)':.*,$")
1818
TEST262_FAILURE_LINE = re.compile("=== test262/(.*) ===")
19+
TEST262_PATTERN = re.compile('^test/(.*)\.js$')
1920
TEST262_REPO_URL = 'https://chromium.googlesource.com/external/github.com/tc39/test262'
2021
V8_TEST262_ROLLS_META_BUG = 'v8:7834'
2122

@@ -175,7 +176,8 @@ def get_git_file_status(self, v8_test262_revision, test262_revision,
175176
return GitFileStatus(status_line[0][0])
176177

177178
def update_file(self, local_file, status, source_file):
178-
if status in GitFileStatus:
179+
gfs = GitFileStatus
180+
if status in [gfs.ADDED, gfs.DELETED, gfs.MODIFIED]:
179181
_log.info(f'{local_file} has counterpart in Test262. Deleting.')
180182
local_file.unlink()
181183
else:
@@ -217,7 +219,7 @@ def update_status_file(self, v8_test262_revision, test262_revision,
217219
updated_status = self.remove_deleted_tests(v8_test262_revision,
218220
test262_revision)
219221

220-
added_lines = self.detected_fail_lines(failure_lines)
222+
added_lines = self.failed_tests_to_status_lines(failure_lines)
221223
if added_lines:
222224
updated_status = self.rewrite_status_file_content(updated_status,
223225
added_lines,
@@ -227,6 +229,7 @@ def update_status_file(self, v8_test262_revision, test262_revision,
227229
w_file.writelines(updated_status)
228230

229231
def remove_deleted_tests(self, v8_test262_revision, test262_revision):
232+
# Remove deleted tests from the status file.
230233
_log.info(f'Remove deleted tests references from status file')
231234
updated_status = []
232235
deleted_tests = self.get_updated_tests(
@@ -236,23 +239,25 @@ def remove_deleted_tests(self, v8_test262_revision, test262_revision):
236239
result = TEST_FILE_REFERENCE_IN_STATUS_FILE.match(line)
237240
if result and (result.group(1) in deleted_tests):
238241
_log.info(f'... removing {result.group(1)}')
239-
else:
240-
updated_status.append(line)
242+
continue
243+
updated_status.append(line)
241244
return updated_status
242245

243-
def detected_fail_lines(self, failure_lines):
244-
return [f" '{test}': [FAIL],\n" for test in failure_lines]
246+
def failed_tests_to_status_lines(self, failed_tests):
247+
# Transform the list of failed tests into a list of status file lines.
248+
return [f" '{test}': [FAIL],\n" for test in failed_tests]
245249

246250
def rewrite_status_file_content(self, updated_status, added_lines,
247251
v8_test262_revision, test262_revision):
252+
# Reassemble the status file with the new tests added.
248253
# TODO(liviurau): This is easy to unit test. Add unit tests.
249254
status_lines_before_eof = updated_status[:-2]
250255
eof_status_lines = updated_status[-2:]
251256
assert eof_status_lines == [
252257
'\n', ']\n'
253258
], f'Unexpected status file eof. {eof_status_lines}'
254259
import_header_lines = [
255-
'\n####', f'# Import test262@{test262_revision[:8]}\n',
260+
'\n####\n', f'# Import test262@{test262_revision[:8]}\n',
256261
f'# {TEST262_REPO_URL}/+log/{v8_test262_revision[:8]}..{test262_revision[:8]}\n'
257262
]
258263
new_failing_tests_lines = ['[ALWAYS, {\n'] + added_lines + [
@@ -270,9 +275,9 @@ def get_updated_tests(self,
270275
v8_test262_revision, test262_revision, '--', 'test'
271276
]).splitlines()
272277
return [
273-
re.sub(r'^test/(.*)\.js$', r'\1', line)
278+
re.sub(TEST262_PATTERN, r'\1', line)
274279
for line in lines
275-
if line.strip()
280+
if line.strip() and TEST262_PATTERN.match(line)
276281
]
277282

278283

+165
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
# Copyright 2024 the V8 project authors. All rights reserved.
2+
# Use of this source code is governed by a BSD-style license that can be
3+
# found in the LICENSE file.
4+
5+
import mocks
6+
import textwrap
7+
import unittest
8+
9+
from pyfakefs import fake_filesystem_unittest
10+
from v8_importer import V8TestImporter, GitFileStatus
11+
from v8configs import to_object
12+
13+
fake_host = to_object({
14+
'project_config': {
15+
'project_root':
16+
'.',
17+
'paths_to_sync': [{
18+
"source": "test/staging",
19+
"destination": "test/test262/local-tests/test/staging"
20+
}]
21+
},
22+
})
23+
V8_REVISION = 'abcdef123456'
24+
TEST262_REVISION = '123456abcdef'
25+
26+
class Test_TestV8Importer(fake_filesystem_unittest.TestCase):
27+
28+
def test_phases(self):
29+
importer = V8TestImporter('ALL', fake_host)
30+
self.assertTrue(importer.run_prebuild_phase())
31+
self.assertTrue(importer.run_build_phase())
32+
self.assertTrue(importer.run_postbuild_phase())
33+
self.assertTrue(importer.run_upload_phase())
34+
35+
importer = V8TestImporter('PREBUILD', fake_host)
36+
self.assertTrue(importer.run_prebuild_phase())
37+
self.assertFalse(importer.run_build_phase())
38+
self.assertFalse(importer.run_postbuild_phase())
39+
self.assertFalse(importer.run_upload_phase())
40+
41+
importer = V8TestImporter('POSTBUILD', fake_host)
42+
self.assertFalse(importer.run_prebuild_phase())
43+
self.assertFalse(importer.run_build_phase())
44+
self.assertTrue(importer.run_postbuild_phase())
45+
self.assertFalse(importer.run_upload_phase())
46+
47+
importer = V8TestImporter('UPLOAD', fake_host)
48+
self.assertFalse(importer.run_prebuild_phase())
49+
self.assertFalse(importer.run_build_phase())
50+
self.assertFalse(importer.run_postbuild_phase())
51+
self.assertTrue(importer.run_upload_phase())
52+
53+
def test_sync_folders(self):
54+
self.setUpPyfakefs(allow_root_user=True)
55+
56+
destination = 'test/test262/local-tests/test/staging'
57+
self.fs.create_file(f'{destination}/test1.js')
58+
self.fs.create_file(f'{destination}/features.txt')
59+
self.fs.create_file(f'{destination}/f1/test1.js')
60+
self.fs.create_file(f'{destination}/f1/test2.js')
61+
62+
def get_git_file_status(*args):
63+
path = str(args[2])
64+
self.assertFalse(path.endswith('features.txt'))
65+
return GitFileStatus.ADDED if path.endswith(
66+
'test1.js') else GitFileStatus.UNKNOWN
67+
68+
importer = V8TestImporter('X', fake_host)
69+
importer.local_test262 = to_object({
70+
'path': '.',
71+
})
72+
importer.get_git_file_status = get_git_file_status
73+
74+
importer.sync_folders(V8_REVISION, TEST262_REVISION)
75+
76+
self.assertFalse(self.fs.exists(f'{destination}/test1.js'))
77+
self.assertTrue(self.fs.exists(f'{destination}/features.txt'))
78+
self.assertFalse(self.fs.exists(f'{destination}/f1/test1.js'))
79+
self.assertTrue(self.fs.exists(f'{destination}/f1/test2.js'))
80+
81+
def test_remove_deleted_tests(self):
82+
self.setUpPyfakefs(allow_root_user=True)
83+
self.fs.create_file(
84+
'test/test262/test262.status',
85+
contents=textwrap.dedent("""\
86+
n'importe quoi
87+
...
88+
'folder1/sometest1': [FAIL],
89+
'deleted_testname': [FAIL],
90+
'folder2/sometest1': [FAIL],
91+
'folder2/sometest2': [FAIL],
92+
...
93+
"""))
94+
95+
importer = V8TestImporter('X', fake_host)
96+
importer.test262_git = to_object({
97+
'run': lambda *args: 'test/deleted_testname.js\n',
98+
})
99+
100+
tests = importer.remove_deleted_tests(V8_REVISION, TEST262_REVISION)
101+
102+
self.assertEquals(textwrap.dedent("""\
103+
n'importe quoi
104+
...
105+
'folder1/sometest1': [FAIL],
106+
'folder2/sometest1': [FAIL],
107+
'folder2/sometest2': [FAIL],
108+
...
109+
"""), ''.join(tests))
110+
111+
def test_failed_tests_to_status_lines(self):
112+
importer = V8TestImporter('X', fake_host)
113+
result = importer.failed_tests_to_status_lines(['test1', 'test2'])
114+
self.assertSequenceEqual([" 'test1': [FAIL],\n", " 'test2': [FAIL],\n"],
115+
result)
116+
117+
def test_rewrite_status_file_content(self):
118+
# Below \n is used inside the text block to avoid a trailing whitespace
119+
# check
120+
updated_status = textwrap.dedent("""\
121+
some_testname
122+
some random line
123+
some other testname\n
124+
]
125+
""")
126+
updated_status = updated_status.splitlines(keepends=True)
127+
added_lines = [' new test 1\n', ' new test 2\n']
128+
129+
importer = V8TestImporter('X', fake_host)
130+
result = importer.rewrite_status_file_content(updated_status, added_lines,
131+
V8_REVISION, TEST262_REVISION)
132+
133+
self.assertEquals(textwrap.dedent("""\
134+
some_testname
135+
some random line
136+
some other testname\n
137+
####
138+
# Import test262@123456ab
139+
# https://chromium.googlesource.com/external/github.com/tc39/test262/+log/abcdef12..123456ab
140+
[ALWAYS, {
141+
new test 1
142+
new test 2
143+
}],
144+
# End import test262@123456ab
145+
####\n
146+
]
147+
"""), ''.join(result))
148+
149+
def test_get_updated_tests(self):
150+
importer = V8TestImporter('X', fake_host)
151+
importer.test262_git = to_object({
152+
'run': lambda *args: textwrap.dedent("""\
153+
test/should_not_match.js extra garbage
154+
test/should_not_match2.js
155+
test/some_testname.js
156+
practically garbage
157+
"""),
158+
})
159+
160+
tests = importer.get_updated_tests('a', 'b')
161+
self.assertEquals(['some_testname'], tests)
162+
163+
164+
if __name__ == '__main__':
165+
unittest.main()

test/test262/tools/v8configs.py

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
from blinkpy.w3c.local_wpt import LocalRepo
1111
from blinkpy.w3c.wpt_github import GitHubRepo, PROVISIONAL_PR_LABEL
12-
from blinkpy.w3c.chromium_finder import absolute_chromium_dir
1312
from blinkpy.w3c.chromium_configs import ProjectConfig
1413

1514

0 commit comments

Comments
 (0)