mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-09-12 21:28:25 -04:00
testsuite: harden ki58/ki62 tests for the fleet
Two of the integrated MC/DC-audit tests were environment-fragile:
- ki58: asserted the exact string '100% done percentfile', but %f expands to the
transfer-relative path (with leading dirs) when the source is an absolute path,
so the basename assumption failed. Assert the literal-percent escape '100% done '
plus the file name instead (still RED on a broken %%: it emits '100%% done').
- ki62: killed daemon.kill() -- the listener -- but rsyncd forks a child per
connection, so the child sender kept streaming and the receiver hung. Parse the
transfer child's pid from the daemon log ('[pid] rsync on <mod>/') and kill that.
killpg is not usable: the test daemon shares this test's process group.
Fixes are unchanged; only the test drivers.
This commit is contained in:
1 parent
3534cab477
commit
7490ad2420
2 files changed
+29
-5
No files matched your search
@@ -33,10 +33,15 @@ p = subprocess.run(
|
||||
if p.returncode != 0:
|
||||
test_fail(f"rsync exited {p.returncode}:\n{p.stderr}")
|
||||
|
||||
expected = '100% done percentfile'
|
||||
if expected not in p.stdout:
|
||||
# %f expands to the transfer-relative path, which includes leading directories
|
||||
# when the source is addressed by an absolute path (as here) -- so don't pin the
|
||||
# exact filename. The point of this test is the escape: "100% done " with a
|
||||
# single literal percent followed by a space (a broken %% consumes the space or
|
||||
# leaves a doubled percent), plus the transferred file name somewhere.
|
||||
if '100% done ' not in p.stdout or 'percentfile' not in p.stdout:
|
||||
test_fail(
|
||||
f"expected {expected!r} in --out-format output, got:\n{p.stdout}"
|
||||
"expected '100% done ' (a single literal percent) and 'percentfile' in "
|
||||
f"--out-format output, got:\n{p.stdout}"
|
||||
)
|
||||
|
||||
print("ki58-log-format-percent: %% literal-percent escape verified")
|
||||
@@ -19,12 +19,15 @@
|
||||
# Exit codes: 0 pass, 1 fail, 77 skip (killable daemon testing not possible --
|
||||
# the test needs --use-tcp so it can SIGKILL the sender process directly).
|
||||
|
||||
import os
|
||||
import re
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
from rsyncfns import (
|
||||
FROMDIR, TODIR, claim_ports, make_data_file, makepath, rmtree,
|
||||
FROMDIR, SCRATCHDIR, TODIR, claim_ports, make_data_file, makepath, rmtree,
|
||||
rsync_argv, start_rsyncd, test_fail, test_skipped, build_rsyncd_conf,
|
||||
USE_TCP,
|
||||
)
|
||||
@@ -97,7 +100,23 @@ client = subprocess.Popen(
|
||||
# (the path that exercises the io_error -> exit-code mapping).
|
||||
time.sleep(2)
|
||||
|
||||
# Kill the sender (daemon) mid-transfer.
|
||||
# Kill the sender mid-transfer. rsyncd forks a child per connection, so the
|
||||
# actual sender is NOT `daemon` (the listener) -- killing only the listener
|
||||
# leaves the child streaming and the receiver never sees EOF. The child logs
|
||||
# "[pid] rsync on <module>/" to the daemon log; kill that pid (plus the
|
||||
# listener). The daemon shares this test's process group, so killpg is not an
|
||||
# option (it would kill the test itself).
|
||||
child_pids = []
|
||||
try:
|
||||
logtext = (SCRATCHDIR / 'rsyncd.log').read_text()
|
||||
child_pids = [int(pid) for pid in re.findall(r'\[(\d+)\] rsync on ', logtext)]
|
||||
except OSError:
|
||||
pass
|
||||
for pid in child_pids:
|
||||
try:
|
||||
os.kill(pid, signal.SIGKILL)
|
||||
except (ProcessLookupError, PermissionError):
|
||||
pass
|
||||
if daemon.poll() is None:
|
||||
daemon.kill()
|
||||
try:
|
||||
|
||||
Reference in new issue
Block a user