git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: 22cdc4553fb9b622685313bf95bdfd95774424cf

Files: 22cdc4553fb9b622685313bf95bdfd95774424cf / tests / index.js

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

Built with git-ssb-web