Files: 600f990b0583a4766c0311209cbe69cad38d2459 / tests / index.js
19663 bytesRaw
1 | const tape = require('tape') |
2 | const IPFS = require('ipfs') |
3 | const Hypervisor = require('../') |
4 | |
5 | const node = new IPFS() |
6 | |
7 | class BaseContainer { |
8 | constructor (kernel) { |
9 | this.kernel = kernel |
10 | } |
11 | |
12 | static createState (code) { |
13 | return { |
14 | nonce: [0], |
15 | ports: {} |
16 | } |
17 | } |
18 | } |
19 | |
20 | node.on('error', err => { |
21 | console.log(err) |
22 | }) |
23 | |
24 | node.on('start', () => { |
25 | tape.onFinish(() => { |
26 | node.stop(() => { |
27 | process.exit() |
28 | }) |
29 | }) |
30 | |
31 | tape('basic', async t => { |
32 | t.plan(2) |
33 | let message |
34 | const expectedState = { |
35 | '/': 'zdpuAntkdU7yBJojcBT5Q9wBhrK56NmLnwpHPKaEGMFnAXpv7' |
36 | } |
37 | |
38 | class testVMContainer extends BaseContainer { |
39 | run (m) { |
40 | t.true(m === message, 'should recive a message') |
41 | } |
42 | } |
43 | |
44 | const hypervisor = new Hypervisor(node.dag) |
45 | hypervisor.registerContainer('test', testVMContainer) |
46 | |
47 | const rootContainer = await hypervisor.createInstance('test') |
48 | const port = rootContainer.ports.create('test') |
49 | message = rootContainer.createMessage() |
50 | rootContainer.ports.bind(port, 'first') |
51 | |
52 | await rootContainer.send(port, message) |
53 | |
54 | const stateRoot = await hypervisor.createStateRoot(rootContainer, Infinity) |
55 | t.deepEquals(stateRoot, expectedState, 'expected root!') |
56 | }) |
57 | |
58 | tape('one child contract', async t => { |
59 | t.plan(4) |
60 | let message |
61 | const expectedState = { |
62 | '/': 'zdpuAofSzrBqwYs6z1r28fMeb8z5oSKF6CcWA6m22RqazgoTB' |
63 | } |
64 | let hasResolved = false |
65 | |
66 | class testVMContainer2 extends BaseContainer { |
67 | run (m) { |
68 | t.true(m === message, 'should recive a message 2') |
69 | return new Promise((resolve, reject) => { |
70 | setTimeout(() => { |
71 | this.kernel.incrementTicks(1) |
72 | hasResolved = true |
73 | resolve() |
74 | }, 200) |
75 | }) |
76 | } |
77 | } |
78 | |
79 | class testVMContainer extends BaseContainer { |
80 | async run (m) { |
81 | const port = this.kernel.ports.create('test2') |
82 | this.kernel.ports.bind(port, 'child') |
83 | await this.kernel.send(port, m) |
84 | this.kernel.incrementTicks(1) |
85 | } |
86 | } |
87 | |
88 | const hypervisor = new Hypervisor(node.dag) |
89 | hypervisor.registerContainer('test', testVMContainer) |
90 | hypervisor.registerContainer('test2', testVMContainer2) |
91 | |
92 | let root = await hypervisor.createInstance('test') |
93 | let port = root.ports.create('test') |
94 | |
95 | root.ports.bind(port, 'first') |
96 | message = root.createMessage() |
97 | |
98 | await root.send(port, message) |
99 | const stateRoot = await hypervisor.createStateRoot(root, Infinity) |
100 | t.true(hasResolved, 'should resolve before generating the state root') |
101 | t.deepEquals(stateRoot, expectedState, 'expected state') |
102 | |
103 | // test reviving the state |
104 | class testVMContainer3 extends BaseContainer { |
105 | async run (m) { |
106 | const port = this.kernel.ports.get('child') |
107 | await this.kernel.send(port, m) |
108 | this.kernel.incrementTicks(1) |
109 | } |
110 | } |
111 | |
112 | hypervisor.registerContainer('test', testVMContainer3) |
113 | root = await hypervisor.createInstance('test', stateRoot) |
114 | port = root.ports.get('first') |
115 | |
116 | root.send(port, message) |
117 | }) |
118 | |
119 | tape('ping pong', async t => { |
120 | class Ping extends BaseContainer { |
121 | async run (m) { |
122 | let port = this.kernel.ports.get('child') |
123 | if (!port) { |
124 | port = this.kernel.ports.create('pong') |
125 | this.kernel.ports.bind(port, 'child') |
126 | } |
127 | |
128 | if (this.kernel.ticks < 100) { |
129 | this.kernel.incrementTicks(1) |
130 | return this.kernel.send(port, this.kernel.createMessage()) |
131 | } |
132 | } |
133 | } |
134 | |
135 | class Pong extends BaseContainer { |
136 | run (m) { |
137 | const port = m.fromPort |
138 | this.kernel.incrementTicks(2) |
139 | return this.kernel.send(port, this.kernel.createMessage()) |
140 | } |
141 | } |
142 | |
143 | const hypervisor = new Hypervisor(node.dag) |
144 | |
145 | hypervisor.registerContainer('ping', Ping) |
146 | hypervisor.registerContainer('pong', Pong) |
147 | const root = await hypervisor.createInstance('pong') |
148 | const port = root.ports.create('ping') |
149 | root.ports.bind(port, 'child') |
150 | |
151 | await root.send(port, root.createMessage()) |
152 | await hypervisor.createStateRoot(root, Infinity) |
153 | |
154 | t.end() |
155 | }) |
156 | |
157 | tape('queing multiple messages', async t => { |
158 | t.plan(2) |
159 | let runs = 0 |
160 | |
161 | class Root extends BaseContainer { |
162 | async run (m) { |
163 | const one = this.kernel.ports.create('child') |
164 | const two = this.kernel.ports.create('child') |
165 | const three = this.kernel.ports.create('child') |
166 | |
167 | this.kernel.ports.bind(one, 'one') |
168 | this.kernel.ports.bind(two, 'two') |
169 | this.kernel.ports.bind(three, 'three') |
170 | |
171 | await Promise.all([ |
172 | this.kernel.send(one, this.kernel.createMessage()), |
173 | this.kernel.send(two, this.kernel.createMessage()), |
174 | this.kernel.send(three, this.kernel.createMessage()) |
175 | ]) |
176 | |
177 | return new Promise((resolve, reject) => { |
178 | setTimeout(() => { |
179 | this.kernel.incrementTicks(6) |
180 | resolve() |
181 | }, 200) |
182 | }) |
183 | } |
184 | } |
185 | |
186 | class Child extends BaseContainer { |
187 | run (m) { |
188 | runs++ |
189 | this.kernel.incrementTicks(2) |
190 | } |
191 | } |
192 | |
193 | const hypervisor = new Hypervisor(node.dag) |
194 | |
195 | hypervisor.registerContainer('root', Root) |
196 | hypervisor.registerContainer('child', Child) |
197 | |
198 | const root = await hypervisor.createInstance('root') |
199 | const port = root.ports.create('root') |
200 | root.ports.bind(port, 'first') |
201 | |
202 | await root.send(port, root.createMessage()) |
203 | await root.wait(Infinity) |
204 | |
205 | t.equals(runs, 3, 'the number of run should be 3') |
206 | const nonce = await hypervisor.graph.get(root.state, 'ports/first/link/nonce/0') |
207 | t.equals(nonce, 3, 'should have the correct nonce') |
208 | }) |
209 | |
210 | tape('traps', async t => { |
211 | t.plan(1) |
212 | class Root extends BaseContainer { |
213 | async run (m) { |
214 | const one = this.kernel.ports.create('child') |
215 | const two = this.kernel.ports.create('child') |
216 | const three = this.kernel.ports.create('child') |
217 | |
218 | this.kernel.ports.bind(one, 'one') |
219 | this.kernel.ports.bind(two, 'two') |
220 | this.kernel.ports.bind(three, 'three') |
221 | |
222 | throw new Error('it is a trap!!!') |
223 | } |
224 | } |
225 | |
226 | const hypervisor = new Hypervisor(node.dag) |
227 | |
228 | hypervisor.registerContainer('root', Root) |
229 | const root = await hypervisor.createInstance('root') |
230 | await root.run() |
231 | |
232 | t.deepEquals(root.state, { |
233 | '/': { |
234 | nonce: [0], |
235 | ports: {} |
236 | } |
237 | }, 'should revert the state') |
238 | }) |
239 | |
240 | tape('invalid port referances', async t => { |
241 | t.plan(2) |
242 | class Root extends BaseContainer { |
243 | async run (m) { |
244 | const port = this.kernel.ports.create('root') |
245 | this.kernel.ports.bind(port, 'three') |
246 | this.kernel.ports.delete('three') |
247 | try { |
248 | await this.kernel.send(port, this.kernel.createMessage()) |
249 | } catch (e) { |
250 | t.pass() |
251 | } |
252 | } |
253 | } |
254 | |
255 | const hypervisor = new Hypervisor(node.dag) |
256 | |
257 | hypervisor.registerContainer('root', Root) |
258 | const root = await hypervisor.createInstance('root') |
259 | await root.run() |
260 | |
261 | t.deepEquals(root.state, { |
262 | '/': { |
263 | nonce: [1], |
264 | ports: {} |
265 | } |
266 | }) |
267 | }) |
268 | |
269 | tape('message should arrive in the correct oder if sent in order', async t => { |
270 | t.plan(2) |
271 | |
272 | class Root extends BaseContainer { |
273 | async run (m) { |
274 | if (!this.runs) { |
275 | this.runs = 1 |
276 | const one = this.kernel.ports.create('first') |
277 | const two = this.kernel.ports.create('second') |
278 | |
279 | this.kernel.ports.bind(one, 'one') |
280 | this.kernel.ports.bind(two, 'two') |
281 | |
282 | await Promise.all([ |
283 | this.kernel.send(one, this.kernel.createMessage()), |
284 | this.kernel.send(two, this.kernel.createMessage()) |
285 | ]) |
286 | |
287 | this.kernel.incrementTicks(6) |
288 | } else if (this.runs === 1) { |
289 | this.runs++ |
290 | t.equals(m.data, 'first', 'should recive the first message') |
291 | } else if (this.runs === 2) { |
292 | t.equals(m.data, 'second', 'should recived the second message') |
293 | } |
294 | } |
295 | } |
296 | |
297 | class First extends BaseContainer { |
298 | async run (m) { |
299 | this.kernel.incrementTicks(1) |
300 | await this.kernel.send(m.fromPort, this.kernel.createMessage({data: 'first'})) |
301 | } |
302 | } |
303 | |
304 | class Second extends BaseContainer { |
305 | async run (m) { |
306 | this.kernel.incrementTicks(2) |
307 | await this.kernel.send(m.fromPort, this.kernel.createMessage({data: 'second'})) |
308 | } |
309 | } |
310 | |
311 | const hypervisor = new Hypervisor(node.dag) |
312 | |
313 | hypervisor.registerContainer('root', Root) |
314 | hypervisor.registerContainer('first', First) |
315 | hypervisor.registerContainer('second', Second) |
316 | |
317 | const root = await hypervisor.createInstance('root') |
318 | const port = root.ports.create('root') |
319 | root.ports.bind(port, 'first') |
320 | |
321 | root.send(port, root.createMessage()) |
322 | }) |
323 | |
324 | tape('message should arrive in the correct order, even if sent out of order', async t => { |
325 | t.plan(2) |
326 | |
327 | class Root extends BaseContainer { |
328 | run (m) { |
329 | if (!this.runs) { |
330 | this.runs = 1 |
331 | const one = this.kernel.ports.create('first') |
332 | const two = this.kernel.ports.create('second') |
333 | |
334 | this.kernel.ports.bind(one, 'one') |
335 | this.kernel.ports.bind(two, 'two') |
336 | |
337 | return Promise.all([ |
338 | this.kernel.send(one, this.kernel.createMessage()), |
339 | this.kernel.send(two, this.kernel.createMessage()) |
340 | ]) |
341 | } else if (this.runs === 1) { |
342 | this.runs++ |
343 | t.equals(m.data, 'second', 'should recive the first message') |
344 | } else if (this.runs === 2) { |
345 | t.equals(m.data, 'first', 'should recived the second message') |
346 | } |
347 | } |
348 | } |
349 | |
350 | class First extends BaseContainer { |
351 | run (m) { |
352 | this.kernel.incrementTicks(2) |
353 | return this.kernel.send(m.fromPort, this.kernel.createMessage({data: 'first'})) |
354 | } |
355 | } |
356 | |
357 | class Second extends BaseContainer { |
358 | run (m) { |
359 | this.kernel.incrementTicks(1) |
360 | this.kernel.send(m.fromPort, this.kernel.createMessage({data: 'second'})) |
361 | } |
362 | } |
363 | |
364 | const hypervisor = new Hypervisor(node.dag) |
365 | |
366 | hypervisor.registerContainer('root', Root) |
367 | hypervisor.registerContainer('first', First) |
368 | hypervisor.registerContainer('second', Second) |
369 | |
370 | const root = await hypervisor.createInstance('root') |
371 | const port = root.ports.create('root') |
372 | root.ports.bind(port, 'first') |
373 | |
374 | root.send(port, root.createMessage()) |
375 | }) |
376 | |
377 | tape('message should arrive in the correct order, even in a tie of ticks', async t => { |
378 | t.plan(2) |
379 | |
380 | class Root extends BaseContainer { |
381 | async run (m) { |
382 | if (!this.runs) { |
383 | this.runs = 1 |
384 | const one = this.kernel.ports.create('first') |
385 | const two = this.kernel.ports.create('second') |
386 | |
387 | this.kernel.ports.bind(one, 'one') |
388 | this.kernel.ports.bind(two, 'two') |
389 | |
390 | await Promise.all([ |
391 | this.kernel.send(one, this.kernel.createMessage()), |
392 | this.kernel.send(two, this.kernel.createMessage()) |
393 | ]) |
394 | |
395 | this.kernel.incrementTicks(6) |
396 | } else if (this.runs === 1) { |
397 | this.runs++ |
398 | t.equals(m.data, 'first', 'should recived the second message') |
399 | } else if (this.runs === 2) { |
400 | t.equals(m.data, 'second', 'should recive the first message') |
401 | } |
402 | } |
403 | } |
404 | |
405 | class First extends BaseContainer { |
406 | run (m) { |
407 | this.kernel.incrementTicks(2) |
408 | return this.kernel.send(m.fromPort, this.kernel.createMessage({ |
409 | data: 'first' |
410 | })) |
411 | } |
412 | } |
413 | |
414 | class Second extends BaseContainer { |
415 | run (m) { |
416 | this.kernel.incrementTicks(2) |
417 | return this.kernel.send(m.fromPort, this.kernel.createMessage({ |
418 | data: 'second' |
419 | })) |
420 | } |
421 | } |
422 | |
423 | const hypervisor = new Hypervisor(node.dag) |
424 | |
425 | hypervisor.registerContainer('root', Root) |
426 | hypervisor.registerContainer('first', First) |
427 | hypervisor.registerContainer('second', Second) |
428 | |
429 | const root = await hypervisor.createInstance('root') |
430 | const port = await root.ports.create('root') |
431 | root.ports.bind(port, 'first') |
432 | root.send(port, root.createMessage()) |
433 | }) |
434 | |
435 | tape('message should arrive in the correct order, even in a tie of ticks', async t => { |
436 | t.plan(2) |
437 | |
438 | class Root extends BaseContainer { |
439 | run (m) { |
440 | if (!this.runs) { |
441 | this.runs = 1 |
442 | const two = this.kernel.ports.create('second') |
443 | const one = this.kernel.ports.create('first') |
444 | |
445 | this.kernel.ports.bind(two, 'two') |
446 | this.kernel.ports.bind(one, 'one') |
447 | |
448 | return Promise.all([ |
449 | this.kernel.send(two, this.kernel.createMessage()), |
450 | this.kernel.send(one, this.kernel.createMessage()) |
451 | ]) |
452 | } else if (this.runs === 1) { |
453 | this.runs++ |
454 | t.equals(m.data, 'second', 'should recive the first message') |
455 | } else if (this.runs === 2) { |
456 | t.equals(m.data, 'first', 'should recived the second message') |
457 | } |
458 | } |
459 | } |
460 | |
461 | class First extends BaseContainer { |
462 | run (m) { |
463 | this.kernel.incrementTicks(2) |
464 | return this.kernel.send(m.fromPort, this.kernel.createMessage({ |
465 | data: 'first' |
466 | })) |
467 | } |
468 | } |
469 | |
470 | class Second extends BaseContainer { |
471 | run (m) { |
472 | this.kernel.incrementTicks(2) |
473 | return this.kernel.send(m.fromPort, this.kernel.createMessage({ |
474 | data: 'second' |
475 | })) |
476 | } |
477 | } |
478 | |
479 | const hypervisor = new Hypervisor(node.dag) |
480 | |
481 | hypervisor.registerContainer('root', Root) |
482 | hypervisor.registerContainer('first', First) |
483 | hypervisor.registerContainer('second', Second) |
484 | |
485 | const root = await hypervisor.createInstance('root') |
486 | |
487 | const port = root.ports.create('root') |
488 | root.ports.bind(port, 'first') |
489 | |
490 | root.send(port, root.createMessage()) |
491 | }) |
492 | |
493 | tape('message should arrive in the correct order, with a tie in ticks but with differnt proity', async t => { |
494 | t.plan(2) |
495 | |
496 | class Root extends BaseContainer { |
497 | run (m) { |
498 | if (!this.runs) { |
499 | this.runs = 1 |
500 | const one = this.kernel.ports.create('first') |
501 | const two = this.kernel.ports.create('second') |
502 | |
503 | this.kernel.ports.bind(one, 'one') |
504 | this.kernel.ports.bind(two, 'two') |
505 | |
506 | return Promise.all([ |
507 | this.kernel.send(two, this.kernel.createMessage()), |
508 | this.kernel.send(one, this.kernel.createMessage()) |
509 | ]) |
510 | } else if (this.runs === 1) { |
511 | this.runs++ |
512 | t.equals(m.data, 'first', 'should recive the first message') |
513 | } else if (this.runs === 2) { |
514 | t.equals(m.data, 'second', 'should recived the second message') |
515 | } |
516 | } |
517 | } |
518 | |
519 | class First extends BaseContainer { |
520 | run (m) { |
521 | this.kernel.incrementTicks(2) |
522 | return this.kernel.send(m.fromPort, this.kernel.createMessage({ |
523 | resources: { |
524 | priority: 100 |
525 | }, |
526 | data: 'first' |
527 | })) |
528 | } |
529 | } |
530 | |
531 | class Second extends BaseContainer { |
532 | run (m) { |
533 | this.kernel.incrementTicks(2) |
534 | return this.kernel.send(m.fromPort, this.kernel.createMessage({ |
535 | data: 'second' |
536 | })) |
537 | } |
538 | } |
539 | |
540 | const hypervisor = new Hypervisor(node.dag) |
541 | |
542 | hypervisor.registerContainer('root', Root) |
543 | hypervisor.registerContainer('first', First) |
544 | hypervisor.registerContainer('second', Second) |
545 | |
546 | const root = await hypervisor.createInstance('root') |
547 | const port = root.ports.create('root') |
548 | root.ports.bind(port, 'first') |
549 | root.send(port, root.createMessage()) |
550 | }) |
551 | |
552 | tape('message should arrive in the correct order, with a tie in ticks but with differnt proity', async t => { |
553 | t.plan(2) |
554 | |
555 | class Root extends BaseContainer { |
556 | run (m) { |
557 | if (!this.runs) { |
558 | this.runs = 1 |
559 | |
560 | const one = this.kernel.ports.create('first') |
561 | const two = this.kernel.ports.create('second') |
562 | |
563 | this.kernel.ports.bind(one, 'one') |
564 | this.kernel.ports.bind(two, 'two') |
565 | |
566 | return Promise.all([ |
567 | this.kernel.send(two, this.kernel.createMessage()), |
568 | this.kernel.send(one, this.kernel.createMessage()) |
569 | ]) |
570 | } else if (this.runs === 1) { |
571 | this.runs++ |
572 | t.equals(m.data, 'second', 'should recive the first message') |
573 | } else if (this.runs === 2) { |
574 | t.equals(m.data, 'first', 'should recived the second message') |
575 | } |
576 | } |
577 | } |
578 | |
579 | class First extends BaseContainer { |
580 | run (m) { |
581 | this.kernel.incrementTicks(2) |
582 | return this.kernel.send(m.fromPort, this.kernel.createMessage({ |
583 | data: 'first' |
584 | })) |
585 | } |
586 | } |
587 | |
588 | class Second extends BaseContainer { |
589 | run (m) { |
590 | this.kernel.incrementTicks(2) |
591 | return this.kernel.send(m.fromPort, this.kernel.createMessage({ |
592 | resources: { |
593 | priority: 100 |
594 | }, |
595 | data: 'second' |
596 | })) |
597 | } |
598 | } |
599 | |
600 | const hypervisor = new Hypervisor(node.dag) |
601 | |
602 | hypervisor.registerContainer('root', Root) |
603 | hypervisor.registerContainer('first', First) |
604 | hypervisor.registerContainer('second', Second) |
605 | |
606 | const root = await hypervisor.createInstance('root') |
607 | const port = root.ports.create('root') |
608 | root.ports.bind(port, 'first') |
609 | root.send(port, root.createMessage()) |
610 | }) |
611 | |
612 | tape('should order parent messages correctly', async t => { |
613 | t.plan(1) |
614 | class Middle extends BaseContainer { |
615 | run (m) { |
616 | if (!this.runs) { |
617 | this.runs = 1 |
618 | this.kernel.incrementTicks(1) |
619 | |
620 | const leaf = this.kernel.ports.create('leaf') |
621 | this.kernel.ports.bind(leaf, 'leaf') |
622 | |
623 | return this.kernel.send(leaf, this.kernel.createMessage()) |
624 | } else { |
625 | ++this.runs |
626 | if (this.runs === 3) { |
627 | t.equals(m.data, 'first') |
628 | } |
629 | } |
630 | } |
631 | } |
632 | |
633 | class Leaf extends BaseContainer { |
634 | run (m) { |
635 | this.kernel.incrementTicks(2) |
636 | return this.kernel.send(m.fromPort, this.kernel.createMessage({ |
637 | data: 'first' |
638 | })) |
639 | } |
640 | } |
641 | |
642 | const hypervisor = new Hypervisor(node.dag) |
643 | |
644 | hypervisor.registerContainer('root', BaseContainer) |
645 | hypervisor.registerContainer('middle', Middle) |
646 | hypervisor.registerContainer('leaf', Leaf) |
647 | |
648 | const root = await hypervisor.createInstance('root') |
649 | root.incrementTicks(2) |
650 | |
651 | const port = root.ports.create('middle') |
652 | root.ports.bind(port, 'first') |
653 | |
654 | await root.send(port, root.createMessage()) |
655 | root.send(port, root.createMessage()) |
656 | }) |
657 | |
658 | tape('get container instance by path', async t => { |
659 | t.plan(1) |
660 | const hypervisor = new Hypervisor(node.dag) |
661 | hypervisor.registerContainer('base', BaseContainer) |
662 | |
663 | const root = await hypervisor.createInstance('base') |
664 | let port = root.ports.create('base') |
665 | root.ports.bind(port, 'first') |
666 | |
667 | const first = await root.getInstance(port) |
668 | port = first.ports.create('base') |
669 | first.ports.bind(port, 'second') |
670 | |
671 | const second = await first.getInstance(port) |
672 | port = second.ports.create('base') |
673 | second.ports.bind(port, 'third') |
674 | |
675 | const third = await second.getInstance(port) |
676 | const foundThird = await hypervisor.getInstanceByPath(root, 'first/second/third') |
677 | t.equals(third, foundThird, 'should find by path') |
678 | }) |
679 | |
680 | tape('copy ports', async t => { |
681 | t.plan(1) |
682 | const hypervisor = new Hypervisor(node.dag) |
683 | hypervisor.registerContainer('base', BaseContainer) |
684 | |
685 | const root = await hypervisor.createInstance('base') |
686 | let port = root.ports.create('base') |
687 | let port2 = root.ports.copy(port) |
688 | |
689 | t.equals(port2.type, port.type, 'should copy port type') |
690 | }) |
691 | }) |
692 |
Built with git-ssb-web