]> git.ipfire.org Git - thirdparty/rsync.git/commitdiff
fleettest: add --testsuite-repo to run another tree's suite against this build
authorAndrew Tridgell <andrew@tridgell.net>
Sun, 7 Jun 2026 03:56:17 +0000 (13:56 +1000)
committerAndrew Tridgell <andrew@tridgell.net>
Sun, 7 Jun 2026 20:29:49 +0000 (06:29 +1000)
--repo couples the built source and the test suite that exercises it.
--testsuite-repo PATH overlays runtests.py + testsuite/ from a second tree onto
the staged build tree, and sources the expected-skip workflows from it, so one
can build an older release (e.g. a 3.4.x stable branch) and run the current
comprehensive suite against that binary. Defaults to --repo, so the existing
single-tree behaviour is unchanged.

testsuite/fleettest.py

index a4f3f2ab82dfdb6253dc574a576b9c36e8d7c012..dc2295b584ca8bfe2ff022c031108b9ba3fa2340 100755 (executable)
@@ -83,7 +83,11 @@ from pathlib import Path
 # source tree these point at, so it must be run from inside an rsync checkout
 # or given --repo PATH.
 REPO = Path.cwd()
-WORKFLOWS = REPO / ".github" / "workflows"
+# Source tree providing the test suite (runtests.py + testsuite/). Defaults to
+# REPO; --testsuite-repo decouples it so one tree is built and another's suite is
+# run against the result.
+TESTSUITE_REPO = REPO
+WORKFLOWS = TESTSUITE_REPO / ".github" / "workflows"
 
 # Fleet config (overridable with --fleet): ~/.fleettest.json is tried first, then
 # fleettest.json next to this script. The example template sits next to the
@@ -815,18 +819,27 @@ def main() -> int:
                     help="report per-target wall-clock (push/build/test) to find "
                     "the slowest target")
     ap.add_argument("--repo", help="rsync source tree to build (default: cwd)")
+    ap.add_argument("--testsuite-repo",
+                    help="rsync tree to take runtests.py + testsuite/ from "
+                    "(default: --repo). Build one tree and run another's test "
+                    "suite against it, e.g. --repo ../rsync-v3.4 --testsuite-repo .")
     ap.add_argument("--fleet", help="fleet config JSON (default: ~/.fleettest.json, "
                     "else fleettest.json next to this script)")
     ap.add_argument("--list", action="store_true", help="list targets and exit")
     args = ap.parse_args()
 
-    global REPO, WORKFLOWS
+    global REPO, WORKFLOWS, TESTSUITE_REPO
     REPO = Path(args.repo).resolve() if args.repo else Path.cwd()
-    WORKFLOWS = REPO / ".github" / "workflows"
-    if not args.cleanup and not (REPO / "runtests.py").is_file():
-        print(f"{REPO} is not an rsync source tree (no runtests.py); "
-              f"run from inside a checkout or pass --repo", file=sys.stderr)
-        return 2
+    TESTSUITE_REPO = Path(args.testsuite_repo).resolve() if args.testsuite_repo else REPO
+    # The expected-skip lists travel with the suite, so read workflows from the
+    # tree that provides the tests.
+    WORKFLOWS = TESTSUITE_REPO / ".github" / "workflows"
+    if not args.cleanup:
+        for label, tree in (("--repo", REPO), ("--testsuite-repo", TESTSUITE_REPO)):
+            if not (tree / "runtests.py").is_file():
+                print(f"{tree} is not an rsync source tree (no runtests.py); "
+                      f"run from inside a checkout or pass {label}", file=sys.stderr)
+                return 2
 
     if args.fleet:
         config_path = Path(args.fleet).resolve()
@@ -905,6 +918,19 @@ def main() -> int:
             print(f"git archive failed: {ar.stderr}", file=sys.stderr)
             return 2
 
+        # --testsuite-repo: overlay another tree's runtests.py + testsuite/ onto
+        # the built source (merge, no delete). Build REPO's rsync, but run
+        # TESTSUITE_REPO's suite against it. The leftover .test files from REPO
+        # are ignored by a Python runtests.py (it globs *_test.py).
+        if TESTSUITE_REPO != REPO:
+            ov = subprocess.run(
+                f"git -C {TESTSUITE_REPO} archive HEAD -- runtests.py testsuite "
+                f"| tar -x -C {staging}",
+                shell=True, capture_output=True, text=True)
+            if ov.returncode != 0:
+                print(f"testsuite overlay archive failed: {ov.stderr}", file=sys.stderr)
+                return 2
+
         # Tests that opt into the non-root pass (same for every target).
         args.nonroot_tests = discover_nonroot_tests(Path(staging) / "testsuite")