Clean up deterministic tests
This commit is contained in:
parent
7b9287ca52
commit
f36a84b275
104 changed files with 1366 additions and 3835 deletions
|
|
@ -1,11 +1,9 @@
|
|||
import type { TestDefinition } from "../test-definition";
|
||||
import type { AssertableState } from "../utils/assertable-state";
|
||||
|
||||
export const textPendingCreateNotDisplacedTest: TestDefinition = {
|
||||
name: "Both offline binary creates at same path survive sync",
|
||||
description:
|
||||
"Two clients each create a binary file at the same path while offline. " +
|
||||
"After syncing, both files should exist on both clients at separate paths.",
|
||||
"Two clients each create a text file at the same path while offline. " +
|
||||
"After syncing, the file should contain merged content from both clients.",
|
||||
clients: 2,
|
||||
steps: [
|
||||
{
|
||||
|
|
@ -25,16 +23,6 @@ export const textPendingCreateNotDisplacedTest: TestDefinition = {
|
|||
{ type: "enable-sync", client: 1 },
|
||||
{ type: "barrier" },
|
||||
|
||||
{ type: "assert-consistent", verify: verifyBothFilesExist }
|
||||
{ type: "assert-consistent", verify: (s) => s.assertFileCount(1).assertFileExists("data.txt").assertAnyFileContains("data from client 0", "data from client 1") }
|
||||
]
|
||||
};
|
||||
|
||||
function verifyBothFilesExist(state: AssertableState): void {
|
||||
state
|
||||
.assertFileCount(1)
|
||||
.assertFileExists("data.txt")
|
||||
.assertAnyFileContains(
|
||||
"data from client 0",
|
||||
"data from client 1"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import type { TestDefinition } from "../test-definition";
|
||||
|
||||
export const concurrentUpdateDiffConsistencyTest: TestDefinition = {
|
||||
name: "Concurrent edits to different sections merge correctly",
|
||||
description:
|
||||
"Both clients edit different sections of the same file while offline. " +
|
||||
"After syncing, the merged file should contain both edits.",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
import type { TestDefinition } from "../test-definition";
|
||||
|
||||
export const userParenthesizedFileNotDeletedTest: TestDefinition = {
|
||||
description:
|
||||
"A user-created file named 'Chapter (1).bin' alongside 'Chapter.bin' should not " +
|
||||
"be mistakenly removed when another client creates a conflicting file.",
|
||||
clients: 2,
|
||||
steps: [
|
||||
{ type: "enable-sync", client: 0 },
|
||||
|
||||
{
|
||||
type: "create",
|
||||
client: 0,
|
||||
path: "Chapter.bin",
|
||||
content: "chapter one"
|
||||
},
|
||||
{
|
||||
type: "create",
|
||||
client: 0,
|
||||
path: "Chapter (1).bin",
|
||||
content: "chapter one notes"
|
||||
},
|
||||
|
||||
{ type: "sync", client: 0 },
|
||||
|
||||
{
|
||||
type: "create",
|
||||
client: 1,
|
||||
path: "Chapter.bin",
|
||||
content: "chapter one notes"
|
||||
},
|
||||
{ type: "enable-sync", client: 1 },
|
||||
{ type: "barrier" },
|
||||
|
||||
{
|
||||
type: "assert-consistent",
|
||||
verify: (state) => {
|
||||
state
|
||||
.assertFileCount(3)
|
||||
.assertFileExists("Chapter.bin")
|
||||
.assertFileExists("Chapter (1).bin")
|
||||
.assertFileExists("Chapter (2).bin");
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
import type { TestDefinition } from "../test-definition";
|
||||
|
||||
export const createDeleteNoopTest: TestDefinition = {
|
||||
name: "Offline create then delete results in no file",
|
||||
description:
|
||||
"A client creates a file, updates it multiple times, then deletes it, all while " +
|
||||
"offline. After syncing, neither client should have the file.",
|
||||
|
|
@ -17,8 +16,6 @@ export const createDeleteNoopTest: TestDefinition = {
|
|||
{ type: "enable-sync", client: 0 },
|
||||
{ type: "barrier" },
|
||||
|
||||
{ type: "assert-not-exists", client: 0, path: "temp.md" },
|
||||
{ type: "assert-not-exists", client: 1, path: "temp.md" },
|
||||
{ type: "assert-consistent" }
|
||||
{ type: "assert-consistent", verify: (s) => s.assertFileNotExists("temp.md") }
|
||||
]
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import type { TestDefinition } from "../test-definition";
|
||||
|
||||
export const createMergeDeleteTest: TestDefinition = {
|
||||
name: "Concurrent Create, Merge, Then Delete",
|
||||
description:
|
||||
"Two clients create A.md offline with different content. Both come online and " +
|
||||
"the content is merged. Then one client deletes A.md. Both clients should " +
|
||||
|
|
@ -23,8 +22,6 @@ export const createMergeDeleteTest: TestDefinition = {
|
|||
{ type: "delete", client: 0, path: "A.md" },
|
||||
{ type: "barrier" },
|
||||
|
||||
{ type: "assert-not-exists", client: 0, path: "A.md" },
|
||||
{ type: "assert-not-exists", client: 1, path: "A.md" },
|
||||
{ type: "assert-consistent", verify: (state) => state.assertFileCount(0) }
|
||||
{ type: "assert-consistent", verify: (s) => s.assertFileCount(0).assertFileNotExists("A.md") }
|
||||
]
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import type { TestDefinition } from "../test-definition";
|
||||
|
||||
export const moveIdenticalContentAmbiguityTest: TestDefinition = {
|
||||
name: "Move Detection Ambiguity With Identical Content",
|
||||
description:
|
||||
"Two files with identical content exist. One is deleted and the other renamed " +
|
||||
"while offline. The system should still converge correctly despite the ambiguity.",
|
||||
|
|
@ -23,19 +22,6 @@ export const moveIdenticalContentAmbiguityTest: TestDefinition = {
|
|||
{ type: "enable-sync", client: 1 },
|
||||
{ type: "barrier" },
|
||||
|
||||
{
|
||||
type: "assert-content",
|
||||
client: 1,
|
||||
path: "A.md",
|
||||
content: "identical content"
|
||||
},
|
||||
{
|
||||
type: "assert-content",
|
||||
client: 1,
|
||||
path: "B.md",
|
||||
content: "identical content"
|
||||
},
|
||||
|
||||
{ type: "disable-sync", client: 1 },
|
||||
{ type: "delete", client: 1, path: "A.md" },
|
||||
{ type: "rename", client: 1, oldPath: "B.md", newPath: "C.md" },
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
import type { TestDefinition } from "../test-definition";
|
||||
|
||||
export const writeWriteConflictTest: TestDefinition = {
|
||||
name: "Write/Write Conflict",
|
||||
description:
|
||||
"Two clients simultaneously create the same file with different content. " +
|
||||
"Both contributions should be preserved in the merged result without duplication.",
|
||||
clients: 2,
|
||||
steps: [
|
||||
{ type: "create", client: 0, path: "A.md", content: "hello" },
|
||||
{ type: "create", client: 1, path: "A.md", content: "hello" },
|
||||
{ type: "enable-sync", client: 0 },
|
||||
{ type: "enable-sync", client: 1 },
|
||||
{ type: "barrier" },
|
||||
{
|
||||
type: "assert-consistent",
|
||||
verify: (state) => {
|
||||
state
|
||||
.assertFileCount(1)
|
||||
.assertContent("A.md", "hello")
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
import type { TestDefinition } from "../test-definition";
|
||||
|
||||
export const createUpdateCoalesceServerPauseTest: TestDefinition = {
|
||||
name: "Create and Immediate Update While Server Is Paused",
|
||||
description:
|
||||
"Client creates a file and immediately updates it while the server is " +
|
||||
"paused. When the server resumes, both clients should have the final " +
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import type { TestDefinition } from "../test-definition";
|
||||
|
||||
export const createDuringReconciliationTest: TestDefinition = {
|
||||
name: "File Created Right After Reconnect Syncs Correctly",
|
||||
description:
|
||||
"Client creates two files while offline, reconnects, then immediately " +
|
||||
"creates a third file. All three files should sync to the other client.",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
import type { TestDefinition } from "../test-definition";
|
||||
|
||||
export const createMergePreservesRenamedUpdateTest: TestDefinition = {
|
||||
description:
|
||||
"Both clients create the same file, which gets merged. One client goes " +
|
||||
"offline, renames the file, updates it, and creates a new file at the " +
|
||||
"original path. After reconnecting, the updated content must be preserved.",
|
||||
clients: 2,
|
||||
steps: [
|
||||
{ type: "create", client: 0, path: "doc.md", content: "alpha" },
|
||||
{ type: "create", client: 1, path: "doc.md", content: "beta" },
|
||||
|
||||
{ type: "enable-sync", client: 0 },
|
||||
{ type: "enable-sync", client: 1 },
|
||||
{ type: "barrier" },
|
||||
|
||||
{ type: "disable-sync", client: 1 },
|
||||
|
||||
{
|
||||
type: "rename",
|
||||
client: 1,
|
||||
oldPath: "doc.md",
|
||||
newPath: "moved.md"
|
||||
},
|
||||
{
|
||||
type: "update",
|
||||
client: 1,
|
||||
path: "moved.md",
|
||||
content: "alpha beta extra-update"
|
||||
},
|
||||
|
||||
{
|
||||
type: "create",
|
||||
client: 1,
|
||||
path: "doc.md",
|
||||
content: "new-content"
|
||||
},
|
||||
|
||||
{ type: "enable-sync", client: 1 },
|
||||
{ type: "barrier" },
|
||||
|
||||
{ type: "assert-consistent", verify: (state) => state.assertContent("moved.md", "alpha beta extra-update").assertContent("doc.md", "new-content") }
|
||||
]
|
||||
};
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
import type { TestDefinition } from "../test-definition";
|
||||
|
||||
export const createRenameCreateSamePathTest: TestDefinition = {
|
||||
description:
|
||||
"Client creates A.md, renames to B.md, creates new A.md, renames " +
|
||||
"to C.md, creates yet another A.md. All three files should exist " +
|
||||
"as separate documents on both clients.",
|
||||
clients: 2,
|
||||
steps: [
|
||||
{ type: "create", client: 0, path: "A.md", content: "first file" },
|
||||
{ type: "rename", client: 0, oldPath: "A.md", newPath: "B.md" },
|
||||
|
||||
{ type: "create", client: 0, path: "A.md", content: "second file" },
|
||||
{ type: "rename", client: 0, oldPath: "A.md", newPath: "C.md" },
|
||||
|
||||
{ type: "create", client: 0, path: "A.md", content: "third file" },
|
||||
|
||||
{ type: "enable-sync", client: 0 },
|
||||
{ type: "enable-sync", client: 1 },
|
||||
{ type: "sync" },
|
||||
{ type: "barrier" },
|
||||
|
||||
{
|
||||
type: "assert-consistent",
|
||||
verify: (state) => {
|
||||
state
|
||||
.assertFileCount(3)
|
||||
.assertContent("B.md", "first file")
|
||||
.assertContent("C.md", "second file")
|
||||
.assertContent("A.md", "third file");
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
import type { TestDefinition } from "../test-definition";
|
||||
|
||||
export const moveChainThreeFilesTest: TestDefinition = {
|
||||
description:
|
||||
"Three files have their contents rotated (A gets C's content, B gets A's, C gets B's) " +
|
||||
"while offline. After reconnecting, both clients should converge with the rotated contents.",
|
||||
clients: 2,
|
||||
steps: [
|
||||
{ type: "enable-sync", client: 0 },
|
||||
{ type: "enable-sync", client: 1 },
|
||||
|
||||
{ type: "create", client: 0, path: "A.md", content: "was A" },
|
||||
{ type: "create", client: 0, path: "B.md", content: "was B" },
|
||||
{ type: "create", client: 0, path: "C.md", content: "was C" },
|
||||
{ type: "barrier" },
|
||||
|
||||
{ type: "disable-sync", client: 0 },
|
||||
|
||||
{ type: "delete", client: 0, path: "A.md" },
|
||||
{ type: "delete", client: 0, path: "B.md" },
|
||||
{ type: "delete", client: 0, path: "C.md" },
|
||||
|
||||
{ type: "create", client: 0, path: "A.md", content: "was C" },
|
||||
{ type: "create", client: 0, path: "B.md", content: "was A" },
|
||||
{ type: "create", client: 0, path: "C.md", content: "was B" },
|
||||
|
||||
{ type: "enable-sync", client: 0 },
|
||||
{ type: "barrier" },
|
||||
|
||||
{
|
||||
type: "assert-consistent",
|
||||
verify: (state) => {
|
||||
state
|
||||
.assertFileCount(3)
|
||||
.assertContent("A.md", "was C")
|
||||
.assertContent("B.md", "was A")
|
||||
.assertContent("C.md", "was B");
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
import type { TestDefinition } from "../test-definition";
|
||||
import type { AssertableState } from "../utils/assertable-state";
|
||||
|
||||
export const binaryPendingCreateNotDisplacedTest: TestDefinition = {
|
||||
name: "Both offline binary creates at same path survive sync",
|
||||
description:
|
||||
"Two clients each create a binary file at the same path while offline. " +
|
||||
"After syncing, both files should exist on both clients at separate paths.",
|
||||
|
|
@ -25,17 +23,6 @@ export const binaryPendingCreateNotDisplacedTest: TestDefinition = {
|
|||
{ type: "enable-sync", client: 1 },
|
||||
{ type: "barrier" },
|
||||
|
||||
{ type: "assert-consistent", verify: verifyBothFilesExist }
|
||||
{ type: "assert-consistent", verify: (s) => s.assertFileCount(2).assertFileExists("data.bin").assertFileExists("data (1).bin").assertAnyFileContains("binary data from client 0", "binary data from client 1") }
|
||||
]
|
||||
};
|
||||
|
||||
function verifyBothFilesExist(state: AssertableState): void {
|
||||
state
|
||||
.assertFileCount(2)
|
||||
.assertFileExists("data.bin")
|
||||
.assertFileExists("data (1).bin")
|
||||
.assertAnyFileContains(
|
||||
"binary data from client 0",
|
||||
"binary data from client 1"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import type { TestDefinition } from "../test-definition";
|
||||
|
||||
export const coalesceUpdateRemoteUpdateDataLossTest: TestDefinition = {
|
||||
name: "Local and remote edits to the same file are both preserved",
|
||||
description:
|
||||
"Client 0 edits a file while client 1 is offline. Client 1 reconnects " +
|
||||
"and immediately edits the same file. Both edits should be preserved.",
|
||||
|
|
|
|||
|
|
@ -1,29 +1,24 @@
|
|||
import type { TestDefinition } from "../test-definition";
|
||||
import type { AssertableState } from "../utils/assertable-state";
|
||||
|
||||
export const coalescedRemoteUpdateWatermarkLossTest: TestDefinition = {
|
||||
name: "Coalesced Remote Updates Lose Earlier vaultUpdateIds",
|
||||
description:
|
||||
"When multiple remote-update events for the same document coalesce, " +
|
||||
"only the last vaultUpdateId is recorded. Earlier IDs create " +
|
||||
"permanent watermark gaps that cause unnecessary server replays " +
|
||||
"on every reconnect.",
|
||||
"Client 0 sends three rapid updates. After syncing, both clients " +
|
||||
"disconnect and reconnect twice. Content should remain correct " +
|
||||
"after each reconnect.",
|
||||
clients: 2,
|
||||
steps: [
|
||||
// Setup: both clients have doc.md
|
||||
{ type: "create", client: 0, path: "doc.md", content: "original" },
|
||||
{ type: "enable-sync", client: 0 },
|
||||
{ type: "enable-sync", client: 1 },
|
||||
{ type: "barrier" },
|
||||
|
||||
// Client 0 sends three rapid updates
|
||||
{ type: "update", client: 0, path: "doc.md", content: "update 1" },
|
||||
{ type: "update", client: 0, path: "doc.md", content: "update 2" },
|
||||
{ type: "update", client: 0, path: "doc.md", content: "final update" },
|
||||
{ type: "sync", client: 0 },
|
||||
|
||||
{ type: "barrier" },
|
||||
{ type: "assert-consistent", verify: verifyContent },
|
||||
{ type: "assert-consistent", verify: (s) => s.assertFileCount(1).assertContent("doc.md", "final update") },
|
||||
|
||||
{ type: "disable-sync", client: 0 },
|
||||
{ type: "disable-sync", client: 1 },
|
||||
|
|
@ -31,18 +26,13 @@ export const coalescedRemoteUpdateWatermarkLossTest: TestDefinition = {
|
|||
{ type: "enable-sync", client: 1 },
|
||||
{ type: "barrier" },
|
||||
|
||||
{ type: "assert-consistent", verify: verifyContent },
|
||||
{ type: "assert-consistent", verify: (s) => s.assertFileCount(1).assertContent("doc.md", "final update") },
|
||||
|
||||
{ type: "disable-sync", client: 0 },
|
||||
{ type: "disable-sync", client: 1 },
|
||||
{ type: "enable-sync", client: 0 },
|
||||
{ type: "enable-sync", client: 1 },
|
||||
{ type: "barrier" },
|
||||
{ type: "assert-consistent", verify: verifyContent }
|
||||
{ type: "assert-consistent", verify: (s) => s.assertFileCount(1).assertContent("doc.md", "final update") }
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
function verifyContent(state: AssertableState): void {
|
||||
state.assertFileCount(1).assertContent("doc.md", "final update");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
import { AssertableState } from "src/utils/assertable-state";
|
||||
import type { TestDefinition } from "../test-definition";
|
||||
|
||||
export const concurrentDeleteDuringRemoteUpdateTest: TestDefinition = {
|
||||
name: "Delete and remote update of same file do not crash",
|
||||
description:
|
||||
"One client updates a file while the other deletes it at the same " +
|
||||
"time. Both clients should converge without errors.",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import type { TestDefinition } from "../test-definition";
|
||||
|
||||
export const concurrentEditExactSamePositionTest: TestDefinition = {
|
||||
name: "Concurrent edits to the exact same word are both preserved",
|
||||
description:
|
||||
"Both clients replace the same word in a file with different text " +
|
||||
"while offline. After syncing, the merged result should contain " +
|
||||
|
|
@ -17,12 +16,6 @@ export const concurrentEditExactSamePositionTest: TestDefinition = {
|
|||
{ type: "enable-sync", client: 0 },
|
||||
{ type: "enable-sync", client: 1 },
|
||||
{ type: "barrier" },
|
||||
{
|
||||
type: "assert-content",
|
||||
client: 1,
|
||||
path: "doc.md",
|
||||
content: "the quick brown fox"
|
||||
},
|
||||
|
||||
{ type: "disable-sync", client: 0 },
|
||||
{ type: "disable-sync", client: 1 },
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import type { TestDefinition } from "../test-definition";
|
||||
|
||||
export const concurrentRenameAndCreateAtTargetTest: TestDefinition = {
|
||||
name: "Rename to path where another client creates a file",
|
||||
description:
|
||||
"One client renames X to Y while another creates a new file at Y, " +
|
||||
"both offline. After syncing, Y should contain merged content from " +
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import type { TestDefinition } from "../test-definition";
|
||||
|
||||
export const concurrentRenameAndCreateAtTargetTest: TestDefinition = {
|
||||
name: "Rename to path where another client creates a file",
|
||||
description:
|
||||
"One client renames X to Y while another creates a new file at Y, " +
|
||||
"both offline. After syncing, Y should contain merged content from " +
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import type { TestDefinition } from "../test-definition";
|
||||
|
||||
export const concurrentRenameSameTargetTest: TestDefinition = {
|
||||
name: "Two clients rename different files to the same target path",
|
||||
description:
|
||||
"One client renames A to C while the other renames B to C, both offline. " +
|
||||
"After syncing, both file contents should be preserved via path deconfliction.",
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue