UNPKG

30.6 kBJavaScriptView Raw
1const test = require('tape')
2const ram = require('random-access-memory')
3
4const Corestore = require('corestore')
5const Replicator = require('./helpers/replicator')
6const create = require('./helpers/create')
7const hyperdrive = require('../')
8
9test('basic read/write to/from a mount', t => {
10 const r = new Replicator(t)
11 const drive1 = create()
12 const drive2 = create()
13
14 r.replicate(drive1, drive2)
15
16 drive2.ready(err => {
17 t.error(err, 'no error')
18 drive2.writeFile('b', 'hello', err => {
19 t.error(err, 'no error')
20 drive1.mount('a', drive2.key, err => {
21 t.error(err, 'no error')
22 drive1.readFile('a/b', (err, contents) => {
23 t.error(err, 'no error')
24 t.same(contents, Buffer.from('hello'))
25 r.end()
26 })
27 })
28 })
29 })
30})
31
32test('should emit metadata-feed and content-feed events for all mounts', t => {
33 const r = new Replicator(t)
34 const drive1 = create()
35 const drive2 = create()
36
37 r.replicate(drive1, drive2)
38
39 var metadataCount = 0
40 var contentCount = 0
41
42 drive1.on('metadata-feed', () => {
43 metadataCount++
44 })
45 drive1.on('content-feed', () => {
46 contentCount++
47 })
48
49 drive2.ready(err => {
50 t.error(err, 'no error')
51 drive2.writeFile('hello', 'world', err => {
52 t.error(err, 'no error')
53 drive1.mount('a', drive2.key, err => {
54 t.error(err, 'no error')
55 drive1.readFile('a/hello', (err, content) => {
56 t.error(err, 'no error')
57 t.same(content, Buffer.from('world'))
58 checkEvents()
59 })
60 })
61 })
62 })
63
64 function checkEvents () {
65 t.same(contentCount, 2)
66 t.same(metadataCount, 2)
67 r.end()
68 }
69})
70
71test('can delete a mount', t => {
72 const r = new Replicator(t)
73 const drive1 = create()
74 const drive2 = create()
75
76 r.replicate(drive1, drive2)
77
78 drive2.ready(err => {
79 t.error(err, 'no error')
80 drive2.writeFile('b', 'hello', err => {
81 t.error(err, 'no error')
82 drive1.mount('a', drive2.key, err => {
83 t.error(err, 'no error')
84 drive1.readFile('a/b', (err, contents) => {
85 t.error(err, 'no error')
86 t.same(contents, Buffer.from('hello'))
87 return deleteMount()
88 })
89 })
90 })
91 })
92
93 function deleteMount () {
94 drive1.unmount('a', err => {
95 t.error(err, 'no error')
96 drive1.readFile('a/b', (err, contents) => {
97 t.true(err)
98 t.same(err.errno, 2)
99 r.end()
100 })
101 })
102 }
103})
104
105test('multiple flat mounts', t => {
106 const r = new Replicator(t)
107 const drive1 = create()
108 const drive2 = create()
109 const drive3 = create()
110
111 var key1, key2
112
113 r.replicate(drive1, drive2)
114 r.replicate(drive2, drive3)
115 r.replicate(drive1, drive3)
116
117 drive3.ready(err => {
118 t.error(err, 'no error')
119 drive2.ready(err => {
120 t.error(err, 'no error')
121 key1 = drive2.key
122 key2 = drive3.key
123 onready()
124 })
125 })
126
127 function onready () {
128 drive2.writeFile('a', 'hello', err => {
129 t.error(err, 'no error')
130 drive3.writeFile('b', 'world', err => {
131 t.error(err, 'no error')
132 onwrite()
133 })
134 })
135 }
136
137 function onwrite () {
138 drive1.mount('a', key1, err => {
139 t.error(err, 'no error')
140 drive1.mount('b', key2, err => {
141 t.error(err, 'no error')
142 onmount()
143 })
144 })
145 }
146
147 function onmount () {
148 drive1.readFile('a/a', (err, contents) => {
149 t.error(err, 'no error')
150 t.same(contents, Buffer.from('hello'))
151 drive1.readFile('b/b', (err, contents) => {
152 t.error(err, 'no error')
153 t.same(contents, Buffer.from('world'))
154 r.end()
155 })
156 })
157 }
158})
159
160test('recursive mounts', async t => {
161 const r = new Replicator(t)
162 const drive1 = create()
163 const drive2 = create()
164 const drive3 = create()
165
166 var key1, key2
167
168 r.replicate(drive1, drive2)
169 r.replicate(drive2, drive3)
170 r.replicate(drive1, drive3)
171
172 drive3.ready(err => {
173 t.error(err, 'no error')
174 drive2.ready(err => {
175 t.error(err, 'no error')
176 key1 = drive2.key
177 key2 = drive3.key
178 onready()
179 })
180 })
181
182 function onready () {
183 drive2.writeFile('a', 'hello', err => {
184 t.error(err, 'no error')
185 drive3.writeFile('b', 'world', err => {
186 t.error(err, 'no error')
187 onwrite()
188 })
189 })
190 }
191
192 function onwrite () {
193 drive1.mount('a', key1, err => {
194 t.error(err, 'no error')
195 drive2.mount('b', key2, err => {
196 t.error(err, 'no error')
197 onmount()
198 })
199 })
200 }
201
202 function onmount () {
203 drive1.readFile('a/a', (err, contents) => {
204 t.error(err, 'no error')
205 t.same(contents, Buffer.from('hello'))
206 drive1.readFile('a/b/b', (err, contents) => {
207 t.error(err, 'no error')
208 t.same(contents, Buffer.from('world'))
209 r.end()
210 })
211 })
212 }
213})
214
215test('readdir returns mounts', t => {
216 const r = new Replicator(t)
217 const drive1 = create()
218 const drive2 = create()
219
220 r.replicate(drive1, drive2)
221
222 drive2.ready(err => {
223 t.error(err, 'no error')
224 drive1.mkdir('b', err => {
225 t.error(err, 'no error')
226 drive1.mkdir('b/a', err => {
227 t.error(err, 'no error')
228 drive1.mount('a', drive2.key, err => {
229 t.error(err, 'no error')
230 drive1.readdir('/', (err, dirs) => {
231 t.error(err, 'no error')
232 t.same(dirs, ['b', 'a'])
233 r.end()
234 })
235 })
236 })
237 })
238 })
239})
240
241test('cross-mount watch', t => {
242 const r = new Replicator(t)
243 const drive1 = create()
244 const drive2 = create()
245
246 r.replicate(drive1, drive2)
247
248 var watchEvents = 0
249
250 drive2.ready(err => {
251 t.error(err, 'no error')
252 drive1.mount('a', drive2.key, err => {
253 t.error(err, 'no error')
254 drive1.watch('/', () => {
255 if (++watchEvents === 1) r.end()
256 })
257 drive2.writeFile('a', 'hello', err => {
258 t.error(err, 'no error')
259 })
260 })
261 })
262})
263
264test('cross-mount symlink', t => {
265 const r = new Replicator(t)
266 const drive1 = create()
267 const drive2 = create()
268
269 r.replicate(drive1, drive2)
270
271 drive2.ready(err => {
272 t.error(err, 'no error')
273 drive1.mount('a', drive2.key, err => {
274 t.error(err, 'no error')
275 onmount()
276 })
277 })
278
279 function onmount () {
280 drive2.writeFile('b', 'hello world', err => {
281 t.error(err, 'no error')
282 drive1.symlink('a/b', 'c', err => {
283 t.error(err, 'no error')
284 drive1.readFile('c', (err, contents) => {
285 t.error(err, 'no error')
286 t.same(contents, Buffer.from('hello world'))
287 r.end()
288 })
289 })
290 })
291 }
292})
293
294test('lists nested mounts, shared write capabilities', async t => {
295 const store = new Corestore(ram)
296 store.ready(onready)
297
298 function onready () {
299 const drive1 = create({ corestore: store, namespace: 'd1' })
300 const drive2 = create({ corestore: store, namespace: 'd2' })
301 const drive3 = create({ corestore: store, namespace: 'd3' })
302
303 drive3.ready(err => {
304 t.error(err, 'no error')
305 drive1.mount('a', drive2.key, err => {
306 t.error(err, 'no error')
307 drive1.mount('a/b', drive3.key, err => {
308 t.error(err, 'no error')
309 onmount(drive1, drive2, drive3)
310 })
311 })
312 })
313 }
314
315 function onmount (drive1, drive2, drive3) {
316 drive2.lstat('b', (err, stat) => {
317 t.error(err, 'no error')
318 drive1.readdir('a', (err, list) => {
319 t.error(err, 'no error')
320 t.same(list, ['b'])
321 t.end()
322 })
323 })
324 }
325})
326
327test('nested mount readdir returns correct mount', async t => {
328 const store = new Corestore(ram)
329 let expected = {}
330 store.ready(onready)
331
332 function onready () {
333 const drive1 = create({ corestore: store, namespace: 'd1' })
334 const drive2 = create({ corestore: store, namespace: 'd2' })
335 const drive3 = create({ corestore: store, namespace: 'd3' })
336
337 drive3.ready(err => {
338 t.error(err, 'no error')
339 drive1.mount('a', drive2.key, err => {
340 t.error(err, 'no error')
341 drive1.mount('a/b', drive3.key, err => {
342 t.error(err, 'no error')
343 drive1.writeFile('a/b/c', 'hello', err => {
344 t.error(err, 'no error')
345 expected['a'] = drive1.key
346 expected['a/b'] = drive2.key
347 expected['a/b/c'] = drive3.key
348 onmount(drive1, drive2, drive3)
349 })
350 })
351 })
352 })
353 }
354
355 function onmount (drive1, drive2, drive3) {
356 drive1.readdir('/', { recursive: true, includeStats: true }, (err, list) => {
357 t.error(err, 'no error')
358 let seen = 0
359 for (let { name, stat, mount } of list) {
360 t.true(expected[name] && expected[name].equals(mount.key), 'correct mount key')
361 seen++
362 }
363 t.same(seen, 3)
364 t.end()
365 })
366 }
367})
368
369test('nested mount readdir returns correct mount starting in mountpoint', async t => {
370 const store = new Corestore(ram)
371 let expected = {}
372 store.ready(onready)
373
374 function onready () {
375 const drive1 = create({ corestore: store, namespace: 'd1' })
376 const drive2 = create({ corestore: store, namespace: 'd2' })
377 const drive3 = create({ corestore: store, namespace: 'd3' })
378
379 drive3.ready(err => {
380 t.error(err, 'no error')
381 drive1.mount('a', drive2.key, err => {
382 t.error(err, 'no error')
383 drive1.mount('a/b', drive3.key, err => {
384 t.error(err, 'no error')
385 drive1.writeFile('a/b/c', 'hello', err => {
386 t.error(err, 'no error')
387 expected['b'] = drive2.key
388 expected['b/c'] = drive3.key
389 onmount(drive1, drive2, drive3)
390 })
391 })
392 })
393 })
394 }
395
396 function onmount (drive1, drive2, drive3) {
397 drive1.readdir('/a', { recursive: true, includeStats: true }, (err, list) => {
398 t.error(err, 'no error')
399 let seen = 0
400 for (let { name, stat, mount } of list) {
401 t.true(expected[name] && expected[name].equals(mount.key), 'correct mount key')
402 seen++
403 }
404 t.same(seen, 2)
405 t.end()
406 })
407 }
408})
409
410test('nested mount readdir returns correct stat modes', async t => {
411 const store = new Corestore(ram)
412 let expected = {}
413 store.ready(onready)
414
415 function onready () {
416 const drive1 = create({ corestore: store, namespace: 'd1' })
417 const drive2 = create({ corestore: store, namespace: 'd2' })
418 const drive3 = create({ corestore: store, namespace: 'd3' })
419
420 drive3.ready(err => {
421 t.error(err, 'no error')
422 drive1.mkdir('b', err => {
423 t.error(err, 'no error')
424 drive1.writeFile('b/c', 'hello', err => {
425 t.error(err, 'no error')
426 drive1.mount('a', drive2.key, err => {
427 t.error(err, 'no error')
428 drive1.mount('a/b', drive3.key, err => {
429 t.error(err, 'no error')
430 drive1.writeFile('a/b/c', 'hello', err => {
431 t.error(err, 'no error')
432 expected['a'] = 16877
433 expected['b'] = 16877
434 expected['b/c'] = 33188
435 expected['a/b'] = 16877
436 expected['a/b/c'] = 33188
437 onmount(drive1, drive2, drive3)
438 })
439 })
440 })
441 })
442 })
443 })
444 }
445
446 function onmount (drive1, drive2, drive3) {
447 drive1.readdir('/', { recursive: true, includeStats: true }, (err, list) => {
448 t.error(err, 'no error')
449 let seen = 0
450 for (let { name, stat, mount } of list) {
451 t.true(expected[name] && expected[name] === stat.mode, 'correct stat mode')
452 seen++
453 }
454 t.same(seen, 5)
455 t.end()
456 })
457 }
458})
459
460test('nested mount readdir returns correct stat modes, non-recursive', async t => {
461 const store = new Corestore(ram)
462 let expected = {}
463 store.ready(onready)
464
465 function onready () {
466 const drive1 = create({ corestore: store, namespace: 'd1' })
467 const drive2 = create({ corestore: store, namespace: 'd2' })
468 const drive3 = create({ corestore: store, namespace: 'd3' })
469
470 drive3.ready(err => {
471 t.error(err, 'no error')
472 drive1.writeFile('b/c', 'hello', err => {
473 t.error(err, 'no error')
474 drive1.mount('a', drive2.key, err => {
475 t.error(err, 'no error')
476 drive1.mount('a/b', drive3.key, err => {
477 t.error(err, 'no error')
478 drive1.writeFile('a/b/c', 'hello', err => {
479 t.error(err, 'no error')
480 expected['a'] = 16877
481 expected['b'] = 16877
482 onmount(drive1, drive2, drive3)
483 })
484 })
485 })
486 })
487 })
488 }
489
490 function onmount (drive1, drive2, drive3) {
491 drive1.readdir('/', { recursive: false, includeStats: true }, (err, list) => {
492 t.error(err, 'no error')
493 let seen = 0
494 for (let { name, stat, mount } of list) {
495 t.true(expected[name] && expected[name] === stat.mode, 'correct stat mode')
496 seen++
497 }
498 t.same(seen, 2)
499 t.end()
500 })
501 }
502})
503
504test('nested mount readdir returns correct inner paths, non-recursive', async t => {
505 const store = new Corestore(ram)
506 let expected = {}
507 store.ready(onready)
508
509 function onready () {
510 const drive1 = create({ corestore: store, namespace: 'd1' })
511 const drive2 = create({ corestore: store, namespace: 'd2' })
512 const drive3 = create({ corestore: store, namespace: 'd3' })
513
514 drive3.ready(err => {
515 t.error(err, 'no error')
516 drive1.writeFile('b/c', 'hello', err => {
517 t.error(err, 'no error')
518 drive1.mount('a', drive2.key, err => {
519 t.error(err, 'no error')
520 drive1.mount('a/b', drive3.key, err => {
521 t.error(err, 'no error')
522 drive1.writeFile('a/b/c', 'hello', err => {
523 t.error(err, 'no error')
524 expected['c'] = 'c'
525 onmount(drive1, drive2, drive3)
526 })
527 })
528 })
529 })
530 })
531 }
532
533 function onmount (drive1, drive2, drive3) {
534 drive1.readdir('/a/b', { recursive: false, includeStats: true }, (err, list) => {
535 t.error(err, 'no error')
536 let seen = 0
537 for (let { name, stat, mount, innerPath } of list) {
538 t.true(expected[name] && expected[name] === innerPath, 'correct stat mode')
539 seen++
540 }
541 t.same(seen, 1)
542 t.end()
543 })
544 }
545})
546
547test('nested mount readdir returns correct inner paths, recursive', async t => {
548 const store = new Corestore(ram)
549 let expected = {}
550 store.ready(onready)
551
552 function onready () {
553 const drive1 = create({ corestore: store, namespace: 'd1' })
554 const drive2 = create({ corestore: store, namespace: 'd2' })
555 const drive3 = create({ corestore: store, namespace: 'd3' })
556
557 drive3.ready(err => {
558 t.error(err, 'no error')
559 drive1.writeFile('b/c', 'hello', err => {
560 t.error(err, 'no error')
561 drive1.mount('a', drive2.key, err => {
562 t.error(err, 'no error')
563 drive1.mount('a/b', drive3.key, err => {
564 t.error(err, 'no error')
565 drive1.writeFile('a/b/c', 'hello', err => {
566 t.error(err, 'no error')
567 expected['a'] = 'a'
568 expected['a/b'] = 'b'
569 expected['b/c'] = 'b/c'
570 expected['a/b/c'] = 'c'
571 onmount(drive1, drive2, drive3)
572 })
573 })
574 })
575 })
576 })
577 }
578
579 function onmount (drive1, drive2, drive3) {
580 drive1.readdir('/', { recursive: true, includeStats: true }, (err, list) => {
581 t.error(err, 'no error')
582 let seen = 0
583 for (let { name, stat, mount, innerPath } of list) {
584 t.true(expected[name] && expected[name] === innerPath, 'correct stat mode')
585 seen++
586 }
587 t.same(seen, 4)
588 t.end()
589 })
590 }
591})
592
593test('independent corestores do not share write capabilities', t => {
594 const r = new Replicator(t)
595 const drive1 = create()
596 const drive2 = create()
597
598 r.replicate(drive1, drive2)
599
600 drive2.ready(err => {
601 t.error(err, 'no error')
602 drive1.mount('a', drive2.key, err => {
603 t.error(err, 'no error')
604 drive1.writeFile('a/b', 'hello', err => {
605 t.ok(err)
606 drive1.readFile('a/b', (err, contents) => {
607 t.ok(err)
608 r.end()
609 })
610 })
611 })
612 })
613})
614
615test('shared corestores will share write capabilities', async t => {
616 const store = new Corestore(ram)
617 store.ready(onready)
618
619 function onready () {
620 const drive1 = create({ corestore: store, namespace: 'ns1' })
621 const drive2 = create({ corestore: store, namespace: 'ns2' })
622
623 drive2.ready(err => {
624 t.error(err, 'no error')
625 drive1.mount('a', drive2.key, err => {
626 t.error(err, 'no error')
627 drive1.writeFile('a/b', 'hello', err => {
628 t.error(err, 'no error')
629 drive1.readFile('a/b', (err, contents) => {
630 t.error(err, 'no error')
631 t.same(contents, Buffer.from('hello'))
632 drive2.readFile('b', (err, contents) => {
633 t.error(err, 'no error')
634 t.same(contents, Buffer.from('hello'))
635 t.end()
636 })
637 })
638 })
639 })
640 })
641 }
642})
643
644test('can mount hypercores', async t => {
645 const store = new Corestore(ram)
646 store.ready(onready)
647
648 function onready () {
649 const drive = create({ corestore: store })
650 var core = store.get()
651
652 drive.ready(err => {
653 t.error(err, 'no error')
654 core.ready(err => {
655 t.error(err, 'no error')
656 core.append('hello', err => {
657 t.error(err, 'no error')
658 return onappend(drive, core)
659 })
660 })
661 })
662 }
663
664 function onappend (drive, core) {
665 drive.mount('/a', core.key, { hypercore: true }, err => {
666 t.error(err, 'no error')
667 drive.readFile('/a', (err, contents) => {
668 t.error(err, 'no error')
669 t.same(contents, Buffer.from('hello'))
670 t.end()
671 })
672 })
673 }
674})
675
676test('truncate within mount (with shared write capabilities)', async t => {
677 const store = new Corestore(ram)
678 store.ready(onready)
679
680 function onready () {
681
682 const drive1 = create({ corestore: store, namespace: 'ns1' })
683 const drive2 = create({ corestore: store, namespace: 'ns2' })
684
685 drive2.ready(err => {
686 t.error(err, 'no error')
687 drive1.mount('a', drive2.key, err => {
688 t.error(err, 'no error')
689 drive1.writeFile('a/b', 'hello', err => {
690 t.error(err, 'no error')
691 drive1.truncate('a/b', 1, err => {
692 t.error(err, 'no error')
693 drive1.readFile('a/b', (err, contents) => {
694 t.error(err, 'no error')
695 t.same(contents, Buffer.from('h'))
696 drive2.readFile('b', (err, contents) => {
697 t.error(err, 'no error')
698 t.same(contents, Buffer.from('h'))
699 t.end()
700 })
701 })
702 })
703 })
704 })
705 })
706 }
707})
708
709test('mount replication between hyperdrives', async t => {
710 const r = new Replicator(t)
711 const store1 = new Corestore(path => ram('cs1/' + path))
712 const store2 = new Corestore(path => ram('cs2/' + path))
713 const store3 = new Corestore(path => ram('cs3/' + path))
714
715 await new Promise(resolve => {
716 store1.ready(() => {
717 store2.ready(() => {
718 store3.ready(resolve)
719 })
720 })
721 })
722
723 const drive1 = create({ corestore: store1 })
724 const drive2 = create({ corestore: store2 })
725 var drive3 = null
726
727 await new Promise(resolve => {
728 drive1.ready(err => {
729 t.error(err, 'no error')
730 drive3 = create(drive1.key, { corestore: store3 })
731 drive2.ready(err => {
732 t.error(err, 'no error')
733 drive3.ready(err => {
734 t.error(err, 'no error')
735 r.replicate(drive1, drive2)
736 r.replicate(drive2, drive3)
737 r.replicate(drive1, drive3)
738 onready()
739 })
740 })
741 })
742
743 function onready () {
744 drive1.writeFile('hey', 'hi', err => {
745 t.error(err, 'no error')
746 drive2.writeFile('hello', 'world', err => {
747 t.error(err, 'no error')
748 drive1.mount('a', drive2.key, err => {
749 t.error(err, 'no error')
750 drive3.ready(err => {
751 t.error(err, 'no error')
752 return setTimeout(onmount, 100)
753 })
754 })
755 })
756 })
757 }
758
759 function onmount () {
760 drive3.readFile('hey', (err, contents) => {
761 t.error(err, 'no error')
762 t.same(contents, Buffer.from('hi'))
763 drive3.readFile('a/hello', (err, contents) => {
764 t.error(err, 'no error')
765 t.same(contents, Buffer.from('world'))
766 return resolve()
767 })
768 })
769 }
770 })
771
772 r.end()
773})
774
775test('mount replication between hyperdrives, multiple, nested mounts', async t => {
776 const r = new Replicator(t)
777 const [d1, d2] = await createMountee()
778 const drive = await createMounter(d1, d2)
779 await verify(drive)
780
781 r.end()
782
783 function createMountee () {
784 const store = new Corestore(path => ram('cs1/' + path))
785 const drive1 = create({ corestore: store, namespace: 'ns1' })
786 var drive2, drive3
787
788 return new Promise(resolve => {
789 drive1.ready(err => {
790 t.error(err, 'no error')
791 drive2 = create({ corestore: store, namespace: 'ns2' })
792 drive3 = create({ corestore: store, namespace: 'ns3' })
793 drive2.ready(err => {
794 t.error(err, 'no error')
795 drive3.ready(err => {
796 t.error(err, 'no error')
797 return onready()
798 })
799 })
800 })
801
802 function onready () {
803 drive1.mount('a', drive2.key, err => {
804 t.error(err, 'no error')
805 drive1.mount('b', drive3.key, err => {
806 t.error(err, 'no error')
807 return onmount()
808 })
809 })
810 }
811
812 function onmount () {
813 drive1.writeFile('a/dog', 'hello', err => {
814 t.error(err, 'no error')
815 drive1.writeFile('b/cat', 'goodbye', err => {
816 t.error(err, 'no error')
817 return resolve([drive2, drive3])
818 })
819 })
820 }
821 })
822 }
823
824 function createMounter (d2, d3) {
825 const store = new Corestore(path => ram('cs4/' + path))
826
827 return new Promise(resolve => {
828 store.ready(() => {
829 const drive1 = create({ corestore: store })
830 drive1.ready(err => {
831 t.error(err, 'no error')
832 r.replicate(drive1, d1)
833 r.replicate(d2, d3)
834 r.replicate(drive1, d3)
835 drive1.mount('a', d2.key, err => {
836 t.error(err, 'no error')
837 drive1.mount('b', d3.key, err => {
838 t.error(err, 'no error')
839 setTimeout(() => resolve(drive1), 1000)
840 })
841 })
842 })
843 })
844 })
845 }
846
847 function verify (drive) {
848 return new Promise(resolve => {
849 drive.readFile('a/dog', (err, contents) => {
850 t.error(err, 'no error')
851 t.same(contents, Buffer.from('hello'))
852 drive.readFile('b/cat', (err, contents) => {
853 t.error(err, 'no error')
854 t.same(contents, Buffer.from('goodbye'))
855 return resolve()
856 })
857 })
858 })
859 }
860})
861
862test('can list in-memory mounts', async t => {
863 const r = new Replicator(t)
864 const drive1 = create()
865 const drive2 = create()
866 const drive3 = create()
867
868 var key1, key2
869
870 r.replicate(drive1, drive2)
871 r.replicate(drive2, drive3)
872 r.replicate(drive1, drive3)
873
874 drive3.ready(err => {
875 t.error(err, 'no error')
876 drive2.ready(err => {
877 t.error(err, 'no error')
878 key1 = drive2.key
879 key2 = drive3.key
880 onready()
881 })
882 })
883
884 function onready () {
885 drive2.writeFile('a', 'hello', err => {
886 t.error(err, 'no error')
887 drive3.writeFile('b', 'world', err => {
888 t.error(err, 'no error')
889 onwrite()
890 })
891 })
892 }
893
894 function onwrite () {
895 drive1.mount('a', key1, err => {
896 t.error(err, 'no error')
897 drive1.mount('b', key2, err => {
898 t.error(err, 'no error')
899 onmount()
900 })
901 })
902 }
903
904 function onmount () {
905 drive1.readFile('a/a', (err, contents) => {
906 t.error(err, 'no error')
907 t.true(contents)
908 drive1.getAllMounts({ memory: true }, (err, mounts) => {
909 t.error(err, 'no error')
910 t.same(mounts.size, 3)
911 t.true(mounts.get('/'))
912 t.true(mounts.get('/a'))
913 r.end()
914 })
915 })
916 }
917})
918
919test('getAllMounts with no mounts returns only the root mount', async t => {
920 const drive1 = create()
921 drive1.ready(err => {
922 t.error(err, 'no error')
923 drive1.getAllMounts({ memory: true}, (err, mounts) => {
924 t.error(err, 'no error')
925 t.true(mounts)
926 t.same(mounts.size, 1)
927 t.end()
928 })
929 })
930})
931
932test('can list all mounts (including those not in memory)', async t => {
933 const r = new Replicator(t)
934 const drive1 = create()
935 const drive2 = create()
936 const drive3 = create()
937
938 var key1, key2
939
940 r.replicate(drive1, drive2)
941 r.replicate(drive2, drive3)
942 r.replicate(drive1, drive3)
943
944 drive3.ready(err => {
945 t.error(err, 'no error')
946 drive2.ready(err => {
947 t.error(err, 'no error')
948 key1 = drive2.key
949 key2 = drive3.key
950 onready()
951 })
952 })
953
954 function onready () {
955 drive2.writeFile('a', 'hello', err => {
956 t.error(err, 'no error')
957 drive3.writeFile('b', 'world', err => {
958 t.error(err, 'no error')
959 onwrite()
960 })
961 })
962 }
963
964 function onwrite () {
965 drive1.mount('a', key1, err => {
966 t.error(err, 'no error')
967 drive1.mount('b', key2, err => {
968 t.error(err, 'no error')
969 onmount()
970 })
971 })
972 }
973
974 function onmount () {
975 drive1.getAllMounts((err, mounts) => {
976 t.error(err, 'no error')
977 t.same(mounts.size, 3)
978 t.true(mounts.get('/'))
979 t.true(mounts.get('/a'))
980 t.true(mounts.get('/b'))
981 r.end()
982 })
983 }
984})
985
986test('can watch multiple mounts', async t => {
987 const r = new Replicator(t)
988 const drive1 = create()
989 const drive2 = create()
990 const drive3 = create()
991
992 var key1, key2
993
994 r.replicate(drive1, drive2)
995 r.replicate(drive2, drive3)
996 r.replicate(drive1, drive3)
997
998 drive3.ready(err => {
999 t.error(err, 'no error')
1000 drive2.ready(err => {
1001 t.error(err, 'no error')
1002 key1 = drive2.key
1003 key2 = drive3.key
1004 onready()
1005 })
1006 })
1007
1008 function onready () {
1009 drive1.mount('a', key1, err => {
1010 t.error(err, 'no error')
1011 drive1.mount('b', key2, err => {
1012 t.error(err, 'no error')
1013 onmount()
1014 })
1015 })
1016 }
1017
1018 function onmount () {
1019 var changes = 0
1020 const watcher = drive1.watch('', () => {
1021 changes++
1022 })
1023 watcher.on('ready', watchers => {
1024 t.same(watchers.length, 2)
1025 drive2.writeFile('a', 'hello', err => {
1026 t.error(err, 'no error')
1027 drive3.writeFile('b', 'world', err => {
1028 t.error(err, 'no error')
1029 setImmediate(() => {
1030 t.same(changes, 3)
1031 r.end()
1032 })
1033 })
1034 })
1035 })
1036 }
1037})
1038
1039test('can watch nested mounts', async t => {
1040 const r = new Replicator(t)
1041 const drive1 = create()
1042 const drive2 = create()
1043 const drive3 = create()
1044
1045 var key1, key2
1046
1047 r.replicate(drive1, drive2)
1048 r.replicate(drive2, drive3)
1049 r.replicate(drive1, drive3)
1050
1051 drive3.ready(err => {
1052 t.error(err, 'no error')
1053 drive2.ready(err => {
1054 t.error(err, 'no error')
1055 key1 = drive2.key
1056 key2 = drive3.key
1057 onready()
1058 })
1059 })
1060
1061 function onready () {
1062 drive1.mount('a', key1, err => {
1063 t.error(err, 'no error')
1064 drive2.mount('b', key2, err => {
1065 t.error(err, 'no error')
1066 onmount()
1067 })
1068 })
1069 }
1070
1071 function onmount () {
1072 var changes = 0
1073 const watcher = drive1.watch('', () => {
1074 changes++
1075 })
1076 watcher.on('ready', watchers => {
1077 t.same(watchers.length, 2)
1078 drive2.writeFile('a', 'hello', err => {
1079 t.error(err, 'no error')
1080 drive3.writeFile('b', 'world', err => {
1081 t.error(err, 'no error')
1082 setImmediate(() => {
1083 t.same(changes, 3)
1084 r.end()
1085 })
1086 })
1087 })
1088 })
1089 }
1090})
1091
1092test('can watch cyclic mounts', async t => {
1093 const r = new Replicator(t)
1094 const drive1 = create()
1095 const drive2 = create()
1096
1097 var key1, key2
1098
1099 r.replicate(drive1, drive2)
1100
1101 drive1.ready(err => {
1102 t.error(err, 'no error')
1103 drive2.ready(err => {
1104 t.error(err, 'no error')
1105 key1 = drive1.key
1106 key2 = drive2.key
1107 onready()
1108 })
1109 })
1110
1111 function onready () {
1112 drive1.mount('a', key2, err => {
1113 t.error(err, 'no error')
1114 drive2.mount('b', key1, err => {
1115 t.error(err, 'no error')
1116 onmount()
1117 })
1118 })
1119 }
1120
1121 function onmount () {
1122 var changes = 0
1123 const watcher = drive1.watch('', () => {
1124 changes++
1125 })
1126 watcher.on('ready', watchers => {
1127 t.same(watchers.length, 2)
1128 drive2.writeFile('c', 'hello', err => {
1129 t.error(err, 'no error')
1130 drive1.writeFile('c', 'world', err => {
1131 t.error(err, 'no error')
1132 setImmediate(() => {
1133 t.same(changes, 4)
1134 r.end()
1135 })
1136 })
1137 })
1138 })
1139 }
1140})
1141
1142test('readdir with noMounts will not traverse mounts', async t => {
1143 const r = new Replicator(t)
1144 const drive1 = create()
1145 const drive2 = create()
1146
1147 r.replicate(drive1, drive2)
1148
1149 drive2.ready(err => {
1150 t.error(err, 'no error')
1151 drive1.mkdir('b', err => {
1152 t.error(err, 'no error')
1153 drive1.mkdir('b/a', err => {
1154 t.error(err, 'no error')
1155 drive2.mkdir('c', err => {
1156 t.error(err, 'no error')
1157 drive1.mount('a', drive2.key, err => {
1158 t.error(err, 'no error')
1159 drive1.readdir('/', { recursive: true, noMounts: true}, (err, dirs) => {
1160 t.error(err, 'no error')
1161 t.same(dirs, ['b', 'b/a', 'a'])
1162 r.end()
1163 })
1164 })
1165 })
1166 })
1167 })
1168 })
1169})
1170
1171test('update does not clear the mount', function (t) {
1172 const drive = hyperdrive(ram)
1173 const other = hyperdrive(drive.corestore, null, { namespace: 'test' })
1174
1175 other.writeFile('/foo', 'bar', function (err) {
1176 t.error(err, 'no error')
1177 drive.mount('/bar', other.key, function (err) {
1178 t.error(err, 'no error')
1179 drive._update('/bar', {}, function (err) {
1180 t.error(err, 'no error')
1181 drive.readdir('/bar', function (err, files) {
1182 t.error(err, 'no error')
1183 t.same(files, ['foo'])
1184 t.end()
1185 })
1186 })
1187 })
1188 })
1189
1190})
1191
1192test('can list in-memory mounts recursively')
1193test('dynamically resolves cross-mount symlinks')
1194test('symlinks cannot break the sandbox')
1195test('versioned mount')
1196test('watch will unwatch on umount')