Files
rsync/testsuite/metadata-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

58 lines
1.9 KiB
Python

#!/usr/bin/env python3
"""Coverage of -p (perms), -t (times) and --chmod at depth.
Each attribute is set distinctively on a file AND a directory at every level of
a >=3-deep tree, then checked per entry after the transfer -- the metadata is
applied as a single-component operation on an entry whose parent chain the
resolver restructure rewrites, so it must be verified deep, not just at the
root.
"""
import os
from rsyncfns import (
FROMDIR, TODIR,
assert_mode, assert_mtime_close, make_tree, rmtree, run_rsync, test_fail,
walk_dirs, walk_files,
)
src = FROMDIR
FILE_MODE = 0o640
DIR_MODE = 0o750
BASE_MTIME = 1_400_000_000 # a fixed, clearly-old timestamp
def seed():
rmtree(src)
rmtree(TODIR)
make_tree(src, depth=3)
for i, f in enumerate(walk_files(src)):
os.chmod(f, FILE_MODE)
os.utime(f, (BASE_MTIME + i * 100, BASE_MTIME + i * 100))
for d in walk_dirs(src):
os.chmod(d, DIR_MODE)
# --- -p preserves exact file and directory modes at every level -------------
seed()
run_rsync('-rlpt', f'{src}/', f'{TODIR}/')
for f in walk_files(src):
assert_mode(TODIR / f.relative_to(src), FILE_MODE, label=f'-p file {f.name}')
for d in walk_dirs(src):
assert_mode(TODIR / d.relative_to(src), DIR_MODE, label=f'-p dir {d.name}')
# --- -t preserves file mtimes at every level --------------------------------
for f in walk_files(src):
rel = f.relative_to(src)
assert_mtime_close(TODIR / rel, f.stat().st_mtime, label=f'-t {rel}')
# --- --chmod rewrites modes at every level ----------------------------------
seed()
run_rsync('-a', '--chmod=D710,F600', f'{src}/', f'{TODIR}/')
for f in walk_files(src):
assert_mode(TODIR / f.relative_to(src), 0o600, label=f'--chmod file {f.name}')
for d in walk_dirs(src):
assert_mode(TODIR / d.relative_to(src), 0o710, label=f'--chmod dir {d.name}')
print("metadata-depth: -p / -t / --chmod verified per entry at depth")