UNPKG

@qiniu/miku-delivery-mp-ks

Version:

Kuaishou Mini Program SDK for Miku Delivery

236 lines (234 loc) 9.34 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; jest.setTimeout(15000); jest.mock('../utils/env'); import { delay, randomText } from '../test'; import Logger, { getLogBody, apiPrefix } from '.'; import { makeSuccFetch } from './test'; import { Response, Headers } from '../utils/fetch'; const appInfo = { appID: 'foo', appSalt: 'bar' }; describe('Logger', () => { it('should construct well', () => { new Logger(appInfo, makeSuccFetch()); }); describe('log', () => { it('should work well', () => __awaiter(void 0, void 0, void 0, function* () { const logger = new Logger(appInfo, makeSuccFetch()); logger.log(...makeDNSResolveLog()); })); it('should batch', () => __awaiter(void 0, void 0, void 0, function* () { const f = makeSuccFetch(); const logger = new Logger(appInfo, f); logger.log(...makeDNSResolveLog()); expect(f).not.toBeCalled(); })); it('should call api correctly', () => __awaiter(void 0, void 0, void 0, function* () { var _a; const f = makeSuccFetch(); const logger = new Logger(appInfo, f, undefined, 1); logger.log(...makeDownloadLog()); logger.log(...makeDNSResolveLog()); logger.log(...makeDownloadLog()); logger.log(...makeDNSResolveLog()); logger.log(...makeDownloadLog()); yield delay(1500); expect(f).toBeCalledTimes(1); const req = f.mock.calls[0][0]; expect((_a = req.headers.get('X-Env')) === null || _a === void 0 ? void 0 : _a.length).toBeGreaterThan(10); expect([ `${apiPrefix}/v1/log/DownloadLog,DnsResolveLog`, `${apiPrefix}/v1/log/DnsResolveLog,DownloadLog` ]).toContain(req.url); const countArray = countLogs(req); expect(countArray.length).toBe(2); expect(countArray.sort()).toEqual([2, 3]); })); it('should flush when $flushNum reached', () => __awaiter(void 0, void 0, void 0, function* () { const flushNum = 5; const f = makeSuccFetch(); const logger = new Logger(appInfo, f, flushNum); logger.log(...makeDownloadLog()); logger.log(...makeDNSResolveLog()); logger.log(...makeDownloadLog()); logger.log(...makeDNSResolveLog()); yield delay(0); expect(f).not.toBeCalled(); logger.log(...makeDownloadLog()); yield delay(0); expect(f).toBeCalledTimes(1); expect([ `${apiPrefix}/v1/log/DownloadLog,DnsResolveLog`, `${apiPrefix}/v1/log/DnsResolveLog,DownloadLog` ]).toContain(f.mock.calls[0][0].url); })); it('should flush when $flushNum exceeded', () => __awaiter(void 0, void 0, void 0, function* () { const flushNum = 5; const logNum = flushNum + 3; const f = makeSuccFetch(); const logger = new Logger(appInfo, f, flushNum); for (let i = 0; i < logNum; i++) { logger.log(...makeDownloadLog()); } yield delay(0); expect(f).toBeCalledTimes(1); const req = f.mock.calls[0][0]; expect(req.url).toBe(`${apiPrefix}/v1/log/DownloadLog`); expect(countLogs(req)).toEqual([logNum]); })); it('should flush when $flushWait reached', () => __awaiter(void 0, void 0, void 0, function* () { const flushWait = 1; const f = makeSuccFetch(); const logger = new Logger(appInfo, f, 100, flushWait); for (let i = 0; i < 10; i++) { logger.log(...makeDownloadLog()); } yield delay(0); expect(f).not.toBeCalled(); for (let i = 0; i < 10; i++) { logger.log(...makeDNSResolveLog()); } yield delay(500); expect(f).not.toBeCalled(); yield delay(1000); expect(f).toBeCalledTimes(1); expect(countLogs(f.mock.calls[0][0])).toEqual([10, 10]); f.mockClear(); logger.log(...makeDownloadLog()); expect(f).not.toBeCalled(); yield delay(1500); expect(f).toBeCalledTimes(1); expect(countLogs(f.mock.calls[0][0])).toEqual([1]); })); it('should send 200 logs at most once', () => __awaiter(void 0, void 0, void 0, function* () { const logNum = 502; const f = makeSuccFetch(); const logger = new Logger(appInfo, f); for (let i = 0; i < logNum; i += 2) { logger.log(...makeDownloadLog()); logger.log(...makeDNSResolveLog()); } yield delay(0); expect(f).toBeCalledTimes(3); expect(countLogs(f.mock.calls[0][0])).toEqual([100, 100]); expect(countLogs(f.mock.calls[1][0])).toEqual([100, 100]); expect(countLogs(f.mock.calls[2][0])).toEqual([51, 51]); })); it('should retry when call api failed', function () { return __awaiter(this, void 0, void 0, function* () { const f = jest.fn() .mockResolvedValueOnce(new Response('', { status: 502, headers: new Headers() })) .mockResolvedValue(new Response('', { status: 200, headers: new Headers() })); const logger = new Logger(appInfo, f, undefined, 1); logger.log(...makeDNSResolveLog()); // flush & 1st try yield delay(1500); expect(f).toBeCalledTimes(1); // retry after 2s yield delay(2000); expect(f).toBeCalledTimes(2); // no more retry after succeed yield delay(2000); expect(f).toBeCalledTimes(2); }); }); it('should limit retry attempts', function () { return __awaiter(this, void 0, void 0, function* () { const f = jest.fn().mockResolvedValue(new Response('', { status: 502, headers: new Headers() })); const logger = new Logger(appInfo, f, undefined, 1); logger.log(...makeDNSResolveLog()); yield delay(10000); expect(f).toBeCalledTimes(3); }); }); }); }); describe('getLogBody', () => { it('should work well', () => { const now = Date.now(); expect(getLogBody([{ schema: 'DnsResolveLog', logs: [ { ts: now, foo: 1, bar: 'bar' }, { ts: now + 1, foo: 2, bar: 'bar,2' }, { ts: now + 2, foo: 3, bar: 'bar,"3' } ] }, { schema: 'DownloadLog', logs: [ { ts: now, baz: 4 } ] }])).toBe(` ts,foo,bar ${now},1,bar ${now + 1},2,"bar,2" ${now + 2},3,"bar,""3" ts,baz ${now},4 `.trim()); }); it('should put ts as the first column', () => { const now = Date.now(); expect(getLogBody([{ schema: 'DnsResolveLog', logs: [ { bar: 'bar', ts: now, foo: 1 }, { bar: 'bar,2', ts: now + 1, foo: 2 }, { bar: 'bar,"3', ts: now + 2, foo: 3 } ] }])).toBe(` ts,bar,foo ${now},bar,1 ${now + 1},"bar,2",2 ${now + 2},"bar,""3",3 `.trim()); }); }); function makeDNSResolveLog() { return ['DnsResolveLog', { r_id: randomText(20), loc: '127.0.0.1', ip: '1.1.1.1', domain: 'foo.com', status_code: 200, err_msg: '', err_desc: '', t_conn: 0.5, t_total: 0.8 }]; } function makeDownloadLog() { return ['DownloadLog', { r_id: randomText(20), loc: '127.0.0.1', ip: '1.1.1.1', domain: 'foo.com', status_code: 200, err_msg: '', err_desc: '', range_st: 0, range_end: 0, retry: 1, ftask_id: randomText(20), d_id: randomText(20), t_conn: 0.5, t_tls: 0.2, t_st_trans: 0.2, t_content_trans: 0.5, t_total: 1.5, resp_size: 1 << 10 }]; } function countLogs(request) { const blocks = request.body.split('\n\n'); return blocks.map(block => block.split('\n').length - 1); }