cojson 0.15.8 → 0.15.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 +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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { describe, expect, test, vi } from "vitest";
|
|
2
2
|
import { PeerState } from "../PeerState.js";
|
|
3
3
|
import { CO_VALUE_PRIORITY } from "../priority.js";
|
|
4
|
+
import { ConnectedPeerChannel } from "../streamUtils.js";
|
|
4
5
|
import { CoValueKnownState, Peer, SyncMessage } from "../sync.js";
|
|
5
6
|
import { waitFor } from "./testUtils.js";
|
|
6
7
|
|
|
@@ -9,13 +10,12 @@ function setup() {
|
|
|
9
10
|
id: "test-peer",
|
|
10
11
|
role: "client",
|
|
11
12
|
priority: 1,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
outgoing: {
|
|
15
|
-
push: vi.fn().mockResolvedValue(undefined),
|
|
16
|
-
close: vi.fn(),
|
|
17
|
-
},
|
|
13
|
+
incoming: new ConnectedPeerChannel(),
|
|
14
|
+
outgoing: new ConnectedPeerChannel(),
|
|
18
15
|
};
|
|
16
|
+
vi.spyOn(mockPeer.outgoing, "push");
|
|
17
|
+
vi.spyOn(mockPeer.incoming, "close");
|
|
18
|
+
vi.spyOn(mockPeer.outgoing, "close");
|
|
19
19
|
const peerState = new PeerState(mockPeer, undefined);
|
|
20
20
|
return { mockPeer, peerState };
|
|
21
21
|
}
|
|
@@ -38,15 +38,6 @@ describe("PeerState", () => {
|
|
|
38
38
|
expect(peerState.incoming).toBe(mockPeer.incoming);
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
test("should return Disconnected when closed", async () => {
|
|
42
|
-
const { peerState } = setup();
|
|
43
|
-
peerState.gracefulShutdown();
|
|
44
|
-
const incomingIterator = peerState.incoming[Symbol.asyncIterator]();
|
|
45
|
-
const { value, done } = await incomingIterator.next();
|
|
46
|
-
expect(value).toBe("Disconnected");
|
|
47
|
-
expect(done).toBe(false);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
41
|
test("should perform graceful shutdown", () => {
|
|
51
42
|
const { mockPeer, peerState } = setup();
|
|
52
43
|
peerState.gracefulShutdown();
|
|
@@ -54,109 +45,6 @@ describe("PeerState", () => {
|
|
|
54
45
|
expect(peerState.closed).toBe(true);
|
|
55
46
|
});
|
|
56
47
|
|
|
57
|
-
test("should empty the queue when closing", async () => {
|
|
58
|
-
const { mockPeer, peerState } = setup();
|
|
59
|
-
|
|
60
|
-
mockPeer.outgoing.push = vi.fn().mockImplementation((message) => {
|
|
61
|
-
return new Promise<void>((resolve) => {
|
|
62
|
-
setTimeout(resolve, 100);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
peerState.pushOutgoingMessage({
|
|
67
|
-
action: "content",
|
|
68
|
-
id: "co_z1",
|
|
69
|
-
new: {},
|
|
70
|
-
priority: CO_VALUE_PRIORITY.HIGH,
|
|
71
|
-
});
|
|
72
|
-
peerState.pushOutgoingMessage({
|
|
73
|
-
action: "content",
|
|
74
|
-
id: "co_z1",
|
|
75
|
-
new: {},
|
|
76
|
-
priority: CO_VALUE_PRIORITY.HIGH,
|
|
77
|
-
});
|
|
78
|
-
peerState.pushOutgoingMessage({
|
|
79
|
-
action: "content",
|
|
80
|
-
id: "co_z1",
|
|
81
|
-
new: {},
|
|
82
|
-
priority: CO_VALUE_PRIORITY.HIGH,
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
peerState.gracefulShutdown();
|
|
86
|
-
|
|
87
|
-
await waitFor(() => {
|
|
88
|
-
expect(peerState.isProcessing()).toBe(false);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
expect(mockPeer.outgoing.push).toHaveBeenCalledTimes(1);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
test("should schedule outgoing messages based on their priority", async () => {
|
|
95
|
-
const { peerState, mockPeer } = setup();
|
|
96
|
-
|
|
97
|
-
mockPeer.outgoing.push = vi.fn().mockImplementation((message) => {
|
|
98
|
-
return new Promise<void>((resolve) => {
|
|
99
|
-
setTimeout(resolve, 0);
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
const loadMessage: SyncMessage = {
|
|
104
|
-
action: "load",
|
|
105
|
-
id: "co_zhigh",
|
|
106
|
-
header: false,
|
|
107
|
-
sessions: {},
|
|
108
|
-
};
|
|
109
|
-
const contentMessageHigh: SyncMessage = {
|
|
110
|
-
action: "content",
|
|
111
|
-
id: "co_zhigh",
|
|
112
|
-
new: {},
|
|
113
|
-
priority: CO_VALUE_PRIORITY.HIGH,
|
|
114
|
-
};
|
|
115
|
-
const contentMessageMid: SyncMessage = {
|
|
116
|
-
action: "content",
|
|
117
|
-
id: "co_zmid",
|
|
118
|
-
new: {},
|
|
119
|
-
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
120
|
-
};
|
|
121
|
-
const contentMessageLow: SyncMessage = {
|
|
122
|
-
action: "content",
|
|
123
|
-
id: "co_zlow",
|
|
124
|
-
new: {},
|
|
125
|
-
priority: CO_VALUE_PRIORITY.LOW,
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
peerState.pushOutgoingMessage(contentMessageLow);
|
|
129
|
-
peerState.pushOutgoingMessage(contentMessageMid);
|
|
130
|
-
peerState.pushOutgoingMessage(contentMessageHigh);
|
|
131
|
-
peerState.pushOutgoingMessage(loadMessage);
|
|
132
|
-
|
|
133
|
-
await waitFor(() => {
|
|
134
|
-
expect(peerState.isProcessing()).toBe(false);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
// The first message is pushed directly, the other three are queued because are waiting
|
|
138
|
-
// for the first push to be completed.
|
|
139
|
-
expect(peerState["peer"].outgoing.push).toHaveBeenNthCalledWith(
|
|
140
|
-
1,
|
|
141
|
-
contentMessageLow,
|
|
142
|
-
);
|
|
143
|
-
|
|
144
|
-
// Load message are managed as high priority messages and having the same priority as the content message
|
|
145
|
-
// they follow the push order.
|
|
146
|
-
expect(peerState["peer"].outgoing.push).toHaveBeenNthCalledWith(
|
|
147
|
-
2,
|
|
148
|
-
contentMessageHigh,
|
|
149
|
-
);
|
|
150
|
-
expect(peerState["peer"].outgoing.push).toHaveBeenNthCalledWith(
|
|
151
|
-
3,
|
|
152
|
-
loadMessage,
|
|
153
|
-
);
|
|
154
|
-
expect(peerState["peer"].outgoing.push).toHaveBeenNthCalledWith(
|
|
155
|
-
4,
|
|
156
|
-
contentMessageMid,
|
|
157
|
-
);
|
|
158
|
-
});
|
|
159
|
-
|
|
160
48
|
test("should clone the knownStates into optimisticKnownStates and knownStates when passed as argument", () => {
|
|
161
49
|
const { peerState, mockPeer } = setup();
|
|
162
50
|
peerState.setKnownState("co_z1", {
|
|
@@ -9,7 +9,11 @@ import {
|
|
|
9
9
|
|
|
10
10
|
function setup(attrs?: Record<string, string | number>) {
|
|
11
11
|
const metricReader = createTestMetricReader();
|
|
12
|
-
const queue = new PriorityBasedMessageQueue(
|
|
12
|
+
const queue = new PriorityBasedMessageQueue(
|
|
13
|
+
CO_VALUE_PRIORITY.MEDIUM,
|
|
14
|
+
"outgoing",
|
|
15
|
+
attrs,
|
|
16
|
+
);
|
|
13
17
|
return { queue, metricReader };
|
|
14
18
|
}
|
|
15
19
|
|
|
@@ -29,21 +33,21 @@ describe("PriorityBasedMessageQueue", () => {
|
|
|
29
33
|
};
|
|
30
34
|
|
|
31
35
|
expect(
|
|
32
|
-
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
|
|
36
|
+
await metricReader.getMetricValue("jazz.messagequeue.outgoing.pushed", {
|
|
33
37
|
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
34
38
|
}),
|
|
35
39
|
).toBe(0);
|
|
36
40
|
|
|
37
41
|
void queue.push(message);
|
|
38
42
|
expect(
|
|
39
|
-
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
|
|
43
|
+
await metricReader.getMetricValue("jazz.messagequeue.outgoing.pushed", {
|
|
40
44
|
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
41
45
|
}),
|
|
42
46
|
).toBe(1);
|
|
43
47
|
|
|
44
48
|
void queue.push(message);
|
|
45
49
|
expect(
|
|
46
|
-
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
|
|
50
|
+
await metricReader.getMetricValue("jazz.messagequeue.outgoing.pushed", {
|
|
47
51
|
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
48
52
|
}),
|
|
49
53
|
).toBe(2);
|
|
@@ -59,14 +63,14 @@ describe("PriorityBasedMessageQueue", () => {
|
|
|
59
63
|
};
|
|
60
64
|
|
|
61
65
|
expect(
|
|
62
|
-
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
|
|
66
|
+
await metricReader.getMetricValue("jazz.messagequeue.outgoing.pulled", {
|
|
63
67
|
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
64
68
|
}),
|
|
65
69
|
).toBe(0);
|
|
66
70
|
|
|
67
71
|
void queue.push(message);
|
|
68
72
|
expect(
|
|
69
|
-
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
|
|
73
|
+
await metricReader.getMetricValue("jazz.messagequeue.outgoing.pulled", {
|
|
70
74
|
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
71
75
|
}),
|
|
72
76
|
).toBe(0);
|
|
@@ -74,7 +78,7 @@ describe("PriorityBasedMessageQueue", () => {
|
|
|
74
78
|
void queue.pull();
|
|
75
79
|
|
|
76
80
|
expect(
|
|
77
|
-
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
|
|
81
|
+
await metricReader.getMetricValue("jazz.messagequeue.outgoing.pulled", {
|
|
78
82
|
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
79
83
|
}),
|
|
80
84
|
).toBe(1);
|
|
@@ -82,7 +86,7 @@ describe("PriorityBasedMessageQueue", () => {
|
|
|
82
86
|
// We only have one item in the queue, so this should not change the metric value
|
|
83
87
|
void queue.pull();
|
|
84
88
|
expect(
|
|
85
|
-
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
|
|
89
|
+
await metricReader.getMetricValue("jazz.messagequeue.outgoing.pulled", {
|
|
86
90
|
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
87
91
|
}),
|
|
88
92
|
).toBe(1);
|
|
@@ -98,13 +102,13 @@ describe("PriorityBasedMessageQueue", () => {
|
|
|
98
102
|
};
|
|
99
103
|
|
|
100
104
|
expect(
|
|
101
|
-
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
|
|
105
|
+
await metricReader.getMetricValue("jazz.messagequeue.outgoing.pushed", {
|
|
102
106
|
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
103
107
|
role: "server",
|
|
104
108
|
}),
|
|
105
109
|
).toBe(0);
|
|
106
110
|
expect(
|
|
107
|
-
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
|
|
111
|
+
await metricReader.getMetricValue("jazz.messagequeue.outgoing.pushed", {
|
|
108
112
|
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
109
113
|
role: "client",
|
|
110
114
|
}),
|
|
@@ -112,13 +116,13 @@ describe("PriorityBasedMessageQueue", () => {
|
|
|
112
116
|
|
|
113
117
|
void queue.push(message);
|
|
114
118
|
expect(
|
|
115
|
-
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
|
|
119
|
+
await metricReader.getMetricValue("jazz.messagequeue.outgoing.pushed", {
|
|
116
120
|
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
117
121
|
role: "server",
|
|
118
122
|
}),
|
|
119
123
|
).toBe(1);
|
|
120
124
|
expect(
|
|
121
|
-
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
|
|
125
|
+
await metricReader.getMetricValue("jazz.messagequeue.outgoing.pulled", {
|
|
122
126
|
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
123
127
|
role: "server",
|
|
124
128
|
}),
|
|
@@ -127,13 +131,13 @@ describe("PriorityBasedMessageQueue", () => {
|
|
|
127
131
|
void queue.pull();
|
|
128
132
|
|
|
129
133
|
expect(
|
|
130
|
-
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
|
|
134
|
+
await metricReader.getMetricValue("jazz.messagequeue.outgoing.pushed", {
|
|
131
135
|
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
132
136
|
role: "server",
|
|
133
137
|
}),
|
|
134
138
|
).toBe(1);
|
|
135
139
|
expect(
|
|
136
|
-
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
|
|
140
|
+
await metricReader.getMetricValue("jazz.messagequeue.outgoing.pulled", {
|
|
137
141
|
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
138
142
|
role: "server",
|
|
139
143
|
}),
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, test, vi } from "vitest";
|
|
2
|
+
import { StoreQueue } from "../storage/StoreQueue.js";
|
|
3
|
+
import type { CoValueKnownState, NewContentMessage } from "../sync.js";
|
|
4
|
+
|
|
5
|
+
function createMockNewContentMessage(id: string): NewContentMessage[] {
|
|
6
|
+
return [
|
|
7
|
+
{
|
|
8
|
+
action: "content",
|
|
9
|
+
id: id as any,
|
|
10
|
+
priority: 0,
|
|
11
|
+
new: {},
|
|
12
|
+
},
|
|
13
|
+
];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function setup() {
|
|
17
|
+
const storeQueue = new StoreQueue();
|
|
18
|
+
const mockCallback = vi.fn();
|
|
19
|
+
const mockCorrectionCallback = vi.fn();
|
|
20
|
+
|
|
21
|
+
return { storeQueue, mockCallback, mockCorrectionCallback };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
describe("StoreQueue", () => {
|
|
25
|
+
describe("push and pull", () => {
|
|
26
|
+
test("should push and pull entries in FIFO order", () => {
|
|
27
|
+
const { storeQueue, mockCorrectionCallback } = setup();
|
|
28
|
+
const data1 = createMockNewContentMessage("co1");
|
|
29
|
+
const data2 = createMockNewContentMessage("co2");
|
|
30
|
+
|
|
31
|
+
storeQueue.push(data1, mockCorrectionCallback);
|
|
32
|
+
storeQueue.push(data2, mockCorrectionCallback);
|
|
33
|
+
|
|
34
|
+
const entry1 = storeQueue.pull();
|
|
35
|
+
const entry2 = storeQueue.pull();
|
|
36
|
+
const entry3 = storeQueue.pull(); // Should be undefined
|
|
37
|
+
|
|
38
|
+
expect(entry1).toEqual({
|
|
39
|
+
data: data1,
|
|
40
|
+
correctionCallback: mockCorrectionCallback,
|
|
41
|
+
});
|
|
42
|
+
expect(entry2).toEqual({
|
|
43
|
+
data: data2,
|
|
44
|
+
correctionCallback: mockCorrectionCallback,
|
|
45
|
+
});
|
|
46
|
+
expect(entry3).toBeUndefined();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("should handle empty queue", () => {
|
|
50
|
+
const { storeQueue } = setup();
|
|
51
|
+
const entry = storeQueue.pull();
|
|
52
|
+
expect(entry).toBeUndefined();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("should handle single entry", () => {
|
|
56
|
+
const { storeQueue, mockCorrectionCallback } = setup();
|
|
57
|
+
const data = createMockNewContentMessage("co1");
|
|
58
|
+
|
|
59
|
+
storeQueue.push(data, mockCorrectionCallback);
|
|
60
|
+
const entry = storeQueue.pull();
|
|
61
|
+
|
|
62
|
+
expect(entry).toEqual({
|
|
63
|
+
data,
|
|
64
|
+
correctionCallback: mockCorrectionCallback,
|
|
65
|
+
});
|
|
66
|
+
expect(storeQueue.pull()).toBeUndefined();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe("processQueue", () => {
|
|
71
|
+
test("should process all entries in queue", async () => {
|
|
72
|
+
const { storeQueue, mockCallback, mockCorrectionCallback } = setup();
|
|
73
|
+
const data1 = createMockNewContentMessage("co1");
|
|
74
|
+
const data2 = createMockNewContentMessage("co2");
|
|
75
|
+
|
|
76
|
+
storeQueue.push(data1, mockCorrectionCallback);
|
|
77
|
+
storeQueue.push(data2, mockCorrectionCallback);
|
|
78
|
+
|
|
79
|
+
await storeQueue.processQueue(mockCallback);
|
|
80
|
+
|
|
81
|
+
expect(mockCallback).toHaveBeenCalledTimes(2);
|
|
82
|
+
expect(mockCallback).toHaveBeenNthCalledWith(
|
|
83
|
+
1,
|
|
84
|
+
data1,
|
|
85
|
+
mockCorrectionCallback,
|
|
86
|
+
);
|
|
87
|
+
expect(mockCallback).toHaveBeenNthCalledWith(
|
|
88
|
+
2,
|
|
89
|
+
data2,
|
|
90
|
+
mockCorrectionCallback,
|
|
91
|
+
);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("should not process if already processing", async () => {
|
|
95
|
+
const { storeQueue, mockCallback, mockCorrectionCallback } = setup();
|
|
96
|
+
const data = createMockNewContentMessage("co1");
|
|
97
|
+
|
|
98
|
+
storeQueue.push(data, mockCorrectionCallback);
|
|
99
|
+
|
|
100
|
+
// Start processing
|
|
101
|
+
const processPromise1 = storeQueue.processQueue(mockCallback);
|
|
102
|
+
|
|
103
|
+
// Try to process again while already processing
|
|
104
|
+
const processPromise2 = storeQueue.processQueue(mockCallback);
|
|
105
|
+
|
|
106
|
+
await Promise.all([processPromise1, processPromise2]);
|
|
107
|
+
|
|
108
|
+
// Should only be called once
|
|
109
|
+
expect(mockCallback).toHaveBeenCalledTimes(1);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("should process entries pushed after a first processing round is done", async () => {
|
|
113
|
+
const { storeQueue, mockCallback, mockCorrectionCallback } = setup();
|
|
114
|
+
const data = createMockNewContentMessage("co1");
|
|
115
|
+
|
|
116
|
+
storeQueue.push(data, mockCorrectionCallback);
|
|
117
|
+
|
|
118
|
+
await storeQueue.processQueue(mockCallback);
|
|
119
|
+
|
|
120
|
+
storeQueue.push(data, mockCorrectionCallback);
|
|
121
|
+
|
|
122
|
+
await storeQueue.processQueue(mockCallback);
|
|
123
|
+
|
|
124
|
+
expect(mockCallback).toHaveBeenCalledTimes(2);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("should handle empty queue during processing", async () => {
|
|
128
|
+
const { storeQueue, mockCallback } = setup();
|
|
129
|
+
await storeQueue.processQueue(mockCallback);
|
|
130
|
+
|
|
131
|
+
expect(mockCallback).not.toHaveBeenCalled();
|
|
132
|
+
expect(storeQueue.processing).toBe(false);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("should handle async callback that throws", async () => {
|
|
136
|
+
const { storeQueue, mockCorrectionCallback } = setup();
|
|
137
|
+
const data = createMockNewContentMessage("co1");
|
|
138
|
+
|
|
139
|
+
storeQueue.push(data, mockCorrectionCallback);
|
|
140
|
+
|
|
141
|
+
const errorCallback = vi.fn().mockRejectedValue(new Error("Test error"));
|
|
142
|
+
|
|
143
|
+
await storeQueue.processQueue(errorCallback);
|
|
144
|
+
expect(storeQueue.processing).toBe(false);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
describe("drain", () => {
|
|
149
|
+
test("should remove all entries from queue", () => {
|
|
150
|
+
const { storeQueue, mockCorrectionCallback } = setup();
|
|
151
|
+
const data1 = createMockNewContentMessage("co1");
|
|
152
|
+
const data2 = createMockNewContentMessage("co2");
|
|
153
|
+
|
|
154
|
+
storeQueue.push(data1, mockCorrectionCallback);
|
|
155
|
+
storeQueue.push(data2, mockCorrectionCallback);
|
|
156
|
+
|
|
157
|
+
storeQueue.drain();
|
|
158
|
+
|
|
159
|
+
expect(storeQueue.pull()).toBeUndefined();
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("should handle empty queue", () => {
|
|
163
|
+
const { storeQueue } = setup();
|
|
164
|
+
expect(() => storeQueue.drain()).not.toThrow();
|
|
165
|
+
expect(storeQueue.pull()).toBeUndefined();
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
describe("integration scenarios", () => {
|
|
170
|
+
test("should handle complex workflow with multiple operations", async () => {
|
|
171
|
+
const { storeQueue, mockCallback, mockCorrectionCallback } = setup();
|
|
172
|
+
const data1 = createMockNewContentMessage("co1");
|
|
173
|
+
const data2 = createMockNewContentMessage("co2");
|
|
174
|
+
|
|
175
|
+
// Push entries
|
|
176
|
+
storeQueue.push(data1, mockCorrectionCallback);
|
|
177
|
+
storeQueue.push(data2, mockCorrectionCallback);
|
|
178
|
+
|
|
179
|
+
// Process queue
|
|
180
|
+
await storeQueue.processQueue(mockCallback);
|
|
181
|
+
|
|
182
|
+
// Verify all entries were processed
|
|
183
|
+
expect(mockCallback).toHaveBeenCalledTimes(2);
|
|
184
|
+
expect(storeQueue.pull()).toBeUndefined();
|
|
185
|
+
|
|
186
|
+
// Add more entries and process again
|
|
187
|
+
const data3 = createMockNewContentMessage("co3");
|
|
188
|
+
storeQueue.push(data3, mockCorrectionCallback);
|
|
189
|
+
|
|
190
|
+
await storeQueue.processQueue(mockCallback);
|
|
191
|
+
|
|
192
|
+
expect(mockCallback).toHaveBeenCalledTimes(3);
|
|
193
|
+
expect(mockCallback).toHaveBeenLastCalledWith(
|
|
194
|
+
data3,
|
|
195
|
+
mockCorrectionCallback,
|
|
196
|
+
);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test("should handle correction callback with known state", async () => {
|
|
200
|
+
const { storeQueue, mockCorrectionCallback } = setup();
|
|
201
|
+
const sessionId = "account1_session_z123" as any;
|
|
202
|
+
const knownState: CoValueKnownState = {
|
|
203
|
+
id: "co1" as any,
|
|
204
|
+
header: true,
|
|
205
|
+
sessions: { [sessionId]: 5 },
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const data = createMockNewContentMessage("co1");
|
|
209
|
+
|
|
210
|
+
storeQueue.push(data, mockCorrectionCallback);
|
|
211
|
+
|
|
212
|
+
await storeQueue.processQueue(async (data, correctionCallback) => {
|
|
213
|
+
// Simulate some processing
|
|
214
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
215
|
+
// Call the correction callback
|
|
216
|
+
correctionCallback(knownState);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
expect(mockCorrectionCallback).toHaveBeenCalledWith(knownState);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
test("should handle concurrent processing attempts", async () => {
|
|
223
|
+
const { storeQueue, mockCallback, mockCorrectionCallback } = setup();
|
|
224
|
+
const data = createMockNewContentMessage("co1");
|
|
225
|
+
|
|
226
|
+
storeQueue.push(data, mockCorrectionCallback);
|
|
227
|
+
|
|
228
|
+
// Start multiple processing attempts concurrently
|
|
229
|
+
const promises = [
|
|
230
|
+
storeQueue.processQueue(mockCallback),
|
|
231
|
+
storeQueue.processQueue(mockCallback),
|
|
232
|
+
storeQueue.processQueue(mockCallback),
|
|
233
|
+
];
|
|
234
|
+
|
|
235
|
+
await Promise.all(promises);
|
|
236
|
+
|
|
237
|
+
// Should only process once
|
|
238
|
+
expect(mockCallback).toHaveBeenCalledTimes(1);
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
describe("edge cases", () => {
|
|
243
|
+
test("should handle undefined data", () => {
|
|
244
|
+
const { storeQueue, mockCorrectionCallback } = setup();
|
|
245
|
+
const data: NewContentMessage[] = [];
|
|
246
|
+
storeQueue.push(data, mockCorrectionCallback);
|
|
247
|
+
|
|
248
|
+
const entry = storeQueue.pull();
|
|
249
|
+
expect(entry).toEqual({
|
|
250
|
+
data,
|
|
251
|
+
correctionCallback: mockCorrectionCallback,
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
test("should handle null correction callback", () => {
|
|
256
|
+
const { storeQueue } = setup();
|
|
257
|
+
const data = createMockNewContentMessage("co1");
|
|
258
|
+
|
|
259
|
+
const nullCallback = () => {};
|
|
260
|
+
storeQueue.push(data, nullCallback);
|
|
261
|
+
|
|
262
|
+
const entry = storeQueue.pull();
|
|
263
|
+
expect(entry).toEqual({ data, correctionCallback: nullCallback });
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
test("should handle very large number of entries", () => {
|
|
267
|
+
const { storeQueue, mockCorrectionCallback } = setup();
|
|
268
|
+
const entries = 1000;
|
|
269
|
+
|
|
270
|
+
for (let i = 0; i < entries; i++) {
|
|
271
|
+
const data = createMockNewContentMessage(`co${i}`);
|
|
272
|
+
storeQueue.push(data, mockCorrectionCallback);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
let count = 0;
|
|
276
|
+
while (storeQueue.pull()) {
|
|
277
|
+
count++;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
expect(count).toBe(entries);
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
});
|
|
@@ -11,8 +11,11 @@ import {
|
|
|
11
11
|
setupTestNode,
|
|
12
12
|
waitFor,
|
|
13
13
|
} from "./testUtils.js";
|
|
14
|
+
import { TEST_NODE_CONFIG } from "./testUtils.js";
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
TEST_NODE_CONFIG.withAsyncPeers = true;
|
|
17
|
+
|
|
18
|
+
let jazzCloud: ReturnType<typeof setupTestNode>;
|
|
16
19
|
|
|
17
20
|
beforeEach(async () => {
|
|
18
21
|
SyncMessagesLog.clear();
|
|
@@ -3,7 +3,7 @@ import { expectAccount } from "../coValues/account.js";
|
|
|
3
3
|
import { WasmCrypto } from "../crypto/WasmCrypto.js";
|
|
4
4
|
import { LocalNode } from "../localNode.js";
|
|
5
5
|
import { connectedPeers } from "../streamUtils.js";
|
|
6
|
-
import {
|
|
6
|
+
import { createAsyncStorage } from "./testStorage.js";
|
|
7
7
|
|
|
8
8
|
const Crypto = await WasmCrypto.create();
|
|
9
9
|
|
|
@@ -89,23 +89,22 @@ test("throws an error if the user tried to create an invite from an account", as
|
|
|
89
89
|
});
|
|
90
90
|
|
|
91
91
|
test("wait for storage sync before resolving withNewlyCreatedAccount", async () => {
|
|
92
|
-
const
|
|
93
|
-
|
|
92
|
+
const storage = await createAsyncStorage({
|
|
93
|
+
nodeName: "account-node",
|
|
94
|
+
storageName: "storage",
|
|
94
95
|
});
|
|
95
96
|
|
|
96
|
-
const {
|
|
97
|
+
const { accountID, node } = await LocalNode.withNewlyCreatedAccount({
|
|
97
98
|
creationProps: { name: "Hermes Puggington" },
|
|
98
99
|
crypto: Crypto,
|
|
99
|
-
|
|
100
|
+
storage,
|
|
100
101
|
});
|
|
101
102
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
expect(account.isAvailable()).toBe(true);
|
|
103
|
+
expect(storage.getKnownState(accountID).header).toBe(true);
|
|
105
104
|
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
)
|
|
105
|
+
const profileId = expectAccount(
|
|
106
|
+
node.getCoValue(accountID).getCurrentContent(),
|
|
107
|
+
).get("profile")!;
|
|
109
108
|
|
|
110
|
-
expect(
|
|
109
|
+
expect(storage.getKnownState(profileId).header).toBe(true);
|
|
111
110
|
});
|
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, test } from "vitest";
|
|
2
2
|
import { expectStream } from "../coValue.js";
|
|
3
|
-
import { MAX_RECOMMENDED_TX_SIZE } from "../coValueCore/coValueCore.js";
|
|
4
3
|
import {
|
|
5
4
|
BinaryStreamItem,
|
|
6
5
|
CoStreamItem,
|
|
7
6
|
RawBinaryCoStream,
|
|
8
7
|
RawCoStreamView,
|
|
9
8
|
} from "../coValues/coStream.js";
|
|
9
|
+
import { MAX_RECOMMENDED_TX_SIZE } from "../config.js";
|
|
10
10
|
import { WasmCrypto } from "../crypto/WasmCrypto.js";
|
|
11
11
|
import { SessionID } from "../ids.js";
|
|
12
|
-
import { LocalNode } from "../localNode.js";
|
|
13
12
|
import {
|
|
14
13
|
loadCoValueOrFail,
|
|
15
14
|
nodeWithRandomAgentAndSessionID,
|
|
16
|
-
randomAgentAndSessionID,
|
|
17
15
|
setupTestNode,
|
|
18
16
|
waitFor,
|
|
19
17
|
} from "./testUtils.js";
|