event-storage 0.8.0 → 0.9.1

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.
@@ -1,455 +0,0 @@
1
- const expect = require('expect.js');
2
- const fs = require('fs-extra');
3
- const Storage = require('../src/Storage');
4
- const Consumer = require('../src/Consumer');
5
-
6
- const dataDirectory = __dirname + '/data';
7
-
8
- describe('Consumer', function() {
9
-
10
- let consumer, storage;
11
-
12
- beforeEach(function () {
13
- fs.emptyDirSync(dataDirectory);
14
- storage = new Storage({ dataDirectory });
15
- storage.ensureIndex('foobar', (doc) => doc.type === 'Foobar');
16
- storage.ensureIndex('bazinga', (doc) => doc.type === 'Bazinga');
17
- });
18
-
19
- afterEach(function () {
20
- if (storage) {
21
- storage.close();
22
- }
23
- storage = null;
24
- consumer = null;
25
- });
26
-
27
- it('throws when instanciated without a storage', function() {
28
- expect(() => new Consumer('foobar', 'consumer1')).to.throwError(/storage/);
29
- });
30
-
31
- it('throws when instanciated without an index name', function() {
32
- expect(() => new Consumer(storage)).to.throwError(/index name/);
33
- });
34
-
35
- it('throws when instanciated without an identifier', function() {
36
- expect(() => new Consumer(storage, 'foobar')).to.throwError(/identifier/);
37
- });
38
-
39
- it('creates consumer directory if not existing', function() {
40
- consumer = new Consumer(storage, 'foobar', 'consumer1');
41
- expect(fs.existsSync(dataDirectory + '/consumers')).to.be(true);
42
- });
43
-
44
- it('cleans up failed write left-overs', function() {
45
- consumer = new Consumer(storage, 'foobar', 'consumer1');
46
- consumer.stop();
47
- fs.writeFileSync(consumer.fileName + '.1', 'failed write!');
48
- consumer = new Consumer(storage, 'foobar', 'consumer1');
49
- expect(fs.existsSync(consumer.fileName + '.1')).to.be(false);
50
- });
51
-
52
- it('emits event when catching up', function(done){
53
- consumer = new Consumer(storage, 'foobar', 'consumer1');
54
- consumer.stop();
55
- storage.write({ type: 'Foobar', id: 1 });
56
- consumer.on('caught-up', () => {
57
- expect(consumer.position).to.be(1);
58
- done();
59
- });
60
- consumer.start();
61
- });
62
-
63
- it('can start with some initial state', function(done){
64
- consumer = new Consumer(storage, 'foobar', 'consumer1', { foos: 0, lastId: 0 });
65
- expect(consumer.state.foos).to.be(0);
66
- expect(consumer.state.lastId).to.be(0);
67
- storage.write({ type: 'Foobar', id: 2 });
68
- consumer.on('caught-up', () => {
69
- expect(consumer.state.foos).to.be(1);
70
- expect(consumer.state.lastId).to.be(2);
71
- done();
72
- });
73
- consumer.on('data', document => {
74
- if (document.type === 'Foobar') {
75
- consumer.setState({foos: consumer.state.foos + 1, lastId: document.id});
76
- }
77
- });
78
- });
79
-
80
- it('continues emitting data after catching up', function(done){
81
- consumer = new Consumer(storage, 'foobar', 'consumer1');
82
- consumer.stop();
83
- storage.write({ type: 'Foobar', id: 1 });
84
- consumer.on('caught-up', () => {
85
- expect(consumer.position).to.be(1);
86
- storage.write({ type: 'Foobar', id: 2 });
87
- storage.write({ type: 'Foobar', id: 3 });
88
- });
89
- let expected = 0;
90
- consumer.on('data', document => {
91
- expect(document.id).to.be(++expected);
92
- if (document.id === 3) {
93
- done();
94
- }
95
- });
96
- consumer.start();
97
- });
98
-
99
- it('receives new documents as they are added', function(done){
100
- consumer = new Consumer(storage, 'foobar', 'consumer1');
101
- let expected = 0;
102
- consumer.on('data', document => {
103
- expect(document.id).to.be(++expected);
104
- if (document.id === 3) {
105
- done();
106
- }
107
- });
108
- storage.write({ type: 'Foobar', id: 1 });
109
- storage.write({ type: 'Foobar', id: 2 });
110
- storage.write({ type: 'Foobar', id: 3 });
111
- });
112
-
113
- it('can start from arbitrary position', function(done){
114
- consumer = new Consumer(storage, 'foobar', 'consumer1', 2);
115
- let expected = 3;
116
- consumer.on('data', document => {
117
- expect(document.id).to.be(expected);
118
- done();
119
- });
120
- storage.write({ type: 'Foobar', id: 1 });
121
- storage.write({ type: 'Foobar', id: 2 });
122
- storage.write({ type: 'Foobar', id: 3 });
123
- });
124
-
125
- it('stops when pushing fails', function(done){
126
- consumer = new Consumer(storage, 'foobar', 'consumer1');
127
- consumer.on('caught-up', () => {
128
- storage.write({type: 'Foobar', id: 1});
129
- storage.write({type: 'Foobar', id: 2});
130
- storage.write({type: 'Foobar', id: 3});
131
- });
132
- const push = consumer.push.bind(consumer);
133
- consumer.push = (doc) => push(doc) && false;
134
- consumer.on('data', document => {
135
- expect(document.id).to.be(1);
136
- setTimeout(done, 10);
137
- });
138
- });
139
-
140
- it('ignores events on other streams', function(done){
141
- consumer = new Consumer(storage, 'foobar', 'consumer1');
142
- consumer.on('caught-up', () => {
143
- storage.write({type: 'Foobar', id: 1});
144
- storage.write({type: 'Foobar', id: 2});
145
- storage.write({type: 'Bazinga', id: 3});
146
- });
147
- let expected = 0;
148
- consumer.on('data', document => {
149
- expect(document.id).to.be(++expected);
150
- if (document.id === 2) {
151
- setTimeout(done, 10);
152
- }
153
- });
154
- });
155
-
156
- it('works with multiple consumers', function(done){
157
- consumer = new Consumer(storage, 'foobar', 'consumer1');
158
- consumer.on('caught-up', () => {
159
- storage.write({type: 'Foobar', id: 1});
160
- storage.write({type: 'Foobar', id: 2});
161
- storage.write({type: 'Bazinga', id: 3});
162
- });
163
- const consumer2 = new Consumer(storage, 'bazinga', 'consumer2');
164
- let expected = 0;
165
- consumer.on('data', document => {
166
- expect(document.id).to.be(++expected);
167
- if (document.id === 2) {
168
- consumer2.on('data', document => {
169
- expect(document.id).to.be(++expected);
170
- done();
171
- });
172
- }
173
- });
174
- });
175
-
176
- it('continues from last position after restart', function(done){
177
- consumer = new Consumer(storage, 'foobar', 'consumer1');
178
- let expected = 0;
179
- consumer.on('data', document => {
180
- expect(document.id).to.be(++expected);
181
- if (document.id === 3) {
182
- consumer.stop();
183
- storage.write({ type: 'Foobar', id: 4 });
184
- storage.write({ type: 'Foobar', id: 5 }, () => {
185
- expect(consumer.position).to.be(3);
186
- consumer.start();
187
- });
188
- }
189
- if (document.id === 5) {
190
- done();
191
- }
192
- });
193
- storage.write({ type: 'Foobar', id: 1 });
194
- storage.write({ type: 'Foobar', id: 2 });
195
- storage.write({ type: 'Foobar', id: 3 });
196
- });
197
-
198
- it('will automatically start consuming when registering data listener', function(done){
199
- consumer = new Consumer(storage, 'foobar', 'consumer1');
200
- let expected = 0;
201
- storage.write({ type: 'Foobar', id: 1 });
202
- storage.write({ type: 'Foobar', id: 2 });
203
- storage.write({ type: 'Foobar', id: 3 }, () => {
204
- expect(consumer.position).to.be(0);
205
-
206
- consumer.on('data', document => {
207
- expect(document.id).to.be(++expected);
208
- if (document.id === 3) {
209
- done();
210
- }
211
- });
212
- });
213
- });
214
-
215
- it('can stop during catching up', function(done){
216
- consumer = new Consumer(storage, 'foobar', 'consumer1');
217
- storage.write({ type: 'Foobar', id: 1 });
218
- storage.write({ type: 'Foobar', id: 2 });
219
- storage.write({ type: 'Foobar', id: 3 }, () => {
220
- expect(consumer.position).to.be(0);
221
- consumer.start();
222
- consumer.stop();
223
-
224
- consumer.on('data', document => {
225
- expect(this).to.be(false);
226
- });
227
- setTimeout(done, 10);
228
- });
229
- });
230
-
231
- it('stops when push fails during catching up', function(done){
232
- consumer = new Consumer(storage, 'foobar', 'consumer1');
233
- const push = consumer.push.bind(consumer);
234
- consumer.push = (doc) => push(doc) && false;
235
- storage.write({ type: 'Foobar', id: 1 });
236
- storage.write({ type: 'Foobar', id: 2 });
237
- storage.write({ type: 'Foobar', id: 3 }, () => {
238
- expect(consumer.position).to.be(0);
239
-
240
- consumer.on('data', document => {
241
- expect(document.id).to.be(1);
242
- setTimeout(done, 10);
243
- });
244
- });
245
- });
246
-
247
- it('starting manually is no-op after registering data listener', function(done){
248
- consumer = new Consumer(storage, 'foobar', 'consumer1');
249
- let expected = 0;
250
- consumer.on('data', document => {
251
- expect(document.id).to.be(++expected);
252
- if (document.id === 3) {
253
- done();
254
- }
255
- });
256
- consumer.start();
257
- storage.write({ type: 'Foobar', id: 1 });
258
- storage.write({ type: 'Foobar', id: 2 });
259
- storage.write({ type: 'Foobar', id: 3 });
260
- });
261
-
262
- it('throws when calling setState outside of document handler', function() {
263
- consumer = new Consumer(storage, 'foobar', 'consumer-1');
264
- expect(() => consumer.setState({ foo: 'bar' })).to.throwError();
265
- });
266
-
267
- it('will persist multiple setState calls only once', function(done) {
268
- consumer = new Consumer(storage, 'foobar', 'consumer-1');
269
- consumer.on('data', () => {
270
- consumer.setState({ foo: 1 });
271
- consumer.setState({ foo: 1, bar: 2 });
272
- consumer.once('persisted', () => {
273
- expect(consumer.state.bar).to.be(2);
274
- done();
275
- });
276
- consumer.stop();
277
- });
278
-
279
- storage.write({ type: 'Foobar', id: 1 });
280
- });
281
-
282
- it('restores state after reopening', function(done) {
283
- const state = { foo: 0, bar: 'baz' };
284
- consumer = new Consumer(storage, 'foobar', 'consumer-1');
285
- consumer.on('data', (document) => {
286
- const newState = {...state, foo: state.foo + 1, lastId: document.id};
287
- consumer.setState(newState);
288
- consumer.once('persisted', () => {
289
- consumer = new Consumer(storage, 'foobar', 'consumer-1');
290
- expect(consumer.state.foo).to.be(1);
291
- done();
292
- });
293
- consumer.stop();
294
- });
295
-
296
- storage.write({ type: 'Foobar', id: 1 });
297
- });
298
-
299
- it('allows function argument in setState', function(done) {
300
- consumer = new Consumer(storage, 'foobar', 'consumer-1');
301
- consumer.on('data', (document) => {
302
- consumer.setState(state => ({...state, foo: (state.foo || 0) + 1, lastId: document.id}));
303
- consumer.once('persisted', () => {
304
- expect(consumer.state.foo).to.be(1);
305
- done();
306
- });
307
- });
308
-
309
- storage.write({ type: 'Foobar', id: 1 });
310
- });
311
-
312
- it('can be reset and reprocesses all events', function(done) {
313
- storage.write({ type: 'Foobar', id: 1 });
314
- storage.write({ type: 'Foobar', id: 2 });
315
- storage.write({ type: 'Foobar', id: 3 });
316
- consumer = new Consumer(storage, 'foobar', 'consumer-1');
317
- consumer.once('caught-up', () => {
318
- consumer.once('caught-up', () => {
319
- expect(consumer.position).to.be(3);
320
- done();
321
- });
322
- consumer.reset();
323
- expect(consumer.position).to.be(0);
324
- });
325
- consumer.start();
326
- });
327
-
328
- it('can be reset with new initialState and reprocesses all events', function(done) {
329
- storage.write({ type: 'Foobar', id: 1 });
330
- storage.write({ type: 'Foobar', id: 2 });
331
- storage.write({ type: 'Foobar', id: 3 });
332
- consumer = new Consumer(storage, 'foobar', 'consumer-1', { foo: 0 });
333
- consumer.once('caught-up', () => {
334
- consumer.once('caught-up', () => {
335
- expect(consumer.state.foo).to.be(4);
336
- done();
337
- });
338
- expect(consumer.state.foo).to.be(3);
339
- consumer.reset({ foo: 1 });
340
- });
341
- consumer.on('data', document => consumer.setState(state => ({ foo: state.foo + 1, lastId: document.id })));
342
- });
343
-
344
- it('can be reset with new starting point and reprocesses all events', function(done) {
345
- storage.write({ type: 'Foobar', id: 1 });
346
- storage.write({ type: 'Foobar', id: 2 });
347
- storage.write({ type: 'Foobar', id: 3 });
348
- consumer = new Consumer(storage, 'foobar', 'consumer-1');
349
- consumer.once('caught-up', () => {
350
- consumer.once('caught-up', () => {
351
- expect(consumer.position).to.be(3);
352
- done();
353
- });
354
- consumer.reset(2);
355
- expect(consumer.position).to.be(2);
356
- });
357
- consumer.start();
358
- });
359
-
360
- it('can be reset while running', function(done) {
361
- consumer = new Consumer(storage, 'foobar', 'consumer-1');
362
- consumer.once('caught-up', () => {
363
- storage.write({ type: 'Foobar', id: 1 });
364
- storage.write({ type: 'Foobar', id: 2 });
365
- storage.write({ type: 'Foobar', id: 3 });
366
- });
367
- consumer.once('data', () => {
368
- consumer.reset();
369
- expect(consumer.position).to.be(0);
370
- consumer.once('caught-up', () => {
371
- expect(consumer.position).to.be(3);
372
- done();
373
- });
374
- });
375
- });
376
-
377
- it('will not restart if stopped before reset', function(done) {
378
- storage.write({ type: 'Foobar', id: 1 });
379
- storage.write({ type: 'Foobar', id: 2 });
380
- storage.write({ type: 'Foobar', id: 3 });
381
- consumer = new Consumer(storage, 'foobar', 'consumer-1');
382
- consumer.once('caught-up', () => {
383
- consumer.stop();
384
- expect(consumer.isPaused()).to.be(true);
385
- consumer.reset();
386
- expect(consumer.isPaused()).to.be(true);
387
- done();
388
- });
389
- consumer.start();
390
- });
391
-
392
- it('persists state on every setState by default', function(done) {
393
- consumer = new Consumer(storage, 'foobar', 'consumer-1', { foo: 0 });
394
- let expected = 0;
395
- consumer.on('data', document => {
396
- consumer.setState(state => ({ foo: state.foo + 1, lastId: document.id }));
397
- });
398
- consumer.on('persisted', () => {
399
- expect(consumer.state.lastId).to.be(++expected);
400
- if (consumer.state.lastId === 3) {
401
- done();
402
- } else {
403
- storage.write({type: 'Foobar', id: consumer.state.lastId + 1});
404
- }
405
- });
406
- consumer.on('caught-up', () => {
407
- storage.write({ type: 'Foobar', id: 1 });
408
- });
409
- });
410
-
411
- it('allows to skip state persistence', function(done) {
412
- consumer = new Consumer(storage, 'foobar', 'consumer-1', { foo: 0 });
413
- consumer.on('data', document => {
414
- consumer.setState(state => ({ foo: state.foo + 1, lastId: document.id }), false);
415
- if (document.id === 3) {
416
- expect(consumer.state.foo).to.be(3);
417
- consumer.stop();
418
-
419
- setTimeout(() => {
420
- const consumer = new Consumer(storage, 'foobar', 'consumer-1', { foo: 0 });
421
- expect(consumer.state.foo).to.be(0);
422
- done();
423
- }, 1);
424
- }
425
- });
426
- consumer.on('caught-up', () => {
427
- consumer.on('persisted', () => { throw new Error('Invoked persistence!'); });
428
- storage.write({ type: 'Foobar', id: 1 });
429
- storage.write({ type: 'Foobar', id: 2 });
430
- storage.write({ type: 'Foobar', id: 3 });
431
- });
432
- });
433
-
434
- it('can build consistency guards (aggregates)', function(done) {
435
- const guard = new Consumer(storage, 'foobar', 'unique-bar-guard');
436
- guard.apply = function(event) {
437
- this.setState(state => ({ ...state, ...event }));
438
- };
439
- guard.handle = function(command) {
440
- if (this.state.foo === 'bar') {
441
- throw new Error('There was already a bar!');
442
- }
443
- return {type: 'Foobar', foo: command.foo};
444
- };
445
- guard.on('data', guard.apply);
446
-
447
- storage.write(guard.handle({ foo: 'bar' }));
448
-
449
- guard.on('persisted', () => {
450
- expect(() => storage.write(guard.handle({foo: 'bar'}))).to.throwError(/already a bar/);
451
- done();
452
- });
453
- });
454
-
455
- });