@villedemontreal/correlation-id 5.3.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.
- package/LICENSE +21 -0
- package/README.md +119 -0
- package/dist/src/config/configs.d.ts +16 -0
- package/dist/src/config/configs.js +26 -0
- package/dist/src/config/configs.js.map +1 -0
- package/dist/src/config/constants.d.ts +27 -0
- package/dist/src/config/constants.js +27 -0
- package/dist/src/config/constants.js.map +1 -0
- package/dist/src/config/init.d.ts +15 -0
- package/dist/src/config/init.js +34 -0
- package/dist/src/config/init.js.map +1 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +25 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/middleware/correlationIdMiddleware.d.ts +8 -0
- package/dist/src/middleware/correlationIdMiddleware.js +43 -0
- package/dist/src/middleware/correlationIdMiddleware.js.map +1 -0
- package/dist/src/middleware/correlationIdMiddleware.test.d.ts +1 -0
- package/dist/src/middleware/correlationIdMiddleware.test.js +306 -0
- package/dist/src/middleware/correlationIdMiddleware.test.js.map +1 -0
- package/dist/src/services/correlationIdService.d.ts +68 -0
- package/dist/src/services/correlationIdService.js +166 -0
- package/dist/src/services/correlationIdService.js.map +1 -0
- package/dist/src/services/correlationIdService.test.d.ts +1 -0
- package/dist/src/services/correlationIdService.test.js +215 -0
- package/dist/src/services/correlationIdService.test.js.map +1 -0
- package/dist/src/utils/logger.d.ts +11 -0
- package/dist/src/utils/logger.js +54 -0
- package/dist/src/utils/logger.js.map +1 -0
- package/dist/src/utils/testingConfigurations.d.ts +9 -0
- package/dist/src/utils/testingConfigurations.js +18 -0
- package/dist/src/utils/testingConfigurations.js.map +1 -0
- package/package.json +62 -0
- package/src/config/configs.ts +26 -0
- package/src/config/constants.ts +40 -0
- package/src/config/init.ts +33 -0
- package/src/index.ts +9 -0
- package/src/middleware/correlationIdMiddleware.test.ts +335 -0
- package/src/middleware/correlationIdMiddleware.ts +45 -0
- package/src/services/correlationIdService.test.ts +255 -0
- package/src/services/correlationIdService.ts +255 -0
- package/src/utils/logger.ts +53 -0
- package/src/utils/testingConfigurations.ts +14 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import { assert } from 'chai';
|
|
2
|
+
import * as express from 'express';
|
|
3
|
+
import httpHeaderFieldsTyped from 'http-header-fields-typed';
|
|
4
|
+
import * as request from 'supertest';
|
|
5
|
+
import { correlationIdService } from '../services/correlationIdService';
|
|
6
|
+
import { setTestingConfigurations } from '../utils/testingConfigurations';
|
|
7
|
+
import { createCorrelationIdMiddleware } from './correlationIdMiddleware';
|
|
8
|
+
|
|
9
|
+
function delay(millis: number): Promise<void> {
|
|
10
|
+
return new Promise<void>(resolve =>
|
|
11
|
+
setTimeout(() => {
|
|
12
|
+
resolve();
|
|
13
|
+
}, millis)
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// ==========================================
|
|
18
|
+
// Set Testing configurations
|
|
19
|
+
// ==========================================
|
|
20
|
+
setTestingConfigurations();
|
|
21
|
+
|
|
22
|
+
const uuidMatcher: RegExp = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
23
|
+
|
|
24
|
+
// ==========================================
|
|
25
|
+
// Correlation ID service
|
|
26
|
+
// ==========================================
|
|
27
|
+
// tslint:disable-next-line: max-func-body-length
|
|
28
|
+
describe('Correlation ID Middleware', () => {
|
|
29
|
+
it('should generate correlation id if it doesnt exists', async () => {
|
|
30
|
+
const app: express.Application = express();
|
|
31
|
+
app.use(createCorrelationIdMiddleware());
|
|
32
|
+
app.get('/', (req, res) => {
|
|
33
|
+
const actual = correlationIdService.getId();
|
|
34
|
+
assert.match(actual, uuidMatcher);
|
|
35
|
+
res.end();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
await request(app)
|
|
39
|
+
.get('/')
|
|
40
|
+
.send();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should get correlation id from incoming request', async () => {
|
|
44
|
+
const testId: string = 'correlation-id-123';
|
|
45
|
+
|
|
46
|
+
const app: express.Application = express();
|
|
47
|
+
app.use(createCorrelationIdMiddleware());
|
|
48
|
+
app.get('/', (req, res) => {
|
|
49
|
+
const actual = correlationIdService.getId();
|
|
50
|
+
assert.strictEqual(actual, testId, 'getId() should return id from x-correlation-id header of inbound request');
|
|
51
|
+
res.end();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
await request(app)
|
|
55
|
+
.get('/')
|
|
56
|
+
.set(httpHeaderFieldsTyped.X_CORRELATION_ID, testId)
|
|
57
|
+
.send();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should maintain correlation id with async callbacks', async () => {
|
|
61
|
+
const testId: string = 'correlation-id-123';
|
|
62
|
+
|
|
63
|
+
let actual = '';
|
|
64
|
+
let actual2 = '';
|
|
65
|
+
const app: express.Application = express();
|
|
66
|
+
app.use(createCorrelationIdMiddleware());
|
|
67
|
+
app.get('/', async (req, res, next) => {
|
|
68
|
+
actual = correlationIdService.getId();
|
|
69
|
+
setTimeout(() => {
|
|
70
|
+
actual2 = correlationIdService.getId();
|
|
71
|
+
res.end();
|
|
72
|
+
}, 250);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
assert.isUndefined(correlationIdService.getId());
|
|
76
|
+
await request(app)
|
|
77
|
+
.get('/')
|
|
78
|
+
.set(httpHeaderFieldsTyped.X_CORRELATION_ID, testId)
|
|
79
|
+
.send();
|
|
80
|
+
|
|
81
|
+
assert.isUndefined(correlationIdService.getId());
|
|
82
|
+
assert.strictEqual(actual, testId, 'getId() should return id from x-correlation-id header of inbound request');
|
|
83
|
+
assert.strictEqual(actual2, testId, 'getId() should return id from x-correlation-id header of inbound request');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should maintain correlation id with async/await operations', async () => {
|
|
87
|
+
const testId: string = 'correlation-id-123';
|
|
88
|
+
|
|
89
|
+
let actual = '';
|
|
90
|
+
let actual2 = '';
|
|
91
|
+
const app: express.Application = express();
|
|
92
|
+
app.use(createCorrelationIdMiddleware());
|
|
93
|
+
app.get('/', async (req, res, next) => {
|
|
94
|
+
try {
|
|
95
|
+
actual = correlationIdService.getId();
|
|
96
|
+
await delay(250);
|
|
97
|
+
actual2 = correlationIdService.getId();
|
|
98
|
+
} catch (e) {
|
|
99
|
+
next(e);
|
|
100
|
+
} finally {
|
|
101
|
+
res.end();
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
assert.isUndefined(correlationIdService.getId());
|
|
106
|
+
await request(app)
|
|
107
|
+
.get('/')
|
|
108
|
+
.set(httpHeaderFieldsTyped.X_CORRELATION_ID, testId)
|
|
109
|
+
.send();
|
|
110
|
+
|
|
111
|
+
assert.isUndefined(correlationIdService.getId());
|
|
112
|
+
assert.strictEqual(actual, testId, 'getId() should return id from x-correlation-id header of inbound request');
|
|
113
|
+
assert.strictEqual(actual2, testId, 'getId() should return id from x-correlation-id header of inbound request');
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should keep correlation ids in nested requests', async () => {
|
|
117
|
+
const testId: string = 'correlation-id-123';
|
|
118
|
+
const testId2: string = 'correlation-id-456';
|
|
119
|
+
|
|
120
|
+
let actual = '';
|
|
121
|
+
let actual2 = '';
|
|
122
|
+
let actual3 = '';
|
|
123
|
+
let actual4 = '';
|
|
124
|
+
let actual5 = '';
|
|
125
|
+
const app: express.Application = express();
|
|
126
|
+
app.use(createCorrelationIdMiddleware());
|
|
127
|
+
app.get('/', async (req, res, next) => {
|
|
128
|
+
try {
|
|
129
|
+
actual = correlationIdService.getId();
|
|
130
|
+
await delay(250);
|
|
131
|
+
actual2 = correlationIdService.getId();
|
|
132
|
+
await request(app)
|
|
133
|
+
.get('/foo')
|
|
134
|
+
.set(httpHeaderFieldsTyped.X_CORRELATION_ID, testId2)
|
|
135
|
+
.send();
|
|
136
|
+
actual3 = correlationIdService.getId();
|
|
137
|
+
} catch (e) {
|
|
138
|
+
next(e);
|
|
139
|
+
} finally {
|
|
140
|
+
res.end();
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
app.get('/foo', async (req, res, next) => {
|
|
144
|
+
try {
|
|
145
|
+
actual4 = correlationIdService.getId();
|
|
146
|
+
await delay(250);
|
|
147
|
+
actual5 = correlationIdService.getId();
|
|
148
|
+
} catch (e) {
|
|
149
|
+
next(e);
|
|
150
|
+
} finally {
|
|
151
|
+
res.end();
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
assert.isUndefined(correlationIdService.getId());
|
|
156
|
+
await request(app)
|
|
157
|
+
.get('/')
|
|
158
|
+
.set(httpHeaderFieldsTyped.X_CORRELATION_ID, testId)
|
|
159
|
+
.send();
|
|
160
|
+
|
|
161
|
+
assert.isUndefined(correlationIdService.getId());
|
|
162
|
+
assert.strictEqual(actual, testId, 'getId() should return id from x-correlation-id header of inbound request');
|
|
163
|
+
assert.strictEqual(actual2, testId, 'getId() should return id from x-correlation-id header of inbound request');
|
|
164
|
+
assert.strictEqual(actual3, testId, 'getId() should return id from x-correlation-id header of inbound request');
|
|
165
|
+
assert.strictEqual(actual4, testId2, 'getId() should return id from x-correlation-id header of inbound request');
|
|
166
|
+
assert.strictEqual(actual5, testId2, 'getId() should return id from x-correlation-id header of inbound request');
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// tslint:disable: no-console
|
|
170
|
+
it('should keep correlation ids separated in parallel requests', async function() {
|
|
171
|
+
this.timeout(5000);
|
|
172
|
+
const testId: string = 'correlation-id-123';
|
|
173
|
+
const testId2: string = 'correlation-id-456';
|
|
174
|
+
|
|
175
|
+
let actual = '';
|
|
176
|
+
let actual2 = '';
|
|
177
|
+
let actual4 = '';
|
|
178
|
+
let actual5 = '';
|
|
179
|
+
let unlock: any;
|
|
180
|
+
const lock = new Promise(async (resolve, reject) => {
|
|
181
|
+
unlock = resolve;
|
|
182
|
+
});
|
|
183
|
+
const app: express.Application = express();
|
|
184
|
+
app.use(createCorrelationIdMiddleware());
|
|
185
|
+
app.get('/', async (req, res, next) => {
|
|
186
|
+
try {
|
|
187
|
+
actual = correlationIdService.getId();
|
|
188
|
+
console.log('start of req1', actual);
|
|
189
|
+
await lock;
|
|
190
|
+
actual2 = correlationIdService.getId();
|
|
191
|
+
console.log('end of req1', actual2);
|
|
192
|
+
} catch (e) {
|
|
193
|
+
next(e);
|
|
194
|
+
} finally {
|
|
195
|
+
res.end();
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
app.get('/foo', async (req, res, next) => {
|
|
199
|
+
try {
|
|
200
|
+
actual4 = correlationIdService.getId();
|
|
201
|
+
console.log('start of req2', actual4);
|
|
202
|
+
unlock();
|
|
203
|
+
await this.timeout(200);
|
|
204
|
+
actual5 = correlationIdService.getId();
|
|
205
|
+
console.log('end of req2', actual5);
|
|
206
|
+
} catch (e) {
|
|
207
|
+
next(e);
|
|
208
|
+
} finally {
|
|
209
|
+
res.end();
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
console.log('send req1');
|
|
214
|
+
assert.isUndefined(correlationIdService.getId());
|
|
215
|
+
const req1 = request(app)
|
|
216
|
+
.get('/')
|
|
217
|
+
.set(httpHeaderFieldsTyped.X_CORRELATION_ID, testId)
|
|
218
|
+
.send();
|
|
219
|
+
console.log('send req2');
|
|
220
|
+
assert.isUndefined(correlationIdService.getId());
|
|
221
|
+
const req2 = request(app)
|
|
222
|
+
.get('/foo')
|
|
223
|
+
.set(httpHeaderFieldsTyped.X_CORRELATION_ID, testId2)
|
|
224
|
+
.send();
|
|
225
|
+
await Promise.all([req1, req2]);
|
|
226
|
+
assert.isUndefined(correlationIdService.getId());
|
|
227
|
+
assert.strictEqual(actual, testId, 'getId() should return id from x-correlation-id header of inbound request');
|
|
228
|
+
assert.strictEqual(actual2, testId, 'getId() should return id from x-correlation-id header of inbound request');
|
|
229
|
+
assert.strictEqual(actual4, testId2, 'getId() should return id from x-correlation-id header of inbound request');
|
|
230
|
+
assert.strictEqual(actual5, testId2, 'getId() should return id from x-correlation-id header of inbound request');
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('should work with operations causing errors', async () => {
|
|
234
|
+
const testId: string = 'correlation-id-123';
|
|
235
|
+
|
|
236
|
+
let actual = '';
|
|
237
|
+
const app: express.Application = express();
|
|
238
|
+
app.use(createCorrelationIdMiddleware());
|
|
239
|
+
app.get('/', (req, res, next) => {
|
|
240
|
+
actual = correlationIdService.getId();
|
|
241
|
+
throw new Error('some error');
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
assert.isUndefined(correlationIdService.getId());
|
|
245
|
+
const result = await request(app)
|
|
246
|
+
.get('/')
|
|
247
|
+
.set(httpHeaderFieldsTyped.X_CORRELATION_ID, testId)
|
|
248
|
+
.send();
|
|
249
|
+
assert.strictEqual(result.status, 500);
|
|
250
|
+
assert.isUndefined(correlationIdService.getId());
|
|
251
|
+
assert.strictEqual(actual, testId, 'getId() should return id from x-correlation-id header of inbound request');
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('a filter can be specified', async () => {
|
|
255
|
+
const testId: string = 'correlation-id-123';
|
|
256
|
+
|
|
257
|
+
const filter = (req: express.Request): boolean => {
|
|
258
|
+
if (req.path.startsWith('/ok/')) {
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
return false;
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
const app: express.Application = express();
|
|
265
|
+
app.use(createCorrelationIdMiddleware(filter));
|
|
266
|
+
|
|
267
|
+
app.get('/ok/1', (req, res) => {
|
|
268
|
+
const actual = correlationIdService.getId();
|
|
269
|
+
assert.strictEqual(actual, testId, 'getId() should return id from x-correlation-id header of inbound request');
|
|
270
|
+
res.end();
|
|
271
|
+
});
|
|
272
|
+
app.get('/ok/2', (req, res) => {
|
|
273
|
+
const actual = correlationIdService.getId();
|
|
274
|
+
assert.strictEqual(actual, testId, 'getId() should return id from x-correlation-id header of inbound request');
|
|
275
|
+
res.end();
|
|
276
|
+
});
|
|
277
|
+
app.get('/notok/1', (req, res) => {
|
|
278
|
+
const actual = correlationIdService.getId();
|
|
279
|
+
assert.isUndefined(actual);
|
|
280
|
+
res.end();
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
await request(app)
|
|
284
|
+
.get('/ok/1')
|
|
285
|
+
.set(httpHeaderFieldsTyped.X_CORRELATION_ID, testId)
|
|
286
|
+
.send();
|
|
287
|
+
|
|
288
|
+
await request(app)
|
|
289
|
+
.get('/ok/2')
|
|
290
|
+
.set(httpHeaderFieldsTyped.X_CORRELATION_ID, testId)
|
|
291
|
+
.send();
|
|
292
|
+
|
|
293
|
+
await request(app)
|
|
294
|
+
.get('/notok/1')
|
|
295
|
+
.set(httpHeaderFieldsTyped.X_CORRELATION_ID, testId)
|
|
296
|
+
.send();
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it('getCidInfo() cid received', async () => {
|
|
300
|
+
const testId: string = 'correlation-id-123';
|
|
301
|
+
|
|
302
|
+
const app: express.Application = express();
|
|
303
|
+
app.use(createCorrelationIdMiddleware());
|
|
304
|
+
app.get('/', (req, res) => {
|
|
305
|
+
const info = correlationIdService.getCidInfo(req);
|
|
306
|
+
assert.strictEqual(info.current, testId);
|
|
307
|
+
assert.strictEqual(info.receivedInRequest, testId);
|
|
308
|
+
assert.isUndefined(info.generated);
|
|
309
|
+
|
|
310
|
+
res.end();
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
await request(app)
|
|
314
|
+
.get('/')
|
|
315
|
+
.set(httpHeaderFieldsTyped.X_CORRELATION_ID, testId)
|
|
316
|
+
.send();
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
it('getCidInfo() cid generated', async () => {
|
|
320
|
+
const app: express.Application = express();
|
|
321
|
+
app.use(createCorrelationIdMiddleware());
|
|
322
|
+
app.get('/', (req, res) => {
|
|
323
|
+
const info = correlationIdService.getCidInfo(req);
|
|
324
|
+
assert.match(info.current, uuidMatcher);
|
|
325
|
+
assert.strictEqual(info.current, info.generated);
|
|
326
|
+
assert.isUndefined(info.receivedInRequest);
|
|
327
|
+
|
|
328
|
+
res.end();
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
await request(app)
|
|
332
|
+
.get('/')
|
|
333
|
+
.send();
|
|
334
|
+
});
|
|
335
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as express from 'express';
|
|
2
|
+
import httpHeaderFieldsTyped from 'http-header-fields-typed';
|
|
3
|
+
import { constants } from '../config/constants';
|
|
4
|
+
import { correlationIdService } from '../services/correlationIdService';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Correlation ID Middleware
|
|
8
|
+
*
|
|
9
|
+
* @param filter a filter which is going to be called with the request to see if a
|
|
10
|
+
* colleration id scope must be managed or not.
|
|
11
|
+
*/
|
|
12
|
+
export let createCorrelationIdMiddleware = (
|
|
13
|
+
filter?: (req: express.Request) => boolean
|
|
14
|
+
): ((req: express.Request, res: express.Response, next: express.NextFunction) => Promise<void>) => {
|
|
15
|
+
const correlationIdMiddleware = (
|
|
16
|
+
req: express.Request,
|
|
17
|
+
res: express.Response,
|
|
18
|
+
next: express.NextFunction
|
|
19
|
+
): Promise<void> => {
|
|
20
|
+
if (filter && !filter(req)) {
|
|
21
|
+
next();
|
|
22
|
+
} else {
|
|
23
|
+
// ==========================================
|
|
24
|
+
// If a Correlation ID (cid) exists in the request
|
|
25
|
+
// it will be used. Otherwise, a new one is created.
|
|
26
|
+
//
|
|
27
|
+
// We add the cid to the response!
|
|
28
|
+
// ==========================================
|
|
29
|
+
let correlationId = req.get(httpHeaderFieldsTyped.X_CORRELATION_ID);
|
|
30
|
+
if (!correlationId) {
|
|
31
|
+
correlationId = correlationIdService.createNewId();
|
|
32
|
+
req[constants.requestExtraVariables.cidNew] = correlationId;
|
|
33
|
+
} else {
|
|
34
|
+
req[constants.requestExtraVariables.cidReceivedInRequest] = correlationId;
|
|
35
|
+
}
|
|
36
|
+
if (!res.headersSent) {
|
|
37
|
+
res.set(httpHeaderFieldsTyped.X_CORRELATION_ID, correlationId);
|
|
38
|
+
}
|
|
39
|
+
correlationIdService.withId(next, correlationId);
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return correlationIdMiddleware;
|
|
45
|
+
};
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
// tslint:disable max-func-body-length
|
|
2
|
+
|
|
3
|
+
import { assert } from 'chai';
|
|
4
|
+
import { EventEmitter } from 'events';
|
|
5
|
+
import { setTestingConfigurations } from '../utils/testingConfigurations';
|
|
6
|
+
import { correlationIdService } from './correlationIdService';
|
|
7
|
+
|
|
8
|
+
setTestingConfigurations();
|
|
9
|
+
|
|
10
|
+
const uuidMatcher: RegExp = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
11
|
+
|
|
12
|
+
async function timeout(work: (params?: any) => any, ms: number = 50) {
|
|
13
|
+
return new Promise<void>(resolve =>
|
|
14
|
+
setTimeout(() => {
|
|
15
|
+
work();
|
|
16
|
+
resolve();
|
|
17
|
+
}, ms)
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe('Correlation Id Service', () => {
|
|
22
|
+
describe('createNewId', () => {
|
|
23
|
+
it('should return UUID', () => {
|
|
24
|
+
const cid = correlationIdService.createNewId();
|
|
25
|
+
assert.match(cid, uuidMatcher);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe('withId correlator', () => {
|
|
30
|
+
it('with sync function', () => {
|
|
31
|
+
// GIVEN
|
|
32
|
+
const expectedResult: string = '⭐';
|
|
33
|
+
|
|
34
|
+
// WHEN
|
|
35
|
+
const result = correlationIdService.withId(() => {
|
|
36
|
+
const actual = correlationIdService.getId();
|
|
37
|
+
assert.match(actual, uuidMatcher, 'getId() should return a uuid');
|
|
38
|
+
return expectedResult;
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// THEN
|
|
42
|
+
assert.strictEqual(result, expectedResult);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('with async function', async () => {
|
|
46
|
+
let done: boolean = false;
|
|
47
|
+
|
|
48
|
+
const promise = correlationIdService.withId(async () => {
|
|
49
|
+
await timeout(() => {
|
|
50
|
+
const actual = correlationIdService.getId();
|
|
51
|
+
assert.match(actual, uuidMatcher, 'getId() should return a uuid');
|
|
52
|
+
done = true;
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// "withId" doesn't care about a promise to be floating or not
|
|
57
|
+
assert.isFalse(done);
|
|
58
|
+
await promise;
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('with supplied id', () => {
|
|
62
|
+
const testId = 'id-1';
|
|
63
|
+
correlationIdService.withId(() => {
|
|
64
|
+
const actual = correlationIdService.getId();
|
|
65
|
+
assert.strictEqual(actual, testId, 'getId() should return supplied id');
|
|
66
|
+
}, testId);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('with bound emitter', () => {
|
|
70
|
+
// GIVEN
|
|
71
|
+
const emitter = new EventEmitter();
|
|
72
|
+
let receivedValue = 0;
|
|
73
|
+
let receivedCid = '';
|
|
74
|
+
emitter.on('test', value => {
|
|
75
|
+
receivedValue = value;
|
|
76
|
+
receivedCid = correlationIdService.getId();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// WHEN
|
|
80
|
+
let boundEmitter: EventEmitter;
|
|
81
|
+
correlationIdService.withId(() => {
|
|
82
|
+
boundEmitter = correlationIdService.bind(emitter);
|
|
83
|
+
assert.strictEqual(boundEmitter, emitter);
|
|
84
|
+
}, 'foo');
|
|
85
|
+
|
|
86
|
+
// THEN
|
|
87
|
+
boundEmitter.emit('test', 33);
|
|
88
|
+
assert.equal(receivedValue, 33);
|
|
89
|
+
assert.equal(receivedCid, 'foo');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('with bound function', () => {
|
|
93
|
+
// GIVEN
|
|
94
|
+
const func = (msg: string) => msg + correlationIdService.getId();
|
|
95
|
+
|
|
96
|
+
// WHEN
|
|
97
|
+
let boundFunc: (msg: string) => string;
|
|
98
|
+
correlationIdService.withId(() => {
|
|
99
|
+
boundFunc = correlationIdService.bind(func);
|
|
100
|
+
}, 'foo');
|
|
101
|
+
|
|
102
|
+
// THEN
|
|
103
|
+
const result = boundFunc('Bar-');
|
|
104
|
+
assert.equal(result, 'Bar-foo');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('with bound method', () => {
|
|
108
|
+
// GIVEN
|
|
109
|
+
const instance = {
|
|
110
|
+
title: 'Hello-',
|
|
111
|
+
say(msg: string): string {
|
|
112
|
+
return this.title + msg + correlationIdService.getId();
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// WHEN
|
|
117
|
+
correlationIdService.withId(() => {
|
|
118
|
+
instance.say = correlationIdService.bind(instance.say);
|
|
119
|
+
}, 'foo');
|
|
120
|
+
|
|
121
|
+
// THEN
|
|
122
|
+
const result = instance.say('Bar-');
|
|
123
|
+
assert.equal(result, 'Hello-Bar-foo');
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('with resolved promise', async () => {
|
|
127
|
+
let done: boolean = false;
|
|
128
|
+
|
|
129
|
+
const promise = correlationIdService.withId(() =>
|
|
130
|
+
Promise.resolve(correlationIdService.getId()).then(id => {
|
|
131
|
+
assert.match(id, uuidMatcher, 'Promise should resolve correlation id');
|
|
132
|
+
done = true;
|
|
133
|
+
})
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
// "withId" doesn't care about a promise to be floating or not
|
|
137
|
+
assert.isFalse(done);
|
|
138
|
+
await promise;
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('with nested functions', () => {
|
|
142
|
+
correlationIdService.withId(() => {
|
|
143
|
+
const cid1 = correlationIdService.getId();
|
|
144
|
+
assert.match(cid1, uuidMatcher, 'correlationIdService.getId() should return a UUID');
|
|
145
|
+
|
|
146
|
+
correlationIdService.withId(() => {
|
|
147
|
+
const cid2 = correlationIdService.getId();
|
|
148
|
+
assert.notEqual(cid2, cid1, 'correlationIdService.getId() should return a different id for every scope');
|
|
149
|
+
assert.match(cid2, uuidMatcher, 'correlationIdService.getId() should return a UUID');
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
const cid3 = correlationIdService.getId();
|
|
153
|
+
assert.strictEqual(cid3, cid1, 'correlationIdService.getId() should return the same id for the same scope');
|
|
154
|
+
assert.match(cid3, uuidMatcher, 'correlationIdService.getId() should return a UUID');
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('with async function', async function() {
|
|
159
|
+
const duration = 25;
|
|
160
|
+
setSlowThreshold(this, duration);
|
|
161
|
+
|
|
162
|
+
// GIVEN
|
|
163
|
+
const expectedResult: string = '⭐';
|
|
164
|
+
|
|
165
|
+
// WHEN
|
|
166
|
+
const result = await correlationIdService.withId(async () => {
|
|
167
|
+
assert.equal(correlationIdService.getId(), 'foo');
|
|
168
|
+
await timeout(() => {
|
|
169
|
+
assert.equal(correlationIdService.getId(), 'foo');
|
|
170
|
+
}, duration);
|
|
171
|
+
assert.equal(correlationIdService.getId(), 'foo');
|
|
172
|
+
return expectedResult;
|
|
173
|
+
}, 'foo');
|
|
174
|
+
|
|
175
|
+
// THEN
|
|
176
|
+
assert.strictEqual(result, expectedResult);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
describe('withIdAsync correlator', () => {
|
|
181
|
+
it('with async function', async function() {
|
|
182
|
+
const duration = 25;
|
|
183
|
+
setSlowThreshold(this, duration);
|
|
184
|
+
|
|
185
|
+
// GIVEN
|
|
186
|
+
const expectedResult: string = '⭐';
|
|
187
|
+
|
|
188
|
+
// WHEN
|
|
189
|
+
const result = await correlationIdService.withIdAsync(async () => {
|
|
190
|
+
assert.equal(correlationIdService.getId(), 'foo');
|
|
191
|
+
await timeout(() => {
|
|
192
|
+
assert.equal(correlationIdService.getId(), 'foo');
|
|
193
|
+
}, duration);
|
|
194
|
+
assert.equal(correlationIdService.getId(), 'foo');
|
|
195
|
+
return expectedResult;
|
|
196
|
+
}, 'foo');
|
|
197
|
+
|
|
198
|
+
// THEN
|
|
199
|
+
assert.strictEqual(result, expectedResult);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('with error in callback', async () => {
|
|
203
|
+
try {
|
|
204
|
+
await correlationIdService.withIdAsync(async () => {
|
|
205
|
+
assert.equal(correlationIdService.getId(), 'foo');
|
|
206
|
+
throw new Error('some error...');
|
|
207
|
+
}, 'foo');
|
|
208
|
+
assert.fail('expected error');
|
|
209
|
+
} catch (err) {
|
|
210
|
+
assert.equal(err.message, 'some error...');
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('with error after await', async function() {
|
|
215
|
+
const duration = 25;
|
|
216
|
+
setSlowThreshold(this, duration);
|
|
217
|
+
|
|
218
|
+
try {
|
|
219
|
+
await correlationIdService.withIdAsync(async () => {
|
|
220
|
+
assert.equal(correlationIdService.getId(), 'foo');
|
|
221
|
+
// tslint:disable-next-line: no-empty
|
|
222
|
+
await timeout(() => {}, duration);
|
|
223
|
+
throw new Error('some error...');
|
|
224
|
+
}, 'foo');
|
|
225
|
+
assert.fail('expected error');
|
|
226
|
+
} catch (err) {
|
|
227
|
+
assert.equal(err.message, 'some error...');
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('with nested async functions', async function() {
|
|
232
|
+
const duration = 25;
|
|
233
|
+
setSlowThreshold(this, 2 * duration);
|
|
234
|
+
|
|
235
|
+
await correlationIdService.withIdAsync(async () => {
|
|
236
|
+
assert.equal(correlationIdService.getId(), 'foo');
|
|
237
|
+
await timeout(async () => {
|
|
238
|
+
await correlationIdService.withIdAsync(async () => {
|
|
239
|
+
await timeout(() => {
|
|
240
|
+
assert.equal(correlationIdService.getId(), 'bar');
|
|
241
|
+
}, duration);
|
|
242
|
+
}, 'bar');
|
|
243
|
+
}, duration);
|
|
244
|
+
assert.equal(correlationIdService.getId(), 'foo');
|
|
245
|
+
}, 'foo');
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
function setSlowThreshold(context: Mocha.Context, expectedTestDuration: number) {
|
|
250
|
+
// Cf. https://mochajs.org/#test-duration
|
|
251
|
+
// 10: budgeted test case own processing time
|
|
252
|
+
// ×2: for the estimation to sit around "slow/2" in Mocha scale (and no warning shows up)
|
|
253
|
+
context.slow((expectedTestDuration + 10) * 2);
|
|
254
|
+
}
|
|
255
|
+
});
|