cojson 0.13.5 → 0.13.10
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 +16 -0
- package/LICENSE.txt +1 -1
- package/dist/PeerState.d.ts +6 -0
- package/dist/PeerState.d.ts.map +1 -1
- package/dist/PeerState.js +43 -0
- package/dist/PeerState.js.map +1 -1
- package/dist/coValueCore.d.ts +3 -1
- package/dist/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore.js +26 -8
- package/dist/coValueCore.js.map +1 -1
- package/dist/coValueState.d.ts +1 -0
- package/dist/coValueState.d.ts.map +1 -1
- package/dist/coValueState.js +27 -2
- package/dist/coValueState.js.map +1 -1
- package/dist/coValues/group.d.ts +1 -0
- package/dist/coValues/group.d.ts.map +1 -1
- package/dist/coValues/group.js +45 -21
- package/dist/coValues/group.js.map +1 -1
- package/dist/crypto/crypto.d.ts +2 -2
- package/dist/crypto/crypto.d.ts.map +1 -1
- package/dist/permissions.d.ts +1 -0
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js +19 -3
- package/dist/permissions.js.map +1 -1
- package/dist/storage/FileSystem.d.ts +2 -2
- package/dist/storage/FileSystem.d.ts.map +1 -1
- package/dist/sync.d.ts +14 -4
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +146 -146
- package/dist/sync.js.map +1 -1
- package/dist/tests/SyncStateManager.test.js +51 -46
- package/dist/tests/SyncStateManager.test.js.map +1 -1
- package/dist/tests/coValueCore.test.js +66 -4
- package/dist/tests/coValueCore.test.js.map +1 -1
- package/dist/tests/coValueState.test.js +31 -4
- package/dist/tests/coValueState.test.js.map +1 -1
- package/dist/tests/group.test.js +135 -2
- package/dist/tests/group.test.js.map +1 -1
- package/dist/tests/messagesTestUtils.d.ts +13 -0
- package/dist/tests/messagesTestUtils.d.ts.map +1 -0
- package/dist/tests/messagesTestUtils.js +42 -0
- package/dist/tests/messagesTestUtils.js.map +1 -0
- package/dist/tests/sync.load.test.d.ts +2 -0
- package/dist/tests/sync.load.test.d.ts.map +1 -0
- package/dist/tests/sync.load.test.js +249 -0
- package/dist/tests/sync.load.test.js.map +1 -0
- package/dist/tests/sync.mesh.test.d.ts +2 -0
- package/dist/tests/sync.mesh.test.d.ts.map +1 -0
- package/dist/tests/sync.mesh.test.js +157 -0
- package/dist/tests/sync.mesh.test.js.map +1 -0
- package/dist/tests/sync.peerReconciliation.test.d.ts +2 -0
- package/dist/tests/sync.peerReconciliation.test.d.ts.map +1 -0
- package/dist/tests/sync.peerReconciliation.test.js +166 -0
- package/dist/tests/sync.peerReconciliation.test.js.map +1 -0
- package/dist/tests/sync.storage.test.d.ts +2 -0
- package/dist/tests/sync.storage.test.d.ts.map +1 -0
- package/dist/tests/sync.storage.test.js +201 -0
- package/dist/tests/sync.storage.test.js.map +1 -0
- package/dist/tests/sync.test.js +139 -1048
- package/dist/tests/sync.test.js.map +1 -1
- package/dist/tests/sync.upload.test.d.ts +2 -0
- package/dist/tests/sync.upload.test.d.ts.map +1 -0
- package/dist/tests/sync.upload.test.js +156 -0
- package/dist/tests/sync.upload.test.js.map +1 -0
- package/dist/tests/testUtils.d.ts +76 -33
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/dist/tests/testUtils.js +154 -47
- package/dist/tests/testUtils.js.map +1 -1
- package/package.json +2 -2
- package/src/PeerState.ts +59 -1
- package/src/coValueCore.ts +37 -7
- package/src/coValueState.ts +34 -3
- package/src/coValues/group.ts +83 -45
- package/src/permissions.ts +31 -3
- package/src/sync.ts +169 -185
- package/src/tests/SyncStateManager.test.ts +58 -70
- package/src/tests/coValueCore.test.ts +90 -3
- package/src/tests/coValueState.test.ts +59 -5
- package/src/tests/group.test.ts +250 -2
- package/src/tests/messagesTestUtils.ts +75 -0
- package/src/tests/sync.load.test.ts +327 -0
- package/src/tests/sync.mesh.test.ts +219 -0
- package/src/tests/sync.peerReconciliation.test.ts +251 -0
- package/src/tests/sync.storage.test.ts +259 -0
- package/src/tests/sync.test.ts +170 -1245
- package/src/tests/sync.upload.test.ts +202 -0
- package/src/tests/testUtils.ts +215 -61
|
@@ -6,54 +6,53 @@ import {
|
|
|
6
6
|
import { connectedPeers } from "../streamUtils.js";
|
|
7
7
|
import { emptyKnownState } from "../sync.js";
|
|
8
8
|
import {
|
|
9
|
+
SyncMessagesLog,
|
|
9
10
|
blockMessageTypeOnOutgoingPeer,
|
|
10
|
-
connectNodeToSyncServer,
|
|
11
11
|
createTestNode,
|
|
12
12
|
loadCoValueOrFail,
|
|
13
|
-
|
|
13
|
+
setupTestNode,
|
|
14
14
|
waitFor,
|
|
15
15
|
} from "./testUtils.js";
|
|
16
16
|
|
|
17
|
-
let jazzCloud =
|
|
17
|
+
let jazzCloud = setupTestNode({ isSyncServer: true });
|
|
18
18
|
|
|
19
19
|
beforeEach(async () => {
|
|
20
|
-
|
|
20
|
+
SyncMessagesLog.clear();
|
|
21
|
+
jazzCloud = setupTestNode({ isSyncServer: true });
|
|
21
22
|
});
|
|
22
23
|
|
|
23
24
|
describe("SyncStateManager", () => {
|
|
24
25
|
test("subscribeToUpdates receives updates when peer state changes", async () => {
|
|
25
26
|
// Setup nodes
|
|
26
|
-
const client =
|
|
27
|
-
const {
|
|
27
|
+
const client = setupTestNode({ connected: true });
|
|
28
|
+
const { peerState } = client.connectToSyncServer();
|
|
28
29
|
|
|
29
30
|
// Create test data
|
|
30
|
-
const group = client.createGroup();
|
|
31
|
+
const group = client.node.createGroup();
|
|
31
32
|
const map = group.createMap();
|
|
32
33
|
map.set("key1", "value1", "trusting");
|
|
33
34
|
|
|
34
|
-
const subscriptionManager = client.syncManager.syncState;
|
|
35
|
+
const subscriptionManager = client.node.syncManager.syncState;
|
|
35
36
|
|
|
36
37
|
const updateSpy: GlobalSyncStateListenerCallback = vi.fn();
|
|
37
38
|
const unsubscribe = subscriptionManager.subscribeToUpdates(updateSpy);
|
|
38
39
|
|
|
39
|
-
await client.syncManager.actuallySyncCoValue(map.core);
|
|
40
|
+
await client.node.syncManager.actuallySyncCoValue(map.core);
|
|
40
41
|
|
|
41
42
|
expect(updateSpy).toHaveBeenCalledWith(
|
|
42
|
-
|
|
43
|
+
peerState.id,
|
|
43
44
|
emptyKnownState(map.core.id),
|
|
44
45
|
{ uploaded: false },
|
|
45
46
|
);
|
|
46
47
|
|
|
47
48
|
await waitFor(() => {
|
|
48
|
-
return subscriptionManager.getCurrentSyncState(
|
|
49
|
-
|
|
50
|
-
map.core.id,
|
|
51
|
-
).uploaded;
|
|
49
|
+
return subscriptionManager.getCurrentSyncState(peerState.id, map.core.id)
|
|
50
|
+
.uploaded;
|
|
52
51
|
});
|
|
53
52
|
|
|
54
53
|
expect(updateSpy).toHaveBeenCalledWith(
|
|
55
|
-
|
|
56
|
-
client.syncManager.peers[
|
|
54
|
+
peerState.id,
|
|
55
|
+
client.node.syncManager.peers[peerState.id]!.knownStates.get(
|
|
57
56
|
map.core.id,
|
|
58
57
|
)!,
|
|
59
58
|
{ uploaded: true },
|
|
@@ -65,11 +64,11 @@ describe("SyncStateManager", () => {
|
|
|
65
64
|
|
|
66
65
|
test("subscribeToPeerUpdates receives updates only for specific peer", async () => {
|
|
67
66
|
// Setup nodes
|
|
68
|
-
const client =
|
|
69
|
-
const {
|
|
67
|
+
const client = setupTestNode({ connected: true });
|
|
68
|
+
const { peerState } = client.connectToSyncServer();
|
|
70
69
|
|
|
71
70
|
// Create test data
|
|
72
|
-
const group = client.createGroup();
|
|
71
|
+
const group = client.node.createGroup();
|
|
73
72
|
const map = group.createMap();
|
|
74
73
|
map.set("key1", "value1", "trusting");
|
|
75
74
|
|
|
@@ -78,14 +77,14 @@ describe("SyncStateManager", () => {
|
|
|
78
77
|
peer2role: "server",
|
|
79
78
|
});
|
|
80
79
|
|
|
81
|
-
client.syncManager.addPeer(clientStoragePeer);
|
|
80
|
+
client.node.syncManager.addPeer(clientStoragePeer);
|
|
82
81
|
|
|
83
|
-
const subscriptionManager = client.syncManager.syncState;
|
|
82
|
+
const subscriptionManager = client.node.syncManager.syncState;
|
|
84
83
|
|
|
85
84
|
const updateToJazzCloudSpy: PeerSyncStateListenerCallback = vi.fn();
|
|
86
85
|
const updateToStorageSpy: PeerSyncStateListenerCallback = vi.fn();
|
|
87
86
|
const unsubscribe1 = subscriptionManager.subscribeToPeerUpdates(
|
|
88
|
-
|
|
87
|
+
peerState.id,
|
|
89
88
|
updateToJazzCloudSpy,
|
|
90
89
|
);
|
|
91
90
|
const unsubscribe2 = subscriptionManager.subscribeToPeerUpdates(
|
|
@@ -98,7 +97,7 @@ describe("SyncStateManager", () => {
|
|
|
98
97
|
unsubscribe2();
|
|
99
98
|
});
|
|
100
99
|
|
|
101
|
-
await client.syncManager.actuallySyncCoValue(map.core);
|
|
100
|
+
await client.node.syncManager.actuallySyncCoValue(map.core);
|
|
102
101
|
|
|
103
102
|
expect(updateToJazzCloudSpy).toHaveBeenCalledWith(
|
|
104
103
|
emptyKnownState(map.core.id),
|
|
@@ -106,14 +105,12 @@ describe("SyncStateManager", () => {
|
|
|
106
105
|
);
|
|
107
106
|
|
|
108
107
|
await waitFor(() => {
|
|
109
|
-
return subscriptionManager.getCurrentSyncState(
|
|
110
|
-
|
|
111
|
-
map.core.id,
|
|
112
|
-
).uploaded;
|
|
108
|
+
return subscriptionManager.getCurrentSyncState(peerState.id, map.core.id)
|
|
109
|
+
.uploaded;
|
|
113
110
|
});
|
|
114
111
|
|
|
115
112
|
expect(updateToJazzCloudSpy).toHaveBeenLastCalledWith(
|
|
116
|
-
client.syncManager.peers[
|
|
113
|
+
client.node.syncManager.peers[peerState.id]!.knownStates.get(
|
|
117
114
|
map.core.id,
|
|
118
115
|
)!,
|
|
119
116
|
{ uploaded: true },
|
|
@@ -127,66 +124,62 @@ describe("SyncStateManager", () => {
|
|
|
127
124
|
|
|
128
125
|
test("getIsCoValueFullyUploadedIntoPeer returns correct status", async () => {
|
|
129
126
|
// Setup nodes
|
|
130
|
-
const client =
|
|
131
|
-
const {
|
|
127
|
+
const client = setupTestNode({ connected: true });
|
|
128
|
+
const { peerState } = client.connectToSyncServer();
|
|
132
129
|
|
|
133
130
|
// Create test data
|
|
134
|
-
const group = client.createGroup();
|
|
131
|
+
const group = client.node.createGroup();
|
|
135
132
|
const map = group.createMap();
|
|
136
133
|
map.set("key1", "value1", "trusting");
|
|
137
134
|
|
|
138
|
-
await client.syncManager.actuallySyncCoValue(map.core);
|
|
135
|
+
await client.node.syncManager.actuallySyncCoValue(map.core);
|
|
139
136
|
|
|
140
|
-
const subscriptionManager = client.syncManager.syncState;
|
|
137
|
+
const subscriptionManager = client.node.syncManager.syncState;
|
|
141
138
|
|
|
142
139
|
expect(
|
|
143
|
-
subscriptionManager.getCurrentSyncState(
|
|
140
|
+
subscriptionManager.getCurrentSyncState(peerState.id, map.core.id)
|
|
144
141
|
.uploaded,
|
|
145
142
|
).toBe(false);
|
|
146
143
|
|
|
147
144
|
await waitFor(() => {
|
|
148
|
-
return subscriptionManager.getCurrentSyncState(
|
|
149
|
-
|
|
150
|
-
map.core.id,
|
|
151
|
-
).uploaded;
|
|
145
|
+
return subscriptionManager.getCurrentSyncState(peerState.id, map.core.id)
|
|
146
|
+
.uploaded;
|
|
152
147
|
});
|
|
153
148
|
|
|
154
149
|
expect(
|
|
155
|
-
subscriptionManager.getCurrentSyncState(
|
|
150
|
+
subscriptionManager.getCurrentSyncState(peerState.id, map.core.id)
|
|
156
151
|
.uploaded,
|
|
157
152
|
).toBe(true);
|
|
158
153
|
});
|
|
159
154
|
|
|
160
155
|
test("unsubscribe stops receiving updates", async () => {
|
|
161
156
|
// Setup nodes
|
|
162
|
-
const client =
|
|
163
|
-
const {
|
|
157
|
+
const client = setupTestNode({ connected: true });
|
|
158
|
+
const { peerState } = client.connectToSyncServer();
|
|
164
159
|
|
|
165
160
|
// Create test data
|
|
166
|
-
const group = client.createGroup();
|
|
161
|
+
const group = client.node.createGroup();
|
|
167
162
|
const map = group.createMap();
|
|
168
163
|
map.set("key1", "value1", "trusting");
|
|
169
164
|
|
|
170
|
-
const subscriptionManager = client.syncManager.syncState;
|
|
165
|
+
const subscriptionManager = client.node.syncManager.syncState;
|
|
171
166
|
const anyUpdateSpy = vi.fn();
|
|
172
167
|
const unsubscribe1 = subscriptionManager.subscribeToUpdates(anyUpdateSpy);
|
|
173
168
|
const unsubscribe2 = subscriptionManager.subscribeToPeerUpdates(
|
|
174
|
-
|
|
169
|
+
peerState.id,
|
|
175
170
|
anyUpdateSpy,
|
|
176
171
|
);
|
|
177
172
|
|
|
178
173
|
unsubscribe1();
|
|
179
174
|
unsubscribe2();
|
|
180
175
|
|
|
181
|
-
await client.syncManager.actuallySyncCoValue(map.core);
|
|
176
|
+
await client.node.syncManager.actuallySyncCoValue(map.core);
|
|
182
177
|
|
|
183
178
|
anyUpdateSpy.mockClear();
|
|
184
179
|
|
|
185
180
|
await waitFor(() => {
|
|
186
|
-
return subscriptionManager.getCurrentSyncState(
|
|
187
|
-
|
|
188
|
-
map.core.id,
|
|
189
|
-
).uploaded;
|
|
181
|
+
return subscriptionManager.getCurrentSyncState(peerState.id, map.core.id)
|
|
182
|
+
.uploaded;
|
|
190
183
|
});
|
|
191
184
|
|
|
192
185
|
expect(anyUpdateSpy).not.toHaveBeenCalled();
|
|
@@ -194,22 +187,20 @@ describe("SyncStateManager", () => {
|
|
|
194
187
|
|
|
195
188
|
test("getCurrentSyncState should return the correct state", async () => {
|
|
196
189
|
// Setup nodes
|
|
197
|
-
const
|
|
198
|
-
const serverNode = jazzCloud;
|
|
199
|
-
const {
|
|
200
|
-
|
|
201
|
-
serverToNodePeer: serverToClientPeer,
|
|
202
|
-
} = connectNodeToSyncServer(clientNode);
|
|
190
|
+
const client = setupTestNode({ connected: true });
|
|
191
|
+
const serverNode = jazzCloud.node;
|
|
192
|
+
const { peer, peerOnServer } = client.connectToSyncServer();
|
|
193
|
+
|
|
203
194
|
// Create test data
|
|
204
|
-
const group =
|
|
195
|
+
const group = client.node.createGroup();
|
|
205
196
|
const map = group.createMap();
|
|
206
197
|
map.set("key1", "value1", "trusting");
|
|
207
198
|
group.addMember("everyone", "writer");
|
|
208
199
|
|
|
209
200
|
// Initially should not be synced
|
|
210
201
|
expect(
|
|
211
|
-
|
|
212
|
-
|
|
202
|
+
client.node.syncManager.syncState.getCurrentSyncState(
|
|
203
|
+
peer.id,
|
|
213
204
|
map.core.id,
|
|
214
205
|
),
|
|
215
206
|
).toEqual({ uploaded: false });
|
|
@@ -218,8 +209,8 @@ describe("SyncStateManager", () => {
|
|
|
218
209
|
await map.core.waitForSync();
|
|
219
210
|
|
|
220
211
|
expect(
|
|
221
|
-
|
|
222
|
-
|
|
212
|
+
client.node.syncManager.syncState.getCurrentSyncState(
|
|
213
|
+
peer.id,
|
|
223
214
|
map.core.id,
|
|
224
215
|
),
|
|
225
216
|
).toEqual({ uploaded: true });
|
|
@@ -227,23 +218,20 @@ describe("SyncStateManager", () => {
|
|
|
227
218
|
const mapOnServer = await loadCoValueOrFail(serverNode, map.id);
|
|
228
219
|
|
|
229
220
|
// Block the content messages so the client won't fully sync immediately
|
|
230
|
-
const outgoing = blockMessageTypeOnOutgoingPeer(
|
|
231
|
-
serverToClientPeer,
|
|
232
|
-
"content",
|
|
233
|
-
);
|
|
221
|
+
const outgoing = blockMessageTypeOnOutgoingPeer(peerOnServer, "content");
|
|
234
222
|
|
|
235
223
|
mapOnServer.set("key2", "value2", "trusting");
|
|
236
224
|
|
|
237
225
|
expect(
|
|
238
|
-
|
|
239
|
-
|
|
226
|
+
client.node.syncManager.syncState.getCurrentSyncState(
|
|
227
|
+
peer.id,
|
|
240
228
|
map.core.id,
|
|
241
229
|
),
|
|
242
230
|
).toEqual({ uploaded: true });
|
|
243
231
|
|
|
244
232
|
expect(
|
|
245
233
|
serverNode.syncManager.syncState.getCurrentSyncState(
|
|
246
|
-
|
|
234
|
+
peerOnServer.id,
|
|
247
235
|
map.core.id,
|
|
248
236
|
),
|
|
249
237
|
).toEqual({ uploaded: false });
|
|
@@ -254,15 +242,15 @@ describe("SyncStateManager", () => {
|
|
|
254
242
|
await mapOnServer.core.waitForSync();
|
|
255
243
|
|
|
256
244
|
expect(
|
|
257
|
-
|
|
258
|
-
|
|
245
|
+
client.node.syncManager.syncState.getCurrentSyncState(
|
|
246
|
+
peer.id,
|
|
259
247
|
map.core.id,
|
|
260
248
|
),
|
|
261
249
|
).toEqual({ uploaded: true });
|
|
262
250
|
|
|
263
251
|
expect(
|
|
264
252
|
serverNode.syncManager.syncState.getCurrentSyncState(
|
|
265
|
-
|
|
253
|
+
peerOnServer.id,
|
|
266
254
|
map.core.id,
|
|
267
255
|
),
|
|
268
256
|
).toEqual({ uploaded: true });
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { expect, test, vi } from "vitest";
|
|
1
|
+
import { assert, afterEach, beforeEach, expect, test, vi } from "vitest";
|
|
2
2
|
import { CoValueCore, Transaction } from "../coValueCore.js";
|
|
3
3
|
import { MapOpPayload } from "../coValues/coMap.js";
|
|
4
4
|
import { WasmCrypto } from "../crypto/WasmCrypto.js";
|
|
@@ -6,14 +6,26 @@ import { stableStringify } from "../jsonStringify.js";
|
|
|
6
6
|
import { LocalNode } from "../localNode.js";
|
|
7
7
|
import { Role } from "../permissions.js";
|
|
8
8
|
import {
|
|
9
|
+
createTestMetricReader,
|
|
9
10
|
createTestNode,
|
|
10
11
|
createTwoConnectedNodes,
|
|
11
12
|
loadCoValueOrFail,
|
|
12
13
|
randomAnonymousAccountAndSessionID,
|
|
14
|
+
tearDownTestMetricReader,
|
|
13
15
|
} from "./testUtils.js";
|
|
14
16
|
|
|
15
17
|
const Crypto = await WasmCrypto.create();
|
|
16
18
|
|
|
19
|
+
let metricReader: ReturnType<typeof createTestMetricReader>;
|
|
20
|
+
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
metricReader = createTestMetricReader();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
afterEach(() => {
|
|
26
|
+
tearDownTestMetricReader();
|
|
27
|
+
});
|
|
28
|
+
|
|
17
29
|
test("Can create coValue with new agent credentials and add transaction to it", () => {
|
|
18
30
|
const [account, sessionID] = randomAnonymousAccountAndSessionID();
|
|
19
31
|
const node = new LocalNode(account, sessionID, Crypto);
|
|
@@ -197,6 +209,63 @@ test("New transactions in a group correctly update owned values, including subsc
|
|
|
197
209
|
expect(map.core.getValidSortedTransactions().length).toBe(0);
|
|
198
210
|
});
|
|
199
211
|
|
|
212
|
+
test("correctly records transactions", async () => {
|
|
213
|
+
const [account, sessionID] = randomAnonymousAccountAndSessionID();
|
|
214
|
+
const node = new LocalNode(account, sessionID, Crypto);
|
|
215
|
+
|
|
216
|
+
const changes1 = stableStringify([{ hello: "world" }]);
|
|
217
|
+
node.syncManager.recordTransactionsSize(
|
|
218
|
+
[
|
|
219
|
+
{
|
|
220
|
+
privacy: "trusting",
|
|
221
|
+
changes: changes1,
|
|
222
|
+
madeAt: Date.now(),
|
|
223
|
+
},
|
|
224
|
+
],
|
|
225
|
+
"server",
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
let value = await metricReader.getMetricValue("jazz.transactions.size", {
|
|
229
|
+
source: "server",
|
|
230
|
+
});
|
|
231
|
+
assert(typeof value !== "number" && !!value?.count);
|
|
232
|
+
expect(value.count).toBe(1);
|
|
233
|
+
expect(value.sum).toBe(changes1.length);
|
|
234
|
+
|
|
235
|
+
const changes2 = stableStringify([{ foo: "bar" }]);
|
|
236
|
+
node.syncManager.recordTransactionsSize(
|
|
237
|
+
[
|
|
238
|
+
{
|
|
239
|
+
privacy: "trusting",
|
|
240
|
+
changes: changes2,
|
|
241
|
+
madeAt: Date.now(),
|
|
242
|
+
},
|
|
243
|
+
],
|
|
244
|
+
"server",
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
value = await metricReader.getMetricValue("jazz.transactions.size", {
|
|
248
|
+
source: "server",
|
|
249
|
+
});
|
|
250
|
+
assert(typeof value !== "number" && !!value?.count);
|
|
251
|
+
expect(value.count).toBe(2);
|
|
252
|
+
expect(value.sum).toBe(changes1.length + changes2.length);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
test("(smoke test) records transactions from local node", async () => {
|
|
256
|
+
const [account, sessionID] = randomAnonymousAccountAndSessionID();
|
|
257
|
+
const node = new LocalNode(account, sessionID, Crypto);
|
|
258
|
+
|
|
259
|
+
node.createGroup();
|
|
260
|
+
|
|
261
|
+
let value = await metricReader.getMetricValue("jazz.transactions.size", {
|
|
262
|
+
source: "local",
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
assert(typeof value !== "number" && !!value?.count);
|
|
266
|
+
expect(value.count).toBe(3);
|
|
267
|
+
});
|
|
268
|
+
|
|
200
269
|
test("creating a coValue with a group should't trigger automatically a content creation (performance)", () => {
|
|
201
270
|
const node = createTestNode();
|
|
202
271
|
|
|
@@ -218,12 +287,30 @@ test("creating a coValue with a group should't trigger automatically a content c
|
|
|
218
287
|
});
|
|
219
288
|
|
|
220
289
|
// It's called once for the group and never for the coValue
|
|
221
|
-
expect(getCurrentContentSpy).toHaveBeenCalledTimes(
|
|
222
|
-
expect(groupSpy).toHaveBeenCalledTimes(
|
|
290
|
+
expect(getCurrentContentSpy).toHaveBeenCalledTimes(0);
|
|
291
|
+
expect(groupSpy).toHaveBeenCalledTimes(0);
|
|
223
292
|
|
|
224
293
|
getCurrentContentSpy.mockRestore();
|
|
225
294
|
});
|
|
226
295
|
|
|
296
|
+
test("loading a coValue core without having the owner group available doesn't crash", () => {
|
|
297
|
+
const [account, sessionID] = randomAnonymousAccountAndSessionID();
|
|
298
|
+
const node = new LocalNode(account, sessionID, Crypto);
|
|
299
|
+
|
|
300
|
+
const otherNode = createTestNode();
|
|
301
|
+
|
|
302
|
+
const group = otherNode.createGroup();
|
|
303
|
+
|
|
304
|
+
const coValue = node.createCoValue({
|
|
305
|
+
type: "costream",
|
|
306
|
+
ruleset: { type: "ownedByGroup", group: group.id },
|
|
307
|
+
meta: null,
|
|
308
|
+
...Crypto.createdNowUnique(),
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
expect(coValue.id).toBeDefined();
|
|
312
|
+
});
|
|
313
|
+
|
|
227
314
|
test("listeners are notified even if the previous listener threw an error", async () => {
|
|
228
315
|
const { node1, node2 } = await createTwoConnectedNodes("server", "server");
|
|
229
316
|
|
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
assert,
|
|
3
|
+
afterEach,
|
|
4
|
+
beforeEach,
|
|
5
|
+
describe,
|
|
6
|
+
expect,
|
|
7
|
+
onTestFinished,
|
|
8
|
+
test,
|
|
9
|
+
vi,
|
|
10
|
+
} from "vitest";
|
|
2
11
|
import { PeerState } from "../PeerState";
|
|
3
12
|
import { CoValueCore } from "../coValueCore";
|
|
4
13
|
import { CO_VALUE_LOADING_CONFIG, CoValueState } from "../coValueState";
|
|
5
14
|
import { RawCoID } from "../ids";
|
|
6
15
|
import { Peer } from "../sync";
|
|
16
|
+
import { createTestMetricReader, tearDownTestMetricReader } from "./testUtils";
|
|
7
17
|
|
|
8
18
|
const initialMaxRetries = CO_VALUE_LOADING_CONFIG.MAX_RETRIES;
|
|
9
19
|
|
|
@@ -15,26 +25,43 @@ function mockMaxRetries(maxRetries: number) {
|
|
|
15
25
|
});
|
|
16
26
|
}
|
|
17
27
|
|
|
28
|
+
let metricReader: ReturnType<typeof createTestMetricReader>;
|
|
29
|
+
|
|
18
30
|
beforeEach(() => {
|
|
31
|
+
metricReader = createTestMetricReader();
|
|
19
32
|
mockMaxRetries(5);
|
|
20
33
|
});
|
|
21
34
|
|
|
35
|
+
afterEach(() => {
|
|
36
|
+
tearDownTestMetricReader();
|
|
37
|
+
});
|
|
38
|
+
|
|
22
39
|
describe("CoValueState", () => {
|
|
23
40
|
const mockCoValueId = "co_test123" as RawCoID;
|
|
24
41
|
|
|
25
|
-
test("should create unknown state", () => {
|
|
42
|
+
test("should create unknown state", async () => {
|
|
26
43
|
const state = CoValueState.Unknown(mockCoValueId);
|
|
27
44
|
|
|
28
45
|
expect(state.id).toBe(mockCoValueId);
|
|
29
46
|
expect(state.state.type).toBe("unknown");
|
|
47
|
+
expect(
|
|
48
|
+
await metricReader.getMetricValue("jazz.covalues.loaded", {
|
|
49
|
+
state: "unknown",
|
|
50
|
+
}),
|
|
51
|
+
).toBe(1);
|
|
30
52
|
});
|
|
31
53
|
|
|
32
|
-
test("should create loading state", () => {
|
|
54
|
+
test("should create loading state", async () => {
|
|
33
55
|
const peerIds = ["peer1", "peer2"];
|
|
34
56
|
const state = CoValueState.Loading(mockCoValueId, peerIds);
|
|
35
57
|
|
|
36
58
|
expect(state.id).toBe(mockCoValueId);
|
|
37
59
|
expect(state.state.type).toBe("loading");
|
|
60
|
+
expect(
|
|
61
|
+
await metricReader.getMetricValue("jazz.covalues.loaded", {
|
|
62
|
+
state: "loading",
|
|
63
|
+
}),
|
|
64
|
+
).toBe(1);
|
|
38
65
|
});
|
|
39
66
|
|
|
40
67
|
test("should create available state", async () => {
|
|
@@ -42,15 +69,31 @@ describe("CoValueState", () => {
|
|
|
42
69
|
const state = CoValueState.Available(mockCoValue);
|
|
43
70
|
|
|
44
71
|
expect(state.id).toBe(mockCoValueId);
|
|
45
|
-
|
|
46
|
-
expect(
|
|
72
|
+
assert(state.state.type === "available");
|
|
73
|
+
expect(state.state.coValue).toBe(mockCoValue);
|
|
47
74
|
await expect(state.getCoValue()).resolves.toEqual(mockCoValue);
|
|
75
|
+
expect(
|
|
76
|
+
await metricReader.getMetricValue("jazz.covalues.loaded", {
|
|
77
|
+
state: "available",
|
|
78
|
+
}),
|
|
79
|
+
).toBe(1);
|
|
48
80
|
});
|
|
49
81
|
|
|
50
82
|
test("should handle found action", async () => {
|
|
51
83
|
const mockCoValue = createMockCoValueCore(mockCoValueId);
|
|
52
84
|
const state = CoValueState.Loading(mockCoValueId, ["peer1", "peer2"]);
|
|
53
85
|
|
|
86
|
+
expect(
|
|
87
|
+
await metricReader.getMetricValue("jazz.covalues.loaded", {
|
|
88
|
+
state: "available",
|
|
89
|
+
}),
|
|
90
|
+
).toBe(undefined);
|
|
91
|
+
expect(
|
|
92
|
+
await metricReader.getMetricValue("jazz.covalues.loaded", {
|
|
93
|
+
state: "loading",
|
|
94
|
+
}),
|
|
95
|
+
).toBe(1);
|
|
96
|
+
|
|
54
97
|
const stateValuePromise = state.getCoValue();
|
|
55
98
|
|
|
56
99
|
state.dispatch({
|
|
@@ -61,6 +104,17 @@ describe("CoValueState", () => {
|
|
|
61
104
|
const result = await state.getCoValue();
|
|
62
105
|
expect(result).toBe(mockCoValue);
|
|
63
106
|
await expect(stateValuePromise).resolves.toBe(mockCoValue);
|
|
107
|
+
|
|
108
|
+
expect(
|
|
109
|
+
await metricReader.getMetricValue("jazz.covalues.loaded", {
|
|
110
|
+
state: "available",
|
|
111
|
+
}),
|
|
112
|
+
).toBe(1);
|
|
113
|
+
expect(
|
|
114
|
+
await metricReader.getMetricValue("jazz.covalues.loaded", {
|
|
115
|
+
state: "loading",
|
|
116
|
+
}),
|
|
117
|
+
).toBe(0);
|
|
64
118
|
});
|
|
65
119
|
|
|
66
120
|
test("should ignore actions when not in loading state", () => {
|