UNPKG

liveperson-functions-client

Version:

JavaScript client for LivePerson Functions.

331 lines 13.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const jwt = __importStar(require("jsonwebtoken")); const baseClient_1 = require("../../src/client/baseClient"); const client_1 = require("../../src/client/client"); const csdsClient_1 = require("../../src/helper/csdsClient"); const nock_1 = __importDefault(require("nock")); const secret = 'mySecret'; const TEST_V2_HOST = 'fninvocations.test124.com'; // V2 hosts starts with fninvocations and is required to trigger v2 flow const ACCOUNT_ID = '123456'; jest.mock('../../src/helper/csdsClient', () => { return { CsdsClient: jest.fn().mockImplementation(() => { return { get: jest.fn(() => TEST_V2_HOST), }; }), }; }); jest.mock('simple-oauth2', () => ({ ClientCredentials: jest.fn(() => ({ getToken: async () => ({ token: { access_token: jwt.sign({ aud: 'le4711', azp: 'bf16f923-b256-40c8-afa5-1b8e8372da09', scope: 'faas.lambda.invoke', iss: 'Sentinel', exp: Date.now() / 1000 + 60 * 60, iat: Date.now(), }, secret), }, }), })), })); const testConfig = { accountId: '123456', authStrategy: { clientId: 'foo', clientSecret: 'bar', }, }; describe('Client V2 flow', () => { beforeEach(() => { nock_1.default.cleanAll(); nock_1.default.enableNetConnect(); }); afterEach(jest.clearAllMocks); describe('success flows', () => { test('class and constructor - Base', () => { const client = new client_1.Client(testConfig); expect(csdsClient_1.CsdsClient).toHaveBeenCalledTimes(1); expect(client).toBeInstanceOf(client_1.Client); expect(client).toBeInstanceOf(baseClient_1.BaseClient); }); test('invoke method', async () => { const lpEventSource = 'testSystem'; const result1 = [123]; const result2 = [456]; const scope = (0, nock_1.default)(`https://${TEST_V2_HOST}`, { reqheaders: { 'Content-Type': 'application/json', 'User-Agent': value => true, 'X-Request-ID': value => true, Authorization: value => true, 'LP-EventSource': lpEventSource, }, }) .post('/api/account/123456/events/fooBar/invoke') .once() .reply(202, result1) .persist() .post('/api/account/le12345/events/fooBar/invoke') .once() .reply(202, result2) .persist(); const client1 = new client_1.Client(testConfig); const response1 = await client1.invoke({ eventId: 'fooBar', lpEventSource, body: { payload: {}, }, }); expect(response1).toBeNonEmptyObject(); expect(response1.body).toEqual(result1); const client2 = new client_1.Client({ ...testConfig, accountId: 'le12345' }); const response2 = await client2.invoke({ eventId: 'fooBar', externalSystem: 'testSystem', body: { payload: {}, }, }); expect(response2).toBeNonEmptyObject(); expect(response2.body).toEqual(result2); expect(scope.isDone()).toBe(true); }); test('invocation metrics', async () => { const lpEventSource = 'testSystem'; let onInvokeCalled = false; class MyMetricCollector { onInvoke(invocationData) { expect(invocationData.lpEventSource).toEqual(lpEventSource); expect(invocationData.externalSystem).toBeUndefined(); onInvokeCalled = true; return; } onGetLambdas(invocationData) { return; } onIsImplemented(invocationData) { return; } } const result1 = [123]; const scope = (0, nock_1.default)(`https://${TEST_V2_HOST}`) .post('/api/account/123456/events/fooBar/invoke') .once() .reply(202, result1) .persist(); const client1 = new client_1.Client(testConfig, { metricCollector: new MyMetricCollector(), }); await client1.invoke({ eventId: 'fooBar', lpEventSource, body: { payload: {}, }, }); expect(onInvokeCalled).toBe(true); expect(scope.isDone()).toBe(true); }); test('invocation metrics should contain deprecated externalSystem', async () => { const lpEventSource = 'testSystem'; let onInvokeCalled = false; class MyMetricCollector { onInvoke(invocationData) { expect(invocationData.lpEventSource).toEqual(lpEventSource); expect(invocationData.externalSystem).toEqual(lpEventSource); onInvokeCalled = true; return; } onGetLambdas(invocationData) { return; } onIsImplemented(invocationData) { return; } } const result1 = [123]; const scope = (0, nock_1.default)(`https://${TEST_V2_HOST}`) .post('/api/account/123456/events/fooBar/invoke') .once() .reply(202, result1) .persist(); const client1 = new client_1.Client(testConfig, { metricCollector: new MyMetricCollector(), }); await client1.invoke({ eventId: 'fooBar', externalSystem: lpEventSource, body: { payload: {}, }, }); expect(onInvokeCalled).toBe(true); expect(scope.isDone()).toBe(true); }); test('getLambdas deprecated method to get V2 functions', async () => { const lambdas = [{ uuid: 'a-b-c-d' }]; const scope = (0, nock_1.default)(`https://${TEST_V2_HOST}`) .get('/api/account/123456/functions?eventId=&userId=&functionName=') .once() .reply(200, lambdas) .persist(); const client = new client_1.Client({ ...testConfig, accountId: ACCOUNT_ID }); const response = await client.getLambdas({ externalSystem: 'testSystem', }); expect(response).toBeNonEmptyObject(); expect(response.body).toEqual(lambdas); expect(scope.isDone()).toBe(true); }); test('getFunctions', async () => { const lambdas = [{ uuid: 'a-b-c-d' }]; const scope = (0, nock_1.default)(`https://${TEST_V2_HOST}`) .get('/api/account/123456/functions?eventId=&userId=&functionName=') .once() .reply(200, lambdas) .persist(); const client = new client_1.Client({ ...testConfig, accountId: ACCOUNT_ID }); const response = await client.getFunctions({ externalSystem: 'testSystem', }); expect(response).toBeNonEmptyObject(); expect(response.body).toEqual(lambdas); expect(scope.isDone()).toBe(true); }); test('should retry on receiving a network error', async () => { const errorCode = { code: 'ECONNRESET' }; const scope = (0, nock_1.default)(`https://${TEST_V2_HOST}`) .post('/api/account/123456/lambdas/this-is-a-uuid/invoke') .times(3) .replyWithError(errorCode); const client = new client_1.Client(testConfig); const response = await client.invoke({ lambdaUuid: 'this-is-a-uuid', externalSystem: 'test-system', body: { payload: {}, }, }); expect(response.retryCount).toEqual(3); expect(scope.isDone()).toBe(true); }); }); describe('Unhappy flows', () => { test('should throw if Functions returns a none-okay status code', async () => { const scope = (0, nock_1.default)(`https://${TEST_V2_HOST}`) .post('/api/account/123456/lambdas/this-is-a-uuid/invoke') .times(3) .reply(502) .persist(); const config = { ...testConfig, failOnErrorStatusCode: true }; const client = new client_1.Client(config); try { await client.invoke({ lambdaUuid: 'this-is-a-uuid', externalSystem: 'test-system', body: { payload: {}, }, }); } catch (error) { expect(error).toMatchObject({ name: 'FaaSInvokeError', message: expect.stringContaining('502 - Bad Gateway'), }); expect(scope.isDone()).toBe(true); } }); test('should map V2 errors code to V1 error', async () => { var _a, _b, _c, _d; const scope = (0, nock_1.default)(`https://${TEST_V2_HOST}`) .post('/api/account/123456/lambdas/this-is-a-uuid/invoke') .times(3) .reply(901, { code: "com.customer.faas.function.threw-error", message: "something wrong" }) .persist(); const config = { ...testConfig, failOnErrorStatusCode: true }; const client = new client_1.Client(config); try { await client.invoke({ lambdaUuid: 'this-is-a-uuid', externalSystem: 'test-system', v1CompError: true, body: { payload: {}, }, }); } catch (error) { expect(error).toMatchObject({ name: 'FaaSLambdaError', message: expect.stringContaining('901'), }); expect((_d = (_c = (_b = (_a = error === null || error === void 0 ? void 0 : error.jse_cause) === null || _a === void 0 ? void 0 : _a.jse_cause) === null || _b === void 0 ? void 0 : _b.jse_info) === null || _c === void 0 ? void 0 : _c.response) === null || _d === void 0 ? void 0 : _d.body).toMatchObject({ errorCode: 'com.liveperson.faas.handler.custom-failure', errorMsg: "something wrong", }); expect(scope.isDone()).toBe(true); } }); test('should throw if network errors are raised continuously', async () => { const errorCode = { code: 'ECONNRESET' }; const scope = (0, nock_1.default)(`https://${TEST_V2_HOST}`) .post('/api/account/123456/lambdas/this-is-a-uuid/invoke') .times(3) .replyWithError(errorCode); const config = { ...testConfig, failOnErrorStatusCode: true }; const client = new client_1.Client(config); try { await client.invoke({ lambdaUuid: 'this-is-a-uuid', externalSystem: 'test-system', body: { payload: {}, }, }); } catch (error) { expect(error).toMatchObject({ name: 'FaaSInvokeError', }); expect(scope.isDone()).toBe(true); } }); }); }); //# sourceMappingURL=client.v2.test.js.map