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