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
5 changes: 4 additions & 1 deletion .github/workflows/unstable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@ jobs:
- name: Create build version
run: echo "BUILD_VERSION=$(cat package.json | grep version | head -1 | awk '{ print $2 }' | sed 's/[\",]//g' | tr -d '[[:space:]]')" >> $GITHUB_ENV

- name: Get short hash
run: echo "SHORT_SHA=$(git rev-parse --short HEAD)" >> $GITHUB_ENV

- name: Docker Build
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: splitio-docker-dev.jfrog.io/${{ github.event.repository.name }}:${{ env.BUILD_VERSION}}
tags: splitio-docker-dev.jfrog.io/${{ github.event.repository.name }}:${{ env.SHORT_SHA}}
18 changes: 16 additions & 2 deletions .jest/setEnvVars.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
// Environments for testing
process.env.SPLIT_EVALUATOR_ENVIRONMENTS='[{"API_KEY":"localhost","AUTH_TOKEN":"test"},{"API_KEY":"apikey1","AUTH_TOKEN":"key_blue"},{"API_KEY":"apikey2","AUTH_TOKEN":"key_red"}]'
process.env.SPLIT_EVALUATOR_ENVIRONMENTS = `[
{"API_KEY":"localhost","AUTH_TOKEN":"test"},
{"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":"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
// sdk factory mock to set a different yaml for each apikey and localhost mode
Expand Down Expand Up @@ -33,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 @@ -47,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
301 changes: 301 additions & 0 deletions client/__tests__/treatmentsByFlagSets.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,301 @@
const request = require('supertest');
const app = require('../../app');
const { expectError, expectErrorContaining, expectOkMultipleResults, getLongKey } = require('../../utils/testWrapper');
const { NULL_FLAG_SETS, EMPTY_FLAG_SETS } = require('../../utils/constants');
const { expectedGreenResults, expectedPurpleResults, expectedPinkResults } = require('../../utils/mocks');

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&flag-sets=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&flag-sets=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?flag-sets=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=&flag-sets=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= &flag-sets=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}&flag-sets=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=&flag-sets=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= &flag-sets=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}&flag-sets=test`)
.set('Authorization', 'key_green');
expectErrorContaining(response, 400, expected);
done();
});

test('should be 400 if flag-sets is not passed', async (done) => {
const expected = [
NULL_FLAG_SETS
];
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 flag-sets is empty', async (done) => {
const expected = [
EMPTY_FLAG_SETS
];
const response = await request(app)
.get('/client/get-treatments-by-sets?key=test&flag-sets=')
.set('Authorization', 'key_green');
expectErrorContaining(response, 400, expected);
done();
});

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

test('should be 400 if there are errors in key and flag-sets', async (done) => {
const expected = [
'you passed an empty string, key must be a non-empty string.',
EMPTY_FLAG_SETS
];
const response = await request(app)
.get('/client/get-treatments-by-sets?key=&flag-sets= ')
.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&flag-sets=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.',
EMPTY_FLAG_SETS,
'attributes must be a plain object.'
];
const response = await request(app)
.get('/client/get-treatments-by-sets?key= &flag-sets=&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.',
EMPTY_FLAG_SETS,
'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= &flag-sets=&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&flag-sets=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();
});

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&flag-sets=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&flag-sets=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&flag-sets=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&flag-sets=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&flag-sets=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&flag-sets=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&flag-sets=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&flag-sets=set_green,set_purple,nonexistant-experiment')
.set('Authorization', 'key_pink');
expectOkMultipleResults(response, 200, expectedPinkResults, 5);
done();
});
});
Loading