diff --git a/.gitignore b/.gitignore index 6489266266..8cc97ce16d 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ tags build dist expansions.yml +**.plist # python __pycache__ diff --git a/src/lamplib/src/genny/cli.py b/src/lamplib/src/genny/cli.py index f24754cb2c..50bc0b7809 100644 --- a/src/lamplib/src/genny/cli.py +++ b/src/lamplib/src/genny/cli.py @@ -212,12 +212,27 @@ def clean(ctx: click.Context) -> None: @cli.command(name="cmake-test", help="Run genny's C++ unit tests.") +@click.option( + "-g", "--regex", required=False, default=None, help=("Regex to match against tests."), +) +@click.option( + "-r", + "--repeat-until-fail", + required=False, + default=1, + help=( + "Repeat this many times, unless a test fails. Default is 1. This is useful for flaky tests." + ), +) @click.pass_context -def cmake_test(ctx: click.Context) -> None: +def cmake_test(ctx: click.Context, regex: str, repeat_until_fail: int) -> None: from genny.tasks import run_tests run_tests.cmake_test( - genny_repo_root=ctx.obj["GENNY_REPO_ROOT"], workspace_root=ctx.obj["WORKSPACE_ROOT"] + genny_repo_root=ctx.obj["GENNY_REPO_ROOT"], + workspace_root=ctx.obj["WORKSPACE_ROOT"], + regex=regex, + repeat_until_fail=repeat_until_fail, ) @@ -292,12 +307,17 @@ def run_debug(ctx: click.Context, genny_args: List[str]): "constructor validates configuration at constructor time." ), ) +@click.option( + "-w", "--workload", required=False, default=None, help=("Workload to dry-run."), +) @click.pass_context -def dry_run_workloads(ctx: click.Context): +def dry_run_workloads(ctx: click.Context, workload: str): from genny.tasks import dry_run dry_run.dry_run_workloads( - genny_repo_root=ctx.obj["GENNY_REPO_ROOT"], workspace_root=ctx.obj["WORKSPACE_ROOT"] + genny_repo_root=ctx.obj["GENNY_REPO_ROOT"], + workspace_root=ctx.obj["WORKSPACE_ROOT"], + given_workload=workload, ) @@ -397,6 +417,16 @@ def create_new_actor(ctx: click.Context, actor_name: str): ) +@cli.command( + "generate-uuid-tag", help=("Generate a random UUID tag for headers."), +) +@click.pass_context +def generate_uuid_tag(ctx: click.Context): + from genny.tasks import generate_uuid_tag + + generate_uuid_tag.run_generate_uuid_tag(genny_repo_root=ctx.obj["GENNY_REPO_ROOT"]) + + @cli.command( name="lint-python", help="Run the 'black' python format checker to ensure genny's internal python is 💅.", diff --git a/src/lamplib/src/genny/tasks/dry_run.py b/src/lamplib/src/genny/tasks/dry_run.py index 0bf812d5d7..2bfd491c05 100644 --- a/src/lamplib/src/genny/tasks/dry_run.py +++ b/src/lamplib/src/genny/tasks/dry_run.py @@ -41,11 +41,14 @@ def dry_run_workload( ) -def dry_run_workloads(genny_repo_root: str, workspace_root: str): +def dry_run_workloads(genny_repo_root: str, workspace_root: str, given_workload: str = None): info = toolchain_info(genny_repo_root=genny_repo_root, workspace_root=workspace_root) - glob_pattern = os.path.join(genny_repo_root, "src", "workloads", "*", "*.yml") - workloads = glob.glob(glob_pattern) + if given_workload is not None: + workloads = [given_workload] + else: + glob_pattern = os.path.join(genny_repo_root, "src", "workloads", "*", "*.yml") + workloads = glob.glob(glob_pattern) curr = 0 for workload in workloads: SLOG.info("Checking workload", workload=workload, index=curr, of_how_many=len(workloads)) diff --git a/src/lamplib/src/genny/tasks/generate_uuid_tag.py b/src/lamplib/src/genny/tasks/generate_uuid_tag.py new file mode 100644 index 0000000000..03fdb50ba0 --- /dev/null +++ b/src/lamplib/src/genny/tasks/generate_uuid_tag.py @@ -0,0 +1,12 @@ +import os + +from genny import cmd_runner + + +def run_generate_uuid_tag(genny_repo_root: str): + path = os.path.join( + genny_repo_root, "src", "lamplib", "src", "genny", "tasks", "generate-uuid-tag.sh" + ) + cmd_runner.run_command( + cmd=[path], cwd=genny_repo_root, capture=False, check=True, + ) diff --git a/src/lamplib/src/genny/tasks/run_tests.py b/src/lamplib/src/genny/tasks/run_tests.py index 4cae1ed4ff..deea5b82be 100644 --- a/src/lamplib/src/genny/tasks/run_tests.py +++ b/src/lamplib/src/genny/tasks/run_tests.py @@ -1,6 +1,8 @@ import structlog import os +import sys import shutil +import subprocess from typing import Callable, TypeVar, Tuple, Optional @@ -69,7 +71,9 @@ def _run_command_with_sentinel_report( ) -def cmake_test(genny_repo_root: str, workspace_root: str): +def cmake_test( + genny_repo_root: str, workspace_root: str, regex: str = None, repeat_until_fail: int = 1 +): info = toolchain.toolchain_info(genny_repo_root=genny_repo_root, workspace_root=workspace_root) workdir = os.path.join(genny_repo_root, "build") @@ -78,20 +82,32 @@ def cmake_test(genny_repo_root: str, workspace_root: str): ctest_cmd = [ "ctest", - "--verbose", + "--schedule-random", + "--output-on-failure", + "--parallel", + "4", + "--repeat-until-fail", + str(repeat_until_fail), "--label-exclude", "(standalone|sharded|single_node_replset|three_node_replset|benchmark)", ] + if regex is not None: + ctest_cmd += ["--tests-regex", regex] + def cmd_func() -> bool: output: cmd_runner.RunCommandOutput = cmd_runner.run_command( cmd=ctest_cmd, cwd=workdir, env=info.toolchain_env, capture=False, check=True ) return output.returncode == 0 - _run_command_with_sentinel_report( - cmd_func=cmd_func, workspace_root=workspace_root, genny_repo_root=genny_repo_root - ) + try: + _run_command_with_sentinel_report( + cmd_func=cmd_func, workspace_root=workspace_root, genny_repo_root=genny_repo_root + ) + + except subprocess.CalledProcessError: + sys.exit(1) def benchmark_test(genny_repo_root: str, workspace_root: str):