corestore 5.8.0 → 6.0.0-alpha.1

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/test/all.js CHANGED
@@ -1,485 +1,156 @@
1
- const p = require('path')
2
- const ram = require('random-access-memory')
3
- const raf = require('random-access-file')
4
- const datEncoding = require('dat-encoding')
5
- const hypercoreCrypto = require('hypercore-crypto')
6
1
  const test = require('tape')
2
+ const crypto = require('hypercore-crypto')
3
+ const ram = require('random-access-memory')
4
+ const tmp = require('tmp-promise')
7
5
 
8
6
  const Corestore = require('..')
9
- const {
10
- runAll,
11
- validateCore,
12
- cleanup
13
- } = require('./helpers')
14
-
15
- test('ram-based corestore, different get options', async t => {
16
- const store1 = await create(ram)
17
- const core1 = store1.default()
18
- var core2, core3, core4, core5, core6
19
-
20
- await runAll([
21
- cb => core1.ready(cb),
22
- cb => core1.append('hello', cb),
23
- cb => {
24
- // Buffer arg
25
- core2 = store1.get(core1.key)
26
- return core2.ready(cb)
27
- },
28
- cb => {
29
- // Object arg
30
- core3 = store1.get({ key: core1.key })
31
- return core3.ready(cb)
32
- },
33
- cb => {
34
- // Discovery key option
35
- core4 = store1.get({ discoveryKey: core1.discoveryKey })
36
- return core4.ready(cb)
37
- },
38
- cb => {
39
- // String option
40
- core5 = store1.get({ key: datEncoding.encode(core1.key) })
41
- return core5.ready(cb)
42
- },
43
- cb => {
44
- // Custom keypair option
45
- core6 = store1.get({ keyPair: { secretKey: core1.secretKey, publicKey: core1.key } })
46
- return core6.ready(cb)
47
- }
48
- ])
49
-
50
- t.same(core1, core2)
51
- t.same(core1, core3)
52
- t.same(core1, core4)
53
- t.same(core1, core5)
54
- t.same(core1, core6)
55
- t.end()
56
- })
57
7
 
58
- test('ram-based corestore, simple replication', async t => {
59
- const store1 = await create(ram)
60
- const store2 = await create(ram)
61
- const core1 = store1.default()
62
- const core2 = store1.get()
63
- var core3 = null
64
- var core4 = null
65
-
66
- await runAll([
67
- cb => core1.ready(cb),
68
- cb => core2.ready(cb),
69
- cb => {
70
- core3 = store2.default(core1.key)
71
- return core3.ready(cb)
72
- },
73
- cb => {
74
- core4 = store2.get({ key: core2.key })
75
- return core4.ready(cb)
76
- },
77
- cb => core1.append('hello', cb),
78
- cb => core1.append('world', cb),
79
- cb => core2.append('cat', cb),
80
- cb => core2.append('dog', cb),
81
- cb => {
82
- const stream = store1.replicate(true)
83
- stream.pipe(store2.replicate(false)).pipe(stream)
84
- stream.on('end', cb)
85
- }
86
- ])
87
-
88
- await validateCore(t, core3, [Buffer.from('hello'), Buffer.from('world')])
89
- await validateCore(t, core4, [Buffer.from('cat'), Buffer.from('dog')])
8
+ test('basic get with caching', async function (t) {
9
+ const store = new Corestore(ram)
10
+ const core1a = store.get({ name: 'core-1' })
11
+ const core1b = store.get({ name: 'core-1' })
12
+ const core2 = store.get({ name: 'core-2' })
90
13
 
91
- t.end()
92
- })
14
+ await Promise.all([core1a.ready(), core1b.ready(), core2.ready()])
93
15
 
94
- test('ram-based corestore, replicating with different default keys', async t => {
95
- const store1 = await create(ram)
96
- const store2 = await create(ram)
97
- const core1 = store1.default()
98
- const core2 = store1.get()
99
- var core3 = null
100
- var core4 = null
101
-
102
- await runAll([
103
- cb => core1.ready(cb),
104
- cb => core2.ready(cb),
105
- cb => {
106
- core3 = store2.default()
107
- return core3.ready(cb)
108
- },
109
- cb => {
110
- core4 = store2.get({ key: core1.key })
111
- return core4.ready(cb)
112
- },
113
- cb => core1.append('cat', cb),
114
- cb => core1.append('dog', cb),
115
- cb => {
116
- const stream = store1.replicate(true)
117
- stream.pipe(store2.replicate(false)).pipe(stream)
118
- stream.on('end', cb)
119
- }
120
- ])
121
-
122
- await validateCore(t, core4, [Buffer.from('cat'), Buffer.from('dog')])
123
- t.end()
124
- })
16
+ t.same(core1a.key, core1b.key)
17
+ t.notSame(core1a.key, core2.key)
125
18
 
126
- test('ram-based corestore, sparse replication', async t => {
127
- const store1 = await create(ram, { sparse: true })
128
- const store2 = await create(ram, { sparse: true })
129
- const core1 = store1.default()
130
- const core2 = store1.get()
131
- var core3 = null
132
- var core4 = null
133
-
134
- await runAll([
135
- cb => core1.ready(cb),
136
- cb => core2.ready(cb),
137
- cb => {
138
- t.same(core2.sparse, true)
139
- t.same(core1.sparse, true)
140
- return process.nextTick(cb, null)
141
- },
142
- cb => {
143
- core3 = store2.default(core1.key)
144
- return core3.ready(cb)
145
- },
146
- cb => {
147
- core4 = store2.get({ key: core2.key })
148
- return core4.ready(cb)
149
- },
150
- cb => {
151
- const stream = store1.replicate(true, { live: true })
152
- stream.pipe(store2.replicate(false, { live: true })).pipe(stream)
153
- return process.nextTick(cb, null)
154
- },
155
- cb => core1.append('hello', cb),
156
- cb => core1.append('world', cb),
157
- cb => core2.append('cat', cb),
158
- cb => core2.append('dog', cb),
159
- cb => {
160
- t.same(core3.length, 0)
161
- t.same(core4.length, 0)
162
- return process.nextTick(cb, null)
163
- }
164
- ])
165
-
166
- await validateCore(t, core3, [Buffer.from('hello'), Buffer.from('world')])
167
- await validateCore(t, core4, [Buffer.from('cat'), Buffer.from('dog')])
168
- t.end()
169
- })
19
+ t.true(core1a.writable)
20
+ t.true(core1b.writable)
170
21
 
171
- test('ram-based corestore, sparse replication with different default keys', async t => {
172
- const store1 = await create(ram, { sparse: true })
173
- const store2 = await create(ram, { sparse: true })
174
- const core1 = store1.default()
175
- var core3 = null
176
- var core4 = null
177
-
178
- await runAll([
179
- cb => core1.ready(cb),
180
- cb => {
181
- core3 = store2.default()
182
- return core3.ready(cb)
183
- },
184
- cb => {
185
- const s1 = store1.replicate(true, { live: true })
186
- const s2 = store2.replicate(false, { live: true })
187
- s1.pipe(s2).pipe(s1)
188
- return process.nextTick(cb, null)
189
- },
190
- cb => core1.append('cat', cb),
191
- cb => core1.append('dog', cb),
192
- cb => {
193
- core4 = store2.get({ key: core1.key })
194
- return core4.ready(cb)
195
- },
196
- cb => {
197
- t.same(core4.length, 0)
198
- t.same(core1.length, 2)
199
- return process.nextTick(cb, null)
200
- }
201
- ])
202
-
203
- await validateCore(t, core4, [Buffer.from('cat'), Buffer.from('dog')])
204
- t.end()
205
- })
22
+ t.same(store.cores.size, 2)
206
23
 
207
- test('raf-based corestore, simple replication', async t => {
208
- const store1 = await create(path => raf(p.join('store1', path)))
209
- const store2 = await create(path => raf(p.join('store2', path)))
210
- const core1 = store1.default()
211
- const core2 = store1.get()
212
- var core3 = null
213
- var core4 = null
214
-
215
- await runAll([
216
- cb => core1.ready(cb),
217
- cb => core2.ready(cb),
218
- cb => {
219
- core3 = store2.default({ key: core1.key })
220
- return core3.ready(cb)
221
- },
222
- cb => {
223
- core4 = store2.get({ key: core2.key })
224
- return core4.ready(cb)
225
- },
226
- cb => core1.append('hello', cb),
227
- cb => core1.append('world', cb),
228
- cb => core2.append('cat', cb),
229
- cb => core2.append('dog', cb),
230
- cb => {
231
- setImmediate(() => {
232
- const stream = store1.replicate(true)
233
- stream.pipe(store2.replicate(false)).pipe(stream)
234
- stream.on('end', cb)
235
- })
236
- }
237
- ])
238
-
239
- await validateCore(t, core3, [Buffer.from('hello'), Buffer.from('world')])
240
- await validateCore(t, core4, [Buffer.from('cat'), Buffer.from('dog')])
241
- await cleanup(['store1', 'store2'])
242
24
  t.end()
243
25
  })
244
26
 
245
- test('raf-based corestore, close and reopen', async t => {
246
- var store = await create('test-store')
247
- var firstCore = store.default()
248
- var reopenedCore = null
249
-
250
- await runAll([
251
- cb => firstCore.ready(cb),
252
- cb => firstCore.append('hello', cb),
253
- cb => store.close(cb),
254
- cb => {
255
- t.true(firstCore.closed)
256
- return process.nextTick(cb, null)
257
- },
258
- cb => {
259
- create('test-store').then(store => {
260
- reopenedCore = store.default()
261
- return reopenedCore.ready(cb)
262
- })
263
- }
264
- ])
265
-
266
- await validateCore(t, reopenedCore, [Buffer.from('hello')])
267
- await cleanup(['test-store'])
268
- t.end()
269
- })
27
+ test('basic get with custom keypair', async function (t) {
28
+ const store = new Corestore(ram)
29
+ const kp1 = crypto.keyPair()
30
+ const kp2 = crypto.keyPair()
270
31
 
271
- test('raf-based corestore, close and reopen with keypair option', async t => {
272
- var store = await create('test-store')
273
- const keyPair = hypercoreCrypto.keyPair()
274
- var firstCore = store.get({ keyPair })
275
- var reopenedCore = null
276
-
277
- await runAll([
278
- cb => firstCore.ready(cb),
279
- cb => firstCore.append('hello', cb),
280
- cb => store.close(cb),
281
- cb => {
282
- t.true(firstCore.closed)
283
- return process.nextTick(cb, null)
284
- },
285
- cb => {
286
- create('test-store').then(store => {
287
- reopenedCore = store.get({ key: keyPair.publicKey })
288
- return reopenedCore.ready(cb)
289
- })
290
- }
291
- ])
292
-
293
- await validateCore(t, reopenedCore, [Buffer.from('hello')])
294
- t.true(reopenedCore.writable)
295
-
296
- await cleanup(['test-store'])
297
- t.end()
298
- })
32
+ const core1 = store.get(kp1)
33
+ const core2 = store.get(kp2)
34
+ await Promise.all([core1.ready(), core2.ready()])
35
+
36
+ t.same(core1.key, kp1.publicKey)
37
+ t.same(core2.key, kp2.publicKey)
38
+ t.true(core1.writable)
39
+ t.true(core2.writable)
299
40
 
300
- test('live replication with an additional core', async t => {
301
- const store1 = await create(ram)
302
- const store2 = await create(ram)
303
-
304
- const core1 = store1.default()
305
- var core2 = null
306
- var core3 = null
307
- var core4 = null
308
-
309
- await runAll([
310
- cb => core1.ready(cb),
311
- cb => {
312
- core3 = store2.default({ key: core1.key })
313
- return core3.ready(cb)
314
- },
315
- cb => {
316
- const stream = store1.replicate(true, { live: true })
317
- stream.pipe(store2.replicate(false, { live: true })).pipe(stream)
318
- return cb(null)
319
- },
320
- cb => {
321
- core2 = store1.get()
322
- return core2.ready(cb)
323
- },
324
- cb => {
325
- core4 = store2.get(core2.key)
326
- return core4.ready(cb)
327
- },
328
- cb => core2.append('hello', cb),
329
- cb => core2.append('world', cb)
330
- ])
331
-
332
- await validateCore(t, core4, [Buffer.from('hello'), Buffer.from('world')])
333
41
  t.end()
334
42
  })
335
43
 
336
- test('namespaced corestores use separate default keys', async t => {
337
- const store1 = await create(ram)
338
- const store2 = store1.namespace('store2')
339
- const store3 = store1.namespace('store3')
340
-
341
- await store2.ready()
342
- await store3.ready()
44
+ test('basic namespaces', async function (t) {
45
+ const store = new Corestore(ram)
46
+ const ns1 = store.namespace('ns1')
47
+ const ns2 = store.namespace('ns2')
48
+ const ns3 = store.namespace('ns1') // Duplicate namespace
343
49
 
344
- const feed1 = store2.default()
345
- const feed2 = store3.default()
50
+ const core1 = ns1.get({ name: 'main' })
51
+ const core2 = ns2.get({ name: 'main' })
52
+ const core3 = ns3.get({ name: 'main' })
53
+ await Promise.all([core1.ready(), core2.ready(), core3.ready()])
346
54
 
347
- t.true(!feed1.key.equals(feed2.key))
55
+ t.false(core1.key.equals(core2.key))
56
+ t.true(core1.key.equals(core3.key))
57
+ t.true(core1.writable)
58
+ t.true(core2.writable)
59
+ t.true(core3.writable)
60
+ t.same(store.cores.size, 2)
348
61
 
349
62
  t.end()
350
63
  })
351
64
 
352
- test('namespaced corestores will not increment reference multiple times', async t => {
353
- const store1 = await create(ram)
354
- const store2 = store1.namespace('store2')
355
- const store3 = store1.namespace('store3')
65
+ test('basic replication', async function (t) {
66
+ const store1 = new Corestore(ram)
67
+ const store2 = new Corestore(ram)
356
68
 
357
- await store2.ready()
358
- await store3.ready()
69
+ const core1 = store1.get({ name: 'core-1' })
70
+ const core2 = store1.get({ name: 'core-2' })
71
+ await core1.append('hello')
72
+ await core2.append('world')
359
73
 
360
- const feed1 = store2.default()
361
- await feed1.ready()
362
- const feed3 = store3.get({ key: feed1.key })
363
- const feed4 = store3.get({ key: feed1.key })
364
- const feed5 = store3.get({ key: feed1.key })
74
+ const core3 = store2.get({ key: core1.key })
75
+ const core4 = store2.get({ key: core2.key })
365
76
 
366
- t.same(feed1, feed3)
367
- t.same(feed1, feed4)
368
- t.same(feed1, feed5)
77
+ const s = store1.replicate(true)
78
+ s.pipe(store2.replicate(false)).pipe(s)
369
79
 
370
- const entry = store1.cache.entry(feed1.discoveryKey.toString('hex'))
371
- t.same(entry.refs, 2)
80
+ t.same(await core3.get(0), Buffer.from('hello'))
81
+ t.same(await core4.get(0), Buffer.from('world'))
372
82
 
373
83
  t.end()
374
84
  })
375
85
 
376
- test('namespaced corestores can be nested', async t => {
377
- const store1 = await create(ram)
378
- const store2 = store1.namespace('store2')
379
- const store1a = store1.namespace('a')
380
- const store2a = store2.namespace('a')
86
+ test('nested namespaces', async function (t) {
87
+ const store = new Corestore(ram)
88
+ const ns1a = store.namespace('ns1').namespace('a')
89
+ const ns1b = store.namespace('ns1').namespace('b')
381
90
 
382
- const feed1 = store1.default()
383
- const feed2 = store2.default()
384
- const feed1a = store1a.default()
385
- const feed2a = store2a.default()
91
+ const core1 = ns1a.get({ name: 'main' })
92
+ const core2 = ns1b.get({ name: 'main' })
93
+ await Promise.all([core1.ready(), core2.ready()])
386
94
 
387
- await feed1.ready()
388
- await feed2.ready()
389
- await feed1a.ready()
390
- await feed2a.ready()
391
-
392
- t.notEqual(feed1a.key, feed2a.key)
95
+ t.false(core1.key.equals(core2.key))
96
+ t.true(core1.writable)
97
+ t.true(core2.writable)
98
+ t.same(store.cores.size, 2)
393
99
 
394
100
  t.end()
395
101
  })
396
102
 
397
- test('caching works correctly when reopening by discovery key', async t => {
398
- var store = await create('test-store')
399
- var firstCore = store.default()
400
- var discoveryKey = null
401
- var reopenedCore = null
402
-
403
- await runAll([
404
- cb => firstCore.ready(cb),
405
- cb => {
406
- discoveryKey = firstCore.discoveryKey
407
- return cb(null)
408
- },
409
- cb => firstCore.append('hello', cb),
410
- cb => store.close(cb),
411
- cb => {
412
- t.true(firstCore.closed)
413
- return process.nextTick(cb, null)
414
- },
415
- cb => {
416
- create('test-store').then(reopenedStore => {
417
- store = reopenedStore
418
- reopenedCore = store.get({ discoveryKey })
419
- return reopenedCore.ready(cb)
420
- })
421
- },
422
- cb => {
423
- const idx = discoveryKey.toString('hex')
424
- t.true(store.cache.has(idx))
425
- return cb(null)
426
- }
427
- ])
428
-
429
- await validateCore(t, reopenedCore, [Buffer.from('hello')])
430
- await cleanup(['test-store'])
103
+ test('core uncached when all sessions close', async function (t) {
104
+ const store = new Corestore(ram)
105
+ const core1 = store.get({ name: 'main' })
106
+ await core1.ready()
107
+ t.same(store.cores.size, 1)
108
+ await core1.close()
109
+ t.same(store.cores.size, 0)
431
110
  t.end()
432
111
  })
433
112
 
434
- test('can check if cores are loaded', async t => {
435
- const store = await create(ram)
436
- await store.ready()
113
+ test('writable core loaded from name userData', async function (t) {
114
+ const dir = await tmp.dir({ unsafeCleanup: true })
115
+
116
+ let store = new Corestore(dir.path)
117
+ let core = store.get({ name: 'main' })
118
+ await core.ready()
119
+ const key = core.key
120
+
121
+ t.true(core.writable)
122
+ await core.append('hello')
123
+ t.same(core.length, 1)
437
124
 
438
- const feed1 = store.default()
439
- const feed2 = store.get()
440
- const badKey = hypercoreCrypto.randomBytes(32)
441
- const badDiscoveryKey = hypercoreCrypto.discoveryKey(badKey)
125
+ await store.close()
126
+ store = new Corestore(dir.path)
127
+ core = store.get(key)
128
+ await core.ready()
442
129
 
443
- t.true(store.isLoaded({ key: feed1.key }))
444
- t.true(store.isLoaded({ discoveryKey: feed1.discoveryKey }))
445
- t.true(store.isLoaded({ discoveryKey: feed2.discoveryKey }))
446
- t.false(store.isLoaded({ key: badKey }))
447
- t.false(store.isLoaded({ key: badDiscoveryKey }))
130
+ t.true(core.writable)
131
+ await core.append('world')
132
+ t.same(core.length, 2)
133
+ t.same(await core.get(0), Buffer.from('hello'))
134
+ t.same(await core.get(1), Buffer.from('world'))
448
135
 
136
+ await dir.cleanup()
449
137
  t.end()
450
138
  })
451
139
 
452
- test('top-level corestore replicates all opened cores', async t => {
453
- const store1 = await create(ram)
454
- const store2 = await create(ram)
455
-
456
- const core1 = store1.default()
457
- const ns1 = store1.namespace()
458
- var core2 = ns1.default()
459
- var core3 = null
460
-
461
- await runAll([
462
- cb => core1.ready(cb),
463
- cb => core2.ready(cb),
464
- cb => {
465
- // Only replicate the top-level corestore
466
- const stream = store1.replicate(true, { live: true })
467
- stream.pipe(store2.replicate(false, { live: true })).pipe(stream)
468
- return cb(null)
469
- },
470
- cb => {
471
- core3 = store2.get(core2.key)
472
- return core3.ready(cb)
473
- },
474
- cb => core2.append('hello', cb),
475
- cb => core2.append('world', cb)
476
- ])
477
-
478
- await validateCore(t, core3, [Buffer.from('hello'), Buffer.from('world')])
140
+ test('storage locking', async function (t) {
141
+ const dir = await tmp.dir({ unsafeCleanup: true })
142
+
143
+ const store1 = new Corestore(dir.path)
144
+ const store2 = new Corestore(dir.path)
145
+ await store1.ready()
146
+
147
+ try {
148
+ await store2.ready()
149
+ t.fail('dir should have been locked')
150
+ } catch {
151
+ t.pass('dir was locked')
152
+ }
153
+
154
+ await dir.cleanup()
479
155
  t.end()
480
156
  })
481
- async function create (storage, opts) {
482
- const store = new Corestore(storage, opts)
483
- await store.ready()
484
- return store
485
- }
@@ -1,37 +1,7 @@
1
- const rimraf = require('rimraf')
2
-
3
- function runAll (ops) {
4
- return new Promise((resolve, reject) => {
5
- runNext(ops.shift())
6
- function runNext (op) {
7
- op(err => {
8
- if (err) return reject(err)
9
- const next = ops.shift()
10
- if (!next) return resolve()
11
- return runNext(next)
12
- })
13
- }
14
- })
15
- }
16
-
17
- function validateCore (t, core, values) {
18
- const ops = values.map((v, idx) => cb => {
19
- core.get(idx, (err, value) => {
20
- t.error(err, 'no error')
21
- t.same(value, values[idx])
22
- return cb(null)
23
- })
24
- })
25
- return runAll(ops)
26
- }
1
+ const fs = require('fs').promises
27
2
 
28
3
  async function cleanup (dirs) {
29
- return Promise.all(dirs.map(dir => new Promise((resolve, reject) => {
30
- rimraf(dir, err => {
31
- if (err) return reject(err)
32
- return resolve()
33
- })
34
- })))
4
+ return Promise.allSettled(dirs.map(dir => fs.rmdir(dir, { recursive: true })))
35
5
  }
36
6
 
37
7
  function delay (ms, cb) {
@@ -45,7 +15,5 @@ function delay (ms, cb) {
45
15
 
46
16
  module.exports = {
47
17
  delay,
48
- cleanup,
49
- validateCore,
50
- runAll
18
+ cleanup
51
19
  }