Files
obsidian-livesync/test/suitep2p/run-p2p-tests.sh
vorotamoroz 6c69547cef ### 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.
2026-03-16 00:48:22 +09:00

195 lines
6.3 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd -- "$SCRIPT_DIR/../.." && pwd)"
CLI_DIR="$REPO_ROOT/src/apps/cli"
CLI_TEST_HELPERS="$CLI_DIR/test/test-helpers.sh"
source "$CLI_TEST_HELPERS"
RUN_BUILD="${RUN_BUILD:-1}"
KEEP_TEST_DATA="${KEEP_TEST_DATA:-1}"
VERBOSE_TEST_LOGGING="${VERBOSE_TEST_LOGGING:-1}"
RELAY="${RELAY:-ws://localhost:4000/}"
USE_INTERNAL_RELAY="${USE_INTERNAL_RELAY:-1}"
APP_ID="${APP_ID:-self-hosted-livesync-vitest-p2p}"
HOST_PEER_NAME="${HOST_PEER_NAME:-p2p-cli-host}"
ROOM_ID="p2p-room-$(date +%s)-$RANDOM-$RANDOM"
PASSPHRASE="p2p-pass-$(date +%s)-$RANDOM-$RANDOM"
UPLOAD_PEER_NAME="p2p-upload-$(date +%s)-$RANDOM"
DOWNLOAD_PEER_NAME="p2p-download-$(date +%s)-$RANDOM"
UPLOAD_VAULT_NAME="TestVaultUpload-$(date +%s)-$RANDOM"
DOWNLOAD_VAULT_NAME="TestVaultDownload-$(date +%s)-$RANDOM"
# ---- Build CLI ----
if [[ "$RUN_BUILD" == "1" ]]; then
echo "[INFO] building CLI"
(cd "$CLI_DIR" && npm run build)
fi
# ---- Temp directory ----
WORK_DIR="$(mktemp -d "${TMPDIR:-/tmp}/livesync-vitest-p2p.XXXXXX")"
VAULT_HOST="$WORK_DIR/vault-host"
SETTINGS_HOST="$WORK_DIR/settings-host.json"
HOST_LOG="$WORK_DIR/p2p-host.log"
# Handoff file: upload phase writes this; download phase reads it.
HANDOFF_FILE="$WORK_DIR/p2p-test-handoff.json"
mkdir -p "$VAULT_HOST"
# ---- Setup CLI command (uses npm run cli from CLI_DIR) ----
# Override run_cli to invoke the built binary directly from CLI_DIR
run_cli() {
(cd "$CLI_DIR" && node dist/index.cjs "$@")
}
# ---- Create host settings ----
echo "[INFO] relay=$RELAY room=$ROOM_ID app=$APP_ID host=$HOST_PEER_NAME"
cli_test_init_settings_file "$SETTINGS_HOST"
cli_test_apply_p2p_settings "$SETTINGS_HOST" "$ROOM_ID" "$PASSPHRASE" "$APP_ID" "$RELAY" "~.*"
# Set host peer name
SETTINGS_HOST_FILE="$SETTINGS_HOST" HOST_PEER_NAME_VAL="$HOST_PEER_NAME" HOST_PASSPHRASE_VAL="$PASSPHRASE" node <<'NODE'
const fs = require("node:fs");
const data = JSON.parse(fs.readFileSync(process.env.SETTINGS_HOST_FILE, "utf-8"));
// Keep tweak values aligned with browser-side P2P test settings.
data.remoteType = "ONLY_P2P";
data.encrypt = true;
data.passphrase = process.env.HOST_PASSPHRASE_VAL;
data.usePathObfuscation = true;
data.handleFilenameCaseSensitive = false;
data.customChunkSize = 50;
data.usePluginSyncV2 = true;
data.doNotUseFixedRevisionForChunks = false;
data.P2P_DevicePeerName = process.env.HOST_PEER_NAME_VAL;
fs.writeFileSync(process.env.SETTINGS_HOST_FILE, JSON.stringify(data, null, 2), "utf-8");
NODE
# ---- Cleanup trap ----
cleanup() {
local exit_code=$?
if [[ -n "${HOST_PID:-}" ]] && kill -0 "$HOST_PID" >/dev/null 2>&1; then
echo "[INFO] stopping CLI host (PID=$HOST_PID)"
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
start_host() {
local attempt=0
while [[ "$attempt" -lt 5 ]]; do
attempt=$((attempt + 1))
echo "[INFO] starting CLI p2p-host (attempt $attempt/5)"
: >"$HOST_LOG"
(cd "$CLI_DIR" && node dist/index.cjs "$VAULT_HOST" --settings "$SETTINGS_HOST" -d p2p-host) >"$HOST_LOG" 2>&1 &
HOST_PID=$!
local host_ready=0
local exited_early=0
for i in $(seq 1 30); do
if grep -qF "P2P host is running" "$HOST_LOG" 2>/dev/null; then
host_ready=1
break
fi
if ! kill -0 "$HOST_PID" >/dev/null 2>&1; then
exited_early=1
break
fi
echo "[INFO] waiting for p2p-host to be ready... ($i/30)"
sleep 1
done
if [[ "$host_ready" == "1" ]]; then
echo "[INFO] p2p-host is ready (PID=$HOST_PID)"
return 0
fi
wait "$HOST_PID" >/dev/null 2>&1 || true
HOST_PID=
if grep -qF "Resource temporarily unavailable" "$HOST_LOG" 2>/dev/null; then
echo "[INFO] p2p-host database lock is still being released, retrying..."
sleep 2
continue
fi
if [[ "$exited_early" == "1" ]]; then
echo "[FAIL] CLI host process exited unexpectedly" >&2
else
echo "[FAIL] p2p-host did not become ready within 30 seconds" >&2
fi
cat "$HOST_LOG" >&2
exit 1
done
echo "[FAIL] p2p-host could not be restarted after multiple attempts" >&2
cat "$HOST_LOG" >&2
exit 1
}
# ---- Start local relay if needed ----
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"
fi
fi
start_host
# Common env vars passed to both vitest runs
P2P_ENV=(
P2P_TEST_ROOM_ID="$ROOM_ID"
P2P_TEST_PASSPHRASE="$PASSPHRASE"
P2P_TEST_HOST_PEER_NAME="$HOST_PEER_NAME"
P2P_TEST_RELAY="$RELAY"
P2P_TEST_APP_ID="$APP_ID"
P2P_TEST_HANDOFF_FILE="$HANDOFF_FILE"
P2P_TEST_UPLOAD_PEER_NAME="$UPLOAD_PEER_NAME"
P2P_TEST_DOWNLOAD_PEER_NAME="$DOWNLOAD_PEER_NAME"
P2P_TEST_UPLOAD_VAULT_NAME="$UPLOAD_VAULT_NAME"
P2P_TEST_DOWNLOAD_VAULT_NAME="$DOWNLOAD_VAULT_NAME"
)
cd "$REPO_ROOT"
# ---- Phase 1: Upload ----
# Each vitest run gets a fresh browser process, so Trystero's module-level
# global state (occupiedRooms, didInit, etc.) is clean for every phase.
echo "[INFO] running P2P vitest — upload phase"
env "${P2P_ENV[@]}" \
npx dotenv-cli -e .env -e .test.env -- \
vitest run --config vitest.config.p2p.ts test/suitep2p/syncp2p.p2p-up.test.ts
echo "[INFO] upload phase completed"
# ---- Phase 2: Download ----
# Keep the same host process alive so its database handle and relay presence stay stable.
echo "[INFO] waiting 5s before download phase..."
sleep 5
echo "[INFO] running P2P vitest — download phase"
env "${P2P_ENV[@]}" \
npx dotenv-cli -e .env -e .test.env -- \
vitest run --config vitest.config.p2p.ts test/suitep2p/syncp2p.p2p-down.test.ts
echo "[INFO] download phase completed"
echo "[INFO] P2P vitest suite completed"