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