| # Copyright 2023 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Flutter Engine tester recipe. |
| |
| Recipe to run engine scoped tests using prebuilts stored in CAS.. |
| |
| |
| This recipe expects configurations with the following format: |
| |
| { |
| "test_dependencies": [ |
| { |
| "dependency": "chrome_and_driver", "version": "version:111.0" |
| } |
| ], |
| "resolved_deps": [ |
| { |
| "full_build": "f5b9de6cc9f4b05833aa128717d3112c133e2363e4303df9a1951540c79e72a3/87" |
| }, |
| {` |
| "full_build": "32b40edba8bfbf7729374eaa4aa44bf0d89c385f080f64b56c9fbce7172e4a71/84" |
| } |
| ], |
| 'tasks': [ |
| { |
| 'language': 'dart', |
| 'name': 'felt test: chrome-unit-linux', |
| 'parameters': [ |
| 'test', |
| '--browser=chrome', |
| '--require-skia-gold' |
| ], |
| 'script': 'flutter/lib/web_ui/dev/felt' |
| } |
| ] |
| } |
| |
| test_dependnecies - is a list of dictionaries with third party dependencies required for the tests. |
| resolved_deps - is a list of dictionaries with CAS hashes pointing to full sub-build archives. |
| tasks - is a list of dictionaries with the scripts to run in this test sub-build. |
| |
| |
| This recipe will be called from the engine_v2/engine_v2 recipe using the shard_util_v2 module. The |
| test configuration is defined in the engine build configurations files as global tests. |
| """ |
| import contextlib |
| import copy |
| |
| from contextlib import contextmanager |
| |
| from google.protobuf import struct_pb2 |
| from PB.go.chromium.org.luci.buildbucket.proto import build as build_pb2 |
| |
| DEPS = [ |
| 'depot_tools/depot_tools', |
| 'flutter/flutter_deps', |
| 'flutter/logs_util', |
| 'flutter/osx_sdk', |
| 'flutter/os_utils', |
| 'flutter/repo_util', |
| 'flutter/retry', |
| 'flutter/test_utils', |
| 'recipe_engine/cas', |
| 'recipe_engine/context', |
| 'recipe_engine/file', |
| 'recipe_engine/path', |
| 'recipe_engine/platform', |
| 'recipe_engine/properties', |
| 'recipe_engine/step', |
| ] |
| |
| DEFAULT_TEST_TIMEOUT_SECS = 30 * 60 |
| |
| |
| def run_tests(api, test, checkout, env, env_prefixes): |
| """Runs sub-build tests.""" |
| # Collect memory/cpu/process before task execution. |
| api.os_utils.collect_os_info() |
| # Install dependencies. |
| deps = test.get('test_dependencies', []) |
| api.flutter_deps.required_deps(env, env_prefixes, deps) |
| |
| out_path = checkout.join('out') |
| # Download build dependencies. |
| for dep in test.get('resolved_deps', []): |
| out_hash = dep.get('full_build') |
| api.cas.download(f'Download {out_hash}', out_hash, out_path) |
| for task in test.get('tasks', []): |
| command = [task.get('language')] if task.get('language') else [] |
| # Ideally local tests should be completely hermetic and in theory we can run |
| # them in parallel using futures. I haven't found a flutter engine |
| # configuration with more than one local test but once we find it we |
| # should run the list of tests using parallelism. |
| # TODO(godofredoc): Optimize to run multiple local tests in parallel. |
| command.append(checkout.join(task.get('script'))) |
| command.extend(task.get('parameters', [])) |
| step_name = api.test_utils.test_step_name(task.get('name')) |
| test_timeout_secs = task.get('test_timeout_secs', DEFAULT_TEST_TIMEOUT_SECS) |
| |
| def run_test(): |
| return api.step(step_name, command, timeout=test_timeout_secs) |
| |
| api.logs_util.initialize_logs_collection(env) |
| try: |
| # Run within another context to make the logs env variable available to |
| # test scripts. |
| with contextlib.ExitStack() as exit_stack: |
| api.flutter_deps.enter_contexts( |
| exit_stack, test.get('contexts', []), env, env_prefixes |
| ) |
| with api.context(env=env, env_prefixes=env_prefixes): |
| api.retry.wrap( |
| run_test, |
| step_name=task.get('name'), |
| max_attempts=task.get('max_attempts', 3) |
| ) |
| finally: |
| api.logs_util.upload_logs(task.get('name')) |
| # This is to clean up leaked processes. |
| api.os_utils.kill_processes() |
| # Collect memory/cpu/process after task execution. |
| api.os_utils.collect_os_info() |
| |
| |
| def Test(api, checkout, env, env_prefixes): |
| """Runs a global test using prebuilts.""" |
| test = api.properties.get('build') |
| with api.context(env=env, env_prefixes=env_prefixes, |
| cwd=checkout.join('flutter')), api.depot_tools.on_path(): |
| run_tests(api, test, checkout, env, env_prefixes) |
| |
| |
| def RunSteps(api): |
| # Sets the engine environment and checkouts the source code. |
| checkout = api.path['cache'].join('builder', 'src') |
| api.file.rmtree('Clobber build output', checkout.join('out')) |
| cache_root = api.path['cache'].join('builder') |
| api.file.ensure_directory('Ensure checkout cache', cache_root) |
| env, env_prefixes = api.repo_util.engine_environment( |
| api.path['cache'].join('builder') |
| ) |
| # Engine path is used inconsistently across the engine repo. We'll start |
| # with [cache]/builder and will adjust it to start using it consistently. |
| env['ENGINE_PATH'] = api.path['cache'].join('builder') |
| api.repo_util.engine_checkout(cache_root, env, env_prefixes) |
| Test(api, checkout, env, env_prefixes) |
| |
| |
| def GenTests(api): |
| build = { |
| "test_dependencies": [{ |
| "dependency": "chrome_and_driver", "version": "version:111.0" |
| }], "resolved_deps": [{ |
| "full_build": |
| "f5b9de6cc9f4b05833aa128717d3112c133e2363e4303df9a1951540c79e72a3/87" |
| }, { |
| "full_build": |
| "32b40edba8bfbf7729374eaa4aa44bf0d89c385f080f64b56c9fbce7172e4a71/84" |
| }], 'tasks': [{ |
| 'language': 'dart', 'name': 'felt test: chrome-unit-linux', |
| 'parameters': ['test', '--browser=chrome', '--require-skia-gold'], |
| 'script': 'flutter/lib/web_ui/dev/felt' |
| }], "contexts": ["osx_sdk"] |
| } |
| yield api.test( |
| 'basic', |
| api.properties(build=build), |
| ) |