From 9c952961f1f1a643b8b8e5d4efab6717afec1bbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Wed, 19 Feb 2020 11:01:02 +0000 Subject: Add parallel test runner The new test runner will evaluate all test profiles from the README.md in parallel in separate nix-build processes. Since we do not load all processes into one process, this also helps saving memory. --- tests/build-profile.nix | 19 +++++++++ tests/run.py | 102 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 tests/build-profile.nix create mode 100755 tests/run.py (limited to 'tests') diff --git a/tests/build-profile.nix b/tests/build-profile.nix new file mode 100644 index 0000000..c4509d3 --- /dev/null +++ b/tests/build-profile.nix @@ -0,0 +1,19 @@ +{ profile }: + +let + shim = { + boot.loader.systemd-boot.enable = true; + + fileSystems."/" = { + device = "/dev/disk/by-uuid/00000000-0000-0000-0000-000000000000"; + fsType = "btrfs"; + }; + + nixpkgs.config = { + allowBroken = true; + allowUnfree = true; + }; + }; +in (import { + configuration.imports = [ profile shim ]; +}).system diff --git a/tests/run.py b/tests/run.py new file mode 100755 index 0000000..653337d --- /dev/null +++ b/tests/run.py @@ -0,0 +1,102 @@ +#!/usr/bin/env nix-shell +#!nix-shell -p nix -p python3 -i python + +import argparse +import multiprocessing +import re +import subprocess +import sys +from pathlib import Path +from typing import List, Tuple + +TEST_ROOT = Path(__file__).resolve().parent +ROOT = TEST_ROOT.parent + +GREEN = "\033[92m" +RED = "\033[91m" +RESET = "\033[0m" + + +def parse_readme() -> List[str]: + profiles = set() + with open(ROOT.joinpath("README.md")) as f: + for line in f: + results = re.findall(r"]+>", line) + profiles.update(results) + return list(profiles) + + +def build_profile(profile: str) -> Tuple[str, subprocess.CompletedProcess]: + # Hard-code this for now until we have enough other architectures to care about this. + system = "x86_64-linux" + if "raspberry-pi/2" in profile: + system = "armv7l-linux" + + cmd = [ + "nix-build", + "-I", + f"nixos-hardware={ROOT}", + "--dry-run", + "--show-trace", + "build-profile.nix", + "--system", + system, + "--arg", + "profile", + profile, + ] + res = subprocess.run( + cmd, cwd=TEST_ROOT, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, + ) + return (profile, res) + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Run hardware tests") + parser.add_argument( + "--jobs", + type=int, + default=multiprocessing.cpu_count(), + help="Number of parallel evaluations." + "If set to 1 it disable multi processing (suitable for debugging)", + ) + parser.add_argument("profiles", nargs="*") + return parser.parse_args() + + +def main() -> None: + args = parse_args() + if len(args.profiles) == 0: + profiles = parse_readme() + else: + profiles = args.profiles + + failed_profiles = [] + + def eval_finished(args: Tuple[str, subprocess.CompletedProcess]) -> None: + profile, res = args + if res.returncode == 0: + print(f"{GREEN}OK {profile}{RESET}") + else: + print(f"{RED}FAIL {profile}:{RESET}", file=sys.stderr) + if res.stdout != "": + print(f"{RED}{res.stdout.rstrip()}{RESET}", file=sys.stderr) + print(f"{RED}{res.stderr.rstrip()}{RESET}", file=sys.stderr) + failed_profiles.append(profile) + + if len(profiles) == 0 or args.jobs == 1: + for profile in profiles: + eval_finished(build_profile(profile)) + else: + pool = multiprocessing.Pool(processes=args.jobs) + for r in pool.imap(build_profile, profiles): + eval_finished(r) + if len(failed_profiles) > 0: + print(f"\n{RED}The following {len(failed_profiles)} test(s) failed:{RESET}") + for profile in failed_profiles: + print(f"{sys.argv[0]} '{profile}'") + sys.exit(1) + + +if __name__ == "__main__": + main() -- cgit v1.2.3