Files: 73e2dee5319d5188d4dda64d13ea38ea8856a714 / tests / index.js
16443 bytesRaw
1 | const tape = require('tape') |
2 | const Hypervisor = require('../') |
3 | const {Message, FunctionRef, ModuleRef} = require('primea-objects') |
4 | |
5 | const level = require('level-browserify') |
6 | const EgressDriver = require('../egressDriver') |
7 | const RadixTree = require('dfinity-radix-tree') |
8 | const db = level('./testdb') |
9 | |
10 | class BaseContainer { |
11 | constructor (actor) { |
12 | this.actor = actor |
13 | } |
14 | onStartup () {} |
15 | static onCreation (code, id) { |
16 | const exp = {} |
17 | Object.getOwnPropertyNames(this.prototype).filter(name => name !== 'constructor').forEach(name => { |
18 | exp[name] = {} |
19 | }) |
20 | return new ModuleRef(exp, id) |
21 | } |
22 | onMessage (message) { |
23 | return this[message.funcRef.identifier[1]](...message.funcArguments) |
24 | } |
25 | static get typeId () { |
26 | return 9 |
27 | } |
28 | } |
29 | |
30 | tape('system objects', async t => { |
31 | t.plan(4) |
32 | const tree = new RadixTree({ |
33 | db |
34 | }) |
35 | |
36 | let id |
37 | let mod |
38 | let funcref |
39 | |
40 | class testVMContainer extends BaseContainer { |
41 | store () { |
42 | id = this.actor.id.id.toString('hex') |
43 | mod = new ModuleRef({'test': ['i32', 'i64']}, this.actor.id) |
44 | funcref = mod.getFuncRef('test') |
45 | this.actor.storage = [this.actor.id, {'/': 'test'}, mod, funcref] |
46 | } |
47 | load () { |
48 | const loadedID = this.actor.storage[0].id.toString('hex') |
49 | const link = this.actor.storage[1] |
50 | const loadedMod = this.actor.storage[2] |
51 | const loadedFuncref = this.actor.storage[3] |
52 | t.equals(id, loadedID, 'should load id correctly') |
53 | t.equals(link['/'].toString('hex'), '6fe3180f700090697285ac1e0e8dc400259373d7', 'should load link correctly') |
54 | t.deepEquals(loadedMod, mod) |
55 | t.deepEquals(funcref, loadedFuncref) |
56 | } |
57 | } |
58 | |
59 | const hypervisor = new Hypervisor(tree, [testVMContainer]) |
60 | const {module} = hypervisor.createActor(testVMContainer.typeId) |
61 | const message = new Message({ |
62 | funcRef: module.getFuncRef('store') |
63 | }) |
64 | |
65 | hypervisor.send(message) |
66 | await hypervisor.createStateRoot() |
67 | |
68 | const message2 = new Message({ |
69 | funcRef: module.getFuncRef('load') |
70 | }) |
71 | hypervisor.send(message2) |
72 | await hypervisor.createStateRoot() |
73 | t.end() |
74 | }) |
75 | |
76 | tape('basic', async t => { |
77 | t.plan(2) |
78 | const expectedState = Buffer.from('32b919149345b74e431c42a1b7dd65c30c625284', 'hex') |
79 | const tree = new RadixTree({ |
80 | db |
81 | }) |
82 | |
83 | class testVMContainer extends BaseContainer { |
84 | main (m) { |
85 | t.equals(m, 1, 'should recive a message') |
86 | } |
87 | } |
88 | |
89 | const hypervisor = new Hypervisor(tree, [testVMContainer]) |
90 | await hypervisor.createStateRoot() |
91 | |
92 | const {module} = hypervisor.createActor(testVMContainer.typeId) |
93 | |
94 | const message = new Message({ |
95 | funcRef: module.getFuncRef('main'), |
96 | funcArguments: [1] |
97 | }) |
98 | hypervisor.send(message) |
99 | |
100 | const stateRoot2 = await hypervisor.createStateRoot() |
101 | t.deepEquals(stateRoot2, expectedState, 'expected root!') |
102 | }) |
103 | |
104 | tape('two communicating actors', async t => { |
105 | t.plan(2) |
106 | const expectedState = Buffer.from('7f638e41261bc0238c3e9b34fce11827b6a3cb61', 'hex') |
107 | |
108 | const tree = new RadixTree({ |
109 | db |
110 | }) |
111 | |
112 | class testVMContainerA extends BaseContainer { |
113 | main (funcRef) { |
114 | const message = new Message({ |
115 | funcRef, |
116 | funcArguments: [2] |
117 | }) |
118 | return this.actor.send(message) |
119 | } |
120 | } |
121 | |
122 | class testVMContainerB extends BaseContainer { |
123 | main (args) { |
124 | t.equals(args, 2, 'should recive a message') |
125 | } |
126 | |
127 | static get typeId () { |
128 | return 8 |
129 | } |
130 | } |
131 | |
132 | const hypervisor = new Hypervisor(tree, [testVMContainerA, testVMContainerB]) |
133 | |
134 | const {module: moduleB} = hypervisor.createActor(testVMContainerB.typeId) |
135 | const {module: moduleA} = hypervisor.createActor(testVMContainerA.typeId) |
136 | |
137 | const message = new Message({ |
138 | funcRef: moduleA.getFuncRef('main'), |
139 | funcArguments: [moduleB.getFuncRef('main')] |
140 | }) |
141 | |
142 | hypervisor.send(message) |
143 | |
144 | const stateRoot = await hypervisor.createStateRoot() |
145 | t.deepEquals(stateRoot, expectedState, 'expected root!') |
146 | }) |
147 | |
148 | tape('three communicating actors', async t => { |
149 | t.plan(3) |
150 | const expectedState = Buffer.from('ae2e8afa84748192064ddebab30d0e9852ceb722', 'hex') |
151 | const tree = new RadixTree({ |
152 | db: db |
153 | }) |
154 | |
155 | class testVMContainerA extends BaseContainer { |
156 | main (funcRef) { |
157 | const message = new Message({ |
158 | funcRef: funcRef, |
159 | funcArguments: [2] |
160 | }) |
161 | this.actor.send(message) |
162 | } |
163 | } |
164 | |
165 | class testVMContainerB extends BaseContainer { |
166 | main (arg) { |
167 | t.equals(arg, 2, 'should recive a message') |
168 | } |
169 | |
170 | static get typeId () { |
171 | return 8 |
172 | } |
173 | } |
174 | |
175 | const hypervisor = new Hypervisor(tree, [testVMContainerA, testVMContainerB]) |
176 | |
177 | let {module: moduleB} = hypervisor.createActor(testVMContainerB.typeId) |
178 | let {module: moduleA0} = hypervisor.createActor(testVMContainerA.typeId) |
179 | let {module: moduleA1} = hypervisor.createActor(testVMContainerA.typeId) |
180 | |
181 | const message0 = new Message({ |
182 | funcRef: moduleA0.getFuncRef('main'), |
183 | funcArguments: [moduleB.getFuncRef('main')] |
184 | }) |
185 | |
186 | const message1 = new Message({ |
187 | funcRef: moduleA1.getFuncRef('main'), |
188 | funcArguments: [moduleB.getFuncRef('main')] |
189 | }) |
190 | |
191 | await hypervisor.send(message0) |
192 | await hypervisor.send(message1) |
193 | |
194 | const stateRoot = await hypervisor.createStateRoot() |
195 | t.deepEquals(stateRoot, expectedState, 'expected root!') |
196 | }) |
197 | |
198 | tape('three communicating actors, with tick counting', async t => { |
199 | t.plan(3) |
200 | const expectedState = Buffer.from('ae2e8afa84748192064ddebab30d0e9852ceb722', 'hex') |
201 | const tree = new RadixTree({ |
202 | db: db |
203 | }) |
204 | |
205 | class testVMContainerA extends BaseContainer { |
206 | main (funcRef) { |
207 | this.actor.incrementTicks(1) |
208 | const message = new Message({ |
209 | funcRef, |
210 | funcArguments: [2] |
211 | }) |
212 | this.actor.send(message) |
213 | } |
214 | } |
215 | |
216 | class testVMContainerB extends BaseContainer { |
217 | main (arg) { |
218 | t.equals(arg, 2, 'should recive a message') |
219 | } |
220 | |
221 | static get typeId () { |
222 | return 8 |
223 | } |
224 | } |
225 | |
226 | const hypervisor = new Hypervisor(tree, [testVMContainerA, testVMContainerB]) |
227 | |
228 | let actorB = hypervisor.createActor(testVMContainerB.typeId) |
229 | let actorA0 = hypervisor.createActor(testVMContainerA.typeId) |
230 | let actorA1 = hypervisor.createActor(testVMContainerA.typeId) |
231 | |
232 | const message0 = new Message({ |
233 | funcRef: actorA0.module.getFuncRef('main'), |
234 | funcArguments: [actorB.module.getFuncRef('main')] |
235 | }) |
236 | const message1 = new Message({ |
237 | funcRef: actorA1.module.getFuncRef('main'), |
238 | funcArguments: [actorB.module.getFuncRef('main')] |
239 | }) |
240 | |
241 | hypervisor.send(message0) |
242 | hypervisor.send(message1) |
243 | |
244 | const stateRoot = await hypervisor.createStateRoot() |
245 | t.deepEquals(stateRoot, expectedState, 'expected root!') |
246 | }) |
247 | |
248 | tape('errors', async t => { |
249 | t.plan(3) |
250 | const expectedState = Buffer.from('7f638e41261bc0238c3e9b34fce11827b6a3cb61', 'hex') |
251 | const tree = new RadixTree({ |
252 | db |
253 | }) |
254 | |
255 | class testVMContainerA extends BaseContainer { |
256 | main (funcRef) { |
257 | const message = new Message({ |
258 | funcRef |
259 | }) |
260 | message.on('execution:error', () => { |
261 | t.pass('should recive a exeption') |
262 | }) |
263 | this.actor.send(message) |
264 | } |
265 | } |
266 | |
267 | class testVMContainerB extends BaseContainer { |
268 | main (funcRef) { |
269 | t.true(true, 'should recive a message') |
270 | throw new Error('test error') |
271 | } |
272 | |
273 | static get typeId () { |
274 | return 8 |
275 | } |
276 | } |
277 | |
278 | const hypervisor = new Hypervisor(tree) |
279 | hypervisor.registerContainer(testVMContainerA) |
280 | hypervisor.registerContainer(testVMContainerB) |
281 | |
282 | let {module: moduleB} = hypervisor.createActor(testVMContainerB.typeId) |
283 | let {module: moduleA} = hypervisor.createActor(testVMContainerA.typeId) |
284 | const message = new Message({ |
285 | funcRef: moduleA.getFuncRef('main'), |
286 | funcArguments: [moduleB.getFuncRef('main')] |
287 | }) |
288 | hypervisor.send(message) |
289 | const stateRoot = await hypervisor.createStateRoot() |
290 | t.deepEquals(stateRoot, expectedState, 'expected root!') |
291 | }) |
292 | |
293 | tape('actor creation', async t => { |
294 | t.plan(2) |
295 | const expectedState = Buffer.from('0e6d32f2fe8b5b99f0203eb46bfc7e319a07f700', 'hex') |
296 | |
297 | const tree = new RadixTree({ |
298 | db |
299 | }) |
300 | |
301 | class testVMContainerA extends BaseContainer { |
302 | async start (funcRef) { |
303 | const {module} = this.actor.createActor(testVMContainerB.typeId) |
304 | const message = new Message({ |
305 | funcRef: module.getFuncRef('main'), |
306 | funcArguments: [{ |
307 | identifier: [0, 'main'], |
308 | actorID: this.actor.id |
309 | }] |
310 | }) |
311 | this.actor.send(message) |
312 | } |
313 | main (data) { |
314 | t.equals(data, 'test', 'should recive a response message') |
315 | } |
316 | } |
317 | |
318 | class testVMContainerB extends BaseContainer { |
319 | main (funcRef) { |
320 | this.actor.send(new Message({funcRef, funcArguments: ['test']})) |
321 | } |
322 | |
323 | static get typeId () { |
324 | return 8 |
325 | } |
326 | } |
327 | |
328 | const hypervisor = new Hypervisor(tree) |
329 | hypervisor.registerContainer(testVMContainerA) |
330 | hypervisor.registerContainer(testVMContainerB) |
331 | |
332 | const {module} = hypervisor.createActor(testVMContainerA.typeId) |
333 | await hypervisor.send(new Message({funcRef: module.getFuncRef('start')})) |
334 | |
335 | const stateRoot = await hypervisor.createStateRoot() |
336 | t.deepEquals(stateRoot, expectedState, 'expected root!') |
337 | t.end() |
338 | }) |
339 | |
340 | tape('simple message arbiter test', async t => { |
341 | t.plan(4) |
342 | const expectedState = Buffer.from('7f638e41261bc0238c3e9b34fce11827b6a3cb61', 'hex') |
343 | const tree = new RadixTree({ |
344 | db |
345 | }) |
346 | |
347 | class testVMContainerA extends BaseContainer { |
348 | main (funcRef) { |
349 | const message1 = new Message({ |
350 | funcArguments: ['first'], |
351 | funcRef |
352 | }) |
353 | const message2 = new Message({ |
354 | funcArguments: ['second'], |
355 | funcRef |
356 | }) |
357 | const message3 = new Message({ |
358 | funcArguments: ['third'], |
359 | funcRef |
360 | }) |
361 | this.actor.send(message1) |
362 | this.actor.incrementTicks(1) |
363 | this.actor.send(message2) |
364 | this.actor.incrementTicks(1) |
365 | this.actor.send(message3) |
366 | } |
367 | } |
368 | |
369 | let recMsg = 0 |
370 | |
371 | class testVMContainerB extends BaseContainer { |
372 | main (data) { |
373 | this.actor.incrementTicks(1) |
374 | if (recMsg === 0) { |
375 | t.equal(data, 'first', 'should recive fist message') |
376 | } else if (recMsg === 1) { |
377 | t.equal(data, 'second', 'should recive second message') |
378 | } else { |
379 | t.equal(data, 'third', 'should recive third message') |
380 | } |
381 | recMsg++ |
382 | } |
383 | |
384 | static get typeId () { |
385 | return 8 |
386 | } |
387 | } |
388 | |
389 | const hypervisor = new Hypervisor(tree) |
390 | hypervisor.registerContainer(testVMContainerA) |
391 | hypervisor.registerContainer(testVMContainerB) |
392 | |
393 | const {module: moduleB} = hypervisor.createActor(testVMContainerB.typeId) |
394 | const {module: moduleA} = hypervisor.createActor(testVMContainerA.typeId) |
395 | const message = new Message({ |
396 | funcRef: moduleA.getFuncRef('main'), |
397 | funcArguments: [moduleB.getFuncRef('main')] |
398 | }) |
399 | hypervisor.send(message) |
400 | |
401 | const stateRoot = await hypervisor.createStateRoot() |
402 | t.deepEquals(stateRoot, expectedState, 'expected root!') |
403 | }) |
404 | |
405 | tape('arbiter test for id comparision', async t => { |
406 | // t.plan(4) |
407 | let message |
408 | const expectedState = Buffer.from('ae2e8afa84748192064ddebab30d0e9852ceb722', 'hex') |
409 | |
410 | const tree = new RadixTree({ |
411 | db: db |
412 | }) |
413 | |
414 | class testVMContainerA extends BaseContainer { |
415 | main (funcRef, funcArguments) { |
416 | this.actor.incrementTicks(1) |
417 | message = new Message({ |
418 | funcRef, |
419 | funcArguments: [funcArguments] |
420 | }) |
421 | this.actor.send(message) |
422 | } |
423 | } |
424 | |
425 | let recMsg = 0 |
426 | |
427 | class testVMContainerB extends BaseContainer { |
428 | main (data) { |
429 | if (recMsg === 0) { |
430 | t.equal(data, 'first', 'should recive fist message') |
431 | } else if (recMsg === 1) { |
432 | t.equal(data, 'second', 'should recive second message') |
433 | } else { |
434 | t.equal(data, 'third', 'should recive third message') |
435 | } |
436 | recMsg++ |
437 | } |
438 | |
439 | static get typeId () { |
440 | return 8 |
441 | } |
442 | } |
443 | |
444 | const hypervisor = new Hypervisor(tree) |
445 | hypervisor.registerContainer(testVMContainerA) |
446 | hypervisor.registerContainer(testVMContainerB) |
447 | |
448 | let {module: moduleB} = hypervisor.createActor(testVMContainerB.typeId) |
449 | hypervisor.send(new Message({ |
450 | funcRef: moduleB.getFuncRef('main'), |
451 | funcArguments: ['first'] |
452 | })) |
453 | |
454 | const sr1 = await hypervisor.createStateRoot() |
455 | |
456 | const {module: moduleA0} = hypervisor.createActor(testVMContainerA.typeId) |
457 | |
458 | hypervisor.send(new Message({ |
459 | funcRef: moduleA0.getFuncRef('main'), |
460 | funcArguments: [moduleB.getFuncRef('main'), 'second'] |
461 | })) |
462 | |
463 | const {module: moduleA1} = hypervisor.createActor(testVMContainerA.typeId) |
464 | hypervisor.send(new Message({ |
465 | funcRef: moduleA1.getFuncRef('main'), |
466 | funcArguments: [moduleB.getFuncRef('main'), 'third'] |
467 | })) |
468 | |
469 | const stateRoot = await hypervisor.createStateRoot() |
470 | t.deepEquals(stateRoot, expectedState, 'expected root!') |
471 | |
472 | await hypervisor.setStateRoot(sr1) |
473 | t.equals(hypervisor.nonce, 1, 'should get the correct nonce') |
474 | t.end() |
475 | }) |
476 | |
477 | tape('async work', async t => { |
478 | t.plan(3) |
479 | const expectedState = Buffer.from('7f638e41261bc0238c3e9b34fce11827b6a3cb61', 'hex') |
480 | |
481 | const tree = new RadixTree({ |
482 | db |
483 | }) |
484 | |
485 | class testVMContainerA extends BaseContainer { |
486 | main (funcRef) { |
487 | const message = new Message({ |
488 | funcRef, |
489 | funcArguments: [2] |
490 | }) |
491 | this.actor.send(message) |
492 | |
493 | const message2 = new Message({ |
494 | funcRef, |
495 | funcArguments: [2] |
496 | }) |
497 | this.actor.send(message2) |
498 | this.actor.incrementTicks(1) |
499 | return new Promise((resolve, reject) => { |
500 | setTimeout(() => { |
501 | resolve() |
502 | }, 10) |
503 | }) |
504 | } |
505 | } |
506 | |
507 | class testVMContainerB extends BaseContainer { |
508 | main (args) { |
509 | this.actor.incrementTicks(1) |
510 | t.equals(args, 2, 'should recive a message') |
511 | } |
512 | |
513 | static get typeId () { |
514 | return 8 |
515 | } |
516 | } |
517 | |
518 | const hypervisor = new Hypervisor(tree) |
519 | hypervisor.registerContainer(testVMContainerA) |
520 | hypervisor.registerContainer(testVMContainerB) |
521 | |
522 | const {module: moduleB} = hypervisor.createActor(testVMContainerB.typeId) |
523 | const {module: moduleA} = hypervisor.createActor(testVMContainerA.typeId) |
524 | |
525 | const message = new Message({ |
526 | funcRef: moduleA.getFuncRef('main'), |
527 | funcArguments: [moduleB.getFuncRef('main')] |
528 | }) |
529 | |
530 | hypervisor.send(message) |
531 | |
532 | const stateRoot = await hypervisor.createStateRoot() |
533 | t.deepEquals(stateRoot, expectedState, 'expected root!') |
534 | }) |
535 | |
536 | tape('driver', async t => { |
537 | const tree = new RadixTree({ |
538 | db |
539 | }) |
540 | |
541 | const egress = new EgressDriver() |
542 | |
543 | egress.on('message', msg => { |
544 | t.equals(msg.funcArguments[0], 'hello') |
545 | t.end() |
546 | }) |
547 | |
548 | class testVMContainer extends BaseContainer { |
549 | main (funcRef) { |
550 | this.actor.send(new Message({ |
551 | funcRef, |
552 | funcArguments: ['hello'] |
553 | })) |
554 | } |
555 | } |
556 | |
557 | const hypervisor = new Hypervisor(tree, [testVMContainer], [egress]) |
558 | const {module} = hypervisor.createActor(testVMContainer.typeId) |
559 | |
560 | const message = new Message({ |
561 | funcRef: module.getFuncRef('main'), |
562 | funcArguments: [new FunctionRef({actorID: egress.id})] |
563 | }) |
564 | |
565 | hypervisor.send(message) |
566 | }) |
567 | |
568 | tape('random', async t => { |
569 | const numOfActors = 10 |
570 | const depth = 10 |
571 | const messageOrder = {} |
572 | let numOfMsg = 0 |
573 | const tree = new RadixTree({ |
574 | db |
575 | }) |
576 | |
577 | class BenchmarkContainer extends BaseContainer { |
578 | main () { |
579 | const refs = [...arguments] |
580 | const ref = refs.pop() |
581 | const last = messageOrder[this.actor.id.id.toString('hex')] |
582 | const message = this.actor.currentMessage |
583 | if (last) { |
584 | t.ok(last <= message._fromTicks, 'message should be in correct order') |
585 | } |
586 | messageOrder[this.actor.id.id.toString('hex')] = message._fromTicks |
587 | numOfMsg++ |
588 | this.actor.incrementTicks(10) |
589 | if (ref) { |
590 | this.actor.send(new Message({ |
591 | funcRef: ref, |
592 | funcArguments: refs |
593 | })) |
594 | } |
595 | } |
596 | } |
597 | |
598 | const hypervisor = new Hypervisor(tree) |
599 | hypervisor.registerContainer(BenchmarkContainer) |
600 | |
601 | const refernces = [] |
602 | let _numOfActors = numOfActors |
603 | while (_numOfActors--) { |
604 | const {module} = hypervisor.createActor(BenchmarkContainer.typeId) |
605 | refernces.push(module.getFuncRef('main')) |
606 | } |
607 | _numOfActors = numOfActors |
608 | let msgs = [] |
609 | while (_numOfActors--) { |
610 | let _depth = depth |
611 | const funcArguments = [] |
612 | while (_depth--) { |
613 | const r = Math.floor(Math.random() * numOfActors) |
614 | const ref = refernces[r] |
615 | funcArguments.push(ref) |
616 | } |
617 | const message = new Message({ |
618 | funcArguments, |
619 | funcRef: refernces[_numOfActors] |
620 | }) |
621 | msgs.push(message) |
622 | } |
623 | |
624 | hypervisor.send(msgs) |
625 | await hypervisor.scheduler.on('idle', () => { |
626 | t.equals(numOfMsg, 110) |
627 | t.end() |
628 | }) |
629 | }) |
630 |
Built with git-ssb-web