@graffiti-garden/wrapper-synchronize 0.2.4 → 1.0.3

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/src/index.spec.ts CHANGED
@@ -1,8 +1,16 @@
1
1
  import { it, expect, describe, assert, beforeAll } from "vitest";
2
- import type { GraffitiSession } from "@graffiti-garden/api";
2
+ import {
3
+ GraffitiErrorNotFound,
4
+ type GraffitiSession,
5
+ } from "@graffiti-garden/api";
3
6
  import { GraffitiLocal } from "@graffiti-garden/implementation-local";
4
- import { randomPutObject, randomString } from "@graffiti-garden/api/tests";
7
+ import { randomPostObject, randomString } from "@graffiti-garden/api/tests";
5
8
  import { GraffitiSynchronize } from "./index";
9
+ import {
10
+ graffitiCRUDTests,
11
+ graffitiDiscoverTests,
12
+ graffitiMediaTests,
13
+ } from "@graffiti-garden/api/tests";
6
14
 
7
15
  const useGraffiti = () => new GraffitiSynchronize(new GraffitiLocal());
8
16
  const graffiti = useGraffiti();
@@ -31,14 +39,13 @@ describe.concurrent("synchronizeDiscover", () => {
31
39
  it("get", async () => {
32
40
  const graffiti1 = useGraffiti();
33
41
 
34
- const object = randomPutObject();
42
+ const object = randomPostObject();
35
43
  const channels = object.channels.slice(1);
36
- const putted = await graffiti1.put<{}>(object, session);
44
+ const posted = await graffiti1.post<{}>(object, session);
37
45
 
38
46
  const graffiti2 = useGraffiti();
39
47
  const next = graffiti2.synchronizeDiscover(channels, {}).next();
40
- await new Promise((resolve) => setTimeout(resolve, 100));
41
- const gotten = await graffiti2.get(putted, {}, session);
48
+ const gotten = await graffiti2.get(posted, {}, session);
42
49
 
43
50
  const result = await next;
44
51
  if (result.done || result.value.error) {
@@ -47,22 +54,19 @@ describe.concurrent("synchronizeDiscover", () => {
47
54
  assert(!result.value.tombstone);
48
55
  expect(result.value.object.value).toEqual(object.value);
49
56
  expect(result.value.object.channels).toEqual(channels);
50
- expect(result.value.object.lastModified).toEqual(gotten.lastModified);
51
57
  });
52
58
 
53
- it("put", async () => {
54
- const beforeChannel = randomString();
55
- const afterChannel = randomString();
56
- const sharedChannel = randomString();
59
+ it("delete", async () => {
60
+ const channels = [randomString(), randomString(), randomString()];
57
61
 
58
62
  // Start listening for changes...
59
- const beforeIterator = graffiti.synchronizeDiscover([beforeChannel], {});
63
+ const beforeIterator = graffiti.synchronizeDiscover(channels, {});
60
64
  // Skip the first result
61
65
  beforeIterator.next();
62
66
 
63
67
  const oldValue = { hello: "world" };
64
- const oldChannels = [beforeChannel, sharedChannel];
65
- const putted = await graffiti.put<{}>(
68
+ const oldChannels = [randomString(), ...channels.slice(1)];
69
+ const posted = await graffiti.post<{}>(
66
70
  {
67
71
  value: oldValue,
68
72
  channels: oldChannels,
@@ -70,26 +74,12 @@ describe.concurrent("synchronizeDiscover", () => {
70
74
  session,
71
75
  );
72
76
 
73
- const beforeButAfter = graffiti
74
- .synchronizeDiscover([beforeChannel], {})
75
- .next();
76
- const before = beforeIterator.next();
77
- const after = graffiti.synchronizeDiscover([afterChannel], {}).next();
78
- const shared = graffiti.synchronizeDiscover([sharedChannel], {}).next();
79
-
80
- // Replace the object
81
- const newValue = { goodbye: "world" };
82
- const newChannels = [afterChannel, sharedChannel];
83
- const putted2 = await graffiti.put<{}>(
84
- {
85
- url: putted.url,
86
- value: newValue,
87
- channels: newChannels,
88
- },
89
- session,
90
- );
77
+ const beforeButAfter = graffiti.synchronizeDiscover(channels, {}).next();
78
+ const next = beforeIterator.next();
79
+
80
+ await graffiti.delete(posted, session);
91
81
 
92
- // If you just start synchronizing after the first put,
82
+ // If you just start synchronizing after the first post,
93
83
  // it won't show the deletion because it never saw the object.
94
84
  await expect(
95
85
  // @ts-ignore
@@ -99,197 +89,66 @@ describe.concurrent("synchronizeDiscover", () => {
99
89
  ]),
100
90
  ).rejects.toThrow("Timeout");
101
91
 
102
- const beforeResult = await before;
103
- const afterResult = await after;
104
- const sharedResult = await shared;
105
- assert(!beforeResult.done && !beforeResult.value.error, "Error in before");
106
- assert(!afterResult.done && !afterResult.value.error, "Error in after");
107
- assert(!sharedResult.done && !sharedResult.value.error, "Error in shared");
108
-
109
- assert(beforeResult.value.tombstone, "Before is not tombstone");
110
- assert(!afterResult.value.tombstone, "After is tombstone");
111
- assert(!sharedResult.value.tombstone, "Shared is tombstone");
112
-
113
- expect(beforeResult.value.object.url).toEqual(putted.url);
114
- expect(beforeResult.value.object.lastModified).toEqual(
115
- putted2.lastModified,
116
- );
117
- expect(afterResult.value.object.value).toEqual(newValue);
118
- expect(afterResult.value.object.channels).toEqual([afterChannel]);
119
- expect(sharedResult.value.object.value).toEqual(newValue);
120
- expect(sharedResult.value.object.channels).toEqual([sharedChannel]);
121
- expect(beforeResult.value.object.lastModified).toEqual(
122
- afterResult.value.object.lastModified,
123
- );
124
- expect(sharedResult.value.object.lastModified).toEqual(
125
- afterResult.value.object.lastModified,
126
- );
92
+ const result = await next;
93
+ assert(!result.done && !result.value.error, "Error in before");
94
+ assert(result.value.tombstone, "Before is not tombstone");
95
+ expect(result.value.object.url).toEqual(posted.url);
127
96
  });
128
97
 
129
- it("patch", async () => {
130
- const beforeChannel = randomString();
131
- const afterChannel = randomString();
132
- const sharedChannel = randomString();
133
-
134
- // Start listening for changes...
135
- const beforeIterator = graffiti.synchronizeDiscover([beforeChannel], {});
136
- // Skip the first result
137
- beforeIterator.next();
138
-
139
- const oldValue = { hello: "world" };
140
- const oldChannels = [beforeChannel, sharedChannel];
141
- const putted = await graffiti.put<{}>(
142
- {
143
- value: oldValue,
144
- channels: oldChannels,
145
- },
146
- session,
147
- );
148
-
149
- const beforeButAfter = graffiti
150
- .synchronizeDiscover([beforeChannel], {})
151
- .next();
152
- const before = beforeIterator.next();
153
- const after = graffiti.synchronizeDiscover([afterChannel], {}).next();
154
- const shared = graffiti.synchronizeDiscover([sharedChannel], {}).next();
98
+ it("get deletion in another instance", async () => {
99
+ // Begin discovering and find nothing
100
+ const object = randomPostObject();
101
+ const posted = await graffiti.post<{}>(object, session);
155
102
 
156
- const patched = await graffiti.patch(
157
- {
158
- value: [
159
- {
160
- op: "add",
161
- path: "/something",
162
- value: "new value",
163
- },
164
- ],
165
- channels: [
166
- {
167
- op: "add",
168
- path: "/-",
169
- value: afterChannel,
170
- },
171
- {
172
- op: "remove",
173
- path: `/${oldChannels.indexOf(beforeChannel)}`,
174
- },
175
- ],
176
- },
177
- putted,
178
- session,
179
- );
103
+ // Now sync a get
104
+ const getIterator = graffiti.synchronizeGet(posted, {});
105
+ const next = getIterator.next();
180
106
 
181
- // If you just start synchronizing after the first put,
182
- // it won't show the deletion because it never saw the object.
107
+ // The sync will not pick up on it since it is not
108
+ // actively listening
183
109
  await expect(
184
- // @ts-ignore
185
110
  Promise.race([
186
- beforeButAfter,
187
- new Promise((resolve, reject) => setTimeout(reject, 100, "Timeout")),
111
+ next,
112
+ new Promise((resolve, rejects) => setTimeout(rejects, 100, "Timeout")),
188
113
  ]),
189
114
  ).rejects.toThrow("Timeout");
190
115
 
191
- const beforeResult = await before;
192
- const afterResult = await after;
193
- const sharedResult = await shared;
194
- assert(!beforeResult.done && !beforeResult.value.error, "Error in before");
195
- assert(!afterResult.done && !afterResult.value.error, "Error in after");
196
- assert(!sharedResult.done && !sharedResult.value.error, "Error in shared");
197
-
198
- assert(beforeResult.value.tombstone, "Before is not tombstone");
199
- assert(!afterResult.value.tombstone, "After is tombstone");
200
- assert(!sharedResult.value.tombstone, "Shared is tombstone");
201
-
202
- const newValue = { ...oldValue, something: "new value" };
203
- expect(beforeResult.value.object.url).toEqual(putted.url);
204
- expect(beforeResult.value.object.lastModified).toEqual(
205
- patched.lastModified,
206
- );
207
- expect(afterResult.value.object.value).toEqual(newValue);
208
- expect(afterResult.value.object.channels).toEqual([afterChannel]);
209
- expect(sharedResult.value.object.value).toEqual(newValue);
210
- expect(sharedResult.value.object.channels).toEqual([sharedChannel]);
211
- expect(beforeResult.value.object.lastModified).toEqual(
212
- afterResult.value.object.lastModified,
213
- );
214
- expect(sharedResult.value.object.lastModified).toEqual(
215
- afterResult.value.object.lastModified,
216
- );
217
- });
218
-
219
- it("delete", async () => {
220
- const channels = [randomString(), randomString(), randomString()];
221
-
222
- // Start listening for changes...
223
- const beforeIterator = graffiti.synchronizeDiscover(channels, {});
224
- // Skip the first result
225
- beforeIterator.next();
116
+ // Delete the object in another graffiti instance
117
+ const graffiti2 = useGraffiti();
118
+ await graffiti2.delete(posted, session);
226
119
 
227
- const oldValue = { hello: "world" };
228
- const oldChannels = [randomString(), ...channels.slice(1)];
229
- const putted = await graffiti.put<{}>(
230
- {
231
- value: oldValue,
232
- channels: oldChannels,
233
- },
234
- session,
120
+ // Call get in the original instance
121
+ await expect(graffiti.get(posted, {})).rejects.toThrow(
122
+ GraffitiErrorNotFound,
235
123
  );
236
124
 
237
- const beforeButAfter = graffiti.synchronizeDiscover(channels, {}).next();
238
- const next = beforeIterator.next();
239
-
240
- const deleted = await graffiti.delete(putted, session);
241
-
242
- // If you just start synchronizing after the first put,
243
- // it won't show the deletion because it never saw the object.
244
- await expect(
245
- // @ts-ignore
246
- Promise.race([
247
- beforeButAfter,
248
- new Promise((resolve, reject) => setTimeout(reject, 100, "Timeout")),
249
- ]),
250
- ).rejects.toThrow("Timeout");
251
-
252
- const result = await next;
253
- assert(!result.done && !result.value.error, "Error in before");
254
- assert(result.value.tombstone, "Before is not tombstone");
255
- expect(result.value.object.url).toEqual(putted.url);
256
- expect(result.value.object.lastModified).toEqual(deleted.lastModified);
125
+ // And then the sync will pick up on it from the continue
126
+ const syncResult = await next;
127
+ assert(!syncResult.done && !syncResult.value.error);
128
+ expect(syncResult.value.tombstone).toBe(true);
129
+ expect(syncResult.value.object.url).toEqual(posted.url);
257
130
  });
258
131
 
259
- it("synchronize happens before putters", async () => {
260
- const object = randomPutObject();
132
+ it("synchronize happens before posters", async () => {
133
+ const object = randomPostObject();
261
134
  const iterator = graffiti.synchronizeDiscover(object.channels, {});
262
135
 
263
136
  for (let i = 0; i < 10; i++) {
264
137
  const next = iterator.next();
265
- const putted = graffiti.put<{}>(object, session);
138
+ const posted = graffiti.post<{}>(object, session);
266
139
 
267
140
  let first: undefined | string = undefined;
268
141
  next.then(() => {
269
142
  if (!first) first = "synchronize";
270
143
  });
271
- putted.then(() => {
272
- if (!first) first = "put";
144
+ posted.then(() => {
145
+ if (!first) first = "post";
273
146
  });
274
- await putted;
147
+ await posted;
275
148
 
276
149
  expect(first).toBe("synchronize");
277
150
 
278
- const patched = graffiti.patch({}, await putted, session);
279
- const next2 = iterator.next();
280
-
281
- let second: undefined | string = undefined;
282
- next2.then(() => {
283
- if (!second) second = "synchronize";
284
- });
285
- patched.then(() => {
286
- if (!second) second = "patch";
287
- });
288
- await patched;
289
-
290
- expect(second).toBe("synchronize");
291
-
292
- const deleted = graffiti.delete(await putted, session);
151
+ const deleted = graffiti.delete(await posted, session);
293
152
  const next3 = iterator.next();
294
153
 
295
154
  let third: undefined | string = undefined;
@@ -327,7 +186,10 @@ describe.concurrent("synchronizeDiscover", () => {
327
186
  hello: "world",
328
187
  };
329
188
  const allowed = [randomString(), session2.actor];
330
- await graffiti.put<{}>({ value, channels: allChannels, allowed }, session1);
189
+ await graffiti.post<{}>(
190
+ { value, channels: allChannels, allowed },
191
+ session1,
192
+ );
331
193
 
332
194
  // Expect no session to time out!
333
195
  await expect(
@@ -377,92 +239,59 @@ describe.concurrent("synchronizeGet", () => {
377
239
  session2 = await useSession2();
378
240
  });
379
241
 
380
- it("replace, delete", async () => {
381
- const object = randomPutObject();
382
- const putted = await graffiti.put<{}>(object, session);
242
+ it("delete", async () => {
243
+ const object = randomPostObject();
244
+ const posted = await graffiti.post<{}>(object, session);
383
245
 
384
- const iterator = graffiti.synchronizeGet(putted, {});
246
+ const iterator = graffiti.synchronizeGet(posted, {});
385
247
  const next = iterator.next();
386
248
 
387
- // Change the object
388
- const newValue = { goodbye: "world" };
389
- const putted2 = await graffiti.put<{}>(
390
- {
391
- url: putted.url,
392
- channels: object.channels,
393
- value: newValue,
394
- },
395
- session,
396
- );
397
-
398
- const result = await next;
399
- assert(!result.done && !result.value.error && !result.value.tombstone);
400
-
401
- expect(result.value.object.value).toEqual(newValue);
402
- expect(result.value.object.actor).toEqual(session.actor);
403
- expect(result.value.object.channels).toEqual([]);
404
- expect(result.value.object.lastModified).toEqual(putted2.lastModified);
405
- expect(result.value.object.allowed).toBeUndefined();
406
-
407
249
  // Delete the object
408
- const deleted = await graffiti.delete(putted2, session);
409
- const result2 = await iterator.next();
250
+ const deleted = await graffiti.delete(posted, session);
251
+ const result2 = await next;
410
252
  assert(!result2.done && !result2.value.error);
411
253
  expect(result2.value.tombstone).toBe(true);
412
- expect(result2.value.object.lastModified).toEqual(deleted.lastModified);
413
-
414
- // Put something else
415
- await graffiti.put<{}>(randomPutObject(), session);
416
- await expect(
417
- // @ts-ignore - otherwise you might get
418
- // "Type instantiation is excessively deep
419
- // and possibly infinite."
420
- Promise.race([
421
- iterator.next(),
422
- new Promise((resolve, reject) => setTimeout(reject, 100, "Timeout")),
423
- ]),
424
- ).rejects.toThrow("Timeout");
254
+ expect(result2.value.object.url).toEqual(posted.url);
425
255
  });
426
256
 
427
- it("not allowed", async () => {
428
- const object = randomPutObject();
429
- const putted = await graffiti.put<{}>(object, session1);
257
+ it("delete in different instance and discover", async () => {
258
+ // Begin discovering and find nothing
259
+ const object = randomPostObject();
260
+ const discoverIterator = graffiti.discover(object.channels, {});
261
+ const nullDiscoverResult = await discoverIterator.next();
262
+ assert(nullDiscoverResult.done, "discover is not done");
430
263
 
431
- const iterator1 = graffiti.synchronizeGet(putted, {}, session1);
432
- const iterator2 = graffiti.synchronizeGet(putted, {}, session2);
264
+ // Post to the channel
265
+ const posted = await graffiti.post<{}>(object, session);
433
266
 
434
- // Do a get to trigger the synchronize
435
- graffiti.get<{}>(putted, {}, session1);
436
- iterator1.next();
437
- iterator2.next();
267
+ // Now sync a get
268
+ const getIterator = graffiti.synchronizeGet(posted, {});
269
+ const next = getIterator.next();
438
270
 
439
- const next1 = iterator1.next();
440
- const next2 = iterator2.next();
271
+ // Delete the object in another graffiti instance
272
+ const graffiti2 = useGraffiti();
273
+ await graffiti2.delete(posted, session);
441
274
 
442
- const newValue = { goodbye: "world" };
443
- const putted2 = await graffiti.put<{}>(
444
- {
445
- ...putted,
446
- ...object,
447
- allowed: [],
448
- value: newValue,
449
- },
450
- session1,
451
- );
275
+ // The sync will not pick up on it since it is not
276
+ // actively listening
277
+ await expect(
278
+ Promise.race([
279
+ next,
280
+ new Promise((resolve, rejects) => setTimeout(rejects, 100, "Timeout")),
281
+ ]),
282
+ ).rejects.toThrow("Timeout");
452
283
 
453
- const result1 = await next1;
454
- const result2 = await next2;
455
- assert(!result1.done && !result1.value.error);
456
- assert(!result2.done && !result2.value.error);
457
- assert(!result1.value.tombstone);
458
- assert(result2.value.tombstone);
459
-
460
- expect(result1.value.object.value).toEqual(newValue);
461
- expect(result1.value.object.actor).toEqual(session1.actor);
462
- expect(result1.value.object.channels).toEqual(object.channels);
463
- expect(result1.value.object.lastModified).toEqual(putted2.lastModified);
464
- expect(result2.value.object.url).toEqual(putted.url);
465
- expect(result2.value.object.lastModified).toEqual(putted2.lastModified);
284
+ // However, the continue will pick up on it
285
+ const continueResult = await nullDiscoverResult.value.continue().next();
286
+ assert(!continueResult.done && !continueResult.value.error);
287
+ expect(continueResult.value.tombstone).toBe(true);
288
+ expect(continueResult.value.object.url).toEqual(posted.url);
289
+
290
+ // And then the sync will pick up on it from the continue
291
+ const syncResult = await next;
292
+ assert(!syncResult.done && !syncResult.value.error);
293
+ expect(syncResult.value.tombstone).toBe(true);
294
+ expect(syncResult.value.object.url).toEqual(posted.url);
466
295
  });
467
296
  });
468
297
 
@@ -478,8 +307,8 @@ describe("synchronizeAll", () => {
478
307
  });
479
308
 
480
309
  it("sync from multiple channels and actors", async () => {
481
- const object1 = randomPutObject();
482
- const object2 = randomPutObject();
310
+ const object1 = randomPostObject();
311
+ const object2 = randomPostObject();
483
312
 
484
313
  expect(object1.channels).not.toEqual(object2.channels);
485
314
 
@@ -488,8 +317,8 @@ describe("synchronizeAll", () => {
488
317
  const next1 = iterator.next();
489
318
  const next2 = iterator.next();
490
319
 
491
- await graffiti.put<{}>(object1, session1);
492
- await graffiti.put<{}>(object2, session2);
320
+ await graffiti.post<{}>(object1, session1);
321
+ await graffiti.post<{}>(object2, session2);
493
322
 
494
323
  const result1 = await next1;
495
324
  const result2 = await next2;
@@ -506,13 +335,13 @@ describe("synchronizeAll", () => {
506
335
  omniscient: true,
507
336
  });
508
337
 
509
- const object1 = randomPutObject();
338
+ const object1 = randomPostObject();
510
339
  object1.allowed = [randomString()];
511
340
 
512
341
  const iterator = graffiti.synchronizeAll({});
513
342
  const next = iterator.next();
514
343
 
515
- await graffiti.put<{}>(object1, session1);
344
+ await graffiti.post<{}>(object1, session1);
516
345
 
517
346
  const result = await next;
518
347
  assert(!result.done && !result.value.error && !result.value.tombstone);
@@ -521,3 +350,7 @@ describe("synchronizeAll", () => {
521
350
  expect(result.value.object.allowed).toEqual(object1.allowed);
522
351
  });
523
352
  });
353
+
354
+ graffitiCRUDTests(useGraffiti, useSession1, useSession2);
355
+ graffitiDiscoverTests(useGraffiti, useSession1, useSession2);
356
+ graffitiMediaTests(useGraffiti, useSession1, useSession2);