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