1 | const test = require('tape')
|
2 | const ram = require('random-access-memory')
|
3 | const Corestore = require('corestore')
|
4 |
|
5 | const Replicator = require('./helpers/replicator')
|
6 | const create = require('./helpers/create')
|
7 |
|
8 | test('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 |
|
50 | test('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 |
|
93 | test('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 |
|
138 | test('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 |
|
192 | test('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 |
|
252 | test('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 |
|
312 | test('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 |
|
344 | t.same(content.downloaded(), 3)
|
345 | t.end()
|
346 | })
|
347 | }
|
348 | })
|
349 |
|
350 | test('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 |
|
385 | t.same(content.downloaded(), 2)
|
386 | t.end()
|
387 | })
|
388 | }
|
389 | })
|
390 |
|
391 | test('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 |
|
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 |
|
433 | test('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 |
|
483 | test('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 |
|
536 | test('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 |
|
581 | function 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 | }
|