Files
rsync/testsuite/COVERAGE.md
Andrew Tridgell 340238421d testsuite: assert absolute --partial-dir delta resume now works
partial_test.py sub-test 5 deterministically asserts a delta (--no-whole-file)
resume from an absolute, outside-tree --partial-dir reproduces the source and
consumes the basis -- the regression guard for the receiver fix. Sub-test 4
keeps asserting the cross-directory partial WRITE on interrupt. Drop the
--whole-file workaround and the 'broken on master' notes in the docstring and
COVERAGE.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 12:31:52 +10:00

11 KiB

rsync option / daemon-parameter test coverage matrix

Living checklist for the test-coverage effort that precedes the path-handling restructure of rsync's path resolution. The restructure rewrites parent-directory resolution for essentially every option, so the goal here is a regression net that exercises each option at directory depth (≥3 levels) and, where the option spans trees, across directory boundaries, asserting the specific property the option controls — not just dest == src.

How to read the columns:

  • test(s) — the testsuite/*_test.py that exercise the option. Tests added by this effort are marked *new*.
  • depth — Y = asserted on entries ≥3 levels deep; ~ = exercised only at/near the tree root; n/a = not a path-resolution option.
  • x-dir — Y = exercised with the relevant aux tree (temp/backup/dest/partial) outside the main tree; = not a cross-directory option.
  • gap — what is still missing.

Status legend: ✓ property asserted · ~ shallow / by an existing ported test · ✗ no coverage.


Command-line options

Recursion / structure

option test(s) depth x-dir notes / gap
-a, --archive (all) Y ✓ ubiquitous
-r, --recursive hands, delete-deepnew Y
-R, --relative relative, relative-impliednew Y ✓ implied-dir attrs at depth
--no-implied-dirs relative-impliednew Y ✓ (proto 30+; proto 29 rejects multi-component path)
--inc-recursive / --no-inc-recursive hardlinks Y ~ exercised, not isolated
-d, --dirs dirsnew Y ✓ no-recurse top layer
--old-dirs / --old-d
-m, --prune-empty-dirs prune-empty-dirsnew Y ✓ incl. filter-emptied chains
option test(s) depth x-dir notes / gap
-l, --links linksnew, symlink-ignore Y
-L, --copy-links linksnew Y ✓ deref file+dir
-k, --copy-dirlinks linksnew Y ✓ follow dir-symlink
-K, --keep-dirlinks symlink-dirlink-basis Y ✓ #715; skips on no-RESOLVE_BENEATH / --disable-openat2
-H, --hard-links hardlinks, hardlinks-deepnew Y Y ✓ cross-directory hardlink
--copy-unsafe-links unsafe-links ~ ~
--safe-links safe-links ~ ~
--munge-links (daemon-mungenew covers the daemon param) ~ client option not isolated; local mode is a near no-op

Metadata / permissions / ownership

option test(s) depth x-dir notes / gap
-p, --perms metadata-depthnew Y ✓ exact modes per entry
-E, --executability executability ~ ~
--chmod metadata-depthnew, chmod-option Y
-A, --acls acls, acls-depthnew Y
-X, --xattrs xattrs, xattrs-depthnew Y
-t, --times metadata-depthnew Y
-U, --atimes atimes ~ ~ (same set path as -t, covered deep)
--open-noatime open-noatime ~ ~
-N, --crtimes crtimes ~ ~ (skips without crtimes support)
-O, --omit-dir-times omit-timesnew Y
-J, --omit-link-times omit-timesnew Y
-o, --owner chown, ownership-depthnew Y ✓ uid map root-gated
-g, --group chgrp, ownership-depthnew Y ✓ group remap non-root
--super / --fake-super chown, chown-fake ~ ~
--numeric-ids ✗ client; daemon numeric ids also ✗
--usermap / --groupmap ownership-depthnew Y ✓ groupmap non-root; usermap root-gated
--chown ownership-depthnew Y ✓ group half
-D / --devices / --specials devices, devices-fake ~ ~ root/device-gated
--copy-devices / --write-devices ✗ device-gated
-S, --sparse sparsenew Y ✓ hole preserved at depth

Delta / temp / backup / dest (highest restructure risk)

option test(s) depth x-dir notes / gap
-T, --temp-dir temp-dirnew, chmod-temp-dir Y Y ✓ cross-dir rename
--partial partialnew Y ✓ partial kept in dest file
--partial-dir partialnew, symlink-dirlink-basis Y Y ✓ relative (in-tree) + absolute (outside), incl. delta resume from an absolute outside-tree partial
--delay-updates delay-updates, delay-updates-deepnew Y ✓ per-dir staging
--inplace inplacenew, alt-dest Y ✓ inode preserved
--append / --append-verify appendnew Y ✓ verify split is proto 30+
-b, --backup / --backup-dir / --suffix backup, backup-deepnew Y Y
--compare-dest / --copy-dest / --link-dest alt-dest, alt-dest-deepnew Y Y ✓ link=hardlink, copy=copy, compare=skip
-y, --fuzzy fuzzy ~ ~
-u, --update updatenew Y ✓ keeps newer dest, updates older
-W, --whole-file (used widely; --no-whole-file ubiquitous) n/a ~
--mkpath mkpath ~ ~
-x, --one-file-system ✗ (needs a mount boundary)
--preallocate / --fsync
-B, --block-size
--max-alloc

Filtering

option test(s) depth x-dir notes / gap
-f, --filter / -F filter-depthnew, merge Y ✓ deep per-dir merge
--exclude / --include filter-depthnew, exclude, exclude-lsh Y
--exclude-from / --include-from files-from-depthnew Y
-C, --cvs-exclude cvs-excludenew Y ✓ incl. deep .cvsignore
--files-from files-from-depthnew Y
-0, --from0 files-from-depthnew Y
--max-size / --min-size size-filternew Y
--existing / --ignore-existing delete-deepnew Y
--ignore-missing-args / --delete-missing-args

Deletion

option test(s) depth x-dir notes / gap
--delete / --del delete, delete-deepnew Y ✓ deep subtree
--delete-before/during/delay/after delete-deepnew Y ✓ all four agree
--delete-excluded delete ~ ~
--max-delete delete-deepnew Y ✓ caps deletions
--remove-source-files delete ~ ~
--force updatenew Y ✓ replaces a non-empty dir with a file
--ignore-errors ✗ (client; daemon ignore errors also ✗)

Comparison / checksum / compression

option test(s) depth x-dir notes / gap
-c, --checksum comparenew Y ✓ catches stealth change
-I, --ignore-times comparenew Y
--size-only comparenew Y
-@, --modify-window comparenew Y
--checksum-choice / --checksum-seed compress-optionsnew Y ✓ every advertised algo
-z, --compress daemon-gzip-{up,down}load, daemon-refuse-compress ~ ~
--compress-choice / --compress-level / --skip-compress compress-optionsnew Y

Output / reporting (path-irrelevant — checked for output shape)

option test(s) notes / gap
-i, --itemize-changes output-optionsnew, itemize
-n, --dry-run output-optionsnew
--stats output-optionsnew
--out-format output-optionsnew
--list-only output-optionsnew
-q, --quiet output-optionsnew
--progress / -P output-optionsnew ✓ (--progress)
-h, --human-readable / -8, --8-bit-output output-optionsnew ✓ smoke
--version / --help output-optionsnew
--info / --debug / --stderr / --no-motd / --outbuf
-M, --remote-option / --log-file / --log-file-format ✗ (daemon log file covered)

Batch / connection / misc

option test(s) notes / gap
--write-batch / --only-write-batch / --read-batch batch-mode ~
-e, --rsh / --rsync-path ssh-basic, many ~
--protocol check29 / check30 (whole suite)
--address / --port daemon tests under --use-tcp ~
--password-file daemon-authnew
--early-input / daemon early exec
--sockopts / --blocking-io / --timeout / --contimeout
-4/-6, --ipv4/--ipv6
--stop-after / --stop-at
--bwlimit partialnew (used, not asserted) ~
--copy-as ✗ root-gated
--iconv
-s/--secluded-args, --old-args, --trust-sender (default arg-protection exercised) ~

Daemon (rsyncd.conf) parameters

parameter test(s) notes / gap
path daemon-accessnew, all daemon tests ✓ incl. deep sub-path
read only daemon-accessnew, daemon
write only daemon-accessnew
list daemon-accessnew, daemon ✓ hidden-but-usable
use chroot sender-flist-symlink-leak, daemon-chroot-acl ~ (no=most tests; yes needs root)
munge symlinks daemon-mungenew ✓ /rsyncd-munged/ add+strip
exclude / include daemon-filternew, daemon ✓ exclude
filter / exclude from / include from ✗ (exclude covers the mechanism)
incoming chmod daemon-filternew, chmod-option
outgoing chmod daemon-filternew
auth users / secrets file daemon-authnew ✓ accept/reject/unauth
strict modes daemon-authnew ✓ rejects world-readable secrets
refuse options daemon-refusenew, daemon-refuse-compress ✓ named/wildcard/allow-list
pre-xfer exec / post-xfer exec daemon-execnew ✓ env + abort
early exec ✗ (needs --early-input)
hosts allow / hosts deny daemon (allow), daemon-chroot-acl (deny) ~ (needs --use-tcp for real peer)
reverse lookup / forward lookup daemon-chroot-acl ~ reverse only
log file / transfer logging / log format daemon ~ set, not asserted
max verbosity daemon ~
comment daemon, daemon-accessnew
numeric ids ✗ (hard to observe non-root)
fake super chown-fake (client side) ✗ as daemon param
timeout / max connections / lock file ✗ (need --use-tcp + concurrency)
temp dir / open noatime / ignore errors / ignore nonreadable
charset / name converter / dont compress
uid / gid / daemon uid / daemon gid / daemon chroot build_rsyncd_conf (uid/gid when root), daemon-chroot-acl ~ root-gated
motd file / pid file / port / address / socket options / listen backlog / proxy protocol / syslog facility / syslog tag ✗ (server-startup/connection params)

Known gaps worth a future pass

  • Connection/timeout params (--timeout, --contimeout, daemon timeout, max connections) need a real socket + concurrency (run under --use-tcp).
  • Root-only behaviours (-o/--usermap uid remap, real devices, use chroot = yes, daemon uid/gid) skip as non-root; run the suite as root to cover.
  • --ignore-errors, -x/--one-file-system, --numeric-ids have no dedicated test yet (lower restructure risk).