cojson 0.15.7 → 0.15.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +12 -0
- package/dist/IncomingMessagesQueue.d.ts +27 -0
- package/dist/IncomingMessagesQueue.d.ts.map +1 -0
- package/dist/IncomingMessagesQueue.js +114 -0
- package/dist/IncomingMessagesQueue.js.map +1 -0
- package/dist/PeerState.d.ts +2 -10
- package/dist/PeerState.d.ts.map +1 -1
- package/dist/PeerState.js +9 -90
- package/dist/PeerState.js.map +1 -1
- package/dist/PriorityBasedMessageQueue.d.ts +2 -1
- package/dist/PriorityBasedMessageQueue.d.ts.map +1 -1
- package/dist/PriorityBasedMessageQueue.js +9 -6
- package/dist/PriorityBasedMessageQueue.js.map +1 -1
- package/dist/SyncStateManager.d.ts +1 -0
- package/dist/SyncStateManager.d.ts.map +1 -1
- package/dist/SyncStateManager.js +1 -1
- package/dist/SyncStateManager.js.map +1 -1
- package/dist/coValue.d.ts +1 -1
- package/dist/coValueCore/coValueCore.d.ts +9 -17
- package/dist/coValueCore/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore/coValueCore.js +75 -50
- package/dist/coValueCore/coValueCore.js.map +1 -1
- package/dist/coValueCore/verifiedState.d.ts +10 -3
- package/dist/coValueCore/verifiedState.d.ts.map +1 -1
- package/dist/coValueCore/verifiedState.js +73 -14
- package/dist/coValueCore/verifiedState.js.map +1 -1
- package/dist/coValues/coMap.d.ts +3 -3
- package/dist/coValues/coStream.d.ts +2 -2
- package/dist/coValues/group.d.ts +1 -1
- package/dist/coValues/group.d.ts.map +1 -1
- package/dist/coValues/group.js +2 -4
- package/dist/coValues/group.js.map +1 -1
- package/dist/config.d.ts +19 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +23 -0
- package/dist/config.js.map +1 -0
- package/dist/crypto/WasmCrypto.d.ts.map +1 -1
- package/dist/crypto/WasmCrypto.js +2 -1
- package/dist/crypto/WasmCrypto.js.map +1 -1
- package/dist/exports.d.ts +18 -7
- package/dist/exports.d.ts.map +1 -1
- package/dist/exports.js +11 -8
- package/dist/exports.js.map +1 -1
- package/dist/localNode.d.ts +8 -2
- package/dist/localNode.d.ts.map +1 -1
- package/dist/localNode.js +19 -12
- package/dist/localNode.js.map +1 -1
- package/dist/storage/StoreQueue.d.ts +15 -0
- package/dist/storage/StoreQueue.d.ts.map +1 -0
- package/dist/storage/StoreQueue.js +35 -0
- package/dist/storage/StoreQueue.js.map +1 -0
- package/dist/storage/index.d.ts +6 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +6 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/knownState.d.ts +18 -0
- package/dist/storage/knownState.d.ts.map +1 -0
- package/dist/storage/knownState.js +63 -0
- package/dist/storage/knownState.js.map +1 -0
- package/dist/storage/sqlite/client.d.ts +37 -0
- package/dist/storage/sqlite/client.d.ts.map +1 -0
- package/dist/storage/sqlite/client.js +89 -0
- package/dist/storage/sqlite/client.js.map +1 -0
- package/dist/storage/sqlite/index.d.ts +5 -0
- package/dist/storage/sqlite/index.d.ts.map +1 -0
- package/dist/storage/sqlite/index.js +13 -0
- package/dist/storage/sqlite/index.js.map +1 -0
- package/dist/storage/sqlite/sqliteMigrations.d.ts +3 -0
- package/dist/storage/sqlite/sqliteMigrations.d.ts.map +1 -0
- package/dist/storage/sqlite/sqliteMigrations.js +44 -0
- package/dist/storage/sqlite/sqliteMigrations.js.map +1 -0
- package/dist/storage/sqlite/types.d.ts +8 -0
- package/dist/storage/sqlite/types.d.ts.map +1 -0
- package/dist/storage/sqlite/types.js +2 -0
- package/dist/storage/sqlite/types.js.map +1 -0
- package/dist/storage/sqliteAsync/client.d.ts +37 -0
- package/dist/storage/sqliteAsync/client.d.ts.map +1 -0
- package/dist/storage/sqliteAsync/client.js +88 -0
- package/dist/storage/sqliteAsync/client.js.map +1 -0
- package/dist/storage/sqliteAsync/index.d.ts +6 -0
- package/dist/storage/sqliteAsync/index.d.ts.map +1 -0
- package/dist/storage/sqliteAsync/index.js +15 -0
- package/dist/storage/sqliteAsync/index.js.map +1 -0
- package/dist/storage/sqliteAsync/types.d.ts +9 -0
- package/dist/storage/sqliteAsync/types.d.ts.map +1 -0
- package/dist/storage/sqliteAsync/types.js +2 -0
- package/dist/storage/sqliteAsync/types.js.map +1 -0
- package/dist/storage/storageAsync.d.ts +22 -0
- package/dist/storage/storageAsync.d.ts.map +1 -0
- package/dist/storage/storageAsync.js +214 -0
- package/dist/storage/storageAsync.js.map +1 -0
- package/dist/storage/storageSync.d.ts +21 -0
- package/dist/storage/storageSync.d.ts.map +1 -0
- package/dist/storage/storageSync.js +206 -0
- package/dist/storage/storageSync.js.map +1 -0
- package/dist/storage/syncUtils.d.ts +13 -0
- package/dist/storage/syncUtils.d.ts.map +1 -0
- package/dist/storage/syncUtils.js +25 -0
- package/dist/storage/syncUtils.js.map +1 -0
- package/dist/storage/types.d.ts +82 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/storage/types.js +2 -0
- package/dist/storage/types.js.map +1 -0
- package/dist/streamUtils.d.ts +13 -9
- package/dist/streamUtils.d.ts.map +1 -1
- package/dist/streamUtils.js +46 -13
- package/dist/streamUtils.js.map +1 -1
- package/dist/sync.d.ts +22 -14
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +143 -125
- package/dist/sync.js.map +1 -1
- package/dist/tests/IncomingMessagesQueue.test.d.ts +2 -0
- package/dist/tests/IncomingMessagesQueue.test.d.ts.map +1 -0
- package/dist/tests/IncomingMessagesQueue.test.js +437 -0
- package/dist/tests/IncomingMessagesQueue.test.js.map +1 -0
- package/dist/tests/PeerState.test.js +6 -94
- package/dist/tests/PeerState.test.js.map +1 -1
- package/dist/tests/PriorityBasedMessageQueue.test.js +14 -14
- package/dist/tests/PriorityBasedMessageQueue.test.js.map +1 -1
- package/dist/tests/StoreQueue.test.d.ts +2 -0
- package/dist/tests/StoreQueue.test.d.ts.map +1 -0
- package/dist/tests/StoreQueue.test.js +208 -0
- package/dist/tests/StoreQueue.test.js.map +1 -0
- package/dist/tests/SyncStateManager.test.js +3 -1
- package/dist/tests/SyncStateManager.test.js.map +1 -1
- package/dist/tests/account.test.js +9 -9
- package/dist/tests/account.test.js.map +1 -1
- package/dist/tests/coStream.test.js +1 -1
- package/dist/tests/coStream.test.js.map +1 -1
- package/dist/tests/coValueCore.test.js +208 -1
- package/dist/tests/coValueCore.test.js.map +1 -1
- package/dist/tests/coValueCoreLoadingState.test.js +2 -2
- package/dist/tests/coValueCoreLoadingState.test.js.map +1 -1
- package/dist/tests/group.addMember.test.js.map +1 -1
- package/dist/tests/group.removeMember.test.js +1 -1
- package/dist/tests/group.removeMember.test.js.map +1 -1
- package/dist/tests/messagesTestUtils.js +1 -1
- package/dist/tests/messagesTestUtils.js.map +1 -1
- package/dist/tests/sync.auth.test.js +23 -15
- package/dist/tests/sync.auth.test.js.map +1 -1
- package/dist/tests/sync.invite.test.js +10 -16
- package/dist/tests/sync.invite.test.js.map +1 -1
- package/dist/tests/sync.load.test.js +52 -50
- package/dist/tests/sync.load.test.js.map +1 -1
- package/dist/tests/sync.mesh.test.js +173 -56
- package/dist/tests/sync.mesh.test.js.map +1 -1
- package/dist/tests/sync.peerReconciliation.test.js +42 -32
- package/dist/tests/sync.peerReconciliation.test.js.map +1 -1
- package/dist/tests/sync.storage.test.js +162 -62
- package/dist/tests/sync.storage.test.js.map +1 -1
- package/dist/tests/sync.storageAsync.test.d.ts +2 -0
- package/dist/tests/sync.storageAsync.test.d.ts.map +1 -0
- package/dist/tests/sync.storageAsync.test.js +361 -0
- package/dist/tests/sync.storageAsync.test.js.map +1 -0
- package/dist/tests/sync.test.js +16 -21
- package/dist/tests/sync.test.js.map +1 -1
- package/dist/tests/sync.upload.test.js +28 -25
- package/dist/tests/sync.upload.test.js.map +1 -1
- package/dist/tests/testStorage.d.ts +12 -0
- package/dist/tests/testStorage.d.ts.map +1 -0
- package/dist/tests/testStorage.js +151 -0
- package/dist/tests/testStorage.js.map +1 -0
- package/dist/tests/testUtils.d.ts +20 -15
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/dist/tests/testUtils.js +79 -45
- package/dist/tests/testUtils.js.map +1 -1
- package/package.json +2 -2
- package/src/IncomingMessagesQueue.ts +142 -0
- package/src/PeerState.ts +11 -110
- package/src/PriorityBasedMessageQueue.ts +13 -5
- package/src/SyncStateManager.ts +1 -1
- package/src/coValueCore/coValueCore.ts +100 -66
- package/src/coValueCore/verifiedState.ts +91 -21
- package/src/coValues/group.ts +2 -4
- package/src/config.ts +26 -0
- package/src/crypto/WasmCrypto.ts +3 -1
- package/src/exports.ts +20 -27
- package/src/localNode.ts +27 -12
- package/src/storage/StoreQueue.ts +56 -0
- package/src/storage/index.ts +5 -0
- package/src/storage/knownState.ts +88 -0
- package/src/storage/sqlite/client.ts +180 -0
- package/src/storage/sqlite/index.ts +19 -0
- package/src/storage/sqlite/sqliteMigrations.ts +44 -0
- package/src/storage/sqlite/types.ts +7 -0
- package/src/storage/sqliteAsync/client.ts +179 -0
- package/src/storage/sqliteAsync/index.ts +25 -0
- package/src/storage/sqliteAsync/types.ts +8 -0
- package/src/storage/storageAsync.ts +367 -0
- package/src/storage/storageSync.ts +343 -0
- package/src/storage/syncUtils.ts +50 -0
- package/src/storage/types.ts +162 -0
- package/src/streamUtils.ts +61 -19
- package/src/sync.ts +191 -160
- package/src/tests/IncomingMessagesQueue.test.ts +626 -0
- package/src/tests/PeerState.test.ts +6 -118
- package/src/tests/PriorityBasedMessageQueue.test.ts +18 -14
- package/src/tests/StoreQueue.test.ts +283 -0
- package/src/tests/SyncStateManager.test.ts +4 -1
- package/src/tests/account.test.ts +11 -12
- package/src/tests/coStream.test.ts +1 -3
- package/src/tests/coValueCore.test.ts +270 -1
- package/src/tests/coValueCoreLoadingState.test.ts +2 -2
- package/src/tests/group.addMember.test.ts +1 -0
- package/src/tests/group.removeMember.test.ts +2 -8
- package/src/tests/messagesTestUtils.ts +2 -2
- package/src/tests/sync.auth.test.ts +24 -14
- package/src/tests/sync.invite.test.ts +11 -17
- package/src/tests/sync.load.test.ts +53 -49
- package/src/tests/sync.mesh.test.ts +198 -56
- package/src/tests/sync.peerReconciliation.test.ts +44 -34
- package/src/tests/sync.storage.test.ts +231 -64
- package/src/tests/sync.storageAsync.test.ts +486 -0
- package/src/tests/sync.test.ts +17 -23
- package/src/tests/sync.upload.test.ts +29 -24
- package/src/tests/testStorage.ts +216 -0
- package/src/tests/testUtils.ts +89 -54
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
import { assert, beforeEach, describe, expect, test, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { emptyKnownState } from "../exports";
|
|
4
|
+
import {
|
|
5
|
+
SyncMessagesLog,
|
|
6
|
+
TEST_NODE_CONFIG,
|
|
7
|
+
loadCoValueOrFail,
|
|
8
|
+
setupTestNode,
|
|
9
|
+
waitFor,
|
|
10
|
+
} from "./testUtils";
|
|
11
|
+
|
|
12
|
+
// We want to simulate a real world communication that happens asynchronously
|
|
13
|
+
TEST_NODE_CONFIG.withAsyncPeers = true;
|
|
14
|
+
|
|
15
|
+
describe("client with storage syncs with server", () => {
|
|
16
|
+
let jazzCloud: ReturnType<typeof setupTestNode>;
|
|
17
|
+
|
|
18
|
+
beforeEach(async () => {
|
|
19
|
+
SyncMessagesLog.clear();
|
|
20
|
+
jazzCloud = setupTestNode({
|
|
21
|
+
isSyncServer: true,
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("coValue loading (empty storage)", async () => {
|
|
26
|
+
const client = setupTestNode();
|
|
27
|
+
|
|
28
|
+
client.connectToSyncServer();
|
|
29
|
+
await client.addAsyncStorage();
|
|
30
|
+
|
|
31
|
+
const group = jazzCloud.node.createGroup();
|
|
32
|
+
const map = group.createMap();
|
|
33
|
+
map.set("hello", "world", "trusting");
|
|
34
|
+
|
|
35
|
+
const mapOnClient = await loadCoValueOrFail(client.node, map.id);
|
|
36
|
+
expect(mapOnClient.get("hello")).toEqual("world");
|
|
37
|
+
|
|
38
|
+
expect(
|
|
39
|
+
SyncMessagesLog.getMessages({
|
|
40
|
+
Group: group.core,
|
|
41
|
+
Map: map.core,
|
|
42
|
+
}),
|
|
43
|
+
).toMatchInlineSnapshot(`
|
|
44
|
+
[
|
|
45
|
+
"client -> storage | LOAD Map sessions: empty",
|
|
46
|
+
"storage -> client | KNOWN Map sessions: empty",
|
|
47
|
+
"client -> server | LOAD Map sessions: empty",
|
|
48
|
+
"server -> client | CONTENT Group header: true new: After: 0 New: 3",
|
|
49
|
+
"server -> client | CONTENT Map header: true new: After: 0 New: 1",
|
|
50
|
+
"client -> server | KNOWN Group sessions: header/3",
|
|
51
|
+
"client -> storage | CONTENT Group header: true new: After: 0 New: 3",
|
|
52
|
+
"client -> server | KNOWN Map sessions: header/1",
|
|
53
|
+
"client -> storage | CONTENT Map header: true new: After: 0 New: 1",
|
|
54
|
+
]
|
|
55
|
+
`);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("coValue loading (synced storage)", async () => {
|
|
59
|
+
const client = setupTestNode();
|
|
60
|
+
|
|
61
|
+
client.connectToSyncServer();
|
|
62
|
+
const { storage } = await client.addAsyncStorage();
|
|
63
|
+
|
|
64
|
+
const group = jazzCloud.node.createGroup();
|
|
65
|
+
const map = group.createMap();
|
|
66
|
+
map.set("hello", "world", "trusting");
|
|
67
|
+
|
|
68
|
+
const firstLoad = await loadCoValueOrFail(client.node, map.id);
|
|
69
|
+
await firstLoad.core.waitForSync(); // Need to wait for sync with storage
|
|
70
|
+
|
|
71
|
+
client.restart();
|
|
72
|
+
|
|
73
|
+
client.connectToSyncServer();
|
|
74
|
+
client.addStorage({
|
|
75
|
+
ourName: "client",
|
|
76
|
+
storage,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
SyncMessagesLog.clear();
|
|
80
|
+
|
|
81
|
+
const mapOnClient = await loadCoValueOrFail(client.node, map.id);
|
|
82
|
+
expect(mapOnClient.get("hello")).toEqual("world");
|
|
83
|
+
|
|
84
|
+
expect(
|
|
85
|
+
SyncMessagesLog.getMessages({
|
|
86
|
+
Group: group.core,
|
|
87
|
+
Map: map.core,
|
|
88
|
+
}),
|
|
89
|
+
).toMatchInlineSnapshot(`
|
|
90
|
+
[
|
|
91
|
+
"client -> storage | LOAD Map sessions: empty",
|
|
92
|
+
"storage -> client | CONTENT Group header: true new: After: 0 New: 3",
|
|
93
|
+
"client -> server | LOAD Group sessions: header/3",
|
|
94
|
+
"storage -> client | CONTENT Map header: true new: After: 0 New: 1",
|
|
95
|
+
"client -> server | LOAD Map sessions: header/1",
|
|
96
|
+
]
|
|
97
|
+
`);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test("coValue with parent groups loading", async () => {
|
|
101
|
+
const client = setupTestNode();
|
|
102
|
+
|
|
103
|
+
client.connectToSyncServer();
|
|
104
|
+
await client.addAsyncStorage();
|
|
105
|
+
|
|
106
|
+
const group = jazzCloud.node.createGroup();
|
|
107
|
+
const parentGroup = jazzCloud.node.createGroup();
|
|
108
|
+
parentGroup.addMember("everyone", "reader");
|
|
109
|
+
|
|
110
|
+
group.extend(parentGroup);
|
|
111
|
+
|
|
112
|
+
const map = group.createMap();
|
|
113
|
+
map.set("hello", "world");
|
|
114
|
+
|
|
115
|
+
const mapOnClient = await loadCoValueOrFail(client.node, map.id);
|
|
116
|
+
expect(mapOnClient.get("hello")).toEqual("world");
|
|
117
|
+
|
|
118
|
+
expect(
|
|
119
|
+
SyncMessagesLog.getMessages({
|
|
120
|
+
ParentGroup: parentGroup.core,
|
|
121
|
+
Group: group.core,
|
|
122
|
+
Map: map.core,
|
|
123
|
+
}),
|
|
124
|
+
).toMatchInlineSnapshot(`
|
|
125
|
+
[
|
|
126
|
+
"client -> storage | LOAD Map sessions: empty",
|
|
127
|
+
"storage -> client | KNOWN Map sessions: empty",
|
|
128
|
+
"client -> server | LOAD Map sessions: empty",
|
|
129
|
+
"server -> client | CONTENT ParentGroup header: true new: After: 0 New: 6",
|
|
130
|
+
"server -> client | CONTENT Group header: true new: After: 0 New: 5",
|
|
131
|
+
"server -> client | CONTENT Map header: true new: After: 0 New: 1",
|
|
132
|
+
"client -> server | KNOWN ParentGroup sessions: header/6",
|
|
133
|
+
"client -> storage | CONTENT ParentGroup header: true new: After: 0 New: 6",
|
|
134
|
+
"client -> server | KNOWN Group sessions: header/5",
|
|
135
|
+
"client -> storage | CONTENT Group header: true new: After: 0 New: 5",
|
|
136
|
+
"client -> server | KNOWN Map sessions: header/1",
|
|
137
|
+
"client -> storage | CONTENT Map header: true new: After: 0 New: 1",
|
|
138
|
+
]
|
|
139
|
+
`);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test("updating a coValue while offline", async () => {
|
|
143
|
+
const client = setupTestNode();
|
|
144
|
+
|
|
145
|
+
client.connectToSyncServer();
|
|
146
|
+
await client.addAsyncStorage();
|
|
147
|
+
|
|
148
|
+
const group = jazzCloud.node.createGroup();
|
|
149
|
+
const map = group.createMap();
|
|
150
|
+
map.set("hello", "world", "trusting");
|
|
151
|
+
|
|
152
|
+
const mapOnClient = await loadCoValueOrFail(client.node, map.id);
|
|
153
|
+
expect(mapOnClient.get("hello")).toEqual("world");
|
|
154
|
+
|
|
155
|
+
client.node.syncManager.getPeers()[0]?.gracefulShutdown();
|
|
156
|
+
|
|
157
|
+
SyncMessagesLog.clear();
|
|
158
|
+
map.set("hello", "updated", "trusting");
|
|
159
|
+
|
|
160
|
+
client.connectToSyncServer();
|
|
161
|
+
|
|
162
|
+
await map.core.waitForSync();
|
|
163
|
+
|
|
164
|
+
expect(mapOnClient.get("hello")).toEqual("updated");
|
|
165
|
+
|
|
166
|
+
await mapOnClient.core.waitForSync();
|
|
167
|
+
|
|
168
|
+
expect(
|
|
169
|
+
SyncMessagesLog.getMessages({
|
|
170
|
+
Group: group.core,
|
|
171
|
+
Map: map.core,
|
|
172
|
+
}),
|
|
173
|
+
).toMatchInlineSnapshot(`
|
|
174
|
+
[
|
|
175
|
+
"client -> server | LOAD Group sessions: header/3",
|
|
176
|
+
"client -> server | LOAD Map sessions: header/1",
|
|
177
|
+
"server -> client | CONTENT Group header: true new: After: 0 New: 3",
|
|
178
|
+
"server -> client | CONTENT Map header: true new: After: 0 New: 2",
|
|
179
|
+
"server -> client | CONTENT Map header: false new: After: 1 New: 1",
|
|
180
|
+
"client -> server | KNOWN Group sessions: header/3",
|
|
181
|
+
"client -> storage | CONTENT Group header: true new: After: 0 New: 3",
|
|
182
|
+
"client -> server | KNOWN Map sessions: header/2",
|
|
183
|
+
"client -> storage | CONTENT Map header: true new: After: 0 New: 2",
|
|
184
|
+
"client -> server | KNOWN Map sessions: header/2",
|
|
185
|
+
"client -> storage | CONTENT Map header: false new: After: 1 New: 1",
|
|
186
|
+
]
|
|
187
|
+
`);
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
describe("client syncs with a server with storage", () => {
|
|
192
|
+
let jazzCloud: ReturnType<typeof setupTestNode>;
|
|
193
|
+
|
|
194
|
+
beforeEach(async () => {
|
|
195
|
+
SyncMessagesLog.clear();
|
|
196
|
+
jazzCloud = setupTestNode({
|
|
197
|
+
isSyncServer: true,
|
|
198
|
+
});
|
|
199
|
+
jazzCloud.addStorage({
|
|
200
|
+
ourName: "server",
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test("coValue uploading", async () => {
|
|
205
|
+
const client = setupTestNode();
|
|
206
|
+
|
|
207
|
+
client.connectToSyncServer();
|
|
208
|
+
|
|
209
|
+
const group = client.node.createGroup();
|
|
210
|
+
const map = group.createMap();
|
|
211
|
+
map.set("hello", "world", "trusting");
|
|
212
|
+
|
|
213
|
+
await map.core.waitForSync();
|
|
214
|
+
|
|
215
|
+
const mapOnServer = await loadCoValueOrFail(jazzCloud.node, map.id);
|
|
216
|
+
expect(mapOnServer.get("hello")).toEqual("world");
|
|
217
|
+
|
|
218
|
+
expect(
|
|
219
|
+
SyncMessagesLog.getMessages({
|
|
220
|
+
Group: group.core,
|
|
221
|
+
Map: map.core,
|
|
222
|
+
}),
|
|
223
|
+
).toMatchInlineSnapshot(`
|
|
224
|
+
[
|
|
225
|
+
"client -> server | CONTENT Group header: true new: After: 0 New: 3",
|
|
226
|
+
"client -> server | CONTENT Map header: true new: After: 0 New: 1",
|
|
227
|
+
"server -> client | KNOWN Group sessions: header/3",
|
|
228
|
+
"server -> storage | CONTENT Group header: true new: After: 0 New: 3",
|
|
229
|
+
"server -> client | KNOWN Map sessions: header/1",
|
|
230
|
+
"server -> storage | CONTENT Map header: true new: After: 0 New: 1",
|
|
231
|
+
]
|
|
232
|
+
`);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
test("large coValue streaming", async () => {
|
|
236
|
+
const client = setupTestNode();
|
|
237
|
+
|
|
238
|
+
client.connectToSyncServer({
|
|
239
|
+
syncServer: jazzCloud.node,
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
const { storage } = await client.addAsyncStorage({
|
|
243
|
+
ourName: "client",
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
const group = client.node.createGroup();
|
|
247
|
+
group.addMember("everyone", "writer");
|
|
248
|
+
|
|
249
|
+
const largeMap = group.createMap();
|
|
250
|
+
|
|
251
|
+
// Generate a large amount of data (about 100MB)
|
|
252
|
+
const dataSize = 1 * 200 * 1024;
|
|
253
|
+
const chunkSize = 1024; // 1KB chunks
|
|
254
|
+
const chunks = dataSize / chunkSize;
|
|
255
|
+
|
|
256
|
+
const value = Buffer.alloc(chunkSize, `value$`).toString("base64");
|
|
257
|
+
|
|
258
|
+
for (let i = 0; i < chunks; i++) {
|
|
259
|
+
const key = `key${i}`;
|
|
260
|
+
largeMap.set(key, value, "trusting");
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
await largeMap.core.waitForSync();
|
|
264
|
+
|
|
265
|
+
expect(
|
|
266
|
+
SyncMessagesLog.getMessages({
|
|
267
|
+
Group: group.core,
|
|
268
|
+
Map: largeMap.core,
|
|
269
|
+
}),
|
|
270
|
+
).toMatchInlineSnapshot(`
|
|
271
|
+
[
|
|
272
|
+
"client -> storage | CONTENT Group header: true new: After: 0 New: 5",
|
|
273
|
+
"client -> server | CONTENT Group header: true new: After: 0 New: 5",
|
|
274
|
+
"client -> storage | CONTENT Map header: true new: expectContentUntil: header/200",
|
|
275
|
+
"client -> storage | CONTENT Map header: false new: After: 0 New: 73",
|
|
276
|
+
"client -> storage | CONTENT Map header: false new: After: 73 New: 73",
|
|
277
|
+
"client -> storage | CONTENT Map header: false new: After: 146 New: 54",
|
|
278
|
+
"client -> server | CONTENT Map header: true new: expectContentUntil: header/200",
|
|
279
|
+
"client -> server | CONTENT Map header: false new: After: 0 New: 73",
|
|
280
|
+
"client -> server | CONTENT Map header: false new: After: 73 New: 73",
|
|
281
|
+
"client -> server | CONTENT Map header: false new: After: 146 New: 54",
|
|
282
|
+
"server -> client | KNOWN Group sessions: header/5",
|
|
283
|
+
"server -> storage | CONTENT Group header: true new: After: 0 New: 5",
|
|
284
|
+
"server -> client | KNOWN Map sessions: header/0",
|
|
285
|
+
"server -> storage | CONTENT Map header: true new: expectContentUntil: header/200",
|
|
286
|
+
"server -> client | KNOWN Map sessions: header/73",
|
|
287
|
+
"server -> storage | CONTENT Map header: false new: After: 0 New: 73",
|
|
288
|
+
"server -> client | KNOWN Map sessions: header/146",
|
|
289
|
+
"server -> storage | CONTENT Map header: false new: After: 73 New: 73",
|
|
290
|
+
"server -> client | KNOWN Map sessions: header/200",
|
|
291
|
+
"server -> storage | CONTENT Map header: false new: After: 146 New: 54",
|
|
292
|
+
]
|
|
293
|
+
`);
|
|
294
|
+
|
|
295
|
+
SyncMessagesLog.clear();
|
|
296
|
+
|
|
297
|
+
client.restart();
|
|
298
|
+
|
|
299
|
+
client.connectToSyncServer({
|
|
300
|
+
ourName: "client",
|
|
301
|
+
syncServer: jazzCloud.node,
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
client.addStorage({
|
|
305
|
+
ourName: "client",
|
|
306
|
+
storage,
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
const mapOnClient2 = await loadCoValueOrFail(client.node, largeMap.id);
|
|
310
|
+
|
|
311
|
+
await mapOnClient2.core.waitForSync();
|
|
312
|
+
|
|
313
|
+
expect(
|
|
314
|
+
SyncMessagesLog.getMessages({
|
|
315
|
+
Group: group.core,
|
|
316
|
+
Map: largeMap.core,
|
|
317
|
+
}),
|
|
318
|
+
).toMatchInlineSnapshot(`
|
|
319
|
+
[
|
|
320
|
+
"client -> storage | LOAD Map sessions: empty",
|
|
321
|
+
"storage -> client | CONTENT Group header: true new: After: 0 New: 5",
|
|
322
|
+
"client -> server | LOAD Group sessions: header/5",
|
|
323
|
+
"storage -> client | CONTENT Map header: true new: After: 0 New: 73 expectContentUntil: header/200",
|
|
324
|
+
"client -> server | LOAD Map sessions: header/200",
|
|
325
|
+
"storage -> client | CONTENT Map header: true new: After: 73 New: 73",
|
|
326
|
+
"storage -> client | CONTENT Map header: true new: After: 146 New: 54",
|
|
327
|
+
"server -> client | KNOWN Group sessions: header/5",
|
|
328
|
+
"server -> client | KNOWN Map sessions: header/200",
|
|
329
|
+
]
|
|
330
|
+
`);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
test("storing stale data should not compromise the signatures", async () => {
|
|
334
|
+
const client = setupTestNode();
|
|
335
|
+
|
|
336
|
+
client.connectToSyncServer({
|
|
337
|
+
syncServer: jazzCloud.node,
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
const { storage } = await client.addAsyncStorage({
|
|
341
|
+
ourName: "client",
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
const group = client.node.createGroup();
|
|
345
|
+
group.addMember("everyone", "writer");
|
|
346
|
+
|
|
347
|
+
const largeMap = group.createMap();
|
|
348
|
+
|
|
349
|
+
// Generate a large amount of data (about 100MB)
|
|
350
|
+
const dataSize = 1 * 200 * 1024;
|
|
351
|
+
const chunkSize = 1024; // 1KB chunks
|
|
352
|
+
const chunks = dataSize / chunkSize;
|
|
353
|
+
|
|
354
|
+
const value = Buffer.alloc(chunkSize, `value$`).toString("base64");
|
|
355
|
+
|
|
356
|
+
for (let i = 0; i < chunks; i++) {
|
|
357
|
+
const key = `key${i}`;
|
|
358
|
+
largeMap.set(key, value, "trusting");
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
await largeMap.core.waitForSync();
|
|
362
|
+
|
|
363
|
+
const newContentChunks = largeMap.core.verified.newContentSince(
|
|
364
|
+
emptyKnownState(largeMap.id),
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
assert(newContentChunks);
|
|
368
|
+
assert(newContentChunks.length > 1);
|
|
369
|
+
|
|
370
|
+
const correctionSpy = vi.fn();
|
|
371
|
+
|
|
372
|
+
client.node.storage?.store(newContentChunks.slice(1, 2), correctionSpy);
|
|
373
|
+
|
|
374
|
+
// Wait for the content to be stored in the storage
|
|
375
|
+
// We can't use waitForSync because we are trying to store stale data
|
|
376
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
377
|
+
|
|
378
|
+
expect(correctionSpy).not.toHaveBeenCalled();
|
|
379
|
+
|
|
380
|
+
client.restart();
|
|
381
|
+
|
|
382
|
+
client.connectToSyncServer({
|
|
383
|
+
ourName: "client",
|
|
384
|
+
syncServer: jazzCloud.node,
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
client.addStorage({
|
|
388
|
+
ourName: "client",
|
|
389
|
+
storage,
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
const mapOnClient2 = await loadCoValueOrFail(client.node, largeMap.id);
|
|
393
|
+
|
|
394
|
+
await waitFor(async () => {
|
|
395
|
+
expect(mapOnClient2.core.knownState()).toEqual(
|
|
396
|
+
largeMap.core.knownState(),
|
|
397
|
+
);
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
test("large coValue streaming from cold server", async () => {
|
|
402
|
+
const server = setupTestNode({
|
|
403
|
+
isSyncServer: true,
|
|
404
|
+
});
|
|
405
|
+
const { storage: serverStorage } = server.addStorage({
|
|
406
|
+
ourName: "server",
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
const client = setupTestNode();
|
|
410
|
+
|
|
411
|
+
client.connectToSyncServer({
|
|
412
|
+
syncServer: server.node,
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
const { storage } = await client.addAsyncStorage({
|
|
416
|
+
ourName: "client",
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
const group = client.node.createGroup();
|
|
420
|
+
group.addMember("everyone", "writer");
|
|
421
|
+
|
|
422
|
+
const largeMap = group.createMap();
|
|
423
|
+
|
|
424
|
+
// Generate a large amount of data (about 100MB)
|
|
425
|
+
const dataSize = 1 * 200 * 1024;
|
|
426
|
+
const chunkSize = 1024; // 1KB chunks
|
|
427
|
+
const chunks = dataSize / chunkSize;
|
|
428
|
+
|
|
429
|
+
const value = Buffer.alloc(chunkSize, `value$`).toString("base64");
|
|
430
|
+
|
|
431
|
+
for (let i = 0; i < chunks; i++) {
|
|
432
|
+
const key = `key${i}`;
|
|
433
|
+
largeMap.set(key, value, "trusting");
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
await largeMap.core.waitForSync();
|
|
437
|
+
|
|
438
|
+
SyncMessagesLog.clear();
|
|
439
|
+
|
|
440
|
+
server.restart();
|
|
441
|
+
|
|
442
|
+
server.addStorage({
|
|
443
|
+
ourName: "server",
|
|
444
|
+
storage: serverStorage,
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
client.restart();
|
|
448
|
+
|
|
449
|
+
client.connectToSyncServer({
|
|
450
|
+
ourName: "client",
|
|
451
|
+
syncServer: server.node,
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
client.addStorage({
|
|
455
|
+
ourName: "client",
|
|
456
|
+
storage,
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
const mapOnClient2 = await loadCoValueOrFail(client.node, largeMap.id);
|
|
460
|
+
|
|
461
|
+
await mapOnClient2.core.waitForSync();
|
|
462
|
+
|
|
463
|
+
expect(
|
|
464
|
+
SyncMessagesLog.getMessages({
|
|
465
|
+
Group: group.core,
|
|
466
|
+
Map: largeMap.core,
|
|
467
|
+
}),
|
|
468
|
+
).toMatchInlineSnapshot(`
|
|
469
|
+
[
|
|
470
|
+
"client -> storage | LOAD Map sessions: empty",
|
|
471
|
+
"storage -> client | CONTENT Group header: true new: After: 0 New: 5",
|
|
472
|
+
"client -> server | LOAD Group sessions: header/5",
|
|
473
|
+
"storage -> client | CONTENT Map header: true new: After: 0 New: 73 expectContentUntil: header/200",
|
|
474
|
+
"client -> server | LOAD Map sessions: header/200",
|
|
475
|
+
"storage -> client | CONTENT Map header: true new: After: 73 New: 73",
|
|
476
|
+
"storage -> client | CONTENT Map header: true new: After: 146 New: 54",
|
|
477
|
+
"server -> storage | LOAD Group sessions: empty",
|
|
478
|
+
"storage -> server | CONTENT Group header: true new: After: 0 New: 5",
|
|
479
|
+
"server -> client | KNOWN Group sessions: header/5",
|
|
480
|
+
"server -> storage | LOAD Map sessions: empty",
|
|
481
|
+
"storage -> server | CONTENT Map header: true new: After: 0 New: 73 expectContentUntil: header/200",
|
|
482
|
+
"server -> client | KNOWN Map sessions: header/200",
|
|
483
|
+
]
|
|
484
|
+
`);
|
|
485
|
+
});
|
|
486
|
+
});
|
package/src/tests/sync.test.ts
CHANGED
|
@@ -9,30 +9,29 @@ import {
|
|
|
9
9
|
} from "vitest";
|
|
10
10
|
import { expectMap } from "../coValue.js";
|
|
11
11
|
import { RawCoMap } from "../coValues/coMap.js";
|
|
12
|
-
import type { RawGroup } from "../coValues/group.js";
|
|
13
12
|
import { WasmCrypto } from "../crypto/WasmCrypto.js";
|
|
14
|
-
import { LocalNode } from "../localNode.js";
|
|
15
13
|
import { connectedPeers, newQueuePair } from "../streamUtils.js";
|
|
16
14
|
import type { LoadMessage } from "../sync.js";
|
|
17
15
|
import {
|
|
16
|
+
TEST_NODE_CONFIG,
|
|
18
17
|
blockMessageTypeOnOutgoingPeer,
|
|
19
18
|
connectTwoPeers,
|
|
20
19
|
createTestMetricReader,
|
|
21
20
|
createTestNode,
|
|
22
21
|
loadCoValueOrFail,
|
|
23
22
|
nodeWithRandomAgentAndSessionID,
|
|
24
|
-
randomAgentAndSessionID,
|
|
25
23
|
setupTestAccount,
|
|
26
24
|
setupTestNode,
|
|
27
25
|
tearDownTestMetricReader,
|
|
28
26
|
waitFor,
|
|
29
27
|
} from "./testUtils.js";
|
|
30
28
|
|
|
29
|
+
// We want to simulate a real world communication that happens asynchronously
|
|
30
|
+
TEST_NODE_CONFIG.withAsyncPeers = true;
|
|
31
|
+
|
|
31
32
|
const Crypto = await WasmCrypto.create();
|
|
32
33
|
|
|
33
|
-
let jazzCloud
|
|
34
|
-
isSyncServer: true,
|
|
35
|
-
});
|
|
34
|
+
let jazzCloud: ReturnType<typeof setupTestNode>;
|
|
36
35
|
|
|
37
36
|
beforeEach(async () => {
|
|
38
37
|
jazzCloud = setupTestNode({
|
|
@@ -47,16 +46,14 @@ test("If we add a client peer, but it never subscribes to a coValue, it won't ge
|
|
|
47
46
|
|
|
48
47
|
const map = group.createMap();
|
|
49
48
|
|
|
50
|
-
const [inRx
|
|
51
|
-
const [
|
|
52
|
-
const outRxQ = outRx[Symbol.asyncIterator]();
|
|
49
|
+
const [inRx] = newQueuePair();
|
|
50
|
+
const [, outTx] = newQueuePair();
|
|
53
51
|
|
|
54
52
|
node.syncManager.addPeer({
|
|
55
53
|
id: "test",
|
|
56
54
|
incoming: inRx,
|
|
57
55
|
outgoing: outTx,
|
|
58
56
|
role: "client",
|
|
59
|
-
crashOnClose: true,
|
|
60
57
|
});
|
|
61
58
|
|
|
62
59
|
map.set("hello", "world", "trusting");
|
|
@@ -66,7 +63,9 @@ test("If we add a client peer, but it never subscribes to a coValue, it won't ge
|
|
|
66
63
|
);
|
|
67
64
|
|
|
68
65
|
const result = await Promise.race([
|
|
69
|
-
|
|
66
|
+
new Promise((resolve) => {
|
|
67
|
+
inRx.onMessage((msg) => resolve(msg));
|
|
68
|
+
}),
|
|
70
69
|
timeoutPromise,
|
|
71
70
|
]);
|
|
72
71
|
|
|
@@ -115,7 +114,7 @@ test("Can sync a coValue with private transactions through a server to another c
|
|
|
115
114
|
test("should keep the peer state when the peer closes", async () => {
|
|
116
115
|
const client = setupTestNode();
|
|
117
116
|
|
|
118
|
-
const { peer, peerState } = client.connectToSyncServer();
|
|
117
|
+
const { peer, peerState, peerOnServer } = client.connectToSyncServer();
|
|
119
118
|
|
|
120
119
|
const group = jazzCloud.node.createGroup();
|
|
121
120
|
const map = group.createMap();
|
|
@@ -125,10 +124,11 @@ test("should keep the peer state when the peer closes", async () => {
|
|
|
125
124
|
|
|
126
125
|
const syncManager = client.node.syncManager;
|
|
127
126
|
|
|
128
|
-
|
|
129
|
-
await peer.outgoing.push("Disconnected");
|
|
127
|
+
peerOnServer.outgoing.push("Disconnected");
|
|
130
128
|
|
|
131
|
-
await waitFor(() =>
|
|
129
|
+
await waitFor(() => {
|
|
130
|
+
return peerState.closed;
|
|
131
|
+
});
|
|
132
132
|
|
|
133
133
|
expect(syncManager.peers[peer.id]).not.toBeUndefined();
|
|
134
134
|
});
|
|
@@ -136,7 +136,7 @@ test("should keep the peer state when the peer closes", async () => {
|
|
|
136
136
|
test("should delete the peer state when the peer closes if deletePeerStateOnClose is true", async () => {
|
|
137
137
|
const client = setupTestNode();
|
|
138
138
|
|
|
139
|
-
const { peer, peerState } = client.connectToSyncServer();
|
|
139
|
+
const { peer, peerState, peerOnServer } = client.connectToSyncServer();
|
|
140
140
|
|
|
141
141
|
peer.deletePeerStateOnClose = true;
|
|
142
142
|
|
|
@@ -148,8 +148,7 @@ test("should delete the peer state when the peer closes if deletePeerStateOnClos
|
|
|
148
148
|
|
|
149
149
|
const syncManager = client.node.syncManager;
|
|
150
150
|
|
|
151
|
-
|
|
152
|
-
await peer.outgoing.push("Disconnected");
|
|
151
|
+
peerOnServer.outgoing.push("Disconnected");
|
|
153
152
|
|
|
154
153
|
await waitFor(() => peerState?.closed);
|
|
155
154
|
|
|
@@ -929,7 +928,6 @@ describe("metrics", () => {
|
|
|
929
928
|
incoming: inPeer1,
|
|
930
929
|
outgoing: outPeer1,
|
|
931
930
|
role: "client",
|
|
932
|
-
crashOnClose: false,
|
|
933
931
|
});
|
|
934
932
|
|
|
935
933
|
connectedPeers = await metricReader.getMetricValue("jazz.peers", {
|
|
@@ -944,7 +942,6 @@ describe("metrics", () => {
|
|
|
944
942
|
incoming: inPeer2,
|
|
945
943
|
outgoing: outPeer2,
|
|
946
944
|
role: "client",
|
|
947
|
-
crashOnClose: false,
|
|
948
945
|
});
|
|
949
946
|
|
|
950
947
|
connectedPeers = await metricReader.getMetricValue("jazz.peers", {
|
|
@@ -959,7 +956,6 @@ describe("metrics", () => {
|
|
|
959
956
|
incoming: inServer1,
|
|
960
957
|
outgoing: outServer1,
|
|
961
958
|
role: "server",
|
|
962
|
-
crashOnClose: false,
|
|
963
959
|
});
|
|
964
960
|
connectedServerPeers = await metricReader.getMetricValue("jazz.peers", {
|
|
965
961
|
role: "server",
|
|
@@ -970,7 +966,6 @@ describe("metrics", () => {
|
|
|
970
966
|
});
|
|
971
967
|
expect(connectedPeers).toBe(2);
|
|
972
968
|
|
|
973
|
-
// @ts-expect-error Simulating peer-1 closing
|
|
974
969
|
await outPeer1.push("Disconnected");
|
|
975
970
|
await waitFor(() => node.syncManager.peers["peer-1"]?.closed);
|
|
976
971
|
|
|
@@ -979,7 +974,6 @@ describe("metrics", () => {
|
|
|
979
974
|
});
|
|
980
975
|
expect(connectedPeers).toBe(1);
|
|
981
976
|
|
|
982
|
-
// @ts-expect-error Simulating server-1 closing
|
|
983
977
|
await outServer1.push("Disconnected");
|
|
984
978
|
|
|
985
979
|
await waitFor(() => node.syncManager.peers["server-1"]?.closed);
|