Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
run_tests.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2#
3# Copyright 2013 The Flutter Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7"""
8A top level harness to run all unit-tests in a specific engine build.
9"""
10
11from pathlib import Path
12
13import argparse
14import errno
15import glob
16import logging
17import logging.handlers
18import multiprocessing
19import os
20import re
21import shutil
22import subprocess
23# Explicitly import the parts of sys that are needed. This is to avoid using
24# sys.stdout and sys.stderr directly. Instead, only the logger defined below
25# should be used for output.
26from sys import exit as sys_exit, platform as sys_platform
27import tempfile
28import time
29import typing
30import xvfb
31
32SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
33BUILDROOT_DIR = os.path.abspath(os.path.join(os.path.realpath(__file__), '..', '..', '..'))
34OUT_DIR = os.path.join(BUILDROOT_DIR, 'out')
35GOLDEN_DIR = os.path.join(BUILDROOT_DIR, 'flutter', 'testing', 'resources')
36FONTS_DIR = os.path.join(BUILDROOT_DIR, 'flutter', 'third_party', 'txt', 'third_party', 'fonts')
37ROBOTO_FONT_PATH = os.path.join(FONTS_DIR, 'Roboto-Regular.ttf')
38FONT_SUBSET_DIR = os.path.join(BUILDROOT_DIR, 'flutter', 'tools', 'font_subset')
39
40ENCODING = 'UTF-8'
41
42LOG_FILE = os.path.join(OUT_DIR, 'run_tests.log')
43logger = logging.getLogger(__name__)
44console_logger_handler = logging.StreamHandler()
45file_logger_handler = logging.FileHandler(LOG_FILE)
46
47
48# Override print so that it uses the logger instead of stdout directly.
49def print(*args, **kwargs): # pylint: disable=redefined-builtin
50 logger.info(*args, **kwargs)
51
52
53def print_divider(char='='):
54 logger.info('\n')
55 for _ in range(4):
56 logger.info(''.join([char for _ in range(80)]))
57 logger.info('\n')
58
59
60def is_asan(build_dir):
61 with open(os.path.join(build_dir, 'args.gn')) as args:
62 if 'is_asan = true' in args.read():
63 return True
64
65 return False
66
67
69 cmd: typing.List[str],
70 forbidden_output: typing.List[str] = None,
71 expect_failure: bool = False,
72 env: typing.Dict[str, str] = None,
73 allowed_failure_output: typing.List[str] = None,
74 **kwargs
75) -> None:
76 if forbidden_output is None:
77 forbidden_output = []
78 if allowed_failure_output is None:
79 allowed_failure_output = []
80
81 command_string = ' '.join(cmd)
82
83 print_divider('>')
84 logger.info('Running command "%s"', command_string)
85
86 start_time = time.time()
87
88 process = subprocess.Popen(
89 cmd,
90 stdout=subprocess.PIPE,
91 stderr=subprocess.STDOUT,
92 env=env,
93 universal_newlines=True,
94 **kwargs
95 )
96 output = ''
97
98 for line in iter(process.stdout.readline, ''):
99 output += line
100 logger.info(line.rstrip())
101
102 process.wait()
103 end_time = time.time()
104
105 if process.returncode != 0 and not expect_failure:
106 print_divider('!')
107
108 logger.error(
109 'Failed Command:\n\n%s\n\nExit Code: %s\n\nOutput:\n%s', command_string, process.returncode,
110 output
111 )
112
113 print_divider('!')
114
115 allowed_failure = False
116 for allowed_string in allowed_failure_output:
117 if allowed_string in output:
118 allowed_failure = True
119
120 if not allowed_failure:
121 raise RuntimeError('Command "%s" exited with code %s.' % (command_string, process.returncode))
122
123 for forbidden_string in forbidden_output:
124 if forbidden_string in output:
125 raise RuntimeError(
126 'command "%s" contained forbidden string "%s"' % (command_string, forbidden_string)
127 )
128
129 print_divider('<')
130 logger.info('Command run successfully in %.2f seconds: %s', end_time - start_time, command_string)
131
132
133def is_mac():
134 return sys_platform == 'darwin'
135
136
138 assert is_mac()
139 output = subprocess.check_output(['sysctl', 'machdep.cpu'])
140 text = output.decode('utf-8')
141 aarm64 = text.find('Apple') >= 0
142 if not aarm64:
143 assert text.find('GenuineIntel') >= 0
144 return aarm64
145
146
148 return sys_platform.startswith('linux')
149
150
152 return sys_platform.startswith(('cygwin', 'win'))
153
154
156 return '.exe' if is_windows() else ''
157
158
160 if os.path.exists(path):
161 return path
162
163 if is_windows():
164 exe_path = path + '.exe'
165 if os.path.exists(exe_path):
166 return exe_path
167
168 bat_path = path + '.bat'
169 if os.path.exists(bat_path):
170 return bat_path
171
172 raise Exception('Executable %s does not exist!' % path)
173
174
176 extra_env = {
177 # pylint: disable=line-too-long
178 # Note: built from //third_party/swiftshader
179 'VK_ICD_FILENAMES': os.path.join(build_dir, 'vk_swiftshader_icd.json'),
180 # Note: built from //third_party/vulkan_validation_layers:vulkan_gen_json_files
181 # and //third_party/vulkan_validation_layers.
182 'VK_LAYER_PATH': os.path.join(build_dir, 'vulkan-data'),
183 'VK_INSTANCE_LAYERS': 'VK_LAYER_KHRONOS_validation',
184 }
185 return extra_env
186
187
189 extra_env = {
190 # pylint: disable=line-too-long
191 # See https://developer.apple.com/documentation/metal/diagnosing_metal_programming_issues_early?language=objc
192 'MTL_SHADER_VALIDATION': '1', # Enables all shader validation tests.
193 'MTL_SHADER_VALIDATION_GLOBAL_MEMORY':
194 '1', # Validates accesses to device and constant memory.
195 'MTL_SHADER_VALIDATION_THREADGROUP_MEMORY': '1', # Validates accesses to threadgroup memory.
196 'MTL_SHADER_VALIDATION_TEXTURE_USAGE': '1', # Validates that texture references are not nil.
197 }
198 if is_aarm64():
199 extra_env.update({
200 'METAL_DEBUG_ERROR_MODE': '0', # Enables metal validation.
201 'METAL_DEVICE_WRAPPER_TYPE': '1', # Enables metal validation.
202 })
203 return extra_env
204
205
207 build_dir, executable_name, flags=None, coverage=False, gtest=False
208):
209 if flags is None:
210 flags = []
211
212 unstripped_exe = os.path.join(build_dir, 'exe.unstripped', executable_name)
213 # We cannot run the unstripped binaries directly when coverage is enabled.
214 if is_linux() and os.path.exists(unstripped_exe) and not coverage:
215 # Use unstripped executables in order to get better symbolized crash
216 # stack traces on Linux.
217 executable = unstripped_exe
218 else:
219 executable = find_executable_path(os.path.join(build_dir, executable_name))
220
221 coverage_script = os.path.join(BUILDROOT_DIR, 'flutter', 'build', 'generate_coverage.py')
222
223 if coverage:
224 coverage_flags = [
225 '-t', executable, '-o',
226 os.path.join(build_dir, 'coverage', executable_name), '-f', 'html'
227 ]
228 updated_flags = ['--args=%s' % ' '.join(flags)]
229 test_command = [coverage_script] + coverage_flags + updated_flags
230 else:
231 test_command = [executable] + flags
232 if gtest:
233 gtest_parallel = os.path.join(
234 BUILDROOT_DIR, 'flutter', 'third_party', 'gtest-parallel', 'gtest-parallel'
235 )
236 test_command = ['python3', gtest_parallel] + test_command
237
238 return test_command
239
240
241def run_engine_executable( # pylint: disable=too-many-arguments
242 build_dir,
243 executable_name,
244 executable_filter,
245 flags=None,
246 cwd=BUILDROOT_DIR,
247 forbidden_output=None,
248 allowed_failure_output=None,
249 expect_failure=False,
250 coverage=False,
251 extra_env=None,
252 gtest=False,
253):
254 if executable_filter is not None and executable_name not in executable_filter:
255 logger.info('Skipping %s due to filter.', executable_name)
256 return
257
258 if flags is None:
259 flags = []
260 if forbidden_output is None:
261 forbidden_output = []
262 if allowed_failure_output is None:
263 allowed_failure_output = []
264 if extra_env is None:
265 extra_env = {}
266
267 unstripped_exe = os.path.join(build_dir, 'exe.unstripped', executable_name)
268 env = os.environ.copy()
269 if is_linux():
270 env['LD_LIBRARY_PATH'] = build_dir
271 env['VK_DRIVER_FILES'] = os.path.join(build_dir, 'vk_swiftshader_icd.json')
272 if os.path.exists(unstripped_exe):
273 unstripped_vulkan = os.path.join(build_dir, 'lib.unstripped', 'libvulkan.so.1')
274 if os.path.exists(unstripped_vulkan):
275 vulkan_path = unstripped_vulkan
276 else:
277 vulkan_path = os.path.join(build_dir, 'libvulkan.so.1')
278 try:
279 os.symlink(vulkan_path, os.path.join(build_dir, 'exe.unstripped', 'libvulkan.so.1'))
280 except OSError as err:
281 if err.errno == errno.EEXIST:
282 pass
283 else:
284 raise
285 elif is_mac():
286 env['DYLD_LIBRARY_PATH'] = build_dir
287 else:
288 env['PATH'] = build_dir + ':' + env['PATH']
289
290 logger.info('Running %s in %s', executable_name, cwd)
291
292 test_command = build_engine_executable_command(
293 build_dir,
294 executable_name,
295 flags=flags,
296 coverage=coverage,
297 gtest=gtest,
298 )
299
300 env['FLUTTER_BUILD_DIRECTORY'] = build_dir
301 for key, value in extra_env.items():
302 env[key] = value
303
304 try:
305 run_cmd(
306 test_command,
307 cwd=cwd,
308 forbidden_output=forbidden_output,
309 expect_failure=expect_failure,
310 env=env,
311 allowed_failure_output=allowed_failure_output,
312 )
313 except:
314 # The LUCI environment may provide a variable containing a directory path
315 # for additional output files that will be uploaded to cloud storage.
316 # If the command generated a core dump, then run a script to analyze
317 # the dump and output a report that will be uploaded.
318 luci_test_outputs_path = os.environ.get('FLUTTER_TEST_OUTPUTS_DIR')
319 core_path = os.path.join(cwd, 'core')
320 if luci_test_outputs_path and os.path.exists(core_path) and os.path.exists(unstripped_exe):
321 dump_path = os.path.join(
322 luci_test_outputs_path, '%s_%s.txt' % (executable_name, sys_platform)
323 )
324 logger.error('Writing core dump analysis to %s', dump_path)
325 subprocess.call([
326 os.path.join(BUILDROOT_DIR, 'flutter', 'testing', 'analyze_core_dump.sh'),
327 BUILDROOT_DIR,
328 unstripped_exe,
329 core_path,
330 dump_path,
331 ])
332 os.unlink(core_path)
333 raise
334
335
336class EngineExecutableTask(): # pylint: disable=too-many-instance-attributes
337
338 def __init__( # pylint: disable=too-many-arguments
339 self,
340 build_dir,
341 executable_name,
342 executable_filter,
343 flags=None,
344 cwd=BUILDROOT_DIR,
345 forbidden_output=None,
346 allowed_failure_output=None,
347 expect_failure=False,
348 coverage=False,
349 extra_env=None,
350 ):
351 self.build_dir = build_dir
352 self.executable_name = executable_name
353 self.executable_filter = executable_filter
354 self.flags = flags
355 self.cwd = cwd
356 self.forbidden_output = forbidden_output
357 self.allowed_failure_output = allowed_failure_output
358 self.expect_failure = expect_failure
359 self.coverage = coverage
360 self.extra_env = extra_env
361
362 def __call__(self, *args):
364 self.build_dir,
365 self.executable_name,
367 flags=self.flags,
368 cwd=self.cwd,
369 forbidden_output=self.forbidden_output,
370 allowed_failure_output=self.allowed_failure_output,
371 expect_failure=self.expect_failure,
372 coverage=self.coverage,
373 extra_env=self.extra_env,
374 )
375
376 def __str__(self):
378 self.build_dir, self.executable_name, flags=self.flags, coverage=self.coverage
379 )
380 return ' '.join(command)
381
382
383shuffle_flags = [
384 '--gtest_repeat=2',
385 '--gtest_shuffle',
386]
387
388repeat_flags = [
389 '--repeat=2',
390]
391
392
393def run_cc_tests(build_dir, executable_filter, coverage, capture_core_dump):
394 logger.info('Running Engine Unit-tests.')
395
396 if capture_core_dump and is_linux():
397 import resource # pylint: disable=import-outside-toplevel
398 resource.setrlimit(resource.RLIMIT_CORE, (resource.RLIM_INFINITY, resource.RLIM_INFINITY))
399
400 def make_test(name, flags=None, extra_env=None):
401 if flags is None:
402 flags = repeat_flags
403 if extra_env is None:
404 extra_env = {}
405 return (name, flags, extra_env)
406
407 unittests = [
408 make_test('client_wrapper_glfw_unittests'),
409 make_test('client_wrapper_unittests'),
410 make_test('common_cpp_core_unittests'),
411 make_test('common_cpp_unittests'),
412 make_test('dart_plugin_registrant_unittests'),
413 make_test('display_list_rendertests'),
414 make_test('display_list_unittests'),
415 make_test('embedder_a11y_unittests'),
416 make_test('embedder_proctable_unittests'),
417 make_test('embedder_unittests'),
418 make_test('fml_unittests'),
419 make_test('fml_arc_unittests'),
420 make_test('no_dart_plugin_registrant_unittests'),
421 make_test('runtime_unittests'),
422 make_test('testing_unittests'),
423 make_test('tonic_unittests'),
424 # The image release unit test can take a while on slow machines.
425 make_test('ui_unittests', flags=repeat_flags + ['--timeout=90']),
426 ]
427
428 if not is_windows():
429 unittests += [
430 # https://github.com/google/googletest/issues/2490
431 make_test('android_external_view_embedder_unittests'),
432 make_test('jni_unittests'),
433 make_test('platform_view_android_delegate_unittests'),
434 # https://github.com/flutter/flutter/issues/36295
435 make_test('shell_unittests'),
436 ]
437
438 if is_windows():
439 unittests += [
440 # The accessibility library only supports Mac and Windows.
441 make_test('accessibility_unittests'),
442 make_test('client_wrapper_windows_unittests'),
443 make_test('flutter_windows_unittests'),
444 ]
445
446 # These unit-tests are Objective-C and can only run on Darwin.
447 if is_mac():
448 unittests += [
449 # The accessibility library only supports Mac and Windows.
450 make_test('accessibility_unittests'),
451 make_test('availability_version_check_unittests'),
452 make_test('framework_common_unittests'),
453 make_test('spring_animation_unittests'),
454 make_test('gpu_surface_metal_unittests'),
455 ]
456
457 if is_linux():
458 flow_flags = [
459 '--golden-dir=%s' % GOLDEN_DIR,
460 '--font-file=%s' % ROBOTO_FONT_PATH,
461 ]
462 icu_flags = ['--icu-data-file-path=%s' % os.path.join(build_dir, 'icudtl.dat')]
463 unittests += [
464 make_test('flow_unittests', flags=repeat_flags + ['--'] + flow_flags),
465 make_test('flutter_glfw_unittests'),
466 make_test('flutter_linux_unittests', extra_env={'G_DEBUG': 'fatal-criticals'}),
467 # https://github.com/flutter/flutter/issues/36296
468 make_test('txt_unittests', flags=repeat_flags + ['--'] + icu_flags),
469 ]
470 else:
471 flow_flags = ['--gtest_filter=-PerformanceOverlayLayer.Gold']
472 unittests += [
473 make_test('flow_unittests', flags=repeat_flags + flow_flags),
474 ]
475
476 build_name = os.path.basename(build_dir)
477 try:
478 if is_linux():
479 xvfb.start_virtual_x(build_name, build_dir)
480 for test, flags, extra_env in unittests:
482 build_dir,
483 test,
484 executable_filter,
485 flags,
486 coverage=coverage,
487 extra_env=extra_env,
488 gtest=True
489 )
490 finally:
491 if is_linux():
492 xvfb.stop_virtual_x(build_name)
493
494 if is_mac():
495 # flutter_desktop_darwin_unittests uses global state that isn't handled
496 # correctly by gtest-parallel.
497 # https://github.com/flutter/flutter/issues/104789
498 if not os.path.basename(build_dir).startswith('host_debug'):
499 # Test is disabled for flaking in debug runs:
500 # https://github.com/flutter/flutter/issues/127441
502 build_dir,
503 'flutter_desktop_darwin_unittests',
504 executable_filter,
505 shuffle_flags,
506 coverage=coverage
507 )
508 extra_env = metal_validation_env()
509 extra_env.update(vulkan_validation_env(build_dir))
510 mac_impeller_unittests_flags = repeat_flags + [
511 '--gtest_filter=-*OpenGLES', # These are covered in the golden tests.
512 '--',
513 '--enable_vulkan_validation',
514 ]
515 # Impeller tests are only supported on macOS for now.
517 build_dir,
518 'impeller_unittests',
519 executable_filter,
520 mac_impeller_unittests_flags,
521 coverage=coverage,
522 extra_env=extra_env,
523 gtest=True,
524 # TODO(https://github.com/flutter/flutter/issues/123733): Remove this allowlist.
525 # See also https://github.com/flutter/flutter/issues/114872.
526 allowed_failure_output=[
527 '[MTLCompiler createVertexStageAndLinkPipelineWithFragment:',
528 '[MTLCompiler pipelineStateWithVariant:',
529 ]
530 )
531
532 # Run one interactive Vulkan test with validation enabled.
533 #
534 # TODO(matanlurey): https://github.com/flutter/flutter/issues/134852; enable
535 # more of the suite, and ideally we'd like to use Skia gold and take screen
536 # shots as well.
538 build_dir,
539 'impeller_unittests',
540 executable_filter,
541 shuffle_flags + [
542 '--enable_vulkan_validation',
543 '--enable_playground',
544 '--playground_timeout_ms=4000',
545 '--gtest_filter="*ColorWheel/Vulkan"',
546 ],
547 coverage=coverage,
548 extra_env=extra_env,
549 )
550
551 # Run the Flutter GPU test suite.
553 build_dir,
554 'impeller_dart_unittests',
555 executable_filter,
556 shuffle_flags + [
557 '--enable_vulkan_validation',
558 # TODO(https://github.com/flutter/flutter/issues/145036)
559 # TODO(https://github.com/flutter/flutter/issues/142642)
560 '--gtest_filter=*Metal',
561 ],
562 coverage=coverage,
563 extra_env=extra_env,
564 )
565
566
567def run_engine_benchmarks(build_dir, executable_filter):
568 logger.info('Running Engine Benchmarks.')
569
570 icu_flags = ['--icu-data-file-path=%s' % os.path.join(build_dir, 'icudtl.dat')]
571
572 run_engine_executable(build_dir, 'shell_benchmarks', executable_filter, icu_flags)
573
574 run_engine_executable(build_dir, 'fml_benchmarks', executable_filter, icu_flags)
575
576 run_engine_executable(build_dir, 'ui_benchmarks', executable_filter, icu_flags)
577
578 run_engine_executable(build_dir, 'display_list_builder_benchmarks', executable_filter, icu_flags)
579
580 run_engine_executable(build_dir, 'geometry_benchmarks', executable_filter, icu_flags)
581
582 run_engine_executable(build_dir, 'canvas_benchmarks', executable_filter, icu_flags)
583
584 if is_linux():
585 run_engine_executable(build_dir, 'txt_benchmarks', executable_filter, icu_flags)
586
587
589
591 self,
592 multithreaded=False,
593 enable_impeller=False,
594 enable_observatory=False,
595 expect_failure=False
596 ):
597 self.multithreaded = multithreaded
598 self.enable_impeller = enable_impeller
599 self.enable_observatory = enable_observatory
600 self.expect_failure = expect_failure
601
602 def apply_args(self, command_args):
603 if not self.enable_observatory:
604 command_args.append('--disable-observatory')
605
606 if self.enable_impeller:
607 command_args += ['--enable-impeller']
608 else:
609 command_args += ['--no-enable-impeller']
610
611 if self.multithreaded:
612 command_args.insert(0, '--force-multithreading')
613
615 if self.multithreaded:
616 return 'multithreaded'
617 return 'single-threaded'
618
620 if self.enable_impeller:
621 return 'impeller swiftshader'
622 return 'skia software'
623
624
625def gather_dart_test(build_dir, dart_file, options):
626 kernel_file_name = os.path.basename(dart_file) + '.dill'
627 kernel_file_output = os.path.join(build_dir, 'gen', kernel_file_name)
628 error_message = "%s doesn't exist. Please run the build that populates %s" % (
629 kernel_file_output, build_dir
630 )
631 assert os.path.isfile(kernel_file_output), error_message
632
633 command_args = []
634
635 options.apply_args(command_args)
636
637 dart_file_contents = open(dart_file, 'r')
638 custom_options = re.findall('// FlutterTesterOptions=(.*)', dart_file_contents.read())
639 dart_file_contents.close()
640 command_args.extend(custom_options)
641
642 command_args += [
643 '--use-test-fonts',
644 '--icu-data-file-path=%s' % os.path.join(build_dir, 'icudtl.dat'),
645 '--flutter-assets-dir=%s' % os.path.join(build_dir, 'gen', 'flutter', 'lib', 'ui', 'assets'),
646 '--disable-asset-fonts',
647 kernel_file_output,
648 ]
649
650 tester_name = 'flutter_tester'
651 logger.info(
652 "Running test '%s' using '%s' (%s, %s)", kernel_file_name, tester_name,
653 options.threading_description(), options.impeller_enabled()
654 )
655 forbidden_output = [] if 'unopt' in build_dir or options.expect_failure else ['[ERROR']
657 build_dir,
658 tester_name,
659 None,
660 command_args,
661 forbidden_output=forbidden_output,
662 expect_failure=options.expect_failure,
663 )
664
665
667 """Builds the engine variant and the test dylib containing the XCTests"""
668 tmp_out_dir = os.path.join(OUT_DIR, ios_out_dir)
669 ios_test_lib = os.path.join(tmp_out_dir, 'libios_test_flutter.dylib')
670 message = []
671 message.append('gn --ios --unoptimized --runtime-mode=debug --no-lto --simulator')
672 message.append('ninja -C %s ios_test_flutter' % ios_out_dir)
673 final_message = "%s or %s doesn't exist. Please run the following commands: \n%s" % (
674 ios_out_dir, ios_test_lib, '\n'.join(message)
675 )
676 assert os.path.exists(tmp_out_dir) and os.path.exists(ios_test_lib), final_message
677
678
680 """Checks that the user has a version of Xcode installed"""
681 version_output = subprocess.check_output(['xcodebuild', '-version'])
682 # TODO ricardoamador: remove this check when python 2 is deprecated.
683 version_output = version_output if isinstance(version_output,
684 str) else version_output.decode(ENCODING)
685 version_output = version_output.strip()
686 match = re.match(r'Xcode (\d+)', version_output)
687 message = 'Xcode must be installed to run the iOS embedding unit tests'
688 assert match, message
689
690
692 script_path = os.path.dirname(os.path.realpath(__file__))
693 if is_mac():
694 return os.path.join(
695 script_path, '..', '..', 'third_party', 'java', 'openjdk', 'Contents', 'Home'
696 )
697 return os.path.join(script_path, '..', '..', 'third_party', 'java', 'openjdk')
698
699
701 return os.path.join(java_home(), 'bin', 'java.exe' if is_windows() else 'java')
702
703
704def run_java_tests(executable_filter, android_variant='android_debug_unopt'):
705 """Runs the Java JUnit unit tests for the Android embedding"""
706 test_runner_dir = os.path.join(
707 BUILDROOT_DIR, 'flutter', 'shell', 'platform', 'android', 'test_runner'
708 )
709 gradle_bin = os.path.join(
710 BUILDROOT_DIR, 'third_party', 'gradle', 'bin', 'gradle.bat' if is_windows() else 'gradle'
711 )
712 flutter_jar = os.path.join(OUT_DIR, android_variant, 'flutter.jar')
713 android_home = os.path.join(BUILDROOT_DIR, 'third_party', 'android_tools', 'sdk')
714 build_dir = os.path.join(OUT_DIR, android_variant, 'robolectric_tests', 'build')
715 gradle_cache_dir = os.path.join(OUT_DIR, android_variant, 'robolectric_tests', '.gradle')
716
717 test_class = executable_filter if executable_filter else '*'
718 command = [
719 gradle_bin,
720 '-Pflutter_jar=%s' % flutter_jar,
721 '-Pbuild_dir=%s' % build_dir,
722 'testDebugUnitTest',
723 '--tests=%s' % test_class,
724 '--rerun-tasks',
725 '--no-daemon',
726 '--project-cache-dir=%s' % gradle_cache_dir,
727 '--gradle-user-home=%s' % gradle_cache_dir,
728 ]
729
730 env = dict(os.environ, ANDROID_HOME=android_home, JAVA_HOME=java_home())
731 run_cmd(command, cwd=test_runner_dir, env=env)
732
733
734def run_android_unittest(test_runner_name, android_variant, adb_path):
735 tests_path = os.path.join(OUT_DIR, android_variant, test_runner_name)
736 remote_path = '/data/local/tmp'
737 remote_tests_path = os.path.join(remote_path, test_runner_name)
738 run_cmd([adb_path, 'push', tests_path, remote_path], cwd=BUILDROOT_DIR)
739
740 try:
741 run_cmd([adb_path, 'shell', remote_tests_path])
742 except:
743 luci_test_outputs_path = os.environ.get('FLUTTER_TEST_OUTPUTS_DIR')
744 if luci_test_outputs_path:
745 print('>>>>> Test %s failed. Capturing logcat.' % test_runner_name)
746 logcat_path = os.path.join(luci_test_outputs_path, '%s_logcat' % test_runner_name)
747 logcat_file = open(logcat_path, 'w')
748 subprocess.run([adb_path, 'logcat', '-d'], stdout=logcat_file, check=False)
749 raise
750
751
752def run_android_tests(android_variant='android_debug_unopt', adb_path=None):
753 if adb_path is None:
754 adb_path = 'adb'
755
756 run_android_unittest('flutter_shell_native_unittests', android_variant, adb_path)
757 run_android_unittest('impeller_toolkit_android_unittests', android_variant, adb_path)
758
759 systrace_test = os.path.join(BUILDROOT_DIR, 'flutter', 'testing', 'android_systrace_test.py')
760 scenario_apk = os.path.join(OUT_DIR, android_variant, 'firebase_apks', 'scenario_app.apk')
761 run_cmd([
762 systrace_test, '--adb-path', adb_path, '--apk-path', scenario_apk, '--package-name',
763 'dev.flutter.scenarios', '--activity-name', '.PlatformViewsActivity'
764 ])
765
766
767def run_objc_tests(ios_variant='ios_debug_sim_unopt', test_filter=None):
768 """Runs Objective-C XCTest unit tests for the iOS embedding"""
770 ios_out_dir = os.path.join(OUT_DIR, ios_variant)
771 ensure_ios_tests_are_built(ios_out_dir)
772
773 new_simulator_name = 'IosUnitTestsSimulator'
774
775 # Delete simulators with this name in case any were leaked
776 # from another test run.
777 delete_simulator(new_simulator_name)
778
779 create_simulator = [
780 'xcrun '
781 'simctl '
782 'create '
783 '%s com.apple.CoreSimulator.SimDeviceType.iPhone-11' % new_simulator_name
784 ]
785 run_cmd(create_simulator, shell=True)
786
787 try:
788 ios_unit_test_dir = os.path.join(BUILDROOT_DIR, 'flutter', 'testing', 'ios', 'IosUnitTests')
789
790 with tempfile.TemporaryDirectory(suffix='ios_embedding_xcresult') as result_bundle_temp:
791 result_bundle_path = os.path.join(result_bundle_temp, 'ios_embedding')
792
793 # Avoid using xcpretty unless the following can be addressed:
794 # - Make sure all relevant failure output is printed on a failure.
795 # - Make sure that a failing exit code is set for CI.
796 # See https://github.com/flutter/flutter/issues/63742
797 test_command = [
798 'xcodebuild '
799 '-sdk iphonesimulator '
800 '-scheme IosUnitTests '
801 '-resultBundlePath ' + result_bundle_path + ' '
802 '-destination name=' + new_simulator_name + ' '
803 'test '
804 'FLUTTER_ENGINE=' + ios_variant
805 ]
806 if test_filter is not None:
807 test_command[0] = test_command[0] + ' -only-testing:%s' % test_filter
808 try:
809 run_cmd(test_command, cwd=ios_unit_test_dir, shell=True)
810
811 except:
812 # The LUCI environment may provide a variable containing a directory path
813 # for additional output files that will be uploaded to cloud storage.
814 # Upload the xcresult when the tests fail.
815 luci_test_outputs_path = os.environ.get('FLUTTER_TEST_OUTPUTS_DIR')
816 xcresult_bundle = os.path.join(result_bundle_temp, 'ios_embedding.xcresult')
817 if luci_test_outputs_path and os.path.exists(xcresult_bundle):
818 dump_path = os.path.join(luci_test_outputs_path, 'ios_embedding.xcresult')
819 # xcresults contain many little files. Archive the bundle before upload.
820 shutil.make_archive(dump_path, 'zip', root_dir=xcresult_bundle)
821 raise
822
823 finally:
824 delete_simulator(new_simulator_name)
825
826
827def delete_simulator(simulator_name):
828 # Will delete all simulators with this name.
829 command = [
830 'xcrun',
831 'simctl',
832 'delete',
833 simulator_name,
834 ]
835 # Let this fail if the simulator was never created.
836 run_cmd(command, expect_failure=True)
837
838
839def gather_dart_tests(build_dir, test_filter):
840 dart_tests_dir = os.path.join(
841 BUILDROOT_DIR,
842 'flutter',
843 'testing',
844 'dart',
845 )
846
847 # Now that we have the Sky packages at the hardcoded location, run `dart pub get`.
849 build_dir,
850 os.path.join('dart-sdk', 'bin', 'dart'),
851 None,
852 flags=['pub', '--suppress-analytics', 'get', '--offline'],
853 cwd=dart_tests_dir,
854 )
855
856 dart_observatory_tests = glob.glob('%s/observatory/*_test.dart' % dart_tests_dir)
857 dart_tests = glob.glob('%s/*_test.dart' % dart_tests_dir)
858
859 if 'release' not in build_dir:
860 for dart_test_file in dart_observatory_tests:
861 if test_filter is not None and os.path.basename(dart_test_file) not in test_filter:
862 logger.info("Skipping '%s' due to filter.", dart_test_file)
863 else:
864 logger.info("Gathering dart test '%s' with observatory enabled", dart_test_file)
865 for multithreaded in [False, True]:
866 for enable_impeller in [False, True]:
867 yield gather_dart_test(
868 build_dir, dart_test_file,
870 multithreaded=multithreaded,
871 enable_impeller=enable_impeller,
872 enable_observatory=True
873 )
874 )
875
876 for dart_test_file in dart_tests:
877 if test_filter is not None and os.path.basename(dart_test_file) not in test_filter:
878 logger.info("Skipping '%s' due to filter.", dart_test_file)
879 else:
880 logger.info("Gathering dart test '%s'", dart_test_file)
881 for multithreaded in [False, True]:
882 for enable_impeller in [False, True]:
883 yield gather_dart_test(
884 build_dir, dart_test_file,
885 FlutterTesterOptions(multithreaded=multithreaded, enable_impeller=enable_impeller)
886 )
887
888
889def gather_dart_smoke_test(build_dir, test_filter):
890 smoke_test = os.path.join(
891 BUILDROOT_DIR,
892 'flutter',
893 'testing',
894 'smoke_test_failure',
895 'fail_test.dart',
896 )
897 if test_filter is not None and os.path.basename(smoke_test) not in test_filter:
898 logger.info("Skipping '%s' due to filter.", smoke_test)
899 else:
900 yield gather_dart_test(
901 build_dir, smoke_test, FlutterTesterOptions(multithreaded=True, expect_failure=True)
902 )
903 yield gather_dart_test(
904 build_dir, smoke_test, FlutterTesterOptions(multithreaded=False, expect_failure=True)
905 )
906
907
908def gather_dart_package_tests(build_dir, package_path, extra_opts):
909 dart_tests = glob.glob('%s/test/*_test.dart' % package_path)
910 if not dart_tests:
911 raise Exception('No tests found for Dart package at %s' % package_path)
912 for dart_test_file in dart_tests:
913 opts = ['--disable-dart-dev', dart_test_file] + extra_opts
915 build_dir, os.path.join('dart-sdk', 'bin', 'dart'), None, flags=opts, cwd=package_path
916 )
917
918
919# Returns a list of Dart packages to test.
920#
921# The first element of each tuple in the returned list is the path to the Dart
922# package to test. It is assumed that the packages follow the convention that
923# tests are named as '*_test.dart', and reside under a directory called 'test'.
924#
925# The second element of each tuple is a list of additional command line
926# arguments to pass to each of the packages tests.
928 dart_host_tests = [
929 (
930 os.path.join('flutter', 'ci'),
931 [os.path.join(BUILDROOT_DIR, 'flutter')],
932 ),
933 (
934 os.path.join('flutter', 'flutter_frontend_server'),
935 [
936 build_dir,
937 os.path.join(build_dir, 'gen', 'frontend_server_aot.dart.snapshot'),
938 os.path.join(build_dir, 'flutter_patched_sdk')
939 ],
940 ),
941 (os.path.join('flutter', 'testing', 'litetest'), []),
942 (os.path.join('flutter', 'testing', 'pkg_test_demo'), []),
943 (os.path.join('flutter', 'testing', 'skia_gold_client'), []),
944 (os.path.join('flutter', 'testing', 'scenario_app'), []),
945 (
946 os.path.join('flutter', 'tools', 'api_check'),
947 [os.path.join(BUILDROOT_DIR, 'flutter')],
948 ),
949 (os.path.join('flutter', 'tools', 'build_bucket_golden_scraper'), []),
950 (os.path.join('flutter', 'tools', 'clang_tidy'), []),
951 (
952 os.path.join('flutter', 'tools', 'const_finder'),
953 [
954 os.path.join(build_dir, 'gen', 'frontend_server_aot.dart.snapshot'),
955 os.path.join(build_dir, 'flutter_patched_sdk'),
956 os.path.join(build_dir, 'dart-sdk', 'lib', 'libraries.json'),
957 ],
958 ),
959 (os.path.join('flutter', 'tools', 'dir_contents_diff'), []),
960 (os.path.join('flutter', 'tools', 'engine_tool'), []),
961 (os.path.join('flutter', 'tools', 'githooks'), []),
962 (os.path.join('flutter', 'tools', 'header_guard_check'), []),
963 (os.path.join('flutter', 'tools', 'pkg', 'engine_build_configs'), []),
964 (os.path.join('flutter', 'tools', 'pkg', 'engine_repo_tools'), []),
965 (os.path.join('flutter', 'tools', 'pkg', 'git_repo_tools'), []),
966 ]
967 if not is_asan(build_dir):
968 dart_host_tests += [
969 (os.path.join('flutter', 'tools', 'path_ops', 'dart'), []),
970 ]
971
972 return dart_host_tests
973
974
975def run_benchmark_tests(build_dir):
976 test_dir = os.path.join(BUILDROOT_DIR, 'flutter', 'testing', 'benchmark')
977 dart_tests = glob.glob('%s/test/*_test.dart' % test_dir)
978 for dart_test_file in dart_tests:
979 opts = ['--disable-dart-dev', dart_test_file]
981 build_dir, os.path.join('dart-sdk', 'bin', 'dart'), None, flags=opts, cwd=test_dir
982 )
983
984
985def worker_init(queue, level):
986 queue_handler = logging.handlers.QueueHandler(queue)
987 log = logging.getLogger(__name__)
988 log.setLevel(logging.INFO)
989 queue_handler.setLevel(level)
990 log.addHandler(queue_handler)
991
992
994 # Work around a bug in Python.
995 #
996 # The multiprocessing package relies on the win32 WaitForMultipleObjects()
997 # call, which supports waiting on a maximum of MAXIMUM_WAIT_OBJECTS (defined
998 # by Windows to be 64) handles, processes in this case. To avoid hitting
999 # this, we limit ourselves to 60 handles (since there are a couple extra
1000 # processes launched for the queue reader and thread wakeup reader).
1001 #
1002 # See: https://bugs.python.org/issue26903
1003 max_processes = multiprocessing.cpu_count()
1004 if sys_platform.startswith(('cygwin', 'win')) and max_processes > 60:
1005 max_processes = 60
1006
1007 queue = multiprocessing.Queue()
1008 queue_listener = logging.handlers.QueueListener(
1009 queue,
1010 console_logger_handler,
1011 file_logger_handler,
1012 respect_handler_level=True,
1013 )
1014 queue_listener.start()
1015
1016 failures = []
1017 try:
1018 with multiprocessing.Pool(max_processes, worker_init,
1019 [queue, logger.getEffectiveLevel()]) as pool:
1020 async_results = [(t, pool.apply_async(t, ())) for t in tasks]
1021 for task, async_result in async_results:
1022 try:
1023 async_result.get()
1024 except Exception as exn: # pylint: disable=broad-except
1025 failures += [(task, exn)]
1026 finally:
1027 queue_listener.stop()
1028
1029 if len(failures) > 0:
1030 logger.error('The following commands failed:')
1031 for task, exn in failures:
1032 logger.error('%s\n %s\n\n', str(task), str(exn))
1033 return False
1034
1035 return True
1036
1037
1039 """
1040 A scoped change in the CWD.
1041 """
1042 old_cwd: str = ''
1043 new_cwd: str = ''
1044
1045 def __init__(self, new_cwd: str):
1046 self.new_cwdnew_cwd = new_cwd
1047
1048 def __enter__(self):
1049 self.old_cwdold_cwd = os.getcwd()
1050 os.chdir(self.new_cwdnew_cwd)
1051
1052 def __exit__(self, exception_type, exception_value, exception_traceback):
1053 os.chdir(self.old_cwdold_cwd)
1054
1055
1056def run_impeller_golden_tests(build_dir: str, require_skia_gold: bool = False):
1057 """
1058 Executes the impeller golden image tests from in the `variant` build.
1059 """
1060 tests_path: str = os.path.join(build_dir, 'impeller_golden_tests')
1061 if not os.path.exists(tests_path):
1062 raise Exception(
1063 'Cannot find the "impeller_golden_tests" executable in "%s". You may need to build it.' %
1064 (build_dir)
1065 )
1066 harvester_path: Path = Path(SCRIPT_DIR).parent.joinpath('tools'
1067 ).joinpath('golden_tests_harvester')
1068
1069 with tempfile.TemporaryDirectory(prefix='impeller_golden') as temp_dir:
1070 extra_env = metal_validation_env()
1071 extra_env.update(vulkan_validation_env(build_dir))
1072 run_cmd([tests_path, f'--working_dir={temp_dir}'], cwd=build_dir, env=extra_env)
1073 dart_bin = os.path.join(build_dir, 'dart-sdk', 'bin', 'dart')
1074 golden_path = os.path.join('testing', 'impeller_golden_tests_output.txt')
1075 script_path = os.path.join('tools', 'dir_contents_diff', 'bin', 'dir_contents_diff.dart')
1076 diff_result = subprocess.run(
1077 f'{dart_bin} --disable-dart-dev {script_path} {golden_path} {temp_dir}',
1078 check=False,
1079 shell=True,
1080 stdout=subprocess.PIPE,
1081 cwd=os.path.join(BUILDROOT_DIR, 'flutter')
1082 )
1083 if diff_result.returncode != 0:
1084 print_divider('<')
1085 print(diff_result.stdout.decode())
1086 raise RuntimeError('impeller_golden_tests diff failure')
1087
1088 if not require_skia_gold:
1089 print_divider('<')
1090 print('Skipping any SkiaGoldClient invocation as the --no-skia-gold flag was set.')
1091 return
1092
1093 # On release builds and local builds, we typically do not have GOLDCTL set,
1094 # which on other words means that this invoking the SkiaGoldClient would
1095 # throw. Skip this step in those cases and log a notice.
1096 if 'GOLDCTL' not in os.environ:
1097 # On CI, we never want to be running golden tests without Skia Gold.
1098 # See https://github.com/flutter/flutter/issues/147180 as an example.
1099 is_luci = 'LUCI_CONTEXT' in os.environ
1100 if is_luci:
1101 raise RuntimeError(
1102 """
1103The GOLDCTL environment variable is not set. This is required for Skia Gold tests.
1104See https://github.com/flutter/engine/tree/main/testing/skia_gold_client#configuring-ci
1105for more information.
1106"""
1107 )
1108
1109 print_divider('<')
1110 print(
1111 'Skipping the SkiaGoldClient invocation as the GOLDCTL environment variable is not set.'
1112 )
1113 return
1114
1115 with DirectoryChange(harvester_path):
1116 bin_path = Path('.').joinpath('bin').joinpath('golden_tests_harvester.dart')
1117 run_cmd([dart_bin, '--disable-dart-dev', str(bin_path), temp_dir])
1118
1119
1120def main():
1121 parser = argparse.ArgumentParser(
1122 description="""
1123In order to learn the details of running tests in the engine, please consult the
1124Flutter Wiki page on the subject: https://github.com/flutter/flutter/wiki/Testing-the-engine
1125"""
1126 )
1127 all_types = [
1128 'engine',
1129 'dart',
1130 'dart-host',
1131 'benchmarks',
1132 'java',
1133 'android',
1134 'objc',
1135 'font-subset',
1136 'impeller-golden',
1137 ]
1138
1139 parser.add_argument(
1140 '--variant',
1141 dest='variant',
1142 action='store',
1143 default='host_debug_unopt',
1144 help='The engine build variant to run the tests for.'
1145 )
1146 parser.add_argument(
1147 '--type',
1148 type=str,
1149 default='all',
1150 help='A list of test types, default is "all" (equivalent to "%s")' % (','.join(all_types))
1151 )
1152 parser.add_argument(
1153 '--engine-filter', type=str, default='', help='A list of engine test executables to run.'
1154 )
1155 parser.add_argument(
1156 '--dart-filter',
1157 type=str,
1158 default='',
1159 help='A list of Dart test scripts to run in flutter_tester.'
1160 )
1161 parser.add_argument(
1162 '--dart-host-filter',
1163 type=str,
1164 default='',
1165 help='A list of Dart test scripts to run with the Dart CLI.'
1166 )
1167 parser.add_argument(
1168 '--java-filter',
1169 type=str,
1170 default='',
1171 help='A single Java test class to run (example: "io.flutter.SmokeTest")'
1172 )
1173 parser.add_argument(
1174 '--android-variant',
1175 dest='android_variant',
1176 action='store',
1177 default='android_debug_unopt',
1178 help='The engine build variant to run java or android tests for'
1179 )
1180 parser.add_argument(
1181 '--ios-variant',
1182 dest='ios_variant',
1183 action='store',
1184 default='ios_debug_sim_unopt',
1185 help='The engine build variant to run objective-c tests for'
1186 )
1187 parser.add_argument(
1188 '--verbose-dart-snapshot',
1189 dest='verbose_dart_snapshot',
1190 action='store_true',
1191 default=False,
1192 help='Show extra dart snapshot logging.'
1193 )
1194 parser.add_argument(
1195 '--objc-filter',
1196 type=str,
1197 default=None,
1198 help=(
1199 'Filter parameter for which objc tests to run '
1200 '(example: "IosUnitTestsTests/SemanticsObjectTest/testShouldTriggerAnnouncement")'
1201 )
1202 )
1203 parser.add_argument(
1204 '--coverage',
1205 action='store_true',
1206 default=None,
1207 help='Generate coverage reports for each unit test framework run.'
1208 )
1209 parser.add_argument(
1210 '--engine-capture-core-dump',
1211 dest='engine_capture_core_dump',
1212 action='store_true',
1213 default=False,
1214 help='Capture core dumps from crashes of engine tests.'
1215 )
1216 parser.add_argument(
1217 '--use-sanitizer-suppressions',
1218 dest='sanitizer_suppressions',
1219 action='store_true',
1220 default=False,
1221 help='Provide the sanitizer suppressions lists to the via environment to the tests.'
1222 )
1223 parser.add_argument(
1224 '--adb-path',
1225 dest='adb_path',
1226 action='store',
1227 default=None,
1228 help='Provide the path of adb used for android tests. By default it looks on $PATH.'
1229 )
1230 parser.add_argument(
1231 '--quiet',
1232 dest='quiet',
1233 action='store_true',
1234 default=False,
1235 help='Only emit output when there is an error.'
1236 )
1237 parser.add_argument(
1238 '--logs-dir',
1239 dest='logs_dir',
1240 type=str,
1241 help='The directory that verbose logs will be copied to in --quiet mode.',
1242 )
1243 parser.add_argument(
1244 '--no-skia-gold',
1245 dest='no_skia_gold',
1246 action='store_true',
1247 default=False,
1248 help='Do not compare golden images with Skia Gold.',
1249 )
1250
1251 args = parser.parse_args()
1252
1253 logger.addHandler(console_logger_handler)
1254 logger.addHandler(file_logger_handler)
1255 logger.setLevel(logging.INFO)
1256 if args.quiet:
1257 file_logger_handler.setLevel(logging.INFO)
1258 console_logger_handler.setLevel(logging.WARNING)
1259 else:
1260 console_logger_handler.setLevel(logging.INFO)
1261
1262 if args.type == 'all':
1263 types = all_types
1264 else:
1265 types = args.type.split(',')
1266
1267 build_dir = os.path.join(OUT_DIR, args.variant)
1268 if args.type != 'java' and args.type != 'android':
1269 assert os.path.exists(build_dir), 'Build variant directory %s does not exist!' % build_dir
1270
1271 if args.sanitizer_suppressions:
1272 assert is_linux() or is_mac(
1273 ), 'The sanitizer suppressions flag is only supported on Linux and Mac.'
1274 file_dir = os.path.dirname(os.path.abspath(__file__))
1275 command = [
1276 'env', '-i', 'bash', '-c',
1277 'source {}/sanitizer_suppressions.sh >/dev/null && env'.format(file_dir)
1278 ]
1279 process = subprocess.Popen(command, stdout=subprocess.PIPE)
1280 for line in process.stdout:
1281 key, _, value = line.decode('utf8').strip().partition('=')
1282 os.environ[key] = value
1283 process.communicate() # Avoid pipe deadlock while waiting for termination.
1284
1285 success = True
1286
1287 engine_filter = args.engine_filter.split(',') if args.engine_filter else None
1288 if 'engine' in types:
1289 run_cc_tests(build_dir, engine_filter, args.coverage, args.engine_capture_core_dump)
1290
1291 # Use this type to exclusively run impeller tests.
1292 if 'impeller' in types:
1293 build_name = args.variant
1294 try:
1295 xvfb.start_virtual_x(build_name, build_dir)
1296 extra_env = vulkan_validation_env(build_dir)
1298 build_dir,
1299 'impeller_unittests',
1300 engine_filter,
1301 repeat_flags,
1302 coverage=args.coverage,
1303 extra_env=extra_env,
1304 gtest=True
1305 )
1306 finally:
1307 xvfb.stop_virtual_x(build_name)
1308
1309 if 'dart' in types:
1310 dart_filter = args.dart_filter.split(',') if args.dart_filter else None
1311 tasks = list(gather_dart_smoke_test(build_dir, dart_filter))
1312 tasks += list(gather_dart_tests(build_dir, dart_filter))
1313 success = success and run_engine_tasks_in_parallel(tasks)
1314
1315 if 'dart-host' in types:
1316 dart_filter = args.dart_host_filter.split(',') if args.dart_host_filter else None
1317 dart_host_packages = build_dart_host_test_list(build_dir)
1318 tasks = []
1319 for dart_host_package, extra_opts in dart_host_packages:
1320 if dart_filter is None or dart_host_package in dart_filter:
1321 tasks += list(
1323 build_dir,
1324 os.path.join(BUILDROOT_DIR, dart_host_package),
1325 extra_opts,
1326 )
1327 )
1328
1329 success = success and run_engine_tasks_in_parallel(tasks)
1330
1331 if 'java' in types:
1332 assert not is_windows(), "Android engine files can't be compiled on Windows."
1333 java_filter = args.java_filter
1334 if ',' in java_filter or '*' in java_filter:
1335 logger.wraning(
1336 'Can only filter JUnit4 tests by single entire class name, '
1337 'eg "io.flutter.SmokeTest". Ignoring filter=' + java_filter
1338 )
1339 java_filter = None
1340 run_java_tests(java_filter, args.android_variant)
1341
1342 if 'android' in types:
1343 assert not is_windows(), "Android engine files can't be compiled on Windows."
1344 run_android_tests(args.android_variant, args.adb_path)
1345
1346 if 'objc' in types:
1347 assert is_mac(), 'iOS embedding tests can only be run on macOS.'
1348 run_objc_tests(args.ios_variant, args.objc_filter)
1349
1350 # https://github.com/flutter/flutter/issues/36300
1351 if 'benchmarks' in types and not is_windows():
1352 run_benchmark_tests(build_dir)
1353 run_engine_benchmarks(build_dir, engine_filter)
1354
1355 variants_to_skip = ['host_release', 'host_profile']
1356
1357 def should_skip(variant):
1358 matches = [variant for variant in variants_to_skip if variant in args.variant]
1359 return len(matches) > 0
1360
1361 if ('engine' in types or 'font-subset' in types) and not should_skip(args.variant):
1362 cmd = ['python3', 'test.py', '--variant', args.variant]
1363 if 'arm64' in args.variant:
1364 cmd += ['--target-cpu', 'arm64']
1365 run_cmd(cmd, cwd=FONT_SUBSET_DIR)
1366
1367 if 'impeller-golden' in types:
1368 run_impeller_golden_tests(build_dir, require_skia_gold=not args.no_skia_gold)
1369
1370 if args.quiet and args.logs_dir:
1371 shutil.copy(LOG_FILE, os.path.join(args.logs_dir, 'run_tests.log'))
1372
1373 return 0 if success else 1
1374
1375
1376if __name__ == '__main__':
1377 sys_exit(main())
static bool should_skip(const char *sink, const char *src, const char *srcOptions, const char *name)
Definition DM.cpp:1142
__init__(self, str new_cwd)
__exit__(self, exception_type, exception_value, exception_traceback)
__init__(self, build_dir, executable_name, executable_filter, flags=None, cwd=BUILDROOT_DIR, forbidden_output=None, allowed_failure_output=None, expect_failure=False, coverage=False, extra_env=None)
Definition run_tests.py:350
apply_args(self, command_args)
Definition run_tests.py:602
__init__(self, multithreaded=False, enable_impeller=False, enable_observatory=False, expect_failure=False)
Definition run_tests.py:596
uint32_t uint32_t * format
Definition main.py:1
delete_simulator(simulator_name)
Definition run_tests.py:827
gather_dart_package_tests(build_dir, package_path, extra_opts)
Definition run_tests.py:908
print(*args, **kwargs)
Definition run_tests.py:49
assert_expected_xcode_version()
Definition run_tests.py:679
run_android_tests(android_variant='android_debug_unopt', adb_path=None)
Definition run_tests.py:752
print_divider(char='=')
Definition run_tests.py:53
executable_suffix()
Definition run_tests.py:155
run_android_unittest(test_runner_name, android_variant, adb_path)
Definition run_tests.py:734
gather_dart_test(build_dir, dart_file, options)
Definition run_tests.py:625
gather_dart_smoke_test(build_dir, test_filter)
Definition run_tests.py:889
ensure_ios_tests_are_built(ios_out_dir)
Definition run_tests.py:666
build_engine_executable_command(build_dir, executable_name, flags=None, coverage=False, gtest=False)
Definition run_tests.py:208
run_engine_benchmarks(build_dir, executable_filter)
Definition run_tests.py:567
build_dart_host_test_list(build_dir)
Definition run_tests.py:927
None run_cmd(typing.List[str] cmd, typing.List[str] forbidden_output=None, bool expect_failure=False, typing.Dict[str, str] env=None, typing.List[str] allowed_failure_output=None, **kwargs)
Definition run_tests.py:75
vulkan_validation_env(build_dir)
Definition run_tests.py:175
run_benchmark_tests(build_dir)
Definition run_tests.py:975
worker_init(queue, level)
Definition run_tests.py:985
run_impeller_golden_tests(str build_dir, bool require_skia_gold=False)
run_objc_tests(ios_variant='ios_debug_sim_unopt', test_filter=None)
Definition run_tests.py:767
is_asan(build_dir)
Definition run_tests.py:60
run_cc_tests(build_dir, executable_filter, coverage, capture_core_dump)
Definition run_tests.py:393
find_executable_path(path)
Definition run_tests.py:159
run_engine_tasks_in_parallel(tasks)
Definition run_tests.py:993
gather_dart_tests(build_dir, test_filter)
Definition run_tests.py:839
metal_validation_env()
Definition run_tests.py:188
run_java_tests(executable_filter, android_variant='android_debug_unopt')
Definition run_tests.py:704
run_engine_executable(build_dir, executable_name, executable_filter, flags=None, cwd=BUILDROOT_DIR, forbidden_output=None, allowed_failure_output=None, expect_failure=False, coverage=False, extra_env=None, gtest=False)
Definition run_tests.py:253
start_virtual_x(child_build_name, build_dir)
Definition xvfb.py:27
stop_virtual_x(child_build_name)
Definition xvfb.py:138