@eagleeye-solutions/integration-events-common
Version:
Eagle Eye CDP connector common functionality
693 lines • 24.6 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const jest_fetch_mock_1 = __importDefault(require("jest-fetch-mock"));
const handlers_1 = require("../../src/handlers");
const index_1 = require("../../src/platform/index");
const connector_configs_1 = require("../fixtures/connector-configs");
const mockAppConfig = {
platformConfig: {
platform: 'GCP',
projectId: 'test-project',
internalMessagesTopicName: 'internal-messages',
cdpDeadLetterQueue: 'internal-messages-dlq',
pubSubAuthenticatedPushServiceAccount: 'fake@example.org',
pubSubAuthenticatedPushAudience: 'https://example.org/internal',
},
configPlatform: 'GENERIC',
configUrl: 'https://example.org/api',
routes: {
internal: {
path: '/internal',
getInternalMessageFromRequest: jest.fn(),
handlers: {
'cdp-outbound-event': jest.fn(),
'cdp-inbound-event': jest.fn(),
'ee-air-inbound-event': jest.fn(),
'ee-air-outbound-event': jest.fn(),
},
},
},
appMetadata: {
name: 'some-api',
version: 'some-version',
tagline: 'some-tagline',
},
handlePermanentMessageDeliveryFailure: jest.fn(),
traceIdName: 'x-ees-connector-trace-id',
includeTraceIdInHttpResponseHeaders: true,
};
const mockLogger = {
debug: jest.fn(msg => {
console.log('debug: ', msg);
}),
info: jest.fn(msg => {
console.log('info: ', msg);
}),
error: jest.fn(msg => {
console.error(msg);
}),
};
jest.mock('../../src/platform/index');
describe.each([
{
requestPath: '/out/generic/connector-id',
requestBody: {
some: {
opaque: 'data',
},
},
connectorConfig: connector_configs_1.mockOutConnectorConfig,
},
])('handleEeAirOutboundRequest: $requestPath', ({ requestPath, requestBody, connectorConfig }) => {
beforeAll(() => {
jest_fetch_mock_1.default.enableMocks();
});
afterAll(() => {
jest_fetch_mock_1.default.disableMocks();
});
afterEach(() => {
jest_fetch_mock_1.default.resetMocks();
handlers_1.getConnectorConfig.clear();
jest.clearAllMocks();
});
it('sets the response status to 200 OK if the request is processed successfully', async () => {
// Arrange
const req = {
params: {
connectorId: 'some-connector-id',
},
get: jest.fn().mockReturnValue('some-external-key'),
body: requestBody,
originalUrl: requestPath,
log: mockLogger,
id: 'some-id',
};
const res = {
status: jest.fn().mockReturnThis(),
send: jest.fn(),
app: {
get: jest.fn().mockReturnValue(mockAppConfig),
},
set: jest.fn().mockReturnThis(),
};
jest_fetch_mock_1.default.mockResponse(async () => {
return {
status: 200,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(connectorConfig),
};
});
// Act
await (0, handlers_1.handleEeAirOutboundRequest)(req, res);
// Assert
expect(res.status).toHaveBeenCalledWith(200);
expect(res.send).toHaveBeenCalledTimes(1);
expect(index_1.sendInternalMessage).toHaveBeenCalledWith(mockAppConfig, {
type: 'ee-air-outbound-event',
connectorConfig,
payload: requestBody,
}, {
'x-ees-connector-trace-id': 'some-id',
}, expect.anything());
});
});
describe.each([
{
requestPath: '/in/generic/connector-id',
requestBody: {
type: 'services/trigger',
body: {
walletTransaction: {
reference: 'some-reference',
},
identityValue: 'some-identity',
triggers: [
{
reference: 'some-reference',
},
],
},
},
connectorConfig: connector_configs_1.mockInConnectorConfig,
},
])('handleExternalRequest: $requestPath', ({ requestPath, requestBody, connectorConfig }) => {
beforeAll(() => {
jest_fetch_mock_1.default.enableMocks();
});
afterAll(() => {
jest_fetch_mock_1.default.disableMocks();
});
afterEach(() => {
jest_fetch_mock_1.default.resetMocks();
handlers_1.getConnectorConfig.clear();
jest.clearAllMocks();
});
it('sets the response status to 200 OK if the request is processed successfully', async () => {
// Arrange
const req = {
params: {
connectorId: 'some-connector-id',
},
get: jest.fn().mockReturnValue('some-external-key'),
body: requestBody,
originalUrl: requestPath,
log: mockLogger,
id: 'some-id',
};
const res = {
status: jest.fn().mockReturnThis(),
send: jest.fn(),
app: {
get: jest.fn().mockReturnValue(mockAppConfig),
},
set: jest.fn().mockReturnThis(),
};
jest_fetch_mock_1.default.mockResponse(async () => {
return {
status: 200,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(connectorConfig),
};
});
// Act
await (0, handlers_1.handleCdpOutboundRequest)(req, res);
// Assert
expect(res.status).toHaveBeenCalledWith(200);
expect(res.send).toHaveBeenCalledTimes(1);
expect(index_1.sendInternalMessage).toHaveBeenCalledWith(mockAppConfig, {
type: 'cdp-outbound-event',
connectorConfig,
payload: requestBody,
}, {
'x-ees-connector-trace-id': 'some-id',
}, expect.anything());
});
});
describe('', () => {
it.each([
{
requestBody: {},
expectedErrors: [
{
message: 'Invalid literal value, expected "services/trigger"',
path: 'type',
},
{
message: 'Required',
path: 'body',
},
],
description: 'is empty',
},
{
requestBody: {
type: 'some/invalid/type',
body: {
walletTransaction: {
reference: 'some reference',
},
identityValue: 'some-identity',
triggers: [{ reference: 'some-reference' }],
},
},
expectedErrors: [
{
message: 'Invalid literal value, expected "services/trigger"',
path: 'type',
},
],
description: 'has an invalid type',
},
{
requestBody: {
type: '',
body: {
walletTransaction: {
reference: 'some reference',
},
identityValue: 'some-identity',
triggers: [{ reference: 'some-reference' }],
},
},
expectedErrors: [
{
message: 'Invalid literal value, expected "services/trigger"',
path: 'type',
},
],
description: 'has an empty type',
},
{
requestBody: {
type: 'services/trigger',
body: {
walletTransaction: {
reference: 'some reference',
},
identityValue: '',
triggers: [{ reference: 'some-reference' }],
},
},
expectedErrors: [
{
message: 'String must contain at least 1 character(s)',
path: 'body.identityValue',
},
],
description: 'has an empty body.identityValue',
},
{
requestBody: {
type: 'services/trigger',
body: {
walletTransaction: {
reference: 'some reference',
},
identityValue: 'a',
triggers: [],
},
},
expectedErrors: [
{
message: 'Array must contain at least 1 element(s)',
path: 'body.triggers',
},
],
description: 'has an empty body.triggers array',
},
{
requestBody: {
type: 'services/trigger',
body: {
walletTransaction: {
reference: 'some reference',
},
identityValue: 'a',
triggers: [''],
},
},
expectedErrors: [
{
message: 'Expected object, received string',
path: 'body.triggers.0',
},
],
description: 'has the wrong element type in body.triggers',
},
{
requestBody: {
type: 'services/trigger',
body: {
walletTransaction: {
reference: 'some reference',
},
identityValue: 'a',
triggers: [{}],
},
},
expectedErrors: [
{
message: 'Required',
path: 'body.triggers.0.reference',
},
],
description: 'has no reference attribute in body.triggers.0',
},
{
requestBody: {
type: 'services/trigger',
body: {
walletTransaction: {
reference: 'some reference',
},
identityValue: 'a',
triggers: [{ reference: 1 }],
},
},
expectedErrors: [
{
message: 'Expected string, received number',
path: 'body.triggers.0.reference',
},
],
description: 'has the wrong type in body.triggers.0.reference (1)',
},
{
requestBody: {
type: 'services/trigger',
body: {
walletTransaction: {
reference: 'some reference',
},
identityValue: 'a',
triggers: [{ reference: null }],
},
},
expectedErrors: [
{
message: 'Expected string, received null',
path: 'body.triggers.0.reference',
},
],
description: 'has the wrong type in body.triggers.0.reference (2)',
},
{
requestBody: {
type: 'services/trigger',
body: {
walletTransaction: {
reference: 'some reference',
},
identityValue: 'a',
triggers: [{ reference: '' }],
},
},
expectedErrors: [
{
message: 'String must contain at least 1 character(s)',
path: 'body.triggers.0.reference',
},
],
description: 'triggers.0.reference does not meet the minimum length requirements',
},
{
requestBody: {
type: 'services/trigger',
body: {
walletTransaction: {
reference: null,
},
identityValue: 'a',
triggers: [{ reference: 'a' }],
},
},
expectedErrors: [
{
message: 'Expected string, received null',
path: 'body.walletTransaction.reference',
},
],
description: 'body.walletTransaction.reference is the wrong type',
},
{
requestBody: {
type: 'services/trigger',
body: {
identityValue: 'a',
triggers: [{ reference: 'a' }],
walletTransaction: {
reference: '',
},
},
},
expectedErrors: [
{
message: 'String must contain at least 1 character(s)',
path: 'body.walletTransaction.reference',
},
],
description: 'body.walletTransaction.reference does not meet the minimum length requirements',
},
{
requestBody: {
type: 'services/trigger',
body: {
identityValue: 'a',
triggers: [{ reference: 'a' }],
walletTransaction: {},
},
},
expectedErrors: [
{
message: 'Required',
path: 'body.walletTransaction.reference',
},
],
description: 'body.walletTransaction.reference is missing',
},
{
requestBody: {
type: 'services/trigger',
body: {
identityValue: 'a',
triggers: [{ reference: 'a' }],
},
},
expectedErrors: [
{
message: 'Required',
path: 'body.walletTransaction',
},
],
description: 'body.walletTransaction is missing',
},
])('sends a 400 Bad Request if the request $description', async ({ requestBody, expectedErrors }) => {
// Arrange
const req = {
params: {
connectorId: 'some-connector-id',
},
get: jest.fn().mockReturnValue('some-external-key'),
body: requestBody,
originalUrl: '/in/generic/some-connector-id',
log: mockLogger,
id: 'some-id',
};
const res = {
status: jest.fn().mockReturnThis(),
send: jest.fn(),
app: {
get: jest.fn().mockReturnValue(mockAppConfig),
},
set: jest.fn().mockReturnThis(),
};
// Act
await (0, handlers_1.handleCdpOutboundRequest)(req, res);
// Assert
expect(res.status).toHaveBeenCalledWith(400);
expect(res.send).toHaveBeenCalledTimes(1);
expect(res.send).toHaveBeenCalledWith({
message: 'Validation error',
errors: expectedErrors,
});
expect(index_1.sendInternalMessage).not.toHaveBeenCalled();
});
});
describe('getConnectorConfig', () => {
beforeAll(() => {
jest_fetch_mock_1.default.enableMocks();
});
afterAll(() => {
jest_fetch_mock_1.default.disableMocks();
});
afterEach(() => {
jest_fetch_mock_1.default.resetMocks();
handlers_1.getConnectorConfig.clear();
});
it('calls the Config API to fetch the connector config', async () => {
// Arrange
jest_fetch_mock_1.default.mockResponse(async () => {
return {
status: 200,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(connector_configs_1.mockOutConnectorConfig),
};
});
// Act
const output = await (0, handlers_1.getConnectorConfig)({
appConfig: mockAppConfig,
connectorId: '123',
externalKey: '456',
direction: 'out',
logger: mockLogger,
});
// Assert
expect(jest_fetch_mock_1.default).toHaveBeenCalledTimes(1);
expect(jest_fetch_mock_1.default).toHaveBeenCalledWith('https://example.org/api/connectors/123/config?platform=GENERIC&key=456');
expect(output).toEqual(connector_configs_1.mockOutConnectorConfig);
});
it('returns a cached response if available', async () => {
// Arrange
jest_fetch_mock_1.default.mockResponse(async () => {
return {
status: 200,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(connector_configs_1.mockOutConnectorConfig),
};
});
// Act
const output1 = await (0, handlers_1.getConnectorConfig)({
appConfig: mockAppConfig,
connectorId: '123',
externalKey: '456',
direction: 'out',
logger: mockLogger,
});
const output2 = await (0, handlers_1.getConnectorConfig)({
appConfig: mockAppConfig,
connectorId: '123',
externalKey: '456',
direction: 'out',
logger: mockLogger,
});
// Assert
expect(jest_fetch_mock_1.default).toHaveBeenCalledTimes(1);
expect(jest_fetch_mock_1.default).toHaveBeenCalledWith('https://example.org/api/connectors/123/config?platform=GENERIC&key=456');
expect(output1).toEqual(connector_configs_1.mockOutConnectorConfig);
expect(output2).toEqual(connector_configs_1.mockOutConnectorConfig);
});
it('returns a cached response even if the logger instance changes', async () => {
// Arrange
jest_fetch_mock_1.default.mockResponse(async () => {
return {
status: 200,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(connector_configs_1.mockOutConnectorConfig),
};
});
// Act
const output1 = await (0, handlers_1.getConnectorConfig)({
appConfig: mockAppConfig,
connectorId: '123',
externalKey: '456',
direction: 'out',
logger: mockLogger,
});
const output2 = await (0, handlers_1.getConnectorConfig)({
appConfig: mockAppConfig,
connectorId: '123',
externalKey: '456',
direction: 'out',
logger: { ...mockLogger, warn: console.log, foo: 'bar' },
});
// Assert
expect(jest_fetch_mock_1.default).toHaveBeenCalledTimes(1);
expect(jest_fetch_mock_1.default).toHaveBeenCalledWith('https://example.org/api/connectors/123/config?platform=GENERIC&key=456');
expect(output1).toEqual(connector_configs_1.mockOutConnectorConfig);
expect(output2).toEqual(connector_configs_1.mockOutConnectorConfig);
});
it('makes separate calls to the Config API if the direction is different', async () => {
// Arrange
jest_fetch_mock_1.default.mockResponse(async (req) => {
if (req.url ===
'https://example.org/api/connectors/123/config?platform=GENERIC&key=some-external-key-out') {
return {
status: 200,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(connector_configs_1.mockOutConnectorConfig),
};
}
else if (req.url ===
'https://example.org/api/connectors/123/config?platform=GENERIC&key=some-external-key-in') {
return {
status: 200,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(connector_configs_1.mockInConnectorConfig),
};
}
else {
return { status: 404 };
}
});
// Act
const output1 = await (0, handlers_1.getConnectorConfig)({
appConfig: mockAppConfig,
connectorId: '123',
externalKey: 'some-external-key-out',
direction: 'out',
logger: mockLogger,
});
const output2 = await (0, handlers_1.getConnectorConfig)({
appConfig: mockAppConfig,
connectorId: '123',
externalKey: 'some-external-key-in',
direction: 'in',
logger: mockLogger,
});
// Assert
expect(jest_fetch_mock_1.default).toHaveBeenCalledTimes(2);
expect(jest_fetch_mock_1.default).toHaveBeenNthCalledWith(1, 'https://example.org/api/connectors/123/config?platform=GENERIC&key=some-external-key-out');
expect(jest_fetch_mock_1.default).toHaveBeenNthCalledWith(2, 'https://example.org/api/connectors/123/config?platform=GENERIC&key=some-external-key-in');
expect(output1).toEqual(connector_configs_1.mockOutConnectorConfig);
expect(output2).toEqual(connector_configs_1.mockInConnectorConfig);
});
it('makes separate calls to the Config API if the connectorId is different', async () => {
// Arrange
jest_fetch_mock_1.default.mockResponse(async (req) => {
if (req.url ===
'https://example.org/api/connectors/123/config?platform=GENERIC&key=some-external-key-out') {
return {
status: 200,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
...connector_configs_1.mockOutConnectorConfig,
unitId: 'x',
}),
};
}
else if (req.url ===
'https://example.org/api/connectors/234/config?platform=GENERIC&key=some-external-key-out') {
return {
status: 200,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
...connector_configs_1.mockOutConnectorConfig,
unitId: 'y',
}),
};
}
else {
return { status: 404 };
}
});
// Act
const output1 = await (0, handlers_1.getConnectorConfig)({
appConfig: mockAppConfig,
connectorId: '123',
externalKey: 'some-external-key-out',
direction: 'out',
logger: mockLogger,
});
const output2 = await (0, handlers_1.getConnectorConfig)({
appConfig: mockAppConfig,
connectorId: '234',
externalKey: 'some-external-key-out',
direction: 'out',
logger: mockLogger,
});
// Assert
expect(jest_fetch_mock_1.default).toHaveBeenCalledTimes(2);
expect(jest_fetch_mock_1.default).toHaveBeenNthCalledWith(1, 'https://example.org/api/connectors/123/config?platform=GENERIC&key=some-external-key-out');
expect(jest_fetch_mock_1.default).toHaveBeenNthCalledWith(2, 'https://example.org/api/connectors/234/config?platform=GENERIC&key=some-external-key-out');
expect(output1).toEqual({
...connector_configs_1.mockOutConnectorConfig,
unitId: 'x',
});
expect(output2).toEqual({
...connector_configs_1.mockOutConnectorConfig,
unitId: 'y',
});
});
});
//# sourceMappingURL=handlers.spec.js.map