UNPKG

15 kBJavaScriptView Raw
1const test = require('tape')
2const ram = require('random-access-memory')
3const Corestore = require('corestore')
4
5const Replicator = require('./helpers/replicator')
6const create = require('./helpers/create')
7
8test('single-file download', t => {
9 const r = new Replicator(t)
10 const drive1 = create()
11 var drive2 = null
12
13 drive1.ready(err => {
14 t.error(err, 'no error')
15 drive2 = create(drive1.key)
16 drive2.ready(err => {
17 t.error(err, 'no error')
18 r.replicate(drive1, drive2)
19 onready()
20 })
21 })
22
23 function onready () {
24 drive1.writeFile('hello', 'world', err => {
25 t.error(err, 'no error')
26 setImmediate(() => {
27 drive2.stats('hello', (err, totals) => {
28 t.error(err, 'no error')
29 t.same(totals.blocks, 1)
30 t.same(totals.downloadedBlocks, 0)
31 const handle = drive2.download('hello')
32 ondownloading(handle)
33 })
34 })
35 })
36 }
37
38 function ondownloading (handle) {
39 handle.on('finish', () => {
40 drive2.stats('hello', (err, totals) => {
41 t.same(totals.downloadedBlocks, 1)
42 r.end()
43 })
44 })
45 handle.on('error', t.fail.bind(t))
46 handle.on('cancel', t.fail.bind(t))
47 }
48})
49
50test('download completion calls callback if provided', t => {
51 const r = new Replicator(t)
52 const drive1 = create()
53 var drive2 = null
54
55 drive1.ready(err => {
56 t.error(err, 'no error')
57 drive2 = create(drive1.key)
58 drive2.ready(err => {
59 t.error(err, 'no error')
60 r.replicate(drive1, drive2)
61 onready()
62 })
63 })
64
65 function onready () {
66 drive1.writeFile('hello', 'world', err => {
67 t.error(err, 'no error')
68 setImmediate(() => {
69 drive2.stats('hello', (err, totals) => {
70 t.error(err, 'no error')
71 t.same(totals.blocks, 1)
72 t.same(totals.downloadedBlocks, 0)
73 const handle = drive2.download('hello', onfinished)
74 ondownloading(handle)
75 })
76 })
77 })
78 }
79
80 function onfinished () {
81 drive2.stats('hello', (err, totals) => {
82 t.same(totals.downloadedBlocks, 1)
83 r.end()
84 })
85 }
86
87 function ondownloading (handle) {
88 handle.on('error', t.fail.bind(t))
89 handle.on('cancel', t.fail.bind(t))
90 }
91})
92
93test('directory download', t => {
94 const r = new Replicator(t)
95 const drive1 = create()
96 var drive2 = null
97
98 drive1.ready(err => {
99 t.error(err, 'no error')
100 drive2 = create(drive1.key)
101 drive2.ready(err => {
102 t.error(err, 'no error')
103 r.replicate(drive1, drive2)
104 onready()
105 })
106 })
107
108 function onready () {
109 drive1.writeFile('a/1', '1', err => {
110 t.error(err, 'no error')
111 drive1.writeFile('a/2', '2',err => {
112 t.error(err, 'no error')
113 drive1.writeFile('a/3', '3', err => {
114 t.error(err, 'no error')
115 setImmediate(() => {
116 const handle = drive2.download('a', { maxConcurrent: 1 })
117 ondownloading(handle)
118 })
119 })
120 })
121 })
122 }
123
124 function ondownloading (handle) {
125 handle.on('finish', () => {
126 drive2.stats('a', (err, totals) => {
127 t.error(err, 'no error')
128 t.same(totals.get('/a/1').downloadedBlocks, 1)
129 t.same(totals.get('/a/2').downloadedBlocks, 1)
130 t.same(totals.get('/a/3').downloadedBlocks, 1)
131 r.end()
132 })
133 })
134 handle.on('error', t.fail.bind(t))
135 }
136})
137
138test('download cancellation', t => {
139 const r = new Replicator(t)
140 const drive1 = create()
141 var drive2 = null
142
143 drive1.ready(err => {
144 t.error(err, 'no error')
145 drive2 = create(drive1.key)
146 drive2.ready(err => {
147 t.error(err, 'no error')
148 r.replicate(drive1, drive2, { throttle: 50 })
149 onready()
150 })
151 })
152
153 function onready () {
154 const writeStream = drive1.createWriteStream('a')
155 var chunks = 100
156 return write()
157
158 function write () {
159 writeStream.write(Buffer.alloc(1024 * 1024).fill('abcdefg'), err => {
160 if (err) return t.fail(err)
161 if (--chunks) return write()
162 return writeStream.end(() => {
163 return onwritten()
164 })
165 })
166 }
167 }
168
169 function onwritten () {
170 setTimeout(() => {
171 const handle = drive2.download('a', { detailed: true, statsInterval: 50 })
172 ondownloading(handle)
173 }, 500)
174 }
175
176 function ondownloading (handle) {
177 setTimeout(() => {
178 handle.destroy()
179 }, 1000)
180 handle.on('finish', (err, total, byFile) => {
181 if (err) t.fail(err)
182 drive2.stats('a', (err, totals) => {
183 t.error(err, 'no error')
184 t.true(totals.downloadedBlocks > 0 && totals.downloadedBlocks < 100)
185 r.end()
186 })
187 })
188 handle.on('error', t.fail.bind(t))
189 }
190})
191
192test('download omits mounts by default', t => {
193 const r = new Replicator(t)
194 const store = new Corestore(ram)
195 var drive1, mount, drive2
196
197 store.ready(() => {
198 drive1 = create({ corestore: store, namespace: 'd1' })
199 mount = create({ corestore: store, namespace: 'd2' })
200 drive1.ready(() => {
201 mount.ready(() => {
202 drive2 = create(drive1.key)
203 drive1.mount('b', mount.key, err => {
204 t.error(err)
205 drive2.ready(err => {
206 t.error(err, 'no error')
207 r.replicate(drive1, drive2)
208 onready()
209 })
210 })
211 })
212 })
213 })
214
215 function onready () {
216 mount.writeFile('hello', 'world', err => {
217 t.error(err)
218 drive1.writeFile('a/1', '1', err => {
219 t.error(err, 'no error')
220 drive1.writeFile('a/2', '2',err => {
221 t.error(err, 'no error')
222 drive1.writeFile('a/3', '3', err => {
223 t.error(err, 'no error')
224 setImmediate(() => {
225 const handle = drive2.download('/', { maxConcurrent: 1 })
226 ondownloading(handle)
227 })
228 })
229 })
230 })
231 })
232 }
233
234 function ondownloading (handle) {
235 handle.on('finish', () => {
236 drive2.stats('a', (err, totals) => {
237 t.error(err, 'no error')
238 t.same(totals.get('/a/1').downloadedBlocks, 1)
239 t.same(totals.get('/a/2').downloadedBlocks, 1)
240 t.same(totals.get('/a/3').downloadedBlocks, 1)
241 drive2.stats('b', (err, totals) => {
242 t.error(err, 'no error')
243 t.same(totals.get('/b/hello').downloadedBlocks, 0)
244 r.end()
245 })
246 })
247 })
248 handle.on('error', t.fail.bind(t))
249 }
250})
251
252test('download with noMounts false includes mounts', t => {
253 const r = new Replicator(t)
254 const store = new Corestore(ram)
255 var drive1, mount, drive2
256
257 store.ready(() => {
258 drive1 = create({ corestore: store, namespace: 'd1' })
259 mount = create({ corestore: store, namespace: 'd2' })
260 drive1.ready(() => {
261 mount.ready(() => {
262 drive2 = create(drive1.key)
263 drive1.mount('b', mount.key, err => {
264 t.error(err)
265 drive2.ready(err => {
266 t.error(err, 'no error')
267 r.replicate(drive1, drive2)
268 onready()
269 })
270 })
271 })
272 })
273 })
274
275 function onready () {
276 mount.writeFile('hello', 'world', err => {
277 t.error(err)
278 drive1.writeFile('a/1', '1', err => {
279 t.error(err, 'no error')
280 drive1.writeFile('a/2', '2',err => {
281 t.error(err, 'no error')
282 drive1.writeFile('a/3', '3', err => {
283 t.error(err, 'no error')
284 setImmediate(() => {
285 const handle = drive2.download('/', { maxConcurrent: 1, noMounts: false })
286 ondownloading(handle)
287 })
288 })
289 })
290 })
291 })
292 }
293
294 function ondownloading (handle) {
295 handle.on('finish', () => {
296 drive2.stats('a', (err, totals) => {
297 t.error(err, 'no error')
298 t.same(totals.get('/a/1').downloadedBlocks, 1)
299 t.same(totals.get('/a/2').downloadedBlocks, 1)
300 t.same(totals.get('/a/3').downloadedBlocks, 1)
301 drive2.stats('b', (err, totals) => {
302 t.error(err, 'no error')
303 t.same(totals.get('/b/hello').downloadedBlocks, 1)
304 r.end()
305 })
306 })
307 })
308 handle.on('error', t.fail.bind(t))
309 }
310})
311
312test('drive mirroring', t => {
313 const r = new Replicator(t)
314 const drive1 = create()
315 var drive2 = null
316
317 drive1.ready(err => {
318 t.error(err, 'no error')
319 drive2 = create(drive1.key)
320 drive2.ready(err => {
321 t.error(err, 'no error')
322 r.replicate(drive1, drive2)
323 onready()
324 })
325 })
326
327 function onready () {
328 drive1.writeFile('hello', 'world', () => {
329 drive1.writeFile('hello', 'world2', () => {
330 drive1.writeFile('hello', 'world3', () => {
331 drive2.mirror()
332 setImmediate(() => {
333 onmirroring()
334 })
335 })
336 })
337 })
338 }
339
340 function onmirroring () {
341 drive2.getContent((err, content) => {
342 t.error(err, 'no error')
343 // All versions of 'hello' should have been synced.
344 t.same(content.downloaded(), 3)
345 t.end()
346 })
347 }
348})
349
350test('can cancel a mirror', t => {
351 const r = new Replicator(t)
352 const drive1 = create()
353 var drive2 = null
354
355 drive1.ready(err => {
356 t.error(err, 'no error')
357 drive2 = create(drive1.key)
358 drive2.ready(err => {
359 t.error(err, 'no error')
360 r.replicate(drive1, drive2)
361 onready()
362 })
363 })
364
365 function onready () {
366 drive1.writeFile('hello', 'world', () => {
367 drive1.writeFile('hello', 'world2', () => {
368 const unmirror = drive2.mirror()
369 setImmediate(() => {
370 unmirror()
371 drive1.writeFile('hello', 'world3', () => {
372 setImmediate(() => {
373 onmirroring()
374 })
375 })
376 })
377 })
378 })
379 }
380
381 function onmirroring () {
382 drive2.getContent((err, content) => {
383 t.error(err, 'no error')
384 // Only the first two versions of 'hello' should have been synced.
385 t.same(content.downloaded(), 2)
386 t.end()
387 })
388 }
389})
390
391test('calling mirror is idempotent', t => {
392 const r = new Replicator(t)
393 const drive1 = create()
394 var drive2 = null
395
396 drive1.ready(err => {
397 t.error(err, 'no error')
398 drive2 = create(drive1.key)
399 drive2.ready(err => {
400 t.error(err, 'no error')
401 r.replicate(drive1, drive2)
402 onready()
403 })
404 })
405
406 function onready () {
407 drive1.writeFile('hello', 'world', () => {
408 drive1.writeFile('hello', 'world2', () => {
409 drive1.writeFile('hello', 'world3', () => {
410 drive2.mirror()
411 drive2.mirror()
412 drive2.mirror()
413 setImmediate(() => {
414 onmirroring()
415 })
416 })
417 })
418 })
419 }
420
421 function onmirroring () {
422 drive2.getContent((err, content) => {
423 t.error(err, 'no error')
424 // All versions of 'hello' should have been synced.
425 t.same(content.downloaded(), 3)
426 t.same(drive2.listeners('content-feed').length, 1)
427 t.same(drive2.listeners('metadata-feed').length, 1)
428 t.end()
429 })
430 }
431})
432
433test('mirroring also mirrors mounts', t => {
434 const r = new Replicator(t)
435 const store = new Corestore(ram)
436 var drive1, mount, drive2
437
438 store.ready(() => {
439 drive1 = create({ corestore: store, namespace: 'd1' })
440 mount = create({ corestore: store, namespace: 'd2' })
441 drive1.ready(() => {
442 mount.ready(() => {
443 drive2 = create(drive1.key)
444 drive1.mount('b', mount.key, err => {
445 t.error(err)
446 drive2.ready(err => {
447 t.error(err, 'no error')
448 r.replicate(drive1, drive2)
449 onready()
450 })
451 })
452 })
453 })
454 })
455
456 function onready () {
457 mount.writeFile('hello', 'world', () => {
458 mount.writeFile('hello', 'world2', () => {
459 drive1.writeFile('a', '1', () => {
460 drive1.writeFile('a', '2', () => {
461 drive2.mirror()
462 setImmediate(() => {
463 onmirroring()
464 })
465 })
466 })
467 })
468 })
469 }
470
471 function onmirroring () {
472 drive2.getAllMounts((err, mounts) => {
473 t.error(err, 'no error')
474 const root = mounts.get('/')
475 const bMount = mounts.get('/b')
476 t.same(root.content.downloaded(), 2)
477 t.same(bMount.content.downloaded(), 2)
478 t.end()
479 })
480 }
481})
482
483test('mirroring mirrors dynamically-added mounts', t => {
484 const r = new Replicator(t)
485 const store = new Corestore(ram)
486 var drive1, mount, drive2
487
488 store.ready(() => {
489 drive1 = create({ corestore: store, namespace: 'd1' })
490 mount = create({ corestore: store, namespace: 'd2' })
491 drive1.ready(() => {
492 mount.ready(() => {
493 drive2 = create(drive1.key)
494 drive2.mirror()
495 setImmediate(() => {
496 drive1.mount('b', mount.key, err => {
497 t.error(err)
498 drive2.ready(err => {
499 t.error(err, 'no error')
500 r.replicate(drive1, drive2)
501 onready()
502 })
503 })
504 })
505 })
506 })
507 })
508
509 function onready () {
510 mount.writeFile('hello', 'world', () => {
511 mount.writeFile('hello', 'world2', () => {
512 drive1.writeFile('a', '1', () => {
513 drive1.writeFile('a', '2', () => {
514 drive2.mirror()
515 setImmediate(() => {
516 onmirroring()
517 })
518 })
519 })
520 })
521 })
522 }
523
524 function onmirroring () {
525 drive2.getAllMounts((err, mounts) => {
526 t.error(err, 'no error')
527 const root = mounts.get('/')
528 const bMount = mounts.get('/b')
529 t.same(root.content.downloaded(), 2)
530 t.same(bMount.content.downloaded(), 2)
531 t.end()
532 })
533 }
534})
535
536test('last unmirror will clean up if mirror is called many times', t => {
537 const r = new Replicator(t)
538 const drive1 = create()
539 var drive2 = null
540 var unmirror = null
541 var initialCount = null
542
543 drive1.ready(err => {
544 t.error(err, 'no error')
545 drive2 = create(drive1.key)
546 drive2.ready(err => {
547 t.error(err, 'no error')
548 r.replicate(drive1, drive2)
549 initialCount = drive2.listenerCount('metadata-feed')
550 onready()
551 })
552 })
553
554 function onready () {
555 drive1.writeFile('hello', 'world', () => {
556 drive1.writeFile('hello', 'world2', () => {
557 drive1.writeFile('hello', 'world3', () => {
558 drive2.mirror()
559 drive2.mirror()
560 unmirror = drive2.mirror()
561 const mirrorCount = drive2.listenerCount('metadata-feed')
562 t.same(mirrorCount, initialCount + 1)
563 setImmediate(() => {
564 onmirroring()
565 })
566 })
567 })
568 })
569 }
570
571 function onmirroring () {
572 drive2.getContent((err, content) => {
573 t.same(content.downloaded(), 3)
574 unmirror()
575 t.same(drive2.listenerCount('metadata-feed'), initialCount)
576 t.end()
577 })
578 }
579})
580
581function printHandle (handle) {
582 handle.on('start', (...args) => console.log('start', args))
583 handle.on('progress', (...args) => console.log('progress', args))
584 handle.on('error', (...args) => console.log('error', args))
585 handle.on('finish', (...args) => console.log('finish', args))
586}