UNPKG

@elastic.io/maester-client

Version:
229 lines (228 loc) 12.1 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); /* eslint-disable no-unused-expressions */ const nock_1 = __importDefault(require("nock")); const sinon_1 = __importDefault(require("sinon")); const chai_1 = require("chai"); const get_stream_1 = __importDefault(require("get-stream")); const jsonwebtoken_1 = require("jsonwebtoken"); const stream_1 = require("stream"); const StorageClient_1 = require("../src/StorageClient"); const errors_1 = require("../src/errors"); const logger_1 = __importDefault(require("../src/logger")); const helpers_1 = require("./helpers"); const interfaces_1 = require("../src/interfaces"); describe('Storage Client', () => { const config = { uri: 'https://ma.es.ter', jwtSecret: 'jwt', userAgent: 'userAgent' }; const storageClient = new StorageClient_1.StorageClient(config); const data = { test: 'test' }; const responseData = { contentLength: 'meta.contentLength', contentType: 'meta.contentType', createdAt: 'meta.createdAt', md5: 'meta.md5Hash', objectId: 'obj.id', metadata: 'meta.userMetadata' }; afterEach(() => { sinon_1.default.restore(); }); function authHeaderMatch(jwtPayload) { return (val) => { const decoded = (0, jsonwebtoken_1.verify)(val.split(' ')[1], config.jwtSecret); if (jwtPayload) { (0, chai_1.expect)(decoded).to.deep.include(jwtPayload); } return !!decoded; }; } describe('get', () => { it('should throw exception if neither jwt secret, nor jwt token provided', async () => { const storageClient2 = new StorageClient_1.StorageClient({ uri: config.uri, userAgent: 'userAgent' }); let err; try { await storageClient2.get('1', { jwtPayloadOrToken: {} }); } catch (e) { err = e; } (0, chai_1.expect)(err.toString()).to.include('JWT'); }); it(`should fail after ${interfaces_1.RETRIES_COUNT.defaultValue} retries`, async () => { const log = sinon_1.default.stub(logger_1.default, 'warn'); const storageClientCalls = (0, nock_1.default)(config.uri) .matchHeader('authorization', authHeaderMatch()) .get('/objects/1') .replyWithError({ code: 'ETIMEDOUT' }) .get('/objects/1') .reply(502) .get('/objects/1') .replyWithError({ code: 'ENOTFOUND' }); let err; try { await storageClient.get('1', { jwtPayloadOrToken: {} }); } catch (e) { err = e; } (0, chai_1.expect)(storageClientCalls.isDone()).to.be.true; (0, chai_1.expect)(err).to.be.instanceOf(errors_1.ServerTransportError); (0, chai_1.expect)(log.getCall(1).args[1].toString()).to.include('Error during object request'); (0, chai_1.expect)(log.callCount).to.be.equal(interfaces_1.RETRIES_COUNT.defaultValue); }); it('should not retry because of config', async () => { const log = sinon_1.default.stub(logger_1.default, 'warn'); const storageClientCalls = (0, nock_1.default)(config.uri) .matchHeader('authorization', authHeaderMatch()) .get('/objects/1') .reply(500); let err; try { await storageClient.get('1', { jwtPayloadOrToken: {}, retryOptions: { retriesCount: 0 } }); } catch (e) { err = e; } (0, chai_1.expect)(storageClientCalls.isDone()).to.be.true; (0, chai_1.expect)(err).to.be.instanceOf(errors_1.ServerTransportError); (0, chai_1.expect)(log.callCount).to.be.equal(0); }); it('should not retry 4xx client error', async () => { const log = sinon_1.default.stub(logger_1.default, 'warn'); const storageClientCalls = (0, nock_1.default)(config.uri) .matchHeader('authorization', authHeaderMatch()) .get('/objects/1') .reply(404); await (0, chai_1.expect)(storageClient.get('1', { jwtPayloadOrToken: {} })).to.be.rejectedWith('Request failed with status code 404'); (0, chai_1.expect)(storageClientCalls.isDone()).to.be.true; (0, chai_1.expect)(log.callCount).to.be.equal(0); }); it('should accept jwt token on get', async () => { const storageClient2 = new StorageClient_1.StorageClient({ uri: config.uri, userAgent: 'userAgent' }); const jwtPayload = { tenantId: '12', contractId: '1' }; const storageClientCalls = (0, nock_1.default)(config.uri) .matchHeader('authorization', authHeaderMatch(jwtPayload)) .get('/objects/1') .reply(200, (0, helpers_1.streamFromObject)(data)); const response = await storageClient2.get('1', { jwtPayloadOrToken: (0, jsonwebtoken_1.sign)(jwtPayload, config.jwtSecret) }); (0, chai_1.expect)(storageClientCalls.isDone()).to.be.true; (0, chai_1.expect)(response.data).to.be.instanceOf(stream_1.Readable); const resultData = JSON.parse(await (0, get_stream_1.default)(response.data)); (0, chai_1.expect)(resultData).to.be.deep.equal(data); }); it(`should retry get request ${interfaces_1.RETRIES_COUNT.defaultValue} times on errors`, async () => { const storageClientCalls = (0, nock_1.default)(config.uri) .matchHeader('authorization', authHeaderMatch()) .get('/objects/1') .reply(502) .get('/objects/1') .replyWithError({ code: 'ECONNRESET' }) .get('/objects/1') .reply(200, (0, helpers_1.streamFromObject)(data)); const response = await storageClient.get('1', { jwtPayloadOrToken: {} }); (0, chai_1.expect)(storageClientCalls.isDone()).to.be.true; (0, chai_1.expect)(response.data).to.be.instanceOf(stream_1.Readable); const resultData = JSON.parse(await (0, get_stream_1.default)(response.data)); (0, chai_1.expect)(resultData).to.be.deep.equal(data); }); describe('post', () => { it(`should retry post request ${interfaces_1.RETRIES_COUNT.defaultValue} times on errors`, async () => { const storageClientCalls = (0, nock_1.default)(config.uri) .matchHeader('authorization', authHeaderMatch()) .post('/objects') .replyWithError({ code: 'ECONNREFUSED' }) .post('/objects') .reply(502) .post('/objects') .reply(200, responseData); const postStream = async () => (0, helpers_1.streamFromObject)(data); const response = await storageClient.post(postStream, { jwtPayloadOrToken: {} }); (0, chai_1.expect)(response.data).to.be.deep.equal(responseData); (0, chai_1.expect)(storageClientCalls.isDone()).to.be.true; }); it('should accept jwt token on add', async () => { const storageClient2 = new StorageClient_1.StorageClient({ uri: config.uri, userAgent: 'userAgent' }); const jwtPayload = { tenantId: '12', contractId: '1' }; const storageClientCalls = (0, nock_1.default)(config.uri) .matchHeader('authorization', authHeaderMatch(jwtPayload)) .post('/objects') .reply(200, responseData); const postStream = async () => (0, helpers_1.streamFromObject)(data); const response = await storageClient2.post(postStream, { jwtPayloadOrToken: (0, jsonwebtoken_1.sign)(jwtPayload, config.jwtSecret) }); (0, chai_1.expect)(storageClientCalls.isDone()).to.be.true; (0, chai_1.expect)(response.data).to.be.deep.equal(responseData); (0, chai_1.expect)(storageClientCalls.isDone()).to.be.true; }); }); describe('put', () => { it(`should fail after ${interfaces_1.RETRIES_COUNT.defaultValue} retries`, async () => { const storageClientCalls = (0, nock_1.default)(config.uri) .matchHeader('authorization', authHeaderMatch()) .put('/objects/1') .replyWithError({ code: 'ECONNREFUSED' }) .put('/objects/1') .reply(502) .put('/objects/1') .replyWithError({ code: 'ENOTFOUND' }); let err; try { const putStream = async () => (0, helpers_1.streamFromObject)(data); await storageClient.put('1', putStream, { jwtPayloadOrToken: {} }); } catch (e) { err = e; } (0, chai_1.expect)(err).to.be.instanceOf(errors_1.ServerTransportError); (0, chai_1.expect)(storageClientCalls.isDone()).to.be.true; }); it('should throw exception if neither jwt secret, nor jwt token provided', async () => { const storageClient2 = new StorageClient_1.StorageClient({ uri: config.uri, userAgent: 'userAgent' }); let err; try { const putStream = async () => (0, helpers_1.streamFromObject)(data); await storageClient2.put('1', putStream, { jwtPayloadOrToken: {} }); } catch (e) { err = e; } (0, chai_1.expect)(err).to.be.instanceOf(errors_1.JwtNotProvidedError); }); it('should accept jwt token on add', async () => { const storageClient2 = new StorageClient_1.StorageClient({ uri: config.uri, userAgent: 'userAgent' }); const jwtPayload = { tenantId: '12', contractId: '1' }; const storageClientCalls = (0, nock_1.default)(config.uri) .matchHeader('authorization', authHeaderMatch(jwtPayload)) .put('/objects/1') .reply(200, responseData); const putStream = async () => (0, helpers_1.streamFromObject)(data); const response = await storageClient2.put('1', putStream, { jwtPayloadOrToken: (0, jsonwebtoken_1.sign)(jwtPayload, config.jwtSecret) }); (0, chai_1.expect)(storageClientCalls.isDone()).to.be.true; (0, chai_1.expect)(response.data).to.be.deep.equal(responseData); (0, chai_1.expect)(storageClientCalls.isDone()).to.be.true; }); it('should retry post request 3 times on errors', async () => { const storageClientCalls = (0, nock_1.default)(config.uri) .matchHeader('authorization', authHeaderMatch()) .put('/objects/1') .replyWithError({ code: 'ECONNREFUSED' }) .put('/objects/1') .reply(502) .put('/objects/1') .reply(200, responseData); const putStream = async () => (0, helpers_1.streamFromObject)(data); const response = await storageClient.put('1', putStream, { jwtPayloadOrToken: {} }); (0, chai_1.expect)(response.data).to.be.deep.equal(responseData); (0, chai_1.expect)(storageClientCalls.isDone()).to.be.true; }); }); }); });