| # Copyright 2023 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import itertools |
| |
| from recipe_engine import post_process |
| from recipe_engine.config_types import Path |
| from recipe_engine.post_process import LogEquals |
| |
| from PB.go.chromium.org.luci.buildbucket.proto import common as common_pb |
| from PB.recipes.build.chromium.fuzz import InputProperties |
| |
| from RECIPE_MODULES.build import chromium_tests_builder_config as ctbc |
| |
| from dataclasses import dataclass |
| |
| from recipe_engine.recipe_api import RecipeScriptApi |
| from recipe_engine.recipe_test_api import RecipeTestApi |
| |
| from RECIPE_MODULES.build import ( |
| archive, |
| chromium, |
| chromium_checkout, |
| chromium_tests, |
| chromium_tests_builder_config, |
| code_coverage, |
| filter as filter_module, |
| gn, |
| profiles, |
| ) |
| from RECIPE_MODULES.depot_tools import depot_tools, gsutil, tryserver |
| from RECIPE_MODULES.recipe_engine import ( |
| buildbucket, |
| context, |
| file, |
| json, |
| path, |
| platform, |
| properties, |
| raw_io, |
| runtime, |
| step, |
| ) |
| |
| |
| @dataclass |
| class DEPS(RecipeScriptApi): |
| archive: archive.API |
| buildbucket: buildbucket.API |
| chromium: chromium.API |
| chromium_checkout: chromium_checkout.API |
| chromium_tests: chromium_tests.API |
| chromium_tests_builder_config: chromium_tests_builder_config.API |
| code_coverage: code_coverage.API |
| context: context.API |
| depot_tools: depot_tools.API |
| file: file.API |
| filter: filter_module.API |
| gn: gn.API |
| gsutil: gsutil.API |
| json: json.API |
| path: path.API |
| platform: platform.API |
| profiles: profiles.API |
| properties: properties.API |
| raw_io: raw_io.API |
| runtime: runtime.API |
| step: step.API |
| tryserver: tryserver.API |
| |
| |
| @dataclass |
| class TEST_DEPS(RecipeTestApi): |
| chromium_tests_builder_config: chromium_tests_builder_config.TEST_API |
| file: file.TEST_API |
| filter: filter_module.TEST_API |
| gn: gn.TEST_API |
| path: path.TEST_API |
| platform: platform.TEST_API |
| properties: properties.TEST_API |
| raw_io: raw_io.TEST_API |
| |
| |
| PROPERTIES = InputProperties |
| |
| # The name of the manifest file that will be written to the archive's build |
| # directory to store metadata about the archive for use by ClusterFuzz. |
| MANIFEST_FILENAME = 'clusterfuzz_manifest.json' |
| |
| # The archive schema version that builders without a specified version should |
| # archive in. |
| # 0: Archive root is at the build directory and contains `src_root` directory. |
| # 1: Archive root is at the source directory. |
| DEFAULT_ARCHIVE_SCHEMA_VERSION = 0 |
| |
| |
| def gn_refs( |
| api: DEPS, build_dir: Path, step_name, target, output_type='executable' |
| ): |
| """Runs gn refs to calculate targets depending on target. |
| Returns: the set of matched targets. |
| """ |
| raw_output = api.gn.refs( |
| build_dir, |
| [target], |
| output_type=output_type, |
| step_name=step_name, |
| output_format='label', |
| ) |
| # Filter out lines starting with "Warning: is_asan " |
| return { |
| line for line in raw_output if not line.startswith('Warning: is_asan ') |
| } |
| |
| |
| def copy_path(api: DEPS, source_dir: Path, build_dir: Path, path_name: str): |
| """Copies the path_name, which could be a file or a directory |
| into ${build_dir}/src_root. |
| """ |
| src = build_dir / path_name |
| # relative_to() raises ValueError if src is not inside source_dir. |
| dest = build_dir / 'src_root' / src.relative_to(source_dir) |
| if api.path.exists(dest): |
| # Nothing to be done as this file/directory already exists in destination. |
| return |
| if api.path.isfile(src): |
| dstfolder = api.path.dirname(dest) |
| if not api.path.exists(dstfolder): |
| # Make sure the destination folder exists. |
| api.file.ensure_directory('ensure builder cache dir', dstfolder) |
| api.file.copy('copying file:' + str(src), src, dest) |
| else: |
| api.file.copytree('copying directory:' + str(src), src, dest) |
| |
| |
| def filter_runtime_deps( |
| runtime_deps: list[str], gn_targets: set[str] |
| ) -> set[str]: |
| """Get the subset of runtime dependencies for the specified targets. |
| |
| The list of runtime dependencies has the following format: |
| some compiler warning |
| some compiler warning2 |
| Target target1 |
| runtime_deps |
| ./path/to/dependency1 |
| ../../path/to/dependency2 |
| Target target2 |
| runtime_deps |
| ./path/to/dependency3 |
| ../../path/to/dependency4 |
| """ |
| result = set() |
| is_collecting = False |
| TARGET_PREFIX = 'Target ' |
| |
| for line in runtime_deps: |
| if line.startswith(TARGET_PREFIX): |
| target_name = line[len(TARGET_PREFIX) :] |
| is_collecting = target_name in gn_targets |
| elif is_collecting: |
| # lines corresponding to runtime dependencies start with spaces. |
| dependency = line.strip() |
| if dependency and dependency != 'runtime_deps': |
| result.add(dependency) |
| return result |
| |
| |
| # How many elements to return per batch by `batched()`. |
| # |
| # Picked by checking how many arguments was finally too much for the Windows |
| # command line in https://crbug.com/1477042: 629! |
| BATCH_SIZE = 500 |
| |
| |
| def batched(iterable): |
| """Batch `iterable` into lists of length `BATCH_SIZE`. |
| |
| The last batch may be shorter. |
| |
| For example, for `BATCH_SIZE == 3`, `batched('ABCDEFG')` yields: |
| |
| ['A', 'B', 'C'] |
| ['D', 'E', 'F'] |
| ['G'] |
| |
| Shamelessly cribbed from the `itertools` python module's docs. |
| """ |
| it = iter(iterable) |
| |
| # `islice(it, n)` returns an iterator over the first `n` elements of `it`. |
| while batch := list(itertools.islice(it, BATCH_SIZE)): |
| yield batch |
| |
| |
| def get_target_cpu(api: DEPS, gn_args): |
| args = api.gn.parse_gn_args(gn_args) |
| return str(args.get('target_cpu')).replace('"', '') |
| |
| |
| def gn_ls_with_filter(api: DEPS, build_dir, inputs, **kwargs): |
| """Wraps api.gn.ls to filter out 'is_asan' warnings.""" |
| raw_output = api.gn.ls(build_dir, inputs, **kwargs) |
| return { |
| line for line in raw_output if not line.startswith('Warning: is_asan ') |
| } |
| |
| |
| def RunSteps(api: DEPS, properties): |
| builder_id, builder_config = ( |
| api.chromium_tests_builder_config.lookup_builder() |
| ) |
| api.chromium_tests.configure_build(builder_config) |
| |
| # Most CI fuzz bots clobber. But we don't want the trybots clobbering, since |
| # some of them are on the CQ. |
| should_clobber = ( |
| api.chromium.c.clobber_before_runhooks and not api.tryserver.is_tryserver |
| ) |
| update_result = api.chromium_checkout.ensure_checkout() |
| checkout_dir = update_result.checkout_dir |
| source_dir = update_result.source_root.path |
| api.profiles.source_dir = source_dir |
| build_dir = api.chromium.default_build_dir(source_dir) |
| |
| api.chromium.ensure_toolchains(checkout_dir) |
| api.chromium.runhooks(source_dir, build_dir, clobber=should_clobber) |
| gn_args = api.chromium.mb_gen(source_dir, build_dir, builder_id) |
| with api.context(cwd=source_dir, env=api.chromium.get_env(source_dir)): |
| if properties.fuzz_engine == 'fuzzilli': |
| # compile d8 to run fuzzilli fuzz tests |
| targets = ['d8'] |
| raw_result = api.chromium.compile(source_dir, build_dir, targets=targets) |
| |
| if raw_result.status != common_pb.SUCCESS: |
| return raw_result |
| else: |
| # compile targets for libfuzzer or centipede |
| gn_output_type = 'executable' |
| if api.chromium.c.TARGET_PLATFORM == 'android': |
| gn_output_type = 'shared_library' |
| |
| all_fuzzers = gn_refs( |
| api, |
| build_dir, |
| 'calculate all_fuzzers', |
| '//testing/libfuzzer:fuzzing_engine', |
| output_type=gn_output_type, |
| ) |
| if properties.v8_targets_only: |
| # Some builders only need the V8 targets as the only difference is code |
| # generated by V8 simulators. |
| v8_fuzzers = gn_refs( |
| api, |
| build_dir, |
| 'calculate v8_fuzzers', |
| '//v8:fuzzer_support', |
| output_type=gn_output_type, |
| ) |
| all_fuzzers = all_fuzzers & v8_fuzzers |
| elif properties.ios_targets_only: |
| ios_fuzzers = gn_refs( |
| api, |
| build_dir, |
| 'calculate ios_fuzzers', |
| '//testing/libfuzzer:build_for_ios_clusterfuzz_job', |
| output_type=gn_output_type, |
| ) |
| all_fuzzers = all_fuzzers & ios_fuzzers |
| no_clusterfuzz = gn_refs( |
| api, |
| build_dir, |
| 'calculate no_clusterfuzz', |
| '//testing/libfuzzer:no_clusterfuzz', |
| output_type=gn_output_type, |
| ) |
| # If we're collecting coverage, build the main `chrome` binary to ensure |
| # that all files that make up the binary show up in the coverage report. |
| # Otherwise, the report includes only files that get built for at least |
| # one fuzzer, which misses a big proportion of Chromium code, and we get a |
| # false picture of how well the codebase is covered. |
| if properties.collect_fuzz_coverage: |
| # `gn ls ... chrome --as=output` will output `phony/chrome/chrome` [0], |
| # which can be passed to `compile()` but doesn't represent a path to |
| # the real `chrome` executable. On Linux we need to give `gn ls` the |
| # `//chrome:chrome_initial` label that actually outputs the executable. |
| # |
| # On macOS, `//chrome:chrome_app` is a `create_bundle` target that |
| # resolves to `phony/chrome/chrome_app`, which `llvm-cov` cannot open. |
| # Use `//chrome:chrome_framework_shared_library` instead, which outputs |
| # the real `Chromium Framework` Mach-O binary containing Chrome's code. |
| # On Windows, `//chrome:chrome_initial` builds the thin launcher |
| # (`initialexe/chrome.exe`), whereas Chrome's code lives in |
| # `//chrome:chrome_dll`. |
| # |
| # [0]: https://gn.googlesource.com/gn/+/master/docs/reference.md#phony-rules |
| if api.platform.is_win: |
| all_fuzzers.add('//chrome:chrome_dll') |
| elif api.platform.is_linux: |
| all_fuzzers.add('//chrome:chrome_initial') |
| elif api.platform.is_mac: |
| all_fuzzers.add('//chrome:chrome_framework_shared_library') |
| targets = sorted(all_fuzzers - no_clusterfuzz) |
| |
| api.step.active_result.presentation.logs['all_fuzzers'] = sorted( |
| all_fuzzers |
| ) |
| api.step.active_result.presentation.logs['no_clusterfuzz'] = sorted( |
| no_clusterfuzz |
| ) |
| api.step.active_result.presentation.logs['targets'] = targets |
| |
| should_analyze = ( |
| not api.runtime.is_experimental |
| and api.tryserver.is_tryserver |
| and not properties.collect_fuzz_coverage |
| ) |
| if should_analyze: |
| # Filter out all targets that the patch doesn't affect. |
| affected_files = api.chromium_checkout.get_files_affected_by_patch() |
| test_targets, compile_targets = api.filter.analyze( |
| source_dir, build_dir, affected_files, None, targets |
| ) |
| targets = sorted(test_targets + compile_targets) |
| if not targets: |
| return |
| |
| # On android the fuzzers are built as shared libraries inside APKs, so the |
| # strategy is to find the library but then recover the main target name by |
| # removing the __library suffix |
| if api.chromium.c.TARGET_PLATFORM == 'android': |
| targets = [t.removesuffix('__library') for t in targets] |
| |
| # Up until now we work in terms of GN labels so that we can use |
| # api.filter.analyze above in the trybot case. We now convert the |
| # GN labels to ninja targets and pass them into compile. |
| |
| gn_targets = targets |
| |
| # `targets` can grow to be quite large, larger than can fit on a Windows |
| # command line... We work around this by batching `gn ls` invocations. |
| # |
| # TODO(https://crbug.com/1477042): Define a static list of fuzzer targets |
| # in the build instead of dynamically generating it based on `gn refs` in |
| # this manner. |
| target_set = set() |
| for target_batch in batched(targets): |
| target_set |= gn_ls_with_filter( |
| api, build_dir, target_batch, output_format='output' |
| ) |
| |
| targets = list(target_set) |
| targets.sort() # Ensure stable order for tests. |
| |
| # For iOS, the target list from |api.gn.refs| is a list of paths like |
| # obj/.../XXX_fuzzer. The last part of the path is the target name to be |
| # compiled. |
| if api.chromium.c.TARGET_PLATFORM == 'ios': |
| targets = [api.path.basename(target) for target in targets] |
| |
| # Same as above, the list of targets can grow so large that Windows chokes |
| # on a single `ninja` invocation against the full list. |
| # |
| # TODO(https://crbug.com/1477042): Define a static target that builds all |
| # fuzzers for ClusterFuzz instead of dynamically generating it like this. |
| raw_result = None |
| for target_batch in batched(targets): |
| raw_result = api.chromium.compile( |
| source_dir, build_dir, targets=target_batch |
| ) |
| |
| if raw_result.status != common_pb.SUCCESS: |
| return raw_result |
| |
| if not properties.collect_fuzz_coverage and not api.tryserver.is_tryserver: |
| assert properties.upload_bucket, 'upload_bucket property is required' |
| |
| if properties.collect_fuzz_coverage: |
| try: |
| corpora_dir = source_dir / 'current-corpora-from-clusterfuzz' |
| profdata_dir = source_dir / 'out' / 'profdata-output-dir' |
| api.file.rmtree('ensure corpora directory blank', corpora_dir) |
| api.file.ensure_directory('make corpora directory', corpora_dir) |
| api.file.rmtree('ensure profdata directory blank', profdata_dir) |
| api.file.ensure_directory('make profdata directory', profdata_dir) |
| download_cmd = [ |
| 'python3', |
| 'tools/code_coverage/download_fuzz_corpora.py', |
| '--download-dir', |
| corpora_dir, |
| '--build-dir', |
| build_dir, |
| '--corpora-type', |
| properties.fuzz_engine, |
| ] |
| if properties.fuzz_engine == 'fuzzilli': |
| download_cmd.extend(['--arch', get_target_cpu(api, gn_args)]) |
| api.step('download corpora', download_cmd) |
| |
| run_cmd = [ |
| 'python3', |
| 'tools/code_coverage/run_all_fuzzers.py', |
| '--fuzzer-binaries-dir', |
| build_dir, |
| '--fuzzer-corpora-dir', |
| corpora_dir, |
| '--profdata-outdir', |
| profdata_dir, |
| '--fuzzer', |
| properties.fuzz_engine, |
| ] |
| if properties.fuzz_engine != 'fuzzilli': |
| target_list_dir = source_dir / 'out' / 'target-list-dir' |
| api.file.rmtree('ensure target list directory blank', target_list_dir) |
| api.file.ensure_directory( |
| 'make target list directory', target_list_dir |
| ) |
| run_cmd.extend(['--target-list-dir', target_list_dir]) |
| |
| if api.platform.is_linux: |
| withxvfb_path = api.repo_resource('recipes', 'withxvfb.py') |
| withxvfb_args = [ |
| '--target', |
| api.chromium.c.build_config_fs, |
| '--build-dir=%s' % build_dir, |
| ] |
| run_cmd = ( |
| ['python3', withxvfb_path] + withxvfb_args + ['--'] + run_cmd |
| ) |
| |
| api.step('run all fuzzers', run_cmd) |
| |
| if properties.fuzz_engine != 'fuzzilli': |
| # For libfuzzer or centipede, upload the succeeded targets in a |
| # json file to GCS |
| gcs_dir = f'fuzz-targets/{properties.fuzz_engine}/' |
| revision = api.buildbucket.gitiles_commit.id[:7] |
| targets_file = api.path.join( |
| target_list_dir, properties.fuzz_engine + '.json' |
| ) |
| api.gsutil.upload( |
| targets_file, 'code-coverage-data', f'{gcs_dir}{revision}/' |
| ) |
| |
| successful_targets = api.file.read_json( |
| 'read successful targets', targets_file |
| ) |
| for target in successful_targets: |
| profdata_path = profdata_dir / f'{target}.profdata' |
| api.code_coverage.get_chromium_fuzz_coverage( |
| source_dir, |
| build_dir, |
| profdata_path, |
| {target}, |
| overall=False, |
| use_cache=True, |
| ) |
| |
| profdata_path = source_dir / 'total_fuzz_coverage.profdata' |
| llvm_profdata_path = api.profiles.llvm_profdata_exec |
| api.step( |
| 'merge all fuzzers', |
| [ |
| 'python3', |
| 'tools/code_coverage/merge_all_profdata.py', |
| '--profdata-dir', |
| profdata_dir, |
| '--outfile', |
| profdata_path, |
| '--llvm-profdata', |
| llvm_profdata_path, |
| ], |
| ) |
| |
| api.code_coverage.get_chromium_fuzz_coverage( |
| source_dir, build_dir, profdata_path, targets, use_cache=True |
| ) |
| except api.step.StepFailure: |
| api.step.empty('could not process fuzz coverage') |
| raise |
| |
| else: |
| # copy data deps outside the build directory |
| # Needed for tests |
| api.path.mock_add_file('[CACHE]/builder/src/path2') |
| |
| archive_schema_version = ( |
| properties.archive_schema_version |
| if properties.HasField('archive_schema_version') |
| else DEFAULT_ARCHIVE_SCHEMA_VERSION |
| ) |
| |
| # Archive schema version >= 1 compiles runtime dependencies and archives |
| # based on `.runtime_deps` files. |
| if archive_schema_version != 0: |
| archive_root = source_dir |
| |
| api.archive.clusterfuzz_archive_targets( |
| source_dir=source_dir, |
| archive_root=archive_root, |
| update_properties=update_result.properties, |
| gs_bucket=properties.upload_bucket, |
| archive_path=properties.archive_path, |
| compile_targets=targets, |
| build_dir=build_dir, |
| archive_schema_version=archive_schema_version, |
| fuzz_targets=targets, |
| gs_acl='public-read', |
| ) |
| return |
| |
| if api.tryserver.is_tryserver: |
| return |
| |
| archive_root = build_dir |
| |
| with api.step.nest('collect all runtime dependencies') as step_result: |
| set_of_gn_targets = set(gn_targets) |
| raw_list_of_runtime_deps = api.gn.desc( |
| build_dir, |
| '*', |
| 'runtime_deps', |
| step_name='get runtime dependencies with pattern *', |
| use_cache=True, |
| ) |
| runtime_deps = filter_runtime_deps( |
| raw_list_of_runtime_deps, set_of_gn_targets |
| ) |
| runtime_deps = sorted(runtime_deps) |
| step_result.logs['runtime_dependencies'] = runtime_deps |
| |
| with api.step.nest('copy runtime dependencies to build directory'): |
| for path in runtime_deps: |
| dep_path = build_dir / path |
| if build_dir not in dep_path.parents and dep_path != build_dir: |
| copy_path(api, source_dir, build_dir, path) |
| |
| fuzz_target_paths = [ |
| api.path.relpath(build_dir / target, archive_root) for target in targets |
| ] |
| manifest_dict = { |
| 'archive_schema_version': 0, |
| 'fuzz_targets': fuzz_target_paths, |
| } |
| |
| api.file.write_json( |
| 'write archive manifest', |
| archive_root / MANIFEST_FILENAME, |
| manifest_dict, |
| ) |
| |
| api.archive.clusterfuzz_archive( |
| source_dir=source_dir, |
| archive_root=archive_root, |
| update_properties=update_result.properties, |
| gs_bucket=properties.upload_bucket, |
| archive_path=properties.archive_path, |
| gs_acl='public-read', |
| ) |
| |
| |
| def GenTests(api: TEST_DEPS): |
| |
| def generate_test( |
| is_try=False, |
| is_coverage=False, |
| is_ios=False, |
| is_v8=False, |
| coverage_metadata_failure=False, |
| engine='libfuzzer', |
| archive_schema_version=None, |
| archive_path='linux-release/libfuzzer-linux-release', |
| drop_expectation=True, |
| ): |
| test = api.properties( |
| upload_bucket='chromium-browser-libfuzzer', |
| upload_directory='fuzz', |
| v8_targets_only=is_v8, |
| ios_targets_only=is_ios, |
| collect_fuzz_coverage=is_coverage, |
| fuzz_engine=engine, |
| archive_path=archive_path, |
| ) |
| if archive_schema_version is not None: |
| test += api.properties(archive_schema_version=archive_schema_version) |
| else: |
| archive_schema_version = DEFAULT_ARCHIVE_SCHEMA_VERSION |
| if engine != 'fuzzilli': |
| targets = api.raw_io.output_text( |
| 'target1\ntarget2\ntarget3\nfuzzer.exe\n' |
| ) |
| test += api.step_data('calculate all_fuzzers', stdout=targets) |
| test += api.step_data( |
| 'calculate no_clusterfuzz', stdout=api.raw_io.output_text('target1') |
| ) |
| if is_v8: |
| test += api.step_data('calculate v8_fuzzers', stdout=targets) |
| if is_ios: |
| test += api.step_data('calculate ios_fuzzers', stdout=targets) |
| # Tryjobs provide their own mocks for 'list gn targets' |
| if not is_try: |
| test += api.step_data('list gn targets', stdout=targets) |
| |
| if not (is_try or is_coverage): |
| if archive_schema_version == 0: |
| test += api.post_process( |
| post_process.MustRun, 'collect all runtime dependencies' |
| ) |
| # this will lead to us having ../../path2 and ../../path4 as runtime |
| # dependencies to copy |
| step_output = ( |
| 'some warning1\n\n' |
| 'some warning2\n' |
| 'Target target1\n' |
| 'runtime_deps\n' |
| ' ./target1\n' |
| ' ../../path14\n' |
| ' ./path15\n\n\n' |
| 'Target target2\n' |
| 'runtime_deps\n' |
| ' ./target2\n' |
| ' ../../path1\n' |
| ' ../../path2\n' |
| 'Target target3\n' |
| 'runtime_deps\n' |
| ' ./target3\n' |
| ' ./path3\n' |
| ' ../../path4\n' |
| 'Target fuzzer.exe\n' |
| 'runtime_deps\n' |
| ' ./fuzzer.exe\n' |
| 'Target target5\n' |
| 'runtime_deps\n' |
| ' ./path16\n' |
| ' ../../path17\n' |
| ) |
| |
| test += api.step_data( |
| 'collect all runtime dependencies.get runtime ' |
| 'dependencies with pattern *', |
| stdout=api.raw_io.output_text(step_output), |
| ) |
| # ../../path1, ../../path2 and ../../path4 need to be copied. |
| test += api.post_process( |
| LogEquals, |
| 'collect all runtime dependencies', |
| 'runtime_dependencies', |
| '../../path1\n' |
| '../../path2\n' |
| '../../path4\n' |
| './fuzzer.exe\n' |
| './path3\n' |
| './target2\n' |
| './target3', |
| ) |
| test += api.post_process( |
| post_process.MustRun, 'copy runtime dependencies to build directory' |
| ) |
| test += api.post_process( |
| post_process.MustRun, |
| 'copy runtime dependencies to build directory.copying file:' |
| '[CACHE]/builder/src/path2', |
| ) |
| test += api.post_process( |
| post_process.MustRun, |
| 'copy runtime dependencies to build directory.copying directory:' |
| '[CACHE]/builder/src/path4', |
| ) |
| else: |
| test += api.post_process( |
| post_process.MustRun, |
| 'collect runtime deps for compile targets', |
| ) |
| test += api.post_process( |
| post_process.MustRun, |
| 'collect runtime deps for compile targets.read fuzzer.runtime_deps', |
| ) |
| test += api.post_process( |
| post_process.MustRun, |
| 'collect runtime deps for compile targets.read target1.runtime_deps', |
| ) |
| test += api.post_process( |
| post_process.MustRun, |
| 'collect runtime deps for compile targets.read target2.runtime_deps', |
| ) |
| test += api.post_process( |
| post_process.MustRun, |
| 'collect runtime deps for compile targets.read target3.runtime_deps', |
| ) |
| expected_paths = '\n'.join( |
| [ |
| 'out/1826-some-ci-bot/fuzzer.exe', |
| 'out/1826-some-ci-bot/fuzzer.runtime_deps', |
| 'out/1826-some-ci-bot/fuzzer_dependency', |
| 'out/1826-some-ci-bot/target1', |
| 'out/1826-some-ci-bot/target1.runtime_deps', |
| 'out/1826-some-ci-bot/target1_dependency', |
| 'out/1826-some-ci-bot/target2', |
| 'out/1826-some-ci-bot/target2.runtime_deps', |
| 'out/1826-some-ci-bot/target2_dependency', |
| 'out/1826-some-ci-bot/target3', |
| 'out/1826-some-ci-bot/target3.runtime_deps', |
| 'out/1826-some-ci-bot/target3_dependency', |
| 'testing/data/fuzzer_seed.txt', |
| ] |
| ) |
| test += api.post_process( |
| LogEquals, |
| 'collect runtime deps for compile targets', |
| 'paths_to_archive', |
| expected_paths, |
| ) |
| test += api.post_process(post_process.MustRun, 'gsutil upload') |
| if is_coverage: |
| test += api.post_process( |
| post_process.MustRun, 'process fuzz coverage (overall)' |
| ) |
| retcode = 0 |
| if coverage_metadata_failure: |
| retcode = 1 |
| if engine != 'fuzzilli': |
| test += api.step_data( |
| 'read successful targets', |
| api.file.read_json(['target1', 'target2', 'target3']), |
| ) |
| test += api.post_process( |
| post_process.MustRun, 'process fuzz coverage (target1)' |
| ) |
| test += api.post_process( |
| post_process.MustRun, 'process fuzz coverage (target2)' |
| ) |
| test += api.post_process( |
| post_process.MustRun, 'process fuzz coverage (target3)' |
| ) |
| test += api.step_data( |
| 'process fuzz coverage (overall).generate coverage metadata', |
| retcode=retcode, |
| ) |
| if is_ios: |
| test += api.properties(xcode_build_version='12345') |
| if archive_schema_version != 0: |
| test += api.post_process( |
| post_process.DoesNotRun, |
| 'copy runtime dependencies to build directory', |
| ) |
| if not is_try: |
| # Verify that targets and runtime_deps are in the archive. |
| # targets in test are fuzzer.exe, target1, target2, target3 |
| # runtime_deps in test (filtered) are ../../path1, ../../path2, |
| # ../../path4, ./path3 |
| expected_paths = ( |
| '["clusterfuzz_manifest.json", ' |
| '"out/1826-some-ci-bot/args.gn", ' |
| '"out/1826-some-ci-bot/fuzzer.exe", ' |
| '"out/1826-some-ci-bot/fuzzer.runtime_deps", ' |
| '"out/1826-some-ci-bot/fuzzer_dependency", ' |
| '"out/1826-some-ci-bot/target1", ' |
| '"out/1826-some-ci-bot/target1.runtime_deps", ' |
| '"out/1826-some-ci-bot/target1_dependency", ' |
| '"out/1826-some-ci-bot/target2", ' |
| '"out/1826-some-ci-bot/target2.runtime_deps", ' |
| '"out/1826-some-ci-bot/target2_dependency", ' |
| '"out/1826-some-ci-bot/target3", ' |
| '"out/1826-some-ci-bot/target3.runtime_deps", ' |
| '"out/1826-some-ci-bot/target3_dependency", ' |
| '"testing/data/fuzzer_seed.txt"]' |
| ) |
| test += api.post_process( |
| post_process.StepCommandContains, |
| 'zipping', |
| [expected_paths], |
| ) |
| expected_manifest_dict = ( |
| '{"archive_schema_version": 1, ' |
| '"fuzz_targets": [' |
| '"out/1826-some-ci-bot/fuzzer.exe", ' |
| '"out/1826-some-ci-bot/target1", ' |
| '"out/1826-some-ci-bot/target2", ' |
| '"out/1826-some-ci-bot/target3"]}' |
| ) |
| test += api.post_process( |
| LogEquals, |
| 'write archive manifest', |
| 'clusterfuzz_manifest.json', |
| expected_manifest_dict, |
| ) |
| if drop_expectation: |
| test += api.post_process(post_process.DropExpectation) |
| return test |
| |
| yield api.test( |
| 'linux-32', |
| api.chromium_tests_builder_config.ci_build( |
| builder_group='chromium.fuzz', |
| builder='some-ci-bot', |
| builder_db=ctbc.BuilderDatabase.create( |
| { |
| 'chromium.fuzz': { |
| 'some-ci-bot': ctbc.BuilderSpec.create( |
| chromium_config='chromium', |
| chromium_apply_config=['clobber'], |
| gclient_config='chromium', |
| chromium_config_kwargs={ |
| 'TARGET_BITS': 32, |
| }, |
| ), |
| }, |
| } |
| ), |
| ), |
| api.platform.name('linux'), |
| api.post_process(post_process.MustRun, 'clobber'), |
| generate_test(), |
| ) |
| |
| yield api.test( |
| 'linux-dbg', |
| api.chromium_tests_builder_config.ci_build( |
| builder_group='chromium.fuzz', |
| builder='some-ci-bot', |
| builder_db=ctbc.BuilderDatabase.create( |
| { |
| 'chromium.fuzz': { |
| 'some-ci-bot': ctbc.BuilderSpec.create( |
| chromium_config='chromium', |
| gclient_config='chromium', |
| chromium_config_kwargs={ |
| 'BUILD_CONFIG': 'Debug', |
| }, |
| ), |
| }, |
| } |
| ), |
| ), |
| api.path.exists( |
| api.path.cache_dir / 'builder/src/out/1826-some-ci-bot/src_root/path1' |
| ), |
| api.platform.name('linux'), |
| generate_test(), |
| ) |
| yield api.test( |
| 'schema_v1', |
| api.chromium_tests_builder_config.ci_build( |
| builder_group='chromium.fuzz', |
| builder='some-ci-bot', |
| builder_db=ctbc.BuilderDatabase.create( |
| { |
| 'chromium.fuzz': { |
| 'some-ci-bot': ctbc.BuilderSpec.create( |
| chromium_config='chromium', |
| gclient_config='chromium', |
| ), |
| }, |
| } |
| ), |
| ), |
| api.platform.name('linux'), |
| generate_test(archive_schema_version=1), |
| ) |
| |
| yield api.test( |
| 'v8', |
| api.chromium_tests_builder_config.ci_build( |
| builder_group='chromium.fuzz', |
| builder='some-ci-bot', |
| builder_db=ctbc.BuilderDatabase.create( |
| { |
| 'chromium.fuzz': { |
| 'some-ci-bot': ctbc.BuilderSpec.create( |
| chromium_config='chromium', |
| gclient_config='chromium', |
| ), |
| }, |
| } |
| ), |
| ), |
| api.platform.name('linux'), |
| generate_test(is_v8=True), |
| ) |
| |
| yield api.test( |
| 'ios', |
| api.chromium_tests_builder_config.ci_build( |
| builder_group='chromium.fuzz', |
| builder='some-ci-bot', |
| builder_db=ctbc.BuilderDatabase.create( |
| { |
| 'chromium.fuzz': { |
| 'some-ci-bot': ctbc.BuilderSpec.create( |
| chromium_config='chromium', |
| gclient_config='chromium', |
| chromium_config_kwargs={ |
| 'TARGET_PLATFORM': 'ios', |
| }, |
| ), |
| }, |
| } |
| ), |
| ), |
| api.platform.name('mac'), |
| generate_test(is_ios=True), |
| ) |
| |
| yield api.test( |
| 'android', |
| api.chromium_tests_builder_config.ci_build( |
| builder_group='chromium.fuzz', |
| builder='some-ci-bot', |
| builder_db=ctbc.BuilderDatabase.create( |
| { |
| 'chromium.fuzz': { |
| 'some-ci-bot': ctbc.BuilderSpec.create( |
| chromium_config='chromium', |
| gclient_config='chromium', |
| chromium_config_kwargs={ |
| 'TARGET_PLATFORM': 'android', |
| }, |
| ), |
| }, |
| } |
| ), |
| ), |
| api.platform.name('linux'), |
| generate_test( |
| archive_path='linux-release-fuzz/libfuzzer-linux-release', |
| drop_expectation=False, |
| ), |
| api.step_data( |
| 'calculate all_fuzzers', |
| stdout=api.raw_io.output_text( |
| '//foo:target1__library\n//foo:target2__library\n' |
| '//foo:fuzzer.exe__library\n' |
| ), |
| ), |
| api.step_data( |
| 'list gn targets', |
| stdout=api.raw_io.output_text('fuzzer.exe\ntarget1\ntarget2'), |
| ), |
| api.step_data( |
| 'collect all runtime dependencies.' |
| 'get runtime dependencies with pattern *', |
| stdout=api.raw_io.output_text( |
| 'Target //foo:target1\n' |
| 'runtime_deps\n' |
| ' ../../path1\n' |
| ' ../../path2\n' |
| ' ../../path4\n' |
| ' ./path3\n' |
| ' ./target2\n' |
| ' ./target3\n' |
| 'Target //foo:fuzzer.exe\n' |
| 'runtime_deps\n' |
| ' ./fuzzer.exe\n' |
| ), |
| ), |
| api.post_check( |
| post_process.StepCommandContains, 'list gn targets', ['//foo:target1'] |
| ), |
| api.post_check( |
| post_process.StepCommandDoesNotContain, |
| 'list gn targets', |
| ['//foo:target1__library'], |
| ), |
| ) |
| |
| yield api.test( |
| 'coverage', |
| api.chromium_tests_builder_config.ci_build( |
| builder_group='chromium.fuzz', |
| builder='some-ci-bot', |
| builder_db=ctbc.BuilderDatabase.create( |
| { |
| 'chromium.fuzz': { |
| 'some-ci-bot': ctbc.BuilderSpec.create( |
| chromium_config='chromium', |
| gclient_config='chromium', |
| ), |
| }, |
| } |
| ), |
| ), |
| api.platform.name('linux'), |
| generate_test(is_coverage=True, drop_expectation=False), |
| api.post_check( |
| post_process.MustRun, |
| 'ensure corpora directory blank', |
| ), |
| api.post_check( |
| post_process.StepCommandContains, |
| 'run all fuzzers', |
| ['RECIPE_REPO[build]/recipes/withxvfb.py'], |
| ), |
| api.post_check( |
| post_process.StepCommandContains, |
| 'merge all fuzzers', |
| [ |
| '[CACHE]/builder/src/third_party/llvm-build/Release+Asserts/bin/llvm-profdata' |
| ], |
| ), |
| api.post_process(post_process.DropExpectation), |
| ) |
| |
| yield api.test( |
| 'mac-coverage', |
| api.chromium_tests_builder_config.ci_build( |
| builder_group='chromium.fuzz', |
| builder='some-ci-bot', |
| builder_db=ctbc.BuilderDatabase.create( |
| { |
| 'chromium.fuzz': { |
| 'some-ci-bot': ctbc.BuilderSpec.create( |
| chromium_config='chromium', |
| gclient_config='chromium', |
| chromium_config_kwargs={ |
| 'TARGET_PLATFORM': 'mac', |
| }, |
| ), |
| }, |
| } |
| ), |
| ), |
| api.platform.name('mac'), |
| generate_test(is_coverage=True, drop_expectation=False), |
| api.post_check( |
| post_process.MustRun, |
| 'ensure corpora directory blank', |
| ), |
| api.post_check( |
| post_process.StepCommandDoesNotContain, |
| 'run all fuzzers', |
| ['RECIPE_REPO[build]/recipes/withxvfb.py'], |
| ), |
| api.post_check( |
| post_process.StepCommandContains, |
| 'merge all fuzzers', |
| [ |
| '[CACHE]/builder/src/third_party/llvm-build/Release+Asserts/bin/llvm-profdata' |
| ], |
| ), |
| api.post_process(post_process.DropExpectation), |
| ) |
| |
| # Verify macOS fuzz coverage builds //chrome:chrome_framework_shared_library |
| # rather than the phony //chrome:chrome_app bundle target. |
| yield api.test( |
| 'mac-coverage-chrome-binary-is-not-phony', |
| api.chromium_tests_builder_config.ci_build( |
| builder_group='chromium.fuzz', |
| builder='some-ci-bot', |
| builder_db=ctbc.BuilderDatabase.create( |
| { |
| 'chromium.fuzz': { |
| 'some-ci-bot': ctbc.BuilderSpec.create( |
| chromium_config='chromium', |
| gclient_config='chromium', |
| chromium_config_kwargs={ |
| 'TARGET_PLATFORM': 'mac', |
| }, |
| ), |
| }, |
| } |
| ), |
| ), |
| api.platform.name('mac'), |
| generate_test(is_coverage=True, drop_expectation=False), |
| api.post_check( |
| post_process.StepCommandContains, |
| 'list gn targets', |
| ['//chrome:chrome_framework_shared_library'], |
| ), |
| api.post_check( |
| post_process.StepCommandDoesNotContain, |
| 'list gn targets', |
| ['//chrome:chrome_app'], |
| ), |
| api.post_process(post_process.DropExpectation), |
| ) |
| # Verify Windows fuzz coverage builds //chrome:chrome_dll rather than the |
| # //chrome:chrome_initial launcher executable. |
| yield api.test( |
| 'win-coverage-chrome-binary-is-not-the-launcher', |
| api.chromium_tests_builder_config.ci_build( |
| builder_group='chromium.fuzz', |
| builder='some-ci-bot', |
| builder_db=ctbc.BuilderDatabase.create( |
| { |
| 'chromium.fuzz': { |
| 'some-ci-bot': ctbc.BuilderSpec.create( |
| chromium_config='chromium', |
| gclient_config='chromium', |
| chromium_config_kwargs={ |
| 'TARGET_PLATFORM': 'win', |
| }, |
| ), |
| }, |
| } |
| ), |
| ), |
| api.platform.name('win'), |
| generate_test(is_coverage=True, drop_expectation=False), |
| api.post_check( |
| post_process.StepCommandContains, |
| 'list gn targets', |
| ['//chrome:chrome_dll'], |
| ), |
| api.post_check( |
| post_process.StepCommandDoesNotContain, |
| 'list gn targets', |
| ['//chrome:chrome_initial'], |
| ), |
| api.post_process(post_process.DropExpectation), |
| ) |
| yield api.test( |
| 'win-coverage', |
| api.chromium_tests_builder_config.ci_build( |
| builder_group='chromium.fuzz', |
| builder='some-ci-bot', |
| builder_db=ctbc.BuilderDatabase.create( |
| { |
| 'chromium.fuzz': { |
| 'some-ci-bot': ctbc.BuilderSpec.create( |
| chromium_config='chromium', |
| gclient_config='chromium', |
| chromium_config_kwargs={ |
| 'TARGET_PLATFORM': 'win', |
| }, |
| ), |
| }, |
| } |
| ), |
| ), |
| api.platform.name('win'), |
| generate_test(is_coverage=True, drop_expectation=False), |
| api.post_check( |
| post_process.MustRun, |
| 'ensure corpora directory blank', |
| ), |
| api.post_check( |
| post_process.StepCommandDoesNotContain, |
| 'run all fuzzers', |
| ['RECIPE_REPO[build]\\recipes\\withxvfb.py'], |
| ), |
| api.post_check( |
| post_process.StepCommandContains, |
| 'merge all fuzzers', |
| [ |
| '[CACHE]\\builder\\src\\third_party\\llvm-build\\Release+Asserts\\bin\\llvm-profdata.exe' |
| ], |
| ), |
| api.post_process(post_process.DropExpectation), |
| ) |
| |
| yield api.test( |
| 'coverage_metadata_generation_failure', |
| api.chromium_tests_builder_config.ci_build( |
| builder_group='chromium.fuzz', |
| builder='some-ci-bot', |
| builder_db=ctbc.BuilderDatabase.create( |
| { |
| 'chromium.fuzz': { |
| 'some-ci-bot': ctbc.BuilderSpec.create( |
| chromium_config='chromium', |
| gclient_config='chromium', |
| ), |
| }, |
| } |
| ), |
| ), |
| api.platform.name('linux'), |
| api.expect_status('FAILURE'), |
| generate_test(is_coverage=True, coverage_metadata_failure=True), |
| ) |
| |
| yield api.test( |
| 'fuzzilli-coverage', |
| api.chromium_tests_builder_config.ci_build( |
| builder_group='chromium.fuzz', |
| builder='some-ci-bot', |
| builder_db=ctbc.BuilderDatabase.create( |
| { |
| 'chromium.fuzz': { |
| 'some-ci-bot': ctbc.BuilderSpec.create( |
| chromium_config='chromium', |
| gclient_config='chromium', |
| ), |
| }, |
| } |
| ), |
| ), |
| api.platform.name('linux'), |
| generate_test(is_coverage=True, engine='fuzzilli'), |
| ) |
| |
| yield api.test( |
| 'centipede-coverage', |
| api.chromium_tests_builder_config.ci_build( |
| builder_group='chromium.fuzz', |
| builder='some-ci-bot', |
| builder_db=ctbc.BuilderDatabase.create( |
| { |
| 'chromium.fuzz': { |
| 'some-ci-bot': ctbc.BuilderSpec.create( |
| chromium_config='chromium', |
| gclient_config='chromium', |
| ), |
| }, |
| } |
| ), |
| ), |
| api.platform.name('linux'), |
| generate_test(is_coverage=True, engine='centipede'), |
| ) |
| |
| yield api.test( |
| 'd8-compile-failure', |
| api.chromium_tests_builder_config.ci_build( |
| builder_group='chromium.fuzz', |
| builder='some-ci-bot', |
| builder_db=ctbc.BuilderDatabase.create( |
| { |
| 'chromium.fuzz': { |
| 'some-ci-bot': ctbc.BuilderSpec.create( |
| chromium_config='chromium', |
| gclient_config='chromium', |
| ), |
| }, |
| } |
| ), |
| ), |
| api.platform.name('linux'), |
| api.properties(fuzz_engine='fuzzilli'), |
| api.step_data('compile', retcode=1), |
| api.expect_status('FAILURE'), |
| api.post_process(post_process.DropExpectation), |
| ) |
| |
| yield api.test( |
| 'compile_failure', |
| api.chromium_tests_builder_config.ci_build( |
| builder_group='chromium.fuzz', |
| builder='Libfuzzer Upload Mac ASan', |
| builder_db=ctbc.BuilderDatabase.create( |
| { |
| 'chromium.fuzz': { |
| 'Libfuzzer Upload Mac ASan': ctbc.BuilderSpec.create( |
| chromium_config='chromium', |
| gclient_config='chromium', |
| ), |
| }, |
| } |
| ), |
| ), |
| api.platform.name('mac'), |
| api.step_data( |
| 'calculate all_fuzzers', |
| stdout=api.raw_io.output_text('//foo/bar:target1'), |
| ), |
| api.step_data('list gn targets', stdout=api.raw_io.output_text('target1')), |
| api.step_data('compile', retcode=1), |
| api.expect_status('FAILURE'), |
| api.post_process(post_process.DropExpectation), |
| ) |
| |
| yield api.test( |
| 'basic_linux_tryjob_no_compile', |
| api.chromium_tests_builder_config.try_build( |
| builder_group='tryserver.chromium.linux', |
| builder='linux-libfuzzer-asan-rel', |
| builder_db=ctbc.BuilderDatabase.create( |
| { |
| 'chromium.fuzz': { |
| 'fuzz-ci-bot': ctbc.BuilderSpec.create( |
| chromium_config='chromium', |
| gclient_config='chromium', |
| ), |
| }, |
| } |
| ), |
| try_db=ctbc.TryDatabase.create( |
| { |
| 'tryserver.chromium.linux': { |
| 'linux-libfuzzer-asan-rel': ctbc.TrySpec.create_for_single_mirror( |
| 'chromium.fuzz', 'fuzz-ci-bot' |
| ), |
| }, |
| } |
| ), |
| ), |
| api.step_data( |
| 'calculate all_fuzzers', |
| stdout=api.raw_io.output_text( |
| '//foo/bar:target1\n//foo/bar:target2\n//foo/bar:target3' |
| ), |
| ), |
| api.step_data( |
| 'calculate no_clusterfuzz', |
| stdout=api.raw_io.output_text('//foo/bar:target1'), |
| ), |
| api.filter.no_dependency(), |
| ) |
| |
| yield api.test( |
| 'basic_linux_tryjob_with_compile', |
| api.chromium_tests_builder_config.try_build( |
| builder_group='tryserver.chromium.linux', |
| builder='linux-libfuzzer-asan-rel', |
| builder_db=ctbc.BuilderDatabase.create( |
| { |
| 'chromium.fuzz': { |
| 'fuzz-ci-bot': ctbc.BuilderSpec.create( |
| chromium_config='chromium', |
| chromium_apply_config=['clobber'], |
| gclient_config='chromium', |
| ), |
| }, |
| } |
| ), |
| try_db=ctbc.TryDatabase.create( |
| { |
| 'tryserver.chromium.linux': { |
| 'linux-libfuzzer-asan-rel': ctbc.TrySpec.create_for_single_mirror( |
| 'chromium.fuzz', 'fuzz-ci-bot' |
| ), |
| }, |
| } |
| ), |
| ), |
| api.step_data( |
| 'calculate all_fuzzers', |
| stdout=api.raw_io.output_text( |
| '\n'.join( |
| ['//foo/bar:target1', '//foo/bar:target2', '//foo/bar:target3'] |
| ) |
| ), |
| ), |
| api.step_data( |
| 'calculate no_clusterfuzz', |
| stdout=api.raw_io.output_text('//foo/bar:target1'), |
| ), |
| api.filter.analyze_output( |
| status='Found dependency', |
| test_targets=[], |
| compile_targets=['//foo/bar:target2'], |
| ), |
| api.step_data('list gn targets', stdout=api.raw_io.output_text('target2')), |
| api.post_process(post_process.DoesNotRun, 'clobber'), |
| ) |
| |
| yield api.test( |
| 'basic_linux_tryjob_with_compile_many_targets', |
| api.chromium_tests_builder_config.try_build( |
| builder_group='tryserver.chromium.linux', |
| builder='linux-libfuzzer-asan-rel', |
| builder_db=ctbc.BuilderDatabase.create( |
| { |
| 'chromium.fuzz': { |
| 'fuzz-ci-bot': ctbc.BuilderSpec.create( |
| chromium_config='chromium', |
| gclient_config='chromium', |
| ), |
| }, |
| } |
| ), |
| try_db=ctbc.TryDatabase.create( |
| { |
| 'tryserver.chromium.linux': { |
| 'linux-libfuzzer-asan-rel': ctbc.TrySpec.create_for_single_mirror( |
| 'chromium.fuzz', 'fuzz-ci-bot' |
| ), |
| }, |
| } |
| ), |
| ), |
| api.step_data( |
| 'calculate all_fuzzers', |
| stdout=api.raw_io.output_text( |
| '\n'.join(f'//foo/bar:target{i}' for i in range(1500)) |
| ), |
| ), |
| api.step_data( |
| 'calculate no_clusterfuzz', stdout=api.raw_io.output_text('') |
| ), |
| api.step_data( |
| 'list gn targets', |
| stdout=api.raw_io.output_text( |
| '\n'.join(f'target{i}' for i in range(500)) |
| ), |
| ), |
| api.step_data( |
| 'list gn targets (2)', |
| stdout=api.raw_io.output_text( |
| '\n'.join(f'target{i}' for i in range(500, 1000)) |
| ), |
| ), |
| api.step_data( |
| 'list gn targets (3)', |
| stdout=api.raw_io.output_text( |
| '\n'.join(f'target{i}' for i in range(1000, 1500)) |
| ), |
| ), |
| # So many targets get batched into several gn ls invocations. |
| api.post_check(post_process.MustRun, 'list gn targets'), |
| api.post_check(post_process.MustRun, 'list gn targets (2)'), |
| api.post_check(post_process.MustRun, 'list gn targets (3)'), |
| api.post_check(post_process.DoesNotRun, 'list gn targets (4)'), |
| # Same goes for ninja invocations. |
| api.post_check(post_process.MustRun, 'compile'), |
| api.post_check(post_process.MustRun, 'compile (3)'), |
| api.post_check(post_process.MustRun, 'compile (3)'), |
| api.post_check(post_process.DoesNotRun, 'compile (4)'), |
| api.post_process(post_process.DropExpectation), |
| ) |
| |
| yield api.test( |
| 'filter_asan_warning', |
| api.chromium_tests_builder_config.ci_build( |
| builder_group='chromium.fuzz', |
| builder='some-ci-bot', |
| builder_db=ctbc.BuilderDatabase.create( |
| { |
| 'chromium.fuzz': { |
| 'some-ci-bot': ctbc.BuilderSpec.create( |
| chromium_config='chromium', |
| gclient_config='chromium', |
| ), |
| }, |
| } |
| ), |
| ), |
| api.platform.name('linux'), |
| api.properties( |
| upload_bucket='chromium-browser-libfuzzer', |
| upload_directory='fuzz', |
| archive_path='linux-release/libfuzzer-linux-release', |
| ), |
| api.step_data( |
| 'calculate all_fuzzers', |
| stdout=api.raw_io.output_text( |
| 'Warning: is_asan is not defined\n//foo/bar:target1\n' |
| ), |
| ), |
| api.step_data( |
| 'calculate no_clusterfuzz', stdout=api.raw_io.output_text('') |
| ), |
| api.step_data('list gn targets', stdout=api.raw_io.output_text('target1')), |
| api.post_check( |
| post_process.StepCommandDoesNotContain, |
| 'list gn targets', |
| ['Warning: is_asan is not defined'], |
| ), |
| api.post_process(post_process.DropExpectation), |
| ) |
| |
| yield api.test( |
| 'filter_asan_warning_in_gn_ls', |
| api.chromium_tests_builder_config.ci_build( |
| builder_group='chromium.fuzz', |
| builder='some-ci-bot', |
| builder_db=ctbc.BuilderDatabase.create( |
| { |
| 'chromium.fuzz': { |
| 'some-ci-bot': ctbc.BuilderSpec.create( |
| chromium_config='chromium', |
| gclient_config='chromium', |
| ), |
| }, |
| } |
| ), |
| ), |
| api.platform.name('linux'), |
| api.properties( |
| upload_bucket='chromium-browser-libfuzzer', |
| upload_directory='fuzz', |
| archive_path='linux-release/libfuzzer-linux-release', |
| ), |
| api.step_data( |
| 'calculate all_fuzzers', |
| stdout=api.raw_io.output_text('//foo/bar:target1\n'), |
| ), |
| api.step_data( |
| 'calculate no_clusterfuzz', stdout=api.raw_io.output_text('') |
| ), |
| api.step_data( |
| 'list gn targets', |
| stdout=api.raw_io.output_text( |
| 'Warning: is_asan is not defined\ntarget1\n' |
| ), |
| ), |
| api.post_check(post_process.StepCommandContains, 'compile', ['target1']), |
| api.post_check( |
| post_process.StepCommandDoesNotContain, |
| 'compile', |
| ['Warning: is_asan is not defined'], |
| ), |
| api.post_process(post_process.DropExpectation), |
| ) |
| |
| def upload_test(name, *args, upload_path=''): |
| test_args = [ |
| api.chromium_tests_builder_config.ci_build( |
| builder_group='chromium.fuzz', |
| builder='some-ci-bot', |
| builder_db=ctbc.BuilderDatabase.create( |
| { |
| 'chromium.fuzz': { |
| 'some-ci-bot': ctbc.BuilderSpec.create( |
| chromium_config='chromium', |
| gclient_config='chromium', |
| ), |
| }, |
| } |
| ), |
| ), |
| *args, |
| api.step_data( |
| 'calculate all_fuzzers', |
| stdout=api.raw_io.output_text('//foo/bar:target1\n'), |
| ), |
| api.step_data( |
| 'calculate no_clusterfuzz', stdout=api.raw_io.output_text('') |
| ), |
| ] |
| if upload_path: |
| test_args.append( |
| api.post_check( |
| post_process.StepCommandContains, |
| 'gsutil upload', |
| [f'{upload_path}-170242.zip'], |
| ) |
| ) |
| test_args.append(api.post_process(post_process.DropExpectation)) |
| return api.test(f'upload path {name}', *test_args) |
| |
| yield upload_test( |
| 'basic', |
| api.platform.name('linux'), |
| api.properties( |
| upload_bucket='bucket', |
| archive_path='linux-release/libfuzzer-linux-release', |
| ), |
| upload_path='gs://bucket/linux-release/libfuzzer-linux-release', |
| ) |
| |
| yield upload_test( |
| 'custom path', |
| api.platform.name('linux'), |
| api.properties( |
| upload_bucket='bucket', |
| archive_path='bleep-bloop/foo-bar', |
| ), |
| upload_path='gs://bucket/bleep-bloop/foo-bar', |
| ) |
| |
| yield upload_test( |
| 'missing archive_path', |
| api.platform.name('linux'), |
| api.properties( |
| upload_bucket='bucket', |
| ), |
| api.expect_exception('AssertionError'), |
| ) |