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
12 changes: 10 additions & 2 deletions .jest/setEnvVars.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ process.env.SPLIT_EVALUATOR_ENVIRONMENTS = `[
{"API_KEY":"apikey1","AUTH_TOKEN":"key_blue"},
{"API_KEY":"apikey2","AUTH_TOKEN":"key_red"},
{"API_KEY":"apikey3","AUTH_TOKEN":"key_green","FLAG_SET_FILTER":"set_green"},
{"API_KEY":"apikey4","AUTH_TOKEN":"key_purple","FLAG_SET_FILTER":"set_purple"}
{"API_KEY":"apikey4","AUTH_TOKEN":"key_purple","FLAG_SET_FILTER":"set_purple"},
{"API_KEY":"apikey5","AUTH_TOKEN":"key_pink","FLAG_SET_FILTER":"set_green,set_purple"}
]`;

// Before all tests, sdk module is mocked to create a wrapper where a different yaml file is assigned to each environment
Expand Down Expand Up @@ -39,6 +40,13 @@ jest.mock('../sdk', () => ({
...settings.core,
authorizationKey: authorizationKey,
},
urls: {
sdk: 'https://sdk.test.io/api',
events: 'https://events.test.io/api',
auth: 'https://auth.test.io/api',
streaming: 'https://streaming.test.io',
telemetry: 'https://telemetry.test.io/api',
},
startup: {
readyTimeout: 1,
},
Expand All @@ -53,7 +61,7 @@ jest.mock('../sdk', () => ({
};

let sdk = jest.requireActual('../sdk');
const { factory, telemetry, impressionsMode } = sdk.getSplitFactory(configForMock);
const { factory, impressionsMode } = sdk.getSplitFactory(configForMock);

const mockedTelemetry = {
splits: {
Expand Down
1 change: 1 addition & 0 deletions admin/__tests__/stats.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ describe('stats', () => {
const authToken = environment.AUTH_TOKEN;
const apiKey = environment.API_KEY;
const mock = apiKeyMocksMap[apiKey];
if (!mock) return;
expect(stats.environments[utils.obfuscate(authToken)]).toEqual({
splitCount: mock.splitNames.length,
segmentCount: mock.segments.length,
Expand Down
343 changes: 343 additions & 0 deletions client/__tests__/treatmentsByFlagSets.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,343 @@
const request = require('supertest');
const app = require('../../app');
const { expectError, expectErrorContaining, expectOkMultipleResults, getLongKey } = require('../../utils/testWrapper');

jest.mock('node-fetch', () => {
return jest.fn().mockImplementation((url) => {

const sdkUrl = 'https://sdk.test.io/api/splitChanges?since=-1';
const splitChange2 = require('../../utils/mocks/splitchanges.since.-1.till.1602796638344.json');
if (url.startsWith(sdkUrl)) return Promise.resolve({ status: 200, json: () => (splitChange2), ok: true });

return Promise.resolve({ status: 200, json: () => ({}), ok: true });
});
});

describe('get-treatments-by-sets', () => {

beforeEach(() => {
jest.resetModules();
jest.clearAllMocks();
});

afterAll(() => {
// Unmock fetch
jest.unmock('node-fetch');
});

// Testing authorization
test('should be 401 if auth is not passed', async (done) => {
const response = await request(app)
.get('/client/get-treatments-by-sets?key=test&set-names=my-experiment');
expectError(response, 401, 'Unauthorized');
done();
});

test('should be 401 if auth does not match', async (done) => {
const response = await request(app)
.get('/client/get-treatments-by-sets?key=test&set-names=my-experiment')
.set('Authorization', 'invalid');
expectError(response, 401, 'Unauthorized');
done();
});

// Testing Input Validation.
// The following tests are going to check null parameters, wrong types or lengths.
test('should be 400 if key is not passed', async (done) => {
const expected = [
'you passed a null or undefined key, key must be a non-empty string.'
];
const response = await request(app)
.get('/client/get-treatments-by-sets?set-names=test')
.set('Authorization', 'key_green');
expectErrorContaining(response, 400, expected);
done();
});

test('should be 400 if key is empty', async (done) => {
const expected = [
'you passed an empty string, key must be a non-empty string.'
];
const response = await request(app)
.get('/client/get-treatments-by-sets?key=&set-names=test')
.set('Authorization', 'key_green');
expectErrorContaining(response, 400, expected);
done();
});

test('should be 400 if key is empty trimmed', async (done) => {
const expected = [
'you passed an empty string, key must be a non-empty string.'
];
const response = await request(app)
.get('/client/get-treatments-by-sets?key= &set-names=test')
.set('Authorization', 'key_green');
expectErrorContaining(response, 400, expected);
done();
});

test('should be 400 if key is too long', async (done) => {
const expected = [
'key too long, key must be 250 characters or less.'
];
let key = '';
for (let i = 0; i <=250; i++) {
key += 'a';
}
const response = await request(app)
.get(`/client/get-treatments-by-sets?key=${key}&set-names=test`)
.set('Authorization', 'key_green');
expectErrorContaining(response, 400, expected);
done();
});

test('should be 400 if bucketing-key is empty', async (done) => {
const expected = [
'you passed an empty string, bucketing-key must be a non-empty string.'
];
const response = await request(app)
.get('/client/get-treatments-by-sets?key=key&bucketing-key=&set-names=test')
.set('Authorization', 'key_green');
expectErrorContaining(response, 400, expected);
done();
});

test('should be 400 if bucketing-key is empty trimmed', async (done) => {
const expected = [
'you passed an empty string, bucketing-key must be a non-empty string.'
];
const response = await request(app)
.get('/client/get-treatments-by-sets?key=key&bucketing-key= &set-names=test')
.set('Authorization', 'key_green');
expectErrorContaining(response, 400, expected);
done();
});

test('should be 400 if bucketing-key is too long', async (done) => {
const expected = [
'bucketing-key too long, bucketing-key must be 250 characters or less.'
];
let key = '';
for (let i = 0; i <=250; i++) {
key += 'a';
}
const response = await request(app)
.get(`/client/get-treatments-by-sets?key=key&bucketing-key=${key}&set-names=test`)
.set('Authorization', 'key_green');
expectErrorContaining(response, 400, expected);
done();
});

test('should be 400 if set-names is not passed', async (done) => {
const expected = [
'you passed a null or undefined set-names, set-names must be a non-empty array.'
];
const response = await request(app)
.get('/client/get-treatments-by-sets?key=test')
.set('Authorization', 'key_green');
expectErrorContaining(response, 400, expected);
done();
});

test('should be 400 if set-names is empty', async (done) => {
const expected = [
'you passed an empty set-names, set-names must be a non-empty array.'
];
const response = await request(app)
.get('/client/get-treatments-by-sets?key=test&set-names=')
.set('Authorization', 'key_green');
expectErrorContaining(response, 400, expected);
done();
});

test('should be 400 if set-names is empty trimmed', async (done) => {
const expected = [
'you passed an empty set-names, set-names must be a non-empty array.'
];
const response = await request(app)
.get('/client/get-treatments-by-sets?key=test&set-names= ')
.set('Authorization', 'key_green');
expectErrorContaining(response, 400, expected);
done();
});

test('should be 400 if there are errors in key and set-names', async (done) => {
const expected = [
'you passed an empty string, key must be a non-empty string.',
'you passed an empty set-names, set-names must be a non-empty array.'
];
const response = await request(app)
.get('/client/get-treatments-by-sets?key=&set-names= ')
.set('Authorization', 'key_green');
expectErrorContaining(response, 400, expected);
done();
});

test('should be 400 if attributes is invalid', async (done) => {
const expected = [
'attributes must be a plain object.'
];
const response = await request(app)
.get('/client/get-treatments-by-sets?key=test&set-names=my-experiment&attributes=lalala')
.set('Authorization', 'key_green');
expectErrorContaining(response, 400, expected);
done();
});

test('should be 400 if there are multiple errors', async (done) => {
const expected = [
'you passed an empty string, key must be a non-empty string.',
'you passed an empty set-names, set-names must be a non-empty array.',
'attributes must be a plain object.'
];
const response = await request(app)
.get('/client/get-treatments-by-sets?key= &set-names=&attributes="lalala"')
.set('Authorization', 'key_green');
expectErrorContaining(response, 400, expected);
done();
});

test('should be 400 if there are multiple errors in every input', async (done) => {
const expected = [
'you passed an empty string, key must be a non-empty string.',
'you passed an empty set-names, set-names must be a non-empty array.',
'attributes must be a plain object.',
'bucketing-key too long, bucketing-key must be 250 characters or less.'
];
const key = getLongKey();
const response = await request(app)
.get(`/client/get-treatments-by-sets?bucketing-key=${key}&key= &set-names=&attributes="lalala"`)
.set('Authorization', 'key_green');
expectErrorContaining(response, 400, expected);
done();
});

test('should be 400 if attributes is an invalid json (POST)', async (done) => {
const response = await request(app)
.post('/client/get-treatments-by-sets?key=test&set-name=my-experiment')
.set('Content-Type', 'application/json')
// eslint-disable-next-line no-useless-escape
.send('\|\\\"/regex/i') // Syntax error parsing the JSON.
.set('Authorization', 'key_green');
expectError(response, 400);
expect(response.body.error.type).toBe('entity.parse.failed'); // validate the error
done();
});

const expectedGreenResults = {
'test_green': {
treatment: 'on',
},
'test_color': {
treatment: 'on',
},
'test_green_config': {
treatment: 'on',
config: undefined,
},
};
const expectedPurpleResults = {
'test_purple': {
treatment: 'on',
},
'test_color': {
treatment: 'on',
},
'test_purple_config': {
treatment: 'on',
config: undefined,
},
};
const expectedPinkResults = {
'test_purple': {
treatment: 'on',
},
'test_green': {
treatment: 'on',
},
'test_color': {
treatment: 'on',
},
'test_purple_config': {
treatment: 'on',
config: undefined,
},
'test_green_config': {
treatment: 'on',
config: undefined,
},
};

test('should be 200 if is valid attributes (GET)', async (done) => {
const response = await request(app)
.get('/client/get-treatments-by-sets?key=key_green&set-names=set_green&attributes={"test":"test"}')
.set('Authorization', 'key_green');
expectOkMultipleResults(response, 200, expectedGreenResults, 3);
done();
});

test('should be 200 when attributes is null (GET)', async (done) => {
const response = await request(app)
.get('/client/get-treatments-by-sets?key=key_green&set-names=set_green')
.set('Authorization', 'key_green');
expectOkMultipleResults(response, 200, expectedGreenResults, 3);
done();
});

test('should be 200 if is valid attributes (POST)', async (done) => {
const response = await request(app)
.post('/client/get-treatments-by-sets?key=key_green&set-names=set_green')
.set('Authorization', 'key_green')
.send({
attributes: {test:'test'},
});
expectOkMultipleResults(response, 200, expectedGreenResults, 3);
done();
});

test('should be 200 if is valid attributes as string (POST)', async (done) => {
const response = await request(app)
.post('/client/get-treatments-by-sets?key=key_green&set-names=set_green')
.send(JSON.stringify({
attributes: {test:'test'},
}))
.set('Authorization', 'key_green');
expectOkMultipleResults(response, 200, expectedGreenResults, 3);
done();
});

test('should be 200 if attributes is null (POST)', async (done) => {
const response = await request(app)
.post('/client/get-treatments-by-sets?key=key_green&set-names=set_green')
.send({
attributes: null,
})
.set('Authorization', 'key_green');
expectOkMultipleResults(response, 200, expectedGreenResults, 3);
done();
});

test('should be 200 with multiple evaluation but evualuate configured flag sets', async (done) => {
const response = await request(app)
.get('/client/get-treatments-by-sets?key=key_green&set-names=set_green,set_purple,nonexistant-experiment')
.set('Authorization', 'key_green');
expectOkMultipleResults(response, 200, expectedGreenResults, 3);
done();
});

test('should be 200 with multiple evaluation but evualuate configured flag sets', async (done) => {
const response = await request(app)
.get('/client/get-treatments-by-sets?key=key_purple&set-names=set_green,set_purple,nonexistant-experiment')
.set('Authorization', 'key_purple');
expectOkMultipleResults(response, 200, expectedPurpleResults, 3);
done();
});

test('should be 200 with multiple evaluation but evualuate configured flag sets', async (done) => {
const response = await request(app)
.get('/client/get-treatments-by-sets?key=key_purple&set-names=set_green,set_purple,nonexistant-experiment')
.set('Authorization', 'key_pink');
expectOkMultipleResults(response, 200, expectedPinkResults, 5);
done();
});
});
Loading