mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-07-23 04:52:58 +00:00
Wait for stable upgrade fixtures to initialise
This commit is contained in:
@@ -144,6 +144,8 @@ The workflow first exercises a non-empty legacy settings document which has no `
|
||||
|
||||
For CouchDB and Object Storage, the workflow then configures 0.25.83 from its own defaults, saves the selected remote, and restarts that release with the same profile before creating history. This both verifies that the old settings persist and lets the old release initialise its replicator from the same saved state as an ordinary existing Vault. The runner waits for that release's asynchronously initialised persistent node identity, creates, edits, renames, and deletes notes, and synchronises each transition before installing the target. Every launch of the upgraded device uses the same isolated Obsidian profile. The session layer closes the renderer before its process-tree fallback, so Chromium persists the legacy compatibility marker naturally; the target must read and migrate that actual profile state to its current namespaced key. The final target restart likewise consumes the marker persisted by the preceding target session. The runner does not reconstruct that device's Vault data, plug-in settings, local database files, device-local state, or remote state. Before the target performs any synchronisation, it must retain the same Vault profile, local database, node identity, remote profile, local checkpoint, and remote milestone. The local node-info document is the identity source of truth; a transient replicator field is used only to confirm that the old asynchronous initialisation has completed. Its first synchronisation must be a no-op: CouchDB document revisions and `update_seq` must remain unchanged, while Object Storage must neither upload nor download journal bodies. The upgraded device then sends a new delta. A separate fresh 1.0 verifier starts from an explicit current-version settings and compatibility fixture, receives the complete surviving history, and returns another delta; it is not part of the legacy-profile migration assertion. The upgraded Vault receives that return journey and retains it across restart.
|
||||
|
||||
Before creating stable-release history, the runner waits until the remote Security Seed can be read and only then marks the remote as resolved. Completion of the old release's remote-creation method alone does not prove that this asynchronous fixture boundary is ready.
|
||||
|
||||
Run the focused wrapper after source changes so that the target plug-in is rebuilt first:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const { evalObsidianJson } = vi.hoisted(() => ({
|
||||
evalObsidianJson: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("./cli.ts", () => ({ evalObsidianJson }));
|
||||
|
||||
import { prepareStableRemote } from "./upgradeWorkflow.ts";
|
||||
|
||||
describe("stable remote preparation", () => {
|
||||
afterEach(() => {
|
||||
vi.unstubAllEnvs();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("waits for a readable Security Seed before marking the remote as resolved", async () => {
|
||||
vi.stubEnv("E2E_OBSIDIAN_REMOTE_READY_INTERVAL_MS", "0");
|
||||
vi.stubEnv("E2E_OBSIDIAN_REMOTE_READY_TIMEOUT_MS", "100");
|
||||
evalObsidianJson
|
||||
.mockResolvedValueOnce({ ok: true })
|
||||
.mockResolvedValueOnce(false)
|
||||
.mockResolvedValueOnce(true)
|
||||
.mockResolvedValueOnce({ ok: true });
|
||||
|
||||
await prepareStableRemote("obsidian-cli", {});
|
||||
|
||||
expect(evalObsidianJson).toHaveBeenCalledTimes(4);
|
||||
const scripts = evalObsidianJson.mock.calls.map(([, script]) => String(script));
|
||||
expect(scripts[0]).toContain("tryCreateRemoteDatabase");
|
||||
expect(scripts[0]).not.toContain("markRemoteResolved");
|
||||
expect(scripts[1]).toContain("ensurePBKDF2Salt");
|
||||
expect(scripts[2]).toContain("ensurePBKDF2Salt");
|
||||
expect(scripts[3]).toContain("markRemoteResolved");
|
||||
});
|
||||
});
|
||||
@@ -190,6 +190,43 @@ export async function prepareStableRemote(cliBinary: string, environment: NodeJS
|
||||
"const settings=core.services.setting.currentSettings();",
|
||||
"const replicator=core.services.replicator.getActiveReplicator();",
|
||||
"await replicator.tryCreateRemoteDatabase(settings);",
|
||||
"return JSON.stringify({ok:true});",
|
||||
"})()",
|
||||
].join(""),
|
||||
environment
|
||||
);
|
||||
|
||||
const timeoutMs = Number(process.env.E2E_OBSIDIAN_REMOTE_READY_TIMEOUT_MS ?? 15000);
|
||||
const intervalMs = Number(process.env.E2E_OBSIDIAN_REMOTE_READY_INTERVAL_MS ?? 250);
|
||||
const deadline = Date.now() + timeoutMs;
|
||||
let securitySeedReady = false;
|
||||
do {
|
||||
securitySeedReady = await evalObsidianJson<boolean>(
|
||||
cliBinary,
|
||||
[
|
||||
"(async()=>{",
|
||||
"const core=app.plugins.plugins['obsidian-livesync'].core;",
|
||||
"const settings=core.services.setting.currentSettings();",
|
||||
"const replicator=core.services.replicator.getActiveReplicator();",
|
||||
"return JSON.stringify(!!(await replicator.ensurePBKDF2Salt(settings,true,false)));",
|
||||
"})()",
|
||||
].join(""),
|
||||
environment
|
||||
);
|
||||
if (securitySeedReady) break;
|
||||
if (Date.now() < deadline) await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
||||
} while (Date.now() < deadline);
|
||||
if (!securitySeedReady) {
|
||||
throw new Error(`Timed out waiting for the stable release Security Seed after ${timeoutMs}ms.`);
|
||||
}
|
||||
|
||||
await evalObsidianJson<unknown>(
|
||||
cliBinary,
|
||||
[
|
||||
"(async()=>{",
|
||||
"const core=app.plugins.plugins['obsidian-livesync'].core;",
|
||||
"const settings=core.services.setting.currentSettings();",
|
||||
"const replicator=core.services.replicator.getActiveReplicator();",
|
||||
"await replicator.markRemoteResolved(settings);",
|
||||
"return JSON.stringify({ok:true});",
|
||||
"})()",
|
||||
|
||||
@@ -608,7 +608,10 @@ async function runObjectStorageUpgrade(context: RunnerContext, ports: readonly [
|
||||
await prepareStableRemote(context.cliBinary, session.cliEnv);
|
||||
await runStableFileHistory(context.cliBinary, session.cliEnv, paths, async () => {
|
||||
const result = await runJournalReplicationObserved(context.cliBinary, session.cliEnv);
|
||||
assert(result.succeeded, "The stable Object Storage synchronisation failed.");
|
||||
assert(
|
||||
result.succeeded,
|
||||
`The stable Object Storage synchronisation failed.\nObservation: ${JSON.stringify(result)}`
|
||||
);
|
||||
});
|
||||
await verifyPreUpgradeHistory(upgradeVault, paths);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user