Files: 4c6125763fffeac43ae5302bb5541ac7f124c0a3 / tests / index.js
14224 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 compile () {} |
12 | static get typeId () { |
13 | return 9 |
14 | } |
15 | |
16 | static exports (m, id) { |
17 | return Object.keys(this.functions()).map(name => { |
18 | return { |
19 | name, |
20 | destId: id |
21 | } |
22 | }) |
23 | } |
24 | static instance (actor) { |
25 | return { |
26 | exports: this.functions(actor) |
27 | } |
28 | } |
29 | } |
30 | |
31 | tape('basic', async t => { |
32 | t.plan(2) |
33 | const expectedState = { |
34 | '/': Buffer.from('926de6b7eb39cfa8d7f8a44d1ef191d3bcb765a7', 'hex') |
35 | } |
36 | |
37 | const tree = new RadixTree({ |
38 | db: db |
39 | }) |
40 | |
41 | class testVMContainer extends BaseContainer { |
42 | static functions () { |
43 | return { |
44 | onMessage: (m) => { |
45 | t.true(m === 1, 'should recive a message') |
46 | } |
47 | } |
48 | } |
49 | } |
50 | |
51 | const hypervisor = new Hypervisor(tree) |
52 | hypervisor.registerContainer(testVMContainer) |
53 | |
54 | let {exports} = await hypervisor.createActor(testVMContainer.typeId) |
55 | |
56 | const message = new Message({ |
57 | funcRef: exports[0], |
58 | funcArguments: [1] |
59 | }) |
60 | hypervisor.send(message) |
61 | |
62 | const stateRoot = await hypervisor.createStateRoot() |
63 | t.deepEquals(stateRoot, expectedState, 'expected root!') |
64 | }) |
65 | |
66 | tape('two communicating actors', async t => { |
67 | t.plan(2) |
68 | const expectedState = { |
69 | '/': Buffer.from('a4c7ceacd8c867ae1d0b472d8bffa3cb10048331', 'hex') |
70 | } |
71 | |
72 | const tree = new RadixTree({ |
73 | db: db |
74 | }) |
75 | |
76 | class testVMContainerA extends BaseContainer { |
77 | static functions (actor) { |
78 | return { |
79 | onMessage: (funcRef) => { |
80 | const message = new Message({ |
81 | funcRef: funcRef, |
82 | funcArguments: [2] |
83 | }) |
84 | return actor.send(message) |
85 | } |
86 | } |
87 | } |
88 | } |
89 | |
90 | class testVMContainerB extends BaseContainer { |
91 | static functions () { |
92 | return { |
93 | onMessage: (args) => { |
94 | t.true(args === 2, 'should recive a message') |
95 | } |
96 | } |
97 | } |
98 | |
99 | static get typeId () { |
100 | return 8 |
101 | } |
102 | } |
103 | |
104 | const hypervisor = new Hypervisor(tree) |
105 | hypervisor.registerContainer(testVMContainerA) |
106 | hypervisor.registerContainer(testVMContainerB) |
107 | |
108 | const {exports: exportsB} = await hypervisor.createActor(testVMContainerB.typeId) |
109 | const {exports: exportsA} = await hypervisor.createActor(testVMContainerA.typeId) |
110 | const message = new Message({ |
111 | funcRef: exportsA[0], |
112 | funcArguments: [exportsB[0]] |
113 | }) |
114 | |
115 | await 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 | |
236 | const message1 = new Message({ |
237 | funcRef: actorA1.exports[0], |
238 | funcArguments: actorB.exports |
239 | }) |
240 | |
241 | hypervisor.send(message0) |
242 | hypervisor.send(message1) |
243 | |
244 | const stateRoot = await hypervisor.createStateRoot() |
245 | t.deepEquals(stateRoot, expectedState, 'expected root!') |
246 | }) |
247 | |
248 | tape('errors', async t => { |
249 | t.plan(3) |
250 | const expectedState = { |
251 | '/': Buffer.from('a4c7ceacd8c867ae1d0b472d8bffa3cb10048331', 'hex') |
252 | } |
253 | |
254 | const tree = new RadixTree({ |
255 | db: db |
256 | }) |
257 | |
258 | class testVMContainerA extends BaseContainer { |
259 | static functions (actor) { |
260 | return { |
261 | onMessage: funcRef => { |
262 | const message = new Message({ |
263 | funcRef |
264 | }) |
265 | message.on('execution:error', () => { |
266 | t.pass('should recive a exeption') |
267 | }) |
268 | actor.send(message) |
269 | } |
270 | } |
271 | } |
272 | } |
273 | |
274 | class testVMContainerB extends BaseContainer { |
275 | static functions (actor) { |
276 | return { |
277 | onMessage: funcRef => { |
278 | t.true(true, 'should recive a message') |
279 | throw new Error('test error') |
280 | } |
281 | } |
282 | } |
283 | |
284 | static get typeId () { |
285 | return 8 |
286 | } |
287 | } |
288 | |
289 | const hypervisor = new Hypervisor(tree) |
290 | hypervisor.registerContainer(testVMContainerA) |
291 | hypervisor.registerContainer(testVMContainerB) |
292 | |
293 | let {exports: exportsB} = await hypervisor.createActor(testVMContainerB.typeId) |
294 | let {exports: exportsA} = await hypervisor.createActor(testVMContainerA.typeId) |
295 | const message = new Message({ |
296 | funcRef: exportsA[0], |
297 | funcArguments: exportsB |
298 | }) |
299 | hypervisor.send(message) |
300 | const stateRoot = await hypervisor.createStateRoot() |
301 | t.deepEquals(stateRoot, expectedState, 'expected root!') |
302 | }) |
303 | |
304 | tape('actor creation', async t => { |
305 | t.plan(2) |
306 | const expectedState = { |
307 | '/': Buffer.from('f47377a763c91247e62138408d706a09bccaaf36', 'hex') |
308 | } |
309 | |
310 | const tree = new RadixTree({ |
311 | db: db |
312 | }) |
313 | |
314 | class testVMContainerA extends BaseContainer { |
315 | static functions (actor) { |
316 | return { |
317 | onCreation: async funcRef => { |
318 | const {exports} = await actor.createActor(testVMContainerB.typeId) |
319 | const message = new Message({ |
320 | funcRef: exports[0], |
321 | funcArguments: [actor.getFuncRef('onMessage')] |
322 | }) |
323 | actor.send(message) |
324 | }, |
325 | onMessage: data => { |
326 | t.equals(data, 'test', 'should recive a response message') |
327 | } |
328 | } |
329 | } |
330 | } |
331 | |
332 | class testVMContainerB extends BaseContainer { |
333 | static functions (actor) { |
334 | return { |
335 | onCreation: funcRef => { |
336 | actor.send(new Message({funcRef, funcArguments: ['test']})) |
337 | } |
338 | } |
339 | } |
340 | |
341 | static get typeId () { |
342 | return 8 |
343 | } |
344 | } |
345 | |
346 | const hypervisor = new Hypervisor(tree) |
347 | hypervisor.registerContainer(testVMContainerA) |
348 | hypervisor.registerContainer(testVMContainerB) |
349 | |
350 | const {exports} = await hypervisor.createActor(testVMContainerA.typeId) |
351 | await hypervisor.send(new Message({funcRef: exports[0]})) |
352 | |
353 | const stateRoot = await hypervisor.createStateRoot() |
354 | t.deepEquals(stateRoot, expectedState, 'expected root!') |
355 | }) |
356 | |
357 | tape('simple message arbiter test', async t => { |
358 | t.plan(4) |
359 | const expectedState = { |
360 | '/': Buffer.from('a4c7ceacd8c867ae1d0b472d8bffa3cb10048331', 'hex') |
361 | } |
362 | |
363 | const tree = new RadixTree({ |
364 | db: db |
365 | }) |
366 | |
367 | class testVMContainerA extends BaseContainer { |
368 | static functions (actor) { |
369 | return { |
370 | onCreation: funcRef => { |
371 | const message1 = new Message({ |
372 | funcArguments: ['first'], |
373 | funcRef |
374 | }) |
375 | const message2 = new Message({ |
376 | funcArguments: ['second'], |
377 | funcRef |
378 | }) |
379 | const message3 = new Message({ |
380 | funcArguments: ['third'], |
381 | funcRef |
382 | }) |
383 | actor.send(message1) |
384 | actor.incrementTicks(1) |
385 | actor.send(message2) |
386 | actor.incrementTicks(1) |
387 | actor.send(message3) |
388 | } |
389 | } |
390 | } |
391 | } |
392 | |
393 | let recMsg = 0 |
394 | |
395 | class testVMContainerB extends BaseContainer { |
396 | static functions (actor) { |
397 | return { |
398 | onMessage: data => { |
399 | actor.incrementTicks(1) |
400 | if (recMsg === 0) { |
401 | t.equal(data, 'first', 'should recive fist message') |
402 | } else if (recMsg === 1) { |
403 | t.equal(data, 'second', 'should recive second message') |
404 | } else { |
405 | t.equal(data, 'third', 'should recive third message') |
406 | } |
407 | recMsg++ |
408 | } |
409 | } |
410 | } |
411 | |
412 | static get typeId () { |
413 | return 8 |
414 | } |
415 | } |
416 | |
417 | const hypervisor = new Hypervisor(tree) |
418 | hypervisor.registerContainer(testVMContainerA) |
419 | hypervisor.registerContainer(testVMContainerB) |
420 | |
421 | const {exports: exportsB} = await hypervisor.createActor(testVMContainerB.typeId) |
422 | const {exports: exportsA} = await hypervisor.createActor(testVMContainerA.typeId) |
423 | const message = new Message({ |
424 | funcRef: exportsA[0], |
425 | funcArguments: exportsB |
426 | }) |
427 | hypervisor.send(message) |
428 | |
429 | const stateRoot = await hypervisor.createStateRoot() |
430 | t.deepEquals(stateRoot, expectedState, 'expected root!') |
431 | }) |
432 | |
433 | tape('arbiter test for id comparision', async t => { |
434 | t.plan(4) |
435 | let message |
436 | const expectedState = { |
437 | '/': Buffer.from('4633ac4b9f8212e501b6c56906039ec081fbe5a3', 'hex') |
438 | } |
439 | |
440 | const tree = new RadixTree({ |
441 | db: db |
442 | }) |
443 | |
444 | class testVMContainerA extends BaseContainer { |
445 | static functions (actor) { |
446 | return { |
447 | onCreation: (funcRef, funcArguments) => { |
448 | actor.incrementTicks(1) |
449 | message = new Message({ |
450 | funcRef, |
451 | funcArguments: [funcArguments] |
452 | }) |
453 | return actor.send(message) |
454 | } |
455 | } |
456 | } |
457 | } |
458 | |
459 | let recMsg = 0 |
460 | |
461 | class testVMContainerB extends BaseContainer { |
462 | static functions (actor) { |
463 | return { |
464 | onMessage: data => { |
465 | if (recMsg === 0) { |
466 | t.equal(data, 'first', 'should recive fist message') |
467 | } else if (recMsg === 1) { |
468 | t.equal(data, 'second', 'should recive second message') |
469 | } else { |
470 | t.equal(data, 'third', 'should recive third message') |
471 | } |
472 | recMsg++ |
473 | } |
474 | } |
475 | } |
476 | |
477 | static get typeId () { |
478 | return 8 |
479 | } |
480 | } |
481 | |
482 | const hypervisor = new Hypervisor(tree) |
483 | hypervisor.registerContainer(testVMContainerA) |
484 | hypervisor.registerContainer(testVMContainerB) |
485 | |
486 | let {exports: exportsB} = await hypervisor.createActor(testVMContainerB.typeId) |
487 | hypervisor.send(new Message({ |
488 | funcRef: exportsB[0], |
489 | funcArguments: ['first'] |
490 | })) |
491 | |
492 | const {exports: exportsA0} = await hypervisor.createActor(testVMContainerA.typeId) |
493 | |
494 | hypervisor.send(new Message({ |
495 | funcRef: exportsA0[0], |
496 | funcArguments: [exportsB[0], 'second'] |
497 | })) |
498 | |
499 | const {exports: exportsA1} = await hypervisor.createActor(testVMContainerA.typeId) |
500 | hypervisor.send(new Message({ |
501 | funcRef: exportsA1[0], |
502 | funcArguments: [exportsB[0], 'third'] |
503 | })) |
504 | |
505 | const stateRoot = await hypervisor.createStateRoot() |
506 | t.deepEquals(stateRoot, expectedState, 'expected root!') |
507 | }) |
508 | |
509 | tape('random', async t => { |
510 | const numOfActors = 10 |
511 | const depth = 10 |
512 | const messageOrder = {} |
513 | let numOfMsg = 0 |
514 | const tree = new RadixTree({ |
515 | db: db |
516 | }) |
517 | |
518 | class BenchmarkContainer extends BaseContainer { |
519 | static functions (actor) { |
520 | return { |
521 | onMessage: function () { |
522 | const refs = [...arguments] |
523 | const ref = refs.pop() |
524 | const last = messageOrder[actor.id.toString('hex')] |
525 | const message = actor.currentMessage |
526 | if (last) { |
527 | t.ok(last <= message._fromTicks) |
528 | } |
529 | messageOrder[actor.id.toString('hex')] = message._fromTicks |
530 | numOfMsg++ |
531 | actor.incrementTicks(10) |
532 | if (ref) { |
533 | return actor.send(new Message({ |
534 | funcRef: ref, |
535 | funcArguments: refs |
536 | })) |
537 | } |
538 | } |
539 | } |
540 | } |
541 | } |
542 | |
543 | const hypervisor = new Hypervisor(tree) |
544 | hypervisor.registerContainer(BenchmarkContainer) |
545 | |
546 | const refernces = [] |
547 | let _numOfActors = numOfActors |
548 | while (_numOfActors--) { |
549 | const {exports} = await hypervisor.createActor(BenchmarkContainer.typeId) |
550 | refernces.push(exports[0]) |
551 | } |
552 | _numOfActors = numOfActors |
553 | let msgs = [] |
554 | while (_numOfActors--) { |
555 | let _depth = depth |
556 | const funcArguments = [] |
557 | while (_depth--) { |
558 | const r = Math.floor(Math.random() * numOfActors) |
559 | const ref = refernces[r] |
560 | funcArguments.push(ref) |
561 | } |
562 | const message = new Message({ |
563 | funcArguments, |
564 | funcRef: refernces[_numOfActors] |
565 | }) |
566 | msgs.push(message) |
567 | } |
568 | |
569 | msgs.forEach(msg => hypervisor.send(msg)) |
570 | // console.log('here', numOfMsg) |
571 | await hypervisor.scheduler.wait(Infinity) |
572 | t.equals(numOfMsg, 110) |
573 | t.end() |
574 | }) |
575 |
Built with git-ssb-web