summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorJörg Thalheim <joerg@thalheim.io>2020-02-19 11:01:02 +0000
committerJörg Thalheim <joerg@thalheim.io>2020-02-23 21:29:22 +0000
commit9c952961f1f1a643b8b8e5d4efab6717afec1bbe (patch)
treee82cd82b09d80d1ce072db6664e6a8f0c27643ea /tests
parent5904e7605c5c6b26994e3b49153feaa29c35e388 (diff)
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.
Diffstat (limited to 'tests')
-rw-r--r--tests/build-profile.nix19
-rwxr-xr-xtests/run.py102
2 files changed, 121 insertions, 0 deletions
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 <nixpkgs/nixos> {
+ 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"<nixos-hardware/[^>]+>", 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()