| # Copyright 2020 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| """Recipe for testing Recipes.""" |
| |
| from recipe_engine.recipe_api import Property |
| |
| DEPS = [ |
| "fuchsia/build_input_resolver", |
| "fuchsia/checkout", |
| "fuchsia/commit_queue", |
| "fuchsia/recipe_testing", |
| "fuchsia/status_check", |
| "recipe_engine/buildbucket", |
| "recipe_engine/context", |
| "recipe_engine/json", |
| "recipe_engine/path", |
| "recipe_engine/properties", |
| "recipe_engine/step", |
| ] |
| |
| PROPERTIES = { |
| "project": Property(kind=str, help="Jiri remote manifest project", default=None), |
| "manifest": Property(kind=str, help="Jiri manifest to use"), |
| "remote": Property(kind=str, help="Remote manifest repository"), |
| "unittest_only": Property(kind=bool, help="Finish after unit tests", default=False), |
| "use_buildbucket": Property( |
| kind=bool, |
| help="Launch tryjobs through Buildbucket API instead of led", |
| default=False, |
| ), |
| "include_includable_only": Property( |
| kind=bool, help="Include includable_only tryjobs", default=True, |
| ), |
| "include_public": Property(kind=bool, help="Include public tryjobs", default=True), |
| "include_private": Property( |
| kind=bool, help="Include private tryjobs", default=False |
| ), |
| "commit_queue_project": Property( |
| kind=str, help="Commit queue project", default="fuchsia" |
| ), |
| "check_deps": Property( |
| kind=bool, |
| help="Whether to check for out-of-order and unused recipe deps", |
| default=False, |
| ), |
| "cq_config_name": Property( |
| kind=str, |
| help="Name of the CQ config file to load, if different from the default", |
| default="", |
| ), |
| } |
| |
| # If this build is being triggered from a change to this recipe, we need |
| # to explicitly pass a CL. The most recent passing run of |
| # fuchsia.try/recipes could take anywhere from about three to 200 minutes, |
| # and the three minute version does not test much of what this recipe |
| # actually does. In that case alter the recipes build to run on a specific |
| # CL that modifies the cobalt recipe alone. (The cobalt build usually |
| # takes less than 10 minutes.) |
| SELFTEST_CL = "https://fuchsia-review.googlesource.com/c/infra/recipes/+/303171" |
| |
| # If this build is being triggered from a change to this recipe, and we're |
| # using the Buildbucket testing codepath, then we need to explicitly pass a |
| # builder. This builder will run in the case that the only affected recipe is |
| # this one, so we are guaranteed to exercise the scheduling codepath without |
| # recursing infinitely. |
| SELFTEST_BUILDER = "fuchsia/try/bringup.x64-debug-no_opt-build_only" |
| |
| |
| def RunSteps( |
| api, |
| project, |
| manifest, |
| remote, |
| unittest_only, |
| use_buildbucket, |
| include_includable_only, |
| include_public, |
| include_private, |
| commit_queue_project, |
| check_deps, |
| cq_config_name, |
| ): |
| """Run tests for recipes.""" |
| |
| # Resolve the build input to always contain a Gitiles commit. |
| api.build_input_resolver.resolve() |
| |
| with api.context(infra_steps=True): |
| api.checkout.with_options( |
| path=api.path["start_dir"], |
| manifest=manifest, |
| remote=remote, |
| project=project, |
| # Override defaults. We should always attempt to patch. |
| skip_patch_projects=(), |
| ) |
| |
| recipes_path = api.path["start_dir"].join("infra", "recipes") |
| |
| if check_deps: |
| with api.context(cwd=recipes_path): |
| run_check_deps(api, recipes_path) |
| |
| with api.step.defer_results(): |
| # TODO(olivernewman): Stop allowlisting pipes after it's no longer used by |
| # gcc_toolchain. |
| api.recipe_testing.run_lint(recipes_path, allowlist=r"^pipes$") |
| api.recipe_testing.run_unit_tests(recipes_path) |
| |
| if not unittest_only: |
| api.recipe_testing.projects = (commit_queue_project,) |
| api.recipe_testing.run_tests( |
| recipes_path, |
| SELFTEST_CL, |
| include_includable_only=include_includable_only, |
| include_public=include_public, |
| include_private=include_private, |
| use_buildbucket=use_buildbucket, |
| selftest_builder=SELFTEST_BUILDER, |
| cq_config_name=cq_config_name, |
| ) |
| |
| |
| def run_check_deps(api, recipes_path): |
| step = api.step( |
| "check deps", |
| [ |
| recipes_path.join("scripts", "cleanup_deps.py"), |
| "--check", |
| "--json-output", |
| api.json.output(), |
| ], |
| ok_ret=(0, 1), |
| step_test_data=lambda: api.json.test_api.output([]), |
| ) |
| if not step.retcode: |
| return |
| |
| step.presentation.status = api.step.FAILURE |
| bad_files = step.json.output |
| summary = ( |
| "Files with malformatted DEPS (run ./scripts/cleanup_deps.py to fix):\n\n" |
| + "\n".join(["- `%s`" % path for path in bad_files]) |
| ) |
| raise api.step.StepFailure(summary) |
| |
| |
| def GenTests(api): # pylint: disable=invalid-name |
| def test(name, status="success", run_tests=True, **props): |
| ret = ( |
| api.status_check.test(name, status=status) |
| + api.buildbucket.try_build( |
| project="fuchsia", |
| git_repo="https://fuchsia.googlesource.com/infra/recipes", |
| ) |
| + api.properties( |
| manifest="manifest/minimal", |
| remote="https://fuchsia.googlesource.com/infra/recipes", |
| check_deps=True, |
| cq_config_name="alternate-commit-queue.cfg", |
| **props |
| ) |
| ) |
| if run_tests: |
| ret += api.commit_queue.test_data( |
| "fuchsia", config_name=ret.properties["cq_config_name"] |
| ) + api.recipe_testing.affected_recipes_data(["none"]) |
| return ret |
| |
| yield ( |
| test("cq_try") |
| + api.recipe_testing.build_data( |
| "fuchsia/try/fuchsia-x64-debug", "fuchsia", skip=True |
| ) |
| + api.recipe_testing.build_data( |
| "fuchsia/try/fuchsia-arm64-debug", "fuchsia", skip=True |
| ) |
| + api.recipe_testing.build_data( |
| "fuchsia/try/cobalt-x64-linux", "cobalt", skip=True |
| ) |
| ) |
| |
| yield ( |
| test("cq_try_private", include_public=False, include_private=True) |
| + api.recipe_testing.build_data("fuchsia/try/secret-tryjob", "docs", skip=True) |
| ) |
| |
| yield ( |
| test("check_deps_fails", run_tests=False, status="failure") |
| + api.step_data("check deps", api.json.output(["recipes/foo.py"]), retcode=1) |
| ) |