testsuite: generate predictable fixture files instead of reading /etc, /bin, /

The Python rewrite of the suite carried over the shell habit of
populating the test tree by capturing "ls -l /etc" / "ls -l /bin"
(falling back to "ls /"): hands_setup() built etc-ltr-list / bin-lt-list
that way, and longdir_test.py did the same for its leaf files. That ties
the fixtures to the host filesystem layout -- those directories are
absent or unreadable on Android/Termux and other minimal environments,
where "ls /" fails outright -- and the captured content was never
reproducible from run to run.

Add a deterministic make_text_file() helper to rsyncfns.py and use it for
hands_setup()'s two fixture files and longdir's leaf files. The names
etc-ltr-list / bin-lt-list are unchanged (chmod, chmod-temp-dir and
alt-dest reference them by name); only the content source changes, so the
fixtures are now self-contained and identical on every platform. This
also drops longdir_test.py's date(1) and ls(1) subprocess calls.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Andrew Tridgell
2026-05-22 14:41:17 +10:00
parent 743d715d43
commit 1d8f47cc71
2 changed files with 34 additions and 23 deletions

View File

@@ -6,10 +6,8 @@
# 175-char directory names, drop a couple of files in the leaf, and
# verify that --delete -avH still produces an identical destination.
import os
import subprocess
from rsyncfns import FROMDIR, TODIR, checkit, hands_setup, test_skipped
from rsyncfns import (FROMDIR, TODIR, checkit, hands_setup, make_text_file,
test_skipped)
hands_setup()
@@ -29,13 +27,8 @@ try:
except OSError:
test_skipped("unable to create files in long directory")
# Drop some recognisably-varied content into the two leaf files.
(longdir / '1').write_text(subprocess.check_output(['date'], text=True))
listdir = '/etc' if os.access('/etc', os.R_OK) else '/'
out = subprocess.run(['ls', '-la', listdir], capture_output=True, text=True)
# ls exits 1 if it can't stat some entries (e.g. permission-denied files in
# /etc); the shell test silently accepts that. We do the same.
(longdir / '2').write_text(out.stdout)
# Drop predictable, self-contained content into the two leaf files.
make_text_file(longdir / '1', 50)
make_text_file(longdir / '2', 100)
checkit(['--delete', '-avH', f'{FROMDIR}/', str(TODIR)], FROMDIR, TODIR)

View File

@@ -410,6 +410,26 @@ def make_data_file(path, size: int) -> 'None':
f.write(bytes(out))
def make_text_file(path, lines: int = 100) -> 'None':
"""Write a predictable, self-contained text file of `lines` lines.
This replaces the old habit of capturing `ls -l /etc` / `ls -l /bin`
(falling back to `ls /`) into the test tree. Those tied the fixtures
to the host filesystem layout: the directories are absent or
unreadable on Android/Termux and other minimal environments, where
`ls /` fails outright, and the captured content was never
reproducible. The output here is deterministic and depends on nothing
outside the suite, so every platform builds the identical fixture.
"""
content = ''.join(
"line %06d the quick brown fox jumps over the lazy dog %d %d\n"
% (i, (i * 31) % 97, (i * 131) % 89)
for i in range(1, lines + 1)
)
with open(str(path), 'w') as f:
f.write(content)
def get_testuid() -> int:
return os.getuid()
@@ -677,11 +697,12 @@ def build_symlinks() -> 'None':
def hands_setup() -> 'None':
"""Equivalent of rsync.fns hands_setup: populate FROMDIR with a varied
tree of files and directories for the canonical 'hands' transfer test.
"""Populate FROMDIR with a varied tree of files and directories for the
canonical 'hands' transfer test.
Recreates the shell behavior bit-for-bit so the tls listings match
across the shell and Python halves of the suite during the transition.
All content is generated from within the suite (srcdir contents plus
make_text_file output) so the fixture is self-contained and
reproducible on every platform.
"""
rmtree(FROMDIR)
rmtree(TODIR)
@@ -717,15 +738,12 @@ def hands_setup() -> 'None':
(FROMDIR / 'dir' / 'subdir').mkdir(exist_ok=True)
(FROMDIR / 'dir' / 'subdir' / 'foobar.baz').write_text("some data\n")
(FROMDIR / 'dir' / 'subdir' / 'subsubdir').mkdir(exist_ok=True)
src_listdir = '/etc' if os.access('/etc', os.R_OK) else '/'
out = subprocess.run(['ls', '-ltr', src_listdir], capture_output=True, text=True)
(FROMDIR / 'dir' / 'subdir' / 'subsubdir' / 'etc-ltr-list').write_text(out.stdout)
# Predictable, self-contained fixture files (the names etc-ltr-list /
# bin-lt-list are kept because other tests reference them by name).
make_text_file(FROMDIR / 'dir' / 'subdir' / 'subsubdir' / 'etc-ltr-list', 120)
(FROMDIR / 'dir' / 'subdir' / 'subsubdir2').mkdir(exist_ok=True)
src_listdir = '/bin' if os.access('/bin', os.R_OK) else '/'
out = subprocess.run(['ls', '-lt', src_listdir], capture_output=True, text=True)
(FROMDIR / 'dir' / 'subdir' / 'subsubdir2' / 'bin-lt-list').write_text(out.stdout)
make_text_file(FROMDIR / 'dir' / 'subdir' / 'subsubdir2' / 'bin-lt-list', 200)
# --- listing / verification ------------------------------------------------