Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 9 additions & 45 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"plugins": [
"@typescript-eslint",
"import",
"eslint-plugin-jsdoc"
"eslint-plugin-tsdoc"
],
"env": {
"browser": false,
Expand Down Expand Up @@ -35,6 +35,13 @@
"no-use-before-define": "off",
"no-undef": "off" // turned off to avoid issue with triple-slash path directive
}
},
{
// Enable TSDoc rules for TypeScript files, allowing the use of JSDoc in JS files.
"files": ["**/*.ts"],
"rules": {
"tsdoc/syntax": "warn"
}
}
],
"rules": {
Expand Down Expand Up @@ -75,49 +82,6 @@
"quote-props": ["error", "as-needed"],
"comma-spacing": ["error", { "before": false, "after": true }],
"object-curly-spacing": ["error", "always"],
"no-trailing-spaces": "error",
// jsdoc
"jsdoc/check-access": "error",
"jsdoc/check-alignment": "error",
"jsdoc/check-param-names": ["error", {
"allowExtraTrailingParamDocs": true
}],
"jsdoc/check-syntax": "error",
"jsdoc/check-tag-names": ["error", {
"definedTags": [
"parent",
"body",
"endpoint",
"ngdoc",
"restrict"
]
}],
"jsdoc/check-types": "error",
"jsdoc/implements-on-classes": "error",
"jsdoc/match-description": "error",
"jsdoc/newline-after-description": "error",
"jsdoc/require-description": ["error", {
"checkConstructors": false,
"descriptionStyle": "any"
}],
"jsdoc/require-description-complete-sentence": "error",
"jsdoc/require-hyphen-before-param-description": ["error", "never"],
"jsdoc/require-param": "error",
"jsdoc/require-param-description": "error",
"jsdoc/require-param-name": "error",
"jsdoc/require-param-type": "error",
"jsdoc/require-property": "error",
"jsdoc/require-property-description": "error",
"jsdoc/require-property-name": "error",
"jsdoc/require-property-type": "error",
"jsdoc/require-returns": "error",
"jsdoc/require-returns-check": "error",
"jsdoc/require-returns-type": "error",
"jsdoc/valid-types": "error"
},
"settings": {
"jsdoc": {
"mode": "typescript"
}
"no-trailing-spaces": "error"
}
}
39 changes: 0 additions & 39 deletions e2e/server/server.js

This file was deleted.

67 changes: 53 additions & 14 deletions e2e/synchronizer.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import responseMocks from './utils/responseMocks.json';
import fetchMock from './utils/nodeFetchMock';
import { Synchronizer } from '../src/index';
import { PREFIX, REDIS_PREFIX, REDIS_URL, SERVER_MOCK_URL } from './utils/constants';
import runSDKConsumer from './utils/SDKConsumerMode';
import redisAdapterWrapper from './utils/redisAdapterWrapper';
import { ISynchronizerSettings } from '../types';

fetchMock.get(SERVER_MOCK_URL + '/version', 200);
fetchMock.post({ url: SERVER_MOCK_URL + '/v1/metrics/config', repeat: 3 }, 200);
fetchMock.post({ url: SERVER_MOCK_URL + '/v1/metrics/usage', repeat: 3 }, 200);
fetchMock.post({ url: SERVER_MOCK_URL + '/events/bulk', repeat: 3 }, 200);
fetchMock.post({ url: SERVER_MOCK_URL + '/testImpressions/bulk', repeat: 2 }, 200);
fetchMock.post({ url: SERVER_MOCK_URL + '/testImpressions/count', repeat: 2 }, 200);
fetchMock.post({ url: SERVER_MOCK_URL + '/v1/keys/ss', repeat: 1 }, 200);

let _redisWrapper = redisAdapterWrapper({ url: REDIS_URL });

// @TODO validate HTTP requests
const createSynchronizer = (synchronizerMode?: string) => {
/**
* Settings creation.
Expand Down Expand Up @@ -57,6 +66,15 @@ describe('Synchronizer e2e tests', () => {

describe('Runs Synchronizer for the [FIRST] time, and', () => {
beforeAll(async () => {
fetchMock.getOnce(SERVER_MOCK_URL + '/splitChanges?s=1.1&since=-1', { status: 200, body: responseMocks.splitChanges[0] });
fetchMock.getOnce(SERVER_MOCK_URL + '/segmentChanges/test_maldo?since=-1', { status: 200, body: responseMocks.segmentChanges[0] });
fetchMock.getOnce(SERVER_MOCK_URL + '/segmentChanges/ENDIOS_PEREZ?since=-1', { status: 200, body: responseMocks.segmentChanges[1] });
fetchMock.getOnce(SERVER_MOCK_URL + '/segmentChanges/Lucas_Segments_Tests?since=-1', { status: 200, body: responseMocks.segmentChanges[2] });
fetchMock.getOnce(SERVER_MOCK_URL + '/segmentChanges/test_maldo?since=1589906133231', { status: 200, body: responseMocks.segmentChanges[3] });
fetchMock.getOnce(SERVER_MOCK_URL + '/segmentChanges/ENDIOS_PEREZ?since=1606940431526', { status: 200, body: responseMocks.segmentChanges[4] });
fetchMock.getOnce(SERVER_MOCK_URL + '/segmentChanges/Lucas_Segments_Tests?since=1609943267407', { status: 200, body: responseMocks.segmentChanges[5] });
fetchMock.getOnce(SERVER_MOCK_URL + '/segmentChanges/Lucas_Segments_Tests?since=1617053238061', { status: 200, body: responseMocks.segmentChanges[6] });

const _synchronizer = createSynchronizer();
await _synchronizer.execute();
});
Expand Down Expand Up @@ -126,6 +144,10 @@ describe('Synchronizer e2e tests', () => {

describe('Runs Synchronizer a [SECOND] time and', () => {
beforeAll(async () => {
fetchMock.getOnce(SERVER_MOCK_URL + '/splitChanges?s=1.1&since=1619720346271', { status: 200, body: responseMocks.splitChanges[2] });
fetchMock.getOnce(SERVER_MOCK_URL + '/segmentChanges/test_maldo?since=1589906133231', { status: 200, body: responseMocks.segmentChanges[3] });
fetchMock.getOnce(SERVER_MOCK_URL + '/segmentChanges/Lucas_Segments_Tests?since=1617053238061', { status: 200, body: responseMocks.segmentChanges[6] });

const _synchronizer = createSynchronizer();

const hasExecute = await _synchronizer.execute();
Expand Down Expand Up @@ -202,6 +224,10 @@ describe('Synchronizer e2e tests', () => {
});

test('Run Synchronizer and check that data was popped from Redis and sent to Split BE', async () => {
fetchMock.getOnce(SERVER_MOCK_URL + '/splitChanges?s=1.1&since=1619720346272', { status: 200, body: responseMocks.splitChanges[3] });
fetchMock.getOnce(SERVER_MOCK_URL + '/segmentChanges/test_maldo?since=1589906133231', { status: 200, body: responseMocks.segmentChanges[3] });
fetchMock.getOnce(SERVER_MOCK_URL + '/segmentChanges/Lucas_Segments_Tests?since=1617053238061', { status: 200, body: responseMocks.segmentChanges[6] });

const _synchronizer = createSynchronizer();

const hasExecute = await _synchronizer.execute();
Expand Down Expand Up @@ -246,6 +272,10 @@ describe('Synchronizer e2e tests', () => {
});

test('Run Synchronizer and check that data was popped from Redis and sent to Split BE', async () => {
fetchMock.getOnce(SERVER_MOCK_URL + '/splitChanges?s=1.1&since=1619720346272', { status: 200, body: responseMocks.splitChanges[3] });
fetchMock.getOnce(SERVER_MOCK_URL + '/segmentChanges/test_maldo?since=1589906133231', { status: 200, body: responseMocks.segmentChanges[3] });
fetchMock.getOnce(SERVER_MOCK_URL + '/segmentChanges/Lucas_Segments_Tests?since=1617053238061', { status: 200, body: responseMocks.segmentChanges[6] });

const _synchronizer = createSynchronizer();

const hasExecute = await _synchronizer.execute();
Expand Down Expand Up @@ -317,6 +347,10 @@ describe('Synchronizer e2e tests - OPTIMIZED impressions mode & Flag Sets filter

describe('Synchronizer runs the first time', () => {
beforeAll(async () => {
fetchMock.getOnce(SERVER_MOCK_URL + '/splitChanges?s=1.1&since=-1&sets=set_b', { status: 200, body: responseMocks.splitChanges[0] });
fetchMock.getOnce(SERVER_MOCK_URL + '/segmentChanges/test_maldo?since=-1', { status: 200, body: responseMocks.segmentChanges[0] });
fetchMock.getOnce(SERVER_MOCK_URL + '/segmentChanges/test_maldo?since=1589906133231', { status: 200, body: responseMocks.segmentChanges[3] });

await _synchronizer.execute();
});

Expand Down Expand Up @@ -368,6 +402,9 @@ describe('Synchronizer e2e tests - OPTIMIZED impressions mode & Flag Sets filter

describe('Synchronizer runs a second time, and', () => {
beforeAll(async () => {
fetchMock.getOnce(SERVER_MOCK_URL + '/splitChanges?s=1.1&since=1619720346271&sets=set_b', { status: 200, body: responseMocks.splitChanges[2] });
fetchMock.getOnce(SERVER_MOCK_URL + '/segmentChanges/test_maldo?since=1589906133231', { status: 200, body: responseMocks.segmentChanges[3] });

await _synchronizer.execute();
});

Expand Down Expand Up @@ -408,45 +445,40 @@ describe('Synchronizer e2e tests - OPTIMIZED impressions mode & Flag Sets filter
});
});

test('Synchronizer runs a 3rd time with same SDK key and filter criteria, but wrong URLs. Execution should fail and storage should not be updated', async () => {
test('Synchronizer runs a 3rd time with same SDK key and filter criteria, but HTTP requests fail. Execution should fail and storage should not be updated', async () => {
const keys = await _redisWrapper.getKeysByPrefix(`${REDIS_PREFIX}.`);

const synchronizer = new Synchronizer({
...settings,
sync: {
// To final filter query after validation is `&sets=set_b`
// Final filter query after validation is `&sets=set_b`
splitFilters: [{
type: 'bySet', values: ['set_b', ' '],
}, {
type: 'byName', values: ['set_b'],
}],
},
urls: {
sdk: SERVER_MOCK_URL + '/invalidpath',
events: SERVER_MOCK_URL + '/invalidpath',
telemetry: SERVER_MOCK_URL + '/invalidpath',
},
});

fetchMock.getOnce(SERVER_MOCK_URL + '/splitChanges?s=1.1&since=1619720346272&sets=set_b', { status: 500 });
fetchMock.getOnce(SERVER_MOCK_URL + '/segmentChanges/test_maldo?since=1589906133231', { status: 200, body: responseMocks.segmentChanges[3] });

expect(await synchronizer.execute()).toBe(false);
expect(await _redisWrapper.getKeysByPrefix(`${REDIS_PREFIX}.`)).toEqual(keys);
});

test('Synchronizer runs a 4th time with a different SDK key and wrong URLs. Execution should fail and storage should be empty, except for storage hash', async () => {
test('Synchronizer runs a 4th time with a different SDK key and HTTP requests fail. Execution should fail and storage should be empty, except for storage hash', async () => {
const keys = await _redisWrapper.getKeysByPrefix(`${REDIS_PREFIX}.`);

const synchronizer = new Synchronizer({
...settings,
core: {
authorizationKey: 'fakeSdkKeyForTesting-2',
},
urls: {
sdk: SERVER_MOCK_URL + '/invalidpath',
events: SERVER_MOCK_URL + '/invalidpath',
telemetry: SERVER_MOCK_URL + '/invalidpath',
},
});

fetchMock.getOnce(SERVER_MOCK_URL + '/splitChanges?s=1.1&since=-1&sets=set_b', { status: 500 });

expect(await synchronizer.execute()).toBe(false);
expect(keys.length).toBeGreaterThan(0);
expect(await _redisWrapper.getKeysByPrefix(`${REDIS_PREFIX}.`)).toEqual([`${REDIS_PREFIX}.hash`]);
Expand All @@ -459,6 +491,13 @@ describe('Synchronizer - only Splits & Segments mode', () => {
let executeImpressionsAndEventsCallSpy: jest.SpyInstance;

beforeAll(async () => {
fetchMock.getOnce(SERVER_MOCK_URL + '/splitChanges?s=1.1&since=-1', { status: 200, body: responseMocks.splitChanges[0] });
fetchMock.getOnce(SERVER_MOCK_URL + '/segmentChanges/test_maldo?since=-1', { status: 200, body: responseMocks.segmentChanges[0] });
fetchMock.getOnce(SERVER_MOCK_URL + '/segmentChanges/Lucas_Segments_Tests?since=-1', { status: 200, body: responseMocks.segmentChanges[2] });
fetchMock.getOnce(SERVER_MOCK_URL + '/segmentChanges/test_maldo?since=1589906133231', { status: 200, body: responseMocks.segmentChanges[3] });
fetchMock.getOnce(SERVER_MOCK_URL + '/segmentChanges/Lucas_Segments_Tests?since=1609943267407', { status: 200, body: responseMocks.segmentChanges[5] });
fetchMock.getOnce(SERVER_MOCK_URL + '/segmentChanges/Lucas_Segments_Tests?since=1617053238061', { status: 200, body: responseMocks.segmentChanges[6] });

_synchronizer = createSynchronizer('MODE_RUN_FEATURE_FLAGS_AND_SEGMENTS'); // @ts-ignore
executeSplitsAndSegmentsCallSpy = jest.spyOn(_synchronizer, 'executeSplitsAndSegments'); // @ts-ignore
executeImpressionsAndEventsCallSpy = jest.spyOn(_synchronizer, 'executeImpressionsAndEvents');
Expand Down
11 changes: 11 additions & 0 deletions e2e/utils/nodeFetchMock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import fetchMock from 'fetch-mock';
import { __setFetch } from '../../src/synchronizers/getFetch';

const sandboxFetchMock = fetchMock.sandbox();

// config the fetch mock to chain routes (appends the new route to the list of routes)
sandboxFetchMock.config.overwriteRoutes = false;

__setFetch(sandboxFetchMock);

export default sandboxFetchMock;
File renamed without changes.
Loading