Skip to content

Commit e44c426

Browse files
author
Artem
committed
#RI-4489 ITests
1 parent a81e288 commit e44c426

File tree

11 files changed

+358
-2
lines changed

11 files changed

+358
-2
lines changed

redisinsight/api/config/test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,19 @@ export default {
33
env: 'test',
44
requestTimeout: 1000,
55
},
6+
db: {
7+
synchronize: process.env.DB_SYNC ? process.env.DB_SYNC === 'true' : true,
8+
migrationsRun: process.env.DB_MIGRATIONS ? process.env.DB_MIGRATIONS === 'true' : false,
9+
},
610
profiler: {
711
logFileIdleThreshold: parseInt(process.env.PROFILER_LOG_FILE_IDLE_THRESHOLD, 10) || 1000 * 2, // 3sec
812
},
913
notifications: {
1014
updateUrl: 'https://s3.amazonaws.com/redisinsight.test/public/tests/notifications.json',
1115
},
16+
features_config: {
17+
url: process.env.RI_FEATURES_CONFIG_URL
18+
// eslint-disable-next-line max-len
19+
|| 'http://localhost:5551/remote/features-config.json',
20+
},
1221
};

redisinsight/api/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand -w 1",
3232
"test:e2e": "jest --config ./test/jest-e2e.json -w 1",
3333
"typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js -d ./config/ormconfig.ts",
34-
"test:api": "ts-mocha --paths -p test/api/api.tsconfig.json --config ./test/api/.mocharc.yml",
34+
"test:api": "cross-env NODE_ENV=test ts-mocha --paths -p test/api/api.tsconfig.json --config ./test/api/.mocharc.yml",
3535
"test:api:cov": "nyc --reporter=html --reporter=text --reporter=text-summary yarn run test:api",
3636
"test:api:ci:cov": "nyc -r text -r text-summary -r html yarn run test:api --reporter mocha-multi-reporters --reporter-options configFile=test/api/reporters.json && nyc merge .nyc_output ./coverage/test-run-coverage.json",
3737
"typeorm:migrate": "cross-env NODE_ENV=staging yarn typeorm migration:generate ./migration/migration",

redisinsight/api/test/api/deps.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as chai from 'chai';
77
import * as localDb from '../helpers/local-db';
88
import { constants } from '../helpers/constants';
99
import { getServer, getSocket } from '../helpers/server';
10+
import { initRemoteServer } from '../helpers/remote-server';
1011
import { testEnv } from '../helpers/test';
1112
import * as redis from '../helpers/redis';
1213
import { initCloudDatabase } from '../helpers/cloud';
@@ -23,6 +24,8 @@ export async function depsInit () {
2324
// initialize analytics module
2425
deps.analytics = await getAnalytics();
2526

27+
await initRemoteServer();
28+
2629
// initializing backend server
2730
deps.server = await getServer();
2831

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
import {
2+
expect,
3+
describe,
4+
deps,
5+
getMainCheckFn, fsExtra, before
6+
} from '../deps';
7+
import { constants } from '../../helpers/constants';
8+
import * as defaultConfig from '../../../config/features-config.json';
9+
import { getRepository, initSettings, repositories } from '../../helpers/local-db';
10+
const { getSocket, server, request } = deps;
11+
12+
// endpoint to test
13+
const endpoint = () => request(server).get('/features');
14+
const syncEndpoint = () => request(server).post('/features/sync');
15+
const updateSettings = (data) => request(server).patch('/settings').send(data);
16+
17+
const mainCheckFn = getMainCheckFn(endpoint);
18+
19+
20+
const waitForFlags = async (flags: any) => {
21+
const client = await getSocket('');
22+
23+
await new Promise((res, rej) => {
24+
client.once('features', (data) => {
25+
expect(flags).to.deep.eq(data);
26+
res(true);
27+
})
28+
setTimeout(() => {
29+
rej(new Error('no flags received in 10s'));
30+
}, 10000);
31+
});
32+
};
33+
34+
let featureConfigRepository;
35+
let featureRepository;
36+
describe('GET /features', () => {
37+
before(async () => {
38+
await initSettings();
39+
featureConfigRepository = await getRepository(repositories.FEATURES_CONFIG);
40+
featureRepository = await getRepository(repositories.FEATURE);
41+
});
42+
43+
[
44+
{
45+
name: 'Should return false flag since no range was defined',
46+
before: async () => {
47+
await fsExtra.writeFile(constants.TEST_FEATURE_FLAG_REMOTE_CONFIG_PATH, JSON.stringify({
48+
version: defaultConfig.version + 1,
49+
features: {
50+
insightsRecommendations: {
51+
perc: [],
52+
flag: true,
53+
}
54+
},
55+
})).catch(console.error);
56+
57+
// remove all configs
58+
await featureConfigRepository.delete({});
59+
await syncEndpoint();
60+
await waitForFlags({
61+
features: {
62+
insightsRecommendations: {
63+
flag: false,
64+
},
65+
},
66+
});
67+
},
68+
statusCode: 200,
69+
responseBody: {
70+
features: {
71+
insightsRecommendations: {
72+
flag: false,
73+
}
74+
}
75+
}
76+
},
77+
{
78+
name: 'Should return true since controlNumber is inside range',
79+
before: async () => {
80+
const [config, empty] = await featureConfigRepository.find();
81+
expect(empty).to.eq(undefined);
82+
83+
await fsExtra.writeFile(constants.TEST_FEATURE_FLAG_REMOTE_CONFIG_PATH, JSON.stringify({
84+
version: defaultConfig.version + 2,
85+
features: {
86+
insightsRecommendations: {
87+
perc: [[config.controlNumber - 1, config.controlNumber + 1]],
88+
flag: true,
89+
}
90+
},
91+
})).catch(console.error);
92+
93+
// remove all configs
94+
95+
await syncEndpoint();
96+
await waitForFlags({
97+
features: {
98+
insightsRecommendations: {
99+
flag: true,
100+
},
101+
},
102+
});
103+
},
104+
statusCode: 200,
105+
responseBody: {
106+
features: {
107+
insightsRecommendations: {
108+
flag: true,
109+
}
110+
}
111+
}
112+
},
113+
{
114+
name: 'Should return true since controlNumber is inside range and filters are match (analytics=true)',
115+
before: async () => {
116+
const [config, empty] = await featureConfigRepository.find();
117+
expect(empty).to.eq(undefined);
118+
119+
await fsExtra.writeFile(constants.TEST_FEATURE_FLAG_REMOTE_CONFIG_PATH, JSON.stringify({
120+
version: JSON.parse(config.data).version + 1,
121+
features: {
122+
insightsRecommendations: {
123+
perc: [[config.controlNumber - 1, config.controlNumber + 1]],
124+
flag: true,
125+
filters: [{
126+
name: 'agreements.analytics',
127+
value: true,
128+
cond: 'eq',
129+
}],
130+
}
131+
},
132+
})).catch(console.error);
133+
134+
await syncEndpoint();
135+
await waitForFlags({
136+
features: {
137+
insightsRecommendations: {
138+
flag: true,
139+
},
140+
},
141+
});
142+
},
143+
statusCode: 200,
144+
responseBody: {
145+
features: {
146+
insightsRecommendations: {
147+
flag: true,
148+
}
149+
}
150+
}
151+
},
152+
{
153+
name: 'Should return false since analytics disabled (triggered by settings change)',
154+
before: async () => {
155+
await new Promise((res, rej) => {
156+
waitForFlags({
157+
features: {
158+
insightsRecommendations: {
159+
flag: false,
160+
},
161+
},
162+
}).then(res).catch(rej);
163+
164+
updateSettings({
165+
agreements: {
166+
analytics: false,
167+
},
168+
}).catch(rej);
169+
});
170+
},
171+
statusCode: 200,
172+
responseBody: {
173+
features: {
174+
insightsRecommendations: {
175+
flag: false,
176+
}
177+
}
178+
}
179+
},
180+
].map(mainCheckFn);
181+
});
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import {
2+
expect,
3+
before,
4+
describe,
5+
deps,
6+
fsExtra,
7+
getMainCheckFn,
8+
} from '../deps';
9+
import { constants } from '../../helpers/constants';
10+
import * as defaultConfig from '../../../config/features-config.json';
11+
import { getRepository, repositories } from '../../helpers/local-db';
12+
13+
const { server, request } = deps;
14+
15+
// endpoint to test
16+
const endpoint = () => request(server).post('/features/sync');
17+
18+
const mainCheckFn = getMainCheckFn(endpoint);
19+
20+
let featureConfigRepository;
21+
let featureRepository;
22+
describe('POST /features/sync', () => {
23+
before(async () => {
24+
featureConfigRepository = await getRepository(repositories.FEATURES_CONFIG);
25+
featureRepository = await getRepository(repositories.FEATURE);
26+
});
27+
28+
[
29+
{
30+
name: 'Should sync with default config when db:null and remote:fail',
31+
before: async () => {
32+
// remove remote config so BE will get an error during fetching
33+
await fsExtra.remove(constants.TEST_FEATURE_FLAG_REMOTE_CONFIG_PATH).catch(console.error);
34+
// remove all configs
35+
await featureConfigRepository.delete({});
36+
37+
const [config] = await featureConfigRepository.find();
38+
expect(config).to.eq(undefined);
39+
},
40+
statusCode: 200,
41+
checkFn: async () => {
42+
const [config, empty] = await featureConfigRepository.find();
43+
44+
expect(empty).to.eq(undefined);
45+
expect(config.controlNumber).to.gte(0).lt(100);
46+
expect(config.data).to.eq(JSON.stringify(defaultConfig));
47+
}
48+
},
49+
{
50+
name: 'Should sync with default config when db:version < default.version and remote:fail',
51+
before: async () => {
52+
await fsExtra.remove(constants.TEST_FEATURE_FLAG_REMOTE_CONFIG_PATH).catch(console.error);
53+
await featureConfigRepository.update({}, {
54+
data: JSON.stringify({
55+
...defaultConfig,
56+
version: defaultConfig.version - 0.1,
57+
}),
58+
});
59+
60+
const [config, empty] = await featureConfigRepository.find();
61+
62+
expect(empty).to.eq(undefined);
63+
expect(config.data).to.eq(JSON.stringify({
64+
...defaultConfig,
65+
version: defaultConfig.version - 0.1,
66+
}));
67+
},
68+
statusCode: 200,
69+
checkFn: async () => {
70+
const [config, empty] = await featureConfigRepository.find();
71+
72+
expect(empty).to.eq(undefined);
73+
expect(config.controlNumber).to.gte(0).lt(100);
74+
expect(config.data).to.eq(JSON.stringify(defaultConfig));
75+
}
76+
},
77+
{
78+
name: 'Should sync with remote config when db:null and remote:version > default.version',
79+
before: async () => {
80+
await fsExtra.writeFile(constants.TEST_FEATURE_FLAG_REMOTE_CONFIG_PATH, JSON.stringify({
81+
...defaultConfig,
82+
version: defaultConfig.version + 3.33,
83+
})).catch(console.error);
84+
85+
// remove all configs
86+
await featureConfigRepository.delete({});
87+
88+
const [config] = await featureConfigRepository.find();
89+
90+
expect(config).to.eq(undefined);
91+
},
92+
statusCode: 200,
93+
checkFn: async () => {
94+
const [config, empty] = await featureConfigRepository.find();
95+
96+
expect(empty).to.eq(undefined);
97+
expect(config.controlNumber).to.gte(0).lt(100);
98+
expect(config.data).to.eq(JSON.stringify({
99+
...defaultConfig,
100+
version: defaultConfig.version + 3.33,
101+
}));
102+
}
103+
},
104+
{
105+
name: 'Should sync with remote config when db:version < default and remote:version > default',
106+
before: async () => {
107+
await fsExtra.writeFile(constants.TEST_FEATURE_FLAG_REMOTE_CONFIG_PATH, JSON.stringify({
108+
...defaultConfig,
109+
version: defaultConfig.version + 1.11,
110+
})).catch(console.error);
111+
// remove all configs
112+
await featureConfigRepository.update({}, {
113+
data: JSON.stringify({
114+
...defaultConfig,
115+
version: defaultConfig.version - 0.1,
116+
}),
117+
});
118+
119+
const [config, empty] = await featureConfigRepository.find();
120+
121+
expect(empty).to.eq(undefined);
122+
expect(config.data).to.eq(JSON.stringify({
123+
...defaultConfig,
124+
version: defaultConfig.version - 0.1,
125+
}));
126+
},
127+
statusCode: 200,
128+
checkFn: async () => {
129+
const [config, empty] = await featureConfigRepository.find();
130+
131+
expect(empty).to.eq(undefined);
132+
expect(config.controlNumber).to.gte(0).lt(100);
133+
expect(config.data).to.eq(JSON.stringify({
134+
...defaultConfig,
135+
version: defaultConfig.version + 1.11,
136+
}));
137+
}
138+
},
139+
].map(mainCheckFn);
140+
});

redisinsight/api/test/api/info/GET-info.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ const responseSchema = Joi.object().keys({
2020
appType: Joi.string().valid('ELECTRON', 'DOCKER', 'REDIS_STACK_WEB', 'UNKNOWN').required(),
2121
encryptionStrategies: Joi.array().items(Joi.string()),
2222
sessionId: Joi.number().required(),
23+
controlNumber: Joi.number().required(),
24+
controlGroup: Joi.string().required(),
2325
}).required();
2426

2527
const mainCheckFn = async (testCase) => {

redisinsight/api/test/helpers/constants.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ export const constants = {
4141
TEST_KEYTAR_PASSWORD: process.env.SECRET_STORAGE_PASSWORD || 'somepassword',
4242
TEST_ENCRYPTION_STRATEGY: 'KEYTAR',
4343
TEST_AGREEMENTS_VERSION: '1.0.3',
44+
TEST_REMOTE_STATIC_PATH: './remote',
45+
TEST_REMOTE_STATIC_URI: '/remote',
46+
TEST_FEATURE_FLAG_REMOTE_CONFIG_PATH: './remote/features-config.json',
4447

4548
// local database
4649
TEST_LOCAL_DB_FILE_PATH: process.env.TEST_LOCAL_DB_FILE_PATH || './redisinsight.db',

0 commit comments

Comments
 (0)