@nebulae/event-store-tpi-rx6 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,509 @@
1
+ // TEST LIBS
2
+ const assert = require('assert');
3
+ const Rx = require('rxjs');
4
+ const should = require('chai').should();
5
+ const expect = require('chai').expect;
6
+ var intersection = require('array-intersection');
7
+ const { map, concatAll, mergeMap, concatMap, take, toArray, reduce } = require('rxjs/operators');
8
+ //LIBS FOR TESTING
9
+ const MongoStore = require('../../lib/store/MongoStore');
10
+ const Event = require('../../lib/entities/Event');
11
+
12
+ //GLOABAL VARS to use between tests
13
+ let store = {};
14
+
15
+ /*
16
+ NOTES:
17
+ before run please start mongo:
18
+ docker run --rm -d -p 27017:27017 mongo --storageEngine wiredTiger
19
+ */
20
+
21
+ describe('MONGO STORE', function() {
22
+ describe('Prepare store', function() {
23
+ it('instance MongoStore', function(done) {
24
+ store = new MongoStore({
25
+ url: 'mongodb://localhost:27017',
26
+ aggregatesDbName: 'Aggregates',
27
+ eventStoreDbName: 'EventStore'
28
+ });
29
+ store.start$().subscribe(
30
+ () => {},
31
+ error => {
32
+ console.error(`Failed to connect MongoStore`);
33
+ return done(error);
34
+ },
35
+ () => {
36
+ console.log(`MongoStore connected`);
37
+ should.exist(store.mongoClient, 'mongoClient not defined');
38
+ should.exist(store.aggregatesDb, 'aggregatesDb not defined');
39
+ return done();
40
+ }
41
+ );
42
+ });
43
+ });
44
+ describe('Aggregates store', function() {
45
+ it('increment and get aggregate version', function(done) {
46
+ const aggreateType = 'TestAggregate_increment_version';
47
+ const aggreateId = '1234567890';
48
+ Rx.concat(
49
+ store.incrementAggregateVersionAndGet$(aggreateType, aggreateId),
50
+ store.incrementAggregateVersionAndGet$(aggreateType, aggreateId),
51
+ store.incrementAggregateVersionAndGet$(aggreateType, aggreateId)
52
+ )
53
+ .pipe(
54
+ reduce((acc, val) => {
55
+ acc.push(val);
56
+ return acc;
57
+ }, [])
58
+ )
59
+ .subscribe(
60
+ ([[v1, t1], [v2, t2], [v3, t3]]) => {
61
+ assert.equal(v2.version, v1.version + 1);
62
+ assert.equal(v3.version, v2.version + 1);
63
+ },
64
+ error => {
65
+ console.log(
66
+ `Error incrementing and getting Aggregate versions`,
67
+ error
68
+ );
69
+ return done(error);
70
+ },
71
+ () => {
72
+ return done();
73
+ }
74
+ );
75
+ });
76
+ it('increment and get aggregate version setting fixed version time', function(done) {
77
+ const aggreateType = 'TestAggregate_increment_version_fixed_time';
78
+ const aggreateId = Math.random();
79
+ const monthTime = 1000 * 86400 * 30;
80
+ const time1 = Date.now();
81
+ const time2 = Date.now() + monthTime;
82
+ const time3 = Date.now() + monthTime + monthTime;
83
+ const minute = 60000;
84
+ Rx.concat(
85
+ store.incrementAggregateVersionAndGet$(aggreateType, aggreateId, time1),
86
+ store.incrementAggregateVersionAndGet$(
87
+ aggreateType,
88
+ aggreateId,
89
+ time1 + minute
90
+ ),
91
+ store.incrementAggregateVersionAndGet$(
92
+ aggreateType,
93
+ aggreateId,
94
+ time1 + minute + minute
95
+ ),
96
+
97
+ store.incrementAggregateVersionAndGet$(aggreateType, aggreateId, time2),
98
+ store.incrementAggregateVersionAndGet$(
99
+ aggreateType,
100
+ aggreateId,
101
+ time2 + minute
102
+ ),
103
+ store.incrementAggregateVersionAndGet$(
104
+ aggreateType,
105
+ aggreateId,
106
+ time2 + minute + minute
107
+ ),
108
+
109
+ store.incrementAggregateVersionAndGet$(aggreateType, aggreateId, time3),
110
+ store.incrementAggregateVersionAndGet$(
111
+ aggreateType,
112
+ aggreateId,
113
+ time3 + minute
114
+ ),
115
+ store.incrementAggregateVersionAndGet$(
116
+ aggreateType,
117
+ aggreateId,
118
+ time3 + minute + minute
119
+ )
120
+ )
121
+ .pipe(
122
+ reduce((acc, val) => {
123
+ acc.push(val);
124
+ return acc;
125
+ }, [])
126
+ )
127
+ .subscribe(
128
+ ([[v1], [v2], [v3], [v4], [v5], [v6], [v7], [v8], [v9]]) => {
129
+ // assert version incremental
130
+ assert.equal(v2.version, v1.version + 1);
131
+ assert.equal(v3.version, v2.version + 1);
132
+ assert.equal(v4.version, v3.version + 1);
133
+ assert.equal(v5.version, v4.version + 1);
134
+ assert.equal(v6.version, v5.version + 1);
135
+ assert.equal(v7.version, v6.version + 1);
136
+ assert.equal(v8.version, v7.version + 1);
137
+ assert.equal(v9.version, v8.version + 1);
138
+
139
+ //chech every month index has 3 records
140
+ Object.keys(v9.index).forEach(indexTag => {
141
+ assert.equal(
142
+ v9.index[indexTag].endVersion - v9.index[indexTag].initVersion,
143
+ 2
144
+ );
145
+ });
146
+
147
+ // assert(v9.version, v8.version + 1);
148
+ // assert(parseInt(Object.keys(v4.index)[0]), parseInt(Object.keys(v1.index)[0]) + 1);
149
+ },
150
+ error => {
151
+ console.log(
152
+ `Error incrementing and getting Aggregate versions fixing times`,
153
+ error
154
+ );
155
+ return done(error);
156
+ },
157
+ () => {
158
+ return done();
159
+ }
160
+ );
161
+ });
162
+
163
+ it('get aggregates created after a date', function(done) {
164
+ this.timeout(3000);
165
+
166
+ const aggreateType = 'TestAggregate_icreated_after_date_' + Math.random();
167
+ const aggreateId = Math.random();
168
+ const monthTime = 1000 * 86400 * 30;
169
+ const time1 = Date.now();
170
+ const time2 = Date.now() + monthTime;
171
+ const time3 = Date.now() + monthTime + monthTime;
172
+ const minute = 60000;
173
+
174
+ Rx.concat(
175
+ store.incrementAggregateVersionAndGet$(
176
+ aggreateType,
177
+ Math.random(),
178
+ time1
179
+ ),
180
+ store.incrementAggregateVersionAndGet$(
181
+ aggreateType,
182
+ Math.random(),
183
+ time1 + minute
184
+ ),
185
+ store.incrementAggregateVersionAndGet$(
186
+ aggreateType,
187
+ Math.random(),
188
+ time1 + minute + minute
189
+ ),
190
+
191
+ store.incrementAggregateVersionAndGet$(
192
+ aggreateType,
193
+ Math.random(),
194
+ time2
195
+ ),
196
+ store.incrementAggregateVersionAndGet$(
197
+ aggreateType,
198
+ Math.random(),
199
+ time2 + minute
200
+ ),
201
+ store.incrementAggregateVersionAndGet$(
202
+ aggreateType,
203
+ Math.random(),
204
+ time2 + minute + minute
205
+ ),
206
+
207
+ store.incrementAggregateVersionAndGet$(
208
+ aggreateType,
209
+ Math.random(),
210
+ time3
211
+ ),
212
+ store.incrementAggregateVersionAndGet$(
213
+ aggreateType,
214
+ Math.random(),
215
+ time3 + minute
216
+ ),
217
+ store.incrementAggregateVersionAndGet$(
218
+ aggreateType,
219
+ Math.random(),
220
+ time3 + minute + minute
221
+ )
222
+ )
223
+ .pipe(
224
+ reduce((acc, val) => {
225
+ acc.push(val);
226
+ return acc;
227
+ }, [])
228
+ )
229
+ .subscribe(
230
+ aggregatesVsTimeArray => {
231
+ let index = 2;
232
+ let verifiedCount = 0;
233
+ const verifiedTotal = 6;
234
+ store
235
+ .findAgregatesCreatedAfter$(
236
+ aggreateType,
237
+ aggregatesVsTimeArray[index][0].creationTime
238
+ )
239
+ .subscribe(
240
+ aggregate => {
241
+ ++index;
242
+ //console.log(`${aggregate.creationTime} vs ${aggregatesVsTimeArray[index][0].creationTime}`);
243
+ assert.equal(
244
+ aggregate.creationTime,
245
+ aggregatesVsTimeArray[index][0].creationTime
246
+ );
247
+ ++verifiedCount;
248
+ },
249
+ error => {
250
+ console.log(
251
+ `Error invoking findAgregatesCreatedAfter`,
252
+ error
253
+ );
254
+ return done(error);
255
+ },
256
+ () => {
257
+ assert.equal(verifiedCount, verifiedTotal);
258
+ return done();
259
+ }
260
+ );
261
+ },
262
+ error => {
263
+ console.log(
264
+ `Error incrementing and getting Aggregates created after a date`,
265
+ error
266
+ );
267
+ return done(error);
268
+ },
269
+ () => {}
270
+ );
271
+ });
272
+ });
273
+
274
+ describe('Events Store', function() {
275
+ it('Push an event', function(done) {
276
+ const evt = new Event({
277
+ eventType: 'TestEventPushed',
278
+ eventTypeVersion: 1,
279
+ aggregateType: 'TestAggregate',
280
+ aggregateId: '12345',
281
+ data: { a: 1, b: 2, c: 3 },
282
+ user: 'MochaTest'
283
+ });
284
+ Rx.concat(store.pushEvent$(evt))
285
+ .pipe(
286
+ reduce((acc, val) => {
287
+ acc.push(val);
288
+ return acc;
289
+ }, [])
290
+ )
291
+ .subscribe(
292
+ ([{ aggregate, event, versionTimeStr }]) => {
293
+ assert.equal(event.av, aggregate.version);
294
+ assert.equal(event.timestamp, aggregate.versionTime);
295
+ },
296
+ error => {
297
+ console.log(
298
+ `Error incrementing and getting Aggregate versions`,
299
+ error
300
+ );
301
+ return done(error);
302
+ },
303
+ () => {
304
+ return done();
305
+ }
306
+ );
307
+ });
308
+ it('get events on same month', function(done) {
309
+ let evtVersionChecker = 1;
310
+ aggregateId = `aggregate-id-${Math.random()}`;
311
+ const evt = new Event({
312
+ eventType: `TestAggregate_retrieval_same_month_event`,
313
+ eventTypeVersion: 1,
314
+ aggregateType: 'TestAggregate_retrieval_same_month',
315
+ aggregateId,
316
+ data: { a: 1, b: 2, c: 3 },
317
+ user: 'MochaTest'
318
+ });
319
+ Rx.range(0, 10)
320
+ .pipe(
321
+ map(i => store.pushEvent$({ ...evt })),
322
+ concatAll(),
323
+ reduce((acc, evt) => {
324
+ acc.push(evt);
325
+ return acc;
326
+ }, []),
327
+ mergeMap(pushedVersions =>
328
+ store.getEvents$(
329
+ 'TestAggregate_retrieval_same_month',
330
+ aggregateId,
331
+ 0
332
+ )
333
+ )
334
+ )
335
+ .subscribe(
336
+ evt => {
337
+ assert.equal(evtVersionChecker++, evt.av);
338
+ },
339
+ error => {
340
+ console.error(`Error retrieving events`, error);
341
+ return done(error);
342
+ },
343
+ () => {
344
+ assert.equal(evtVersionChecker - 1, 10);
345
+ console.log(`TestAggregate_retrieval_same_month_event completed`);
346
+ return done();
347
+ }
348
+ );
349
+ });
350
+
351
+ it('get events on multiple months', function(done) {
352
+ const monthTime = 1000 * 86400 * 30;
353
+
354
+ const aggregateId = `aggregate-id-${Math.random()}`;
355
+ console.log(
356
+ `get events on multiple months: aggregateId = ${aggregateId}`
357
+ );
358
+
359
+ const total = 30;
360
+ const offset = 15;
361
+ let evtVersionChecker = 15;
362
+
363
+ const evt = new Event({
364
+ eventType: `TestAggregate_retrieval_multiple_months_event`,
365
+ eventTypeVersion: 1,
366
+ aggregateType: 'TestAggregate_retrieval_multiple_months',
367
+ aggregateId,
368
+ data: { a: 1, b: 2, c: 3 },
369
+ user: 'MochaTest'
370
+ });
371
+
372
+ Rx.range(0, 3)
373
+ .pipe(
374
+ map(i => i * monthTime),
375
+ concatMap(monthOffsetMillis =>
376
+ Rx.range(0, 10).pipe(map(evtNumber => {
377
+ return { monthOffsetMillis, evtNumber };
378
+ }))
379
+ ),
380
+ map(({ monthOffsetMillis, evtNumber }) => {
381
+ const newEvt = { ...evt };
382
+ newEvt.timestamp = Date.now() + monthOffsetMillis;
383
+ return store.pushEvent$(newEvt);
384
+ }),
385
+ concatAll(),
386
+ reduce((acc, evt) => {
387
+ acc.push(evt);
388
+ return acc;
389
+ }, []),
390
+ mergeMap(pushedVersions =>
391
+ store.getEvents$(
392
+ 'TestAggregate_retrieval_multiple_months',
393
+ aggregateId,
394
+ offset
395
+ )
396
+ )
397
+ )
398
+ .subscribe(
399
+ evt => {
400
+ evtVersionChecker = evtVersionChecker + 1;
401
+ assert.equal(evt.av, evtVersionChecker);
402
+ },
403
+ error => {
404
+ console.error(`Error retrieving events`, error);
405
+ return done(error);
406
+ },
407
+ () => {
408
+ //assert.equal((evtVersionChecker - offset), total - offset);
409
+ console.log(`TestAggregate_retrieval_multiple_months completed`);
410
+ return done();
411
+ }
412
+ );
413
+ });
414
+ });
415
+
416
+ describe('Events ACK and Retrieve', function() {
417
+ const aggregateType = 'TestAggregate_' + Math.random();
418
+ const events = [];
419
+ const versionTimeStrSet = new Set();
420
+ it('push some test events', function(done) {
421
+ Rx.range(1, 100)
422
+ .pipe(
423
+ map(i => {
424
+ const timestamp = Date.now();
425
+ const evt = new Event({
426
+ eventType: 'TestEventAck',
427
+ eventTypeVersion: 1,
428
+ aggregateType,
429
+ aggregateId: i,
430
+ data: { a: 1, b: 2, c: 3 },
431
+ user: 'MochaTest'
432
+ });
433
+ evt.timestamp = timestamp + i * 86400000; //event per day
434
+ return evt;
435
+ }),
436
+ concatMap(evt => store.pushEvent$(evt))
437
+ )
438
+ .subscribe(
439
+ ({ aggregate, event, versionTimeStr }) => {
440
+ events.push(event);
441
+ versionTimeStrSet.add(versionTimeStr);
442
+ //console.log(` pushed test event for ack => at:${event.at}, aid:${event.aid}, ts=${event.timestamp}, versionTimeStr=${versionTimeStr}`);
443
+ },
444
+ error => {
445
+ //console.log(` Error pusing test events for ACK`, error);
446
+ return done(error);
447
+ },
448
+ () => {
449
+ assert.equal(events.length, 100);
450
+ expect(versionTimeStrSet.size).to.be.within(4, 5);
451
+ return done();
452
+ }
453
+ );
454
+ });
455
+
456
+ it('acknowledge half the messages and retrieve the other half', function(done) {
457
+ this.timeout(5000);
458
+ Rx.concat(
459
+ store.ensureAcknowledgeRegistry$(aggregateType,'mocha'),
460
+ Rx.from(events).pipe(
461
+ take(events.length / 2),
462
+ concatMap(evt => store.acknowledgeEvent$(evt, 'MOCHA_EventStore')),
463
+ //.do(event => console.log(` event acknowledeg => at:${event.at}, aid:${event.aid}, ts=${event.timestamp}`))
464
+ toArray()
465
+ ),
466
+ store
467
+ .retrieveUnacknowledgedEvents$(aggregateType, 'MOCHA_EventStore')
468
+ //.do(event => console.log(` event retrieved without ack => at:${event.at}, aid:${event.aid}, ts=${event.timestamp}`))
469
+ .pipe(toArray())
470
+ )
471
+ .pipe(toArray())
472
+ .subscribe(
473
+ ([ensure, ackEvents, nacksEvents]) => {
474
+ console.log(ensure);
475
+ expect(ackEvents.length + nacksEvents.length).to.be.equal(
476
+ events.length
477
+ );
478
+ expect(ackEvents.length).to.be.equal(nacksEvents.length);
479
+ const intersec = intersection(ackEvents, nacksEvents);
480
+ expect(intersec).to.be.empty;
481
+ },
482
+ error => {
483
+ return done(error);
484
+ },
485
+
486
+ () => {
487
+ return done();
488
+ }
489
+ );
490
+ });
491
+ });
492
+
493
+ describe('de-prepare MongoStore', function() {
494
+ it('stop MongoStore', function(done) {
495
+ store.stop$().subscribe(
496
+ next => console.log(next),
497
+ error => {
498
+ console.error(`Error stopping MongoStore`, error);
499
+ return done(error);
500
+ },
501
+ () => {
502
+ console.log('MongoStore stopped');
503
+ assert.ok(true, 'MqttBroker stoped');
504
+ return done();
505
+ }
506
+ );
507
+ });
508
+ });
509
+ });