{
  "_comment": [
    "Example fleet definition for testsuite/fleettest.py -- this is one",
    "maintainer's setup. Copy (or symlink) this file to testsuite/fleettest.json",
    "and edit it for your own machines, or point at another file with --fleet PATH.",
    "fleettest.json is git-ignored; this .example is the committed template.",
    "",
    "Each object under \"targets\" maps to fields of the Target dataclass in",
    "fleettest.py. Required: name, ssh_host (null = run locally), workflow",
    "(a file under .github/workflows, whose configure flags and RSYNC_EXPECT_SKIPPED",
    "this target mirrors), configure_flags. Optional (with defaults): make (\"make\"),",
    "python (\"python3\"), rsync_bin (\"rsync\"; \"rsync.exe\" on Cygwin), privilege",
    "(\"root\" | \"sudo\" | \"user\"), pipe_jobs/tcp_jobs (8), builddir (\"rsync-citest\",",
    "relative to the remote $HOME), env_prefix, configure_pre, nonroot, protocols,",
    "max_retry.",
    "",
    "nonroot: true reruns -- as the non-root ssh user, after the sudo runs -- the",
    "tests that declare `fleet_nonroot = True` at module level (so the set is",
    "maintained in the test files, not here).",
    "",
    "protocols: [30, 29] adds one extra stdio-pipe test pass per listed version,",
    "each run with runtests --protocol=N (the fleet analogue of a workflow's",
    "check30/check29 steps) and shown as a protoNN column.",
    "",
    "max_retry: N (default 0) re-runs each failed test on its own up to N more",
    "times and drops any that then pass (listed under RECOVERED, not hidden). Use",
    "on a slow/loaded box where concurrency-sensitive tests occasionally flake,",
    "instead of dropping the whole target to a lower pipe_jobs/tcp_jobs.",
    "",
    "Keys starting with \"_\" are comments. See testsuite/README.md."
  ],
  "targets": [
    {
      "name": "freebsd",
      "ssh_host": "root@freebsd",
      "workflow": "freebsd-build.yml",
      "make": "gmake",
      "configure_flags": [
        "--with-rrsync",
        "--disable-zstd",
        "--disable-md2man",
        "--disable-xxhash",
        "--disable-lz4"
      ]
    },
    {
      "name": "solaris",
      "ssh_host": "root@solaris",
      "workflow": "solaris-build.yml",
      "make": "gmake",
      "configure_flags": [
        "--with-rrsync",
        "--disable-zstd",
        "--disable-md2man",
        "--disable-xxhash",
        "--disable-lz4"
      ]
    },
    {
      "_comment": "Nested-VM OpenBSD. max_retry re-runs a flaky test on its own. The daemon+flipper symlink-race tests are excluded here: this box's kernel has a connect()-under-rename-load lost-wakeup (and an FFS rename-storm corruption) that hangs them for non-rsync reasons (see dev-notes/openbsd-connect-lost-wakeup-report.txt); the protections they check are verified on the Linux/BSD boxes.",
      "name": "openbsd",
      "ssh_host": "root@openbsd",
      "workflow": "openbsd-build.yml",
      "make": "gmake",
      "configure_pre": "export AUTOCONF_VERSION=2.71 AUTOMAKE_VERSION=1.16;",
      "max_retry": 2,
      "exclude": [
        "acl-symlink-race",
        "sender-readlink-atfd",
        "sender-remove-source-secure"
      ],
      "configure_flags": [
        "--with-rrsync",
        "--disable-zstd",
        "--disable-md2man",
        "--disable-xxhash",
        "--disable-lz4"
      ]
    },
    {
      "name": "netbsd",
      "ssh_host": "root@netbsd",
      "workflow": "netbsd-build.yml",
      "make": "gmake",
      "configure_flags": [
        "--with-rrsync",
        "--disable-zstd",
        "--disable-md2man",
        "--disable-xxhash",
        "--disable-lz4"
      ]
    },
    {
      "_comment": "Ubuntu 18.04 older-LTS backport coverage on a root@ box; no 18.04 runner image exists so it mirrors the 22.04 workflow.",
      "name": "ubuntu-1804",
      "ssh_host": "root@ubuntu-1804",
      "workflow": "ubuntu-22.04-build.yml",
      "_python_comment": "18.04's default python3 is 3.6, but runtests.py uses subprocess capture_output (3.7+); run the suite under the 3.10 that's also installed.",
      "python": "python3.10",
      "_configure_flags_comment": "18.04's libzstd 1.3.3 lacks ZSTD_minCLevel (configure aborts), so disable zstd; also disable lz4 so the default -z compressor is zlib -- with lz4 as the default, compress-options' --compress-level=9 check fails since lz4 has no levels. xxhash is fine.",
      "configure_flags": [
        "--with-rrsync",
        "--disable-zstd",
        "--disable-lz4"
      ],
      "_expect_skip_extra_comment": "daemon-max-alloc-zero needs the old static client (git-archive export-ignore'd); protected-regular's fs.protected_regular path is not exercised on this box.",
      "expect_skip_extra": [
        "daemon-max-alloc-zero",
        "protected-regular"
      ]
    },
    {
      "_comment": "Ubuntu 20.04 older-LTS backport coverage on a root@ box; no 20.04 runner image exists so it mirrors the 22.04 workflow.",
      "name": "ubuntu-2004",
      "ssh_host": "root@ubuntu-2004",
      "workflow": "ubuntu-22.04-build.yml",
      "configure_flags": [
        "--with-rrsync"
      ],
      "_expect_skip_extra_comment": "The symlink-race tests now run on every platform (one portable race-free resolver), so only daemon-max-alloc-zero skips here: it needs the old static client, which git-archive omits (.gitattributes export-ignore) from the source-only fleet push.",
      "expect_skip_extra": [
        "daemon-max-alloc-zero"
      ]
    },
    {
      "_comment": "Builds unprivileged (like a CI runner) and runs the suite via sudo; the nonroot pass reruns the privilege-sensitive tests as the ssh user. protocols: [30, 29] runs the check30/check29 passes on this NO-xattrat kernel: the CI's proto-29 step runs here, but the only other proto-29 fleet box (ubuntu-2604) is xattrat, so without this the (no-xattrat x proto-29) cell is uncovered.",
      "name": "ubuntu-2204",
      "ssh_host": "runner@ubuntu-2204",
      "workflow": "ubuntu-22.04-build.yml",
      "privilege": "sudo",
      "nonroot": true,
      "protocols": [
        30,
        29
      ],
      "configure_flags": [
        "--with-rrsync"
      ],
      "_expect_skip_extra_comment": "daemon-max-alloc-zero needs the old static client, which git-archive omits (.gitattributes export-ignore) from the source-only fleet push.",
      "expect_skip_extra": [
        "daemon-max-alloc-zero"
      ]
    },
    {
      "_comment": "Noble (24.04), kernel 6.8 -- a NO-xattrat kernel like ubuntu-2204 but with modern userspace; mirrors ubuntu-build.yml.",
      "name": "ubuntu-2404",
      "ssh_host": "runner@ubuntu-2404",
      "workflow": "ubuntu-build.yml",
      "privilege": "sudo",
      "nonroot": true,
      "protocols": [
        30,
        29
      ],
      "configure_flags": [
        "--with-rrsync"
      ],
      "_expect_skip_extra_comment": "daemon-max-alloc-zero needs the old static client, which git-archive omits (.gitattributes export-ignore) from the source-only fleet push.",
      "expect_skip_extra": [
        "daemon-max-alloc-zero"
      ]
    },
    {
      "_comment": "Modern Ubuntu (mirrors ubuntu-build.yml). protocols: [30, 29] also runs the workflow's check30/check29 passes as extra stdio-pipe runs.",
      "name": "ubuntu-2604",
      "ssh_host": "runner@ubuntu-2604",
      "workflow": "ubuntu-build.yml",
      "privilege": "sudo",
      "nonroot": true,
      "protocols": [
        30,
        29
      ],
      "configure_flags": [
        "--with-rrsync"
      ],
      "_expect_skip_extra_comment": "daemon-max-alloc-zero needs the old static client, which git-archive omits (.gitattributes export-ignore) from the source-only fleet push.",
      "expect_skip_extra": [
        "daemon-max-alloc-zero"
      ]
    },
    {
      "_comment": "AlmaLinux 8 (RHEL 8 rebuild): the oldest active LTS in the Fedora/RHEL family, for backport coverage. glibc 2.28 / gcc 8.5. The CI job runs in an almalinux:8 container; this is the VM equivalent. python3 must be the python39 module (alternatives --set python3 /usr/bin/python3.9) -- the stock 3.6 is too old for runtests.py.",
      "name": "almalinux-8",
      "ssh_host": "root@almalinux-8",
      "workflow": "almalinux-8-build.yml",
      "configure_flags": [
        "--with-rrsync"
      ],
      "_expect_skip_extra_comment": "Box-specific, not workflow-specific: this VM has no separate filesystem for a cross-device temp dir, and daemon-max-alloc-zero needs the old static client that the source-only fleet push omits (.gitattributes export-ignore), as on ubuntu-2004. fs.protected_regular is enabled in /etc/sysctl.d/90-rsync-fleettest.conf so protected-regular runs here rather than skipping.",
      "expect_skip_extra": [
        "chmod-temp-dir",
        "daemon-max-alloc-zero"
      ]
    },
    {
      "_comment": "macOS: brew is not on the non-interactive ssh PATH, so put it on PATH for the whole build and pass brew include/lib dirs to configure.",
      "name": "mac2",
      "ssh_host": "runner@mac2",
      "workflow": "macos-build.yml",
      "privilege": "sudo",
      "env_prefix": "export PATH=/opt/homebrew/bin:/usr/local/bin:$PATH",
      "configure_pre": "CPPFLAGS=\"-I$(brew --prefix)/include -I$(brew --prefix openssl)/include\"; LDFLAGS=\"-L$(brew --prefix)/lib -L$(brew --prefix openssl)/lib\"; export CPPFLAGS LDFLAGS;",
      "configure_flags": [
        "--with-rrsync"
      ],
      "_xfail_comment": "crtimes uses APFS birthtime via setattrlist; older backport binaries (3.4.x/3.2.7) drive it differently than current rsync, so the 3.5.0 testsuite's crtimes check fails here. Tolerated -- it passes for a current binary, where this entry is a no-op.",
      "xfail": [
        "crtimes"
      ]
    },
    {
      "_comment": "Same host and build as mac2, but the tests' scratch trees live on an HFS+ volume instead of APFS -- runtests.py honours $scratchbase, so only the data under test moves.  The setup VERIFIES the mount rather than assuming it: a stale directory or a name collision mounting at 'RsyncHFS 1' would otherwise leave the tests on APFS reporting green, which is exactly how the first version of this target lied.  Ownership must be on too: a user-attached image mounts 'noowners', under which every uid/gid and permission check is meaningless -- that alone caused 28 of the 31 failures the first honest run produced.",
      "name": "mac2-hfs",
      "ssh_host": "runner@mac2",
      "workflow": "macos-build.yml",
      "privilege": "sudo",
      "env_prefix": "export PATH=/opt/homebrew/bin:/usr/local/bin:$PATH; if ! mount | grep -q 'on /Volumes/RsyncHFS (hfs'; then [ -f ~/hfsplus.dmg ] || hdiutil create -size 3g -fs 'HFS+' -volname RsyncHFS -quiet ~/hfsplus.dmg; hdiutil attach -quiet ~/hfsplus.dmg; fi; mount | grep -q 'on /Volumes/RsyncHFS (hfs' || { echo 'FATAL: /Volumes/RsyncHFS is not a mounted HFS+ volume' >&2; exit 9; }; sudo -n diskutil enableOwnership /Volumes/RsyncHFS >/dev/null || { echo 'FATAL: could not enable ownership on /Volumes/RsyncHFS' >&2; exit 9; }; mount | grep 'on /Volumes/RsyncHFS (hfs' | grep -q noowners && { echo 'FATAL: /Volumes/RsyncHFS still mounted noowners' >&2; exit 9; } || true",
      "configure_pre": "CPPFLAGS=\"-I$(brew --prefix)/include -I$(brew --prefix openssl)/include\"; LDFLAGS=\"-L$(brew --prefix)/lib -L$(brew --prefix openssl)/lib\"; export CPPFLAGS LDFLAGS;",
      "configure_flags": [
        "--with-rrsync"
      ],
      "_xfail_comment": "Same APFS birthtime caveat as mac2.",
      "xfail": [
        "crtimes"
      ],
      "scratchbase": "/Volumes/RsyncHFS",
      "expect_skip_omit": [
        "backup-crossdev-copy",
        "chmod-temp-dir"
      ],
      "_skip_comment": "The two omitted entries are macOS-wide expected-skips that this target RUNS: the separate volume supplies the cross-device conditions mac2 lacks. (itemize used to XFAIL here, before --link-dest learned to fall back when the filesystem cannot hard-link a symlink.)"
    },
    {
      "_comment": "The x86-64 Mac (macOS 10.13).  The ONLY target that can build the x86-64 md5 assembly -- mac2 is arm64, where configure refuses --enable-md5-asm outright.  MacPorts supplies autotools, python3 and the crypto/hash libs the stock 10.13 image lacks, and is not on the non-interactive ssh PATH, so put it there for the whole run.  This target keeps the STOCK Apple compiler (clang 10, the 10.13 ceiling), which is what caught #161; it cannot build --enable-roll-simd, because a clang that old rejects configure's target(\"default\") multiversioning probe. That is a compiler-VERSION limit, not a Mach-O one -- see mac-x86-asm below, which builds the same source with MacPorts clang 19 and all three optimizations on.",
      "name": "mac-x86",
      "ssh_host": "tridge@mac",
      "workflow": "macos-build.yml",
      "privilege": "sudo",
      "configure_flags": [
        "--with-rrsync",
        "--enable-md5-asm",
        "--disable-md2man"
      ],
      "_xfail_comment": "Same APFS birthtime caveat as mac2.",
      "xfail": [
        "crtimes"
      ],
      "env_prefix": "export PATH=/opt/local/bin:/opt/local/sbin:$PATH",
      "configure_pre": "CPPFLAGS=\"-I/opt/local/include\"; LDFLAGS=\"-L/opt/local/lib\"; export CPPFLAGS LDFLAGS;",
      "expect_skip_extra": [
        "symlink-mknod-fakesuper-symlink-race"
      ],
      "expect_skip_omit": [
        "sender-remove-source-root-anchor"
      ]
    },
    {
      "_comment": "Same host and OS as mac-x86, built with the SIMD/asm optimizations ON. The only target that exercises --enable-roll-asm/--enable-md5-asm on Mach-O -- the combination Roland Kletzing reported in #160, where an AVX2 over-read (#178) survived two months precisely because nothing built with these flags. Needs MacPorts clang 19 via CC/CXX: Apple clang 10 cannot compile the function-multiversioning probe. Runs after mac-x86, since the harness never runs two targets on one machine at once.",
      "name": "mac-x86-asm",
      "ssh_host": "tridge@mac",
      "workflow": "macos-build.yml",
      "privilege": "sudo",
      "configure_flags": [
        "--with-rrsync",
        "--enable-roll-simd",
        "--enable-roll-asm",
        "--enable-md5-asm",
        "--disable-md2man"
      ],
      "_xfail_comment": "Same APFS birthtime caveat as mac2.",
      "xfail": [
        "crtimes"
      ],
      "env_prefix": "export PATH=/opt/local/bin:/opt/local/sbin:$PATH",
      "configure_pre": "CC=clang-mp-19; CXX=clang++-mp-19; CPPFLAGS=\"-I/opt/local/include\"; LDFLAGS=\"-L/opt/local/lib\"; export CC CXX CPPFLAGS LDFLAGS;",
      "expect_skip_extra": [
        "symlink-mknod-fakesuper-symlink-race"
      ],
      "_expect_skip_omit_comment": "simd-checksum is a macOS-wide expected skip because simdtest is only built when SIMD is enabled -- which is the whole point of this target, so it RUNS here.",
      "expect_skip_omit": [
        "sender-remove-source-root-anchor",
        "simd-checksum"
      ]
    },
    {
      "_comment": "Cygwin: non-root plain user (no sudo), binary is rsync.exe.",
      "name": "cygwin",
      "ssh_host": "win11",
      "workflow": "cygwin-build.yml",
      "rsync_bin": "rsync.exe",
      "privilege": "user",
      "configure_flags": [
        "--with-rrsync"
      ]
    }
  ]
}
