Flutter Engine
The Flutter Engine
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, 'flutter', 'third_party', 'gradle', 'bin',
711 'gradle.bat' if is_windows() else 'gradle'
712 )
713 flutter_jar = os.path.join(OUT_DIR, android_variant, 'flutter.jar')
714 android_home = os.path.join(BUILDROOT_DIR, 'flutter', 'third_party', 'android_tools', 'sdk')
715 build_dir = os.path.join(OUT_DIR, android_variant, 'robolectric_tests', 'build')
716 gradle_cache_dir = os.path.join(OUT_DIR, android_variant, 'robolectric_tests', '.gradle')
717
718 test_class = executable_filter if executable_filter else '*'
719 command = [
720 gradle_bin,
721 '-Pflutter_jar=%s' % flutter_jar,
722 '-Pbuild_dir=%s' % build_dir,
723 'testDebugUnitTest',
724 '--tests=%s' % test_class,
725 '--rerun-tasks',
726 '--no-daemon',
727 '--project-cache-dir=%s' % gradle_cache_dir,
728 '--gradle-user-home=%s' % gradle_cache_dir,
729 ]
730
731 env = dict(os.environ, ANDROID_HOME=android_home, JAVA_HOME=java_home())
732 run_cmd(command, cwd=test_runner_dir, env=env)
733
734
735def run_android_unittest(test_runner_name, android_variant, adb_path):
736 tests_path = os.path.join(OUT_DIR, android_variant, test_runner_name)
737 remote_path = '/data/local/tmp'
738 remote_tests_path = os.path.join(remote_path, test_runner_name)
739 run_cmd([adb_path, 'push', tests_path, remote_path], cwd=BUILDROOT_DIR)
740
741 try:
742 run_cmd([adb_path, 'shell', remote_tests_path])
743 except:
744 luci_test_outputs_path = os.environ.get('FLUTTER_TEST_OUTPUTS_DIR')
745 if luci_test_outputs_path:
746 print('>>>>> Test %s failed. Capturing logcat.' % test_runner_name)
747 logcat_path = os.path.join(luci_test_outputs_path, '%s_logcat' % test_runner_name)
748 logcat_file = open(logcat_path, 'w')
749 subprocess.run([adb_path, 'logcat', '-d'], stdout=logcat_file, check=False)
750 raise
751
752
753def run_android_tests(android_variant='android_debug_unopt', adb_path=None):
754 if adb_path is None:
755 adb_path = 'adb'
756
757 run_android_unittest('flutter_shell_native_unittests', android_variant, adb_path)
758 run_android_unittest('impeller_toolkit_android_unittests', android_variant, adb_path)
759
760 systrace_test = os.path.join(BUILDROOT_DIR, 'flutter', 'testing', 'android_systrace_test.py')
761 scenario_apk = os.path.join(OUT_DIR, android_variant, 'firebase_apks', 'scenario_app.apk')
762 run_cmd([
763 systrace_test, '--adb-path', adb_path, '--apk-path', scenario_apk, '--package-name',
764 'dev.flutter.scenarios', '--activity-name', '.PlatformViewsActivity'
765 ])
766
767
768def run_objc_tests(ios_variant='ios_debug_sim_unopt', test_filter=None):
769 """Runs Objective-C XCTest unit tests for the iOS embedding"""
771 ios_out_dir = os.path.join(OUT_DIR, ios_variant)
772 ensure_ios_tests_are_built(ios_out_dir)
773
774 new_simulator_name = 'IosUnitTestsSimulator'
775
776 # Delete simulators with this name in case any were leaked
777 # from another test run.
778 delete_simulator(new_simulator_name)
779
780 create_simulator = [
781 'xcrun '
782 'simctl '
783 'create '
784 '%s com.apple.CoreSimulator.SimDeviceType.iPhone-11' % new_simulator_name
785 ]
786 run_cmd(create_simulator, shell=True)
787
788 try:
789 ios_unit_test_dir = os.path.join(BUILDROOT_DIR, 'flutter', 'testing', 'ios', 'IosUnitTests')
790
791 with tempfile.TemporaryDirectory(suffix='ios_embedding_xcresult') as result_bundle_temp:
792 result_bundle_path = os.path.join(result_bundle_temp, 'ios_embedding')
793
794 # Avoid using xcpretty unless the following can be addressed:
795 # - Make sure all relevant failure output is printed on a failure.
796 # - Make sure that a failing exit code is set for CI.
797 # See https://github.com/flutter/flutter/issues/63742
798 test_command = [
799 'xcodebuild '
800 '-sdk iphonesimulator '
801 '-scheme IosUnitTests '
802 '-resultBundlePath ' + result_bundle_path + ' '
803 '-destination name=' + new_simulator_name + ' '
804 'test '
805 'FLUTTER_ENGINE=' + ios_variant
806 ]
807 if test_filter is not None:
808 test_command[0] = test_command[0] + ' -only-testing:%s' % test_filter
809 try:
810 run_cmd(test_command, cwd=ios_unit_test_dir, shell=True)
811
812 except:
813 # The LUCI environment may provide a variable containing a directory path
814 # for additional output files that will be uploaded to cloud storage.
815 # Upload the xcresult when the tests fail.
816 luci_test_outputs_path = os.environ.get('FLUTTER_TEST_OUTPUTS_DIR')
817 xcresult_bundle = os.path.join(result_bundle_temp, 'ios_embedding.xcresult')
818 if luci_test_outputs_path and os.path.exists(xcresult_bundle):
819 dump_path = os.path.join(luci_test_outputs_path, 'ios_embedding.xcresult')
820 # xcresults contain many little files. Archive the bundle before upload.
821 shutil.make_archive(dump_path, 'zip', root_dir=xcresult_bundle)
822 raise
823
824 finally:
825 delete_simulator(new_simulator_name)
826
827
828def delete_simulator(simulator_name):
829 # Will delete all simulators with this name.
830 command = [
831 'xcrun',
832 'simctl',
833 'delete',
834 simulator_name,
835 ]
836 # Let this fail if the simulator was never created.
837 run_cmd(command, expect_failure=True)
838
839
840def gather_dart_tests(build_dir, test_filter):
841 dart_tests_dir = os.path.join(
842 BUILDROOT_DIR,
843 'flutter',
844 'testing',
845 'dart',
846 )
847
848 # Now that we have the Sky packages at the hardcoded location, run `dart pub get`.
850 build_dir,
851 os.path.join('dart-sdk', 'bin', 'dart'),
852 None,
853 flags=['pub', '--suppress-analytics', 'get', '--offline'],
854 cwd=dart_tests_dir,
855 )
856
857 dart_observatory_tests = glob.glob('%s/observatory/*_test.dart' % dart_tests_dir)
858 dart_tests = glob.glob('%s/*_test.dart' % dart_tests_dir)
859
860 if 'release' not in build_dir:
861 for dart_test_file in dart_observatory_tests:
862 if test_filter is not None and os.path.basename(dart_test_file) not in test_filter:
863 logger.info("Skipping '%s' due to filter.", dart_test_file)
864 else:
865 logger.info("Gathering dart test '%s' with observatory enabled", dart_test_file)
866 for multithreaded in [False, True]:
867 for enable_impeller in [False, True]:
868 yield gather_dart_test(
869 build_dir, dart_test_file,
871 multithreaded=multithreaded,
872 enable_impeller=enable_impeller,
873 enable_observatory=True
874 )
875 )
876
877 for dart_test_file in dart_tests:
878 if test_filter is not None and os.path.basename(dart_test_file) not in test_filter:
879 logger.info("Skipping '%s' due to filter.", dart_test_file)
880 else:
881 logger.info("Gathering dart test '%s'", dart_test_file)
882 for multithreaded in [False, True]:
883 for enable_impeller in [False, True]:
884 yield gather_dart_test(
885 build_dir, dart_test_file,
886 FlutterTesterOptions(multithreaded=multithreaded, enable_impeller=enable_impeller)
887 )
888
889
890def gather_dart_smoke_test(build_dir, test_filter):
891 smoke_test = os.path.join(
892 BUILDROOT_DIR,
893 'flutter',
894 'testing',
895 'smoke_test_failure',
896 'fail_test.dart',
897 )
898 if test_filter is not None and os.path.basename(smoke_test) not in test_filter:
899 logger.info("Skipping '%s' due to filter.", smoke_test)
900 else:
901 yield gather_dart_test(
902 build_dir, smoke_test, FlutterTesterOptions(multithreaded=True, expect_failure=True)
903 )
904 yield gather_dart_test(
905 build_dir, smoke_test, FlutterTesterOptions(multithreaded=False, expect_failure=True)
906 )
907
908
909def gather_dart_package_tests(build_dir, package_path, extra_opts):
910 dart_tests = glob.glob('%s/test/*_test.dart' % package_path)
911 if not dart_tests:
912 raise Exception('No tests found for Dart package at %s' % package_path)
913 for dart_test_file in dart_tests:
914 opts = ['--disable-dart-dev', dart_test_file] + extra_opts
916 build_dir, os.path.join('dart-sdk', 'bin', 'dart'), None, flags=opts, cwd=package_path
917 )
918
919
920# Returns a list of Dart packages to test.
921#
922# The first element of each tuple in the returned list is the path to the Dart
923# package to test. It is assumed that the packages follow the convention that
924# tests are named as '*_test.dart', and reside under a directory called 'test'.
925#
926# The second element of each tuple is a list of additional command line
927# arguments to pass to each of the packages tests.
929 dart_host_tests = [
930 (
931 os.path.join('flutter', 'ci'),
932 [os.path.join(BUILDROOT_DIR, 'flutter')],
933 ),
934 (
935 os.path.join('flutter', 'flutter_frontend_server'),
936 [
937 build_dir,
938 os.path.join(build_dir, 'gen', 'frontend_server_aot.dart.snapshot'),
939 os.path.join(build_dir, 'flutter_patched_sdk')
940 ],
941 ),
942 (os.path.join('flutter', 'testing', 'litetest'), []),
943 (os.path.join('flutter', 'testing', 'pkg_test_demo'), []),
944 (os.path.join('flutter', 'testing', 'skia_gold_client'), []),
945 (os.path.join('flutter', 'testing', 'scenario_app'), []),
946 (
947 os.path.join('flutter', 'tools', 'api_check'),
948 [os.path.join(BUILDROOT_DIR, 'flutter')],
949 ),
950 (os.path.join('flutter', 'tools', 'build_bucket_golden_scraper'), []),
951 (os.path.join('flutter', 'tools', 'clang_tidy'), []),
952 (
953 os.path.join('flutter', 'tools', 'const_finder'),
954 [
955 os.path.join(build_dir, 'gen', 'frontend_server_aot.dart.snapshot'),
956 os.path.join(build_dir, 'flutter_patched_sdk'),
957 os.path.join(build_dir, 'dart-sdk', 'lib', 'libraries.json'),
958 ],
959 ),
960 (os.path.join('flutter', 'tools', 'dir_contents_diff'), []),
961 (os.path.join('flutter', 'tools', 'engine_tool'), []),
962 (os.path.join('flutter', 'tools', 'githooks'), []),
963 (os.path.join('flutter', 'tools', 'header_guard_check'), []),
964 (os.path.join('flutter', 'tools', 'pkg', 'engine_build_configs'), []),
965 (os.path.join('flutter', 'tools', 'pkg', 'engine_repo_tools'), []),
966 (os.path.join('flutter', 'tools', 'pkg', 'git_repo_tools'), []),
967 ]
968 if not is_asan(build_dir):
969 dart_host_tests += [
970 (os.path.join('flutter', 'tools', 'path_ops', 'dart'), []),
971 ]
972
973 return dart_host_tests
974
975
976def run_benchmark_tests(build_dir):
977 test_dir = os.path.join(BUILDROOT_DIR, 'flutter', 'testing', 'benchmark')
978 dart_tests = glob.glob('%s/test/*_test.dart' % test_dir)
979 for dart_test_file in dart_tests:
980 opts = ['--disable-dart-dev', dart_test_file]
982 build_dir, os.path.join('dart-sdk', 'bin', 'dart'), None, flags=opts, cwd=test_dir
983 )
984
985
986def worker_init(queue, level):
987 queue_handler = logging.handlers.QueueHandler(queue)
988 log = logging.getLogger(__name__)
989 log.setLevel(logging.INFO)
990 queue_handler.setLevel(level)
991 log.addHandler(queue_handler)
992
993
995 # Work around a bug in Python.
996 #
997 # The multiprocessing package relies on the win32 WaitForMultipleObjects()
998 # call, which supports waiting on a maximum of MAXIMUM_WAIT_OBJECTS (defined
999 # by Windows to be 64) handles, processes in this case. To avoid hitting
1000 # this, we limit ourselves to 60 handles (since there are a couple extra
1001 # processes launched for the queue reader and thread wakeup reader).
1002 #
1003 # See: https://bugs.python.org/issue26903
1004 max_processes = multiprocessing.cpu_count()
1005 if sys_platform.startswith(('cygwin', 'win')) and max_processes > 60:
1006 max_processes = 60
1007
1008 queue = multiprocessing.Queue()
1009 queue_listener = logging.handlers.QueueListener(
1010 queue,
1011 console_logger_handler,
1012 file_logger_handler,
1013 respect_handler_level=True,
1014 )
1015 queue_listener.start()
1016
1017 failures = []
1018 try:
1019 with multiprocessing.Pool(max_processes, worker_init,
1020 [queue, logger.getEffectiveLevel()]) as pool:
1021 async_results = [(t, pool.apply_async(t, ())) for t in tasks]
1022 for task, async_result in async_results:
1023 try:
1024 async_result.get()
1025 except Exception as exn: # pylint: disable=broad-except
1026 failures += [(task, exn)]
1027 finally:
1028 queue_listener.stop()
1029
1030 if len(failures) > 0:
1031 logger.error('The following commands failed:')
1032 for task, exn in failures:
1033 logger.error('%s\n %s\n\n', str(task), str(exn))
1034 return False
1035
1036 return True
1037
1038
1040 """
1041 A scoped change in the CWD.
1042 """
1043 old_cwd: str = ''
1044 new_cwd: str = ''
1045
1046 def __init__(self, new_cwd: str):
1047 self.new_cwd = new_cwd
1048
1049 def __enter__(self):
1050 self.old_cwd = os.getcwd()
1051 os.chdir(self.new_cwd)
1052
1053 def __exit__(self, exception_type, exception_value, exception_traceback):
1054 os.chdir(self.old_cwd)
1055
1056
1057def run_impeller_golden_tests(build_dir: str, require_skia_gold: bool = False):
1058 """
1059 Executes the impeller golden image tests from in the `variant` build.
1060 """
1061 tests_path: str = os.path.join(build_dir, 'impeller_golden_tests')
1062 if not os.path.exists(tests_path):
1063 raise Exception(
1064 'Cannot find the "impeller_golden_tests" executable in "%s". You may need to build it.' %
1065 (build_dir)
1066 )
1067 harvester_path: Path = Path(SCRIPT_DIR).parent.joinpath('tools'
1068 ).joinpath('golden_tests_harvester')
1069
1070 with tempfile.TemporaryDirectory(prefix='impeller_golden') as temp_dir:
1071 extra_env = metal_validation_env()
1072 extra_env.update(vulkan_validation_env(build_dir))
1073 run_cmd([tests_path, f'--working_dir={temp_dir}'], cwd=build_dir, env=extra_env)
1074 dart_bin = os.path.join(build_dir, 'dart-sdk', 'bin', 'dart')
1075 golden_path = os.path.join('testing', 'impeller_golden_tests_output.txt')
1076 script_path = os.path.join('tools', 'dir_contents_diff', 'bin', 'dir_contents_diff.dart')
1077 diff_result = subprocess.run(
1078 f'{dart_bin} --disable-dart-dev {script_path} {golden_path} {temp_dir}',
1079 check=False,
1080 shell=True,
1081 stdout=subprocess.PIPE,
1082 cwd=os.path.join(BUILDROOT_DIR, 'flutter')
1083 )
1084 if diff_result.returncode != 0:
1085 print_divider('<')
1086 print(diff_result.stdout.decode())
1087 raise RuntimeError('impeller_golden_tests diff failure')
1088
1089 if not require_skia_gold:
1090 print_divider('<')
1091 print('Skipping any SkiaGoldClient invocation as the --no-skia-gold flag was set.')
1092 return
1093
1094 # On release builds and local builds, we typically do not have GOLDCTL set,
1095 # which on other words means that this invoking the SkiaGoldClient would
1096 # throw. Skip this step in those cases and log a notice.
1097 if 'GOLDCTL' not in os.environ:
1098 # On CI, we never want to be running golden tests without Skia Gold.
1099 # See https://github.com/flutter/flutter/issues/147180 as an example.
1100 is_luci = 'LUCI_CONTEXT' in os.environ
1101 if is_luci:
1102 raise RuntimeError(
1103 """
1104The GOLDCTL environment variable is not set. This is required for Skia Gold tests.
1105See https://github.com/flutter/engine/tree/main/testing/skia_gold_client#configuring-ci
1106for more information.
1107"""
1108 )
1109
1110 print_divider('<')
1111 print(
1112 'Skipping the SkiaGoldClient invocation as the GOLDCTL environment variable is not set.'
1113 )
1114 return
1115
1116 with DirectoryChange(harvester_path):
1117 bin_path = Path('.').joinpath('bin').joinpath('golden_tests_harvester.dart')
1118 run_cmd([dart_bin, '--disable-dart-dev', str(bin_path), temp_dir])
1119
1120
1121def main():
1122 parser = argparse.ArgumentParser(
1123 description="""
1124In order to learn the details of running tests in the engine, please consult the
1125Flutter Wiki page on the subject: https://github.com/flutter/flutter/wiki/Testing-the-engine
1126"""
1127 )
1128 all_types = [
1129 'engine',
1130 'dart',
1131 'dart-host',
1132 'benchmarks',
1133 'java',
1134 'android',
1135 'objc',
1136 'font-subset',
1137 'impeller-golden',
1138 ]
1139
1140 parser.add_argument(
1141 '--variant',
1142 dest='variant',
1143 action='store',
1144 default='host_debug_unopt',
1145 help='The engine build variant to run the tests for.'
1146 )
1147 parser.add_argument(
1148 '--type',
1149 type=str,
1150 default='all',
1151 help='A list of test types, default is "all" (equivalent to "%s")' % (','.join(all_types))
1152 )
1153 parser.add_argument(
1154 '--engine-filter', type=str, default='', help='A list of engine test executables to run.'
1155 )
1156 parser.add_argument(
1157 '--dart-filter',
1158 type=str,
1159 default='',
1160 help='A list of Dart test script base file names to run in '
1161 'flutter_tester (example: "image_filter_test.dart").'
1162 )
1163 parser.add_argument(
1164 '--dart-host-filter',
1165 type=str,
1166 default='',
1167 help='A list of Dart test scripts to run with the Dart CLI.'
1168 )
1169 parser.add_argument(
1170 '--java-filter',
1171 type=str,
1172 default='',
1173 help='A single Java test class to run (example: "io.flutter.SmokeTest")'
1174 )
1175 parser.add_argument(
1176 '--android-variant',
1177 dest='android_variant',
1178 action='store',
1179 default='android_debug_unopt',
1180 help='The engine build variant to run java or android tests for'
1181 )
1182 parser.add_argument(
1183 '--ios-variant',
1184 dest='ios_variant',
1185 action='store',
1186 default='ios_debug_sim_unopt',
1187 help='The engine build variant to run objective-c tests for'
1188 )
1189 parser.add_argument(
1190 '--verbose-dart-snapshot',
1191 dest='verbose_dart_snapshot',
1192 action='store_true',
1193 default=False,
1194 help='Show extra dart snapshot logging.'
1195 )
1196 parser.add_argument(
1197 '--objc-filter',
1198 type=str,
1199 default=None,
1200 help=(
1201 'Filter parameter for which objc tests to run '
1202 '(example: "IosUnitTestsTests/SemanticsObjectTest/testShouldTriggerAnnouncement")'
1203 )
1204 )
1205 parser.add_argument(
1206 '--coverage',
1207 action='store_true',
1208 default=None,
1209 help='Generate coverage reports for each unit test framework run.'
1210 )
1211 parser.add_argument(
1212 '--engine-capture-core-dump',
1213 dest='engine_capture_core_dump',
1214 action='store_true',
1215 default=False,
1216 help='Capture core dumps from crashes of engine tests.'
1217 )
1218 parser.add_argument(
1219 '--use-sanitizer-suppressions',
1220 dest='sanitizer_suppressions',
1221 action='store_true',
1222 default=False,
1223 help='Provide the sanitizer suppressions lists to the via environment to the tests.'
1224 )
1225 parser.add_argument(
1226 '--adb-path',
1227 dest='adb_path',
1228 action='store',
1229 default=None,
1230 help='Provide the path of adb used for android tests. By default it looks on $PATH.'
1231 )
1232 parser.add_argument(
1233 '--quiet',
1234 dest='quiet',
1235 action='store_true',
1236 default=False,
1237 help='Only emit output when there is an error.'
1238 )
1239 parser.add_argument(
1240 '--logs-dir',
1241 dest='logs_dir',
1242 type=str,
1243 help='The directory that verbose logs will be copied to in --quiet mode.',
1244 )
1245 parser.add_argument(
1246 '--no-skia-gold',
1247 dest='no_skia_gold',
1248 action='store_true',
1249 default=False,
1250 help='Do not compare golden images with Skia Gold.',
1251 )
1252
1253 args = parser.parse_args()
1254
1255 logger.addHandler(console_logger_handler)
1256 logger.addHandler(file_logger_handler)
1257 logger.setLevel(logging.INFO)
1258 if args.quiet:
1259 file_logger_handler.setLevel(logging.INFO)
1260 console_logger_handler.setLevel(logging.WARNING)
1261 else:
1262 console_logger_handler.setLevel(logging.INFO)
1263
1264 if args.type == 'all':
1265 types = all_types
1266 else:
1267 types = args.type.split(',')
1268
1269 build_dir = os.path.join(OUT_DIR, args.variant)
1270 if args.type != 'java' and args.type != 'android':
1271 assert os.path.exists(build_dir), 'Build variant directory %s does not exist!' % build_dir
1272
1273 if args.sanitizer_suppressions:
1274 assert is_linux() or is_mac(
1275 ), 'The sanitizer suppressions flag is only supported on Linux and Mac.'
1276 file_dir = os.path.dirname(os.path.abspath(__file__))
1277 command = [
1278 'env', '-i', 'bash', '-c',
1279 'source {}/sanitizer_suppressions.sh >/dev/null && env'.format(file_dir)
1280 ]
1281 process = subprocess.Popen(command, stdout=subprocess.PIPE)
1282 for line in process.stdout:
1283 key, _, value = line.decode('utf8').strip().partition('=')
1284 os.environ[key] = value
1285 process.communicate() # Avoid pipe deadlock while waiting for termination.
1286
1287 success = True
1288
1289 engine_filter = args.engine_filter.split(',') if args.engine_filter else None
1290 if 'engine' in types:
1291 run_cc_tests(build_dir, engine_filter, args.coverage, args.engine_capture_core_dump)
1292
1293 # Use this type to exclusively run impeller tests.
1294 if 'impeller' in types:
1295 build_name = args.variant
1296 try:
1297 xvfb.start_virtual_x(build_name, build_dir)
1298 extra_env = vulkan_validation_env(build_dir)
1300 build_dir,
1301 'impeller_unittests',
1302 engine_filter,
1303 repeat_flags,
1304 coverage=args.coverage,
1305 extra_env=extra_env,
1306 gtest=True
1307 )
1308 finally:
1309 xvfb.stop_virtual_x(build_name)
1310
1311 if 'dart' in types:
1312 dart_filter = args.dart_filter.split(',') if args.dart_filter else None
1313 tasks = list(gather_dart_smoke_test(build_dir, dart_filter))
1314 tasks += list(gather_dart_tests(build_dir, dart_filter))
1315 success = success and run_engine_tasks_in_parallel(tasks)
1316
1317 if 'dart-host' in types:
1318 dart_filter = args.dart_host_filter.split(',') if args.dart_host_filter else None
1319 dart_host_packages = build_dart_host_test_list(build_dir)
1320 tasks = []
1321 for dart_host_package, extra_opts in dart_host_packages:
1322 if dart_filter is None or dart_host_package in dart_filter:
1323 tasks += list(
1325 build_dir,
1326 os.path.join(BUILDROOT_DIR, dart_host_package),
1327 extra_opts,
1328 )
1329 )
1330
1331 success = success and run_engine_tasks_in_parallel(tasks)
1332
1333 if 'java' in types:
1334 assert not is_windows(), "Android engine files can't be compiled on Windows."
1335 java_filter = args.java_filter
1336 if ',' in java_filter or '*' in java_filter:
1337 logger.wraning(
1338 'Can only filter JUnit4 tests by single entire class name, '
1339 'eg "io.flutter.SmokeTest". Ignoring filter=' + java_filter
1340 )
1341 java_filter = None
1342 run_java_tests(java_filter, args.android_variant)
1343
1344 if 'android' in types:
1345 assert not is_windows(), "Android engine files can't be compiled on Windows."
1346 run_android_tests(args.android_variant, args.adb_path)
1347
1348 if 'objc' in types:
1349 assert is_mac(), 'iOS embedding tests can only be run on macOS.'
1350 run_objc_tests(args.ios_variant, args.objc_filter)
1351
1352 # https://github.com/flutter/flutter/issues/36300
1353 if 'benchmarks' in types and not is_windows():
1354 run_benchmark_tests(build_dir)
1355 run_engine_benchmarks(build_dir, engine_filter)
1356
1357 variants_to_skip = ['host_release', 'host_profile']
1358
1359 def should_skip(variant):
1360 matches = [variant for variant in variants_to_skip if variant in args.variant]
1361 return len(matches) > 0
1362
1363 if ('engine' in types or 'font-subset' in types) and not should_skip(args.variant):
1364 cmd = ['python3', 'test.py', '--variant', args.variant]
1365 if 'arm64' in args.variant:
1366 cmd += ['--target-cpu', 'arm64']
1367 run_cmd(cmd, cwd=FONT_SUBSET_DIR)
1368
1369 if 'impeller-golden' in types:
1370 run_impeller_golden_tests(build_dir, require_skia_gold=not args.no_skia_gold)
1371
1372 if args.quiet and args.logs_dir:
1373 shutil.copy(LOG_FILE, os.path.join(args.logs_dir, 'run_tests.log'))
1374
1375 return 0 if success else 1
1376
1377
1378if __name__ == '__main__':
1379 sys_exit(main())
static bool should_skip(const char *sink, const char *src, const char *srcOptions, const char *name)
Definition: DM.cpp:1142
def __init__(self, str new_cwd)
Definition: run_tests.py:1046
def __exit__(self, exception_type, exception_value, exception_traceback)
Definition: run_tests.py:1053
def __call__(self, *args)
Definition: run_tests.py:362
def __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
def __init__(self, multithreaded=False, enable_impeller=False, enable_observatory=False, expect_failure=False)
Definition: run_tests.py:596
def apply_args(self, command_args)
Definition: run_tests.py:602
uint32_t uint32_t * format
CanvasPath Path
Definition: dart_ui.cc:58
Definition: main.py:1
def run_android_unittest(test_runner_name, android_variant, adb_path)
Definition: run_tests.py:735
def is_aarm64()
Definition: run_tests.py:137
def gather_dart_tests(build_dir, test_filter)
Definition: run_tests.py:840
def java_bin()
Definition: run_tests.py:700
def build_engine_executable_command(build_dir, executable_name, flags=None, coverage=False, gtest=False)
Definition: run_tests.py:208
def delete_simulator(simulator_name)
Definition: run_tests.py:828
def is_windows()
Definition: run_tests.py:151
def assert_expected_xcode_version()
Definition: run_tests.py:679
def metal_validation_env()
Definition: run_tests.py:188
def run_engine_tasks_in_parallel(tasks)
Definition: run_tests.py:994
def build_dart_host_test_list(build_dir)
Definition: run_tests.py:928
def run_impeller_golden_tests(str build_dir, bool require_skia_gold=False)
Definition: run_tests.py:1057
def gather_dart_package_tests(build_dir, package_path, extra_opts)
Definition: run_tests.py:909
def is_mac()
Definition: run_tests.py:133
def ensure_ios_tests_are_built(ios_out_dir)
Definition: run_tests.py:666
def run_java_tests(executable_filter, android_variant='android_debug_unopt')
Definition: run_tests.py:704
def run_benchmark_tests(build_dir)
Definition: run_tests.py:976
def run_cc_tests(build_dir, executable_filter, coverage, capture_core_dump)
Definition: run_tests.py:393
def find_executable_path(path)
Definition: run_tests.py:159
def gather_dart_test(build_dir, dart_file, options)
Definition: run_tests.py:625
def run_android_tests(android_variant='android_debug_unopt', adb_path=None)
Definition: run_tests.py:753
def 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
def is_linux()
Definition: run_tests.py:147
def worker_init(queue, level)
Definition: run_tests.py:986
def run_objc_tests(ios_variant='ios_debug_sim_unopt', test_filter=None)
Definition: run_tests.py:768
def print_divider(char='=')
Definition: run_tests.py:53
def is_asan(build_dir)
Definition: run_tests.py:60
def main()
Definition: run_tests.py:1121
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
def vulkan_validation_env(build_dir)
Definition: run_tests.py:175
def gather_dart_smoke_test(build_dir, test_filter)
Definition: run_tests.py:890
def executable_suffix()
Definition: run_tests.py:155
def print(*args, **kwargs)
Definition: run_tests.py:49
def java_home()
Definition: run_tests.py:691
def run_engine_benchmarks(build_dir, executable_filter)
Definition: run_tests.py:567
def start_virtual_x(child_build_name, build_dir)
Definition: xvfb.py:27
def stop_virtual_x(child_build_name)
Definition: xvfb.py:138
static SkString join(const CommandLineFlags::StringArray &)
Definition: skpbench.cpp:741