mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-05-04 06:41:49 +00:00
- 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.
195 lines
6.3 KiB
Bash
Executable File
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"
|