test: expand phase 8 fault matrix
This commit is contained in:
Executable
+382
@@ -0,0 +1,382 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
source "$(dirname "$0")/lib.sh"
|
||||
|
||||
bundle_hash=547cec172aab2f4d418d73d4f5fc0d2794e971b7
|
||||
bundle_torrent=ZDQ6aW5mb2Q1OmZpbGVzbGQ2Omxlbmd0aGkxNjM4NGU0OnBhdGhsOTphbHBoYS5iaW5lZWQ2Omxlbmd0aGkxNjM4NGU0OnBhdGhsNjpuZXN0ZWQ5OmJyYXZvLmJpbmVlZDY6bGVuZ3RoaTE2Mzg0ZTQ6cGF0aGw2Om5lc3RlZDExOmNoYXJsaWUuYmluZWVkNjpsZW5ndGhpMTYzODRlNDpwYXRobDk6ZGVsdGEuYmluZWVlNDpuYW1lNjpidW5kbGUxMjpwaWVjZSBsZW5ndGhpMTYzODRlNjpwaWVjZXM4MDp9tnus7uyzpCC/N6e+ykpFGF+PPHmZb79ZCq2dp84v4EgIIzMZE7bwEMQCvl+7qybWEDECinYwiKcGKn82sWFjoNungr001vTmtGeLhKBGd2Vl
|
||||
legacy_bundle_hash=305af159425d76140eea48d20cfcfbb3f8dccf46
|
||||
shared_hash=03fbcf663bd3fe80c298ca54a55780a6b1d4b43b
|
||||
shared_torrent=ZDQ6aW5mb2Q1OmZpbGVzbGQ2Omxlbmd0aGkxNjM4NGU0OnBhdGhsNjpuZXN0ZWQ5OmJyYXZvLmJpbmVlZTQ6bmFtZTY6YnVuZGxlMTI6cGllY2UgbGVuZ3RoaTE2Mzg0ZTY6cGllY2VzMjA6eZlvv1kKrZ2nzi/gSAgjMxkTtvBlZQ==
|
||||
cancel_hash=330be0cb7c2201135a2de63b28e77993745ff688
|
||||
cancel_torrent=ZDQ6aW5mb2Q2Omxlbmd0aGkzMWU0Om5hbWUxMTpmaXh0dXJlLmJpbjEyOnBpZWNlIGxlbmd0aGkxNjM4NGU2OnBpZWNlczIwOlFlB05MtIUU4oem2MNz5LJW/GI6ZWU=
|
||||
|
||||
control_scenario() {
|
||||
compose_control exec -T control \
|
||||
python /e2e/scenarios/complex_jobs.py "$@"
|
||||
}
|
||||
|
||||
qb_endpoint() {
|
||||
case "$1" in
|
||||
cache-1) printf '%s' http://qb-cache-1:8080/api/v2 ;;
|
||||
cache-2) printf '%s' http://qb-cache-2:8080/api/v2 ;;
|
||||
archive-1) printf '%s' http://qb-archive-1:8080/api/v2 ;;
|
||||
archive-2) printf '%s' http://qb-archive-2:8080/api/v2 ;;
|
||||
*) printf 'unknown E2E node: %s\n' "$1" >&2; return 2 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
wait_qb_present() {
|
||||
local node=$1
|
||||
local info_hash=$2
|
||||
local deadline=$((SECONDS + 30))
|
||||
while (( SECONDS < deadline )); do
|
||||
local records
|
||||
records=$(compose_node "$node" exec -T qbittorrent curl -fsS \
|
||||
"http://127.0.0.1:8080/api/v2/torrents/info?hashes=$info_hash")
|
||||
if [[ "$records" != "[]" ]]; then
|
||||
return
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
printf 'timed out waiting for torrent %s on %s\n' \
|
||||
"$info_hash" "$node" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
delete_torrent() {
|
||||
local node=$1
|
||||
local info_hash=$2
|
||||
compose_node "$node" exec -T qbittorrent curl -fsS \
|
||||
-X POST http://127.0.0.1:8080/api/v2/torrents/delete \
|
||||
--data-urlencode "hashes=$info_hash" \
|
||||
--data-urlencode "deleteFiles=true" >/dev/null || true
|
||||
control_scenario assert-qb \
|
||||
--endpoint "$(qb_endpoint "$node")" \
|
||||
--info-hash "$info_hash" \
|
||||
--absent >/dev/null
|
||||
}
|
||||
|
||||
install_torrent() {
|
||||
local node=$1
|
||||
local info_hash=$2
|
||||
local encoded=$3
|
||||
local save_path=$4
|
||||
local selected=$5
|
||||
local all_indices=$6
|
||||
compose_node "$node" exec -T qbittorrent /bin/sh -c \
|
||||
"printf '%s' '$encoded' | base64 -d > /tmp/e2e.torrent"
|
||||
compose_node "$node" exec -T qbittorrent curl -fsS \
|
||||
-X POST http://127.0.0.1:8080/api/v2/torrents/add \
|
||||
-F torrents=@/tmp/e2e.torrent \
|
||||
-F "savepath=$save_path" \
|
||||
-F stopped=true >/dev/null
|
||||
wait_qb_present "$node" "$info_hash"
|
||||
compose_node "$node" exec -T qbittorrent curl -fsS \
|
||||
-X POST http://127.0.0.1:8080/api/v2/torrents/filePrio \
|
||||
--data-urlencode "hash=$info_hash" \
|
||||
--data-urlencode "id=$all_indices" \
|
||||
--data-urlencode "priority=0" >/dev/null
|
||||
compose_node "$node" exec -T qbittorrent curl -fsS \
|
||||
-X POST http://127.0.0.1:8080/api/v2/torrents/filePrio \
|
||||
--data-urlencode "hash=$info_hash" \
|
||||
--data-urlencode "id=$selected" \
|
||||
--data-urlencode "priority=1" >/dev/null
|
||||
compose_node "$node" exec -T qbittorrent curl -fsS \
|
||||
-X POST http://127.0.0.1:8080/api/v2/torrents/recheck \
|
||||
--data-urlencode "hashes=$info_hash" >/dev/null
|
||||
}
|
||||
|
||||
assert_qb() {
|
||||
local node=$1
|
||||
local info_hash=$2
|
||||
local selected=$3
|
||||
control_scenario assert-qb \
|
||||
--endpoint "$(qb_endpoint "$node")" \
|
||||
--info-hash "$info_hash" \
|
||||
--selected "$selected" >/dev/null
|
||||
}
|
||||
|
||||
for node in cache-1 cache-2 archive-1 archive-2; do
|
||||
delete_torrent "$node" "$legacy_bundle_hash"
|
||||
delete_torrent "$node" "$bundle_hash"
|
||||
delete_torrent "$node" "$shared_hash"
|
||||
delete_torrent "$node" "$cancel_hash"
|
||||
compose_node "$node" exec -T qbittorrent /bin/sh -c \
|
||||
'rm -f /downloads/bundle/alpha.bin \
|
||||
/downloads/bundle/nested/bravo.bin \
|
||||
/downloads/bundle/nested/charlie.bin \
|
||||
/downloads/bundle/delta.bin \
|
||||
/downloads/bundle/unknown.keep \
|
||||
/downloads/fixture.bin; \
|
||||
rmdir /downloads/bundle/nested /downloads/bundle 2>/dev/null || true'
|
||||
compose_node "$node" exec -T qbittorrent /bin/sh -c \
|
||||
'chown -R 1001:1001 /downloads/bundle 2>/dev/null || true'
|
||||
done
|
||||
|
||||
compose_node cache-1 exec -T --user 1001:1001 qbittorrent /bin/sh -c \
|
||||
'mkdir -p /downloads/bundle/nested; \
|
||||
dd if=/dev/zero bs=16384 count=1 2>/dev/null | tr "\000" A \
|
||||
> /downloads/bundle/alpha.bin; \
|
||||
dd if=/dev/zero bs=16384 count=1 2>/dev/null | tr "\000" C \
|
||||
> /downloads/bundle/nested/charlie.bin'
|
||||
install_torrent cache-1 "$bundle_hash" "$bundle_torrent" \
|
||||
/downloads '0|2' '0|1|2|3'
|
||||
assert_qb cache-1 "$bundle_hash" '0,2'
|
||||
|
||||
compose_node cache-2 exec -T --user 1001:1001 qbittorrent /bin/sh -c \
|
||||
'mkdir -p /downloads/bundle/nested; \
|
||||
dd if=/dev/zero bs=16384 count=1 2>/dev/null | tr "\000" B \
|
||||
> /downloads/bundle/nested/bravo.bin; \
|
||||
dd if=/dev/zero bs=16384 count=1 2>/dev/null | tr "\000" D \
|
||||
> /downloads/bundle/delta.bin'
|
||||
install_torrent cache-2 "$bundle_hash" "$bundle_torrent" \
|
||||
/downloads '1|3' '0|1|2|3'
|
||||
assert_qb cache-2 "$bundle_hash" '1,3'
|
||||
|
||||
control_scenario stale-preview \
|
||||
--operation archive \
|
||||
--source-client cache-1 \
|
||||
--target-client archive-1 \
|
||||
--info-hash "$bundle_hash" \
|
||||
--selected '0' >/dev/null
|
||||
|
||||
control_scenario transfer \
|
||||
--operation archive \
|
||||
--source-client cache-1 \
|
||||
--target-client archive-1 \
|
||||
--info-hash "$bundle_hash" \
|
||||
--selected '0,2' \
|
||||
--expected-selection '0,2' \
|
||||
--expected-delta '0,2'
|
||||
assert_qb archive-1 "$bundle_hash" '0,2'
|
||||
|
||||
control_scenario preview-error \
|
||||
--operation evict_cache \
|
||||
--cache-client cache-2 \
|
||||
--info-hash "$bundle_hash" \
|
||||
--status 400 \
|
||||
--contains 'missing file indices'
|
||||
|
||||
control_scenario transfer \
|
||||
--operation archive \
|
||||
--source-client cache-2 \
|
||||
--target-client archive-2 \
|
||||
--info-hash "$bundle_hash" \
|
||||
--selected '1,3' \
|
||||
--expected-selection '1,3' \
|
||||
--expected-delta '1,3'
|
||||
assert_qb archive-2 "$bundle_hash" '1,3'
|
||||
|
||||
compose_node cache-2 exec -T --user 1001:1001 qbittorrent /bin/sh -c \
|
||||
'dd if=/dev/zero bs=16384 count=1 2>/dev/null | tr "\000" A \
|
||||
> /downloads/bundle/alpha.bin; \
|
||||
dd if=/dev/zero bs=16384 count=1 2>/dev/null | tr "\000" C \
|
||||
> /downloads/bundle/nested/charlie.bin'
|
||||
compose_node cache-2 exec -T qbittorrent curl -fsS \
|
||||
-X POST http://127.0.0.1:8080/api/v2/torrents/filePrio \
|
||||
--data-urlencode "hash=$bundle_hash" \
|
||||
--data-urlencode 'id=0|1|2|3' \
|
||||
--data-urlencode priority=1 >/dev/null
|
||||
compose_node cache-2 exec -T qbittorrent curl -fsS \
|
||||
-X POST http://127.0.0.1:8080/api/v2/torrents/recheck \
|
||||
--data-urlencode "hashes=$bundle_hash" >/dev/null
|
||||
assert_qb cache-2 "$bundle_hash" '0,1,2,3'
|
||||
|
||||
control_scenario evict \
|
||||
--cache-client cache-2 \
|
||||
--info-hash "$bundle_hash" \
|
||||
--minimum-coverage-proofs 2
|
||||
control_scenario assert-qb \
|
||||
--endpoint "$(qb_endpoint cache-2)" \
|
||||
--info-hash "$bundle_hash" \
|
||||
--absent >/dev/null
|
||||
|
||||
control_scenario transfer \
|
||||
--operation unarchive \
|
||||
--source-client archive-1 \
|
||||
--target-client cache-2 \
|
||||
--info-hash "$bundle_hash" \
|
||||
--selected '0,2' \
|
||||
--expected-selection '0,2' \
|
||||
--expected-delta '0,2'
|
||||
assert_qb cache-2 "$bundle_hash" '0,2'
|
||||
|
||||
control_scenario transfer \
|
||||
--operation unarchive \
|
||||
--source-client archive-2 \
|
||||
--target-client cache-2 \
|
||||
--info-hash "$bundle_hash" \
|
||||
--selected '1,3' \
|
||||
--expected-selection '1,3' \
|
||||
--expected-delta '1,3'
|
||||
assert_qb cache-2 "$bundle_hash" '0,1,2,3'
|
||||
|
||||
control_scenario transfer \
|
||||
--operation archive \
|
||||
--source-client cache-2 \
|
||||
--target-client archive-1 \
|
||||
--info-hash "$bundle_hash" \
|
||||
--selected '1,3' \
|
||||
--expected-selection '1,3' \
|
||||
--expected-delta '1,3'
|
||||
assert_qb archive-1 "$bundle_hash" '0,1,2,3'
|
||||
|
||||
control_scenario transfer \
|
||||
--operation archive \
|
||||
--source-client cache-2 \
|
||||
--target-client archive-2 \
|
||||
--info-hash "$bundle_hash" \
|
||||
--selected '0,2' \
|
||||
--expected-selection '0,2' \
|
||||
--expected-delta '0,2'
|
||||
assert_qb archive-2 "$bundle_hash" '0,1,2,3'
|
||||
|
||||
control_scenario preview-error \
|
||||
--operation archive \
|
||||
--source-client cache-2 \
|
||||
--target-client archive-1 \
|
||||
--info-hash "$bundle_hash" \
|
||||
--selected '0' \
|
||||
--status 400 \
|
||||
--contains 'already contains'
|
||||
|
||||
control_scenario evict \
|
||||
--cache-client cache-1 \
|
||||
--info-hash "$bundle_hash"
|
||||
control_scenario transfer \
|
||||
--operation unarchive \
|
||||
--source-client archive-1 \
|
||||
--target-client cache-1 \
|
||||
--info-hash "$bundle_hash" \
|
||||
--selected '1' \
|
||||
--expected-selection '1' \
|
||||
--expected-delta '1'
|
||||
assert_qb cache-1 "$bundle_hash" '1'
|
||||
|
||||
compose_node cache-1 exec -T --user 1001:1001 qbittorrent /bin/sh -c \
|
||||
'printf "preserve-unknown\n" > /downloads/bundle/unknown.keep'
|
||||
install_torrent cache-1 "$shared_hash" "$shared_torrent" \
|
||||
/downloads '0' '0'
|
||||
assert_qb cache-1 "$shared_hash" '0'
|
||||
control_scenario evict \
|
||||
--cache-client cache-1 \
|
||||
--info-hash "$bundle_hash"
|
||||
control_scenario assert-qb \
|
||||
--endpoint "$(qb_endpoint cache-1)" \
|
||||
--info-hash "$bundle_hash" \
|
||||
--absent >/dev/null
|
||||
assert_qb cache-1 "$shared_hash" '0'
|
||||
compose_node cache-1 exec -T qbittorrent test -f \
|
||||
/downloads/bundle/nested/bravo.bin
|
||||
compose_node cache-1 exec -T qbittorrent test -f \
|
||||
/downloads/bundle/unknown.keep
|
||||
|
||||
compose_node cache-1 exec -T --user 1001:1001 qbittorrent /bin/sh -c \
|
||||
'printf "archive-control-e2e-happy-path\n" > /downloads/fixture.bin'
|
||||
install_torrent cache-1 "$cancel_hash" "$cancel_torrent" \
|
||||
/downloads '0' '0'
|
||||
assert_qb cache-1 "$cancel_hash" '0'
|
||||
|
||||
control_scenario queued-cancel \
|
||||
--operation archive \
|
||||
--source-client cache-1 \
|
||||
--target-client archive-1 \
|
||||
--info-hash "$cancel_hash"
|
||||
compose_node cache-1 exec -T qbittorrent test -f /downloads/fixture.bin
|
||||
|
||||
cancel_job=$(control_scenario drive \
|
||||
--operation archive \
|
||||
--source-client cache-1 \
|
||||
--target-client archive-2 \
|
||||
--info-hash "$cancel_hash" \
|
||||
--through target_materialize)
|
||||
control_scenario cancel --job-id "$cancel_job"
|
||||
control_scenario assert-qb \
|
||||
--endpoint "$(qb_endpoint archive-2)" \
|
||||
--info-hash "$cancel_hash" \
|
||||
--absent >/dev/null
|
||||
if compose_node archive-2 exec -T qbittorrent \
|
||||
test -e /downloads/fixture.bin; then
|
||||
printf 'precommit cancellation left a materialized target file\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
assert_qb cache-1 "$cancel_hash" '0'
|
||||
|
||||
restart_job=$(control_scenario drive \
|
||||
--operation archive \
|
||||
--source-client cache-1 \
|
||||
--target-client archive-1 \
|
||||
--info-hash "$cancel_hash" \
|
||||
--through source_stage)
|
||||
compose_control restart control
|
||||
sleep 2
|
||||
control_scenario resume --job-id "$restart_job"
|
||||
assert_qb archive-1 "$cancel_hash" '0'
|
||||
|
||||
delete_torrent archive-2 "$cancel_hash"
|
||||
replay_job=$(control_scenario drive \
|
||||
--operation archive \
|
||||
--source-client cache-1 \
|
||||
--target-client archive-2 \
|
||||
--info-hash "$cancel_hash" \
|
||||
--through source_stage)
|
||||
compose_node archive-2 stop client
|
||||
sleep 1
|
||||
control_scenario advance \
|
||||
--job-id "$replay_job" \
|
||||
--action syncthing_transfer >/dev/null
|
||||
compose_node archive-2 start client
|
||||
control_scenario resume --job-id "$replay_job"
|
||||
control_scenario assert-qb \
|
||||
--endpoint "$(qb_endpoint archive-2)" \
|
||||
--info-hash "$cancel_hash" \
|
||||
--selected '0' \
|
||||
--no-downloaded >/dev/null
|
||||
|
||||
delete_torrent archive-2 "$cancel_hash"
|
||||
stale_source_job=$(control_scenario create-paused \
|
||||
--operation archive \
|
||||
--source-client cache-1 \
|
||||
--target-client archive-2 \
|
||||
--info-hash "$cancel_hash")
|
||||
compose_node cache-1 exec -T qbittorrent curl -fsS \
|
||||
-X POST http://127.0.0.1:8080/api/v2/torrents/filePrio \
|
||||
--data-urlencode "hash=$cancel_hash" \
|
||||
--data-urlencode id=0 \
|
||||
--data-urlencode priority=0 >/dev/null
|
||||
control_scenario expect-failure \
|
||||
--job-id "$stale_source_job" \
|
||||
--contains 'source resource changed after job confirmation'
|
||||
compose_node cache-1 exec -T qbittorrent curl -fsS \
|
||||
-X POST http://127.0.0.1:8080/api/v2/torrents/filePrio \
|
||||
--data-urlencode "hash=$cancel_hash" \
|
||||
--data-urlencode id=0 \
|
||||
--data-urlencode priority=1 >/dev/null
|
||||
compose_node cache-1 exec -T qbittorrent curl -fsS \
|
||||
-X POST http://127.0.0.1:8080/api/v2/torrents/recheck \
|
||||
--data-urlencode "hashes=$cancel_hash" >/dev/null
|
||||
assert_qb cache-1 "$cancel_hash" '0'
|
||||
|
||||
target_appeared_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 qbittorrent /bin/sh -c \
|
||||
"printf '%s' '$cancel_torrent' | base64 -d > /tmp/appeared.torrent"
|
||||
compose_node archive-2 exec -T qbittorrent curl -fsS \
|
||||
-X POST http://127.0.0.1:8080/api/v2/torrents/add \
|
||||
-F torrents=@/tmp/appeared.torrent \
|
||||
-F savepath=/downloads \
|
||||
-F stopped=true >/dev/null
|
||||
wait_qb_present archive-2 "$cancel_hash"
|
||||
control_scenario expect-failure \
|
||||
--job-id "$target_appeared_job" \
|
||||
--contains 'target resource appeared after job confirmation'
|
||||
assert_qb cache-1 "$cancel_hash" '0'
|
||||
delete_torrent archive-2 "$cancel_hash"
|
||||
|
||||
printf '%s\n' \
|
||||
'complex matrix passed: selective merges, union eviction, hostile retention,' \
|
||||
'queued/partial cancellation, restart/replay, and hostile state changes'
|
||||
@@ -24,3 +24,6 @@ done
|
||||
if [[ "${E2E_RUN_TRANSFER:-0}" == "1" ]]; then
|
||||
"$E2E_ROOT/scripts/archive-happy.sh"
|
||||
fi
|
||||
if [[ "${E2E_RUN_COMPLEX:-0}" == "1" ]]; then
|
||||
"$E2E_ROOT/scripts/complex-matrix.sh"
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user