UNPKG

async-local-storage

Version:

Get the value like thread-local storage in threaded programming

372 lines (343 loc) 9.31 kB
const path = require('path'); const fs = require('fs'); const util = require('util'); const crypto = require('crypto'); const dns = require('dns'); const http = require('http'); const request = require('supertest'); const als = require('./als'); const {server, redisClient} = require('./support/server'); const topList = []; const delay = ms => new Promise(resolve => setTimeout(resolve, ms)); const randomBytes = () => crypto.randomBytes(8).toString('hex'); const writeFile = util.promisify(fs.writeFile); const readFile = util.promisify(fs.readFile); const lookup = util.promisify(dns.lookup); const lookupService = util.promisify(dns.lookupService); const file = path.join(__dirname, './tmp'); fs.writeFileSync(file, ''); als.enable(); afterAll(() => { als.disable(); redisClient.disconnect(); server.close(); const ids = []; let err = null; topList.forEach(item => { if (ids.indexOf(item.id) !== -1) { err = new Error('the id should be unique'); } else { ids.push(item.id); } }); if (err) { console.error(err); throw err; } }); describe('fs', () => { test('fs watch', async () => { als.scope(); const id = randomBytes(); als.set('id', id); const watcher = fs.watch(file, () => { expect(als.get('id')).toBe(id); watcher.close(); }); await writeFile(file, 'a'); topList.push(als.top()); }); test('fs write/read promise', () => { als.scope(); const id = randomBytes(); als.set('id', id); return writeFile(file, 'a') .then(() => { expect(als.get('id')).toBe(id); return new Promise((resolve, reject) => { fs.readFile(file, err => { if (err) { reject(err); return; } expect(als.get('id')).toBe(id); resolve(); }); }); }) .then(() => { topList.push(als.top()); }); }); test('fs write/read async/await', async () => { als.scope(); const id = randomBytes(); als.set('id', id); await writeFile(file, 'a'); expect(als.get('id')).toBe(id); await readFile(file); expect(als.get('id')).toBe(id); topList.push(als.top()); }); }); describe('JSSTREAM', () => { test('js read stream', () => new Promise((resolve, reject) => { als.scope(); const id = randomBytes(); als.set('id', id); const stream = fs.createReadStream(file); stream.on('data', () => { expect(als.get('id')).toBe(id); stream.close(); }); stream.on('error', reject); stream.on('close', () => { topList.push(als.top()); expect(als.get('id')).toBe(id); resolve(); }); fs.writeFileSync(file, 'ab'); })); test('js write stream', () => new Promise((resolve, reject) => { als.scope(); const id = randomBytes(); als.set('id', id); const stream = fs.createWriteStream(file); stream.on('error', reject); stream.on('close', () => { topList.push(als.top()); expect(als.get('id')).toBe(id); resolve(); }); stream.write('ab'); stream.end(); })); }); describe('dns', () => { test('get addr info promise', () => { als.scope(); const id = randomBytes(); als.set('id', id); return lookup('www.baidu.com') .then(() => { expect(als.get('id')).toBe(id); }) .then(() => { topList.push(als.top()); }); }); test('get addr info async/await', async () => { als.scope(); const id = randomBytes(); als.set('id', id); await lookup('www.baidu.com'); expect(als.get('id')).toBe(id); topList.push(als.top()); }); test('get name info promise', () => { als.scope(); const id = randomBytes(); als.set('id', id); return lookupService('127.0.0.1', 80) .then(() => { expect(als.get('id')).toBe(id); }) .then(() => { topList.push(als.top()); }); }); test('get name info async/await', async () => { als.scope(); const id = randomBytes(); als.set('id', id); await lookupService('127.0.0.1', 80); expect(als.get('id')).toBe(id); topList.push(als.top()); }); }); describe('http', () => { test('http get', () => { als.scope(); const id = randomBytes(); als.set('id', id); return new Promise((resolve, reject) => { expect(als.get('id')).toBe(id); http .get('http://www.baidu.com/', res => { expect(als.get('id')).toBe(id); res.on('data', () => { expect(als.get('id')).toBe(id); }); res.on('end', () => { expect(als.get('id')).toBe(id); resolve(); }); }) .on('error', reject); }).then(() => { expect(als.get('id')).toBe(id); topList.push(als.top()); }); }); }); describe('linked top', () => { test('normal linked top', () => { als.scope(); const id = randomBytes(); const user = randomBytes(); als.set('id', id); return delay(10) .then(() => { const fn1 = delay(10).then(() => { const current = als.getCurrentData(); expect(current.user).toBeUndefined(); }); const fn2 = new Promise(resolve => { als.set('user', user); resolve(); }); return Promise.all([fn1, fn2]); }) .then(() => { expect(als.get('id')).toBe(id); expect(als.get('user')).toBe(user); }); }); test('set value to self scope', () => { als.scope(); const id = randomBytes(); const user = randomBytes(); als.set('id', id); return delay(10) .then(() => { expect(als.get('id')).toBe(id); als.set('id', 'a'); als.set('user', user); }) .then(() => { expect(als.get('id')).toBe('a'); expect(als.get('user')).toBe(user); }); }); test('enableLinkedTop', () => { als.scope(); const id = randomBytes(); const user = randomBytes(); als.enableLinkedTop(); als.set('id', id); const current = als.getCurrentData(); return delay(10) .then(() => { als.set('user', user); }) .then(() => { expect(current.id).toBe(id); expect(current.user).toBe(user); als.disableLinkedTop(); }); }); }); describe('get use', () => { test('use', () => { als.scope(); let id = als.currentId(); return delay(10).then(() => { const use = als.use(id); expect(use).toBeGreaterThanOrEqual(9 * 1000 * 1000); id = als.currentId(); als.disableCreateTime(); return delay(10); }).then(() => { const use = als.use(id); expect(use).toBe(-1); }); }); }); describe('size', () => { test('get size', () => { expect(als.size()).toBeGreaterThan(1); }); }); describe('koa', () => { const check = url => { const fns = [1, 2, 3, 4, 5].map(() => { const id = randomBytes(8); return request(server) .get(url) .set('X-Request-Id', id) .expect(200) .then(response => { expect(response.text).toBe(id); }); }); return Promise.all(fns); }; test('get request id', () => check('/')); test('get request id (fs)', () => check('/?fs=true')); test('get request id(delay)', () => check('/?delay=true')); test('get request id(http)', () => check('/?http=true')); test('get request id(session)', () => check('/?session=true')); test('get request id(all)', () => check('/?fs=true&delay=true&http=true&session=true')); }); describe('getFromParent', () => { test('top', () => { als.scope(); let id = als.getFromParent('id'); expect(id).toBe(undefined); als.set('id', 1); id = als.getFromParent('id'); expect(id).toBe(undefined); }); describe('1 level', () => { test('single', () => { als.scope(); als.set('id', 1); return delay(10).then(() => { expect(als.getFromParent('id')).toBe(1); als.set('id', 2); expect(als.getFromParent('id')).toBe(1); expect(als.get('id')).toBe(2); }); }); test('multiple', () => { als.scope(); als.set('id', 1); return Promise.all([ delay(10).then(() => { expect(als.getFromParent('id')).toBe(1); als.set('id', 2); expect(als.getFromParent('id')).toBe(1); expect(als.get('id')).toBe(2); }), delay(10).then(() => { expect(als.getFromParent('id')).toBe(1); als.set('id', 3); expect(als.getFromParent('id')).toBe(1); expect(als.get('id')).toBe(3); }), ]).then(() => { expect(als.get('id')).toBe(1); }); }); }); test('2 level', () => { als.scope(); als.set('id', 1); return delay(10).then(() => { als.set('key2', 1); return delay(10).then(() => { expect(als.get('key2')).toBe(1); expect(als.getFromParent('id')).toBe(1); als.set('id', 2); expect(als.getFromParent('id')).toBe(1); expect(als.get('id')).toBe(2); }); }); }); }); describe('get all data', () => { expect(als.getAllData()).toBeDefined(); });