mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-05-04 14:51:52 +00:00
### Fixed
- Fixed flaky timing issues in P2P synchronisation. - Fixed more binary file handling issues in CLI. ### Tests - Rewrite P2P end-to-end tests to use the CLI as host.
This commit is contained in:
0
src/apps/cli/test/test-p2p-three-nodes-conflict-linux.sh
Normal file → Executable file
0
src/apps/cli/test/test-p2p-three-nodes-conflict-linux.sh
Normal file → Executable file
228
src/apps/cli/test/test-p2p-upload-download-repro-linux.sh
Normal file
228
src/apps/cli/test/test-p2p-upload-download-repro-linux.sh
Normal file
@@ -0,0 +1,228 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CLI_DIR="$(cd -- "$SCRIPT_DIR/.." && pwd)"
|
||||
cd "$CLI_DIR"
|
||||
source "$SCRIPT_DIR/test-helpers.sh"
|
||||
display_test_info
|
||||
|
||||
RUN_BUILD="${RUN_BUILD:-1}"
|
||||
KEEP_TEST_DATA="${KEEP_TEST_DATA:-1}"
|
||||
VERBOSE_TEST_LOGGING="${VERBOSE_TEST_LOGGING:-0}"
|
||||
|
||||
RELAY="${RELAY:-ws://localhost:4000/}"
|
||||
USE_INTERNAL_RELAY="${USE_INTERNAL_RELAY:-1}"
|
||||
APP_ID="${APP_ID:-self-hosted-livesync-cli-tests}"
|
||||
PEERS_TIMEOUT="${PEERS_TIMEOUT:-20}"
|
||||
SYNC_TIMEOUT="${SYNC_TIMEOUT:-240}"
|
||||
|
||||
ROOM_ID="p2p-room-$(date +%s)-$RANDOM-$RANDOM"
|
||||
PASSPHRASE="p2p-pass-$(date +%s)-$RANDOM-$RANDOM"
|
||||
|
||||
HOST_PEER_NAME="p2p-cli-host"
|
||||
UPLOAD_PEER_NAME="p2p-cli-upload-$(date +%s)-$RANDOM"
|
||||
DOWNLOAD_PEER_NAME="p2p-cli-download-$(date +%s)-$RANDOM"
|
||||
|
||||
cli_test_init_cli_cmd
|
||||
|
||||
if [[ "$RUN_BUILD" == "1" ]]; then
|
||||
echo "[INFO] building CLI"
|
||||
npm run build
|
||||
fi
|
||||
|
||||
WORK_DIR="$(mktemp -d "${TMPDIR:-/tmp}/livesync-cli-p2p-upload-download.XXXXXX")"
|
||||
VAULT_HOST="$WORK_DIR/vault-host"
|
||||
VAULT_UP="$WORK_DIR/vault-up"
|
||||
VAULT_DOWN="$WORK_DIR/vault-down"
|
||||
SETTINGS_HOST="$WORK_DIR/settings-host.json"
|
||||
SETTINGS_UP="$WORK_DIR/settings-up.json"
|
||||
SETTINGS_DOWN="$WORK_DIR/settings-down.json"
|
||||
HOST_LOG="$WORK_DIR/p2p-host.log"
|
||||
mkdir -p "$VAULT_HOST" "$VAULT_UP" "$VAULT_DOWN"
|
||||
|
||||
cleanup() {
|
||||
local exit_code=$?
|
||||
if [[ -n "${HOST_PID:-}" ]] && kill -0 "$HOST_PID" >/dev/null 2>&1; then
|
||||
kill -TERM "$HOST_PID" >/dev/null 2>&1 || true
|
||||
wait "$HOST_PID" >/dev/null 2>&1 || true
|
||||
fi
|
||||
if [[ "${P2P_RELAY_STARTED:-0}" == "1" ]]; then
|
||||
cli_test_stop_p2p_relay
|
||||
fi
|
||||
if [[ "$KEEP_TEST_DATA" != "1" ]]; then
|
||||
rm -rf "$WORK_DIR"
|
||||
else
|
||||
echo "[INFO] KEEP_TEST_DATA=1, preserving artefacts at $WORK_DIR"
|
||||
fi
|
||||
exit "$exit_code"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
if [[ "$USE_INTERNAL_RELAY" == "1" ]]; then
|
||||
if cli_test_is_local_p2p_relay "$RELAY"; then
|
||||
cli_test_start_p2p_relay
|
||||
P2P_RELAY_STARTED=1
|
||||
else
|
||||
echo "[INFO] USE_INTERNAL_RELAY=1 but RELAY is not local ($RELAY), skipping local relay startup"
|
||||
fi
|
||||
fi
|
||||
|
||||
run_cli_host() {
|
||||
run_cli "$VAULT_HOST" --settings "$SETTINGS_HOST" "$@"
|
||||
}
|
||||
|
||||
run_cli_up() {
|
||||
run_cli "$VAULT_UP" --settings "$SETTINGS_UP" "$@"
|
||||
}
|
||||
|
||||
run_cli_down() {
|
||||
run_cli "$VAULT_DOWN" --settings "$SETTINGS_DOWN" "$@"
|
||||
}
|
||||
|
||||
apply_p2p_test_tweaks() {
|
||||
local settings_file="$1"
|
||||
local device_name="$2"
|
||||
SETTINGS_FILE="$settings_file" DEVICE_NAME="$device_name" PASSPHRASE_VAL="$PASSPHRASE" node <<'NODE'
|
||||
const fs = require("node:fs");
|
||||
const settingsPath = process.env.SETTINGS_FILE;
|
||||
const data = JSON.parse(fs.readFileSync(settingsPath, "utf-8"));
|
||||
|
||||
data.remoteType = "ONLY_P2P";
|
||||
data.encrypt = true;
|
||||
data.passphrase = process.env.PASSPHRASE_VAL;
|
||||
data.usePathObfuscation = true;
|
||||
data.handleFilenameCaseSensitive = false;
|
||||
data.customChunkSize = 50;
|
||||
data.usePluginSyncV2 = true;
|
||||
data.doNotUseFixedRevisionForChunks = false;
|
||||
data.P2P_DevicePeerName = process.env.DEVICE_NAME;
|
||||
data.isConfigured = true;
|
||||
|
||||
fs.writeFileSync(settingsPath, JSON.stringify(data, null, 2), "utf-8");
|
||||
NODE
|
||||
}
|
||||
|
||||
discover_peer_id() {
|
||||
local side="$1"
|
||||
local output
|
||||
local peer_id
|
||||
if [[ "$side" == "up" ]]; then
|
||||
output="$(run_cli_up p2p-peers "$PEERS_TIMEOUT")"
|
||||
else
|
||||
output="$(run_cli_down p2p-peers "$PEERS_TIMEOUT")"
|
||||
fi
|
||||
peer_id="$(awk -F $'\t' 'NF>=3 && $1=="[peer]" {print $2; exit}' <<< "$output")"
|
||||
if [[ -z "$peer_id" ]]; then
|
||||
echo "[FAIL] ${side} could not discover any peer" >&2
|
||||
echo "[FAIL] peers output:" >&2
|
||||
echo "$output" >&2
|
||||
return 1
|
||||
fi
|
||||
echo "$peer_id"
|
||||
}
|
||||
|
||||
echo "[INFO] preparing settings"
|
||||
echo "[INFO] relay=$RELAY room=$ROOM_ID app=$APP_ID"
|
||||
cli_test_init_settings_file "$SETTINGS_HOST"
|
||||
cli_test_init_settings_file "$SETTINGS_UP"
|
||||
cli_test_init_settings_file "$SETTINGS_DOWN"
|
||||
cli_test_apply_p2p_settings "$SETTINGS_HOST" "$ROOM_ID" "$PASSPHRASE" "$APP_ID" "$RELAY" "~.*"
|
||||
cli_test_apply_p2p_settings "$SETTINGS_UP" "$ROOM_ID" "$PASSPHRASE" "$APP_ID" "$RELAY" "~.*"
|
||||
cli_test_apply_p2p_settings "$SETTINGS_DOWN" "$ROOM_ID" "$PASSPHRASE" "$APP_ID" "$RELAY" "~.*"
|
||||
apply_p2p_test_tweaks "$SETTINGS_HOST" "$HOST_PEER_NAME"
|
||||
apply_p2p_test_tweaks "$SETTINGS_UP" "$UPLOAD_PEER_NAME"
|
||||
apply_p2p_test_tweaks "$SETTINGS_DOWN" "$DOWNLOAD_PEER_NAME"
|
||||
|
||||
echo "[CASE] start p2p-host"
|
||||
run_cli_host p2p-host >"$HOST_LOG" 2>&1 &
|
||||
HOST_PID=$!
|
||||
for _ in 1 2 3 4 5 6 7 8 9 10 11 12; do
|
||||
if grep -Fq "P2P host is running" "$HOST_LOG"; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if ! grep -Fq "P2P host is running" "$HOST_LOG"; then
|
||||
echo "[FAIL] p2p-host did not become ready" >&2
|
||||
cat "$HOST_LOG" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "[PASS] p2p-host started"
|
||||
|
||||
echo "[CASE] upload peer discovers host"
|
||||
HOST_PEER_ID_FOR_UP="$(discover_peer_id up)"
|
||||
echo "[PASS] upload peer discovered host: $HOST_PEER_ID_FOR_UP"
|
||||
|
||||
echo "[CASE] upload phase writes source files"
|
||||
STORE_TEXT="$WORK_DIR/store-file.md"
|
||||
DIFF_A_TEXT="$WORK_DIR/test-diff-1.md"
|
||||
DIFF_B_TEXT="$WORK_DIR/test-diff-2.md"
|
||||
DIFF_C_TEXT="$WORK_DIR/test-diff-3.md"
|
||||
printf 'Hello, World!\n' > "$STORE_TEXT"
|
||||
printf 'Content A\n' > "$DIFF_A_TEXT"
|
||||
printf 'Content B\n' > "$DIFF_B_TEXT"
|
||||
printf 'Content C\n' > "$DIFF_C_TEXT"
|
||||
run_cli_up push "$STORE_TEXT" p2p/store-file.md >/dev/null
|
||||
run_cli_up push "$DIFF_A_TEXT" p2p/test-diff-1.md >/dev/null
|
||||
run_cli_up push "$DIFF_B_TEXT" p2p/test-diff-2.md >/dev/null
|
||||
run_cli_up push "$DIFF_C_TEXT" p2p/test-diff-3.md >/dev/null
|
||||
|
||||
LARGE_TXT_100K="$WORK_DIR/large-100k.txt"
|
||||
LARGE_TXT_1M="$WORK_DIR/large-1m.txt"
|
||||
head -c 100000 /dev/zero | tr '\0' 'a' > "$LARGE_TXT_100K"
|
||||
head -c 1000000 /dev/zero | tr '\0' 'b' > "$LARGE_TXT_1M"
|
||||
run_cli_up push "$LARGE_TXT_100K" p2p/large-100000.md >/dev/null
|
||||
run_cli_up push "$LARGE_TXT_1M" p2p/large-1000000.md >/dev/null
|
||||
|
||||
BINARY_100K="$WORK_DIR/binary-100k.bin"
|
||||
BINARY_5M="$WORK_DIR/binary-5m.bin"
|
||||
head -c 100000 /dev/urandom > "$BINARY_100K"
|
||||
head -c 5000000 /dev/urandom > "$BINARY_5M"
|
||||
run_cli_up push "$BINARY_100K" p2p/binary-100000.bin >/dev/null
|
||||
run_cli_up push "$BINARY_5M" p2p/binary-5000000.bin >/dev/null
|
||||
echo "[PASS] upload source files prepared"
|
||||
|
||||
echo "[CASE] upload phase syncs to host"
|
||||
run_cli_up p2p-sync "$HOST_PEER_ID_FOR_UP" "$SYNC_TIMEOUT" >/dev/null
|
||||
run_cli_up p2p-sync "$HOST_PEER_ID_FOR_UP" "$SYNC_TIMEOUT" >/dev/null
|
||||
echo "[PASS] upload phase synced"
|
||||
|
||||
echo "[CASE] download peer discovers host"
|
||||
HOST_PEER_ID_FOR_DOWN="$(discover_peer_id down)"
|
||||
echo "[PASS] download peer discovered host: $HOST_PEER_ID_FOR_DOWN"
|
||||
|
||||
echo "[CASE] download phase syncs from host"
|
||||
run_cli_down p2p-sync "$HOST_PEER_ID_FOR_DOWN" "$SYNC_TIMEOUT" >/dev/null
|
||||
run_cli_down p2p-sync "$HOST_PEER_ID_FOR_DOWN" "$SYNC_TIMEOUT" >/dev/null
|
||||
echo "[PASS] download phase synced"
|
||||
|
||||
echo "[CASE] verify text files on download peer"
|
||||
DOWN_STORE_TEXT="$WORK_DIR/down-store-file.md"
|
||||
DOWN_DIFF_A_TEXT="$WORK_DIR/down-test-diff-1.md"
|
||||
DOWN_DIFF_B_TEXT="$WORK_DIR/down-test-diff-2.md"
|
||||
DOWN_DIFF_C_TEXT="$WORK_DIR/down-test-diff-3.md"
|
||||
run_cli_down pull p2p/store-file.md "$DOWN_STORE_TEXT" >/dev/null
|
||||
run_cli_down pull p2p/test-diff-1.md "$DOWN_DIFF_A_TEXT" >/dev/null
|
||||
run_cli_down pull p2p/test-diff-2.md "$DOWN_DIFF_B_TEXT" >/dev/null
|
||||
run_cli_down pull p2p/test-diff-3.md "$DOWN_DIFF_C_TEXT" >/dev/null
|
||||
cmp -s "$STORE_TEXT" "$DOWN_STORE_TEXT" || { echo "[FAIL] store-file mismatch" >&2; exit 1; }
|
||||
cmp -s "$DIFF_A_TEXT" "$DOWN_DIFF_A_TEXT" || { echo "[FAIL] test-diff-1 mismatch" >&2; exit 1; }
|
||||
cmp -s "$DIFF_B_TEXT" "$DOWN_DIFF_B_TEXT" || { echo "[FAIL] test-diff-2 mismatch" >&2; exit 1; }
|
||||
cmp -s "$DIFF_C_TEXT" "$DOWN_DIFF_C_TEXT" || { echo "[FAIL] test-diff-3 mismatch" >&2; exit 1; }
|
||||
|
||||
echo "[CASE] verify pushed files on download peer"
|
||||
DOWN_LARGE_100K="$WORK_DIR/down-large-100k.txt"
|
||||
DOWN_LARGE_1M="$WORK_DIR/down-large-1m.txt"
|
||||
DOWN_BINARY_100K="$WORK_DIR/down-binary-100k.bin"
|
||||
DOWN_BINARY_5M="$WORK_DIR/down-binary-5m.bin"
|
||||
run_cli_down pull p2p/large-100000.md "$DOWN_LARGE_100K" >/dev/null
|
||||
run_cli_down pull p2p/large-1000000.md "$DOWN_LARGE_1M" >/dev/null
|
||||
run_cli_down pull p2p/binary-100000.bin "$DOWN_BINARY_100K" >/dev/null
|
||||
run_cli_down pull p2p/binary-5000000.bin "$DOWN_BINARY_5M" >/dev/null
|
||||
cmp -s "$LARGE_TXT_100K" "$DOWN_LARGE_100K" || { echo "[FAIL] large-100000 mismatch" >&2; exit 1; }
|
||||
cmp -s "$LARGE_TXT_1M" "$DOWN_LARGE_1M" || { echo "[FAIL] large-1000000 mismatch" >&2; exit 1; }
|
||||
cmp -s "$BINARY_100K" "$DOWN_BINARY_100K" || { echo "[FAIL] binary-100000 mismatch" >&2; exit 1; }
|
||||
cmp -s "$BINARY_5M" "$DOWN_BINARY_5M" || { echo "[FAIL] binary-5000000 mismatch" >&2; exit 1; }
|
||||
|
||||
echo "[PASS] CLI P2P upload/download reproduction scenario completed"
|
||||
Reference in New Issue
Block a user