git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: fe17252ec249e039c0e509ba0d745ca0da354881

Files: fe17252ec249e039c0e509ba0d745ca0da354881 / tests / index.js

31095 bytesRaw
1const tape = require('tape')
2const AbstractContainer = require('primea-abstract-container')
3const Message = require('primea-message')
4const Hypervisor = require('../')
5
6const level = require('level')
7const RadixTree = require('dfinity-radix-tree')
8const db = level('./testdb')
9
10class CreationMessage extends Message {
11 constructor (params) {
12 const buf = [Buffer.from([0x0]), Buffer.from([params.data.type])]
13 if (params.data.code) {
14 buf.push(params.data.code)
15 }
16 params.data = Buffer.concat(buf)
17 super(params)
18 }
19}
20
21class BaseContainer extends AbstractContainer {
22 onCreation (message) {
23 const port = message.ports[0]
24 if (port) {
25 return this.kernel.ports.bind('root', port)
26 }
27 }
28 static get typeId () {
29 return 9
30 }
31}
32
33tape('basic', async t => {
34 t.plan(3)
35 let message
36 const expectedState = {
37 '/': Buffer.from('646e7b89a3a4bb5dd6d43d1a7a29c69e72943bcd', 'hex')
38 }
39
40 const tree = new RadixTree({
41 db: db
42 })
43
44 class testVMContainer extends BaseContainer {
45 onMessage (m) {
46 t.true(m === message, 'should recive a message')
47 }
48 }
49
50 const hypervisor = new Hypervisor(tree)
51 hypervisor.registerContainer(testVMContainer)
52
53 const port = hypervisor.creationService.getPort()
54
55 let rootContainer = await hypervisor.send(port, new CreationMessage({
56 data: {
57 type: testVMContainer.typeId
58 }
59 }))
60
61 rootContainer = await hypervisor.getInstance(rootContainer.id)
62 hypervisor.pin(rootContainer)
63
64 const [portRef1, portRef2] = rootContainer.ports.createChannel()
65 const initMessage = new CreationMessage({
66 data: {
67 code: Buffer.from('test code'),
68 type: testVMContainer.typeId
69 },
70 ports: [portRef2]
71 })
72
73 message = rootContainer.createMessage()
74 await Promise.all([
75 rootContainer.send(port, initMessage),
76 rootContainer.ports.bind('first', portRef1),
77 rootContainer.send(portRef1, message)
78 ])
79 rootContainer.shutdown()
80
81 const stateRoot = await hypervisor.createStateRoot(Infinity)
82 t.deepEquals(stateRoot, expectedState, 'expected root!')
83
84 t.equals(hypervisor.scheduler.leastNumberOfTicks(), 0)
85})
86
87tape('basic - do not store containers with no ports bound', async t => {
88 t.plan(1)
89
90 const tree = new RadixTree({
91 db: db
92 })
93
94 const expectedState = {
95 '/': Buffer.from('5a316218edbc909f511b41d936517b27bb51cd6c', 'hex')
96 }
97
98 class testVMContainer extends BaseContainer {
99 onCreation () {}
100 }
101
102 const hypervisor = new Hypervisor(tree)
103 hypervisor.registerContainer(testVMContainer)
104
105 const creationPort = hypervisor.creationService.getPort()
106 let root = await hypervisor.send(creationPort, new CreationMessage({
107 data: {
108 type: testVMContainer.typeId
109 }
110 }))
111
112 hypervisor.pin(root)
113
114 root = await hypervisor.getInstance(root.id)
115
116 const [portRef1, portRef2] = root.ports.createChannel()
117
118 await Promise.all([
119 root.ports.bind('one', portRef1),
120 root.send(creationPort, new CreationMessage({
121 data: {
122 type: testVMContainer.typeId
123 },
124 ports: [portRef2]
125 }))
126 ])
127
128 root.shutdown()
129
130 const stateRoot = await hypervisor.createStateRoot(Infinity)
131
132 // await hypervisor.graph.tree(stateRoot, Infinity, true)
133 // console.log(JSON.stringify(stateRoot, null, 2))
134 t.deepEquals(stateRoot, expectedState, 'expected root!')
135})
136
137tape('one child contract', async t => {
138 t.plan(4)
139
140 const tree = new RadixTree({
141 db: db
142 })
143
144 let message
145 const expectedState = {
146 '/': Buffer.from('c91821c303cd07adde06c0d46c40aafe4542dea1', 'hex')
147 }
148
149 let hasResolved = false
150
151 class testVMContainer2 extends BaseContainer {
152 onMessage (m) {
153 t.true(m === message, 'should recive a message')
154 return new Promise((resolve, reject) => {
155 setTimeout(() => {
156 this.kernel.incrementTicks(1)
157 hasResolved = true
158 resolve()
159 }, 200)
160 })
161 }
162
163 static get typeId () {
164 return 99
165 }
166 }
167
168 class testVMContainer extends BaseContainer {
169 async onMessage (m) {
170 const [portRef1, portRef2] = this.kernel.ports.createChannel()
171 const port = this.kernel.hypervisor.creationService.getPort()
172
173 await Promise.all([
174 this.kernel.send(port, new CreationMessage({
175 data: {
176 type: testVMContainer2.typeId
177 },
178 ports: [portRef2]
179 })),
180 this.kernel.send(portRef1, m)
181 ])
182
183 this.kernel.incrementTicks(1)
184 return this.kernel.ports.bind('child', portRef1)
185 }
186 }
187
188 const hypervisor = new Hypervisor(tree)
189 hypervisor.registerContainer(testVMContainer)
190 hypervisor.registerContainer(testVMContainer2)
191
192 let creationPort = hypervisor.creationService.getPort()
193 let root = await hypervisor.send(creationPort, new CreationMessage({
194 data: {
195 type: testVMContainer.typeId
196 }
197 }))
198
199 hypervisor.pin(root)
200
201 const rootId = root.id
202 root = await hypervisor.getInstance(rootId)
203 const [portRef1, portRef2] = root.ports.createChannel()
204
205 message = root.createMessage()
206 await Promise.all([
207 root.send(creationPort, new CreationMessage({
208 data: {
209 type: testVMContainer.typeId
210 },
211 ports: [portRef2]
212 })),
213 root.ports.bind('first', portRef1),
214 root.send(portRef1, message)
215 ])
216
217 root.shutdown()
218
219 const stateRoot = await hypervisor.createStateRoot(Infinity)
220 t.true(hasResolved, 'should resolve before generating the state root')
221 t.deepEquals(stateRoot, expectedState, 'expected state')
222
223 // test reviving the state
224 class testVMContainer3 extends BaseContainer {
225 onMessage (m) {
226 const port = this.kernel.ports.get('child')
227 this.kernel.send(port, m)
228 this.kernel.incrementTicks(1)
229 }
230 }
231
232 hypervisor.registerContainer(testVMContainer3)
233 root = await hypervisor.getInstance(rootId)
234 const port = root.ports.get('first')
235 root.send(port, message)
236})
237
238tape('traps', async t => {
239 t.plan(1)
240
241 const tree = new RadixTree({
242 db: db
243 })
244 class Root extends BaseContainer {
245 async onMessage (m) {
246 const [portRef1] = this.kernel.ports.createChannel()
247 const [portRef3] = this.kernel.ports.createChannel()
248 const [portRef5] = this.kernel.ports.createChannel()
249
250 await Promise.all([
251 this.kernel.ports.bind('one', portRef1),
252 this.kernel.ports.bind('two', portRef3),
253 this.kernel.ports.bind('three', portRef5)
254 ])
255
256 throw new Error('it is a trap!!!')
257 }
258 }
259
260 const hypervisor = new Hypervisor(tree)
261
262 hypervisor.registerContainer(Root)
263 const creationPort = hypervisor.creationService.getPort()
264 const root = await hypervisor.send(creationPort, new CreationMessage({
265 data: {
266 type: Root.typeId
267 }
268 }))
269
270 hypervisor.pin(root)
271
272 await root.message(root.createMessage())
273 const stateRoot = await hypervisor.createStateRoot()
274
275 t.deepEquals(stateRoot, {
276 '/': Buffer.from('308b10121e2c46102e2d9701cfe11032786ef955', 'hex')
277 }, 'should revert the state')
278})
279
280tape('recieving older messages', async t => {
281 t.plan(2)
282
283 const tree = new RadixTree({
284 db: db
285 })
286 let runs = 0
287 const hypervisor = new Hypervisor(tree)
288 const creationPort = hypervisor.creationService.getPort()
289
290 class Root extends BaseContainer {
291 async onMessage (m) {
292 if (!runs) {
293 runs++
294 const [portRef1, portRef2] = this.kernel.ports.createChannel()
295 const [portRef3, portRef4] = this.kernel.ports.createChannel()
296
297 const message1 = new CreationMessage({
298 data: {
299 type: First.typeId
300 },
301 ports: [portRef2]
302 })
303 const message2 = new CreationMessage({
304 data: {
305 type: Waiter.typeId
306 },
307 ports: [portRef4]
308 })
309
310 return Promise.all([
311 this.kernel.send(creationPort, message1),
312 this.kernel.send(portRef1, this.kernel.createMessage()),
313 this.kernel.send(portRef3, this.kernel.createMessage()),
314 this.kernel.ports.bind('one', portRef1),
315 this.kernel.ports.bind('two', portRef3),
316 this.kernel.send(creationPort, message2)
317 ])
318 } else if (runs === 1) {
319 runs++
320 t.equals(m.data, 'first', 'should recive the first message')
321 } else {
322 runs++
323 t.equals(m.data, 'second', 'should recive the second message')
324 }
325 }
326 static get typeId () {
327 return 211
328 }
329 }
330
331 class First extends BaseContainer {
332 onMessage (m) {
333 this.kernel.incrementTicks(2)
334 return this.kernel.send(m.fromPort, this.kernel.createMessage({
335 data: 'second'
336 }))
337 }
338 static get typeId () {
339 return 29
340 }
341 }
342
343 class Waiter extends BaseContainer {
344 onMessage (m) {
345 return new Promise((resolve, reject) => {
346 setTimeout(() => {
347 this.kernel.send(m.fromPort, this.kernel.createMessage({
348 data: 'first'
349 })).then(resolve)
350 }, 200)
351 })
352 }
353 }
354
355 hypervisor.registerContainer(Root)
356 hypervisor.registerContainer(First)
357 hypervisor.registerContainer(Waiter)
358
359 let root = await hypervisor.send(creationPort, new CreationMessage({
360 data: {
361 type: Root.typeId
362 }
363 }))
364
365 hypervisor.pin(root)
366
367 root = await hypervisor.getInstance(root.id)
368 const [portRef1, portRef2] = root.ports.createChannel()
369
370 const message = root.createMessage()
371 await Promise.all([
372 root.send(portRef1, message),
373 root.ports.bind('first', portRef1),
374 root.send(creationPort, new CreationMessage({
375 data: {
376 type: Root.typeId
377 },
378 ports: [portRef2]
379 }))
380 ])
381 root.shutdown()
382})
383
384tape('saturation', async t => {
385 t.plan(3)
386
387 const tree = new RadixTree({
388 db: db
389 })
390 let runs = 0
391
392 const hypervisor = new Hypervisor(tree)
393 const creationPort = hypervisor.creationService.getPort()
394
395 class Root extends BaseContainer {
396 onIdle () {}
397 async onMessage (m) {
398 if (!runs) {
399 runs++
400 const [portRef1, portRef2] = this.kernel.ports.createChannel()
401 const [portRef3, portRef4] = this.kernel.ports.createChannel()
402
403 const message1 = new CreationMessage({
404 data: {
405 type: First.typeId
406 },
407 ports: [portRef2]
408 })
409
410 const message2 = new CreationMessage({
411 data: {
412 type: Second.typeId
413 },
414 ports: [portRef4]
415 })
416
417 this.kernel.incrementTicks(6)
418 await Promise.all([
419 this.kernel.send(creationPort, message1),
420 this.kernel.send(creationPort, message2),
421 this.kernel.send(portRef1, this.kernel.createMessage()),
422 this.kernel.send(portRef3, this.kernel.createMessage()),
423 this.kernel.ports.bind('one', portRef1),
424 this.kernel.ports.bind('two', portRef3)
425 ])
426 } else if (runs === 1) {
427 runs++
428 t.equals(m.data, 'first', 'should recive the first message')
429 } else if (runs === 2) {
430 runs++
431 t.equals(m.data, 'second', 'should recive the second message')
432 } else {
433 runs++
434 t.equals(m.data, 'third', 'should recived the third message')
435 }
436 }
437 static get typeId () {
438 return 112
439 }
440 }
441
442 class First extends BaseContainer {
443 onMessage (m) {
444 this.kernel.incrementTicks(2)
445 return this.kernel.send(m.fromPort, this.kernel.createMessage({
446 data: 'second'
447 }))
448 }
449 static get typeId () {
450 return 29
451 }
452 }
453
454 class Second extends BaseContainer {
455 onMessage (m) {
456 this.kernel.incrementTicks(3)
457 return this.kernel.send(m.fromPort, this.kernel.createMessage({
458 data: 'third'
459 }))
460 }
461 static get typeId () {
462 return 2
463 }
464 }
465
466 class Waiter extends BaseContainer {
467 onCreation (m) {
468 return new Promise((resolve, reject) => {
469 setTimeout(() => {
470 this.kernel.send(m.ports[0], this.kernel.createMessage({
471 data: 'first'
472 })).then(resolve)
473 }, 200)
474 })
475 }
476 }
477
478 hypervisor.registerContainer(Root)
479 hypervisor.registerContainer(First)
480 hypervisor.registerContainer(Second)
481 hypervisor.registerContainer(Waiter)
482
483 let root = await hypervisor.send(creationPort, new CreationMessage({
484 data: {
485 type: Root.typeId
486 }
487 }))
488
489 hypervisor.pin(root)
490 root = await hypervisor.getInstance(root.id)
491
492 const [portRef1, portRef2] = root.ports.createChannel()
493 const [portRef3, portRef4] = root.ports.createChannel()
494
495 const message = root.createMessage()
496 await Promise.all([
497 root.send(portRef1, message),
498 root.ports.bind('first', portRef1),
499 root.send(creationPort, new CreationMessage({
500 data: {
501 type: Root.typeId
502 },
503 ports: [portRef2]
504 })),
505 root.ports.bind('sencond', portRef3),
506 root.send(creationPort, new CreationMessage({
507 data: {
508 type: Waiter.typeId
509 },
510 ports: [portRef4]
511 }))
512 ])
513
514 root.incrementTicks(100)
515 await root.send(portRef1, root.createMessage({
516 data: 'testss'
517 }))
518 root.shutdown()
519})
520
521tape('send to the same container at the same time', async t => {
522 t.plan(2)
523
524 const tree = new RadixTree({
525 db: db
526 })
527 let runs = 0
528 let instance
529
530 const hypervisor = new Hypervisor(tree)
531 const creationPort = hypervisor.creationService.getPort()
532
533 class Root extends BaseContainer {
534 async onMessage (m) {
535 let one = this.kernel.ports.get('one')
536 if (!one) {
537 const [portRef1, portRef2] = this.kernel.ports.createChannel()
538 const message1 = new CreationMessage({
539 data: {
540 type: First.typeId
541 },
542 ports: [portRef2]
543 })
544 await this.kernel.send(creationPort, message1)
545 return this.kernel.ports.bind('one', portRef1)
546 } else {
547 return Promise.all([
548 this.kernel.send(one, this.kernel.createMessage()),
549 this.kernel.send(one, this.kernel.createMessage())
550 ])
551 }
552 }
553 static get typeId () {
554 return 111
555 }
556 }
557
558 class First extends BaseContainer {
559 onMessage (m) {
560 ++runs
561 if (runs === 2) {
562 t.equals(instance, this, 'should have same instances')
563 } else {
564 instance = this
565 }
566 }
567 }
568
569 hypervisor.registerContainer(Root)
570 hypervisor.registerContainer(First)
571
572 let root = await hypervisor.send(creationPort, new CreationMessage({
573 data: {
574 type: Root.typeId
575 }
576 }))
577
578 hypervisor.pin(root)
579 root = await hypervisor.getInstance(root.id)
580
581 const [portRef1, portRef2] = root.ports.createChannel()
582 await Promise.all([
583 root.ports.bind('first', portRef1),
584 root.send(creationPort, new CreationMessage({
585 data: {
586 type: Root.typeId
587 },
588 ports: [portRef2]
589 }))
590 ])
591
592 const message = root.createMessage()
593
594 await root.send(portRef1, message)
595 root.shutdown()
596 await hypervisor.createStateRoot()
597 await root.send(portRef1, root.createMessage())
598 await hypervisor.createStateRoot()
599 t.equals(runs, 2)
600})
601
602tape('checking ports', async t => {
603 t.plan(4)
604
605 const tree = new RadixTree({
606 db: db
607 })
608 const hypervisor = new Hypervisor(tree)
609 const creationPort = hypervisor.creationService.getPort()
610 hypervisor.registerContainer(BaseContainer)
611
612 let root = await hypervisor.send(creationPort, new CreationMessage({
613 data: {
614 type: BaseContainer.typeId
615 }
616 }))
617
618 hypervisor.pin(root)
619 root = await hypervisor.getInstance(root.id)
620
621 const [portRef1, portRef2] = root.ports.createChannel()
622 root.send(creationPort, new CreationMessage({
623 data: {
624 type: BaseContainer.typeId
625 },
626 ports: [portRef2]
627 }))
628 await root.ports.bind('test', portRef1)
629
630 try {
631 root.createMessage({
632 ports: [portRef1]
633 })
634 } catch (e) {
635 t.pass('should thow if sending a port that is bound')
636 }
637
638 try {
639 await root.ports.bind('test', portRef1)
640 } catch (e) {
641 t.pass('should thow if binding an already bound port')
642 }
643
644 try {
645 const [portRef3] = root.ports.createChannel()
646 await root.ports.bind('test', portRef3)
647 } catch (e) {
648 t.pass('should thow if binding an already bound name')
649 }
650
651 await root.ports.unbind('test')
652 const message = root.createMessage({
653 ports: [portRef1]
654 })
655 t.equals(message.ports[0], portRef1, 'should create a message if the port is unbound')
656})
657
658tape('port deletion', async t => {
659 const expectedSr = {
660 '/': Buffer.from('1f0673f23b4eeb86115992621d7edc981a6afade', 'hex')
661 }
662
663 const tree = new RadixTree({
664 db: db
665 })
666 const hypervisor = new Hypervisor(tree)
667 const creationPort = hypervisor.creationService.getPort()
668
669 class Root extends BaseContainer {
670 async onMessage (m) {
671 const [portRef1, portRef2] = this.kernel.ports.createChannel()
672 const message1 = new CreationMessage({
673 data: {
674 type: First.typeId
675 },
676 ports: [portRef2]
677 })
678
679 await Promise.all([
680 this.kernel.send(creationPort, message1),
681 this.kernel.send(portRef1, this.kernel.createMessage())
682 ])
683 this.kernel.incrementTicks(6)
684 return this.kernel.ports.bind('one', portRef1)
685 }
686 }
687
688 class First extends BaseContainer {
689 onMessage (m) {
690 this.kernel.incrementTicks(2)
691 return this.kernel.ports.delete('root')
692 }
693 static get typeId () {
694 return 111
695 }
696 }
697
698 hypervisor.registerContainer(Root)
699 hypervisor.registerContainer(First)
700
701 let root = await hypervisor.send(creationPort, new CreationMessage({
702 data: {
703 type: Root.typeId
704 }
705 }))
706
707 hypervisor.pin(root)
708 root = await hypervisor.getInstance(root.id)
709
710 const [portRef1, portRef2] = root.ports.createChannel()
711 await root.ports.bind('first', portRef1)
712 await root.send(creationPort, new CreationMessage({
713 data: {
714 type: Root.typeId
715 },
716 ports: [portRef2]
717 }))
718
719 const message = root.createMessage()
720 await root.send(portRef1, message)
721
722 root.shutdown()
723
724 const sr = await hypervisor.createStateRoot()
725 t.deepEquals(sr, expectedSr, 'should produce the corret state root')
726
727 t.end()
728})
729
730tape('clear unbounded ports', async t => {
731 const expectedSr = {
732 '/': Buffer.from('1f0673f23b4eeb86115992621d7edc981a6afade', 'hex')
733 }
734
735 const tree = new RadixTree({
736 db: db
737 })
738 const hypervisor = new Hypervisor(tree)
739 const creationPort = hypervisor.creationService.getPort()
740
741 class Root extends BaseContainer {
742 onMessage (m) {
743 return this.kernel.send(creationPort, new CreationMessage({
744 data: {
745 type: Root.typeId
746 }
747 }))
748 }
749 }
750
751 hypervisor.registerContainer(Root)
752
753 let root = await hypervisor.send(creationPort, new CreationMessage({
754 data: {
755 type: Root.typeId
756 }
757 }))
758
759 root = await hypervisor.getInstance(root.id)
760 hypervisor.pin(root)
761
762 const [portRef1, portRef2] = root.ports.createChannel()
763 await root.ports.bind('first', portRef1)
764 await root.send(creationPort, new CreationMessage({
765 data: {
766 type: Root.typeId
767 },
768 ports: [portRef2]
769 }))
770
771 const message = root.createMessage()
772 await root.send(portRef1, message)
773 root.shutdown()
774 const sr = await hypervisor.createStateRoot()
775 t.deepEquals(sr, expectedSr, 'should produce the corret state root')
776
777 t.end()
778})
779
780tape('should remove subgraphs', async t => {
781 const expectedSr = {
782 '/': Buffer.from('1f0673f23b4eeb86115992621d7edc981a6afade', 'hex')
783 }
784
785 const tree = new RadixTree({
786 db: db
787 })
788 const hypervisor = new Hypervisor(tree)
789 const creationPort = hypervisor.creationService.getPort()
790
791 class Root extends BaseContainer {
792 onMessage (m) {
793 const [, portRef2] = this.kernel.ports.createChannel()
794 return this.kernel.send(creationPort, new CreationMessage({
795 data: {
796 type: Sub.typeId
797 },
798 ports: [portRef2]
799 }))
800 }
801 }
802
803 class Sub extends BaseContainer {
804 static get typeId () {
805 return 199
806 }
807 }
808
809 hypervisor.registerContainer(Root)
810 hypervisor.registerContainer(Sub)
811
812 let root = await hypervisor.send(creationPort, new CreationMessage({
813 data: {
814 type: Root.typeId
815 }
816 }))
817
818 root = await hypervisor.getInstance(root.id)
819
820 hypervisor.pin(root)
821
822 const [portRef1, portRef2] = root.ports.createChannel()
823 await root.ports.bind('first', portRef1)
824 await root.send(creationPort, new CreationMessage({
825 data: {
826 type: Root.typeId
827 },
828 ports: [portRef2]
829 }))
830
831 await root.send(portRef1, root.createMessage())
832 root.shutdown()
833 const sr = await hypervisor.createStateRoot()
834
835 t.deepEquals(sr, expectedSr, 'should produce the corret state root')
836 t.end()
837})
838
839tape('should not remove connected nodes', async t => {
840 const tree = new RadixTree({
841 db: db
842 })
843
844 const expectedSr = {
845 '/': Buffer.from('9aeb0ce35c0ab845e7b273afe0329f826297124e', 'hex')
846 }
847
848 const hypervisor = new Hypervisor(tree)
849 const creationPort = hypervisor.creationService.getPort()
850
851 class Root extends BaseContainer {
852 async onMessage (m) {
853 if (m.ports.length) {
854 const port = this.kernel.ports.get('test1')
855 await this.kernel.send(port, m)
856 return this.kernel.ports.unbind('test1')
857 } else {
858 const [portRef1, portRef2] = this.kernel.ports.createChannel()
859 await this.kernel.send(creationPort, new CreationMessage({
860 data: {
861 type: Sub.typeId
862 },
863 ports: [portRef2]
864 }))
865 await this.kernel.ports.bind('test1', portRef1)
866
867 const [portRef3, portRef4] = this.kernel.ports.createChannel()
868 await this.kernel.send(creationPort, new CreationMessage({
869 data: {
870 type: Sub.typeId
871 },
872 ports: [portRef4]
873 }))
874 await this.kernel.ports.bind('test2', portRef3)
875 await this.kernel.send(portRef3, this.kernel.createMessage({
876 data: 'getChannel'
877 }))
878 }
879 }
880 }
881
882 class Sub extends BaseContainer {
883 async onMessage (message) {
884 if (message.data === 'getChannel') {
885 const ports = this.kernel.ports.createChannel()
886 await this.kernel.send(message.fromPort, this.kernel.createMessage({
887 data: 'bindPort',
888 ports: [ports[1]]
889 }))
890 return this.kernel.ports.bind('channel', ports[0])
891 } else {
892 return this.kernel.ports.bind('channel', message.ports[0])
893 }
894 }
895 static get typeId () {
896 return 111
897 }
898 }
899
900 hypervisor.registerContainer(Root)
901 hypervisor.registerContainer(Sub)
902
903 let root = await hypervisor.send(creationPort, new CreationMessage({
904 data: {
905 type: Root.typeId
906 }
907 }))
908
909 root = await hypervisor.getInstance(root.id)
910 hypervisor.pin(root)
911
912 const [portRef1, portRef2] = root.ports.createChannel()
913 await root.ports.bind('first', portRef1)
914 await root.send(creationPort, new CreationMessage({
915 data: {
916 type: Root.typeId
917 },
918 ports: [portRef2]
919 }))
920
921 await root.send(portRef1, root.createMessage())
922 root.shutdown()
923 const sr = await hypervisor.createStateRoot()
924
925 t.deepEquals(sr, expectedSr, 'should produce the corret state root')
926 t.end()
927})
928
929tape('should remove multiple subgraphs', async t => {
930 const tree = new RadixTree({
931 db: db
932 })
933 const expectedSr = {
934 '/': Buffer.from('196a7b55f26afb41f065923332e14b40cd0edf2e', 'hex')
935 }
936
937 const hypervisor = new Hypervisor(tree)
938 const creationPort = hypervisor.creationService.getPort()
939
940 class Root extends BaseContainer {
941 onMessage (m) {
942 if (m.ports.length) {
943 const port = this.kernel.ports.get('test1')
944 return Promise.all([
945 this.kernel.send(port, m),
946 this.kernel.ports.unbind('test1'),
947 this.kernel.ports.unbind('test2')
948 ])
949 } else {
950 const [portRef1, portRef2] = this.kernel.ports.createChannel()
951 const [portRef3, portRef4] = this.kernel.ports.createChannel()
952 return Promise.all([
953 this.kernel.send(creationPort, new CreationMessage({
954 data: {
955 type: Sub.typeId
956 },
957 ports: [portRef2]
958 })),
959 this.kernel.ports.bind('test1', portRef1),
960 this.kernel.send(creationPort, new CreationMessage({
961 data: {
962 type: Sub.typeId
963 },
964 ports: [portRef4]
965 })),
966 this.kernel.ports.bind('test2', portRef3),
967 this.kernel.send(portRef3, this.kernel.createMessage({
968 data: 'getChannel'
969 }))
970 ])
971 }
972 }
973 }
974
975 class Sub extends BaseContainer {
976 async onMessage (message) {
977 if (message.data === 'getChannel') {
978 const ports = this.kernel.ports.createChannel()
979 await this.kernel.send(message.fromPort, this.kernel.createMessage({
980 data: 'bindPort',
981 ports: [ports[1]]
982 }))
983 return this.kernel.ports.bind('channel', ports[0])
984 } else {
985 return this.kernel.ports.bind('channel', message.ports[0])
986 }
987 }
988 static get typeId () {
989 return 111
990 }
991 }
992
993 hypervisor.registerContainer(Root)
994 hypervisor.registerContainer(Sub)
995
996 let root = await hypervisor.send(creationPort, new CreationMessage({
997 data: {
998 type: Root.typeId
999 }
1000 }))
1001
1002 root = await hypervisor.getInstance(root.id)
1003 hypervisor.pin(root)
1004
1005 const [portRef1, portRef2] = root.ports.createChannel()
1006 await Promise.all([
1007 root.ports.bind('first', portRef1),
1008 root.send(creationPort, new CreationMessage({
1009 data: {
1010 type: Root.typeId
1011 },
1012 ports: [portRef2]
1013 })),
1014 root.send(portRef1, root.createMessage())
1015 ])
1016
1017 root.shutdown()
1018
1019 const sr = await hypervisor.createStateRoot()
1020
1021 t.deepEquals(sr, expectedSr, 'should produce the corret state root')
1022
1023 t.end()
1024})
1025
1026tape('response ports', async t => {
1027 t.plan(2)
1028 const tree = new RadixTree({
1029 db: db
1030 })
1031 let runs = 0
1032 const returnValue = 'this is a test'
1033 const hypervisor = new Hypervisor(tree)
1034 const creationPort = hypervisor.creationService.getPort()
1035
1036 class testVMContainer extends BaseContainer {
1037 onMessage (m) {
1038 runs++
1039 if (runs === 1) {
1040 return returnValue
1041 } else {
1042 t.equals(m.data, returnValue, 'should have correct return value')
1043 }
1044 }
1045 }
1046
1047 hypervisor.registerContainer(testVMContainer)
1048
1049 let rootContainer = await hypervisor.send(creationPort, new CreationMessage({
1050 data: {
1051 type: testVMContainer.typeId
1052 }
1053 }))
1054
1055 rootContainer = await hypervisor.getInstance(rootContainer.id)
1056
1057 hypervisor.pin(rootContainer)
1058
1059 const [portRef1, portRef2] = rootContainer.ports.createChannel()
1060 const initMessage = new CreationMessage({
1061 data: {
1062 type: testVMContainer.typeId
1063 },
1064 ports: [portRef2]
1065 })
1066
1067 rootContainer.send(creationPort, initMessage)
1068
1069 await rootContainer.ports.bind('first', portRef1)
1070 const message = rootContainer.createMessage()
1071 const rPort = rootContainer.getResponsePort(message)
1072 const rPort2 = rootContainer.getResponsePort(message)
1073
1074 t.equals(rPort2, rPort)
1075
1076 rootContainer.send(portRef1, message)
1077 await rootContainer.ports.bind('response', rPort)
1078})
1079
1080tape('start up', async t => {
1081 t.plan(1)
1082
1083 const tree = new RadixTree({
1084 db: db
1085 })
1086
1087 class testVMContainer extends BaseContainer {
1088 onStartup () {
1089 t.pass('should start up')
1090 }
1091 }
1092
1093 const hypervisor = new Hypervisor(tree)
1094 const creationPort = hypervisor.creationService.getPort()
1095 hypervisor.registerContainer(testVMContainer)
1096 const instance = await hypervisor.send(creationPort, new CreationMessage({
1097 data: {
1098 type: testVMContainer.typeId
1099 }
1100 }))
1101 hypervisor.getInstance(instance.id)
1102})
1103
1104tape('large code size', async t => {
1105 t.plan(1)
1106 const tree = new RadixTree({
1107 db: db
1108 })
1109 const content = Buffer.from(new ArrayBuffer(1e6))
1110 class testVMContainer extends BaseContainer {}
1111
1112 const hypervisor = new Hypervisor(tree)
1113 const creationPort = hypervisor.creationService.getPort()
1114 hypervisor.registerContainer(testVMContainer)
1115 const oldInst = await hypervisor.send(creationPort, new CreationMessage({
1116 data: {
1117 type: testVMContainer.typeId,
1118 code: content
1119 }
1120 }))
1121 const instance = await hypervisor.getInstance(oldInst.id)
1122 t.equals(content.length, instance.code.length)
1123})
1124
1125tape('creation service messaging', async t => {
1126 t.plan(1)
1127
1128 const tree = new RadixTree({
1129 db: db
1130 })
1131
1132 class TestVMContainer extends BaseContainer {
1133 async onCreation (m) {
1134 const creationPort = m.ports[0]
1135 const [port1, port2] = this.kernel.ports.createChannel()
1136 await this.kernel.ports.bind('child', port1)
1137
1138 const message = new CreationMessage({
1139 data: {
1140 type: TestVMContainer2.typeId
1141 },
1142 ports: [port2]
1143 })
1144 return this.kernel.send(creationPort, message)
1145 }
1146 }
1147
1148 class TestVMContainer2 extends BaseContainer {
1149 static get typeId () {
1150 return 66
1151 }
1152 }
1153
1154 const hypervisor = new Hypervisor(tree)
1155 hypervisor.registerContainer(TestVMContainer)
1156 hypervisor.registerContainer(TestVMContainer2)
1157
1158 const port = hypervisor.creationService.getPort()
1159 const port2 = hypervisor.creationService.getPort()
1160
1161 const root = await hypervisor.send(port2, new CreationMessage({
1162 data: {
1163 type: TestVMContainer.typeId
1164 },
1165 ports: [port]
1166 }))
1167
1168 hypervisor.pin(root)
1169
1170 const stateRoot = await hypervisor.createStateRoot()
1171 // await hypervisor.graph.tree(hypervisor.state, Infinity, true)
1172 const expectedSR = {
1173 '/': Buffer.from('c86f6a4519b4a18e1f31abe357a84712aabce8d2', 'hex')
1174 }
1175 t.deepEquals(stateRoot, expectedSR)
1176})
1177
1178tape('creation service - port copy', async t => {
1179 t.plan(2)
1180
1181 const tree = new RadixTree({
1182 db: db
1183 })
1184
1185 class TestVMContainer extends BaseContainer {
1186 onCreation (m) {
1187 const creationPort = m.ports[0]
1188
1189 const message = this.kernel.createMessage()
1190 const responePort = this.kernel.getResponsePort(message)
1191
1192 return Promise.all([
1193 this.kernel.ports.bind('response', responePort),
1194 this.kernel.send(creationPort, message)
1195 ])
1196 }
1197 onMessage (m) {
1198 t.equal(m.fromName, 'response')
1199 t.equal(m.ports.length, 1)
1200 }
1201 }
1202
1203 const hypervisor = new Hypervisor(tree)
1204 hypervisor.registerContainer(TestVMContainer)
1205
1206 const port = hypervisor.creationService.getPort()
1207
1208 const root = await hypervisor.send(port, new CreationMessage({
1209 data: {
1210 type: TestVMContainer.typeId
1211 },
1212 ports: [port]
1213 }))
1214
1215 hypervisor.pin(root)
1216})
1217
1218tape('waiting on ports', async t => {
1219 t.plan(1)
1220
1221 const tree = new RadixTree({
1222 db: db
1223 })
1224
1225 class TestVMContainer extends BaseContainer {
1226 async onCreation (m) {
1227 await this.kernel.ports.bind('test', m.ports[0])
1228 this.kernel.ports.getNextMessage()
1229 try {
1230 await this.kernel.ports.getNextMessage()
1231 } catch (e) {
1232 t.pass('should throw if already trying to get a message')
1233 }
1234 }
1235 }
1236
1237 const hypervisor = new Hypervisor(tree)
1238 hypervisor.registerContainer(TestVMContainer)
1239
1240 const port = hypervisor.creationService.getPort()
1241
1242 await hypervisor.send(port, new CreationMessage({
1243 data: {
1244 type: TestVMContainer.typeId
1245 },
1246 ports: [port]
1247 }))
1248})
1249

Built with git-ssb-web