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