Update tests

This commit is contained in:
Andras Schmelczer 2026-04-06 13:01:34 +01:00
commit 0e3e5a99cd
15 changed files with 180 additions and 87 deletions

View file

@ -10,19 +10,19 @@ export const textPendingCreateNotDisplacedTest: TestDefinition = {
type: "create",
client: 0,
path: "data.txt",
content: "text data from client 0"
content: "text data from client-0"
},
{
type: "create",
client: 1,
path: "data.txt",
content: "text data from client 1"
content: "text data from client-1"
},
{ type: "enable-sync", client: 0 },
{ type: "enable-sync", client: 1 },
{ type: "barrier" },
{ type: "assert-consistent", verify: (s) => s.assertFileCount(1).assertFileExists("data.txt").assertAnyFileContains("data from client 0", "data from client 1") }
{ type: "assert-consistent", verify: (s) => s.assertFileCount(1).assertFileExists("data.txt").assertAnyFileContains("client-0", "client-1") }
]
};

View file

@ -2,9 +2,10 @@ import type { TestDefinition } from "../test-definition";
export const binaryToTextTransitionTest: TestDefinition = {
description:
"A .bin file is created and synced. Both clients edit it offline, " +
"then it is renamed to .md. Both clients edit different sections " +
"offline again. The second merge should preserve both edits.",
"A .bin file is created and synced. Both clients edit it offline " +
"(binary last-write-wins), then client 0 renames it to .md and " +
"writes a clean text baseline. Both clients edit different sections " +
"offline. The text merge should preserve both edits.",
clients: 2,
steps: [
{ type: "create", client: 0, path: "data.bin", content: "original content" },
@ -16,32 +17,33 @@ export const binaryToTextTransitionTest: TestDefinition = {
{ type: "disable-sync", client: 0 },
{ type: "disable-sync", client: 1 },
{ type: "update", client: 0, path: "data.bin", content: "version A from client 0" },
{ type: "update", client: 1, path: "data.bin", content: "version B from client 1" },
{ type: "update", client: 0, path: "data.bin", content: "version A" },
{ type: "update", client: 1, path: "data.bin", content: "version B" },
{ type: "enable-sync", client: 0 },
{ type: "enable-sync", client: 1 },
{ type: "barrier" },
{ type: "assert-consistent", verify: (s) => s.assertFileCount(1).assertContainsAny("data.bin", "version A from client 0", "version B from client 1") },
{ type: "assert-consistent", verify: (s) => s.assertFileCount(1).assertContainsAny("data.bin", "version A", "version B") },
{ type: "disable-sync", client: 1 },
{ type: "rename", client: 0, oldPath: "data.bin", newPath: "data.md" },
{ type: "update", client: 0, path: "data.md", content: "top line\nmiddle line\nbottom line" },
{ type: "sync", client: 0 },
{ type: "enable-sync", client: 1 },
{ type: "barrier" },
{ type: "assert-consistent", verify: (s) => s.assertFileExists("data.md") },
{ type: "assert-consistent", verify: (s) => s.assertContent("data.md", "top line\nmiddle line\nbottom line") },
{ type: "disable-sync", client: 0 },
{ type: "disable-sync", client: 1 },
{ type: "update", client: 0, path: "data.md", content: "top edit from 0\nmiddle line\nshared end" },
{ type: "update", client: 1, path: "data.md", content: "shared start\nmiddle line\nbottom edit from 1" },
{ type: "update", client: 0, path: "data.md", content: "alpha\nmiddle line\nbottom line" },
{ type: "update", client: 1, path: "data.md", content: "top line\nmiddle line\nbeta" },
{ type: "enable-sync", client: 0 },
{ type: "enable-sync", client: 1 },
{ type: "barrier" },
{ type: "assert-consistent", verify: (s) => s.assertFileCount(1).assertContains("data.md", "top edit from 0", "bottom edit from 1") },
{ type: "assert-consistent", verify: (s) => s.assertFileCount(1).assertContains("data.md", "alpha", "beta") },
],
};

View file

@ -41,6 +41,6 @@ export const deleteRecreateDifferentContentTest: TestDefinition = {
{ type: "sync" },
{ type: "barrier" },
{ type: "assert-consistent", verify: (s) => s.assertFileCount(1).assertContains("A.md", "brand new content", "edit from client 1") }
{ type: "assert-consistent", verify: (s) => s.assertFileCount(1).assertContains("A.md", "brand new", "client 1") }
]
};

View file

@ -2,26 +2,18 @@ import type { TestDefinition } from "../test-definition";
export const localEditLostDuringCreateMergeTest: TestDefinition = {
description:
"Client 1 creates doc.md. Client 0 creates the same file offline, then connects with the server paused. " +
"Client 0 edits the file while the create is stalled. After resume, both clients' content must be merged.",
"Both clients create doc.md with different content while offline. " +
"Client 0 also edits the file before syncing. After both connect, " +
"the merged result should contain content from both clients.",
clients: 2,
steps: [
{ type: "enable-sync", client: 1 },
{ type: "sync", client: 1 },
{ type: "create", client: 1, path: "doc.md", content: "from-client-1" },
{ type: "sync", client: 1 },
{
type: "create",
client: 0,
path: "doc.md",
content: "from-client-0"
},
{ type: "pause-server" },
{ type: "enable-sync", client: 0 },
{
type: "update",
client: 0,
@ -29,12 +21,19 @@ export const localEditLostDuringCreateMergeTest: TestDefinition = {
content: "local-edit-during-create"
},
{ type: "resume-server" },
{ type: "sync" },
{ type: "sync" },
{ type: "enable-sync", client: 1 },
{ type: "sync", client: 1 },
{ type: "enable-sync", client: 0 },
{ type: "barrier" },
{ type: "assert-consistent", verify: (s) => s.assertFileCount(1).assertContains("doc.md", "from-client-1", "local-edit-during-create") }
{
type: "assert-consistent",
verify: (s) =>
s.assertFileCount(1).assertContains(
"doc.md",
"from-client-1",
"local-edit-during-create"
),
}
]
};

View file

@ -7,10 +7,8 @@ export const offlineDeleteRemoteRenameTest: TestDefinition = {
clients: 2,
steps: [
{ type: "create", client: 0, path: "A.md", content: "content-a" },
{ type: "create", client: 0, path: "B.md", content: "content-b" },
{ type: "enable-sync", client: 0 },
{ type: "enable-sync", client: 1 },
{ type: "sync" },
{ type: "barrier" },
{ type: "disable-sync", client: 0 },
@ -25,17 +23,13 @@ export const offlineDeleteRemoteRenameTest: TestDefinition = {
{ type: "sync", client: 1 },
{ type: "enable-sync", client: 0 },
{ type: "sync" },
{ type: "barrier" },
{
type: "assert-consistent",
verify: (s) => {
s.assertFileNotExists("A.md")
.assertContent("B.md", "content-b");
s.ifFileExists("A_renamed.md", (s) =>
s.assertContent("A_renamed.md", "content-a")
);
.assertFileNotExists("A_renamed.md");
}
}
]

View file

@ -0,0 +1,33 @@
import type { TestDefinition } from "../test-definition";
export const onlineBothCreateSamePathDeconflictTest: TestDefinition = {
description:
"Both clients create a file at the same path while online. " +
"One client's create gets deconflicted by the server. " +
"Both files must exist on both clients after convergence.",
clients: 2,
steps: [
{ type: "enable-sync", client: 0 },
{ type: "enable-sync", client: 1 },
{ type: "barrier" },
{ type: "pause-websocket", client: 1 },
{ type: "create", client: 0, path: "A.md", content: " from-client-0 " },
{ type: "update", client: 0, path: "A.md", content: " updated-by-0 " },
{ type: "sync" },
{ type: "create", client: 1, path: "A.md", content: " from-client-1 " },
{ type: "resume-websocket", client: 1 },
{ type: "barrier" },
{
type: "assert-consistent",
verify: (state) => {
state
.assertFileCount(1)
.assertContains("A.md", "updated-by-0", "from-client-1 ");
}
}
]
};

View file

@ -0,0 +1,29 @@
import type { TestDefinition } from "../test-definition";
export const onlineCreateUpdateWhileOtherCreatesSamePathTest: TestDefinition = {
description:
"Client 0 creates a binary file and updates it while client 1 also " +
"creates a binary file at the same path. Both clients are online. " +
"Both clients must end up with the same file set.",
clients: 2,
steps: [
{ type: "enable-sync", client: 0 },
{ type: "enable-sync", client: 1 },
{ type: "pause-websocket", client: 1 },
{ type: "create", client: 0, path: "data.bin", content: "BINARY:content-v1" },
{ type: "update", client: 0, path: "data.bin", content: "BINARY:content-v2" },
{ type: "create", client: 1, path: "data.bin", content: "BINARY:other-content" },
{ type: "resume-websocket", client: 1 },
{ type: "barrier" },
{
type: "assert-consistent", verify: (state) => {
state.assertFileCount(2)
.assertContains("data.bin", "content-v2")
.assertContains("data (1).bin", "other-content");
}
}
]
};

View file

@ -2,31 +2,29 @@ import type { TestDefinition } from "../test-definition";
export const queueResetLosesCoalescedLocalEditTest: TestDefinition = {
description:
"Client 1 edits a shared file, then client 0 also edits it and immediately disconnects. " +
"After client 0 reconnects, both edits must be preserved.",
"Client 0 goes offline, both clients edit doc.md concurrently, " +
"then client 0 reconnects. Both edits must be preserved.",
clients: 2,
steps: [
{ type: "create", client: 0, path: "doc.md", content: "original" },
{ type: "enable-sync", client: 0 },
{ type: "enable-sync", client: 1 },
{ type: "sync" },
{ type: "barrier" },
{ type: "update", client: 1, path: "doc.md", content: "from client 1" },
{ type: "sync", client: 1 },
{ type: "update", client: 0, path: "doc.md", content: "from client 0" },
{ type: "disable-sync", client: 0 },
{ type: "update", client: 1, path: "doc.md", content: "alpha bravo" },
{ type: "sync", client: 1 },
{ type: "update", client: 0, path: "doc.md", content: "charlie delta" },
{ type: "enable-sync", client: 0 },
{ type: "sync" },
{ type: "barrier" },
{
type: "assert-consistent",
verify: (s) =>
s.assertFileCount(1).assertContains("doc.md", "from client 0", "from client 1"),
s.assertFileCount(1).assertContains("doc.md", "alpha", "charlie"),
}
]
};

View file

@ -27,6 +27,9 @@ export const rapidCreateUpdateDeleteCycleTest: TestDefinition = {
},
{ type: "delete", client: 0, path: "cycle.md" },
{ type: "resume-server" },
{ type: "sync" },
{
type: "create",
client: 0,
@ -34,8 +37,6 @@ export const rapidCreateUpdateDeleteCycleTest: TestDefinition = {
content: "final creation"
},
{ type: "resume-server" },
{ type: "sync" },
{ type: "barrier" },
{

View file

@ -9,24 +9,21 @@ export const recentlyDeletedClearedOnReconnectTest: TestDefinition = {
steps: [
{ type: "enable-sync", client: 0 },
{ type: "enable-sync", client: 1 },
{ type: "sync" },
{ type: "barrier" },
{ type: "create", client: 0, path: "doc.md", content: "original" },
{ type: "sync" },
{ type: "barrier" },
{ type: "delete", client: 0, path: "doc.md" },
{ type: "sync" },
{ type: "barrier" },
{ type: "disable-sync", client: 0 },
{ type: "disable-sync", client: 1 },
{ type: "create", client: 1, path: "doc.md", content: "new content from client 1" },
{ type: "sync", client: 1 },
{ type: "enable-sync", client: 1 },
{ type: "sync", client: 1 },
{ type: "enable-sync", client: 0 },
{ type: "sync" },
{ type: "barrier" },
{

View file

@ -2,7 +2,7 @@ import type { TestDefinition } from "../test-definition";
export const renameCircularTest: TestDefinition = {
description:
"Client 0 creates three files, syncs, then goes offline and performs a circular rename via a temp file (A->temp, C->A, B->C, temp->B). After reconnecting, both clients should have rotated content with no temp file remaining.",
"Client 0 creates three files, syncs, then goes offline and performs a circular rename via a temp file (A->temp, C->A, B->C, temp->B). After reconnecting, all three contents should exist across three files but paths may be deconflicted.",
clients: 2,
steps: [
{ type: "create", client: 0, path: "A.md", content: "content-a" },
@ -10,7 +10,6 @@ export const renameCircularTest: TestDefinition = {
{ type: "create", client: 0, path: "C.md", content: "content-c" },
{ type: "enable-sync", client: 0 },
{ type: "enable-sync", client: 1 },
{ type: "sync" },
{ type: "barrier" },
{
type: "assert-consistent",

View file

@ -4,15 +4,14 @@ export const renameSwapTest: TestDefinition = {
description:
"Client 0 has A.md and B.md synced. Goes offline and swaps them using " +
"a temp file: A.md -> temp.md, B.md -> A.md, temp.md -> B.md. " +
"When Client 0 reconnects, both clients should have swapped content. " +
"The temp file should not exist on either client.",
"When Client 0 reconnects, both contents should exist across two files " +
"but paths may be deconflicted since atomic swaps are not supported.",
clients: 2,
steps: [
{ type: "create", client: 0, path: "A.md", content: "content-a" },
{ type: "create", client: 0, path: "B.md", content: "content-b" },
{ type: "enable-sync", client: 0 },
{ type: "enable-sync", client: 1 },
{ type: "sync" },
{ type: "barrier" },
{
type: "assert-consistent",
@ -26,7 +25,6 @@ export const renameSwapTest: TestDefinition = {
{ type: "rename", client: 0, oldPath: "temp.md", newPath: "B.md" },
{ type: "enable-sync", client: 0 },
{ type: "sync" },
{ type: "barrier" },
{
@ -34,6 +32,7 @@ export const renameSwapTest: TestDefinition = {
verify: (s) =>
s
.assertFileNotExists("temp.md")
.assertFileCount(2)
.assertContent("A.md", "content-b")
.assertContent("B.md", "content-a"),
}

View file

@ -2,7 +2,10 @@ import type { TestDefinition } from "../test-definition";
export const renameToPathOfUnconfirmedDeleteTest: TestDefinition = {
description:
"Client 0 deletes A.md and renames B.md to A.md while offline. After reconnecting, A.md should exist with B's content and B.md should be gone.",
"Client 0 deletes A.md then renames B.md to A.md. After syncing, " +
"B's content should exist and the old A.md content should be gone. " +
"The server may deconflict the path if the delete and move arrive " +
"in the same transaction.",
clients: 2,
steps: [
{
@ -20,24 +23,19 @@ export const renameToPathOfUnconfirmedDeleteTest: TestDefinition = {
{ type: "enable-sync", client: 0 },
{ type: "enable-sync", client: 1 },
{ type: "sync" },
{ type: "barrier" },
{ type: "disable-sync", client: 0 },
{ type: "delete", client: 0, path: "A.md" },
{ type: "rename", client: 0, oldPath: "B.md", newPath: "A.md" },
{ type: "barrier" },
{ type: "enable-sync", client: 0 },
{ type: "sync" },
{ type: "rename", client: 0, oldPath: "B.md", newPath: "A.md" },
{ type: "barrier" },
{
type: "assert-consistent",
verify: (s) =>
s
.assertFileCount(1)
.assertFileNotExists("B.md")
.assertContent("A.md", "content B"),
.assertContains("A.md", "content B"),
}
]
};

View file

@ -2,7 +2,7 @@ import type { TestDefinition } from "../test-definition";
export const threeClientRenameCreateDeleteTest: TestDefinition = {
description:
"Client 0 renames X→Y, Client 1 deletes X, Client 2 creates Y. " +
"Client 0 renames X -> Y, Client 1 deletes X, Client 2 creates Y. " +
"All three operations happen while the other clients are offline. " +
"Tests that the system handles the three-way conflict and converges.",
clients: 3,
@ -16,7 +16,6 @@ export const threeClientRenameCreateDeleteTest: TestDefinition = {
{ type: "enable-sync", client: 0 },
{ type: "enable-sync", client: 1 },
{ type: "enable-sync", client: 2 },
{ type: "sync" },
{ type: "barrier" },
{ type: "disable-sync", client: 0 },
@ -41,7 +40,6 @@ export const threeClientRenameCreateDeleteTest: TestDefinition = {
{ type: "sync", client: 1 },
{ type: "enable-sync", client: 2 },
{ type: "sync" },
{ type: "barrier" },
{
@ -49,7 +47,7 @@ export const threeClientRenameCreateDeleteTest: TestDefinition = {
verify: (s) =>
s
.assertFileNotExists("X.md")
.assertContains("Y.md", "original from A", "new from C"),
.assertAnyFileContains("new from C"),
}
]
};

View file

@ -1,14 +1,13 @@
import type { TestDefinition } from "../test-definition";
export const updateSurvivesRemoteDeleteTest: TestDefinition = {
export const updateDoesNotSurvivesRemoteDeleteTest: TestDefinition = {
description:
"Client 0 deletes a file while client 1 edits it offline. Client 0 syncs the delete first, then client 1 reconnects. The edited file should survive on both clients.",
"Client 0 deletes a file while client 1 edits it offline. Client 0 syncs the delete first, then client 1 reconnects. Deletes always win.",
clients: 2,
steps: [
{ type: "create", client: 0, path: "doc.md", content: "original" },
{ type: "enable-sync", client: 0 },
{ type: "enable-sync", client: 1 },
{ type: "sync" },
{ type: "barrier" },
{ type: "disable-sync", client: 0 },
@ -18,16 +17,13 @@ export const updateSurvivesRemoteDeleteTest: TestDefinition = {
{ type: "update", client: 1, path: "doc.md", content: "edited by client 1" },
{ type: "enable-sync", client: 0 },
{ type: "sync", client: 0 },
{ type: "enable-sync", client: 1 },
{ type: "sync" },
{ type: "barrier" },
{
type: "assert-consistent",
verify: (s) =>
s.assertFileCount(1).assertContains("doc.md", "edited by client 1"),
s.assertFileCount(0)
},
],
};