test: cover collision and permission failures

This commit is contained in:
2026-07-23 10:20:08 +00:00
parent 63da21f07d
commit 3d09e32ccd
2 changed files with 42 additions and 2 deletions
+3 -1
View File
@@ -45,7 +45,9 @@ source staging, and command replay after a target client disconnect. The final
hostile cases change the source selection and make an absent target appear hostile cases change the source selection and make an absent target appear
after confirmation; each must fail before commit with its exact precondition after confirmation; each must fail before commit with its exact precondition
reason. qBittorrent is also checked for zero downloaded bytes at the replayed reason. qBittorrent is also checked for zero downloaded bytes at the replayed
target. target. Finally, a wrong-size pre-existing target and an unwritable target root
must fail without committing or losing the source; the permission fixture
restores the target root's original mode even on an aborted run.
The scheduler pause/resume endpoints exist only on the loopback test adapter; The scheduler pause/resume endpoints exist only on the loopback test adapter;
normal control and Telegram orchestration always use the automatic scheduler. normal control and Telegram orchestration always use the automatic scheduler.
+39 -1
View File
@@ -97,6 +97,15 @@ assert_qb() {
--selected "$selected" >/dev/null --selected "$selected" >/dev/null
} }
archive2_download_mode=
restore_archive2_download_mode() {
if [[ -n "$archive2_download_mode" ]]; then
compose_node archive-2 exec -T qbittorrent \
chmod "$archive2_download_mode" /downloads >/dev/null 2>&1 || true
fi
}
trap restore_archive2_download_mode EXIT
for node in cache-1 cache-2 archive-1 archive-2; do for node in cache-1 cache-2 archive-1 archive-2; do
delete_torrent "$node" "$legacy_bundle_hash" delete_torrent "$node" "$legacy_bundle_hash"
delete_torrent "$node" "$bundle_hash" delete_torrent "$node" "$bundle_hash"
@@ -377,6 +386,35 @@ control_scenario expect-failure \
assert_qb cache-1 "$cancel_hash" '0' assert_qb cache-1 "$cancel_hash" '0'
delete_torrent archive-2 "$cancel_hash" delete_torrent archive-2 "$cancel_hash"
target_collision_job=$(control_scenario create-paused \
--operation archive \
--source-client cache-1 \
--target-client archive-2 \
--info-hash "$cancel_hash")
compose_node archive-2 exec -T --user 1001:1001 qbittorrent /bin/sh -c \
'printf "wrong-size\n" > /downloads/fixture.bin'
control_scenario expect-failure \
--job-id "$target_collision_job" \
--contains 'pre-existing destination size does not match'
assert_qb cache-1 "$cancel_hash" '0'
compose_node archive-2 exec -T qbittorrent rm -f /downloads/fixture.bin
permission_job=$(control_scenario create-paused \
--operation archive \
--source-client cache-1 \
--target-client archive-2 \
--info-hash "$cancel_hash")
archive2_download_mode=$(compose_node archive-2 exec -T qbittorrent \
stat -c '%a' /downloads)
compose_node archive-2 exec -T qbittorrent chmod 0555 /downloads
control_scenario expect-failure \
--job-id "$permission_job" \
--contains 'Permission denied'
restore_archive2_download_mode
archive2_download_mode=
assert_qb cache-1 "$cancel_hash" '0'
printf '%s\n' \ printf '%s\n' \
'complex matrix passed: selective merges, union eviction, hostile retention,' \ 'complex matrix passed: selective merges, union eviction, hostile retention,' \
'queued/partial cancellation, restart/replay, and hostile state changes' 'queued/partial cancellation, restart/replay, hostile state changes,' \
'target collisions, and permission denial'