Files
rsync/testsuite/xattrs-depth_test.py
Andrew Tridgell 273b9f265f testsuite: metadata preservation coverage at depth
Set each attribute distinctively on a file AND a directory at every level of a
>=3-deep tree and verify it per entry after transfer (metadata is applied as a
single-component op on an entry whose parent chain the resolver restructure
rewrites):

  metadata-depth   -p preserves exact file/dir modes; -t preserves file
                   mtimes; --chmod=D710,F600 rewrites them.
  omit-times       -O omits directory times (files still preserved); -J omits
                   symlink times.
  sparse           -S preserves a deep file's hole (allocated << size);
                   --no-sparse fills it.
  xattrs-depth     -X reproduces a user xattr on every entry (gated on xattr
                   support).
  acls-depth       -A reproduces a POSIX ACL on every entry (gated on ACL
                   support + setfacl/getfacl).
  ownership-depth  --groupmap and --chown=:GROUP remap the group of every
                   entry (non-root, to a secondary group); -o/--usermap gated
                   on root.

All green on master and under --protocol=29/30.

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

53 lines
1.5 KiB
Python

#!/usr/bin/env python3
"""Coverage of -X (xattrs) at depth.
xattrs_test.py exercises a shallow tree; this companion sets a distinctive user
xattr on a file AND a directory at every level of a >=3-deep tree and checks
that -X reproduces them all (the xattr is applied per entry, on a name whose
parent chain the resolver restructure rewrites).
"""
import os
import sys
from rsyncfns import (
FROMDIR, TODIR,
make_tree, rmtree, run_rsync, test_fail, test_skipped,
walk_dirs, walk_files, xattr_dump, xattr_set, xattrs_supported,
)
if not xattrs_supported():
test_skipped("rsync built without xattr support (or no xattr tooling here)")
src = FROMDIR
rmtree(src)
rmtree(TODIR)
make_tree(src, depth=3)
entries = [p.relative_to(src) for p in (walk_dirs(src) + walk_files(src))]
entries.sort()
os.chdir(src)
try:
for i, rel in enumerate(entries):
xattr_set('depth', f'value-{i}-{rel}', str(rel))
except OSError as e:
test_skipped(f"unable to set an xattr on this filesystem: {e}")
want = xattr_dump(*[str(r) for r in entries])
run_rsync('-aX', '-f-x_system.*', '-f-x_security.*', '--super',
f'{src}/', f'{TODIR}/')
os.chdir(TODIR)
got = xattr_dump(*[str(r) for r in entries])
if got != want:
from difflib import unified_diff
sys.stdout.write(''.join(unified_diff(
want.splitlines(keepends=True), got.splitlines(keepends=True),
fromfile='source', tofile='dest')))
test_fail("xattrs differ between source and destination at depth")
print("xattrs-depth: -X reproduced a user xattr on every entry at depth")