Files: 7feb7c9fd152c9b122c6ee9ec57387c444a89541 / tests / index.js
14201 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.true(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 | const message = new Message({ |
110 | funcRef: exportsA[0], |
111 | funcArguments: [exportsB[0]] |
112 | }) |
113 | |
114 | await hypervisor.send(message) |
115 | |
116 | const stateRoot = await hypervisor.createStateRoot() |
117 | t.deepEquals(stateRoot, expectedState, 'expected root!') |
118 | }) |
119 | |
120 | tape('three communicating actors', async t => { |
121 | t.plan(3) |
122 | const expectedState = { |
123 | '/': Buffer.from('4633ac4b9f8212e501b6c56906039ec081fbe5a3', 'hex') |
124 | } |
125 | |
126 | const tree = new RadixTree({ |
127 | db: db |
128 | }) |
129 | |
130 | class testVMContainerA extends BaseContainer { |
131 | static functions (actor) { |
132 | return { |
133 | onMessage: (funcRef) => { |
134 | const message = new Message({ |
135 | funcRef: funcRef, |
136 | funcArguments: [2] |
137 | }) |
138 | actor.send(message) |
139 | } |
140 | } |
141 | } |
142 | } |
143 | |
144 | class testVMContainerB extends BaseContainer { |
145 | static functions () { |
146 | return { |
147 | onMessage: (arg) => { |
148 | t.equals(arg, 2, 'should recive a message') |
149 | } |
150 | } |
151 | } |
152 | |
153 | static get typeId () { |
154 | return 8 |
155 | } |
156 | } |
157 | |
158 | const hypervisor = new Hypervisor(tree) |
159 | hypervisor.registerContainer(testVMContainerA) |
160 | hypervisor.registerContainer(testVMContainerB) |
161 | |
162 | let {exports: exportsB} = await hypervisor.createActor(testVMContainerB.typeId) |
163 | let {exports: exportsA0} = await hypervisor.createActor(testVMContainerA.typeId) |
164 | let {exports: exportsA1} = await hypervisor.createActor(testVMContainerA.typeId) |
165 | |
166 | const message0 = new Message({ |
167 | funcRef: exportsA0[0], |
168 | funcArguments: [exportsB[0]] |
169 | }) |
170 | |
171 | const message1 = new Message({ |
172 | funcRef: exportsA1[0], |
173 | funcArguments: [exportsB[0]] |
174 | }) |
175 | |
176 | await hypervisor.send(message0) |
177 | await hypervisor.send(message1) |
178 | |
179 | const stateRoot = await hypervisor.createStateRoot() |
180 | t.deepEquals(stateRoot, expectedState, 'expected root!') |
181 | }) |
182 | |
183 | tape('three communicating actors, with tick counting', async t => { |
184 | t.plan(3) |
185 | const expectedState = { |
186 | '/': Buffer.from('4633ac4b9f8212e501b6c56906039ec081fbe5a3', 'hex') |
187 | } |
188 | |
189 | const tree = new RadixTree({ |
190 | db: db |
191 | }) |
192 | |
193 | class testVMContainerA extends BaseContainer { |
194 | static functions (actor) { |
195 | return { |
196 | onMessage: funcRef => { |
197 | actor.incrementTicks(1) |
198 | const message = new Message({ |
199 | funcRef: funcRef, |
200 | funcArguments: [2] |
201 | }) |
202 | actor.send(message) |
203 | } |
204 | } |
205 | } |
206 | } |
207 | |
208 | class testVMContainerB extends BaseContainer { |
209 | static functions (actor) { |
210 | return { |
211 | onMessage: arg => { |
212 | t.equals(arg, 2, 'should recive a message') |
213 | } |
214 | } |
215 | } |
216 | |
217 | static get typeId () { |
218 | return 8 |
219 | } |
220 | } |
221 | |
222 | const hypervisor = new Hypervisor(tree) |
223 | hypervisor.registerContainer(testVMContainerA) |
224 | hypervisor.registerContainer(testVMContainerB) |
225 | |
226 | let actorB = await hypervisor.createActor(testVMContainerB.typeId) |
227 | let actorA0 = await hypervisor.createActor(testVMContainerA.typeId) |
228 | let actorA1 = await hypervisor.createActor(testVMContainerA.typeId) |
229 | |
230 | const message0 = new Message({ |
231 | funcRef: actorA0.exports[0], |
232 | funcArguments: [actorB.exports[0]] |
233 | }) |
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('random', async t => { |
509 | const numOfActors = 10 |
510 | const depth = 10 |
511 | const messageOrder = {} |
512 | let numOfMsg = 0 |
513 | const tree = new RadixTree({ |
514 | db: db |
515 | }) |
516 | |
517 | class BenchmarkContainer extends BaseContainer { |
518 | static functions (actor) { |
519 | return { |
520 | onMessage: function () { |
521 | const refs = [...arguments] |
522 | const ref = refs.pop() |
523 | const last = messageOrder[actor.id.toString('hex')] |
524 | const message = actor.currentMessage |
525 | if (last) { |
526 | t.ok(last <= message._fromTicks) |
527 | } |
528 | messageOrder[actor.id.toString('hex')] = message._fromTicks |
529 | numOfMsg++ |
530 | actor.incrementTicks(10) |
531 | if (ref) { |
532 | return actor.send(new Message({ |
533 | funcRef: ref, |
534 | funcArguments: refs |
535 | })) |
536 | } |
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 {exports} = await hypervisor.createActor(BenchmarkContainer.typeId) |
549 | refernces.push(exports[0]) |
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 | msgs.forEach(msg => hypervisor.send(msg)) |
569 | // console.log('here', numOfMsg) |
570 | await hypervisor.scheduler.wait(Infinity) |
571 | t.equals(numOfMsg, 110) |
572 | t.end() |
573 | }) |
574 |
Built with git-ssb-web