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