1 |
|
2 |
|
3 | const expect = require('expect');
|
4 | const uuid = require('uuid');
|
5 | const { InvalidSignatureError, SignedObservedRemoveMap, getSigner, generateId } = require('../src');
|
6 | const { generateValue } = require('./lib/values');
|
7 | const NodeRSA = require('node-rsa');
|
8 |
|
9 | const privateKey = new NodeRSA({ b: 512 });
|
10 | const sign = getSigner(privateKey.exportKey('pkcs1-private-pem'));
|
11 | const key = privateKey.exportKey('pkcs1-public-pem');
|
12 |
|
13 | describe('Signed Map', () => {
|
14 | test('Set and delete values', () => {
|
15 | const keyA = uuid.v4();
|
16 | const keyB = uuid.v4();
|
17 | const valueA = generateValue();
|
18 | const valueB = generateValue();
|
19 | const map = new SignedObservedRemoveMap([], { key });
|
20 | expect(map.size).toEqual(0);
|
21 | const id1 = generateId();
|
22 | map.setSigned(keyA, valueA, id1, sign(keyA, valueA, id1));
|
23 | expect(map.has(keyA)).toEqual(true);
|
24 | expect(map.has(keyB)).toEqual(false);
|
25 | expect(map.size).toEqual(1);
|
26 | const id2 = generateId();
|
27 | map.setSigned(keyB, valueB, id2, sign(keyB, valueB, id2));
|
28 | expect(map.has(keyA)).toEqual(true);
|
29 | expect(map.has(keyB)).toEqual(true);
|
30 | expect(map.size).toEqual(2);
|
31 | map.deleteSigned(keyB, id2, sign(keyB, id2));
|
32 | expect(map.has(keyA)).toEqual(true);
|
33 | expect(map.has(keyB)).toEqual(false);
|
34 | expect(map.size).toEqual(1);
|
35 | map.deleteSigned(keyA, id1, sign(keyA, id1));
|
36 | expect(map.has(keyA)).toEqual(false);
|
37 | expect(map.has(keyB)).toEqual(false);
|
38 | expect(map.size).toEqual(0);
|
39 | const id3 = generateId();
|
40 | map.setSigned(keyA, valueA, id3, sign(keyA, valueA, id3));
|
41 | expect(map.has(keyA)).toEqual(true);
|
42 | expect(map.has(keyB)).toEqual(false);
|
43 | expect(map.size).toEqual(1);
|
44 | const id4 = generateId();
|
45 | map.setSigned(keyB, valueB, id4, sign(keyB, valueB, id4));
|
46 | expect(map.has(keyA)).toEqual(true);
|
47 | expect(map.has(keyB)).toEqual(true);
|
48 | expect(map.size).toEqual(2);
|
49 | expect([...map.values()]).toEqual([valueA, valueB]);
|
50 | expect([...map.keys()]).toEqual([keyA, keyB]);
|
51 | expect([...map]).toEqual([[keyA, valueA], [keyB, valueB]]);
|
52 | expect([...map.entries()]).toEqual([[keyA, valueA], [keyB, valueB]]);
|
53 | });
|
54 |
|
55 | test('Throw on invalid signatures', () => {
|
56 | const keyA = uuid.v4();
|
57 | const valueA = generateValue();
|
58 | const map = new SignedObservedRemoveMap([], { key });
|
59 | expect(() => {
|
60 | new SignedObservedRemoveMap([[keyA, valueA, generateId(), '***']], { key });
|
61 | }).toThrowError(InvalidSignatureError);
|
62 | expect(() => {
|
63 | map.setSigned(keyA, valueA, generateId(), '***');
|
64 | }).toThrowError(InvalidSignatureError);
|
65 | const id = generateId();
|
66 | map.setSigned(keyA, valueA, id, sign(keyA, valueA, id));
|
67 | expect(() => {
|
68 | map.deleteSigned(keyA, id, '***');
|
69 | }).toThrowError(InvalidSignatureError);
|
70 | });
|
71 |
|
72 | test('Throw on clear', () => {
|
73 | const map = new SignedObservedRemoveMap([], { key });
|
74 | expect(() => {
|
75 | map.clear();
|
76 | }).toThrow();
|
77 | });
|
78 |
|
79 |
|
80 | test('Throw on invalid synchronization', async () => {
|
81 | const alicePrivateKey = new NodeRSA({ b: 512 });
|
82 | const aliceSign = getSigner(alicePrivateKey.exportKey('pkcs1-private-pem'));
|
83 | const aliceKey = alicePrivateKey.exportKey('pkcs1-public-pem');
|
84 | const bobPrivateKey = new NodeRSA({ b: 512 });
|
85 | const bobSign = getSigner(bobPrivateKey.exportKey('pkcs1-private-pem'));
|
86 | const bobKey = bobPrivateKey.exportKey('pkcs1-public-pem');
|
87 | const keyX = uuid.v4();
|
88 | const keyY = uuid.v4();
|
89 | const valueX = generateValue();
|
90 | const valueY = generateValue();
|
91 | const alice = new SignedObservedRemoveMap([], { key: aliceKey });
|
92 | const bob = new SignedObservedRemoveMap([], { key: bobKey });
|
93 | const id1 = generateId();
|
94 | const bobMessage1 = await new Promise((resolve) => {
|
95 | bob.on('publish', (message) => {
|
96 | resolve(message);
|
97 | });
|
98 | bob.setSigned(keyX, valueX, id1, bobSign(keyX, valueX, id1));
|
99 | });
|
100 | expect(() => {
|
101 | alice.process(bobMessage1);
|
102 | }).toThrowError(InvalidSignatureError);
|
103 | const id2 = generateId();
|
104 | const aliceMessage1 = await new Promise((resolve) => {
|
105 | alice.on('publish', (message) => {
|
106 | resolve(message);
|
107 | });
|
108 | alice.setSigned(keyY, valueY, id2, aliceSign(keyY, valueY, id2));
|
109 | });
|
110 | expect(() => {
|
111 | bob.process(aliceMessage1);
|
112 | }).toThrowError(InvalidSignatureError);
|
113 | const bobMessage2 = await new Promise((resolve) => {
|
114 | bob.on('publish', (message) => {
|
115 | resolve(message);
|
116 | });
|
117 | bob.deleteSigned(keyX, id1, bobSign(keyX, id1));
|
118 | });
|
119 | expect(() => {
|
120 | alice.process(bobMessage2);
|
121 | }).toThrowError(InvalidSignatureError);
|
122 | const aliceMessage2 = await new Promise((resolve) => {
|
123 | alice.on('publish', (message) => {
|
124 | resolve(message);
|
125 | });
|
126 | alice.deleteSigned(keyY, id2, aliceSign(keyY, id2));
|
127 | });
|
128 | expect(() => {
|
129 | bob.process(aliceMessage2);
|
130 | }).toThrowError(InvalidSignatureError);
|
131 | });
|
132 |
|
133 |
|
134 | test('Emit set and delete events', async () => {
|
135 | const keyA = uuid.v4();
|
136 | const keyB = uuid.v4();
|
137 | const valueA = generateValue();
|
138 | const valueB = generateValue();
|
139 | const map = new SignedObservedRemoveMap([], { key });
|
140 | const id1 = generateId();
|
141 | const setAPromise = new Promise((resolve) => {
|
142 | map.once('set', (k, v) => {
|
143 | expect(k).toEqual(keyA);
|
144 | expect(v).toEqual(valueA);
|
145 | resolve();
|
146 | });
|
147 | map.setSigned(keyA, valueA, id1, sign(keyA, valueA, id1));
|
148 | });
|
149 | const id2 = generateId();
|
150 | const setBPromise = new Promise((resolve) => {
|
151 | map.once('set', (k, v) => {
|
152 | expect(k).toEqual(keyB);
|
153 | expect(v).toEqual(valueB);
|
154 | resolve();
|
155 | });
|
156 | map.setSigned(keyB, valueB, id2, sign(keyB, valueB, id2));
|
157 | });
|
158 | await setAPromise;
|
159 | await setBPromise;
|
160 | const deleteAPromise = new Promise((resolve) => {
|
161 | map.once('delete', (k, v) => {
|
162 | expect(k).toEqual(keyA);
|
163 | expect(v).toEqual(valueA);
|
164 | resolve();
|
165 | });
|
166 | map.deleteSigned(keyA, id1, sign(keyA, id1));
|
167 | });
|
168 | const deleteBPromise = new Promise((resolve) => {
|
169 | map.once('delete', (k, v) => {
|
170 | expect(k).toEqual(keyB);
|
171 | expect(v).toEqual(valueB);
|
172 | resolve();
|
173 | });
|
174 | map.deleteSigned(keyB, id2, sign(keyB, id2));
|
175 | });
|
176 | await deleteAPromise;
|
177 | await deleteBPromise;
|
178 | });
|
179 |
|
180 | test('Iterate through values', () => {
|
181 | const keyA = uuid.v4();
|
182 | const keyB = uuid.v4();
|
183 | const keyC = uuid.v4();
|
184 | const valueA = generateValue();
|
185 | const valueB = generateValue();
|
186 | const valueC = generateValue();
|
187 | const idA = generateId();
|
188 | const idB = generateId();
|
189 | const idC = generateId();
|
190 | const map = new SignedObservedRemoveMap([[keyA, valueA, idA, sign(keyA, valueA, idA)], [keyB, valueB, idB, sign(keyB, valueB, idB)], [keyC, valueC, idC, sign(keyC, valueC, idC)]], { key });
|
191 | let i = 0;
|
192 | for (const [k, v] of map) {
|
193 | if (i === 0) {
|
194 | expect(k).toEqual(keyA);
|
195 | expect(v).toEqual(valueA);
|
196 | } else if (i === 1) {
|
197 | expect(k).toEqual(keyB);
|
198 | expect(v).toEqual(valueB);
|
199 | } else if (i === 2) {
|
200 | expect(k).toEqual(keyC);
|
201 | expect(v).toEqual(valueC);
|
202 | }
|
203 | i += 1;
|
204 | }
|
205 | map.forEach((v, k) => {
|
206 | if (k === keyA) {
|
207 | expect(v).toEqual(valueA);
|
208 | } else if (k === keyB) {
|
209 | expect(v).toEqual(valueB);
|
210 | } else if (k === keyC) {
|
211 | expect(v).toEqual(valueC);
|
212 | }
|
213 | });
|
214 | });
|
215 |
|
216 |
|
217 | test('Synchronize maps', async () => {
|
218 | const keyX = uuid.v4();
|
219 | const keyY = uuid.v4();
|
220 | const keyZ = uuid.v4();
|
221 | const valueX = generateValue();
|
222 | const valueY = generateValue();
|
223 | const valueZ = generateValue();
|
224 | const alice = new SignedObservedRemoveMap([], { key });
|
225 | const bob = new SignedObservedRemoveMap([], { key });
|
226 | let aliceAddCount = 0;
|
227 | let bobAddCount = 0;
|
228 | let aliceDeleteCount = 0;
|
229 | let bobDeleteCount = 0;
|
230 | alice.on('set', () => (aliceAddCount += 1));
|
231 | bob.on('set', () => (bobAddCount += 1));
|
232 | alice.on('delete', () => (aliceDeleteCount += 1));
|
233 | bob.on('delete', () => (bobDeleteCount += 1));
|
234 | alice.on('publish', (message) => {
|
235 | bob.process(message);
|
236 | });
|
237 | bob.on('publish', (message) => {
|
238 | alice.process(message);
|
239 | });
|
240 | const id1 = generateId();
|
241 | alice.setSigned(keyX, valueX, id1, sign(keyX, valueX, id1));
|
242 | const id2 = generateId();
|
243 | alice.setSigned(keyY, valueY, id2, sign(keyY, valueY, id2));
|
244 | const id3 = generateId();
|
245 | alice.setSigned(keyZ, valueZ, id3, sign(keyZ, valueZ, id3));
|
246 | while (aliceAddCount !== 3 || bobAddCount !== 3) {
|
247 | await new Promise((resolve) => setTimeout(resolve, 100));
|
248 | }
|
249 | expect(alice.get(keyX)).toEqual(valueX);
|
250 | expect(alice.get(keyY)).toEqual(valueY);
|
251 | expect(alice.get(keyZ)).toEqual(valueZ);
|
252 | expect(bob.get(keyX)).toEqual(valueX);
|
253 | expect(bob.get(keyY)).toEqual(valueY);
|
254 | expect(bob.get(keyZ)).toEqual(valueZ);
|
255 | expect([...alice]).toEqual([[keyX, valueX], [keyY, valueY], [keyZ, valueZ]]);
|
256 | expect([...bob]).toEqual([[keyX, valueX], [keyY, valueY], [keyZ, valueZ]]);
|
257 | bob.deleteSigned(keyX, id1, sign(keyX, id1));
|
258 | bob.deleteSigned(keyY, id2, sign(keyY, id2));
|
259 | bob.deleteSigned(keyZ, id3, sign(keyZ, id3));
|
260 | while (aliceDeleteCount !== 3 || bobDeleteCount !== 3) {
|
261 | await new Promise((resolve) => setTimeout(resolve, 100));
|
262 | }
|
263 | expect(alice.get(keyX)).toBeUndefined();
|
264 | expect(alice.get(keyY)).toBeUndefined();
|
265 | expect(alice.get(keyZ)).toBeUndefined();
|
266 | expect(bob.get(keyX)).toBeUndefined();
|
267 | expect(bob.get(keyY)).toBeUndefined();
|
268 | expect(bob.get(keyZ)).toBeUndefined();
|
269 | expect([...alice]).toEqual([]);
|
270 | expect([...bob]).toEqual([]);
|
271 | });
|
272 |
|
273 | test('Flush deletions', async () => {
|
274 | const keyX = uuid.v4();
|
275 | const keyY = uuid.v4();
|
276 | const keyZ = uuid.v4();
|
277 | const valueX = generateValue();
|
278 | const valueY = generateValue();
|
279 | const valueZ = generateValue();
|
280 | const idX = generateId();
|
281 | const idY = generateId();
|
282 | const idZ = generateId();
|
283 | const map = new SignedObservedRemoveMap([[keyX, valueX, idX, sign(keyX, valueX, idX)], [keyY, valueY, idY, sign(keyY, valueY, idY)], [keyZ, valueZ, idZ, sign(keyZ, valueZ, idZ)]], { maxAge: 100, key });
|
284 | map.deleteSigned(keyX, idX, sign(keyX, idX));
|
285 | map.deleteSigned(keyY, idY, sign(keyY, idY));
|
286 | map.deleteSigned(keyZ, idZ, sign(keyZ, idZ));
|
287 | expect(map.deletions.size).toEqual(3);
|
288 | expect(map.deletionSignatureMap.size).toEqual(3);
|
289 | map.flush();
|
290 | expect(map.deletions.size).toEqual(3);
|
291 | expect(map.deletionSignatureMap.size).toEqual(3);
|
292 | await new Promise((resolve) => setTimeout(resolve, 200));
|
293 | map.flush();
|
294 | expect(map.deletions.size).toEqual(0);
|
295 | expect(map.deletionSignatureMap.size).toEqual(0);
|
296 | });
|
297 |
|
298 |
|
299 | test('Synchronize set and delete events', async () => {
|
300 | const keyX = uuid.v4();
|
301 | const keyY = uuid.v4();
|
302 | const valueX = generateValue();
|
303 | const valueY = generateValue();
|
304 | const alice = new SignedObservedRemoveMap([], { key });
|
305 | const bob = new SignedObservedRemoveMap([], { key });
|
306 | alice.on('publish', (message) => {
|
307 | bob.process(message);
|
308 | });
|
309 | bob.on('publish', (message) => {
|
310 | alice.process(message);
|
311 | });
|
312 | const aliceSetXPromise = new Promise((resolve) => {
|
313 | alice.once('set', (k, v) => {
|
314 | expect(k).toEqual(keyX);
|
315 | expect(v).toEqual(valueX);
|
316 | resolve();
|
317 | });
|
318 | });
|
319 | const aliceDeleteXPromise = new Promise((resolve) => {
|
320 | alice.once('delete', (k, v) => {
|
321 | expect(k).toEqual(keyX);
|
322 | expect(v).toEqual(valueX);
|
323 | resolve();
|
324 | });
|
325 | });
|
326 | const id1 = generateId();
|
327 | bob.setSigned(keyX, valueX, id1, sign(keyX, valueX, id1));
|
328 | await aliceSetXPromise;
|
329 | bob.deleteSigned(keyX, id1, sign(keyX, id1));
|
330 | await aliceDeleteXPromise;
|
331 | const bobSetYPromise = new Promise((resolve) => {
|
332 | bob.once('set', (k, v) => {
|
333 | expect(k).toEqual(keyY);
|
334 | expect(v).toEqual(valueY);
|
335 | resolve();
|
336 | });
|
337 | });
|
338 | const bobDeleteYPromise = new Promise((resolve) => {
|
339 | bob.once('delete', (k, v) => {
|
340 | expect(k).toEqual(keyY);
|
341 | expect(v).toEqual(valueY);
|
342 | resolve();
|
343 | });
|
344 | });
|
345 | const id2 = generateId();
|
346 | alice.setSigned(keyY, valueY, id2, sign(keyY, valueY, id2));
|
347 | await bobSetYPromise;
|
348 | alice.deleteSigned(keyY, id2, sign(keyY, id2));
|
349 | await bobDeleteYPromise;
|
350 | });
|
351 |
|
352 | test('Should not emit events for remote set/delete combos on sync', async () => {
|
353 | const keyX = uuid.v4();
|
354 | const keyY = uuid.v4();
|
355 | const valueX = generateValue();
|
356 | const valueY = generateValue();
|
357 | const alice = new SignedObservedRemoveMap([], { key });
|
358 | const bob = new SignedObservedRemoveMap([], { key });
|
359 | const id1 = generateId();
|
360 | alice.setSigned(keyX, valueX, id1, sign(keyX, valueX, id1));
|
361 | alice.deleteSigned(keyX, id1, sign(keyX, id1));
|
362 | const id2 = generateId();
|
363 | bob.setSigned(keyY, valueY, id2, sign(keyY, valueY, id2));
|
364 | bob.deleteSigned(keyY, id2, sign(keyY, id2));
|
365 | await new Promise((resolve) => setTimeout(resolve, 250));
|
366 | const bobPromise = new Promise((resolve, reject) => {
|
367 | bob.once('set', () => {
|
368 | reject(new Error('Bob should not receive set event'));
|
369 | });
|
370 | bob.once('delete', () => {
|
371 | reject(new Error('Bob should not receive delete event'));
|
372 | });
|
373 | setTimeout(resolve, 500);
|
374 | });
|
375 | const alicePromise = new Promise((resolve, reject) => {
|
376 | alice.once('set', () => {
|
377 | reject(new Error('Alice should not receive set event'));
|
378 | });
|
379 | alice.once('delete', () => {
|
380 | reject(new Error('Alice should not receive delete event'));
|
381 | });
|
382 | setTimeout(resolve, 500);
|
383 | });
|
384 | alice.on('publish', (message) => {
|
385 | bob.process(message);
|
386 | });
|
387 | bob.on('publish', (message) => {
|
388 | alice.process(message);
|
389 | });
|
390 | alice.sync();
|
391 | bob.sync();
|
392 | await bobPromise;
|
393 | await alicePromise;
|
394 | expect(alice.get(keyX)).toBeUndefined();
|
395 | expect(alice.get(keyY)).toBeUndefined();
|
396 | expect(bob.get(keyX)).toBeUndefined();
|
397 | expect(bob.get(keyY)).toBeUndefined();
|
398 | });
|
399 |
|
400 | test('Synchronize mixed maps using sync', async () => {
|
401 | let id;
|
402 | const keyA = uuid.v4();
|
403 | const keyB = uuid.v4();
|
404 | const keyC = uuid.v4();
|
405 | const keyX = uuid.v4();
|
406 | const keyY = uuid.v4();
|
407 | const keyZ = uuid.v4();
|
408 | const valueA = generateValue();
|
409 | const valueB = generateValue();
|
410 | const valueC = generateValue();
|
411 | const valueX = generateValue();
|
412 | const valueY = generateValue();
|
413 | const valueZ = generateValue();
|
414 | const alice = new SignedObservedRemoveMap([], { key });
|
415 | const bob = new SignedObservedRemoveMap([], { key });
|
416 | id = generateId();
|
417 | alice.setSigned(keyA, valueA, id, sign(keyA, valueA, id));
|
418 | id = generateId();
|
419 | bob.setSigned(keyX, valueX, id, sign(keyX, valueX, id));
|
420 | id = generateId();
|
421 | alice.setSigned(keyB, valueB, id, sign(keyB, valueB, id));
|
422 | id = generateId();
|
423 | bob.setSigned(keyY, valueY, id, sign(keyY, valueY, id));
|
424 | id = generateId();
|
425 | alice.setSigned(keyC, valueC, id, sign(keyC, valueC, id));
|
426 | id = generateId();
|
427 | bob.setSigned(keyZ, valueZ, id, sign(keyZ, valueZ, id));
|
428 | let aliceAddCount = 0;
|
429 | let bobAddCount = 0;
|
430 | let aliceDeleteCount = 0;
|
431 | let bobDeleteCount = 0;
|
432 | await new Promise((resolve) => setTimeout(resolve, 100));
|
433 | expect([...alice]).toEqual([[keyA, valueA], [keyB, valueB], [keyC, valueC]]);
|
434 | expect([...bob]).toEqual([[keyX, valueX], [keyY, valueY], [keyZ, valueZ]]);
|
435 | alice.on('set', () => (aliceAddCount += 1));
|
436 | bob.on('set', () => (bobAddCount += 1));
|
437 | alice.on('delete', () => (aliceDeleteCount += 1));
|
438 | bob.on('delete', () => (bobDeleteCount += 1));
|
439 | alice.on('publish', (message) => {
|
440 | bob.process(message);
|
441 | });
|
442 | bob.on('publish', (message) => {
|
443 | alice.process(message);
|
444 | });
|
445 | alice.sync();
|
446 | bob.sync();
|
447 | while (aliceAddCount !== 3 || bobAddCount !== 3) {
|
448 | await new Promise((resolve) => setTimeout(resolve, 20));
|
449 | }
|
450 | expect([...alice]).toEqual(expect.arrayContaining([[keyA, valueA], [keyX, valueX], [keyB, valueB], [keyY, valueY], [keyC, valueC], [keyZ, valueZ]]));
|
451 | expect([...bob]).toEqual(expect.arrayContaining([[keyA, valueA], [keyX, valueX], [keyB, valueB], [keyY, valueY], [keyC, valueC], [keyZ, valueZ]]));
|
452 | });
|
453 |
|
454 | test('Key-value pairs should not repeat', async () => {
|
455 | let id;
|
456 | const k = uuid.v4();
|
457 | const value1 = generateValue();
|
458 | const value2 = generateValue();
|
459 | const alice = new SignedObservedRemoveMap([], { key });
|
460 | id = generateId();
|
461 | alice.setSigned(k, value1, id, sign(k, value1, id));
|
462 | id = generateId();
|
463 | alice.setSigned(k, value2, id, sign(k, value2, id));
|
464 | expect([...alice].length).toEqual(1);
|
465 | expect([...alice.entries()].length).toEqual(1);
|
466 | expect([...alice.keys()].length).toEqual(1);
|
467 | expect([...alice.values()].length).toEqual(1);
|
468 | expect([...alice]).toEqual([[k, value2]]);
|
469 | expect([...alice.entries()]).toEqual([[k, value2]]);
|
470 | expect([...alice.keys()]).toEqual([k]);
|
471 | expect([...alice.values()]).toEqual([value2]);
|
472 | expect(alice.get(k)).toEqual(value2);
|
473 | });
|
474 |
|
475 | test('Synchronizes 100 asynchrous maps', async () => {
|
476 | const keyA = uuid.v4();
|
477 | const keyB = uuid.v4();
|
478 | const keyC = uuid.v4();
|
479 | const valueA = generateValue();
|
480 | const valueB = generateValue();
|
481 | const valueC = generateValue();
|
482 | const maps = [];
|
483 | const callbacks = [];
|
484 | const publish = (sourceId:number, message:Buffer) => {
|
485 | for (let i = 0; i < callbacks.length; i += 1) {
|
486 | const [targetId, callback] = callbacks[i];
|
487 | if (targetId === sourceId) {
|
488 | continue;
|
489 | }
|
490 | setTimeout(() => callback(message), Math.round(1000 * Math.random()));
|
491 | }
|
492 | };
|
493 | const subscribe = (targetId: number, callback:Function) => {
|
494 | callbacks.push([targetId, callback]);
|
495 | };
|
496 | const getPair = () => {
|
497 | const mapA = maps[Math.floor(Math.random() * maps.length)];
|
498 | let mapB = mapA;
|
499 | while (mapB === mapA) {
|
500 | mapB = maps[Math.floor(Math.random() * maps.length)];
|
501 | }
|
502 | return [mapA, mapB];
|
503 | };
|
504 | for (let i = 0; i < 100; i += 1) {
|
505 | const map = new SignedObservedRemoveMap([], { key });
|
506 | map.on('publish', (message) => publish(i, message));
|
507 | subscribe(i, (message) => map.process(message));
|
508 | maps.push(map);
|
509 | }
|
510 | const [alice, bob] = getPair();
|
511 | let aliceAddCount = 0;
|
512 | let bobAddCount = 0;
|
513 | let aliceDeleteCount = 0;
|
514 | let bobDeleteCount = 0;
|
515 | alice.on('set', () => (aliceAddCount += 1));
|
516 | bob.on('set', () => (bobAddCount += 1));
|
517 | alice.on('delete', () => (aliceDeleteCount += 1));
|
518 | bob.on('delete', () => (bobDeleteCount += 1));
|
519 | const id1 = generateId();
|
520 | alice.setSigned(keyA, valueA, id1, sign(keyA, valueA, id1));
|
521 | const id2 = generateId();
|
522 | bob.setSigned(keyB, valueB, id2, sign(keyB, valueB, id2));
|
523 | const id3 = generateId();
|
524 | alice.setSigned(keyC, valueC, id3, sign(keyC, valueC, id3));
|
525 | while (aliceAddCount !== 3 || bobAddCount !== 3) {
|
526 | await new Promise((resolve) => setTimeout(resolve, 20));
|
527 | }
|
528 | bob.deleteSigned(keyC, id3, sign(keyC, id3));
|
529 | alice.deleteSigned(keyB, id2, sign(keyB, id2));
|
530 | bob.deleteSigned(keyA, id1, sign(keyA, id1));
|
531 | while (aliceDeleteCount !== 3 || bobDeleteCount !== 3) {
|
532 | await new Promise((resolve) => setTimeout(resolve, 20));
|
533 | }
|
534 | expect([...alice]).toEqual([]);
|
535 | expect([...bob]).toEqual([]);
|
536 | });
|
537 | });
|