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