braid-text 0.2.106 → 0.2.108
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/index.js +39 -36
- package/package.json +12 -2
- package/.claude/settings.local.json +0 -9
- package/test/fuzz-test.js +0 -643
- package/test/test.html +0 -118
- package/test/test.js +0 -321
- package/test/tests.js +0 -2899
package/test/tests.js
DELETED
|
@@ -1,2899 +0,0 @@
|
|
|
1
|
-
// Shared test definitions that work in both Node.js and browser environments
|
|
2
|
-
// This file exports a function that takes a test runner and braid_fetch implementation
|
|
3
|
-
|
|
4
|
-
function defineTests(runTest, braid_fetch) {
|
|
5
|
-
|
|
6
|
-
runTest(
|
|
7
|
-
"test subscribe update with body_text",
|
|
8
|
-
async () => {
|
|
9
|
-
var key = 'test' + Math.random().toString(36).slice(2)
|
|
10
|
-
|
|
11
|
-
var r = await braid_fetch(`/${key}`, {
|
|
12
|
-
method: 'PUT',
|
|
13
|
-
body: 'hi'
|
|
14
|
-
})
|
|
15
|
-
if (!r.ok) return 'got: ' + r.status
|
|
16
|
-
|
|
17
|
-
var r1 = await braid_fetch(`/eval`, {
|
|
18
|
-
method: 'PUT',
|
|
19
|
-
body: `void (async () => {
|
|
20
|
-
var x = await new Promise(done => {
|
|
21
|
-
braid_text.get(new URL('http://localhost:8889/${key}'), {
|
|
22
|
-
subscribe: update => {
|
|
23
|
-
if (update.body_text === 'hi') done(update.body_text)
|
|
24
|
-
}
|
|
25
|
-
})
|
|
26
|
-
})
|
|
27
|
-
res.end(x)
|
|
28
|
-
})()`
|
|
29
|
-
})
|
|
30
|
-
if (!r1.ok) return 'got: ' + r.status
|
|
31
|
-
|
|
32
|
-
return await r1.text()
|
|
33
|
-
},
|
|
34
|
-
'hi'
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
runTest(
|
|
38
|
-
"test braid_text.sync, key to url, where url breaks",
|
|
39
|
-
async () => {
|
|
40
|
-
var key = 'test' + Math.random().toString(36).slice(2)
|
|
41
|
-
|
|
42
|
-
var r = await braid_fetch(`/eval`, {
|
|
43
|
-
method: 'PUT',
|
|
44
|
-
body: `void (async () => {
|
|
45
|
-
var count = 0
|
|
46
|
-
var ac = new AbortController()
|
|
47
|
-
braid_text.sync('/${key}', new URL('http://localhost:8889/have_error'), {
|
|
48
|
-
signal: ac.signal,
|
|
49
|
-
on_pre_connect: () => {
|
|
50
|
-
count++
|
|
51
|
-
if (count === 2) {
|
|
52
|
-
res.end('it reconnected!')
|
|
53
|
-
ac.abort()
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
})
|
|
57
|
-
})()`
|
|
58
|
-
})
|
|
59
|
-
return await r.text()
|
|
60
|
-
|
|
61
|
-
},
|
|
62
|
-
'it reconnected!'
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
runTest(
|
|
66
|
-
"test braid_text.sync, url to key",
|
|
67
|
-
async () => {
|
|
68
|
-
var key_a = 'test-a-' + Math.random().toString(36).slice(2)
|
|
69
|
-
var key_b = 'test-b-' + Math.random().toString(36).slice(2)
|
|
70
|
-
|
|
71
|
-
var r = await braid_fetch(`/${key_a}`, {
|
|
72
|
-
method: 'PUT',
|
|
73
|
-
body: 'hi'
|
|
74
|
-
})
|
|
75
|
-
if (!r.ok) return 'got: ' + r.status
|
|
76
|
-
|
|
77
|
-
var r = await braid_fetch(`/eval`, {
|
|
78
|
-
method: 'PUT',
|
|
79
|
-
body: `void (async () => {
|
|
80
|
-
braid_text.sync(new URL('http://localhost:8889/${key_a}'), '/${key_b}')
|
|
81
|
-
res.end('')
|
|
82
|
-
})()`
|
|
83
|
-
})
|
|
84
|
-
if (!r.ok) return 'got: ' + r.status
|
|
85
|
-
|
|
86
|
-
await new Promise(done => setTimeout(done, 100))
|
|
87
|
-
|
|
88
|
-
var r = await braid_fetch(`/${key_b}`)
|
|
89
|
-
return 'got: ' + (await r.text())
|
|
90
|
-
},
|
|
91
|
-
'got: hi'
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
runTest(
|
|
95
|
-
"test braid_text.sync, url to resource",
|
|
96
|
-
async () => {
|
|
97
|
-
var key_a = 'test-a-' + Math.random().toString(36).slice(2)
|
|
98
|
-
var key_b = 'test-b-' + Math.random().toString(36).slice(2)
|
|
99
|
-
|
|
100
|
-
var r = await braid_fetch(`/${key_a}`, {
|
|
101
|
-
method: 'PUT',
|
|
102
|
-
body: 'hi'
|
|
103
|
-
})
|
|
104
|
-
if (!r.ok) return 'got: ' + r.status
|
|
105
|
-
|
|
106
|
-
var r = await braid_fetch(`/eval`, {
|
|
107
|
-
method: 'PUT',
|
|
108
|
-
body: `void (async () => {
|
|
109
|
-
var resource = await braid_text.get_resource('/${key_b}')
|
|
110
|
-
braid_text.sync(new URL('http://localhost:8889/${key_a}'), resource)
|
|
111
|
-
res.end('')
|
|
112
|
-
})()`
|
|
113
|
-
})
|
|
114
|
-
if (!r.ok) return 'got: ' + r.status
|
|
115
|
-
|
|
116
|
-
await new Promise(done => setTimeout(done, 100))
|
|
117
|
-
|
|
118
|
-
var r = await braid_fetch(`/${key_b}`)
|
|
119
|
-
return 'got: ' + (await r.text())
|
|
120
|
-
},
|
|
121
|
-
'got: hi'
|
|
122
|
-
)
|
|
123
|
-
|
|
124
|
-
runTest(
|
|
125
|
-
"test braid_text.sync, with two urls",
|
|
126
|
-
async () => {
|
|
127
|
-
var key_a = 'test-a-' + Math.random().toString(36).slice(2)
|
|
128
|
-
var key_b = 'test-b-' + Math.random().toString(36).slice(2)
|
|
129
|
-
|
|
130
|
-
var r = await braid_fetch(`/eval`, {
|
|
131
|
-
method: 'PUT',
|
|
132
|
-
body: `void (async () => {
|
|
133
|
-
try {
|
|
134
|
-
await braid_text.sync(new URL('http://localhost:8889/${key_a}'),
|
|
135
|
-
new URL('http://localhost:8889/${key_b}'))
|
|
136
|
-
res.end('no error')
|
|
137
|
-
} catch (e) {
|
|
138
|
-
res.end('' + e)
|
|
139
|
-
}
|
|
140
|
-
})()`
|
|
141
|
-
})
|
|
142
|
-
if (!r.ok) return 'got: ' + r.status
|
|
143
|
-
|
|
144
|
-
return 'got: ' + (await r.text())
|
|
145
|
-
},
|
|
146
|
-
'got: Error: one parameter should be local string key, and the other a remote URL object'
|
|
147
|
-
)
|
|
148
|
-
|
|
149
|
-
runTest(
|
|
150
|
-
"test braid_text.sync, key to url",
|
|
151
|
-
async () => {
|
|
152
|
-
var key_a = 'test-a-' + Math.random().toString(36).slice(2)
|
|
153
|
-
var key_b = 'test-b-' + Math.random().toString(36).slice(2)
|
|
154
|
-
|
|
155
|
-
var r = await braid_fetch(`/${key_a}`, {
|
|
156
|
-
method: 'PUT',
|
|
157
|
-
body: 'hi'
|
|
158
|
-
})
|
|
159
|
-
if (!r.ok) return 'got: ' + r.status
|
|
160
|
-
|
|
161
|
-
var r = await braid_fetch(`/eval`, {
|
|
162
|
-
method: 'PUT',
|
|
163
|
-
body: `void (async () => {
|
|
164
|
-
braid_text.sync('/${key_a}', new URL('http://localhost:8889/${key_b}'))
|
|
165
|
-
res.end('')
|
|
166
|
-
})()`
|
|
167
|
-
})
|
|
168
|
-
if (!r.ok) return 'got: ' + r.status
|
|
169
|
-
|
|
170
|
-
await new Promise(done => setTimeout(done, 100))
|
|
171
|
-
|
|
172
|
-
var r = await braid_fetch(`/${key_b}`)
|
|
173
|
-
return 'got: ' + (await r.text())
|
|
174
|
-
},
|
|
175
|
-
'got: hi'
|
|
176
|
-
)
|
|
177
|
-
|
|
178
|
-
runTest(
|
|
179
|
-
"test braid_text.sync, key to url, when HEAD fails",
|
|
180
|
-
async () => {
|
|
181
|
-
var key_a = 'test-a-' + Math.random().toString(36).slice(2)
|
|
182
|
-
|
|
183
|
-
var r = await braid_fetch(`/${key_a}`, {
|
|
184
|
-
method: 'PUT',
|
|
185
|
-
body: 'hi'
|
|
186
|
-
})
|
|
187
|
-
if (!r.ok) return 'got: ' + r.status
|
|
188
|
-
|
|
189
|
-
var r = await braid_fetch(`/eval`, {
|
|
190
|
-
method: 'PUT',
|
|
191
|
-
body: `void (async () => {
|
|
192
|
-
var count = 0
|
|
193
|
-
var ac = new AbortController()
|
|
194
|
-
braid_text.sync('/${key_a}', new URL('http://localhost:8889/have_error'), {
|
|
195
|
-
signal: ac.signal,
|
|
196
|
-
on_pre_connect: () => {
|
|
197
|
-
count++
|
|
198
|
-
if (count === 2) {
|
|
199
|
-
res.end('it reconnected!')
|
|
200
|
-
ac.abort()
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
})
|
|
204
|
-
})()`
|
|
205
|
-
})
|
|
206
|
-
if (!r.ok) return 'got: ' + r.status
|
|
207
|
-
|
|
208
|
-
return await r.text()
|
|
209
|
-
},
|
|
210
|
-
'it reconnected!'
|
|
211
|
-
)
|
|
212
|
-
|
|
213
|
-
runTest(
|
|
214
|
-
"test when remote doesn't have a fork-point that we think they have",
|
|
215
|
-
async () => {
|
|
216
|
-
var key_a = 'test-a-' + Math.random().toString(36).slice(2)
|
|
217
|
-
var key_b = 'test-b-' + Math.random().toString(36).slice(2)
|
|
218
|
-
var key_c = 'test-c-' + Math.random().toString(36).slice(2)
|
|
219
|
-
|
|
220
|
-
var r = await braid_fetch(`/${key_a}`, {
|
|
221
|
-
method: 'PUT',
|
|
222
|
-
body: 'hi'
|
|
223
|
-
})
|
|
224
|
-
if (!r.ok) return 'got: ' + r.status
|
|
225
|
-
|
|
226
|
-
var r = await braid_fetch(`/eval`, {
|
|
227
|
-
method: 'PUT',
|
|
228
|
-
body: `void (async () => {
|
|
229
|
-
braid_text.sync('/${key_a}', new URL('http://localhost:8889/${key_b}'))
|
|
230
|
-
await new Promise(done => setTimeout(done, 100))
|
|
231
|
-
braid_text.sync('/${key_a}', new URL('http://localhost:8889/${key_c}'))
|
|
232
|
-
await new Promise(done => setTimeout(done, 100))
|
|
233
|
-
res.end('')
|
|
234
|
-
})()`
|
|
235
|
-
})
|
|
236
|
-
if (!r.ok) return 'got: ' + r.status
|
|
237
|
-
|
|
238
|
-
return await (await braid_fetch(`/${key_c}`)).text()
|
|
239
|
-
},
|
|
240
|
-
'hi'
|
|
241
|
-
)
|
|
242
|
-
|
|
243
|
-
runTest(
|
|
244
|
-
"test when we don't have a fork-point with remote, but they do have a shared version",
|
|
245
|
-
async () => {
|
|
246
|
-
var key_a = 'test-a-' + Math.random().toString(36).slice(2)
|
|
247
|
-
var key_b = 'test-b-' + Math.random().toString(36).slice(2)
|
|
248
|
-
|
|
249
|
-
var r = await braid_fetch(`/${key_a}`, {
|
|
250
|
-
method: 'PUT',
|
|
251
|
-
body: 'hi'
|
|
252
|
-
})
|
|
253
|
-
if (!r.ok) return 'got: ' + r.status
|
|
254
|
-
|
|
255
|
-
var r = await braid_fetch(`/eval`, {
|
|
256
|
-
method: 'PUT',
|
|
257
|
-
body: `void (async () => {
|
|
258
|
-
var ac = new AbortController()
|
|
259
|
-
braid_text.get('/${key_a}', {
|
|
260
|
-
signal: ac.signal,
|
|
261
|
-
subscribe: update => braid_text.put('/${key_b}', update)
|
|
262
|
-
})
|
|
263
|
-
await new Promise(done => setTimeout(done, 100))
|
|
264
|
-
ac.abort()
|
|
265
|
-
res.end('')
|
|
266
|
-
})()`
|
|
267
|
-
})
|
|
268
|
-
if (!r.ok) return 'got: ' + r.status
|
|
269
|
-
|
|
270
|
-
var r = await braid_fetch(`/${key_a}`, {
|
|
271
|
-
method: 'PUT',
|
|
272
|
-
body: 'yo'
|
|
273
|
-
})
|
|
274
|
-
if (!r.ok) return 'got: ' + r.status
|
|
275
|
-
|
|
276
|
-
var r = await braid_fetch(`/eval`, {
|
|
277
|
-
method: 'PUT',
|
|
278
|
-
body: `void (async () => {
|
|
279
|
-
var ac = new AbortController()
|
|
280
|
-
braid_text.sync('/${key_a}', new URL('http://localhost:8889/${key_b}'), {signal: ac.signal})
|
|
281
|
-
await new Promise(done => setTimeout(done, 100))
|
|
282
|
-
ac.abort()
|
|
283
|
-
res.end('')
|
|
284
|
-
})()`
|
|
285
|
-
})
|
|
286
|
-
if (!r.ok) return 'got: ' + r.status
|
|
287
|
-
|
|
288
|
-
return await (await braid_fetch(`/${key_b}`)).text()
|
|
289
|
-
},
|
|
290
|
-
'yo'
|
|
291
|
-
)
|
|
292
|
-
|
|
293
|
-
runTest(
|
|
294
|
-
"test braid_text.sync, with two keys",
|
|
295
|
-
async () => {
|
|
296
|
-
var key_a = 'test-a-' + Math.random().toString(36).slice(2)
|
|
297
|
-
var key_b = 'test-b-' + Math.random().toString(36).slice(2)
|
|
298
|
-
|
|
299
|
-
var r = await braid_fetch(`/eval`, {
|
|
300
|
-
method: 'PUT',
|
|
301
|
-
body: `void (async () => {
|
|
302
|
-
try {
|
|
303
|
-
await braid_text.sync('/${key_a}', '/${key_b}')
|
|
304
|
-
res.end('no error')
|
|
305
|
-
} catch (e) {
|
|
306
|
-
res.end('' + e)
|
|
307
|
-
}
|
|
308
|
-
})()`
|
|
309
|
-
})
|
|
310
|
-
if (!r.ok) return 'got: ' + r.status
|
|
311
|
-
|
|
312
|
-
return 'got: ' + (await r.text())
|
|
313
|
-
},
|
|
314
|
-
'got: Error: one parameter should be local string key, and the other a remote URL object'
|
|
315
|
-
)
|
|
316
|
-
|
|
317
|
-
runTest(
|
|
318
|
-
"test putting version with multiple event ids, should have error",
|
|
319
|
-
async () => {
|
|
320
|
-
var key_a = 'test-a-' + Math.random().toString(36).slice(2)
|
|
321
|
-
|
|
322
|
-
var r = await braid_fetch(`/${key_a}`, {
|
|
323
|
-
method: 'PUT',
|
|
324
|
-
version: ['abc-1', 'xyz-2'],
|
|
325
|
-
body: 'hi'
|
|
326
|
-
})
|
|
327
|
-
return '' + (await r.text()).includes('cannot put a version with multiple ids')
|
|
328
|
-
},
|
|
329
|
-
'true'
|
|
330
|
-
)
|
|
331
|
-
|
|
332
|
-
runTest(
|
|
333
|
-
"test braid_text.get(url), with no options",
|
|
334
|
-
async () => {
|
|
335
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
336
|
-
let r = await braid_fetch(`/${key}`, {
|
|
337
|
-
method: 'PUT',
|
|
338
|
-
body: 'hi'
|
|
339
|
-
})
|
|
340
|
-
if (!r.ok) return 'got: ' + r.status
|
|
341
|
-
|
|
342
|
-
var r1 = await braid_fetch(`/eval`, {
|
|
343
|
-
method: 'PUT',
|
|
344
|
-
body: `void (async () => {
|
|
345
|
-
res.end(await braid_text.get(new URL('http://localhost:8889/${key}')))
|
|
346
|
-
})()`
|
|
347
|
-
})
|
|
348
|
-
|
|
349
|
-
return 'got: ' + (await r1.text())
|
|
350
|
-
},
|
|
351
|
-
'got: hi'
|
|
352
|
-
)
|
|
353
|
-
|
|
354
|
-
runTest(
|
|
355
|
-
"test braid_text.get(url), with headers",
|
|
356
|
-
async () => {
|
|
357
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
358
|
-
let r = await braid_fetch(`/${key}`, {
|
|
359
|
-
method: 'PUT',
|
|
360
|
-
version: ['xyz-1'],
|
|
361
|
-
body: 'hi'
|
|
362
|
-
})
|
|
363
|
-
if (!r.ok) return 'got: ' + r.status
|
|
364
|
-
|
|
365
|
-
var r1 = await braid_fetch(`/eval`, {
|
|
366
|
-
method: 'PUT',
|
|
367
|
-
body: `void (async () => {
|
|
368
|
-
res.end(await braid_text.get(new URL('http://localhost:8889/${key}'), {
|
|
369
|
-
headers: {
|
|
370
|
-
version: '"xyz-0"'
|
|
371
|
-
}
|
|
372
|
-
}))
|
|
373
|
-
})()`
|
|
374
|
-
})
|
|
375
|
-
|
|
376
|
-
return 'got: ' + (await r1.text())
|
|
377
|
-
},
|
|
378
|
-
'got: h'
|
|
379
|
-
)
|
|
380
|
-
|
|
381
|
-
runTest(
|
|
382
|
-
"test braid_text.get(url), with parents",
|
|
383
|
-
async () => {
|
|
384
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
385
|
-
let r = await braid_fetch(`/${key}`, {
|
|
386
|
-
method: 'PUT',
|
|
387
|
-
version: ['xyz-1'],
|
|
388
|
-
body: 'hi'
|
|
389
|
-
})
|
|
390
|
-
if (!r.ok) return 'got: ' + r.status
|
|
391
|
-
|
|
392
|
-
var r1 = await braid_fetch(`/eval`, {
|
|
393
|
-
method: 'PUT',
|
|
394
|
-
body: `void (async () => {
|
|
395
|
-
res.end(await braid_text.get(new URL('http://localhost:8889/${key}'), {
|
|
396
|
-
parents: ['xyz-0']
|
|
397
|
-
}))
|
|
398
|
-
})()`
|
|
399
|
-
})
|
|
400
|
-
|
|
401
|
-
return 'got: ' + (await r1.text())
|
|
402
|
-
},
|
|
403
|
-
'got: h'
|
|
404
|
-
)
|
|
405
|
-
|
|
406
|
-
runTest(
|
|
407
|
-
"test braid_text.get(url), with version and peer",
|
|
408
|
-
async () => {
|
|
409
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
410
|
-
let r = await braid_fetch(`/${key}`, {
|
|
411
|
-
method: 'PUT',
|
|
412
|
-
version: ['xyz-1'],
|
|
413
|
-
body: 'hi'
|
|
414
|
-
})
|
|
415
|
-
if (!r.ok) return 'got: ' + r.status
|
|
416
|
-
|
|
417
|
-
var r1 = await braid_fetch(`/eval`, {
|
|
418
|
-
method: 'PUT',
|
|
419
|
-
body: `void (async () => {
|
|
420
|
-
res.end(await braid_text.get(new URL('http://localhost:8889/${key}'), {
|
|
421
|
-
version: ['xyz-0'],
|
|
422
|
-
peer: 'xyz'
|
|
423
|
-
}))
|
|
424
|
-
})()`
|
|
425
|
-
})
|
|
426
|
-
|
|
427
|
-
return 'got: ' + (await r1.text())
|
|
428
|
-
},
|
|
429
|
-
'got: h'
|
|
430
|
-
)
|
|
431
|
-
|
|
432
|
-
runTest(
|
|
433
|
-
"test braid_text.get(url) with subscription",
|
|
434
|
-
async () => {
|
|
435
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
436
|
-
let r = await braid_fetch(`/${key}`, {
|
|
437
|
-
method: 'PUT',
|
|
438
|
-
version: ['xyz-1'],
|
|
439
|
-
body: 'hi'
|
|
440
|
-
})
|
|
441
|
-
if (!r.ok) return 'got: ' + r.status
|
|
442
|
-
|
|
443
|
-
var r1 = await braid_fetch(`/eval`, {
|
|
444
|
-
method: 'PUT',
|
|
445
|
-
body: `void (async () => {
|
|
446
|
-
var url = new URL('http://localhost:8889/${key}')
|
|
447
|
-
var ac = new AbortController()
|
|
448
|
-
var update = await new Promise(done => {
|
|
449
|
-
braid_text.get(url, {
|
|
450
|
-
signal: ac.signal,
|
|
451
|
-
subscribe: update => {
|
|
452
|
-
ac.abort()
|
|
453
|
-
done(update)
|
|
454
|
-
}
|
|
455
|
-
})
|
|
456
|
-
})
|
|
457
|
-
res.end(update.body)
|
|
458
|
-
})()`
|
|
459
|
-
})
|
|
460
|
-
|
|
461
|
-
return 'got: ' + (await r1.text())
|
|
462
|
-
},
|
|
463
|
-
'got: hi'
|
|
464
|
-
)
|
|
465
|
-
|
|
466
|
-
runTest(
|
|
467
|
-
"test braid_text.put(url), with body",
|
|
468
|
-
async () => {
|
|
469
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
470
|
-
|
|
471
|
-
var r = await braid_fetch(`/eval`, {
|
|
472
|
-
method: 'PUT',
|
|
473
|
-
body: `void (async () => {
|
|
474
|
-
var r = await braid_text.put(new URL('http://localhost:8889/${key}'),
|
|
475
|
-
{body: 'yo'})
|
|
476
|
-
res.end('')
|
|
477
|
-
})()`
|
|
478
|
-
})
|
|
479
|
-
if (!r.ok) return 'got: ' + r.status
|
|
480
|
-
|
|
481
|
-
let r1 = await braid_fetch(`/${key}`)
|
|
482
|
-
return 'got: ' + (await r1.text())
|
|
483
|
-
},
|
|
484
|
-
'got: yo'
|
|
485
|
-
)
|
|
486
|
-
|
|
487
|
-
runTest(
|
|
488
|
-
"test braid_text.put(url), with body and headers",
|
|
489
|
-
async () => {
|
|
490
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
491
|
-
|
|
492
|
-
var r = await braid_fetch(`/eval`, {
|
|
493
|
-
method: 'PUT',
|
|
494
|
-
body: `void (async () => {
|
|
495
|
-
var r = await braid_text.put(new URL('http://localhost:8889/${key}'),
|
|
496
|
-
{body: 'yo', headers: {version: '"abc123-1"'}})
|
|
497
|
-
res.end('')
|
|
498
|
-
})()`
|
|
499
|
-
})
|
|
500
|
-
if (!r.ok) return 'got: ' + r.status
|
|
501
|
-
|
|
502
|
-
let r2 = await braid_fetch(`/${key}`)
|
|
503
|
-
return 'got: ' + (await r2.text()) + ' -- version: ' + r2.headers.get('version')
|
|
504
|
-
},
|
|
505
|
-
'got: yo -- version: "abc123-1"'
|
|
506
|
-
)
|
|
507
|
-
|
|
508
|
-
runTest(
|
|
509
|
-
"test braid_text.put(url), with body and version and parents",
|
|
510
|
-
async () => {
|
|
511
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
512
|
-
let r = await braid_fetch(`/${key}`, {
|
|
513
|
-
method: 'PUT',
|
|
514
|
-
body: 'hi',
|
|
515
|
-
version: ['abc-1']
|
|
516
|
-
})
|
|
517
|
-
|
|
518
|
-
var r1 = await braid_fetch(`/eval`, {
|
|
519
|
-
method: 'PUT',
|
|
520
|
-
body: `void (async () => {
|
|
521
|
-
var r = await braid_text.put(new URL('http://localhost:8889/${key}'),
|
|
522
|
-
{body: 'yo', version: ['xyz-3'], parents: ['abc-1']})
|
|
523
|
-
res.end('')
|
|
524
|
-
})()`
|
|
525
|
-
})
|
|
526
|
-
if (!r1.ok) return 'got: ' + r1.status
|
|
527
|
-
|
|
528
|
-
let r2 = await braid_fetch(`/${key}`)
|
|
529
|
-
return 'got: ' + (await r2.text()) + ' -- version: ' + r2.headers.get('version')
|
|
530
|
-
},
|
|
531
|
-
'got: yo -- version: "xyz-3"'
|
|
532
|
-
)
|
|
533
|
-
|
|
534
|
-
runTest(
|
|
535
|
-
"test braid_text.put(url), with peer",
|
|
536
|
-
async () => {
|
|
537
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
538
|
-
|
|
539
|
-
var r1 = await braid_fetch(`/eval`, {
|
|
540
|
-
method: 'PUT',
|
|
541
|
-
body: `void (async () => {
|
|
542
|
-
var r = await braid_text.put(new URL('http://localhost:8889/${key}'),
|
|
543
|
-
{body: 'yo', peer: 'xyz', parents: []})
|
|
544
|
-
res.end('')
|
|
545
|
-
})()`
|
|
546
|
-
})
|
|
547
|
-
if (!r1.ok) return 'got: ' + r1.status
|
|
548
|
-
|
|
549
|
-
let r2 = await braid_fetch(`/${key}`)
|
|
550
|
-
return 'got: ' + (await r2.text()) + ' -- version: ' + r2.headers.get('version')
|
|
551
|
-
},
|
|
552
|
-
'got: yo -- version: "xyz-1"'
|
|
553
|
-
)
|
|
554
|
-
|
|
555
|
-
runTest(
|
|
556
|
-
"test loading a meta file from disk",
|
|
557
|
-
async () => {
|
|
558
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
559
|
-
|
|
560
|
-
var r1 = await braid_fetch(`/eval`, {
|
|
561
|
-
method: 'PUT',
|
|
562
|
-
body: `void (async () => {
|
|
563
|
-
var resource = await braid_text.get_resource('/${key}')
|
|
564
|
-
resource.meta = { test_meta_info: 42 }
|
|
565
|
-
resource.change_meta()
|
|
566
|
-
|
|
567
|
-
await new Promise(done => setTimeout(done, 200))
|
|
568
|
-
|
|
569
|
-
delete braid_text.cache['/${key}']
|
|
570
|
-
|
|
571
|
-
var resource = await braid_text.get_resource('/${key}')
|
|
572
|
-
res.end(JSON.stringify(resource.meta))
|
|
573
|
-
})()`
|
|
574
|
-
})
|
|
575
|
-
|
|
576
|
-
return (await r1.text())
|
|
577
|
-
},
|
|
578
|
-
'{"test_meta_info":42}'
|
|
579
|
-
)
|
|
580
|
-
|
|
581
|
-
runTest(
|
|
582
|
-
"test selection-sharing-prototype PUT and GET",
|
|
583
|
-
async () => {
|
|
584
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
585
|
-
|
|
586
|
-
let time = Date.now()
|
|
587
|
-
|
|
588
|
-
let r = await braid_fetch(`/${key}`, {
|
|
589
|
-
method: 'PUT',
|
|
590
|
-
body: JSON.stringify({
|
|
591
|
-
hello: {
|
|
592
|
-
yo: 'hi',
|
|
593
|
-
time
|
|
594
|
-
}
|
|
595
|
-
}),
|
|
596
|
-
headers: {
|
|
597
|
-
'selection-sharing-prototype': 'true'
|
|
598
|
-
}
|
|
599
|
-
})
|
|
600
|
-
if (!r.ok) return 'got: ' + r.status
|
|
601
|
-
|
|
602
|
-
let r2 = await braid_fetch(`/${key}`, {
|
|
603
|
-
method: 'GET',
|
|
604
|
-
headers: {
|
|
605
|
-
'selection-sharing-prototype': 'true'
|
|
606
|
-
}
|
|
607
|
-
})
|
|
608
|
-
if (!r2.ok) return 'got: ' + r2.status
|
|
609
|
-
|
|
610
|
-
let o = await r2.json()
|
|
611
|
-
return o.hello.time === time ? 'times match' : 'bad'
|
|
612
|
-
},
|
|
613
|
-
'times match'
|
|
614
|
-
)
|
|
615
|
-
|
|
616
|
-
runTest(
|
|
617
|
-
"test selection-sharing-prototype GET/subscribe",
|
|
618
|
-
async () => {
|
|
619
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
620
|
-
|
|
621
|
-
var a = new AbortController()
|
|
622
|
-
let r = await braid_fetch(`/${key}`, {
|
|
623
|
-
method: 'GET',
|
|
624
|
-
signal: a.signal,
|
|
625
|
-
subscribe: true,
|
|
626
|
-
peer: 'abc',
|
|
627
|
-
headers: {
|
|
628
|
-
'selection-sharing-prototype': 'true'
|
|
629
|
-
}
|
|
630
|
-
})
|
|
631
|
-
if (!r.ok) return 'got: ' + r.status
|
|
632
|
-
var p = new Promise(done => {
|
|
633
|
-
r.subscribe(update => {
|
|
634
|
-
var body = update.body_text
|
|
635
|
-
if (body.length > 2) done(body)
|
|
636
|
-
})
|
|
637
|
-
})
|
|
638
|
-
|
|
639
|
-
var time = Date.now()
|
|
640
|
-
|
|
641
|
-
let r2 = await braid_fetch(`/${key}`, {
|
|
642
|
-
method: 'PUT',
|
|
643
|
-
peer: 'xyz',
|
|
644
|
-
body: JSON.stringify({
|
|
645
|
-
hello: {
|
|
646
|
-
yo: 'hi',
|
|
647
|
-
time
|
|
648
|
-
}
|
|
649
|
-
}),
|
|
650
|
-
headers: {
|
|
651
|
-
'selection-sharing-prototype': 'true'
|
|
652
|
-
}
|
|
653
|
-
})
|
|
654
|
-
if (!r2.ok) return 'got: ' + r2.status
|
|
655
|
-
|
|
656
|
-
var ret_val = JSON.parse(await p).hello.time === time ? 'times match' : 'bad'
|
|
657
|
-
|
|
658
|
-
a.abort()
|
|
659
|
-
|
|
660
|
-
return ret_val
|
|
661
|
-
},
|
|
662
|
-
'times match'
|
|
663
|
-
)
|
|
664
|
-
|
|
665
|
-
runTest(
|
|
666
|
-
"test selection-sharing-prototype PUT old cursor",
|
|
667
|
-
async () => {
|
|
668
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
669
|
-
|
|
670
|
-
let time = Date.now()
|
|
671
|
-
|
|
672
|
-
let r = await braid_fetch(`/${key}`, {
|
|
673
|
-
method: 'PUT',
|
|
674
|
-
body: JSON.stringify({
|
|
675
|
-
hello: {
|
|
676
|
-
yo: 'hi',
|
|
677
|
-
time
|
|
678
|
-
}
|
|
679
|
-
}),
|
|
680
|
-
headers: {
|
|
681
|
-
'selection-sharing-prototype': 'true'
|
|
682
|
-
}
|
|
683
|
-
})
|
|
684
|
-
if (!r.ok) return 'got: ' + r.status
|
|
685
|
-
|
|
686
|
-
let r3 = await braid_fetch(`/${key}`, {
|
|
687
|
-
method: 'PUT',
|
|
688
|
-
body: JSON.stringify({
|
|
689
|
-
hello: {
|
|
690
|
-
yo: 'hoop',
|
|
691
|
-
time: time - 5
|
|
692
|
-
}
|
|
693
|
-
}),
|
|
694
|
-
headers: {
|
|
695
|
-
'selection-sharing-prototype': 'true'
|
|
696
|
-
}
|
|
697
|
-
})
|
|
698
|
-
if (!r3.ok) return 'got: ' + r3.status
|
|
699
|
-
|
|
700
|
-
let r2 = await braid_fetch(`/${key}`, {
|
|
701
|
-
method: 'GET',
|
|
702
|
-
headers: {
|
|
703
|
-
'selection-sharing-prototype': 'true'
|
|
704
|
-
}
|
|
705
|
-
})
|
|
706
|
-
if (!r2.ok) return 'got: ' + r2.status
|
|
707
|
-
|
|
708
|
-
let o = await r2.json()
|
|
709
|
-
return o.hello.yo
|
|
710
|
-
},
|
|
711
|
-
'hi'
|
|
712
|
-
)
|
|
713
|
-
|
|
714
|
-
runTest(
|
|
715
|
-
"test selection-sharing-prototype PUT really old cursor",
|
|
716
|
-
async () => {
|
|
717
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
718
|
-
|
|
719
|
-
let time = Date.now() - 1000 * 60 * 60 * 24
|
|
720
|
-
|
|
721
|
-
let r = await braid_fetch(`/${key}`, {
|
|
722
|
-
method: 'PUT',
|
|
723
|
-
body: JSON.stringify({
|
|
724
|
-
hello: {
|
|
725
|
-
yo: 'hi',
|
|
726
|
-
time
|
|
727
|
-
}
|
|
728
|
-
}),
|
|
729
|
-
headers: {
|
|
730
|
-
'selection-sharing-prototype': 'true'
|
|
731
|
-
}
|
|
732
|
-
})
|
|
733
|
-
if (!r.ok) return 'got: ' + r.status
|
|
734
|
-
|
|
735
|
-
let r2 = await braid_fetch(`/${key}`, {
|
|
736
|
-
method: 'GET',
|
|
737
|
-
headers: {
|
|
738
|
-
'selection-sharing-prototype': 'true'
|
|
739
|
-
}
|
|
740
|
-
})
|
|
741
|
-
if (!r2.ok) return 'got: ' + r2.status
|
|
742
|
-
|
|
743
|
-
let o = await r2.json()
|
|
744
|
-
return JSON.stringify(o)
|
|
745
|
-
},
|
|
746
|
-
'{}'
|
|
747
|
-
)
|
|
748
|
-
|
|
749
|
-
runTest(
|
|
750
|
-
"test PUT digest (good)",
|
|
751
|
-
async () => {
|
|
752
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
753
|
-
|
|
754
|
-
async function get_digest(s) {
|
|
755
|
-
var bytes = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(s))
|
|
756
|
-
return `sha-256=:${btoa(String.fromCharCode(...new Uint8Array(bytes)))}:`
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
let r = await braid_fetch(`/${key}`, {
|
|
760
|
-
method: 'PUT',
|
|
761
|
-
version: ['hi-1'],
|
|
762
|
-
parents: [],
|
|
763
|
-
body: 'xx',
|
|
764
|
-
headers: {
|
|
765
|
-
'Repr-Digest': await get_digest('xx')
|
|
766
|
-
}
|
|
767
|
-
})
|
|
768
|
-
if (!r.ok) return 'got: ' + r.status
|
|
769
|
-
return 'ok'
|
|
770
|
-
},
|
|
771
|
-
'ok'
|
|
772
|
-
)
|
|
773
|
-
|
|
774
|
-
runTest(
|
|
775
|
-
"test PUT digest (bad)",
|
|
776
|
-
async () => {
|
|
777
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
778
|
-
|
|
779
|
-
async function get_digest(s) {
|
|
780
|
-
var bytes = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(s))
|
|
781
|
-
return `sha-256=:${btoa(String.fromCharCode(...new Uint8Array(bytes)))}:`
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
let r = await braid_fetch(`/${key}`, {
|
|
785
|
-
method: 'PUT',
|
|
786
|
-
version: ['hi-1'],
|
|
787
|
-
parents: [],
|
|
788
|
-
body: 'xx',
|
|
789
|
-
headers: {
|
|
790
|
-
'Repr-Digest': await get_digest('yy')
|
|
791
|
-
}
|
|
792
|
-
})
|
|
793
|
-
if (!r.ok) return 'got: ' + r.status
|
|
794
|
-
return 'ok'
|
|
795
|
-
},
|
|
796
|
-
'got: 550'
|
|
797
|
-
)
|
|
798
|
-
|
|
799
|
-
runTest(
|
|
800
|
-
"test subscribing and verifying digests [simpleton]",
|
|
801
|
-
async () => {
|
|
802
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
803
|
-
|
|
804
|
-
let r = await braid_fetch(`/${key}`, {
|
|
805
|
-
method: 'PUT',
|
|
806
|
-
version: ['hi-1'],
|
|
807
|
-
parents: [],
|
|
808
|
-
body: 'xx'
|
|
809
|
-
})
|
|
810
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
811
|
-
|
|
812
|
-
var a = new AbortController()
|
|
813
|
-
let r2 = await braid_fetch(`/${key}`, {
|
|
814
|
-
signal: a.signal,
|
|
815
|
-
version: ['hi-0'],
|
|
816
|
-
subscribe: true
|
|
817
|
-
})
|
|
818
|
-
var parts = []
|
|
819
|
-
var p = new Promise(async (done, fail) => {
|
|
820
|
-
r2.subscribe(update => {
|
|
821
|
-
parts.push(update.extra_headers['repr-digest'])
|
|
822
|
-
if (parts.length > 1) {
|
|
823
|
-
done()
|
|
824
|
-
a.abort()
|
|
825
|
-
}
|
|
826
|
-
}, fail)
|
|
827
|
-
})
|
|
828
|
-
|
|
829
|
-
await new Promise(done => setTimeout(done, 300))
|
|
830
|
-
let rr = await braid_fetch(`/${key}`, {
|
|
831
|
-
method: 'PUT',
|
|
832
|
-
version: ['hi-2'],
|
|
833
|
-
parents: ['hi-1'],
|
|
834
|
-
patches: [{unit: "text", range: "[1:1]", content: "Y"}]
|
|
835
|
-
})
|
|
836
|
-
if (!rr.ok) throw 'got: ' + rr.statusCode
|
|
837
|
-
|
|
838
|
-
await p
|
|
839
|
-
return JSON.stringify(parts)
|
|
840
|
-
},
|
|
841
|
-
'["sha-256=:Xd6JaIf2dUybFb/jpEGuSAbfL96UABMR4IvxEGIuC74=:","sha-256=:77cl3INcGEtczN0zK3eOgW/YWYAOm8ub73LkVcF2/rA=:"]'
|
|
842
|
-
)
|
|
843
|
-
|
|
844
|
-
runTest(
|
|
845
|
-
"test subscribing and verifying digests [dt]",
|
|
846
|
-
async () => {
|
|
847
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
848
|
-
|
|
849
|
-
let r = await braid_fetch(`/${key}`, {
|
|
850
|
-
method: 'PUT',
|
|
851
|
-
version: ['hi-1'],
|
|
852
|
-
parents: [],
|
|
853
|
-
body: 'xx'
|
|
854
|
-
})
|
|
855
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
856
|
-
|
|
857
|
-
var a = new AbortController()
|
|
858
|
-
let r2 = await braid_fetch(`/${key}`, {
|
|
859
|
-
signal: a.signal,
|
|
860
|
-
version: ['hi-0'],
|
|
861
|
-
headers: { 'merge-type': 'dt' },
|
|
862
|
-
subscribe: true
|
|
863
|
-
})
|
|
864
|
-
var parts = []
|
|
865
|
-
var p = new Promise(async (done, fail) => {
|
|
866
|
-
r2.subscribe(update => {
|
|
867
|
-
parts.push(update.extra_headers['repr-digest'])
|
|
868
|
-
if (parts.length > 1) {
|
|
869
|
-
done()
|
|
870
|
-
a.abort()
|
|
871
|
-
}
|
|
872
|
-
}, fail)
|
|
873
|
-
})
|
|
874
|
-
|
|
875
|
-
await new Promise(done => setTimeout(done, 300))
|
|
876
|
-
let rr = await braid_fetch(`/${key}`, {
|
|
877
|
-
method: 'PUT',
|
|
878
|
-
version: ['hi-2'],
|
|
879
|
-
parents: ['hi-1'],
|
|
880
|
-
patches: [{unit: "text", range: "[2:2]", content: "Y"}]
|
|
881
|
-
})
|
|
882
|
-
if (!rr.ok) throw 'got: ' + rr.statusCode
|
|
883
|
-
|
|
884
|
-
await p
|
|
885
|
-
return JSON.stringify(parts)
|
|
886
|
-
},
|
|
887
|
-
'["sha-256=:Xd6JaIf2dUybFb/jpEGuSAbfL96UABMR4IvxEGIuC74=:","sha-256=:QknHazou37wCCwv3JXnCoAvXcKszP6xBTxLIiUAETgI=:"]'
|
|
888
|
-
)
|
|
889
|
-
|
|
890
|
-
runTest(
|
|
891
|
-
"test PUTing a version that the server already has",
|
|
892
|
-
async () => {
|
|
893
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
894
|
-
|
|
895
|
-
var r1 = await braid_fetch(`/${key}`, {
|
|
896
|
-
method: 'PUT',
|
|
897
|
-
version: ['hi-0'],
|
|
898
|
-
parents: [],
|
|
899
|
-
body: 'x'
|
|
900
|
-
})
|
|
901
|
-
|
|
902
|
-
var r2 = await braid_fetch(`/${key}`, {
|
|
903
|
-
method: 'PUT',
|
|
904
|
-
version: ['hi-0'],
|
|
905
|
-
parents: [],
|
|
906
|
-
body: 'x'
|
|
907
|
-
})
|
|
908
|
-
|
|
909
|
-
return r1.status + " " + r2.status
|
|
910
|
-
},
|
|
911
|
-
'200 200'
|
|
912
|
-
)
|
|
913
|
-
|
|
914
|
-
runTest(
|
|
915
|
-
"test validate_already_seen_versions with same version",
|
|
916
|
-
async () => {
|
|
917
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
918
|
-
|
|
919
|
-
var r1 = await braid_fetch(`/eval`, {
|
|
920
|
-
method: 'PUT',
|
|
921
|
-
body: `void (async () => {
|
|
922
|
-
var resource = await braid_text.get_resource('/${key}')
|
|
923
|
-
|
|
924
|
-
var {change_count} = await braid_text.put(resource, { peer: "abc", version: ["hi-2"], parents: [], patches: [{unit: "text", range: "[0:0]", content: "XYZ"}], merge_type: "dt" })
|
|
925
|
-
|
|
926
|
-
res.end('' + change_count)
|
|
927
|
-
})()`
|
|
928
|
-
})
|
|
929
|
-
|
|
930
|
-
var r2 = await braid_fetch(`/eval`, {
|
|
931
|
-
method: 'PUT',
|
|
932
|
-
body: `void (async () => {
|
|
933
|
-
var resource = await braid_text.get_resource('/${key}')
|
|
934
|
-
|
|
935
|
-
var {change_count} = await braid_text.put(resource, { peer: "abc", version: ["hi-2"], parents: [], patches: [{unit: "text", range: "[0:0]", content: "XYZ"}], merge_type: "dt", validate_already_seen_versions: true })
|
|
936
|
-
|
|
937
|
-
res.end('' + change_count)
|
|
938
|
-
})()`
|
|
939
|
-
})
|
|
940
|
-
|
|
941
|
-
return (await r1.text()) + " " + (await r2.text())
|
|
942
|
-
},
|
|
943
|
-
'3 3'
|
|
944
|
-
)
|
|
945
|
-
|
|
946
|
-
runTest(
|
|
947
|
-
"test validate_already_seen_versions with modified version",
|
|
948
|
-
async () => {
|
|
949
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
950
|
-
|
|
951
|
-
var r1 = await braid_fetch(`/eval`, {
|
|
952
|
-
method: 'PUT',
|
|
953
|
-
body: `void (async () => {
|
|
954
|
-
var resource = await braid_text.get_resource('/${key}')
|
|
955
|
-
|
|
956
|
-
var {change_count} = await braid_text.put(resource, { peer: "abc", version: ["hi-2"], parents: [], patches: [{unit: "text", range: "[0:0]", content: "XYZ"}], merge_type: "dt" })
|
|
957
|
-
|
|
958
|
-
res.end('' + change_count)
|
|
959
|
-
})()`
|
|
960
|
-
})
|
|
961
|
-
|
|
962
|
-
var r2 = await braid_fetch(`/eval`, {
|
|
963
|
-
method: 'PUT',
|
|
964
|
-
body: `void (async () => {
|
|
965
|
-
var resource = await braid_text.get_resource('/${key}')
|
|
966
|
-
|
|
967
|
-
try {
|
|
968
|
-
var {change_count} = await braid_text.put(resource, { peer: "abc", version: ["hi-2"], parents: [], patches: [{unit: "text", range: "[0:0]", content: "ABC"}], merge_type: "dt", validate_already_seen_versions: true })
|
|
969
|
-
|
|
970
|
-
res.end('' + change_count)
|
|
971
|
-
} catch (e) {
|
|
972
|
-
res.end(e.message)
|
|
973
|
-
}
|
|
974
|
-
})()`
|
|
975
|
-
})
|
|
976
|
-
|
|
977
|
-
return await r2.text()
|
|
978
|
-
},
|
|
979
|
-
'invalid update: different from previous update with same version'
|
|
980
|
-
)
|
|
981
|
-
|
|
982
|
-
runTest(
|
|
983
|
-
"test loading a previously saved resource",
|
|
984
|
-
async () => {
|
|
985
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
986
|
-
|
|
987
|
-
var f1 = await braid_fetch(`/${key}`, {
|
|
988
|
-
method: 'PUT',
|
|
989
|
-
version: ['hi-2'],
|
|
990
|
-
parents: [],
|
|
991
|
-
body: 'abc'
|
|
992
|
-
})
|
|
993
|
-
|
|
994
|
-
var f1 = await braid_fetch(`/eval`, {
|
|
995
|
-
method: 'PUT',
|
|
996
|
-
body: `
|
|
997
|
-
delete braid_text.cache['/${key}']
|
|
998
|
-
res.end()
|
|
999
|
-
`
|
|
1000
|
-
})
|
|
1001
|
-
|
|
1002
|
-
var r = await braid_fetch(`/${key}`)
|
|
1003
|
-
return await r.text()
|
|
1004
|
-
},
|
|
1005
|
-
'abc'
|
|
1006
|
-
)
|
|
1007
|
-
|
|
1008
|
-
runTest(
|
|
1009
|
-
"test non-contigous ids",
|
|
1010
|
-
async () => {
|
|
1011
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
1012
|
-
|
|
1013
|
-
var r = await braid_fetch(`/${key}`, {
|
|
1014
|
-
method: 'PUT',
|
|
1015
|
-
version: ['hi-10'],
|
|
1016
|
-
parents: [],
|
|
1017
|
-
body: 'abc'
|
|
1018
|
-
})
|
|
1019
|
-
|
|
1020
|
-
var r = await braid_fetch(`/${key}`, {
|
|
1021
|
-
method: 'PUT',
|
|
1022
|
-
version: ['hi-20'],
|
|
1023
|
-
parents: ['hi-10'],
|
|
1024
|
-
body: 'ABC'
|
|
1025
|
-
})
|
|
1026
|
-
|
|
1027
|
-
var f1 = await braid_fetch(`/eval`, {
|
|
1028
|
-
method: 'PUT',
|
|
1029
|
-
body: `
|
|
1030
|
-
delete braid_text.cache['/${key}']
|
|
1031
|
-
res.end()
|
|
1032
|
-
`
|
|
1033
|
-
})
|
|
1034
|
-
|
|
1035
|
-
var r = await braid_fetch(`/${key}`)
|
|
1036
|
-
return await r.text()
|
|
1037
|
-
},
|
|
1038
|
-
'ABC'
|
|
1039
|
-
)
|
|
1040
|
-
|
|
1041
|
-
runTest(
|
|
1042
|
-
"test when PUT cache/buffer size fails",
|
|
1043
|
-
async () => {
|
|
1044
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
1045
|
-
|
|
1046
|
-
var f1 = braid_fetch(`/${key}`, {
|
|
1047
|
-
method: 'PUT',
|
|
1048
|
-
version: ['hi-3000000'],
|
|
1049
|
-
parents: ['yo-0'],
|
|
1050
|
-
body: 'A'.repeat(3000000)
|
|
1051
|
-
})
|
|
1052
|
-
|
|
1053
|
-
await new Promise(done => setTimeout(done, 300))
|
|
1054
|
-
|
|
1055
|
-
var f2 = braid_fetch(`/${key}`, {
|
|
1056
|
-
method: 'PUT',
|
|
1057
|
-
version: ['ih-3000000'],
|
|
1058
|
-
parents: ['yo-0'],
|
|
1059
|
-
body: 'B'.repeat(3000000)
|
|
1060
|
-
})
|
|
1061
|
-
|
|
1062
|
-
await new Promise(done => setTimeout(done, 300))
|
|
1063
|
-
|
|
1064
|
-
var r = await braid_fetch(`/${key}`, {
|
|
1065
|
-
method: 'PUT',
|
|
1066
|
-
version: ['yo-0'],
|
|
1067
|
-
parents: [],
|
|
1068
|
-
body: 'x'
|
|
1069
|
-
})
|
|
1070
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1071
|
-
|
|
1072
|
-
return `f1: ${(await f1).status}, f2: ${(await f2).status}`
|
|
1073
|
-
},
|
|
1074
|
-
'f1: 200, f2: 309'
|
|
1075
|
-
)
|
|
1076
|
-
|
|
1077
|
-
runTest(
|
|
1078
|
-
"test multiple patches",
|
|
1079
|
-
async () => {
|
|
1080
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
1081
|
-
|
|
1082
|
-
var r = await braid_fetch(`/${key}`, {
|
|
1083
|
-
method: 'PUT',
|
|
1084
|
-
version: ['hi-0'],
|
|
1085
|
-
parents: [],
|
|
1086
|
-
body: 'A'
|
|
1087
|
-
})
|
|
1088
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1089
|
-
|
|
1090
|
-
var r = await braid_fetch(`/${key}`, {
|
|
1091
|
-
method: 'PUT',
|
|
1092
|
-
version: ['yo-1'],
|
|
1093
|
-
parents: ['hi-0'],
|
|
1094
|
-
patches: [
|
|
1095
|
-
{unit: 'text', range: '[0:0]', content: 'C'},
|
|
1096
|
-
{unit: 'text', range: '[1:1]', content: 'T'}
|
|
1097
|
-
]
|
|
1098
|
-
})
|
|
1099
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1100
|
-
|
|
1101
|
-
var r2 = await braid_fetch(`/${key}`)
|
|
1102
|
-
return await r2.text()
|
|
1103
|
-
},
|
|
1104
|
-
'CAT'
|
|
1105
|
-
)
|
|
1106
|
-
|
|
1107
|
-
runTest(
|
|
1108
|
-
"test PUT after subscribing",
|
|
1109
|
-
async () => {
|
|
1110
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
1111
|
-
|
|
1112
|
-
var p_done
|
|
1113
|
-
var p = new Promise(done => p_done = done)
|
|
1114
|
-
|
|
1115
|
-
var a = new AbortController()
|
|
1116
|
-
var r = await braid_fetch(`/${key}`, {
|
|
1117
|
-
signal: a.signal,
|
|
1118
|
-
subscribe: true
|
|
1119
|
-
})
|
|
1120
|
-
r.subscribe(update => {
|
|
1121
|
-
if (update.version[0] === 'hi-0') {
|
|
1122
|
-
p_done(update.patches[0].content_text)
|
|
1123
|
-
a.abort()
|
|
1124
|
-
}
|
|
1125
|
-
})
|
|
1126
|
-
|
|
1127
|
-
var r = await braid_fetch(`/${key}`, {
|
|
1128
|
-
method: 'PUT',
|
|
1129
|
-
version: ['hi-0'],
|
|
1130
|
-
parents: [],
|
|
1131
|
-
body: 'x'
|
|
1132
|
-
})
|
|
1133
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1134
|
-
|
|
1135
|
-
return await p
|
|
1136
|
-
},
|
|
1137
|
-
'x'
|
|
1138
|
-
)
|
|
1139
|
-
|
|
1140
|
-
runTest(
|
|
1141
|
-
"test put awaits subscriber callbacks",
|
|
1142
|
-
async () => {
|
|
1143
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
1144
|
-
|
|
1145
|
-
var r = await braid_fetch(`/eval`, {
|
|
1146
|
-
method: 'PUT',
|
|
1147
|
-
body: `void (async () => {
|
|
1148
|
-
var order = []
|
|
1149
|
-
|
|
1150
|
-
// Subscribe with an async callback that takes some time
|
|
1151
|
-
braid_text.get('/${key}', {
|
|
1152
|
-
subscribe: async (update) => {
|
|
1153
|
-
if (update.version?.[0]?.startsWith('test-v')) {
|
|
1154
|
-
order.push('subscriber-start')
|
|
1155
|
-
await new Promise(done => setTimeout(done, 50))
|
|
1156
|
-
order.push('subscriber-end')
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1159
|
-
})
|
|
1160
|
-
|
|
1161
|
-
// Wait for subscription to be established
|
|
1162
|
-
await new Promise(done => setTimeout(done, 50))
|
|
1163
|
-
|
|
1164
|
-
// Put should await the subscriber callback
|
|
1165
|
-
await braid_text.put('/${key}', {
|
|
1166
|
-
version: ['test-v-0'],
|
|
1167
|
-
parents: [],
|
|
1168
|
-
body: 'hello'
|
|
1169
|
-
})
|
|
1170
|
-
order.push('put-done')
|
|
1171
|
-
|
|
1172
|
-
// If put properly awaited, order should be: subscriber-start, subscriber-end, put-done
|
|
1173
|
-
// If put didn't await, order would be: subscriber-start, put-done, subscriber-end
|
|
1174
|
-
res.end(order.join(','))
|
|
1175
|
-
})()`
|
|
1176
|
-
})
|
|
1177
|
-
if (!r.ok) return 'eval failed: ' + r.status
|
|
1178
|
-
|
|
1179
|
-
return await r.text()
|
|
1180
|
-
},
|
|
1181
|
-
'subscriber-start,subscriber-end,put-done'
|
|
1182
|
-
)
|
|
1183
|
-
|
|
1184
|
-
runTest(
|
|
1185
|
-
"test out-of-order PUTs",
|
|
1186
|
-
async () => {
|
|
1187
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
1188
|
-
|
|
1189
|
-
var f = braid_fetch(`/${key}`, {
|
|
1190
|
-
method: 'PUT',
|
|
1191
|
-
version: ['hi-1'],
|
|
1192
|
-
parents: ['hi-0'],
|
|
1193
|
-
patches: [{unit: 'text', range: '[1:1]', content: 'y'}]
|
|
1194
|
-
})
|
|
1195
|
-
|
|
1196
|
-
await new Promise(done => setTimeout(done, 500))
|
|
1197
|
-
|
|
1198
|
-
var r = await braid_fetch(`/${key}`, {
|
|
1199
|
-
method: 'PUT',
|
|
1200
|
-
version: ['hi-0'],
|
|
1201
|
-
parents: [],
|
|
1202
|
-
body: 'x'
|
|
1203
|
-
})
|
|
1204
|
-
|
|
1205
|
-
if (!r.ok) throw 'got: ' + r.status
|
|
1206
|
-
|
|
1207
|
-
r = await f
|
|
1208
|
-
if (!r.ok) throw 'got: ' + r.status
|
|
1209
|
-
|
|
1210
|
-
var r2 = await braid_fetch(`/${key}`)
|
|
1211
|
-
return await r2.text()
|
|
1212
|
-
},
|
|
1213
|
-
'xy'
|
|
1214
|
-
)
|
|
1215
|
-
|
|
1216
|
-
runTest(
|
|
1217
|
-
"test out-of-order PUTs (trial two)",
|
|
1218
|
-
async () => {
|
|
1219
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
1220
|
-
|
|
1221
|
-
var f = braid_fetch(`/${key}`, {
|
|
1222
|
-
method: 'PUT',
|
|
1223
|
-
version: ['ab-1'],
|
|
1224
|
-
parents: ['hi-0'],
|
|
1225
|
-
patches: [{unit: 'text', range: '[1:1]', content: 'y'}]
|
|
1226
|
-
})
|
|
1227
|
-
|
|
1228
|
-
await new Promise(done => setTimeout(done, 500))
|
|
1229
|
-
|
|
1230
|
-
var r = await braid_fetch(`/${key}`, {
|
|
1231
|
-
method: 'PUT',
|
|
1232
|
-
version: ['hi-1'],
|
|
1233
|
-
parents: [],
|
|
1234
|
-
body: 'xz'
|
|
1235
|
-
})
|
|
1236
|
-
|
|
1237
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1238
|
-
|
|
1239
|
-
r = await f
|
|
1240
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1241
|
-
|
|
1242
|
-
var r2 = await braid_fetch(`/${key}`)
|
|
1243
|
-
return await r2.text()
|
|
1244
|
-
},
|
|
1245
|
-
'xyz'
|
|
1246
|
-
)
|
|
1247
|
-
|
|
1248
|
-
runTest(
|
|
1249
|
-
"test in-order PUTs",
|
|
1250
|
-
async () => {
|
|
1251
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
1252
|
-
|
|
1253
|
-
var r = await braid_fetch(`/${key}`, {
|
|
1254
|
-
method: 'PUT',
|
|
1255
|
-
version: ['hi-0'],
|
|
1256
|
-
parents: [],
|
|
1257
|
-
body: 'x'
|
|
1258
|
-
})
|
|
1259
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1260
|
-
|
|
1261
|
-
var r = await braid_fetch(`/${key}`, {
|
|
1262
|
-
method: 'PUT',
|
|
1263
|
-
version: ['hi-1'],
|
|
1264
|
-
parents: ['hi-0'],
|
|
1265
|
-
patches: [{unit: 'text', range: '[1:1]', content: 'y'}]
|
|
1266
|
-
})
|
|
1267
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1268
|
-
|
|
1269
|
-
var r2 = await braid_fetch(`/${key}`)
|
|
1270
|
-
return await r2.text()
|
|
1271
|
-
},
|
|
1272
|
-
'xy'
|
|
1273
|
-
)
|
|
1274
|
-
|
|
1275
|
-
runTest(
|
|
1276
|
-
"test put with transfer-encoding: dt",
|
|
1277
|
-
async () => {
|
|
1278
|
-
await dt_p
|
|
1279
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
1280
|
-
var doc = new Doc('hi')
|
|
1281
|
-
doc.ins(0, 'xy')
|
|
1282
|
-
|
|
1283
|
-
var bytes = doc.toBytes()
|
|
1284
|
-
|
|
1285
|
-
var r1 = await braid_fetch(`/eval`, {
|
|
1286
|
-
method: 'PUT',
|
|
1287
|
-
body: `void (async () => {
|
|
1288
|
-
var key = '/${key}'
|
|
1289
|
-
|
|
1290
|
-
var {change_count} = await braid_text.put(key, {
|
|
1291
|
-
body: new Uint8Array([${'' + bytes}]),
|
|
1292
|
-
transfer_encoding: "dt"
|
|
1293
|
-
})
|
|
1294
|
-
var {body, version} = await braid_text.get(key, {})
|
|
1295
|
-
|
|
1296
|
-
res.end('' + change_count + " " + body + " " + version)
|
|
1297
|
-
})()`
|
|
1298
|
-
})
|
|
1299
|
-
|
|
1300
|
-
return await r1.text()
|
|
1301
|
-
},
|
|
1302
|
-
'2 xy hi-1'
|
|
1303
|
-
)
|
|
1304
|
-
|
|
1305
|
-
runTest(
|
|
1306
|
-
"test transfer-encoding dt (with parents)",
|
|
1307
|
-
async () => {
|
|
1308
|
-
await dt_p
|
|
1309
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
1310
|
-
var doc = new Doc('hi')
|
|
1311
|
-
doc.ins(0, 'x')
|
|
1312
|
-
|
|
1313
|
-
let r = await braid_fetch(`/${key}`, {
|
|
1314
|
-
method: 'PUT',
|
|
1315
|
-
version: ['hi-1'],
|
|
1316
|
-
parents: [],
|
|
1317
|
-
body: 'xy'
|
|
1318
|
-
})
|
|
1319
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1320
|
-
|
|
1321
|
-
let r2 = await braid_fetch(`/${key}`, {
|
|
1322
|
-
parents: ['hi-0'],
|
|
1323
|
-
headers: {
|
|
1324
|
-
'Accept-Transfer-Encoding': 'dt'
|
|
1325
|
-
}
|
|
1326
|
-
})
|
|
1327
|
-
|
|
1328
|
-
doc.mergeBytes([...new Uint8Array(await r2.arrayBuffer())])
|
|
1329
|
-
var text = doc.get()
|
|
1330
|
-
doc.free()
|
|
1331
|
-
|
|
1332
|
-
return r2.headers.get('current-version') + ' ' + r2.headers.get('x-transfer-encoding') + ' ' + text + ' ' + r2.statusText
|
|
1333
|
-
},
|
|
1334
|
-
'"hi-1" dt xy Multiresponse'
|
|
1335
|
-
)
|
|
1336
|
-
|
|
1337
|
-
runTest(
|
|
1338
|
-
"test transfer-encoding dt",
|
|
1339
|
-
async () => {
|
|
1340
|
-
await dt_p
|
|
1341
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
1342
|
-
|
|
1343
|
-
let r = await braid_fetch(`/${key}`, {
|
|
1344
|
-
method: 'PUT',
|
|
1345
|
-
version: ['hi-1'],
|
|
1346
|
-
parents: [],
|
|
1347
|
-
body: 'xy'
|
|
1348
|
-
})
|
|
1349
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1350
|
-
|
|
1351
|
-
let r2 = await braid_fetch(`/${key}`, {
|
|
1352
|
-
headers: {
|
|
1353
|
-
'Accept-Transfer-Encoding': 'dt'
|
|
1354
|
-
}
|
|
1355
|
-
})
|
|
1356
|
-
|
|
1357
|
-
var doc = new Doc('yo')
|
|
1358
|
-
doc.mergeBytes([...new Uint8Array(await r2.arrayBuffer())])
|
|
1359
|
-
var text = doc.get()
|
|
1360
|
-
doc.free()
|
|
1361
|
-
|
|
1362
|
-
return r2.headers.get('current-version') + ' ' + r2.headers.get('x-transfer-encoding') + ' ' + text
|
|
1363
|
-
},
|
|
1364
|
-
'"hi-1" dt xy'
|
|
1365
|
-
)
|
|
1366
|
-
|
|
1367
|
-
runTest(
|
|
1368
|
-
"test GETing old version explicitly with transfer-encoding dt",
|
|
1369
|
-
async () => {
|
|
1370
|
-
await dt_p
|
|
1371
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
1372
|
-
|
|
1373
|
-
let r = await braid_fetch(`/${key}`, {
|
|
1374
|
-
method: 'PUT',
|
|
1375
|
-
version: ['hi∑-1'],
|
|
1376
|
-
parents: [],
|
|
1377
|
-
body: 'xy'
|
|
1378
|
-
})
|
|
1379
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1380
|
-
|
|
1381
|
-
let r2 = await braid_fetch(`/${key}`, {
|
|
1382
|
-
version: ['hi∑-0'],
|
|
1383
|
-
headers: {
|
|
1384
|
-
'Accept-Transfer-Encoding': 'dt'
|
|
1385
|
-
}
|
|
1386
|
-
})
|
|
1387
|
-
|
|
1388
|
-
var doc = new Doc('yo')
|
|
1389
|
-
doc.mergeBytes([...new Uint8Array(await r2.arrayBuffer())])
|
|
1390
|
-
var text = doc.get()
|
|
1391
|
-
doc.free()
|
|
1392
|
-
|
|
1393
|
-
return r2.headers.get('current-version') + ' ' + text + ' ' + JSON.parse(r2.headers.get('current-version'))
|
|
1394
|
-
},
|
|
1395
|
-
'"hi\\u2211-1" x hi∑-1'
|
|
1396
|
-
)
|
|
1397
|
-
|
|
1398
|
-
runTest(
|
|
1399
|
-
"test GETing current version explicitly with transfer-encoding dt",
|
|
1400
|
-
async () => {
|
|
1401
|
-
await dt_p
|
|
1402
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
1403
|
-
|
|
1404
|
-
let r = await braid_fetch(`/${key}`, {
|
|
1405
|
-
method: 'PUT',
|
|
1406
|
-
version: ['hi∑-1'],
|
|
1407
|
-
parents: [],
|
|
1408
|
-
body: 'xy'
|
|
1409
|
-
})
|
|
1410
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1411
|
-
|
|
1412
|
-
let r2 = await braid_fetch(`/${key}`, {
|
|
1413
|
-
version: ['hi∑-1'],
|
|
1414
|
-
headers: {
|
|
1415
|
-
'Accept-Transfer-Encoding': 'dt'
|
|
1416
|
-
}
|
|
1417
|
-
})
|
|
1418
|
-
|
|
1419
|
-
var doc = new Doc('yo')
|
|
1420
|
-
doc.mergeBytes([...new Uint8Array(await r2.arrayBuffer())])
|
|
1421
|
-
var text = doc.get()
|
|
1422
|
-
doc.free()
|
|
1423
|
-
|
|
1424
|
-
return r2.headers.get('current-version') + ' ' + text + ' ' + JSON.parse(r2.headers.get('current-version'))
|
|
1425
|
-
},
|
|
1426
|
-
'"hi\\u2211-1" xy hi∑-1'
|
|
1427
|
-
)
|
|
1428
|
-
|
|
1429
|
-
runTest(
|
|
1430
|
-
"test for Current-Version when GETing old version",
|
|
1431
|
-
async () => {
|
|
1432
|
-
await dt_p
|
|
1433
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
1434
|
-
|
|
1435
|
-
let r = await braid_fetch(`/${key}`, {
|
|
1436
|
-
method: 'PUT',
|
|
1437
|
-
version: ['hi∑-1'],
|
|
1438
|
-
parents: [],
|
|
1439
|
-
body: 'xy'
|
|
1440
|
-
})
|
|
1441
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1442
|
-
|
|
1443
|
-
let r2 = await braid_fetch(`/${key}`, {
|
|
1444
|
-
version: ['hi∑-0']
|
|
1445
|
-
})
|
|
1446
|
-
|
|
1447
|
-
var text = await r2.text()
|
|
1448
|
-
|
|
1449
|
-
return r2.headers.get('current-version') + ' ' + r2.headers.get('version') + ' ' + text + ' ' + JSON.parse(r2.headers.get('current-version'))
|
|
1450
|
-
},
|
|
1451
|
-
'"hi\\u2211-1" "hi\\u2211-0" x hi∑-1'
|
|
1452
|
-
)
|
|
1453
|
-
|
|
1454
|
-
runTest(
|
|
1455
|
-
"test HEAD for GET without subscribe",
|
|
1456
|
-
async () => {
|
|
1457
|
-
await dt_p
|
|
1458
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
1459
|
-
|
|
1460
|
-
let r = await braid_fetch(`/${key}`, {
|
|
1461
|
-
method: 'PUT',
|
|
1462
|
-
version: ['hi∑-1'],
|
|
1463
|
-
parents: [],
|
|
1464
|
-
body: 'xy'
|
|
1465
|
-
})
|
|
1466
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1467
|
-
|
|
1468
|
-
let r2 = await braid_fetch(`/${key}`, {
|
|
1469
|
-
method: 'HEAD'
|
|
1470
|
-
})
|
|
1471
|
-
|
|
1472
|
-
var text = await r2.text()
|
|
1473
|
-
|
|
1474
|
-
return r2.headers.get('version') + ' ' + JSON.parse(r2.headers.get('version')) + ` text:[${text}]`
|
|
1475
|
-
},
|
|
1476
|
-
'"hi\\u2211-1" hi∑-1 text:[]'
|
|
1477
|
-
)
|
|
1478
|
-
|
|
1479
|
-
runTest(
|
|
1480
|
-
"test HEAD for GET without subscribe (with transfer-encoding)",
|
|
1481
|
-
async () => {
|
|
1482
|
-
await dt_p
|
|
1483
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
1484
|
-
|
|
1485
|
-
let r = await braid_fetch(`/${key}`, {
|
|
1486
|
-
method: 'PUT',
|
|
1487
|
-
version: ['hi∑-1'],
|
|
1488
|
-
parents: [],
|
|
1489
|
-
body: 'xy'
|
|
1490
|
-
})
|
|
1491
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1492
|
-
|
|
1493
|
-
let r2 = await braid_fetch(`/${key}`, {
|
|
1494
|
-
method: 'HEAD',
|
|
1495
|
-
headers: {
|
|
1496
|
-
'accept-transfer-encoding': 'dt'
|
|
1497
|
-
}
|
|
1498
|
-
})
|
|
1499
|
-
|
|
1500
|
-
var buf = await r2.arrayBuffer()
|
|
1501
|
-
|
|
1502
|
-
return r2.headers.get('current-version') + ' ' + JSON.parse(r2.headers.get('current-version')) + ` buf.byteLength:${buf.byteLength}`
|
|
1503
|
-
},
|
|
1504
|
-
'"hi\\u2211-1" hi∑-1 buf.byteLength:0'
|
|
1505
|
-
)
|
|
1506
|
-
|
|
1507
|
-
runTest(
|
|
1508
|
-
"test accept-encoding updates(dt) (with parents)",
|
|
1509
|
-
async () => {
|
|
1510
|
-
await dt_p
|
|
1511
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
1512
|
-
var doc = new Doc('hi')
|
|
1513
|
-
doc.ins(0, 'x')
|
|
1514
|
-
|
|
1515
|
-
let r = await braid_fetch(`/${key}`, {
|
|
1516
|
-
method: 'PUT',
|
|
1517
|
-
version: ['hi-1'],
|
|
1518
|
-
parents: [],
|
|
1519
|
-
body: 'xy'
|
|
1520
|
-
})
|
|
1521
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1522
|
-
|
|
1523
|
-
var a = new AbortController()
|
|
1524
|
-
let r2 = await braid_fetch(`/${key}`, {
|
|
1525
|
-
signal: a.signal,
|
|
1526
|
-
parents: ['hi-0'],
|
|
1527
|
-
subscribe: true,
|
|
1528
|
-
headers: {
|
|
1529
|
-
'merge-type': 'dt',
|
|
1530
|
-
'X-Accept-Encoding': 'updates(dt)'
|
|
1531
|
-
}
|
|
1532
|
-
})
|
|
1533
|
-
|
|
1534
|
-
return await new Promise(done => {
|
|
1535
|
-
r2.subscribe(u => {
|
|
1536
|
-
doc.mergeBytes(u.body)
|
|
1537
|
-
done(doc.get())
|
|
1538
|
-
doc.free()
|
|
1539
|
-
a.abort()
|
|
1540
|
-
})
|
|
1541
|
-
})
|
|
1542
|
-
},
|
|
1543
|
-
'xy'
|
|
1544
|
-
)
|
|
1545
|
-
|
|
1546
|
-
runTest(
|
|
1547
|
-
"test accept-encoding updates(dt) (with parents which are current version)",
|
|
1548
|
-
async () => {
|
|
1549
|
-
await dt_p
|
|
1550
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
1551
|
-
var doc = new Doc('hi')
|
|
1552
|
-
doc.ins(0, 'xy')
|
|
1553
|
-
|
|
1554
|
-
let r = await braid_fetch(`/${key}`, {
|
|
1555
|
-
method: 'PUT',
|
|
1556
|
-
version: ['hi-1'],
|
|
1557
|
-
parents: [],
|
|
1558
|
-
body: 'xy'
|
|
1559
|
-
})
|
|
1560
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1561
|
-
|
|
1562
|
-
var a = new AbortController()
|
|
1563
|
-
let r2 = await braid_fetch(`/${key}`, {
|
|
1564
|
-
signal: a.signal,
|
|
1565
|
-
parents: ['hi-1'],
|
|
1566
|
-
subscribe: true,
|
|
1567
|
-
headers: {
|
|
1568
|
-
'merge-type': 'dt',
|
|
1569
|
-
'X-Accept-Encoding': 'updates(dt)'
|
|
1570
|
-
}
|
|
1571
|
-
})
|
|
1572
|
-
|
|
1573
|
-
return await new Promise(done => {
|
|
1574
|
-
r2.subscribe(u => {
|
|
1575
|
-
doc.mergeBytes(u.body)
|
|
1576
|
-
done(doc.get())
|
|
1577
|
-
doc.free()
|
|
1578
|
-
a.abort()
|
|
1579
|
-
})
|
|
1580
|
-
})
|
|
1581
|
-
},
|
|
1582
|
-
'xy'
|
|
1583
|
-
)
|
|
1584
|
-
|
|
1585
|
-
runTest(
|
|
1586
|
-
"test accept-encoding updates(dt)",
|
|
1587
|
-
async () => {
|
|
1588
|
-
await dt_p
|
|
1589
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
1590
|
-
|
|
1591
|
-
let r = await braid_fetch(`/${key}`, {
|
|
1592
|
-
method: 'PUT',
|
|
1593
|
-
version: ['hi-1'],
|
|
1594
|
-
parents: [],
|
|
1595
|
-
body: 'xy'
|
|
1596
|
-
})
|
|
1597
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1598
|
-
|
|
1599
|
-
var a = new AbortController()
|
|
1600
|
-
let r2 = await braid_fetch(`/${key}`, {
|
|
1601
|
-
signal: a.signal,
|
|
1602
|
-
subscribe: true,
|
|
1603
|
-
headers: {
|
|
1604
|
-
'merge-type': 'dt',
|
|
1605
|
-
'X-Accept-Encoding': 'updates(dt)'
|
|
1606
|
-
}
|
|
1607
|
-
})
|
|
1608
|
-
|
|
1609
|
-
var doc = new Doc('yo')
|
|
1610
|
-
return await new Promise(done => {
|
|
1611
|
-
r2.subscribe(u => {
|
|
1612
|
-
doc.mergeBytes(u.body)
|
|
1613
|
-
done(doc.get())
|
|
1614
|
-
doc.free()
|
|
1615
|
-
a.abort()
|
|
1616
|
-
})
|
|
1617
|
-
})
|
|
1618
|
-
},
|
|
1619
|
-
'xy'
|
|
1620
|
-
)
|
|
1621
|
-
|
|
1622
|
-
runTest(
|
|
1623
|
-
"test accept-encoding updates(dt), getting non-encoded update",
|
|
1624
|
-
async () => {
|
|
1625
|
-
await dt_p
|
|
1626
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
1627
|
-
|
|
1628
|
-
let r = await braid_fetch(`/${key}`, {
|
|
1629
|
-
method: 'PUT',
|
|
1630
|
-
version: ['hi-1'],
|
|
1631
|
-
parents: [],
|
|
1632
|
-
body: 'xy'
|
|
1633
|
-
})
|
|
1634
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1635
|
-
|
|
1636
|
-
var a = new AbortController()
|
|
1637
|
-
let r2 = await braid_fetch(`/${key}`, {
|
|
1638
|
-
signal: a.signal,
|
|
1639
|
-
subscribe: true,
|
|
1640
|
-
headers: {
|
|
1641
|
-
'merge-type': 'dt',
|
|
1642
|
-
'X-Accept-Encoding': 'updates(dt)'
|
|
1643
|
-
}
|
|
1644
|
-
})
|
|
1645
|
-
|
|
1646
|
-
setTimeout(async () => {
|
|
1647
|
-
await braid_fetch(`/${key}`, {
|
|
1648
|
-
method: 'PUT',
|
|
1649
|
-
version: ['yo-0'],
|
|
1650
|
-
parents: ['hi-1'],
|
|
1651
|
-
patches: [{unit: 'text', range: '[2:2]', content: 'z'}]
|
|
1652
|
-
})
|
|
1653
|
-
}, 200)
|
|
1654
|
-
|
|
1655
|
-
var results = []
|
|
1656
|
-
|
|
1657
|
-
var doc = new Doc('yo')
|
|
1658
|
-
return await new Promise(done => {
|
|
1659
|
-
r2.subscribe(u => {
|
|
1660
|
-
if (!u.status) {
|
|
1661
|
-
doc.mergeBytes(u.body)
|
|
1662
|
-
results.push(doc.get())
|
|
1663
|
-
doc.free()
|
|
1664
|
-
} else {
|
|
1665
|
-
results.push(u.patches[0].content_text)
|
|
1666
|
-
done(results.join(''))
|
|
1667
|
-
a.abort()
|
|
1668
|
-
}
|
|
1669
|
-
})
|
|
1670
|
-
})
|
|
1671
|
-
},
|
|
1672
|
-
'xyz'
|
|
1673
|
-
)
|
|
1674
|
-
|
|
1675
|
-
runTest(
|
|
1676
|
-
"test Version we get from PUTing",
|
|
1677
|
-
async () => {
|
|
1678
|
-
await dt_p
|
|
1679
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
1680
|
-
|
|
1681
|
-
let r = await braid_fetch(`/${key}`, {
|
|
1682
|
-
method: 'PUT',
|
|
1683
|
-
version: ['hi∑-1'],
|
|
1684
|
-
parents: [],
|
|
1685
|
-
body: 'xy'
|
|
1686
|
-
})
|
|
1687
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1688
|
-
|
|
1689
|
-
return r.headers.get('version')
|
|
1690
|
-
},
|
|
1691
|
-
'"hi\\u2211-1"'
|
|
1692
|
-
)
|
|
1693
|
-
|
|
1694
|
-
runTest(
|
|
1695
|
-
"test error code when missing parents",
|
|
1696
|
-
async () => {
|
|
1697
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
1698
|
-
let r = await braid_fetch(`/${key}`, {
|
|
1699
|
-
method: 'PUT',
|
|
1700
|
-
version: ['hi-1'],
|
|
1701
|
-
parents: ['missing-0', 'y😀-0'],
|
|
1702
|
-
body: 'xx'
|
|
1703
|
-
})
|
|
1704
|
-
return r.status + ' ' + r.ok + ' ' + r.statusText + ' ' + r.headers.get('Version')
|
|
1705
|
-
},
|
|
1706
|
-
'309 false Version Unknown Here "missing-0", "y\\ud83d\\ude00-0"'
|
|
1707
|
-
)
|
|
1708
|
-
|
|
1709
|
-
runTest(
|
|
1710
|
-
"test subscribing starting at a version using simpleton",
|
|
1711
|
-
async () => {
|
|
1712
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
1713
|
-
|
|
1714
|
-
let r = await braid_fetch(`/${key}`, {
|
|
1715
|
-
method: 'PUT',
|
|
1716
|
-
version: ['hi-1'],
|
|
1717
|
-
parents: [],
|
|
1718
|
-
body: 'xx'
|
|
1719
|
-
})
|
|
1720
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1721
|
-
|
|
1722
|
-
var a = new AbortController()
|
|
1723
|
-
let r2 = await braid_fetch(`/${key}`, {
|
|
1724
|
-
signal: a.signal,
|
|
1725
|
-
version: ['hi-0'],
|
|
1726
|
-
subscribe: true
|
|
1727
|
-
})
|
|
1728
|
-
return await new Promise(async (done, fail) => {
|
|
1729
|
-
r2.subscribe(update => {
|
|
1730
|
-
done(JSON.stringify(update.parents))
|
|
1731
|
-
a.abort()
|
|
1732
|
-
}, fail)
|
|
1733
|
-
})
|
|
1734
|
-
},
|
|
1735
|
-
JSON.stringify([ "hi-0" ])
|
|
1736
|
-
)
|
|
1737
|
-
|
|
1738
|
-
runTest(
|
|
1739
|
-
"test subscribing starting at a version using dt",
|
|
1740
|
-
async () => {
|
|
1741
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
1742
|
-
|
|
1743
|
-
let r = await braid_fetch(`/${key}`, {
|
|
1744
|
-
method: 'PUT',
|
|
1745
|
-
version: ['hi-1'],
|
|
1746
|
-
parents: [],
|
|
1747
|
-
body: 'xx'
|
|
1748
|
-
})
|
|
1749
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1750
|
-
|
|
1751
|
-
var a = new AbortController()
|
|
1752
|
-
let r2 = await braid_fetch(`/${key}`, {
|
|
1753
|
-
signal: a.signal,
|
|
1754
|
-
version: ['hi-0'],
|
|
1755
|
-
subscribe: true,
|
|
1756
|
-
headers: {
|
|
1757
|
-
'Merge-Type': 'dt'
|
|
1758
|
-
}
|
|
1759
|
-
})
|
|
1760
|
-
return r2.headers.get('merge-type') + ':' + await new Promise(async (done, fail) => {
|
|
1761
|
-
r2.subscribe(update => {
|
|
1762
|
-
done(JSON.stringify(update.parents))
|
|
1763
|
-
a.abort()
|
|
1764
|
-
}, fail)
|
|
1765
|
-
})
|
|
1766
|
-
},
|
|
1767
|
-
'dt:' + JSON.stringify([ "hi-0" ])
|
|
1768
|
-
)
|
|
1769
|
-
|
|
1770
|
-
runTest(
|
|
1771
|
-
"test subscribing starting at the latest version using dt",
|
|
1772
|
-
async () => {
|
|
1773
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
1774
|
-
|
|
1775
|
-
let r = await braid_fetch(`/${key}`, {
|
|
1776
|
-
method: 'PUT',
|
|
1777
|
-
version: ['hi-1'],
|
|
1778
|
-
parents: [],
|
|
1779
|
-
body: 'xx'
|
|
1780
|
-
})
|
|
1781
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1782
|
-
|
|
1783
|
-
var a = new AbortController()
|
|
1784
|
-
let r2 = await braid_fetch(`/${key}`, {
|
|
1785
|
-
signal: a.signal,
|
|
1786
|
-
version: ['hi-1'],
|
|
1787
|
-
subscribe: true,
|
|
1788
|
-
headers: {
|
|
1789
|
-
'Merge-Type': 'dt'
|
|
1790
|
-
}
|
|
1791
|
-
})
|
|
1792
|
-
return await new Promise(async (done, fail) => {
|
|
1793
|
-
r2.subscribe(update => {
|
|
1794
|
-
done('got something')
|
|
1795
|
-
a.abort()
|
|
1796
|
-
}, fail)
|
|
1797
|
-
setTimeout(() => {
|
|
1798
|
-
done('got nothing')
|
|
1799
|
-
a.abort()
|
|
1800
|
-
}, 1500)
|
|
1801
|
-
})
|
|
1802
|
-
},
|
|
1803
|
-
'got nothing'
|
|
1804
|
-
)
|
|
1805
|
-
|
|
1806
|
-
runTest(
|
|
1807
|
-
"test subscribing starting at beginning using dt",
|
|
1808
|
-
async () => {
|
|
1809
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
1810
|
-
|
|
1811
|
-
let r = await braid_fetch(`/${key}`, {
|
|
1812
|
-
method: 'PUT',
|
|
1813
|
-
version: ['hi-1'],
|
|
1814
|
-
parents: [],
|
|
1815
|
-
body: 'xx'
|
|
1816
|
-
})
|
|
1817
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
1818
|
-
|
|
1819
|
-
var a = new AbortController()
|
|
1820
|
-
let r2 = await braid_fetch(`/${key}`, {
|
|
1821
|
-
signal: a.signal,
|
|
1822
|
-
subscribe: true,
|
|
1823
|
-
headers: {
|
|
1824
|
-
'Merge-Type': 'dt'
|
|
1825
|
-
}
|
|
1826
|
-
})
|
|
1827
|
-
return r2.headers.get('merge-type') + ':' + await new Promise(async (done, fail) => {
|
|
1828
|
-
r2.subscribe(update => {
|
|
1829
|
-
if (update.version[0] === 'hi-1') {
|
|
1830
|
-
done('got it!')
|
|
1831
|
-
a.abort()
|
|
1832
|
-
}
|
|
1833
|
-
}, fail)
|
|
1834
|
-
})
|
|
1835
|
-
},
|
|
1836
|
-
'dt:got it!'
|
|
1837
|
-
)
|
|
1838
|
-
|
|
1839
|
-
runTest(
|
|
1840
|
-
"test dt_create_bytes with big agent name",
|
|
1841
|
-
async () => {
|
|
1842
|
-
let x = await (await fetch(`/test.html?dt_create_bytes_big_name`)).json()
|
|
1843
|
-
return JSON.stringify(x)
|
|
1844
|
-
},
|
|
1845
|
-
JSON.stringify({ok: true})
|
|
1846
|
-
)
|
|
1847
|
-
|
|
1848
|
-
runTest(
|
|
1849
|
-
"test dt_create_bytes with many agent names",
|
|
1850
|
-
async () => {
|
|
1851
|
-
let x = await (await fetch(`/test.html?dt_create_bytes_many_names`)).json()
|
|
1852
|
-
return JSON.stringify(x)
|
|
1853
|
-
},
|
|
1854
|
-
JSON.stringify({ok: true})
|
|
1855
|
-
)
|
|
1856
|
-
|
|
1857
|
-
runTest(
|
|
1858
|
-
"test deleting a resource",
|
|
1859
|
-
async () => {
|
|
1860
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
1861
|
-
|
|
1862
|
-
await fetch(`/${key}`, {
|
|
1863
|
-
method: 'PUT',
|
|
1864
|
-
body: 'hi'
|
|
1865
|
-
})
|
|
1866
|
-
|
|
1867
|
-
await fetch(`/${key}`, {method: 'DELETE'})
|
|
1868
|
-
|
|
1869
|
-
let r = await fetch(`/${key}`)
|
|
1870
|
-
|
|
1871
|
-
return await r.text()
|
|
1872
|
-
},
|
|
1873
|
-
''
|
|
1874
|
-
)
|
|
1875
|
-
|
|
1876
|
-
runTest(
|
|
1877
|
-
"test deleting a resource completely removes all traces",
|
|
1878
|
-
async () => {
|
|
1879
|
-
let key = 'test-delete-complete-' + Math.random().toString(36).slice(2)
|
|
1880
|
-
|
|
1881
|
-
// Create a resource with some content
|
|
1882
|
-
// "hello world" is 11 characters, so version should be alice-10 (positions 0-10 inclusive)
|
|
1883
|
-
await braid_fetch(`/${key}`, {
|
|
1884
|
-
method: 'PUT',
|
|
1885
|
-
version: ['alice-10'],
|
|
1886
|
-
parents: [],
|
|
1887
|
-
body: 'hello world'
|
|
1888
|
-
})
|
|
1889
|
-
|
|
1890
|
-
// Verify it exists in cache using eval endpoint
|
|
1891
|
-
let r1 = await braid_fetch(`/eval`, {
|
|
1892
|
-
method: 'PUT',
|
|
1893
|
-
body: `res.end(braid_text.cache['/${key}'] ? 'exists' : 'missing')`
|
|
1894
|
-
})
|
|
1895
|
-
if ((await r1.text()) !== 'exists') return 'Resource not in cache after creation'
|
|
1896
|
-
|
|
1897
|
-
// Delete the resource
|
|
1898
|
-
await braid_fetch(`/${key}`, {method: 'DELETE'})
|
|
1899
|
-
|
|
1900
|
-
// Verify it's removed from cache
|
|
1901
|
-
let r2 = await braid_fetch(`/eval`, {
|
|
1902
|
-
method: 'PUT',
|
|
1903
|
-
body: `res.end(braid_text.cache['/${key}'] ? 'exists' : 'missing')`
|
|
1904
|
-
})
|
|
1905
|
-
if ((await r2.text()) !== 'missing') return 'Resource still in cache after deletion'
|
|
1906
|
-
|
|
1907
|
-
// Verify we can create it again from scratch with same key
|
|
1908
|
-
// "new content" is 11 characters, so version should be bob-10 (positions 0-10 inclusive)
|
|
1909
|
-
await braid_fetch(`/${key}`, {
|
|
1910
|
-
method: 'PUT',
|
|
1911
|
-
version: ['bob-10'],
|
|
1912
|
-
parents: [],
|
|
1913
|
-
body: 'new content'
|
|
1914
|
-
})
|
|
1915
|
-
|
|
1916
|
-
// Get the new resource and verify it's fresh (not the old one)
|
|
1917
|
-
let r = await braid_fetch(`/${key}`)
|
|
1918
|
-
let body = await r.text()
|
|
1919
|
-
|
|
1920
|
-
if (body !== 'new content') return `Expected 'new content', got '${body}'`
|
|
1921
|
-
|
|
1922
|
-
// Verify the version is from scratch (bob-10, not alice-10)
|
|
1923
|
-
let version = r.headers.get('version')
|
|
1924
|
-
if (!version.includes('bob-10')) return `Expected version to include bob-10, got: ${version}`
|
|
1925
|
-
if (version.includes('alice-')) return `Old version alice-10 should not be present, got: ${version}`
|
|
1926
|
-
|
|
1927
|
-
return 'ok'
|
|
1928
|
-
},
|
|
1929
|
-
'ok'
|
|
1930
|
-
)
|
|
1931
|
-
|
|
1932
|
-
runTest(
|
|
1933
|
-
"test braid_text.delete(url)",
|
|
1934
|
-
async () => {
|
|
1935
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
1936
|
-
|
|
1937
|
-
// Create a resource first
|
|
1938
|
-
await braid_fetch(`/${key}`, {
|
|
1939
|
-
method: 'PUT',
|
|
1940
|
-
body: 'hello there'
|
|
1941
|
-
})
|
|
1942
|
-
|
|
1943
|
-
// Verify it exists
|
|
1944
|
-
let r1 = await braid_fetch(`/${key}`)
|
|
1945
|
-
if ((await r1.text()) !== 'hello there') return 'Resource not created properly'
|
|
1946
|
-
|
|
1947
|
-
// Delete using braid_text.delete(url)
|
|
1948
|
-
var r = await braid_fetch(`/eval`, {
|
|
1949
|
-
method: 'PUT',
|
|
1950
|
-
body: `void (async () => {
|
|
1951
|
-
await braid_text.delete(new URL('http://localhost:8889/${key}'))
|
|
1952
|
-
res.end('deleted')
|
|
1953
|
-
})()`
|
|
1954
|
-
})
|
|
1955
|
-
if (!r.ok) return 'delete failed: ' + r.status
|
|
1956
|
-
if ((await r.text()) !== 'deleted') return 'delete did not complete'
|
|
1957
|
-
|
|
1958
|
-
// Verify it's deleted (should be empty)
|
|
1959
|
-
let r2 = await braid_fetch(`/${key}`)
|
|
1960
|
-
return 'got: ' + (await r2.text())
|
|
1961
|
-
},
|
|
1962
|
-
'got: '
|
|
1963
|
-
)
|
|
1964
|
-
|
|
1965
|
-
runTest(
|
|
1966
|
-
"test braid_text.get(url) returns null for 404",
|
|
1967
|
-
async () => {
|
|
1968
|
-
// Use the /404 endpoint that always returns 404
|
|
1969
|
-
var r = await braid_fetch(`/eval`, {
|
|
1970
|
-
method: 'PUT',
|
|
1971
|
-
body: `void (async () => {
|
|
1972
|
-
var result = await braid_text.get(new URL('http://localhost:8889/404'))
|
|
1973
|
-
res.end(result === null ? 'null' : 'not null: ' + result)
|
|
1974
|
-
})()`
|
|
1975
|
-
})
|
|
1976
|
-
return await r.text()
|
|
1977
|
-
},
|
|
1978
|
-
'null'
|
|
1979
|
-
)
|
|
1980
|
-
|
|
1981
|
-
runTest(
|
|
1982
|
-
"test braid_text.sync handles remote not existing yet",
|
|
1983
|
-
async () => {
|
|
1984
|
-
var local_key = 'test-local-' + Math.random().toString(36).slice(2)
|
|
1985
|
-
var remote_key = 'test-remote-' + Math.random().toString(36).slice(2)
|
|
1986
|
-
|
|
1987
|
-
// Start sync between a local key and a remote URL that doesn't exist yet
|
|
1988
|
-
// The sync should wait for local to create something, then push to remote
|
|
1989
|
-
var r = await braid_fetch(`/eval`, {
|
|
1990
|
-
method: 'PUT',
|
|
1991
|
-
body: `void (async () => {
|
|
1992
|
-
var ac = new AbortController()
|
|
1993
|
-
|
|
1994
|
-
// Start sync - remote doesn't exist yet
|
|
1995
|
-
braid_text.sync('/${local_key}', new URL('http://localhost:8889/${remote_key}'), {
|
|
1996
|
-
signal: ac.signal
|
|
1997
|
-
})
|
|
1998
|
-
|
|
1999
|
-
// Wait a bit then put something locally
|
|
2000
|
-
await new Promise(done => setTimeout(done, 100))
|
|
2001
|
-
await braid_text.put('/${local_key}', { body: 'created locally' })
|
|
2002
|
-
|
|
2003
|
-
// Wait for sync to propagate
|
|
2004
|
-
await new Promise(done => setTimeout(done, 200))
|
|
2005
|
-
|
|
2006
|
-
// Stop sync
|
|
2007
|
-
ac.abort()
|
|
2008
|
-
|
|
2009
|
-
res.end('done')
|
|
2010
|
-
})()`
|
|
2011
|
-
})
|
|
2012
|
-
if (!r.ok) return 'eval failed: ' + r.status
|
|
2013
|
-
|
|
2014
|
-
// Check that remote now has the content
|
|
2015
|
-
var r2 = await braid_fetch(`/${remote_key}`)
|
|
2016
|
-
return await r2.text()
|
|
2017
|
-
},
|
|
2018
|
-
'created locally'
|
|
2019
|
-
)
|
|
2020
|
-
|
|
2021
|
-
runTest(
|
|
2022
|
-
"test braid_text.sync on_res callback",
|
|
2023
|
-
async () => {
|
|
2024
|
-
var local_key = 'test-local-' + Math.random().toString(36).slice(2)
|
|
2025
|
-
var remote_key = 'test-remote-' + Math.random().toString(36).slice(2)
|
|
2026
|
-
|
|
2027
|
-
// Create the remote resource first
|
|
2028
|
-
var r = await braid_fetch(`/${remote_key}`, {
|
|
2029
|
-
method: 'PUT',
|
|
2030
|
-
body: 'remote content'
|
|
2031
|
-
})
|
|
2032
|
-
if (!r.ok) return 'put failed: ' + r.status
|
|
2033
|
-
|
|
2034
|
-
// Start sync with on_res callback and verify it gets called
|
|
2035
|
-
var r = await braid_fetch(`/eval`, {
|
|
2036
|
-
method: 'PUT',
|
|
2037
|
-
body: `void (async () => {
|
|
2038
|
-
var ac = new AbortController()
|
|
2039
|
-
var got_res = false
|
|
2040
|
-
|
|
2041
|
-
braid_text.sync('/${local_key}', new URL('http://localhost:8889/${remote_key}'), {
|
|
2042
|
-
signal: ac.signal,
|
|
2043
|
-
on_res: (response) => {
|
|
2044
|
-
got_res = response && typeof response.headers !== 'undefined'
|
|
2045
|
-
}
|
|
2046
|
-
})
|
|
2047
|
-
|
|
2048
|
-
// Wait for sync to establish and on_res to be called
|
|
2049
|
-
await new Promise(done => setTimeout(done, 200))
|
|
2050
|
-
|
|
2051
|
-
ac.abort()
|
|
2052
|
-
res.end(got_res ? 'on_res called' : 'on_res not called')
|
|
2053
|
-
})()`
|
|
2054
|
-
})
|
|
2055
|
-
if (!r.ok) return 'eval failed: ' + r.status
|
|
2056
|
-
|
|
2057
|
-
return await r.text()
|
|
2058
|
-
},
|
|
2059
|
-
'on_res called'
|
|
2060
|
-
)
|
|
2061
|
-
|
|
2062
|
-
runTest(
|
|
2063
|
-
"test braid_text.sync uses accept-encoding updates(dt)",
|
|
2064
|
-
async () => {
|
|
2065
|
-
var remote_key = 'test-remote-' + Math.random().toString(36).slice(2)
|
|
2066
|
-
var local_key = 'test-local-' + Math.random().toString(36).slice(2)
|
|
2067
|
-
|
|
2068
|
-
// Create the remote resource with some content
|
|
2069
|
-
var r = await braid_fetch(`/${remote_key}`, {
|
|
2070
|
-
method: 'PUT',
|
|
2071
|
-
body: 'remote content here'
|
|
2072
|
-
})
|
|
2073
|
-
if (!r.ok) return 'put failed: ' + r.status
|
|
2074
|
-
|
|
2075
|
-
// Start sync with URL first (like the passing "url to key" test)
|
|
2076
|
-
var r = await braid_fetch(`/eval`, {
|
|
2077
|
-
method: 'PUT',
|
|
2078
|
-
body: `void (async () => {
|
|
2079
|
-
braid_text.sync(new URL('http://localhost:8889/${remote_key}'), '/${local_key}')
|
|
2080
|
-
res.end('')
|
|
2081
|
-
})()`
|
|
2082
|
-
})
|
|
2083
|
-
if (!r.ok) return 'eval failed: ' + r.status
|
|
2084
|
-
|
|
2085
|
-
// Wait for sync to complete
|
|
2086
|
-
await new Promise(done => setTimeout(done, 100))
|
|
2087
|
-
|
|
2088
|
-
// Check local has remote content
|
|
2089
|
-
var r = await braid_fetch(`/${local_key}`)
|
|
2090
|
-
return await r.text()
|
|
2091
|
-
},
|
|
2092
|
-
'remote content here'
|
|
2093
|
-
)
|
|
2094
|
-
|
|
2095
|
-
runTest(
|
|
2096
|
-
"test braid_text.sync reconnects when inner put fails with non-200 status",
|
|
2097
|
-
async () => {
|
|
2098
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
2099
|
-
|
|
2100
|
-
// Create a local resource with content
|
|
2101
|
-
var r = await braid_fetch(`/${key}`, {
|
|
2102
|
-
method: 'PUT',
|
|
2103
|
-
body: 'initial'
|
|
2104
|
-
})
|
|
2105
|
-
if (!r.ok) return 'initial put failed: ' + r.status
|
|
2106
|
-
|
|
2107
|
-
var r = await braid_fetch(`/eval`, {
|
|
2108
|
-
method: 'PUT',
|
|
2109
|
-
body: `void (async () => {
|
|
2110
|
-
var connect_count = 0
|
|
2111
|
-
var ac = new AbortController()
|
|
2112
|
-
|
|
2113
|
-
braid_text.sync('/${key}', new URL('http://localhost:8889/server_error'), {
|
|
2114
|
-
signal: ac.signal,
|
|
2115
|
-
on_pre_connect: () => {
|
|
2116
|
-
connect_count++
|
|
2117
|
-
if (connect_count >= 2) {
|
|
2118
|
-
ac.abort()
|
|
2119
|
-
res.end('reconnected after put failure')
|
|
2120
|
-
}
|
|
2121
|
-
}
|
|
2122
|
-
})
|
|
2123
|
-
|
|
2124
|
-
// Trigger a local put which will fail when synced to the error endpoint
|
|
2125
|
-
await new Promise(done => setTimeout(done, 100))
|
|
2126
|
-
await braid_text.put('/${key}', { body: 'trigger sync' })
|
|
2127
|
-
|
|
2128
|
-
// Wait for reconnect attempt
|
|
2129
|
-
await new Promise(done => setTimeout(done, 2000))
|
|
2130
|
-
ac.abort()
|
|
2131
|
-
res.end('did not reconnect')
|
|
2132
|
-
})()`
|
|
2133
|
-
})
|
|
2134
|
-
if (!r.ok) return 'eval failed: ' + r.status
|
|
2135
|
-
|
|
2136
|
-
return await r.text()
|
|
2137
|
-
},
|
|
2138
|
-
'reconnected after put failure'
|
|
2139
|
-
)
|
|
2140
|
-
|
|
2141
|
-
runTest(
|
|
2142
|
-
"test braid_text.sync on_unauthorized callback for 401",
|
|
2143
|
-
async () => {
|
|
2144
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
2145
|
-
|
|
2146
|
-
// Create a local resource with content
|
|
2147
|
-
var r = await braid_fetch(`/${key}`, {
|
|
2148
|
-
method: 'PUT',
|
|
2149
|
-
body: 'initial'
|
|
2150
|
-
})
|
|
2151
|
-
if (!r.ok) return 'initial put failed: ' + r.status
|
|
2152
|
-
|
|
2153
|
-
var r = await braid_fetch(`/eval`, {
|
|
2154
|
-
method: 'PUT',
|
|
2155
|
-
body: `void (async () => {
|
|
2156
|
-
var unauthorized_called = false
|
|
2157
|
-
var ac = new AbortController()
|
|
2158
|
-
|
|
2159
|
-
braid_text.sync('/${key}', new URL('http://localhost:8889/unauthorized'), {
|
|
2160
|
-
signal: ac.signal,
|
|
2161
|
-
on_unauthorized: () => {
|
|
2162
|
-
unauthorized_called = true
|
|
2163
|
-
ac.abort()
|
|
2164
|
-
res.end('on_unauthorized called')
|
|
2165
|
-
}
|
|
2166
|
-
})
|
|
2167
|
-
|
|
2168
|
-
// Trigger a local put which will get 401 when synced
|
|
2169
|
-
await new Promise(done => setTimeout(done, 100))
|
|
2170
|
-
await braid_text.put('/${key}', { body: 'trigger sync' })
|
|
2171
|
-
|
|
2172
|
-
// Wait for callback
|
|
2173
|
-
await new Promise(done => setTimeout(done, 2000))
|
|
2174
|
-
ac.abort()
|
|
2175
|
-
res.end('on_unauthorized not called')
|
|
2176
|
-
})()`
|
|
2177
|
-
})
|
|
2178
|
-
if (!r.ok) return 'eval failed: ' + r.status
|
|
2179
|
-
|
|
2180
|
-
return await r.text()
|
|
2181
|
-
},
|
|
2182
|
-
'on_unauthorized called'
|
|
2183
|
-
)
|
|
2184
|
-
|
|
2185
|
-
runTest(
|
|
2186
|
-
"test braid_text.sync on_unauthorized callback for 403",
|
|
2187
|
-
async () => {
|
|
2188
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
2189
|
-
|
|
2190
|
-
// Create a local resource with content
|
|
2191
|
-
var r = await braid_fetch(`/${key}`, {
|
|
2192
|
-
method: 'PUT',
|
|
2193
|
-
body: 'initial'
|
|
2194
|
-
})
|
|
2195
|
-
if (!r.ok) return 'initial put failed: ' + r.status
|
|
2196
|
-
|
|
2197
|
-
var r = await braid_fetch(`/eval`, {
|
|
2198
|
-
method: 'PUT',
|
|
2199
|
-
body: `void (async () => {
|
|
2200
|
-
var unauthorized_called = false
|
|
2201
|
-
var ac = new AbortController()
|
|
2202
|
-
|
|
2203
|
-
braid_text.sync('/${key}', new URL('http://localhost:8889/forbidden'), {
|
|
2204
|
-
signal: ac.signal,
|
|
2205
|
-
on_unauthorized: () => {
|
|
2206
|
-
unauthorized_called = true
|
|
2207
|
-
ac.abort()
|
|
2208
|
-
res.end('on_unauthorized called')
|
|
2209
|
-
}
|
|
2210
|
-
})
|
|
2211
|
-
|
|
2212
|
-
// Trigger a local put which will get 403 when synced
|
|
2213
|
-
await new Promise(done => setTimeout(done, 100))
|
|
2214
|
-
await braid_text.put('/${key}', { body: 'trigger sync' })
|
|
2215
|
-
|
|
2216
|
-
// Wait for callback
|
|
2217
|
-
await new Promise(done => setTimeout(done, 2000))
|
|
2218
|
-
ac.abort()
|
|
2219
|
-
res.end('on_unauthorized not called')
|
|
2220
|
-
})()`
|
|
2221
|
-
})
|
|
2222
|
-
if (!r.ok) return 'eval failed: ' + r.status
|
|
2223
|
-
|
|
2224
|
-
return await r.text()
|
|
2225
|
-
},
|
|
2226
|
-
'on_unauthorized called'
|
|
2227
|
-
)
|
|
2228
|
-
|
|
2229
|
-
runTest(
|
|
2230
|
-
"test getting a binary update from a subscription",
|
|
2231
|
-
async () => {
|
|
2232
|
-
return await new Promise(async (done, fail) => {
|
|
2233
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
2234
|
-
|
|
2235
|
-
await fetch(`/${key}`, {
|
|
2236
|
-
method: 'PUT',
|
|
2237
|
-
body: JSON.stringify({a: 5, b: 6}, null, 4)
|
|
2238
|
-
})
|
|
2239
|
-
|
|
2240
|
-
var a = new AbortController()
|
|
2241
|
-
let r = await braid_fetch(`/${key}`, {
|
|
2242
|
-
signal: a.signal,
|
|
2243
|
-
subscribe: true
|
|
2244
|
-
})
|
|
2245
|
-
|
|
2246
|
-
r.subscribe(update => {
|
|
2247
|
-
done(update.body_text)
|
|
2248
|
-
a.abort()
|
|
2249
|
-
}, fail)
|
|
2250
|
-
})
|
|
2251
|
-
},
|
|
2252
|
-
JSON.stringify({a: 5, b: 6}, null, 4)
|
|
2253
|
-
)
|
|
2254
|
-
|
|
2255
|
-
runTest(
|
|
2256
|
-
"test sending a json patch to some json-text",
|
|
2257
|
-
async () => {
|
|
2258
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
2259
|
-
|
|
2260
|
-
await fetch(`/${key}`, {
|
|
2261
|
-
method: 'PUT',
|
|
2262
|
-
body: JSON.stringify({a: 5, b: 6})
|
|
2263
|
-
})
|
|
2264
|
-
|
|
2265
|
-
await fetch(`/${key}`, {
|
|
2266
|
-
method: 'PUT',
|
|
2267
|
-
headers: { 'Content-Range': 'json a' },
|
|
2268
|
-
body: '67'
|
|
2269
|
-
})
|
|
2270
|
-
|
|
2271
|
-
let r = await fetch(`/${key}`)
|
|
2272
|
-
|
|
2273
|
-
return await r.text()
|
|
2274
|
-
},
|
|
2275
|
-
JSON.stringify({a: 67, b: 6}, null, 4)
|
|
2276
|
-
)
|
|
2277
|
-
|
|
2278
|
-
runTest(
|
|
2279
|
-
"test sending multiple json patches to some json-text",
|
|
2280
|
-
async () => {
|
|
2281
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
2282
|
-
|
|
2283
|
-
await fetch(`/${key}`, {
|
|
2284
|
-
method: 'PUT',
|
|
2285
|
-
body: JSON.stringify({a: 5, b: 6, c: 7})
|
|
2286
|
-
})
|
|
2287
|
-
|
|
2288
|
-
await braid_fetch(`/${key}`, {
|
|
2289
|
-
method: 'PUT',
|
|
2290
|
-
headers: { 'Content-Range': 'json a' },
|
|
2291
|
-
patches: [{
|
|
2292
|
-
unit: 'json',
|
|
2293
|
-
range: 'a',
|
|
2294
|
-
content: '55',
|
|
2295
|
-
}, {
|
|
2296
|
-
unit: 'json',
|
|
2297
|
-
range: 'b',
|
|
2298
|
-
content: '66',
|
|
2299
|
-
}]
|
|
2300
|
-
})
|
|
2301
|
-
|
|
2302
|
-
let r = await fetch(`/${key}`)
|
|
2303
|
-
|
|
2304
|
-
return await r.text()
|
|
2305
|
-
},
|
|
2306
|
-
JSON.stringify({a: 55, b: 66, c: 7}, null, 4)
|
|
2307
|
-
)
|
|
2308
|
-
|
|
2309
|
-
runTest(
|
|
2310
|
-
"test deleting something using a json patch",
|
|
2311
|
-
async () => {
|
|
2312
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
2313
|
-
|
|
2314
|
-
await fetch(`/${key}`, {
|
|
2315
|
-
method: 'PUT',
|
|
2316
|
-
body: JSON.stringify({a: 5, b: 6}, null, 4)
|
|
2317
|
-
})
|
|
2318
|
-
|
|
2319
|
-
await fetch(`/${key}`, {
|
|
2320
|
-
method: 'PUT',
|
|
2321
|
-
headers: { 'Content-Range': 'json a' },
|
|
2322
|
-
body: ''
|
|
2323
|
-
})
|
|
2324
|
-
|
|
2325
|
-
let r = await fetch(`/${key}`)
|
|
2326
|
-
|
|
2327
|
-
return await r.text()
|
|
2328
|
-
},
|
|
2329
|
-
JSON.stringify({b: 6}, null, 4)
|
|
2330
|
-
)
|
|
2331
|
-
|
|
2332
|
-
runTest(
|
|
2333
|
-
"test length updating",
|
|
2334
|
-
async () => {
|
|
2335
|
-
let key = 'test-' + Math.random().toString(36).slice(2)
|
|
2336
|
-
|
|
2337
|
-
await fetch(`/${key}`, { method: 'PUT', body: '' })
|
|
2338
|
-
await fetch(`/${key}`, { method: 'PUT', body: '0123456789' })
|
|
2339
|
-
await fetch(`/${key}`, { method: 'PUT', body: '0123456789' })
|
|
2340
|
-
await fetch(`/${key}`, { method: 'PUT', body: '0123456789' })
|
|
2341
|
-
|
|
2342
|
-
let r = await fetch(`/${key}`, { method: 'HEAD' })
|
|
2343
|
-
return '' + parseInt(r.headers.get('version').split('-')[1])
|
|
2344
|
-
},
|
|
2345
|
-
'19'
|
|
2346
|
-
)
|
|
2347
|
-
|
|
2348
|
-
runTest(
|
|
2349
|
-
"test retry when parents not there..",
|
|
2350
|
-
async () => {
|
|
2351
|
-
return await new Promise(done => {
|
|
2352
|
-
var count = 0
|
|
2353
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
2354
|
-
var a = new AbortController()
|
|
2355
|
-
braid_fetch(`/${key}`, {
|
|
2356
|
-
signal: a.signal,
|
|
2357
|
-
multiplex: false,
|
|
2358
|
-
method: 'PUT',
|
|
2359
|
-
version: ['hi-3'],
|
|
2360
|
-
parents: ['hi-1'],
|
|
2361
|
-
body: 'xx',
|
|
2362
|
-
onFetch: () => {
|
|
2363
|
-
count++
|
|
2364
|
-
if (count === 2) {
|
|
2365
|
-
done('retried!')
|
|
2366
|
-
a.abort()
|
|
2367
|
-
}
|
|
2368
|
-
},
|
|
2369
|
-
retry: true
|
|
2370
|
-
})
|
|
2371
|
-
})
|
|
2372
|
-
},
|
|
2373
|
-
'retried!'
|
|
2374
|
-
)
|
|
2375
|
-
|
|
2376
|
-
runTest(
|
|
2377
|
-
"test asking for a version that should and shouldn't be there",
|
|
2378
|
-
async () => {
|
|
2379
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
2380
|
-
|
|
2381
|
-
var r = await braid_fetch(`/${key}`, {
|
|
2382
|
-
method: 'PUT',
|
|
2383
|
-
version: ['hi-10'],
|
|
2384
|
-
parents: [],
|
|
2385
|
-
body: 'x'
|
|
2386
|
-
})
|
|
2387
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
2388
|
-
|
|
2389
|
-
var r = await braid_fetch(`/${key}`, {
|
|
2390
|
-
method: 'HEAD',
|
|
2391
|
-
version: ['hi-5']
|
|
2392
|
-
})
|
|
2393
|
-
if (r.status !== 309) throw 'expected 309, got: ' + r.status
|
|
2394
|
-
if (r.statusText !== 'Version Unknown Here') throw 'unexpected status text: ' + r.statusText
|
|
2395
|
-
if (r.ok) throw 'found version we should not have found'
|
|
2396
|
-
|
|
2397
|
-
var r = await braid_fetch(`/${key}`, {
|
|
2398
|
-
method: 'HEAD',
|
|
2399
|
-
version: ['hi-10']
|
|
2400
|
-
})
|
|
2401
|
-
if (!r.ok) throw 'could not find version we should have found'
|
|
2402
|
-
|
|
2403
|
-
return 'worked out!'
|
|
2404
|
-
},
|
|
2405
|
-
'worked out!'
|
|
2406
|
-
)
|
|
2407
|
-
|
|
2408
|
-
runTest(
|
|
2409
|
-
"test asking for parents that should and shouldn't be there",
|
|
2410
|
-
async () => {
|
|
2411
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
2412
|
-
|
|
2413
|
-
var r = await braid_fetch(`/${key}`, {
|
|
2414
|
-
method: 'PUT',
|
|
2415
|
-
version: ['hi-10'],
|
|
2416
|
-
parents: [],
|
|
2417
|
-
body: 'x'
|
|
2418
|
-
})
|
|
2419
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
2420
|
-
|
|
2421
|
-
var r = await braid_fetch(`/${key}`, {
|
|
2422
|
-
method: 'HEAD',
|
|
2423
|
-
parents: ['hi-5']
|
|
2424
|
-
})
|
|
2425
|
-
if (r.status !== 309) throw 'expected 309, got: ' + r.status
|
|
2426
|
-
if (r.ok) throw 'found parents we should not have found'
|
|
2427
|
-
|
|
2428
|
-
var r = await braid_fetch(`/${key}`, {
|
|
2429
|
-
method: 'HEAD',
|
|
2430
|
-
parents: ['hi-10']
|
|
2431
|
-
})
|
|
2432
|
-
if (!r.ok) throw 'could not find parents we should have found'
|
|
2433
|
-
|
|
2434
|
-
return 'worked out!'
|
|
2435
|
-
},
|
|
2436
|
-
'worked out!'
|
|
2437
|
-
)
|
|
2438
|
-
|
|
2439
|
-
runTest(
|
|
2440
|
-
"test that 309 returns all missing events",
|
|
2441
|
-
async () => {
|
|
2442
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
2443
|
-
|
|
2444
|
-
var r = await braid_fetch(`/${key}`, {
|
|
2445
|
-
method: 'PUT',
|
|
2446
|
-
version: ['hi-11'],
|
|
2447
|
-
parents: [],
|
|
2448
|
-
body: 'xyz'
|
|
2449
|
-
})
|
|
2450
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
2451
|
-
|
|
2452
|
-
var r = await braid_fetch(`/${key}`, {
|
|
2453
|
-
method: 'HEAD',
|
|
2454
|
-
version: ['yo-1', 'hi-11'],
|
|
2455
|
-
parents: ['hi-5', 'hi-8', 'hi-9', 'hi-10']
|
|
2456
|
-
})
|
|
2457
|
-
if (r.status !== 309) throw 'expected 309, got: ' + r.status
|
|
2458
|
-
return r.headers.get('version')
|
|
2459
|
-
},
|
|
2460
|
-
'"yo-1", "hi-5", "hi-8"'
|
|
2461
|
-
)
|
|
2462
|
-
|
|
2463
|
-
runTest(
|
|
2464
|
-
"test that subscribe returns current-version header",
|
|
2465
|
-
async () => {
|
|
2466
|
-
var key = 'test-' + Math.random().toString(36).slice(2)
|
|
2467
|
-
|
|
2468
|
-
var r = await braid_fetch(`/${key}`, {
|
|
2469
|
-
method: 'PUT',
|
|
2470
|
-
version: ['hi-11'],
|
|
2471
|
-
parents: [],
|
|
2472
|
-
body: 'xyz'
|
|
2473
|
-
})
|
|
2474
|
-
if (!r.ok) throw 'got: ' + r.statusCode
|
|
2475
|
-
|
|
2476
|
-
var a = new AbortController()
|
|
2477
|
-
var r = await braid_fetch(`/${key}`, {
|
|
2478
|
-
signal: a.signal,
|
|
2479
|
-
subscribe: true
|
|
2480
|
-
})
|
|
2481
|
-
var result = r.headers.get('current-version')
|
|
2482
|
-
a.abort()
|
|
2483
|
-
return result
|
|
2484
|
-
},
|
|
2485
|
-
'"hi-11"'
|
|
2486
|
-
)
|
|
2487
|
-
|
|
2488
|
-
runTest(
|
|
2489
|
-
"test case-insensitive filesystem handling (/a vs /A)",
|
|
2490
|
-
async () => {
|
|
2491
|
-
// This test verifies that keys differing only in case are stored
|
|
2492
|
-
// in separate files on case-insensitive filesystems (Mac/Windows)
|
|
2493
|
-
var key_lower = '/test-case-' + Math.random().toString(36).slice(2)
|
|
2494
|
-
var key_upper = key_lower.toUpperCase()
|
|
2495
|
-
|
|
2496
|
-
// Store different values for lowercase and uppercase keys
|
|
2497
|
-
// Then clear cache and reload from disk to verify filesystem storage
|
|
2498
|
-
var r1 = await braid_fetch(`/eval`, {
|
|
2499
|
-
method: 'PUT',
|
|
2500
|
-
body: `void (async () => {
|
|
2501
|
-
await braid_text.put('${key_lower}', {body: 'lowercase-value'})
|
|
2502
|
-
await braid_text.put('${key_upper}', {body: 'uppercase-value'})
|
|
2503
|
-
|
|
2504
|
-
// Wait for disk write
|
|
2505
|
-
await new Promise(done => setTimeout(done, 200))
|
|
2506
|
-
|
|
2507
|
-
// Clear the in-memory cache to force reload from disk
|
|
2508
|
-
// Note: We keep the key_to_encoded mapping intact since that persists across cache clears
|
|
2509
|
-
delete braid_text.cache['${key_lower}']
|
|
2510
|
-
delete braid_text.cache['${key_upper}']
|
|
2511
|
-
|
|
2512
|
-
// Also need to wait for any async file operations
|
|
2513
|
-
await new Promise(done => setTimeout(done, 100))
|
|
2514
|
-
|
|
2515
|
-
// Read back from disk - pass empty options to force loading
|
|
2516
|
-
var lower = (await braid_text.get('${key_lower}', {})).body
|
|
2517
|
-
var upper = (await braid_text.get('${key_upper}', {})).body
|
|
2518
|
-
res.end(JSON.stringify({lower, upper}))
|
|
2519
|
-
})()`
|
|
2520
|
-
})
|
|
2521
|
-
if (!r1.ok) return 'eval failed: ' + r1.status
|
|
2522
|
-
|
|
2523
|
-
var result = JSON.parse(await r1.text())
|
|
2524
|
-
if (result.lower !== 'lowercase-value') {
|
|
2525
|
-
return 'lower mismatch: ' + result.lower
|
|
2526
|
-
}
|
|
2527
|
-
if (result.upper !== 'uppercase-value') {
|
|
2528
|
-
return 'upper mismatch: ' + result.upper
|
|
2529
|
-
}
|
|
2530
|
-
return 'ok'
|
|
2531
|
-
},
|
|
2532
|
-
'ok'
|
|
2533
|
-
)
|
|
2534
|
-
|
|
2535
|
-
runTest(
|
|
2536
|
-
"test Merge-Type header per Braid spec",
|
|
2537
|
-
async () => {
|
|
2538
|
-
let key = 'test-merge-type-' + Math.random().toString(36).slice(2)
|
|
2539
|
-
|
|
2540
|
-
// First PUT some content (15 characters, so version is alice-14)
|
|
2541
|
-
await braid_fetch(`/${key}`, {
|
|
2542
|
-
method: 'PUT',
|
|
2543
|
-
version: ['alice-14'],
|
|
2544
|
-
parents: [],
|
|
2545
|
-
body: 'initial content'
|
|
2546
|
-
})
|
|
2547
|
-
|
|
2548
|
-
// Test 1: GET with Version header should include Merge-Type
|
|
2549
|
-
let r1 = await braid_fetch(`/${key}`, {
|
|
2550
|
-
version: ['alice-14']
|
|
2551
|
-
})
|
|
2552
|
-
if (!r1.headers.get('merge-type')) return 'Missing Merge-Type with Version header'
|
|
2553
|
-
|
|
2554
|
-
// Test 2: GET with empty Version header should still include Merge-Type
|
|
2555
|
-
let r2 = await braid_fetch(`/${key}`, {
|
|
2556
|
-
headers: {
|
|
2557
|
-
'Version': ''
|
|
2558
|
-
}
|
|
2559
|
-
})
|
|
2560
|
-
if (!r2.headers.get('merge-type')) return 'Missing Merge-Type with empty Version header'
|
|
2561
|
-
|
|
2562
|
-
// Test 3: GET with Parents header should include Merge-Type
|
|
2563
|
-
let r3 = await braid_fetch(`/${key}`, {
|
|
2564
|
-
parents: []
|
|
2565
|
-
})
|
|
2566
|
-
if (!r3.headers.get('merge-type')) return 'Missing Merge-Type with Parents header'
|
|
2567
|
-
|
|
2568
|
-
// Test 4: Regular GET without Version/Parents should NOT include Merge-Type
|
|
2569
|
-
let r4 = await braid_fetch(`/${key}`)
|
|
2570
|
-
if (r4.headers.get('merge-type')) return 'Unexpected Merge-Type without Version/Parents'
|
|
2571
|
-
|
|
2572
|
-
// Test 5: GET with Subscribe should include Merge-Type
|
|
2573
|
-
let a = new AbortController()
|
|
2574
|
-
let r5 = await braid_fetch(`/${key}`, {
|
|
2575
|
-
signal: a.signal,
|
|
2576
|
-
subscribe: true
|
|
2577
|
-
})
|
|
2578
|
-
if (!r5.headers.get('merge-type')) return 'Missing Merge-Type with Subscribe'
|
|
2579
|
-
|
|
2580
|
-
// Close subscription
|
|
2581
|
-
a.abort()
|
|
2582
|
-
|
|
2583
|
-
return 'ok'
|
|
2584
|
-
},
|
|
2585
|
-
'ok'
|
|
2586
|
-
)
|
|
2587
|
-
|
|
2588
|
-
runTest(
|
|
2589
|
-
"test filename conflict detection (different encodings of same key)",
|
|
2590
|
-
async () => {
|
|
2591
|
-
// This test creates two files on disk with different URL-encoded names
|
|
2592
|
-
// that decode to the same key, then tries to load them, which should
|
|
2593
|
-
// throw "filename conflict detected"
|
|
2594
|
-
|
|
2595
|
-
// Use a unique test subdirectory to avoid affecting other tests
|
|
2596
|
-
var testId = Math.random().toString(36).slice(2)
|
|
2597
|
-
|
|
2598
|
-
var r = await braid_fetch(`/eval`, {
|
|
2599
|
-
method: 'PUT',
|
|
2600
|
-
body: `void (async () => {
|
|
2601
|
-
var fs = require('fs')
|
|
2602
|
-
var path = require('path')
|
|
2603
|
-
|
|
2604
|
-
// Create a temporary test db folder
|
|
2605
|
-
var testFolder = path.join(braid_text.db_folder, 'conflict-test-${testId}')
|
|
2606
|
-
await fs.promises.mkdir(testFolder, { recursive: true })
|
|
2607
|
-
|
|
2608
|
-
// Create two files that decode to the same key "/hello"
|
|
2609
|
-
// File 1: Using the standard encoding with ! swapped for /
|
|
2610
|
-
// !hello -> decodes to /hello (after !/swap)
|
|
2611
|
-
await fs.promises.writeFile(path.join(testFolder, '!hello.0'), 'content1')
|
|
2612
|
-
|
|
2613
|
-
// File 2: Using %2F encoding for /
|
|
2614
|
-
// %2Fhello -> decodes to /hello (via URL decoding, then !/swap on /)
|
|
2615
|
-
// Actually, let's trace through decode_filename:
|
|
2616
|
-
// 1. decodeURIComponent('%21hello') = '!hello'
|
|
2617
|
-
// 2. swap !/: '!hello' -> '/hello'
|
|
2618
|
-
// So %21hello decodes to /hello
|
|
2619
|
-
await fs.promises.writeFile(path.join(testFolder, '%21hello.0'), 'content2')
|
|
2620
|
-
|
|
2621
|
-
// Now try to initialize filename mapping with these files
|
|
2622
|
-
// We need to call the internal init_filename_mapping function
|
|
2623
|
-
// through a resource load that reads the test directory
|
|
2624
|
-
|
|
2625
|
-
try {
|
|
2626
|
-
// Read the files from the test folder
|
|
2627
|
-
var files = await fs.promises.readdir(testFolder)
|
|
2628
|
-
|
|
2629
|
-
// Simulate what init_filename_mapping does
|
|
2630
|
-
var key_to_filename = new Map()
|
|
2631
|
-
for (var file of files) {
|
|
2632
|
-
var encoded = file.replace(/\\\.\\d+$/, '')
|
|
2633
|
-
var key = braid_text.decode_filename(encoded)
|
|
2634
|
-
|
|
2635
|
-
if (!key_to_filename.has(key)) {
|
|
2636
|
-
key_to_filename.set(key, encoded)
|
|
2637
|
-
} else {
|
|
2638
|
-
throw new Error('filename conflict detected')
|
|
2639
|
-
}
|
|
2640
|
-
}
|
|
2641
|
-
res.end('no error thrown')
|
|
2642
|
-
} catch (e) {
|
|
2643
|
-
res.end(e.message)
|
|
2644
|
-
} finally {
|
|
2645
|
-
// Clean up test folder
|
|
2646
|
-
try {
|
|
2647
|
-
for (var f of await fs.promises.readdir(testFolder)) {
|
|
2648
|
-
await fs.promises.unlink(path.join(testFolder, f))
|
|
2649
|
-
}
|
|
2650
|
-
await fs.promises.rmdir(testFolder)
|
|
2651
|
-
} catch (e) {}
|
|
2652
|
-
}
|
|
2653
|
-
})()`
|
|
2654
|
-
})
|
|
2655
|
-
|
|
2656
|
-
return await r.text()
|
|
2657
|
-
},
|
|
2658
|
-
'filename conflict detected'
|
|
2659
|
-
)
|
|
2660
|
-
|
|
2661
|
-
runTest(
|
|
2662
|
-
"test wal-intent recovery after simulated crash during append",
|
|
2663
|
-
async () => {
|
|
2664
|
-
var r = await braid_fetch(`/eval`, {
|
|
2665
|
-
method: 'PUT',
|
|
2666
|
-
body: `void (async () => {
|
|
2667
|
-
var fs = require('fs')
|
|
2668
|
-
var test_db = __dirname + '/test_wal_recovery_' + Math.random().toString(36).slice(2)
|
|
2669
|
-
try {
|
|
2670
|
-
// Create a fresh braid_text instance with its own db_folder
|
|
2671
|
-
var bt = braid_text.create_braid_text()
|
|
2672
|
-
bt.db_folder = test_db
|
|
2673
|
-
|
|
2674
|
-
// Do initial PUT (5 chars = 'hello', version ends at 4)
|
|
2675
|
-
await bt.put('/test', {
|
|
2676
|
-
version: ['a-4'],
|
|
2677
|
-
parents: [],
|
|
2678
|
-
body: 'hello'
|
|
2679
|
-
})
|
|
2680
|
-
|
|
2681
|
-
// Do second PUT to trigger an append (6 more chars = ' world', version ends at 10)
|
|
2682
|
-
await bt.put('/test', {
|
|
2683
|
-
version: ['a-10'],
|
|
2684
|
-
parents: ['a-4'],
|
|
2685
|
-
body: 'hello world'
|
|
2686
|
-
})
|
|
2687
|
-
|
|
2688
|
-
var encoded = bt.encode_filename('/test')
|
|
2689
|
-
var db_file = test_db + '/' + encoded + '.1'
|
|
2690
|
-
var intent_file = test_db + '/.wal-intent/' + encoded + '.1'
|
|
2691
|
-
|
|
2692
|
-
// Read the db file
|
|
2693
|
-
var data = await fs.promises.readFile(db_file)
|
|
2694
|
-
|
|
2695
|
-
// Parse chunks to find the last one
|
|
2696
|
-
var cursor = 0
|
|
2697
|
-
var chunks = []
|
|
2698
|
-
while (cursor < data.length) {
|
|
2699
|
-
var chunk_start = cursor
|
|
2700
|
-
var chunk_size = data.readUInt32LE(cursor)
|
|
2701
|
-
cursor += 4 + chunk_size
|
|
2702
|
-
chunks.push({ start: chunk_start, size: chunk_size, end: cursor })
|
|
2703
|
-
}
|
|
2704
|
-
|
|
2705
|
-
if (chunks.length < 2) {
|
|
2706
|
-
res.end('expected at least 2 chunks, got ' + chunks.length)
|
|
2707
|
-
return
|
|
2708
|
-
}
|
|
2709
|
-
|
|
2710
|
-
var last_chunk = chunks[chunks.length - 1]
|
|
2711
|
-
var prev_end = chunks[chunks.length - 2].end
|
|
2712
|
-
|
|
2713
|
-
// Create the wal-intent file: 8-byte size + the last chunk data
|
|
2714
|
-
var size_buf = Buffer.allocUnsafe(8)
|
|
2715
|
-
size_buf.writeBigUInt64LE(BigInt(prev_end), 0)
|
|
2716
|
-
var last_chunk_data = data.subarray(last_chunk.start, last_chunk.end)
|
|
2717
|
-
var intent_data = Buffer.concat([size_buf, last_chunk_data])
|
|
2718
|
-
await fs.promises.writeFile(intent_file, intent_data)
|
|
2719
|
-
|
|
2720
|
-
// Truncate the db file partway through the last chunk (keep ~half)
|
|
2721
|
-
var truncate_point = last_chunk.start + Math.floor((last_chunk.end - last_chunk.start) / 2)
|
|
2722
|
-
await fs.promises.truncate(db_file, truncate_point)
|
|
2723
|
-
|
|
2724
|
-
// Create a new braid_text instance to simulate restart
|
|
2725
|
-
var bt2 = braid_text.create_braid_text()
|
|
2726
|
-
bt2.db_folder = test_db
|
|
2727
|
-
|
|
2728
|
-
// Get the resource - this should trigger wal-intent replay
|
|
2729
|
-
var resource = await bt2.get_resource('/test')
|
|
2730
|
-
var text = resource.doc.get()
|
|
2731
|
-
|
|
2732
|
-
// Verify intent file was cleaned up
|
|
2733
|
-
var intent_exists = true
|
|
2734
|
-
try {
|
|
2735
|
-
await fs.promises.access(intent_file)
|
|
2736
|
-
} catch (e) {
|
|
2737
|
-
intent_exists = false
|
|
2738
|
-
}
|
|
2739
|
-
|
|
2740
|
-
await fs.promises.rm(test_db, { recursive: true, force: true })
|
|
2741
|
-
|
|
2742
|
-
if (intent_exists) {
|
|
2743
|
-
res.end('intent file still exists')
|
|
2744
|
-
return
|
|
2745
|
-
}
|
|
2746
|
-
|
|
2747
|
-
res.end(text)
|
|
2748
|
-
} catch (e) {
|
|
2749
|
-
await fs.promises.rm(test_db, { recursive: true, force: true }).catch(() => {})
|
|
2750
|
-
res.end('error: ' + e.message + ' ' + e.stack)
|
|
2751
|
-
}
|
|
2752
|
-
})()`
|
|
2753
|
-
})
|
|
2754
|
-
|
|
2755
|
-
return await r.text()
|
|
2756
|
-
},
|
|
2757
|
-
'hello world'
|
|
2758
|
-
)
|
|
2759
|
-
|
|
2760
|
-
runTest(
|
|
2761
|
-
"test wal-intent throws error when db file is too large",
|
|
2762
|
-
async () => {
|
|
2763
|
-
var r = await braid_fetch(`/eval`, {
|
|
2764
|
-
method: 'PUT',
|
|
2765
|
-
body: `void (async () => {
|
|
2766
|
-
var fs = require('fs')
|
|
2767
|
-
var test_db = __dirname + '/test_wal_error_' + Math.random().toString(36).slice(2)
|
|
2768
|
-
try {
|
|
2769
|
-
// Create a fresh braid_text instance with its own db_folder
|
|
2770
|
-
var bt = braid_text.create_braid_text()
|
|
2771
|
-
bt.db_folder = test_db
|
|
2772
|
-
|
|
2773
|
-
// Do initial PUT (5 chars = 'hello', version ends at 4)
|
|
2774
|
-
await bt.put('/test', {
|
|
2775
|
-
version: ['a-4'],
|
|
2776
|
-
parents: [],
|
|
2777
|
-
body: 'hello'
|
|
2778
|
-
})
|
|
2779
|
-
|
|
2780
|
-
// Do second PUT to trigger an append (6 more chars = ' world', version ends at 10)
|
|
2781
|
-
await bt.put('/test', {
|
|
2782
|
-
version: ['a-10'],
|
|
2783
|
-
parents: ['a-4'],
|
|
2784
|
-
body: 'hello world'
|
|
2785
|
-
})
|
|
2786
|
-
|
|
2787
|
-
var encoded = bt.encode_filename('/test')
|
|
2788
|
-
var db_file = test_db + '/' + encoded + '.1'
|
|
2789
|
-
var intent_file = test_db + '/.wal-intent/' + encoded + '.1'
|
|
2790
|
-
|
|
2791
|
-
// Read the db file
|
|
2792
|
-
var data = await fs.promises.readFile(db_file)
|
|
2793
|
-
|
|
2794
|
-
// Parse chunks to find the last one
|
|
2795
|
-
var cursor = 0
|
|
2796
|
-
var chunks = []
|
|
2797
|
-
while (cursor < data.length) {
|
|
2798
|
-
var chunk_start = cursor
|
|
2799
|
-
var chunk_size = data.readUInt32LE(cursor)
|
|
2800
|
-
cursor += 4 + chunk_size
|
|
2801
|
-
chunks.push({ start: chunk_start, size: chunk_size, end: cursor })
|
|
2802
|
-
}
|
|
2803
|
-
|
|
2804
|
-
if (chunks.length < 2) {
|
|
2805
|
-
res.end('expected at least 2 chunks, got ' + chunks.length)
|
|
2806
|
-
return
|
|
2807
|
-
}
|
|
2808
|
-
|
|
2809
|
-
var last_chunk = chunks[chunks.length - 1]
|
|
2810
|
-
var prev_end = chunks[chunks.length - 2].end
|
|
2811
|
-
|
|
2812
|
-
// Create the wal-intent file: 8-byte size + the last chunk data
|
|
2813
|
-
var size_buf = Buffer.allocUnsafe(8)
|
|
2814
|
-
size_buf.writeBigUInt64LE(BigInt(prev_end), 0)
|
|
2815
|
-
var last_chunk_data = data.subarray(last_chunk.start, last_chunk.end)
|
|
2816
|
-
var intent_data = Buffer.concat([size_buf, last_chunk_data])
|
|
2817
|
-
await fs.promises.writeFile(intent_file, intent_data)
|
|
2818
|
-
|
|
2819
|
-
// Append extra garbage to the db file (making it too large)
|
|
2820
|
-
await fs.promises.appendFile(db_file, Buffer.from('extra garbage data'))
|
|
2821
|
-
|
|
2822
|
-
// Create a new braid_text instance to simulate restart
|
|
2823
|
-
var bt2 = braid_text.create_braid_text()
|
|
2824
|
-
bt2.db_folder = test_db
|
|
2825
|
-
|
|
2826
|
-
// Now try to init - this should throw an error
|
|
2827
|
-
var result
|
|
2828
|
-
try {
|
|
2829
|
-
await bt2.db_folder_init()
|
|
2830
|
-
result = 'should have thrown an error'
|
|
2831
|
-
} catch (e) {
|
|
2832
|
-
if (e.message.includes('wal-intent replay failed')) {
|
|
2833
|
-
result = 'correctly threw error'
|
|
2834
|
-
} else {
|
|
2835
|
-
result = 'wrong error: ' + e.message
|
|
2836
|
-
}
|
|
2837
|
-
}
|
|
2838
|
-
await fs.promises.rm(test_db, { recursive: true, force: true })
|
|
2839
|
-
res.end(result)
|
|
2840
|
-
} catch (e) {
|
|
2841
|
-
await fs.promises.rm(test_db, { recursive: true, force: true }).catch(() => {})
|
|
2842
|
-
res.end('error: ' + e.message)
|
|
2843
|
-
}
|
|
2844
|
-
})()`
|
|
2845
|
-
})
|
|
2846
|
-
|
|
2847
|
-
return await r.text()
|
|
2848
|
-
},
|
|
2849
|
-
'correctly threw error'
|
|
2850
|
-
)
|
|
2851
|
-
|
|
2852
|
-
// Tests for reconnector/sync edge cases
|
|
2853
|
-
|
|
2854
|
-
runTest(
|
|
2855
|
-
"test braid_text.sync remote null triggers local_first_put_promise path",
|
|
2856
|
-
async () => {
|
|
2857
|
-
var local_key = 'test-local-' + Math.random().toString(36).slice(2)
|
|
2858
|
-
|
|
2859
|
-
// Use the /404 endpoint which always returns 404 (null from braid_text.get)
|
|
2860
|
-
var r = await braid_fetch(`/eval`, {
|
|
2861
|
-
method: 'PUT',
|
|
2862
|
-
body: `void (async () => {
|
|
2863
|
-
var ac = new AbortController()
|
|
2864
|
-
var reconnect_count = 0
|
|
2865
|
-
|
|
2866
|
-
braid_text.sync('/${local_key}', new URL('http://localhost:8889/404'), {
|
|
2867
|
-
signal: ac.signal,
|
|
2868
|
-
on_pre_connect: () => {
|
|
2869
|
-
reconnect_count++
|
|
2870
|
-
if (reconnect_count >= 2) {
|
|
2871
|
-
ac.abort()
|
|
2872
|
-
res.end('reconnected after local put')
|
|
2873
|
-
}
|
|
2874
|
-
}
|
|
2875
|
-
})
|
|
2876
|
-
|
|
2877
|
-
// Wait a bit then put something locally - this should trigger
|
|
2878
|
-
// the local_first_put_promise to resolve and cause reconnect
|
|
2879
|
-
await new Promise(done => setTimeout(done, 100))
|
|
2880
|
-
await braid_text.put('/${local_key}', { body: 'local data' })
|
|
2881
|
-
|
|
2882
|
-
// Wait for reconnect
|
|
2883
|
-
await new Promise(done => setTimeout(done, 2000))
|
|
2884
|
-
res.end('did not reconnect')
|
|
2885
|
-
})()`
|
|
2886
|
-
})
|
|
2887
|
-
if (!r.ok) return 'eval failed: ' + r.status
|
|
2888
|
-
|
|
2889
|
-
return await r.text()
|
|
2890
|
-
},
|
|
2891
|
-
'reconnected after local put'
|
|
2892
|
-
)
|
|
2893
|
-
|
|
2894
|
-
}
|
|
2895
|
-
|
|
2896
|
-
// Export for both Node.js and browser environments
|
|
2897
|
-
if (typeof module !== 'undefined' && module.exports) {
|
|
2898
|
-
module.exports = defineTests
|
|
2899
|
-
}
|