@villedemontreal/correlation-id
Version:
Express middleware to set a correlation in Express. The correlation id will be consistent across async calls within the handling of a request.
213 lines • 10.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const chai_1 = require("chai");
const events_1 = require("events");
const testingConfigurations_1 = require("../utils/testingConfigurations");
const correlationIdService_1 = require("./correlationIdService");
(0, testingConfigurations_1.setTestingConfigurations)();
const uuidMatcher = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
async function timeout(work, ms = 50) {
return new Promise((resolve) => setTimeout(() => {
work();
resolve();
}, ms));
}
describe('Correlation Id Service', () => {
describe('createNewId', () => {
it('should return UUID', () => {
const cid = correlationIdService_1.correlationIdService.createNewId();
chai_1.assert.match(cid, uuidMatcher);
});
});
describe('withId correlator', () => {
it('with sync function', () => {
// GIVEN
const expectedResult = '⭐';
// WHEN
const result = correlationIdService_1.correlationIdService.withId(() => {
const actual = correlationIdService_1.correlationIdService.getId();
chai_1.assert.match(actual, uuidMatcher, 'getId() should return a uuid');
return expectedResult;
});
// THEN
chai_1.assert.strictEqual(result, expectedResult);
});
it('with async function', async () => {
let done = false;
const promise = correlationIdService_1.correlationIdService.withId(async () => {
await timeout(() => {
const actual = correlationIdService_1.correlationIdService.getId();
chai_1.assert.match(actual, uuidMatcher, 'getId() should return a uuid');
done = true;
});
});
// "withId" doesn't care about a promise to be floating or not
chai_1.assert.isFalse(done);
await promise;
});
it('with supplied id', () => {
const testId = 'id-1';
correlationIdService_1.correlationIdService.withId(() => {
const actual = correlationIdService_1.correlationIdService.getId();
chai_1.assert.strictEqual(actual, testId, 'getId() should return supplied id');
}, testId);
});
it('with bound emitter', () => {
// GIVEN
const emitter = new events_1.EventEmitter();
let receivedValue = 0;
let receivedCid = '';
emitter.on('test', (value) => {
receivedValue = value;
receivedCid = correlationIdService_1.correlationIdService.getId();
});
// WHEN
let boundEmitter;
correlationIdService_1.correlationIdService.withId(() => {
boundEmitter = correlationIdService_1.correlationIdService.bind(emitter);
chai_1.assert.strictEqual(boundEmitter, emitter);
}, 'foo');
// THEN
boundEmitter.emit('test', 33);
chai_1.assert.equal(receivedValue, 33);
chai_1.assert.equal(receivedCid, 'foo');
});
it('with bound function', () => {
// GIVEN
const func = (msg) => msg + correlationIdService_1.correlationIdService.getId();
// WHEN
let boundFunc;
correlationIdService_1.correlationIdService.withId(() => {
boundFunc = correlationIdService_1.correlationIdService.bind(func);
}, 'foo');
// THEN
const result = boundFunc('Bar-');
chai_1.assert.equal(result, 'Bar-foo');
});
it('with bound method', () => {
// GIVEN
const instance = {
title: 'Hello-',
say(msg) {
return this.title + msg + correlationIdService_1.correlationIdService.getId();
},
};
// WHEN
correlationIdService_1.correlationIdService.withId(() => {
instance.say = correlationIdService_1.correlationIdService.bind(instance.say);
}, 'foo');
// THEN
const result = instance.say('Bar-');
chai_1.assert.equal(result, 'Hello-Bar-foo');
});
it('with resolved promise', async () => {
let done = false;
const promise = correlationIdService_1.correlationIdService.withId(() => Promise.resolve(correlationIdService_1.correlationIdService.getId()).then((id) => {
chai_1.assert.match(id, uuidMatcher, 'Promise should resolve correlation id');
done = true;
}));
// "withId" doesn't care about a promise to be floating or not
chai_1.assert.isFalse(done);
await promise;
});
it('with nested functions', () => {
correlationIdService_1.correlationIdService.withId(() => {
const cid1 = correlationIdService_1.correlationIdService.getId();
chai_1.assert.match(cid1, uuidMatcher, 'correlationIdService.getId() should return a UUID');
correlationIdService_1.correlationIdService.withId(() => {
const cid2 = correlationIdService_1.correlationIdService.getId();
chai_1.assert.notEqual(cid2, cid1, 'correlationIdService.getId() should return a different id for every scope');
chai_1.assert.match(cid2, uuidMatcher, 'correlationIdService.getId() should return a UUID');
});
const cid3 = correlationIdService_1.correlationIdService.getId();
chai_1.assert.strictEqual(cid3, cid1, 'correlationIdService.getId() should return the same id for the same scope');
chai_1.assert.match(cid3, uuidMatcher, 'correlationIdService.getId() should return a UUID');
});
});
it('with async function', async function () {
const duration = 25;
setSlowThreshold(this, duration);
// GIVEN
const expectedResult = '⭐';
// WHEN
const result = await correlationIdService_1.correlationIdService.withId(async () => {
chai_1.assert.equal(correlationIdService_1.correlationIdService.getId(), 'foo');
await timeout(() => {
chai_1.assert.equal(correlationIdService_1.correlationIdService.getId(), 'foo');
}, duration);
chai_1.assert.equal(correlationIdService_1.correlationIdService.getId(), 'foo');
return expectedResult;
}, 'foo');
// THEN
chai_1.assert.strictEqual(result, expectedResult);
});
});
describe('withIdAsync correlator', () => {
it('with async function', async function () {
const duration = 25;
setSlowThreshold(this, duration);
// GIVEN
const expectedResult = '⭐';
// WHEN
const result = await correlationIdService_1.correlationIdService.withIdAsync(async () => {
chai_1.assert.equal(correlationIdService_1.correlationIdService.getId(), 'foo');
await timeout(() => {
chai_1.assert.equal(correlationIdService_1.correlationIdService.getId(), 'foo');
}, duration);
chai_1.assert.equal(correlationIdService_1.correlationIdService.getId(), 'foo');
return expectedResult;
}, 'foo');
// THEN
chai_1.assert.strictEqual(result, expectedResult);
});
it('with error in callback', async () => {
try {
await correlationIdService_1.correlationIdService.withIdAsync(async () => {
chai_1.assert.equal(correlationIdService_1.correlationIdService.getId(), 'foo');
throw new Error('some error...');
}, 'foo');
chai_1.assert.fail('expected error');
}
catch (err) {
chai_1.assert.equal(err.message, 'some error...');
}
});
it('with error after await', async function () {
const duration = 25;
setSlowThreshold(this, duration);
try {
await correlationIdService_1.correlationIdService.withIdAsync(async () => {
chai_1.assert.equal(correlationIdService_1.correlationIdService.getId(), 'foo');
await timeout(() => { }, duration);
throw new Error('some error...');
}, 'foo');
chai_1.assert.fail('expected error');
}
catch (err) {
chai_1.assert.equal(err.message, 'some error...');
}
});
it('with nested async functions', async function () {
const duration = 25;
setSlowThreshold(this, 2 * duration);
await correlationIdService_1.correlationIdService.withIdAsync(async () => {
chai_1.assert.equal(correlationIdService_1.correlationIdService.getId(), 'foo');
await timeout(async () => {
await correlationIdService_1.correlationIdService.withIdAsync(async () => {
await timeout(() => {
chai_1.assert.equal(correlationIdService_1.correlationIdService.getId(), 'bar');
}, duration);
}, 'bar');
}, duration);
chai_1.assert.equal(correlationIdService_1.correlationIdService.getId(), 'foo');
}, 'foo');
});
});
function setSlowThreshold(context, expectedTestDuration) {
// Cf. https://mochajs.org/#test-duration
// 10: budgeted test case own processing time
// ×2: for the estimation to sit around "slow/2" in Mocha scale (and no warning shows up)
context.slow((expectedTestDuration + 10) * 2);
}
});
//# sourceMappingURL=correlationIdService.test.js.map