mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-11-01 05:48:18 +00:00
Run the CLI subprocess suites and benchmark tools as native TypeScript with node:test, and move them under test/e2e-cli. Update CI and Compose runners, run local smoke tests on Linux, macOS, and Windows, and collect source-mapped CLI coverage with c8.
101 lines
4.3 KiB
TypeScript
101 lines
4.3 KiB
TypeScript
/**
|
|
* Node.js port of test-sync-locked-remote-linux.sh
|
|
*
|
|
* Verifies CLI sync behaviour when the remote milestone document is unlocked
|
|
* versus locked.
|
|
*/
|
|
|
|
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { mkdir } from "node:fs/promises";
|
|
|
|
import { TempDir } from "./helpers/temp.ts";
|
|
import { runCli } from "./helpers/cli.ts";
|
|
import { applyCouchdbSettings, initSettingsFile } from "./helpers/settings.ts";
|
|
import { createCouchdbDatabase, startCouchdb, stopCouchdb, updateCouchdbDoc } from "./helpers/docker.ts";
|
|
|
|
function assertStringIncludes(actual: string, expected: string, message?: string): void {
|
|
assert.ok(actual.includes(expected), message ?? `Expected ${JSON.stringify(actual)} to include ${JSON.stringify(expected)}`);
|
|
}
|
|
|
|
const MILESTONE_DOC = "_local/obsydian_livesync_milestone";
|
|
|
|
function requireEnv(...keys: string[]): string {
|
|
for (const key of keys) {
|
|
const value = process.env[key]?.trim();
|
|
if (value) return value;
|
|
}
|
|
throw new Error(`Required env var is missing: ${keys.join(" or ")}`);
|
|
}
|
|
|
|
test("sync: actionable error against locked remote DB", async () => {
|
|
const couchdbUri = requireEnv("COUCHDB_URI", "hostname").replace(/\/$/, "");
|
|
const couchdbUser = requireEnv("COUCHDB_USER", "username");
|
|
const couchdbPassword = requireEnv("COUCHDB_PASSWORD", "password");
|
|
const dbPrefix = requireEnv("COUCHDB_DBNAME", "dbname");
|
|
const dbname = `${dbPrefix}-locked-${Date.now()}-${Math.floor(Math.random() * 100000)}`;
|
|
|
|
await using workDir = await TempDir.create("livesync-cli-locked-test");
|
|
const vaultDir = workDir.join("vault");
|
|
const settingsFile = workDir.join("settings.json");
|
|
await mkdir(vaultDir, { recursive: true });
|
|
|
|
const shouldStartDocker = process.env["LIVESYNC_START_DOCKER"] !== "0";
|
|
const keepDocker = process.env["LIVESYNC_DEBUG_KEEP_DOCKER"] === "1";
|
|
|
|
if (shouldStartDocker) {
|
|
console.log(`[INFO] starting CouchDB and creating test database: ${dbname}`);
|
|
await startCouchdb(couchdbUri, couchdbUser, couchdbPassword, dbname);
|
|
} else {
|
|
console.log(`[INFO] using existing CouchDB and creating test database: ${dbname}`);
|
|
await createCouchdbDatabase(couchdbUri, couchdbUser, couchdbPassword, dbname);
|
|
}
|
|
|
|
try {
|
|
await initSettingsFile(settingsFile);
|
|
await applyCouchdbSettings(settingsFile, couchdbUri, couchdbUser, couchdbPassword, dbname, true);
|
|
|
|
console.log("[CASE] initial sync to create milestone document");
|
|
const initialSync = await runCli(vaultDir, "--settings", settingsFile, "sync");
|
|
assert(
|
|
initialSync.code === 0,
|
|
`initial sync failed\nstdout: ${initialSync.stdout}\nstderr: ${initialSync.stderr}`
|
|
);
|
|
|
|
const updateMilestone = async (locked: boolean) => {
|
|
await updateCouchdbDoc(couchdbUri, couchdbUser, couchdbPassword, `${dbname}/${MILESTONE_DOC}`, (doc) => ({
|
|
...doc,
|
|
locked,
|
|
accepted_nodes: [],
|
|
}));
|
|
};
|
|
|
|
console.log("[CASE] sync should succeed when remote is not locked");
|
|
await updateMilestone(false);
|
|
const unlockedSync = await runCli(vaultDir, "--settings", settingsFile, "sync");
|
|
assert(
|
|
unlockedSync.code === 0,
|
|
`sync should succeed when remote is not locked\nstdout: ${unlockedSync.stdout}\nstderr: ${unlockedSync.stderr}`
|
|
);
|
|
assert(
|
|
!unlockedSync.combined.includes("The remote database is locked"),
|
|
`locked error should not appear when remote is not locked\n${unlockedSync.combined}`
|
|
);
|
|
console.log("[PASS] unlocked remote DB syncs successfully");
|
|
|
|
console.log("[CASE] sync should fail with actionable error when remote is locked");
|
|
await updateMilestone(true);
|
|
const lockedSync = await runCli(vaultDir, "--settings", settingsFile, "sync");
|
|
assert(
|
|
lockedSync.code !== 0,
|
|
`sync should fail when remote is locked\nstdout: ${lockedSync.stdout}\nstderr: ${lockedSync.stderr}`
|
|
);
|
|
assertStringIncludes(lockedSync.combined, "The remote database is locked and this device is not yet accepted");
|
|
console.log("[PASS] locked remote DB produces actionable CLI error");
|
|
} finally {
|
|
if (shouldStartDocker && !keepDocker) {
|
|
await stopCouchdb().catch(() => {});
|
|
}
|
|
}
|
|
});
|