mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-08-27 13:57:07 +00:00
118 lines
5.2 KiB
TypeScript
118 lines
5.2 KiB
TypeScript
import { assert, assertEquals, assertStringIncludes } from "@std/assert";
|
|
import { join } from "@std/path";
|
|
import { TempDir } from "./helpers/temp.ts";
|
|
import { initSettingsFile, applyP2pSettings, applyP2pTestTweaks } from "./helpers/settings.ts";
|
|
import { startCliInBackground } from "./helpers/backgroundCli.ts";
|
|
import { maybeStartLocalRelay, stopLocalRelayIfStarted, maybeStartCoturn, stopCoturnIfStarted } from "./helpers/p2p.ts";
|
|
import { CLI_DIR, runCli, sanitiseCatStdout } from "./helpers/cli.ts";
|
|
|
|
const NOTE_PATH = "p2p-replicator-replacement.md";
|
|
const NOTE_CONTENT = "Replicated after replacing the active P2P replicator.";
|
|
|
|
async function runReplacementProbe(
|
|
vaultPath: string,
|
|
settingsPath: string,
|
|
targetPeer: string,
|
|
timeoutMs: number
|
|
): Promise<{ code: number; stdout: string; stderr: string }> {
|
|
const command = new Deno.Command("node", {
|
|
args: [
|
|
join(CLI_DIR, "dist", "p2p-lifecycle-test.cjs"),
|
|
vaultPath,
|
|
"--settings",
|
|
settingsPath,
|
|
"p2p-sync",
|
|
targetPeer,
|
|
String(timeoutMs / 1000),
|
|
NOTE_PATH,
|
|
NOTE_CONTENT,
|
|
],
|
|
cwd: CLI_DIR,
|
|
stdout: "piped",
|
|
stderr: "piped",
|
|
});
|
|
const result = await command.output();
|
|
return {
|
|
code: result.code,
|
|
stdout: new TextDecoder().decode(result.stdout),
|
|
stderr: new TextDecoder().decode(result.stderr),
|
|
};
|
|
}
|
|
|
|
Deno.test("p2p lifecycle: replacement keeps real CLI communication on the current replicator", async () => {
|
|
const relay = Deno.env.get("RELAY") ?? "ws://localhost:4000/";
|
|
const peersTimeout = Number(Deno.env.get("PEERS_TIMEOUT") ?? "20");
|
|
const syncTimeout = Number(Deno.env.get("SYNC_TIMEOUT") ?? "60");
|
|
const probeTimeoutMs = Math.max(peersTimeout, syncTimeout) * 1000;
|
|
const nonce = `${Date.now()}-${crypto.randomUUID().slice(0, 8)}`;
|
|
const roomId = Deno.env.get("ROOM_ID") ?? `replacement-room-${nonce}`;
|
|
const passphrase = Deno.env.get("PASSPHRASE") ?? `replacement-pass-${nonce}`;
|
|
const appId = "self-hosted-livesync-cli-replacement-test";
|
|
const hostPeerName = `p2p-replacement-host-${nonce}`;
|
|
const probePeerName = `p2p-replacement-probe-${nonce}`;
|
|
const verifierPeerName = `p2p-replacement-verifier-${nonce}`;
|
|
const useCoturn = Deno.env.get("LIVESYNC_USE_COTURN") !== "0";
|
|
const turnServers = Deno.env.get("TURN_SERVERS") ?? (useCoturn ? "turn:127.0.0.1:3478" : "none");
|
|
|
|
await using workDir = await TempDir.create("livesync-cli-p2p-replacement");
|
|
const hostVault = workDir.join("vault-host");
|
|
const probeVault = workDir.join("vault-probe");
|
|
const verifierVault = workDir.join("vault-verifier");
|
|
const hostSettings = workDir.join("settings-host.json");
|
|
const probeSettings = workDir.join("settings-probe.json");
|
|
const verifierSettings = workDir.join("settings-verifier.json");
|
|
await Promise.all([
|
|
Deno.mkdir(hostVault, { recursive: true }),
|
|
Deno.mkdir(probeVault, { recursive: true }),
|
|
Deno.mkdir(verifierVault, { recursive: true }),
|
|
]);
|
|
|
|
const relayStarted = await maybeStartLocalRelay(relay);
|
|
const coturnStarted = await maybeStartCoturn(turnServers);
|
|
try {
|
|
for (const settingsPath of [hostSettings, probeSettings, verifierSettings]) {
|
|
await initSettingsFile(settingsPath);
|
|
await applyP2pSettings(settingsPath, roomId, passphrase, appId, relay, "~.*", turnServers);
|
|
}
|
|
await applyP2pTestTweaks(hostSettings, hostPeerName, passphrase);
|
|
await applyP2pTestTweaks(probeSettings, probePeerName, passphrase);
|
|
await applyP2pTestTweaks(verifierSettings, verifierPeerName, passphrase);
|
|
|
|
const host = startCliInBackground(hostVault, "--settings", hostSettings, "p2p-host");
|
|
try {
|
|
await host.waitUntilContains("P2P host is running", 20000);
|
|
const probe = await runReplacementProbe(probeVault, probeSettings, hostPeerName, probeTimeoutMs);
|
|
assert(
|
|
probe.code === 0,
|
|
`P2P replacement probe failed\nstdout: ${probe.stdout}\nstderr: ${probe.stderr}`
|
|
);
|
|
assertStringIncludes(probe.stdout, "[Probe] P2P replicator replaced");
|
|
|
|
const syncResult = await runCli(
|
|
verifierVault,
|
|
"--settings",
|
|
verifierSettings,
|
|
"p2p-sync",
|
|
hostPeerName,
|
|
String(syncTimeout)
|
|
);
|
|
assert(
|
|
syncResult.code === 0,
|
|
`Verifier P2P sync failed\nstdout: ${syncResult.stdout}\nstderr: ${syncResult.stderr}`
|
|
);
|
|
|
|
const catResult = await runCli(verifierVault, "--settings", verifierSettings, "cat", NOTE_PATH);
|
|
assert(
|
|
catResult.code === 0,
|
|
`Verifier could not read ${NOTE_PATH}\nstdout: ${catResult.stdout}\nstderr: ${catResult.stderr}`
|
|
);
|
|
assertEquals(sanitiseCatStdout(catResult.stdout).trim(), NOTE_CONTENT);
|
|
} finally {
|
|
await host.stop();
|
|
}
|
|
} finally {
|
|
await stopLocalRelayIfStarted(relayStarted);
|
|
await stopCoturnIfStarted(coturnStarted);
|
|
}
|
|
});
|