Files: c1baf026f5fba05cb5619603b350445d6e40a0d5 / tests / index.js
14256 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('926de6b7eb39cfa8d7f8a44d1ef191d3bcb765a7', '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('a4c7ceacd8c867ae1d0b472d8bffa3cb10048331', '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('4633ac4b9f8212e501b6c56906039ec081fbe5a3', '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('4633ac4b9f8212e501b6c56906039ec081fbe5a3', '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('a4c7ceacd8c867ae1d0b472d8bffa3cb10048331', '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('f47377a763c91247e62138408d706a09bccaaf36', '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: [this.actor.getFuncRef('main')] |
285 | }) |
286 | this.actor.send(message) |
287 | } |
288 | main (data) { |
289 | t.equals(data, 'test', 'should recive a response message') |
290 | } |
291 | } |
292 | |
293 | class testVMContainerB extends BaseContainer { |
294 | main (funcRef) { |
295 | this.actor.send(new Message({funcRef, funcArguments: ['test']})) |
296 | } |
297 | |
298 | static get typeId () { |
299 | return 8 |
300 | } |
301 | } |
302 | |
303 | const hypervisor = new Hypervisor(tree) |
304 | hypervisor.registerContainer(testVMContainerA) |
305 | hypervisor.registerContainer(testVMContainerB) |
306 | |
307 | const {module} = await hypervisor.createActor(testVMContainerA.typeId) |
308 | await hypervisor.send(new Message({funcRef: module.start})) |
309 | |
310 | const stateRoot = await hypervisor.createStateRoot() |
311 | t.deepEquals(stateRoot, expectedState, 'expected root!') |
312 | }) |
313 | |
314 | tape('simple message arbiter test', async t => { |
315 | t.plan(4) |
316 | const expectedState = { |
317 | '/': Buffer.from('a4c7ceacd8c867ae1d0b472d8bffa3cb10048331', 'hex') |
318 | } |
319 | |
320 | const tree = new RadixTree({ |
321 | db: db |
322 | }) |
323 | |
324 | class testVMContainerA extends BaseContainer { |
325 | main (funcRef) { |
326 | const message1 = new Message({ |
327 | funcArguments: ['first'], |
328 | funcRef |
329 | }) |
330 | const message2 = new Message({ |
331 | funcArguments: ['second'], |
332 | funcRef |
333 | }) |
334 | const message3 = new Message({ |
335 | funcArguments: ['third'], |
336 | funcRef |
337 | }) |
338 | this.actor.send(message1) |
339 | this.actor.incrementTicks(1) |
340 | this.actor.send(message2) |
341 | this.actor.incrementTicks(1) |
342 | this.actor.send(message3) |
343 | } |
344 | } |
345 | |
346 | let recMsg = 0 |
347 | |
348 | class testVMContainerB extends BaseContainer { |
349 | main (data) { |
350 | this.actor.incrementTicks(1) |
351 | if (recMsg === 0) { |
352 | t.equal(data, 'first', 'should recive fist message') |
353 | } else if (recMsg === 1) { |
354 | t.equal(data, 'second', 'should recive second message') |
355 | } else { |
356 | t.equal(data, 'third', 'should recive third message') |
357 | } |
358 | recMsg++ |
359 | } |
360 | |
361 | static get typeId () { |
362 | return 8 |
363 | } |
364 | } |
365 | |
366 | const hypervisor = new Hypervisor(tree) |
367 | hypervisor.registerContainer(testVMContainerA) |
368 | hypervisor.registerContainer(testVMContainerB) |
369 | |
370 | const {module: moduleB} = await hypervisor.createActor(testVMContainerB.typeId) |
371 | const {module: moduleA} = await hypervisor.createActor(testVMContainerA.typeId) |
372 | const message = new Message({ |
373 | funcRef: moduleA.main, |
374 | funcArguments: [moduleB.main] |
375 | }) |
376 | hypervisor.send(message) |
377 | |
378 | const stateRoot = await hypervisor.createStateRoot() |
379 | t.deepEquals(stateRoot, expectedState, 'expected root!') |
380 | }) |
381 | |
382 | tape('arbiter test for id comparision', async t => { |
383 | t.plan(4) |
384 | let message |
385 | const expectedState = { |
386 | '/': Buffer.from('4633ac4b9f8212e501b6c56906039ec081fbe5a3', 'hex') |
387 | } |
388 | |
389 | const tree = new RadixTree({ |
390 | db: db |
391 | }) |
392 | |
393 | class testVMContainerA extends BaseContainer { |
394 | main (funcRef, funcArguments) { |
395 | this.actor.incrementTicks(1) |
396 | message = new Message({ |
397 | funcRef, |
398 | funcArguments: [funcArguments] |
399 | }) |
400 | this.actor.send(message) |
401 | } |
402 | } |
403 | |
404 | let recMsg = 0 |
405 | |
406 | class testVMContainerB extends BaseContainer { |
407 | main (data) { |
408 | if (recMsg === 0) { |
409 | t.equal(data, 'first', 'should recive fist message') |
410 | } else if (recMsg === 1) { |
411 | t.equal(data, 'second', 'should recive second message') |
412 | } else { |
413 | t.equal(data, 'third', 'should recive third message') |
414 | } |
415 | recMsg++ |
416 | } |
417 | |
418 | static get typeId () { |
419 | return 8 |
420 | } |
421 | } |
422 | |
423 | const hypervisor = new Hypervisor(tree) |
424 | hypervisor.registerContainer(testVMContainerA) |
425 | hypervisor.registerContainer(testVMContainerB) |
426 | |
427 | let {module: moduleB} = await hypervisor.createActor(testVMContainerB.typeId) |
428 | hypervisor.send(new Message({ |
429 | funcRef: moduleB.main, |
430 | funcArguments: ['first'] |
431 | })) |
432 | |
433 | const {module: moduleA0} = await hypervisor.createActor(testVMContainerA.typeId) |
434 | |
435 | hypervisor.send(new Message({ |
436 | funcRef: moduleA0.main, |
437 | funcArguments: [moduleB.main, 'second'] |
438 | })) |
439 | |
440 | const {module: moduleA1} = await hypervisor.createActor(testVMContainerA.typeId) |
441 | hypervisor.send(new Message({ |
442 | funcRef: moduleA1.main, |
443 | funcArguments: [moduleB.main, 'third'] |
444 | })) |
445 | |
446 | const stateRoot = await hypervisor.createStateRoot() |
447 | t.deepEquals(stateRoot, expectedState, 'expected root!') |
448 | }) |
449 | |
450 | tape('async work', async t => { |
451 | t.plan(3) |
452 | const expectedState = { |
453 | '/': Buffer.from('a4c7ceacd8c867ae1d0b472d8bffa3cb10048331', 'hex') |
454 | } |
455 | |
456 | const tree = new RadixTree({ |
457 | db: db |
458 | }) |
459 | |
460 | class testVMContainerA extends BaseContainer { |
461 | main (funcRef) { |
462 | const message = new Message({ |
463 | funcRef: funcRef, |
464 | funcArguments: [2] |
465 | }) |
466 | this.actor.send(message) |
467 | |
468 | const message2 = new Message({ |
469 | funcRef: funcRef, |
470 | funcArguments: [2] |
471 | }) |
472 | this.actor.send(message2) |
473 | this.actor.incrementTicks(1) |
474 | return new Promise((resolve, reject) => { |
475 | setTimeout(() => { |
476 | resolve() |
477 | }, 10) |
478 | }) |
479 | } |
480 | } |
481 | |
482 | class testVMContainerB extends BaseContainer { |
483 | main (args) { |
484 | this.actor.incrementTicks(1) |
485 | t.equals(args, 2, 'should recive a message') |
486 | } |
487 | |
488 | static get typeId () { |
489 | return 8 |
490 | } |
491 | } |
492 | |
493 | const hypervisor = new Hypervisor(tree) |
494 | hypervisor.registerContainer(testVMContainerA) |
495 | hypervisor.registerContainer(testVMContainerB) |
496 | |
497 | const {module: moduleB} = await hypervisor.createActor(testVMContainerB.typeId) |
498 | const {module: moduleA} = await hypervisor.createActor(testVMContainerA.typeId) |
499 | |
500 | const message = new Message({ |
501 | funcRef: moduleA.main, |
502 | funcArguments: [moduleB.main] |
503 | }) |
504 | |
505 | hypervisor.send(message) |
506 | |
507 | const stateRoot = await hypervisor.createStateRoot() |
508 | t.deepEquals(stateRoot, expectedState, 'expected root!') |
509 | }) |
510 | |
511 | tape('random', async t => { |
512 | const numOfActors = 10 |
513 | const depth = 10 |
514 | const messageOrder = {} |
515 | let numOfMsg = 0 |
516 | const tree = new RadixTree({ |
517 | db: db |
518 | }) |
519 | |
520 | class BenchmarkContainer extends BaseContainer { |
521 | main () { |
522 | const refs = [...arguments] |
523 | const ref = refs.pop() |
524 | const last = messageOrder[this.actor.id.toString('hex')] |
525 | const message = this.actor.currentMessage |
526 | if (last) { |
527 | t.ok(last <= message._fromTicks) |
528 | } |
529 | messageOrder[this.actor.id.toString('hex')] = message._fromTicks |
530 | numOfMsg++ |
531 | this.actor.incrementTicks(10) |
532 | if (ref) { |
533 | this.actor.send(new Message({ |
534 | funcRef: ref, |
535 | funcArguments: refs |
536 | })) |
537 | } |
538 | } |
539 | } |
540 | |
541 | const hypervisor = new Hypervisor(tree) |
542 | hypervisor.registerContainer(BenchmarkContainer) |
543 | |
544 | const refernces = [] |
545 | let _numOfActors = numOfActors |
546 | while (_numOfActors--) { |
547 | const {module} = await hypervisor.createActor(BenchmarkContainer.typeId) |
548 | refernces.push(module.main) |
549 | } |
550 | _numOfActors = numOfActors |
551 | let msgs = [] |
552 | while (_numOfActors--) { |
553 | let _depth = depth |
554 | const funcArguments = [] |
555 | while (_depth--) { |
556 | const r = Math.floor(Math.random() * numOfActors) |
557 | const ref = refernces[r] |
558 | funcArguments.push(ref) |
559 | } |
560 | const message = new Message({ |
561 | funcArguments, |
562 | funcRef: refernces[_numOfActors] |
563 | }) |
564 | msgs.push(message) |
565 | } |
566 | |
567 | hypervisor.send(msgs) |
568 | await hypervisor.scheduler.on('idle', () => { |
569 | t.equals(numOfMsg, 110) |
570 | t.end() |
571 | }) |
572 | }) |
573 |
Built with git-ssb-web