Prepare consistent Chunk sizes and fresh Fast Fetch integration

This commit is contained in:
vorotamoroz committed 2026-10-23 09:12:02 +00:00
1 parent ce0524d49f
commit d1e4c34054
24 files changed
+2042 -14

No files matched your search

@@ -47,6 +47,16 @@ const uiTimeoutMs = Number(process.env.E2E_OBSIDIAN_SETUP_URI_TIMEOUT_MS ?? 3000
const e2eePassphrase = `%${randomBytes(24).toString("base64url")}`;
const notePath = "E2E/manual-couchdb/from-first-device.md";
const noteContent = "# Manual CouchDB setup\n\nThis note was sent by the manually configured first device.\n";
const binaryPath = "E2E/manual-couchdb/content-boundaries.png";
const binaryBlockSize = 32 * 1024;
function binaryFixture(): Uint8Array {
const bytes = new Uint8Array(binaryBlockSize * 8);
for (let index = 0; index < 8; index++) {
bytes[index * binaryBlockSize] = index + 2;
bytes[(index + 1) * binaryBlockSize - 1] = 1;
}
return bytes;
}
const returnNotePath = "E2E/manual-couchdb/from-second-device.md";
const returnNoteContent =
"# Manual CouchDB return journey\n\nThis note returned through a Setup URI generated by the first device.\n";
@@ -395,6 +405,32 @@ async function waitForVaultFile(
throw new Error(`Timed out waiting for ${path}. Last content:\n${lastContent}`);
}
async function waitForBinaryFile(vault: TemporaryVault): Promise<void> {
const expected = Buffer.from(binaryFixture());
const deadline = Date.now() + Number(process.env.E2E_OBSIDIAN_FILE_TIMEOUT_MS ?? 30000);
while (Date.now() < deadline) {
try {
if ((await readFile(join(vault.path, binaryPath))).equals(expected)) return;
} catch (error) {
if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
}
await new Promise((resolve) => setTimeout(resolve, 250));
}
throw new Error("The fetched binary did not match its exact original bytes.");
}
async function readChunkInventory(context: RunnerContext, session: ObsidianLiveSyncSession): Promise<string[]> {
return await evalObsidianJson<string[]>(
context.cliBinary,
`(async()=>{
const core=app.plugins.plugins['obsidian-livesync'].core;
const rows=(await core.localDatabase.allDocsRaw({include_docs:true})).rows;
return JSON.stringify(rows.filter(row=>row.doc?.type==='leaf').map(row=>row.id).sort());
})()`,
session.cliEnv
);
}
async function waitForRemoteEntry(context: RunnerContext, entry: { id: string; children: string[] }): Promise<void> {
await waitForCouchDbDocs(context.couchDb, context.dbName, (docs) => {
const ids = new Set(docs.map((doc) => doc._id));
@@ -681,6 +717,8 @@ async function main(): Promise<void> {
process.env.E2E_OBSIDIAN_INDEPENDENT_IDS === "true" ? randomBytes(32).toString("base64url") : undefined;
let firstEntryId: string | undefined;
let returnEntryId: string | undefined;
let binaryRevision: string | undefined;
let chunkInventory: string[] = [];
try {
await assertCouchDbReachable(couchDb);
@@ -712,10 +750,34 @@ async function main(): Promise<void> {
}
await writeNoteViaObsidian(context.cliBinary, session.cliEnv, notePath, noteContent);
const size = await evalObsidianJson<number>(
context.cliBinary,
`JSON.stringify(app.plugins.plugins['obsidian-livesync'].core.settings.customChunkSize)`,
session.cliEnv
);
assertEqual(size, 0, "New manual setup did not retain the common Chunk-size recommendation.");
await evalObsidianJson(
context.cliBinary,
`(async()=>{
const bytes=new Uint8Array(${binaryBlockSize}*8);
for(let index=0;index<8;index++){
bytes[index*${binaryBlockSize}]=index+2;
bytes[(index+1)*${binaryBlockSize}-1]=1;
}
await app.vault.createBinary(${JSON.stringify(binaryPath)},bytes.buffer);
return JSON.stringify(true);
})()`,
session.cliEnv
);
const binaryEntry = await waitForLocalDatabaseEntry(context.cliBinary, session.cliEnv, binaryPath);
assertEqual(binaryEntry.children.length, 8, "V3 size 0 did not use the expected content boundaries.");
binaryRevision = binaryEntry.rev;
const entry = await waitForLocalDatabaseEntry(context.cliBinary, session.cliEnv, notePath);
firstEntryId = entry.id;
await pushLocalChanges(context.cliBinary, session.cliEnv);
await waitForRemoteEntry(context, entry);
await waitForRemoteEntry(context, binaryEntry);
chunkInventory = await readChunkInventory(context, session);
} catch (error) {
await captureFailure(session, "first-device");
throw error;
@@ -729,6 +791,13 @@ async function main(): Promise<void> {
session = await startUnconfiguredSession(context, vaultA);
try {
await assertRestoredE2EEPassphrase(session, context.cliBinary);
const unchanged = await waitForLocalDatabaseEntry(context.cliBinary, session.cliEnv, binaryPath);
assertEqual(unchanged.rev, binaryRevision, "Restart rewrote unchanged binary Metadata.");
assertEqual(
JSON.stringify(await readChunkInventory(context, session)),
JSON.stringify(chunkInventory),
"Restart created Chunks for unchanged Vault files."
);
await scheduleRemoteOverwrite(session.remoteDebuggingPort);
screenshots.push(await confirmRebuild(session.remoteDebuggingPort, e2eeRebuildCaptures));
screenshots.push(
@@ -775,6 +844,7 @@ async function main(): Promise<void> {
await assertPersistedE2EE(vaultB, independentIdSource);
await pushLocalChanges(context.cliBinary, session.cliEnv);
await waitForVaultFile(vaultB, notePath, noteContent);
await waitForBinaryFile(vaultB);
if (independentIdSource) {
assertEqual(
await readDocumentId(context.cliBinary, session.cliEnv, notePath),
@@ -815,7 +885,7 @@ async function main(): Promise<void> {
}
console.log(
`Manual CouchDB onboarding created and tested its database, generated a second-device Setup URI, and completed a bidirectional note round-trip. Screenshots: ${screenshots.join(", ")}`
`Manual CouchDB onboarding retained size 0, used binary content boundaries, preserved unchanged revisions and Chunks across restart, fetched exact binary bytes, and completed a bidirectional note round-trip. Screenshots: ${screenshots.join(", ")}`
);
} finally {
await stopTrackedSessions(context).catch((error: unknown) => {