mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-08-01 00:06:28 -04:00
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>
11 KiB
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.pythat 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 |
Links
| 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, daemontimeout,max connections) need a real socket + concurrency (run under--use-tcp). - Root-only behaviours (
-o/--usermapuid 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-idshave no dedicated test yet (lower restructure risk).