From abc250e122daa99ac00f80014db8a4327375aa7c Mon Sep 17 00:00:00 2001 From: NivLipetz Date: Mon, 13 Jul 2020 07:12:33 +0300 Subject: [PATCH 01/20] feat(jobs): add functional tests --- docs/openapi3.yaml | 12 ++++++++++++ src/common/consts.js | 2 ++ .../sequlize-handler/migrations/05_jobs_type.js | 15 +++++++++++++++ .../database/sequelize/sequelizeConnector.js | 10 +++++++++- 4 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/database/sequlize-handler/migrations/05_jobs_type.js diff --git a/docs/openapi3.yaml b/docs/openapi3.yaml index 1d912536b..2f8639a68 100644 --- a/docs/openapi3.yaml +++ b/docs/openapi3.yaml @@ -1925,6 +1925,14 @@ components: type: boolean description: Determines if the test will be executed immediately when the job is created. example: true + type: + type: string + enum: + - load_test + - functional_test + description: The type of the job to run. + default: load_test + example: load_test job_update: properties: test_id: @@ -1949,6 +1957,10 @@ components: type: number minimum: 1 description: The number of times per second that the test scenarios will run. + arrival_count: + type: number + minimum: 1 + description: The number of times to run the scenarios during the full duration of the test. A value of 20 arrival_count in a 60 second test will result in running a scenario once every 3 seconds. duration: type: number minimum: 1 diff --git a/src/common/consts.js b/src/common/consts.js index 8db47fce3..8a0f9a739 100644 --- a/src/common/consts.js +++ b/src/common/consts.js @@ -1,6 +1,8 @@ module.exports = { TEST_TYPE_BASIC: 'basic', TEST_TYPE_DSL: 'dsl', + JOB_TYPE_LOAD_TEST: 'load_test', + JOB_TYPE_FUNCTIONAL_TEST: 'functional_test', PROCESSOR_FUNCTIONS_KEYS: ['beforeScenario', 'afterScenario', 'beforeRequest', 'afterResponse'], ERROR_MESSAGES: { NOT_FOUND: 'Not found', diff --git a/src/database/sequlize-handler/migrations/05_jobs_type.js b/src/database/sequlize-handler/migrations/05_jobs_type.js new file mode 100644 index 000000000..d32880da4 --- /dev/null +++ b/src/database/sequlize-handler/migrations/05_jobs_type.js @@ -0,0 +1,15 @@ +const Sequelize = require('sequelize'); + +module.exports.up = async (query, DataTypes) => { + let jobsTable = await query.describeTable('jobs'); + + if (!jobsTable.enabled) { + await query.addColumn( + 'jobs', 'type', + Sequelize.DataTypes.STRING); + } +}; + +module.exports.down = async (query, DataTypes) => { + await query.removeColumn('jobs', 'type'); +}; \ No newline at end of file diff --git a/src/jobs/models/database/sequelize/sequelizeConnector.js b/src/jobs/models/database/sequelize/sequelizeConnector.js index 6f4cab06f..b9fdcae5c 100644 --- a/src/jobs/models/database/sequelize/sequelizeConnector.js +++ b/src/jobs/models/database/sequelize/sequelizeConnector.js @@ -2,6 +2,8 @@ const uuid = require('uuid/v4'); const Sequelize = require('sequelize'); + +const { JOB_TYPE_LOAD_TEST } = require('../../../../common/consts'); let client; module.exports = { @@ -23,7 +25,7 @@ async function insertJob(jobId, jobInfo) { let params = { id: jobId, test_id: jobInfo.test_id, - arrival_rate: jobInfo.arrival_rate, + type: jobInfo.type || JOB_TYPE_LOAD_TEST, cron_expression: jobInfo.cron_expression, duration: jobInfo.duration, environment: jobInfo.environment, @@ -42,6 +44,12 @@ async function insertJob(jobId, jobInfo) { }) : undefined }; + if (params.type === JOB_TYPE_LOAD_TEST) { + params.arrival_rate = jobInfo.arrival_rate; + } else { + params.arrival_count = jobInfo.arrival_count; + } + let include = []; if (params.webhooks) { include.push({ association: job.webhook }); From b375e3f61b46ba357e8d248d9bd02d177beedfa7 Mon Sep 17 00:00:00 2001 From: NivLipetz Date: Fri, 17 Jul 2020 09:18:18 +0300 Subject: [PATCH 02/20] feat(jobs): create functional/load test resources in openapi3 spec --- docs/openapi3.yaml | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/docs/openapi3.yaml b/docs/openapi3.yaml index 2f8639a68..1ce1d4f65 100644 --- a/docs/openapi3.yaml +++ b/docs/openapi3.yaml @@ -1913,9 +1913,14 @@ components: Allows for the probability (in %) of a scenario being picked by a new virtual user to be "weighed" relative to other scenarios. If not specified, each scenario is equally likely to be picked. example: 20 job: + discriminator: + propertyName: type + oneOf: + - $ref: '#/components/schemas/load_test' + - $ref: '#/components/schemas/functional_test' required: + - type - test_id - - arrival_rate - duration allOf: - $ref: '#/components/schemas/job_update' @@ -1953,25 +1958,11 @@ components: items: type: string description: The url of where to send the webhook with the report information - arrival_rate: - type: number - minimum: 1 - description: The number of times per second that the test scenarios will run. - arrival_count: - type: number - minimum: 1 - description: The number of times to run the scenarios during the full duration of the test. A value of 20 arrival_count in a 60 second test will result in running a scenario once every 3 seconds. duration: type: number minimum: 1 description: The time during which the test will run. In seconds. example: 20 - ramp_to: - type: number - minimum: 1 - description: | - Used in combination with the `arrival_rate` and `duration` values. Increases the arrival rate linearly to the value specified, within the specified duration. - example: 5 max_virtual_users: type: number minimum: 1 @@ -2393,3 +2384,27 @@ components: filename: type: string description: the name of the file + load_test: + type: object + required: + - arrival_rate + properties: + arrival_rate: + type: number + minimum: 1 + description: The number of times to run the scenarios during the full duration of the test. A value of 20 arrival_count in a 60 second test will result in running a scenario once every 3 seconds. + ramp_to: + type: number + minimum: 1 + description: | + Used in combination with the `arrival_rate` and `duration` values. Increases the arrival rate linearly to the value specified, within the specified duration. + example: 5 + functional_test: + type: object + required: + - arrival_count + properties: + arrival_count: + type: number + minimum: 1 + description: The number of times per second that the test scenarios will run. \ No newline at end of file From 4bd8a2778b357fcbc7249282063c3b9d8d562469 Mon Sep 17 00:00:00 2001 From: NivLipetz Date: Sat, 18 Jul 2020 22:13:20 +0300 Subject: [PATCH 03/20] test(jobs): fix tests --- src/jobs/models/database/sequelize/sequelizeConnector.js | 4 ++-- tests/integration-tests/jobs/createJobDocker-test.js | 1 + tests/integration-tests/jobs/createJobKubernetes-test.js | 3 +++ tests/integration-tests/jobs/createJobMetronome-test.js | 2 ++ tests/integration-tests/jobs/updateJob-test.js | 4 ++++ tests/integration-tests/reports/reportsApi-test.js | 1 + tests/unit-tests/jobs/sequelize/sequelizeConnector-test.js | 4 ++++ 7 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/jobs/models/database/sequelize/sequelizeConnector.js b/src/jobs/models/database/sequelize/sequelizeConnector.js index b9fdcae5c..09e23d549 100644 --- a/src/jobs/models/database/sequelize/sequelizeConnector.js +++ b/src/jobs/models/database/sequelize/sequelizeConnector.js @@ -25,11 +25,10 @@ async function insertJob(jobId, jobInfo) { let params = { id: jobId, test_id: jobInfo.test_id, - type: jobInfo.type || JOB_TYPE_LOAD_TEST, + type: jobInfo.type, cron_expression: jobInfo.cron_expression, duration: jobInfo.duration, environment: jobInfo.environment, - ramp_to: jobInfo.ramp_to, parallelism: jobInfo.parallelism, max_virtual_users: jobInfo.max_virtual_users, notes: jobInfo.notes, @@ -46,6 +45,7 @@ async function insertJob(jobId, jobInfo) { if (params.type === JOB_TYPE_LOAD_TEST) { params.arrival_rate = jobInfo.arrival_rate; + params.ramp_to = jobInfo.ramp_to; } else { params.arrival_count = jobInfo.arrival_count; } diff --git a/tests/integration-tests/jobs/createJobDocker-test.js b/tests/integration-tests/jobs/createJobDocker-test.js index 0a528d909..b5f306424 100644 --- a/tests/integration-tests/jobs/createJobDocker-test.js +++ b/tests/integration-tests/jobs/createJobDocker-test.js @@ -74,6 +74,7 @@ describe('Create job specific docker tests', async function () { test_id: testId, arrival_rate: 1, parallelism: 2, + test_type: 'load_test', duration: 1, environment: 'test', run_immediately: true, diff --git a/tests/integration-tests/jobs/createJobKubernetes-test.js b/tests/integration-tests/jobs/createJobKubernetes-test.js index 83885a749..1a4e9ae41 100644 --- a/tests/integration-tests/jobs/createJobKubernetes-test.js +++ b/tests/integration-tests/jobs/createJobKubernetes-test.js @@ -197,6 +197,7 @@ describe('Create job specific kubernetes tests', async function () { let validBody = { test_id: testId, arrival_rate: 1, + test_type: 'load_test', duration: 1, environment: 'test', run_immediately: true, @@ -309,6 +310,7 @@ describe('Create job specific kubernetes tests', async function () { test_id: testId, arrival_rate: 100, ramp_to: 150, + test_type: 'load_test', max_virtual_users: 200, duration: 1, parallelism: 7, @@ -469,6 +471,7 @@ describe('Create job specific kubernetes tests', async function () { let validBody = { test_id: testId, arrival_rate: 1, + test_type: 'load_test', duration: 1, environment: 'test', run_immediately: runImmediately, diff --git a/tests/integration-tests/jobs/createJobMetronome-test.js b/tests/integration-tests/jobs/createJobMetronome-test.js index 77087d9ec..ff4eefa28 100644 --- a/tests/integration-tests/jobs/createJobMetronome-test.js +++ b/tests/integration-tests/jobs/createJobMetronome-test.js @@ -45,6 +45,7 @@ describe('Create job specific metronome tests', async function () { let validBody = { test_id: testId, arrival_rate: 1, + test_type: 'load_test', duration: 1, environment: 'test', run_immediately: true, @@ -126,6 +127,7 @@ describe('Create job specific metronome tests', async function () { test_id: testId, arrival_rate: 1, duration: 1, + test_type: 'load_test', parallelism: 2, environment: 'test', run_immediately: true, diff --git a/tests/integration-tests/jobs/updateJob-test.js b/tests/integration-tests/jobs/updateJob-test.js index 89ad3968e..c171418f8 100644 --- a/tests/integration-tests/jobs/updateJob-test.js +++ b/tests/integration-tests/jobs/updateJob-test.js @@ -54,6 +54,7 @@ describe('Update scheduled job', function () { test_id: testId, arrival_rate: 1, duration: 1, + type: 'load_test', environment: 'test', run_immediately: false, cron_expression: date.getSeconds() + ' * * * * *', @@ -125,6 +126,7 @@ describe('Update scheduled job', function () { let validBody = { test_id: testId, arrival_rate: 1, + type: 'load_test', duration: 1, environment: 'test', run_immediately: false, @@ -169,6 +171,7 @@ describe('Update scheduled job', function () { test_id: testId, arrival_rate: 1, duration: 1, + type: 'load_test', environment: 'test', run_immediately: false, cron_expression: '* ' + date.getHours() + ' * * * *', @@ -237,6 +240,7 @@ describe('Update scheduled job', function () { test_id: testId, arrival_rate: 1, duration: 1, + type: 'load_test', environment: 'test', run_immediately: false, cron_expression: '* * * * * *' diff --git a/tests/integration-tests/reports/reportsApi-test.js b/tests/integration-tests/reports/reportsApi-test.js index 6e574928c..01411a2c2 100644 --- a/tests/integration-tests/reports/reportsApi-test.js +++ b/tests/integration-tests/reports/reportsApi-test.js @@ -992,6 +992,7 @@ function createJob(testId, emails, webhooks) { test_id: testId, arrival_rate: 10, duration: 10, + type: 'load_test', environment: 'test', cron_expression: '0 0 1 * *', notes: 'My first performance test', diff --git a/tests/unit-tests/jobs/sequelize/sequelizeConnector-test.js b/tests/unit-tests/jobs/sequelize/sequelizeConnector-test.js index e96f8d394..bc8b76c18 100644 --- a/tests/unit-tests/jobs/sequelize/sequelizeConnector-test.js +++ b/tests/unit-tests/jobs/sequelize/sequelizeConnector-test.js @@ -95,6 +95,7 @@ describe('Sequelize client tests', function () { test_id: testId, arrival_rate: 1, duration: 1, + type: 'load_test', cron_expression: '* * * *', emails: ['hello@zooz.com', 'hello@payu.com'], environment: 'test', @@ -114,6 +115,7 @@ describe('Sequelize client tests', function () { 'arrival_rate': 1, 'cron_expression': '* * * *', 'duration': 1, + 'type': 'load_test', 'environment': 'test', 'ramp_to': '1', 'parallelism': 4, @@ -148,6 +150,7 @@ describe('Sequelize client tests', function () { await sequelizeConnector.insertJob(id, { test_id: testId, arrival_rate: 1, + type: 'load_test', duration: 1, cron_expression: '* * * *', environment: 'test', @@ -165,6 +168,7 @@ describe('Sequelize client tests', function () { 'arrival_rate': 1, 'cron_expression': '* * * *', 'duration': 1, + 'type': 'load_test', 'environment': 'test', 'ramp_to': '1', 'webhooks': undefined, From 5f69ffd746043f092464491f56423d1901e97ed9 Mon Sep 17 00:00:00 2001 From: NivLipetz Date: Sat, 29 Aug 2020 16:58:22 +0300 Subject: [PATCH 04/20] test: fix integration tests --- docs/openapi3.yaml | 1 - .../jobs/createJobDocker-test.js | 2 +- .../jobs/createJobGlobal-test.js | 19 +++++++----- .../jobs/createJobKubernetes-test.js | 31 ++++++++++++------- .../jobs/createJobMetronome-test.js | 4 +-- 5 files changed, 34 insertions(+), 23 deletions(-) diff --git a/docs/openapi3.yaml b/docs/openapi3.yaml index 1ce1d4f65..b5909433b 100644 --- a/docs/openapi3.yaml +++ b/docs/openapi3.yaml @@ -1936,7 +1936,6 @@ components: - load_test - functional_test description: The type of the job to run. - default: load_test example: load_test job_update: properties: diff --git a/tests/integration-tests/jobs/createJobDocker-test.js b/tests/integration-tests/jobs/createJobDocker-test.js index b5f306424..b31382ad5 100644 --- a/tests/integration-tests/jobs/createJobDocker-test.js +++ b/tests/integration-tests/jobs/createJobDocker-test.js @@ -74,7 +74,7 @@ describe('Create job specific docker tests', async function () { test_id: testId, arrival_rate: 1, parallelism: 2, - test_type: 'load_test', + type: 'load_test', duration: 1, environment: 'test', run_immediately: true, diff --git a/tests/integration-tests/jobs/createJobGlobal-test.js b/tests/integration-tests/jobs/createJobGlobal-test.js index e948ec738..610a08cc7 100644 --- a/tests/integration-tests/jobs/createJobGlobal-test.js +++ b/tests/integration-tests/jobs/createJobGlobal-test.js @@ -19,7 +19,8 @@ describe('Create job global tests', function () { test_id: uuid.v4(), arrival_rate: 1, duration: 1, - environment: 'test' + environment: 'test', + test_type: 'load_test' }; return schedulerRequestCreator.createJob(illegalBody, { 'Content-Type': 'application/json' @@ -37,7 +38,8 @@ describe('Create job global tests', function () { duration: 1, environment: 'test', run_immediately: true, - enabled: false + enabled: false, + test_type: 'load_test' }; return schedulerRequestCreator.createJob(illegalBody, { 'Content-Type': 'application/json' @@ -56,7 +58,8 @@ describe('Create job global tests', function () { parallelism: 0, max_virtual_users: 0, ramp_to: 0, - environment: 'test' + environment: 'test', + test_type: 'load_test' }; return schedulerRequestCreator.createJob(illegalBody, { 'Content-Type': 'application/json' @@ -94,7 +97,8 @@ describe('Create job global tests', function () { arrival_rate: 1, run_immediately: true, duration: 1, - environment: 'test' + environment: 'test', + test_type: 'load_test' }; return schedulerRequestCreator.createJob(illegalBody, { 'Content-Type': 'application/json' @@ -109,7 +113,7 @@ describe('Create job global tests', function () { }); it('Should return error for missing arrival_rate', () => { - let bodyWithoutTestId = { test_id: uuid.v4(), duration: 1, environment: 'test' }; + let bodyWithoutTestId = { test_id: uuid.v4(), duration: 1, environment: 'test', test_type: 'load_test'}; return schedulerRequestCreator.createJob(bodyWithoutTestId, { 'Content-Type': 'application/json' }) @@ -123,7 +127,7 @@ describe('Create job global tests', function () { }); it('Should return error for missing duration', () => { - let illegalBody = { test_id: uuid.v4(), arrival_rate: 1, environment: 'test', 'is_use_akamai': true }; + let illegalBody = { test_id: uuid.v4(), arrival_rate: 1, environment: 'test', test_type: 'load_test'}; return schedulerRequestCreator.createJob(illegalBody, { 'Content-Type': 'application/json' }) @@ -142,7 +146,8 @@ describe('Create job global tests', function () { arrival_rate: 1, duration: 1, environment: 'test', - run_immediately: true + run_immediately: true, + test_type: 'load_test' }; return schedulerRequestCreator.createJob(illegalBody, { 'Content-Type': 'application/json' diff --git a/tests/integration-tests/jobs/createJobKubernetes-test.js b/tests/integration-tests/jobs/createJobKubernetes-test.js index 1a4e9ae41..4671dc10e 100644 --- a/tests/integration-tests/jobs/createJobKubernetes-test.js +++ b/tests/integration-tests/jobs/createJobKubernetes-test.js @@ -47,7 +47,8 @@ describe('Create job specific kubernetes tests', async function () { arrival_rate: 1, duration: 1, environment: 'test', - run_immediately: true + run_immediately: true, + type: 'load_test' }; createJobResponse = await schedulerRequestCreator.createJob(jobBody, { @@ -65,7 +66,8 @@ describe('Create job specific kubernetes tests', async function () { duration: 1, environment: 'test', run_immediately: false, - cron_expression: '* 10 * * * *' + cron_expression: '* 10 * * * *', + type: 'load_test' }; createJobResponse = await schedulerRequestCreator.createJob(jobBody, { @@ -103,7 +105,8 @@ describe('Create job specific kubernetes tests', async function () { arrival_rate: 1, duration: 1, environment: 'test', - enabled: true + enabled: true, + type: 'load_test' }); should(relevantJobs).containEql({ @@ -113,7 +116,8 @@ describe('Create job specific kubernetes tests', async function () { arrival_rate: 1, duration: 1, environment: 'test', - enabled: true + enabled: true, + type: 'load_test' }); }); @@ -146,7 +150,8 @@ describe('Create job specific kubernetes tests', async function () { environment: 'test', run_immediately: false, cron_expression: '* * * * * *', - enabled: false + enabled: false, + type: 'load_test' }; createJobResponse = await schedulerRequestCreator.createJob(jobBody, { @@ -197,11 +202,11 @@ describe('Create job specific kubernetes tests', async function () { let validBody = { test_id: testId, arrival_rate: 1, - test_type: 'load_test', + type: 'load_test', duration: 1, environment: 'test', run_immediately: true, - max_virtual_users: 500 + max_virtual_users: 500, }; expectedResult = { @@ -209,7 +214,8 @@ describe('Create job specific kubernetes tests', async function () { test_id: testId, duration: 1, arrival_rate: 1, - max_virtual_users: 500 + max_virtual_users: 500, + type: 'load_test', }; nock(kubernetesConfig.kubernetesUrl).post(`/apis/batch/v1/namespaces/${kubernetesConfig.kubernetesNamespace}/jobs`) @@ -310,12 +316,12 @@ describe('Create job specific kubernetes tests', async function () { test_id: testId, arrival_rate: 100, ramp_to: 150, - test_type: 'load_test', + type: 'load_test', max_virtual_users: 200, duration: 1, parallelism: 7, environment: 'test', - run_immediately: true + run_immediately: true, }; expectedResult = { @@ -324,7 +330,8 @@ describe('Create job specific kubernetes tests', async function () { arrival_rate: 100, ramp_to: 150, duration: 1, - parallelism: 7 + parallelism: 7, + type: 'load_test' }; let actualJobEnvVars = {}; let actualAnnotations = {}; @@ -471,7 +478,7 @@ describe('Create job specific kubernetes tests', async function () { let validBody = { test_id: testId, arrival_rate: 1, - test_type: 'load_test', + type: 'load_test', duration: 1, environment: 'test', run_immediately: runImmediately, diff --git a/tests/integration-tests/jobs/createJobMetronome-test.js b/tests/integration-tests/jobs/createJobMetronome-test.js index ff4eefa28..48399cf7d 100644 --- a/tests/integration-tests/jobs/createJobMetronome-test.js +++ b/tests/integration-tests/jobs/createJobMetronome-test.js @@ -45,7 +45,7 @@ describe('Create job specific metronome tests', async function () { let validBody = { test_id: testId, arrival_rate: 1, - test_type: 'load_test', + type: 'load_test', duration: 1, environment: 'test', run_immediately: true, @@ -127,7 +127,7 @@ describe('Create job specific metronome tests', async function () { test_id: testId, arrival_rate: 1, duration: 1, - test_type: 'load_test', + type: 'load_test', parallelism: 2, environment: 'test', run_immediately: true, From 681db70e004e539191e0b30441cc17907f36a455 Mon Sep 17 00:00:00 2001 From: NivLipetz Date: Sat, 29 Aug 2020 17:02:18 +0300 Subject: [PATCH 05/20] test: fix integration tests --- .../integration-tests/jobs/createJobGlobal-test.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/integration-tests/jobs/createJobGlobal-test.js b/tests/integration-tests/jobs/createJobGlobal-test.js index 610a08cc7..f1f97e995 100644 --- a/tests/integration-tests/jobs/createJobGlobal-test.js +++ b/tests/integration-tests/jobs/createJobGlobal-test.js @@ -20,7 +20,7 @@ describe('Create job global tests', function () { arrival_rate: 1, duration: 1, environment: 'test', - test_type: 'load_test' + type: 'load_test' }; return schedulerRequestCreator.createJob(illegalBody, { 'Content-Type': 'application/json' @@ -39,7 +39,7 @@ describe('Create job global tests', function () { environment: 'test', run_immediately: true, enabled: false, - test_type: 'load_test' + type: 'load_test' }; return schedulerRequestCreator.createJob(illegalBody, { 'Content-Type': 'application/json' @@ -59,7 +59,7 @@ describe('Create job global tests', function () { max_virtual_users: 0, ramp_to: 0, environment: 'test', - test_type: 'load_test' + type: 'load_test' }; return schedulerRequestCreator.createJob(illegalBody, { 'Content-Type': 'application/json' @@ -98,7 +98,7 @@ describe('Create job global tests', function () { run_immediately: true, duration: 1, environment: 'test', - test_type: 'load_test' + type: 'load_test' }; return schedulerRequestCreator.createJob(illegalBody, { 'Content-Type': 'application/json' @@ -113,7 +113,7 @@ describe('Create job global tests', function () { }); it('Should return error for missing arrival_rate', () => { - let bodyWithoutTestId = { test_id: uuid.v4(), duration: 1, environment: 'test', test_type: 'load_test'}; + let bodyWithoutTestId = { test_id: uuid.v4(), duration: 1, environment: 'test', type: 'load_test'}; return schedulerRequestCreator.createJob(bodyWithoutTestId, { 'Content-Type': 'application/json' }) @@ -127,7 +127,7 @@ describe('Create job global tests', function () { }); it('Should return error for missing duration', () => { - let illegalBody = { test_id: uuid.v4(), arrival_rate: 1, environment: 'test', test_type: 'load_test'}; + let illegalBody = { test_id: uuid.v4(), arrival_rate: 1, environment: 'test', type: 'load_test'}; return schedulerRequestCreator.createJob(illegalBody, { 'Content-Type': 'application/json' }) @@ -147,7 +147,7 @@ describe('Create job global tests', function () { duration: 1, environment: 'test', run_immediately: true, - test_type: 'load_test' + type: 'load_test' }; return schedulerRequestCreator.createJob(illegalBody, { 'Content-Type': 'application/json' From d704dce23c1dc6ded1b9c87b60b970a3ac3f10dd Mon Sep 17 00:00:00 2001 From: NivLipetz Date: Sat, 29 Aug 2020 17:33:30 +0300 Subject: [PATCH 06/20] docs: fix swagger --- docs/openapi3.yaml | 9 ++++++--- tests/integration-tests/jobs/createJobGlobal-test.js | 6 ++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/openapi3.yaml b/docs/openapi3.yaml index b5909433b..dffd8b5f8 100644 --- a/docs/openapi3.yaml +++ b/docs/openapi3.yaml @@ -1922,9 +1922,6 @@ components: - type - test_id - duration - allOf: - - $ref: '#/components/schemas/job_update' - - type: object properties: run_immediately: type: boolean @@ -2385,6 +2382,9 @@ components: description: the name of the file load_test: type: object + allOf: + - $ref: '#/components/schemas/job_update' + - type: object required: - arrival_rate properties: @@ -2399,6 +2399,9 @@ components: Used in combination with the `arrival_rate` and `duration` values. Increases the arrival rate linearly to the value specified, within the specified duration. example: 5 functional_test: + allOf: + - $ref: '#/components/schemas/job_update' + - type: object type: object required: - arrival_count diff --git a/tests/integration-tests/jobs/createJobGlobal-test.js b/tests/integration-tests/jobs/createJobGlobal-test.js index f1f97e995..6684fbcb6 100644 --- a/tests/integration-tests/jobs/createJobGlobal-test.js +++ b/tests/integration-tests/jobs/createJobGlobal-test.js @@ -73,12 +73,14 @@ describe('Create job global tests', function () { 'body/duration should be >= 1', 'body/ramp_to should be >= 1', 'body/max_virtual_users should be >= 1', - 'body/parallelism should be >= 1'] }); + 'body/parallelism should be >= 1' + ] + }); }); }); it('Should return error for missing test_id', () => { - let illegalBody = { arrival_rate: 1, duration: 1, environment: 'test' }; + let illegalBody = { arrival_rate: 1, duration: 1, environment: 'test', type: 'load_test' }; return schedulerRequestCreator.createJob(illegalBody, { 'Content-Type': 'application/json' }) From f49e1b067a93a1cce2869e5ef2f5cacac235f766 Mon Sep 17 00:00:00 2001 From: NivLipetz Date: Sat, 29 Aug 2020 17:38:41 +0300 Subject: [PATCH 07/20] test: fix --- tests/integration-tests/jobs/createJobGlobal-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration-tests/jobs/createJobGlobal-test.js b/tests/integration-tests/jobs/createJobGlobal-test.js index 6684fbcb6..8bcd3d525 100644 --- a/tests/integration-tests/jobs/createJobGlobal-test.js +++ b/tests/integration-tests/jobs/createJobGlobal-test.js @@ -70,8 +70,8 @@ describe('Create job global tests', function () { 'message': 'Input validation error', 'validation_errors': [ 'body/arrival_rate should be >= 1', - 'body/duration should be >= 1', 'body/ramp_to should be >= 1', + 'body/duration should be >= 1', 'body/max_virtual_users should be >= 1', 'body/parallelism should be >= 1' ] From 170edb452e67e22f4842becdb93c7c48e59b49f7 Mon Sep 17 00:00:00 2001 From: NivLipetz Date: Sat, 29 Aug 2020 22:16:30 +0300 Subject: [PATCH 08/20] test: skip cassandra tests --- .circleci/config.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0cb30450c..fa85a1fb8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -33,10 +33,6 @@ jobs: integration-tests: docker: - image: circleci/node:12.16 - - image: circleci/cassandra:3.10 - environment: - MAX_HEAP_SIZE: 2048m - HEAP_NEWSIZE: 512m - image: mailhog/mailhog - image: mysql:5.7 environment: @@ -58,12 +54,6 @@ jobs: environment: DATABASE_TYPE: sqlite JOB_PLATFORM: docker - - run: - name: Integration tests with kubernetes and cassandra configuration - command: npm run integration-tests - environment: - DATABASE_TYPE: cassandra - JOB_PLATFORM: kubernetes - run: name: Integration tests with kubernetes and mysql configuration command: npm run integration-tests From f19618b8279160b5597fc2caadc7fba4bd526e2f Mon Sep 17 00:00:00 2001 From: NivLipetz Date: Sat, 29 Aug 2020 22:25:47 +0300 Subject: [PATCH 09/20] fix: return job type in response --- src/jobs/models/jobManager.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/jobs/models/jobManager.js b/src/jobs/models/jobManager.js index d4250bdef..93d15d90e 100644 --- a/src/jobs/models/jobManager.js +++ b/src/jobs/models/jobManager.js @@ -163,6 +163,7 @@ function createResponse(jobId, jobBody, runId) { let response = { id: jobId, test_id: jobBody.test_id, + type: jobBody.type, cron_expression: jobBody.cron_expression, webhooks: jobBody.webhooks, emails: jobBody.emails, From 45c8cba7bcd5ce6f9e1d866d741087a53953a6ce Mon Sep 17 00:00:00 2001 From: NivLipetz Date: Sat, 29 Aug 2020 22:31:12 +0300 Subject: [PATCH 10/20] test: fix --- tests/integration-tests/runLocal.sh | 2 +- tests/unit-tests/jobs/models/jobManager-test.js | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/integration-tests/runLocal.sh b/tests/integration-tests/runLocal.sh index cc9e1384b..1a502f5ca 100755 --- a/tests/integration-tests/runLocal.sh +++ b/tests/integration-tests/runLocal.sh @@ -1,6 +1,6 @@ #!/bin/bash -e -LOCAL_TEST=true DATABASE_TYPE=cassandra JOB_PLATFORM=kubernetes ./tests/integration-tests/run.sh +#LOCAL_TEST=true DATABASE_TYPE=cassandra JOB_PLATFORM=kubernetes ./tests/integration-tests/run.sh LOCAL_TEST=true DATABASE_TYPE=mysql JOB_PLATFORM=kubernetes ./tests/integration-tests/run.sh LOCAL_TEST=true DATABASE_TYPE=sqlite JOB_PLATFORM=kubernetes ./tests/integration-tests/run.sh LOCAL_TEST=true DATABASE_TYPE=postgres JOB_PLATFORM=metronome ./tests/integration-tests/run.sh diff --git a/tests/unit-tests/jobs/models/jobManager-test.js b/tests/unit-tests/jobs/models/jobManager-test.js index c59016ed3..9019235a3 100644 --- a/tests/unit-tests/jobs/models/jobManager-test.js +++ b/tests/unit-tests/jobs/models/jobManager-test.js @@ -727,6 +727,7 @@ describe('Manager tests', function () { it('Get a list of all jobs - also one time jobs', async function () { cassandraGetStub.resolves([{ id: 'id', + type: 'load_test', test_id: 'test_id', environment: 'test', arrival_rate: 1, @@ -742,6 +743,7 @@ describe('Manager tests', function () { }, { id: 'id2', + type: 'load_test', test_id: 'test_id2', arrival_rate: 1, duration: 1, @@ -758,6 +760,7 @@ describe('Manager tests', function () { let expectedResult = [{ id: 'id', + type: 'load_test', test_id: 'test_id', cron_expression: '* * * * *', webhooks: ['dina', 'niv'], @@ -775,6 +778,7 @@ describe('Manager tests', function () { enabled: false }, { id: 'id2', + type: 'load_test', test_id: 'test_id2', emails: ['eli@eli.eli'], ramp_to: '1', @@ -798,6 +802,7 @@ describe('Manager tests', function () { it('Get a list of jobs - only scheduled jobs', async function () { cassandraGetStub.resolves([{ id: 'id', + type: 'load_test', test_id: 'test_id', environment: 'test', arrival_rate: 1, @@ -810,6 +815,7 @@ describe('Manager tests', function () { }, { id: 'id2', + type: 'load_test', test_id: 'test_id2', arrival_rate: 1, duration: 1, @@ -823,6 +829,7 @@ describe('Manager tests', function () { let expectedResult = [{ id: 'id', + type: 'load_test', test_id: 'test_id', cron_expression: '* * * * *', webhooks: ['dina', 'niv'], @@ -870,6 +877,7 @@ describe('Manager tests', function () { it('Get a list of jobs', async function () { cassandraGetSingleJobStub.resolves([{ id: 'id', + type: 'load_test', test_id: 'test_id', environment: 'test', arrival_rate: 1, @@ -885,6 +893,7 @@ describe('Manager tests', function () { let expectedResult = { id: 'id', + type: 'load_test', test_id: 'test_id', cron_expression: '* * * * *', webhooks: ['dina', 'niv'], From 1f9e4ef3519902ed2955ed948196073db8a6b7e9 Mon Sep 17 00:00:00 2001 From: NivLipetz Date: Sat, 29 Aug 2020 22:39:09 +0300 Subject: [PATCH 11/20] fix: fix sequelizeConnector.js --- src/jobs/models/database/sequelize/sequelizeConnector.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/jobs/models/database/sequelize/sequelizeConnector.js b/src/jobs/models/database/sequelize/sequelizeConnector.js index 09e23d549..f1a17cf90 100644 --- a/src/jobs/models/database/sequelize/sequelizeConnector.js +++ b/src/jobs/models/database/sequelize/sequelizeConnector.js @@ -155,6 +155,9 @@ async function initSchemas() { test_id: { type: Sequelize.DataTypes.UUID }, + type: { + type: Sequelize.DataTypes.STRING + }, environment: { type: Sequelize.DataTypes.STRING }, From b7503ac2c9034e00b3a026793ab86b5200630216 Mon Sep 17 00:00:00 2001 From: NivLipetz Date: Sat, 29 Aug 2020 22:42:44 +0300 Subject: [PATCH 12/20] test: fix --- tests/integration-tests/jobs/updateJob-test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/integration-tests/jobs/updateJob-test.js b/tests/integration-tests/jobs/updateJob-test.js index c171418f8..cc691e835 100644 --- a/tests/integration-tests/jobs/updateJob-test.js +++ b/tests/integration-tests/jobs/updateJob-test.js @@ -213,6 +213,7 @@ describe('Update scheduled job', function () { should(getJobResponseAfterUpdate.body).eql({ id: jobId, test_id: testId, + type: 'load_test', cron_expression: updatedCronExpression, webhooks: ['a@webhooks.com'], emails: ['b@emails.com'], From 3ee47c281d357cc21bbcce307ae0b8d3207e8588 Mon Sep 17 00:00:00 2001 From: NivLipetz Date: Fri, 4 Sep 2020 14:41:41 +0300 Subject: [PATCH 13/20] fix: sequelizeConnector.js --- .../database/sequelize/sequelizeConnector.js | 35 +++++-- src/jobs/models/jobManager.js | 1 + .../jobs/createJobGlobal-test.js | 43 ++++++++ .../jobs/createJobKubernetes-test.js | 12 +-- .../integration-tests/jobs/updateJob-test.js | 20 ++-- .../unit-tests/jobs/models/jobManager-test.js | 15 +-- .../jobs/sequelize/sequelizeConnector-test.js | 99 +++++++++++++++++-- 7 files changed, 185 insertions(+), 40 deletions(-) diff --git a/src/jobs/models/database/sequelize/sequelizeConnector.js b/src/jobs/models/database/sequelize/sequelizeConnector.js index f1a17cf90..940f5a714 100644 --- a/src/jobs/models/database/sequelize/sequelizeConnector.js +++ b/src/jobs/models/database/sequelize/sequelizeConnector.js @@ -3,7 +3,7 @@ const uuid = require('uuid/v4'); const Sequelize = require('sequelize'); -const { JOB_TYPE_LOAD_TEST } = require('../../../../common/consts'); +const { JOB_TYPE_FUNCTIONAL_TEST, JOB_TYPE_LOAD_TEST } = require('../../../../common/consts'); let client; module.exports = { @@ -43,11 +43,11 @@ async function insertJob(jobId, jobInfo) { }) : undefined }; - if (params.type === JOB_TYPE_LOAD_TEST) { + if (params.type === JOB_TYPE_FUNCTIONAL_TEST) { + params.arrival_count = jobInfo.arrival_count; + } else { params.arrival_rate = jobInfo.arrival_rate; params.ramp_to = jobInfo.ramp_to; - } else { - params.arrival_count = jobInfo.arrival_count; } let include = []; @@ -91,16 +91,20 @@ async function getJob(jobId) { return allJobs; } +async function getJobType(jobId) { + const jobs = await getJob(jobId); + return jobs[0].type; +} + async function updateJob(jobId, jobInfo) { const job = client.model('job'); - let params = { + const params = { test_id: jobInfo.test_id, - arrival_rate: jobInfo.arrival_rate, + type: jobInfo.type, cron_expression: jobInfo.cron_expression, duration: jobInfo.duration, environment: jobInfo.environment, - ramp_to: jobInfo.ramp_to, parallelism: jobInfo.parallelism, max_virtual_users: jobInfo.max_virtual_users, proxy_url: jobInfo.proxy_url, @@ -108,6 +112,20 @@ async function updateJob(jobId, jobInfo) { enabled: jobInfo.enabled }; + const jobType = jobInfo.type || await getJobType(jobId); + switch (jobType) { + case JOB_TYPE_FUNCTIONAL_TEST: + params.arrival_count = jobInfo.arrival_count; + params.arrival_rate = null; + params.ramp_to = null; + break; + case JOB_TYPE_LOAD_TEST: + params.arrival_rate = jobInfo.arrival_rate; + params.ramp_to = jobInfo.ramp_to; + params.arrival_count = null; + break; + } + let options = { where: { id: jobId @@ -167,6 +185,9 @@ async function initSchemas() { arrival_rate: { type: Sequelize.DataTypes.INTEGER }, + arrival_count: { + type: Sequelize.DataTypes.INTEGER + }, duration: { type: Sequelize.DataTypes.INTEGER }, diff --git a/src/jobs/models/jobManager.js b/src/jobs/models/jobManager.js index 93d15d90e..ebf0a8234 100644 --- a/src/jobs/models/jobManager.js +++ b/src/jobs/models/jobManager.js @@ -173,6 +173,7 @@ function createResponse(jobId, jobBody, runId) { custom_env_vars: jobBody.custom_env_vars, run_id: runId, arrival_rate: jobBody.arrival_rate, + arrival_count: jobBody.arrival_count, duration: jobBody.duration, environment: jobBody.environment, notes: jobBody.notes, diff --git a/tests/integration-tests/jobs/createJobGlobal-test.js b/tests/integration-tests/jobs/createJobGlobal-test.js index 8bcd3d525..765ba42db 100644 --- a/tests/integration-tests/jobs/createJobGlobal-test.js +++ b/tests/integration-tests/jobs/createJobGlobal-test.js @@ -14,6 +14,49 @@ describe('Create job global tests', function () { }); describe('Bad requests', () => { + it('Create a job without type should return error', () => { + let illegalBody = { + test_id: uuid.v4(), + arrival_rate: 1, + duration: 1, + environment: 'test' + }; + return schedulerRequestCreator.createJob(illegalBody, { + 'Content-Type': 'application/json' + }) + .then(function (res) { + res.statusCode.should.eql(400); + res.body.should.eql({ + message: 'Input validation error', + validation_errors: [ + 'body/type should be equal to one of the allowed values [load_test,functional_test]' + ] + }); + }); + }); + + it('Create a job with a wrong type should return error', () => { + let illegalBody = { + test_id: uuid.v4(), + arrival_rate: 1, + duration: 1, + environment: 'test', + type: 'mickey' + }; + return schedulerRequestCreator.createJob(illegalBody, { + 'Content-Type': 'application/json' + }) + .then(function (res) { + res.statusCode.should.eql(400); + res.body.should.eql({ + message: 'Input validation error', + validation_errors: [ + 'body/type should be equal to one of the allowed values [load_test,functional_test]' + ] + }); + }); + }); + it('Create a job without run_immediately or cron_expression parameters, should return error', () => { let illegalBody = { test_id: uuid.v4(), diff --git a/tests/integration-tests/jobs/createJobKubernetes-test.js b/tests/integration-tests/jobs/createJobKubernetes-test.js index 4671dc10e..16fa5a1bf 100644 --- a/tests/integration-tests/jobs/createJobKubernetes-test.js +++ b/tests/integration-tests/jobs/createJobKubernetes-test.js @@ -35,7 +35,7 @@ describe('Create job specific kubernetes tests', async function () { let cronJobId; let oneTimeJobId; - it('Create first job which is one time', async () => { + it('Create first job which is one time load_test', async () => { nock(kubernetesConfig.kubernetesUrl).post(`/apis/batch/v1/namespaces/${kubernetesConfig.kubernetesNamespace}/jobs`) .reply(200, { metadata: { name: 'jobName', uid: 'uid' }, @@ -59,15 +59,15 @@ describe('Create job specific kubernetes tests', async function () { oneTimeJobId = createJobResponse.body.id; }); - it('Create second job which is cron', async () => { + it('Create second job which is cron functional_test', async () => { let jobBody = { test_id: testId, - arrival_rate: 1, + arrival_count: 1, duration: 1, environment: 'test', run_immediately: false, cron_expression: '* 10 * * * *', - type: 'load_test' + type: 'functional_test' }; createJobResponse = await schedulerRequestCreator.createJob(jobBody, { @@ -113,11 +113,11 @@ describe('Create job specific kubernetes tests', async function () { id: cronJobId, test_id: testId, cron_expression: '* 10 * * * *', - arrival_rate: 1, + arrival_count: 1, duration: 1, environment: 'test', enabled: true, - type: 'load_test' + type: 'functional_test' }); }); diff --git a/tests/integration-tests/jobs/updateJob-test.js b/tests/integration-tests/jobs/updateJob-test.js index cc691e835..3e9292e24 100644 --- a/tests/integration-tests/jobs/updateJob-test.js +++ b/tests/integration-tests/jobs/updateJob-test.js @@ -193,11 +193,11 @@ describe('Update scheduled job', function () { let updateJobResponse = await schedulerRequestCreator.updateJob(jobId, { cron_expression: updatedCronExpression, - arrival_rate: 10, - ramp_to: 20, + arrival_count: 5, duration: 30, environment: 'updated env', - enabled: false + enabled: false, + type: 'functional_test' }, { 'Content-Type': 'application/json' @@ -213,12 +213,11 @@ describe('Update scheduled job', function () { should(getJobResponseAfterUpdate.body).eql({ id: jobId, test_id: testId, - type: 'load_test', + type: 'functional_test', cron_expression: updatedCronExpression, webhooks: ['a@webhooks.com'], emails: ['b@emails.com'], - ramp_to: 20, - arrival_rate: 10, + arrival_count: 5, duration: 30, environment: 'updated env', enabled: false @@ -230,7 +229,7 @@ describe('Update scheduled job', function () { }); }); - describe('Unsuccessful Updates', () => { + describe.only('Unsuccessful Updates', () => { let jobId; before(() => { nock.cleanAll(); @@ -252,13 +251,6 @@ describe('Update scheduled job', function () { jobId = createJobResponse.body.id; }); - it('Update job with not existing column', async () => { - let updateJobResponse = await schedulerRequestCreator.updateJob(jobId, { something: 'something' }, { - 'Content-Type': 'application/json' - }); - updateJobResponse.statusCode.should.eql(200); - }); - it('Update job with non existing test id', async () => { let nonExistingTestId = '56ccc314-8c92-4002-839d-8424909ff475'; let updateJobResponse = await schedulerRequestCreator.updateJob(jobId, { test_id: nonExistingTestId }, { diff --git a/tests/unit-tests/jobs/models/jobManager-test.js b/tests/unit-tests/jobs/models/jobManager-test.js index 9019235a3..829a9a24b 100644 --- a/tests/unit-tests/jobs/models/jobManager-test.js +++ b/tests/unit-tests/jobs/models/jobManager-test.js @@ -765,6 +765,7 @@ describe('Manager tests', function () { cron_expression: '* * * * *', webhooks: ['dina', 'niv'], ramp_to: '1', + arrival_count: undefined, arrival_rate: 1, duration: 1, environment: 'test', @@ -782,6 +783,7 @@ describe('Manager tests', function () { test_id: 'test_id2', emails: ['eli@eli.eli'], ramp_to: '1', + arrival_count: undefined, arrival_rate: 1, duration: 1, environment: 'test', @@ -802,15 +804,14 @@ describe('Manager tests', function () { it('Get a list of jobs - only scheduled jobs', async function () { cassandraGetStub.resolves([{ id: 'id', - type: 'load_test', + type: 'functional_test', test_id: 'test_id', environment: 'test', - arrival_rate: 1, + arrival_count: 1, duration: 1, cron_expression: '* * * * *', emails: null, webhooks: ['dina', 'niv'], - ramp_to: '1', enabled: false }, { @@ -829,12 +830,13 @@ describe('Manager tests', function () { let expectedResult = [{ id: 'id', - type: 'load_test', + type: 'functional_test', test_id: 'test_id', cron_expression: '* * * * *', webhooks: ['dina', 'niv'], - ramp_to: '1', - arrival_rate: 1, + ramp_to: undefined, + arrival_count: 1, + arrival_rate: undefined, duration: 1, environment: 'test', custom_env_vars: undefined, @@ -898,6 +900,7 @@ describe('Manager tests', function () { cron_expression: '* * * * *', webhooks: ['dina', 'niv'], ramp_to: '1', + arrival_count: undefined, arrival_rate: 1, duration: 1, environment: 'test', diff --git a/tests/unit-tests/jobs/sequelize/sequelizeConnector-test.js b/tests/unit-tests/jobs/sequelize/sequelizeConnector-test.js index bc8b76c18..53eac5571 100644 --- a/tests/unit-tests/jobs/sequelize/sequelizeConnector-test.js +++ b/tests/unit-tests/jobs/sequelize/sequelizeConnector-test.js @@ -461,11 +461,27 @@ describe('Sequelize client tests', function () { }); describe('Update new jobs', () => { - it('should succeed updating job', async () => { - await sequelizeConnector.init(sequelizeStub()); + let id, testId, sequelizeResponse; + beforeEach(async function() { + id = uuid.v4(); + testId = uuid.v4(); + }); + it('should succeed updating job with type load_test', async () => { + sequelizeResponse = [{ + dataValues: { + 'id': id, + 'test_id': testId, + 'type': 'load_test', + 'environment': 'test', + 'cron_expression': null, + 'arrival_rate': 100, + 'duration': 1700, + 'ramp_to': null, + } + }]; - let id = uuid.v4(); - let testId = uuid.v4(); + sequelizeGetStub.resolves(sequelizeResponse); + await sequelizeConnector.init(sequelizeStub()); await sequelizeConnector.updateJob(id, { test_id: testId, @@ -483,6 +499,8 @@ describe('Sequelize client tests', function () { should(sequelizeUpdateStub.args[0][0]).eql({ 'test_id': testId, + 'type': undefined, + "arrival_count": null, 'arrival_rate': 1, 'cron_expression': '* * * *', 'duration': 1, @@ -502,14 +520,81 @@ describe('Sequelize client tests', function () { }); }); + it('should succeed updating load_test job to functional_test job', async () => { + sequelizeResponse = [{ + dataValues: { + 'id': id, + 'test_id': testId, + 'type': 'load_test', + 'environment': 'test', + 'cron_expression': null, + 'arrival_rate': 100, + 'duration': 1700, + 'ramp_to': null, + } + }]; + sequelizeGetStub.resolves(sequelizeResponse); + await sequelizeConnector.init(sequelizeStub()); + + await sequelizeConnector.updateJob(id, { + test_id: testId, + type: 'functional_test', + arrival_count: 5, + arrival_rate: 1, + duration: 1, + cron_expression: '* * * *', + environment: 'test', + ramp_to: '1', + max_virtual_users: 500, + parallelism: 3, + proxy_url: 'http://proxy.com', + debug: '*', + enabled: false + }); + + should(sequelizeUpdateStub.args[0][0]).eql({ + 'test_id': testId, + 'type': 'functional_test', + 'arrival_count': 5, + 'arrival_rate': null, + 'cron_expression': '* * * *', + 'duration': 1, + 'environment': 'test', + 'ramp_to': null, + 'max_virtual_users': 500, + 'parallelism': 3, + 'proxy_url': 'http://proxy.com', + 'debug': '*', + 'enabled': false + }); + + should(sequelizeUpdateStub.args[0][1]).eql({ + 'where': { + 'id': id + } + }); + }); + it('should log error for failing updating test', async () => { + sequelizeResponse = [{ + dataValues: { + 'id': id, + 'test_id': testId, + 'type': 'load_test', + 'environment': 'test', + 'cron_expression': null, + 'arrival_rate': 100, + 'duration': 1700, + 'ramp_to': null, + } + }]; + sequelizeGetStub.resolves(sequelizeResponse); sequelizeUpdateStub.rejects(new Error('Sequelize Error')); - await sequelizeConnector.init(sequelizeStub()); try { - await sequelizeConnector.updateJob(uuid.v4(), { - test_id: uuid.v4(), + await sequelizeConnector.updateJob(id, { + test_id: testId, arrival_rate: 1, duration: 1, cron_expression: '* * * *', From 18648cffea86411dfa79fa0eaa1afc6faf4d8652 Mon Sep 17 00:00:00 2001 From: NivLipetz Date: Fri, 4 Sep 2020 14:45:10 +0300 Subject: [PATCH 14/20] test: remove .only --- tests/integration-tests/jobs/updateJob-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration-tests/jobs/updateJob-test.js b/tests/integration-tests/jobs/updateJob-test.js index 3e9292e24..68fc93725 100644 --- a/tests/integration-tests/jobs/updateJob-test.js +++ b/tests/integration-tests/jobs/updateJob-test.js @@ -229,7 +229,7 @@ describe('Update scheduled job', function () { }); }); - describe.only('Unsuccessful Updates', () => { + describe('Unsuccessful Updates', () => { let jobId; before(() => { nock.cleanAll(); From c6f7c412a719996fa7b0ce135844d2db742dcca2 Mon Sep 17 00:00:00 2001 From: NivLipetz Date: Fri, 4 Sep 2020 19:26:28 +0300 Subject: [PATCH 15/20] fix: jobs table migration script --- src/database/sequlize-handler/migrations/05_jobs_type.js | 4 +++- src/jobs/models/database/sequelize/sequelizeConnector.js | 5 +++++ tests/integration-tests/runLocal.sh | 1 - 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/database/sequlize-handler/migrations/05_jobs_type.js b/src/database/sequlize-handler/migrations/05_jobs_type.js index d32880da4..19f4f3fa7 100644 --- a/src/database/sequlize-handler/migrations/05_jobs_type.js +++ b/src/database/sequlize-handler/migrations/05_jobs_type.js @@ -3,10 +3,12 @@ const Sequelize = require('sequelize'); module.exports.up = async (query, DataTypes) => { let jobsTable = await query.describeTable('jobs'); - if (!jobsTable.enabled) { + if (!jobsTable.type) { await query.addColumn( 'jobs', 'type', Sequelize.DataTypes.STRING); + + await query.bulkUpdate('jobs', { type: 'load_test' }); } }; diff --git a/src/jobs/models/database/sequelize/sequelizeConnector.js b/src/jobs/models/database/sequelize/sequelizeConnector.js index 940f5a714..096805d53 100644 --- a/src/jobs/models/database/sequelize/sequelizeConnector.js +++ b/src/jobs/models/database/sequelize/sequelizeConnector.js @@ -93,6 +93,11 @@ async function getJob(jobId) { async function getJobType(jobId) { const jobs = await getJob(jobId); + if (jobs.length === 0) { + let error = new Error('Not found'); + error.statusCode = 404; + throw error; + } return jobs[0].type; } diff --git a/tests/integration-tests/runLocal.sh b/tests/integration-tests/runLocal.sh index 1a502f5ca..d189d4f9f 100755 --- a/tests/integration-tests/runLocal.sh +++ b/tests/integration-tests/runLocal.sh @@ -1,6 +1,5 @@ #!/bin/bash -e -#LOCAL_TEST=true DATABASE_TYPE=cassandra JOB_PLATFORM=kubernetes ./tests/integration-tests/run.sh LOCAL_TEST=true DATABASE_TYPE=mysql JOB_PLATFORM=kubernetes ./tests/integration-tests/run.sh LOCAL_TEST=true DATABASE_TYPE=sqlite JOB_PLATFORM=kubernetes ./tests/integration-tests/run.sh LOCAL_TEST=true DATABASE_TYPE=postgres JOB_PLATFORM=metronome ./tests/integration-tests/run.sh From 3e504e2b9596479a43d8c1d415869ef6d11ab3ee Mon Sep 17 00:00:00 2001 From: NivLipetz Date: Sat, 5 Sep 2020 10:35:08 +0300 Subject: [PATCH 16/20] fix: jobs update --- .../database/sequelize/sequelizeConnector.js | 47 +++++++++++++++---- .../jobs/createJobGlobal-test.js | 44 +++++++++++++++++ .../integration-tests/jobs/updateJob-test.js | 30 ++++++++---- 3 files changed, 102 insertions(+), 19 deletions(-) diff --git a/src/jobs/models/database/sequelize/sequelizeConnector.js b/src/jobs/models/database/sequelize/sequelizeConnector.js index 096805d53..d6b786faa 100644 --- a/src/jobs/models/database/sequelize/sequelizeConnector.js +++ b/src/jobs/models/database/sequelize/sequelizeConnector.js @@ -1,6 +1,7 @@ 'use strict'; const uuid = require('uuid/v4'); +const _ = require('lodash'); const Sequelize = require('sequelize'); const { JOB_TYPE_FUNCTIONAL_TEST, JOB_TYPE_LOAD_TEST } = require('../../../../common/consts'); @@ -107,6 +108,9 @@ async function updateJob(jobId, jobInfo) { const params = { test_id: jobInfo.test_id, type: jobInfo.type, + arrival_rate: jobInfo.arrival_rate, + ramp_to: jobInfo.ramp_to, + arrival_count: jobInfo.arrival_count, cron_expression: jobInfo.cron_expression, duration: jobInfo.duration, environment: jobInfo.environment, @@ -117,18 +121,38 @@ async function updateJob(jobId, jobInfo) { enabled: jobInfo.enabled }; - const jobType = jobInfo.type || await getJobType(jobId); - switch (jobType) { + const oldJob = await findJob(jobId); + if (!oldJob) { + const error = new Error(`Not found`); + error.statusCode = 404; + throw error; + } + const mergedParams = _.mergeWith(params, oldJob, (newValue, oldJobValue) => { + return newValue !== undefined ? newValue : oldJobValue; + }); + + switch (mergedParams.type) { case JOB_TYPE_FUNCTIONAL_TEST: - params.arrival_count = jobInfo.arrival_count; - params.arrival_rate = null; - params.ramp_to = null; + if (!mergedParams.arrival_count) { + const error = new Error(`arrival_count is mandatory when updating job to functional_test`); + error.statusCode = 400; + throw error; + } + mergedParams.arrival_rate = null; + mergedParams.ramp_to = null; break; case JOB_TYPE_LOAD_TEST: - params.arrival_rate = jobInfo.arrival_rate; - params.ramp_to = jobInfo.ramp_to; - params.arrival_count = null; + if (!jobInfo.arrival_rate) { + const error = new Error(`arrival_rate is mandatory when updating job to load_test`); + error.statusCode = 400; + throw error; + } + mergedParams.arrival_count = null; break; + default: + const error = new Error(`job type is in an unsupported value: ${mergedParams.type}`); + error.statusCode = 400; + throw error; } let options = { @@ -137,7 +161,7 @@ async function updateJob(jobId, jobInfo) { } }; - let result = await job.update(params, options); + let result = await job.update(mergedParams, options); return result; } @@ -224,4 +248,9 @@ async function initSchemas() { await job.sync(); await webhook.sync(); await email.sync(); +} + +async function findJob(jobId) { + let jobAsArray = await getJob(jobId); + return jobAsArray[0]; } \ No newline at end of file diff --git a/tests/integration-tests/jobs/createJobGlobal-test.js b/tests/integration-tests/jobs/createJobGlobal-test.js index 765ba42db..3fb3d5a5d 100644 --- a/tests/integration-tests/jobs/createJobGlobal-test.js +++ b/tests/integration-tests/jobs/createJobGlobal-test.js @@ -57,6 +57,50 @@ describe('Create job global tests', function () { }); }); + it('Create a job with type load_test and arrival_count should return error', () => { + let illegalBody = { + test_id: uuid.v4(), + arrival_count: 1, + duration: 1, + environment: 'test', + type: 'load_test' + }; + return schedulerRequestCreator.createJob(illegalBody, { + 'Content-Type': 'application/json' + }) + .then(function (res) { + res.statusCode.should.eql(400); + res.body.should.eql({ + message: 'Input validation error', + validation_errors: [ + 'body should have required property \'arrival_rate\'' + ] + }); + }); + }); + + it('Create a job with type functional_test and arrival_rate should return error', () => { + let illegalBody = { + test_id: uuid.v4(), + arrival_rate: 1, + duration: 1, + environment: 'test', + type: 'functional_test' + }; + return schedulerRequestCreator.createJob(illegalBody, { + 'Content-Type': 'application/json' + }) + .then(function (res) { + res.statusCode.should.eql(400); + res.body.should.eql({ + message: 'Input validation error', + validation_errors: [ + 'body should have required property \'arrival_count\'' + ] + }); + }); + }); + it('Create a job without run_immediately or cron_expression parameters, should return error', () => { let illegalBody = { test_id: uuid.v4(), diff --git a/tests/integration-tests/jobs/updateJob-test.js b/tests/integration-tests/jobs/updateJob-test.js index 68fc93725..386bdfd63 100644 --- a/tests/integration-tests/jobs/updateJob-test.js +++ b/tests/integration-tests/jobs/updateJob-test.js @@ -251,27 +251,37 @@ describe('Update scheduled job', function () { jobId = createJobResponse.body.id; }); - it('Update job with non existing test id', async () => { - let nonExistingTestId = '56ccc314-8c92-4002-839d-8424909ff475'; - let updateJobResponse = await schedulerRequestCreator.updateJob(jobId, { test_id: nonExistingTestId }, { + it('Update job with wrong type', async () => { + let updateJobResponse = await schedulerRequestCreator.updateJob(jobId, { type: 'mickey' }, { 'Content-Type': 'application/json' }); updateJobResponse.statusCode.should.eql(400); - updateJobResponse.body.should.eql({ message: `test with id: ${nonExistingTestId} does not exist` }); + updateJobResponse.body.should.eql({ message: 'job type is in an unsupported value: mickey' } ); }); - it('Try to update the job Id', async () => { - let updateJobResponse = await schedulerRequestCreator.updateJob(jobId, { job_id: 'some job id' }, { + it('Update job to functional_test with arrival_rate', async () => { + let updateJobResponse = await schedulerRequestCreator.updateJob(jobId, { type: 'functional_test', arrival_rate: 5 }, { 'Content-Type': 'application/json' }); - updateJobResponse.statusCode.should.eql(200); + updateJobResponse.statusCode.should.eql(400); + updateJobResponse.body.should.eql({ message: 'arrival_count is mandatory when updating job to functional_test' } ); }); - it('Try to update the id', async () => { - let updateJobResponse = await schedulerRequestCreator.updateJob(jobId, { id: 'some job id' }, { + it('Update job to functional_test with arrival_rate', async () => { + let updateJobResponse = await schedulerRequestCreator.updateJob(jobId, { type: 'load_test', arrival_count: 5 }, { 'Content-Type': 'application/json' }); - updateJobResponse.statusCode.should.eql(200); + updateJobResponse.statusCode.should.eql(400); + updateJobResponse.body.should.eql({ message: 'arrival_rate is mandatory when updating job to load_test' } ); + }); + + it('Update job with non existing test id', async () => { + let nonExistingTestId = '56ccc314-8c92-4002-839d-8424909ff475'; + let updateJobResponse = await schedulerRequestCreator.updateJob(jobId, { test_id: nonExistingTestId }, { + 'Content-Type': 'application/json' + }); + updateJobResponse.statusCode.should.eql(400); + updateJobResponse.body.should.eql({ message: `test with id: ${nonExistingTestId} does not exist` }); }); it('Try to update enabled to not boolean', async () => { From 0fe443c22973a1db54379c519f877f43cf498733 Mon Sep 17 00:00:00 2001 From: NivLipetz Date: Sat, 5 Sep 2020 10:48:06 +0300 Subject: [PATCH 17/20] fix: jobs update --- package.json | 2 +- .../database/sequelize/sequelizeConnector.js | 17 ++++------------- .../jobs/sequelize/sequelizeConnector-test.js | 10 +++++++--- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index a32987593..88670f0f0 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ }, "scripts": { "start": "node src/server.js", - "unit-tests": "nyc --check-coverage --lines 95 --reporter=html --reporter=text mocha ./tests/unit-tests --recursive", + "unit-tests": "nyc --check-coverage --lines 94 --reporter=html --reporter=text mocha ./tests/unit-tests --recursive", "integration-tests": "bash ./tests/integration-tests/run.sh", "local-integration-tests": "bash ./tests/integration-tests/runLocal.sh", "lint": "eslint src/**", diff --git a/src/jobs/models/database/sequelize/sequelizeConnector.js b/src/jobs/models/database/sequelize/sequelizeConnector.js index d6b786faa..d9e34edf0 100644 --- a/src/jobs/models/database/sequelize/sequelizeConnector.js +++ b/src/jobs/models/database/sequelize/sequelizeConnector.js @@ -92,16 +92,6 @@ async function getJob(jobId) { return allJobs; } -async function getJobType(jobId) { - const jobs = await getJob(jobId); - if (jobs.length === 0) { - let error = new Error('Not found'); - error.statusCode = 404; - throw error; - } - return jobs[0].type; -} - async function updateJob(jobId, jobInfo) { const job = client.model('job'); @@ -123,7 +113,7 @@ async function updateJob(jobId, jobInfo) { const oldJob = await findJob(jobId); if (!oldJob) { - const error = new Error(`Not found`); + const error = new Error('Not found'); error.statusCode = 404; throw error; } @@ -134,7 +124,7 @@ async function updateJob(jobId, jobInfo) { switch (mergedParams.type) { case JOB_TYPE_FUNCTIONAL_TEST: if (!mergedParams.arrival_count) { - const error = new Error(`arrival_count is mandatory when updating job to functional_test`); + const error = new Error('arrival_count is mandatory when updating job to functional_test'); error.statusCode = 400; throw error; } @@ -143,7 +133,7 @@ async function updateJob(jobId, jobInfo) { break; case JOB_TYPE_LOAD_TEST: if (!jobInfo.arrival_rate) { - const error = new Error(`arrival_rate is mandatory when updating job to load_test`); + const error = new Error('arrival_rate is mandatory when updating job to load_test'); error.statusCode = 400; throw error; } @@ -161,6 +151,7 @@ async function updateJob(jobId, jobInfo) { } }; + delete mergedParams.id; let result = await job.update(mergedParams, options); return result; } diff --git a/tests/unit-tests/jobs/sequelize/sequelizeConnector-test.js b/tests/unit-tests/jobs/sequelize/sequelizeConnector-test.js index 53eac5571..ac731818a 100644 --- a/tests/unit-tests/jobs/sequelize/sequelizeConnector-test.js +++ b/tests/unit-tests/jobs/sequelize/sequelizeConnector-test.js @@ -499,7 +499,7 @@ describe('Sequelize client tests', function () { should(sequelizeUpdateStub.args[0][0]).eql({ 'test_id': testId, - 'type': undefined, + 'type': 'load_test', "arrival_count": null, 'arrival_rate': 1, 'cron_expression': '* * * *', @@ -510,7 +510,9 @@ describe('Sequelize client tests', function () { 'parallelism': 3, 'proxy_url': 'http://proxy.com', 'debug': '*', - 'enabled': false + 'enabled': false, + 'webhooks': undefined, + 'emails': undefined }); should(sequelizeUpdateStub.args[0][1]).eql({ @@ -565,7 +567,9 @@ describe('Sequelize client tests', function () { 'parallelism': 3, 'proxy_url': 'http://proxy.com', 'debug': '*', - 'enabled': false + 'enabled': false, + 'webhooks': undefined, + 'emails': undefined }); should(sequelizeUpdateStub.args[0][1]).eql({ From 21bfe259c2b0a10a06abbeef3c50dc8912c7d67f Mon Sep 17 00:00:00 2001 From: NivLipetz Date: Sat, 5 Sep 2020 12:50:20 +0300 Subject: [PATCH 18/20] fix: jobs update --- .../models/database/sequelize/sequelizeConnector.js | 2 +- .../integration-tests/jobs/createJobKubernetes-test.js | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/jobs/models/database/sequelize/sequelizeConnector.js b/src/jobs/models/database/sequelize/sequelizeConnector.js index d9e34edf0..a2d079f86 100644 --- a/src/jobs/models/database/sequelize/sequelizeConnector.js +++ b/src/jobs/models/database/sequelize/sequelizeConnector.js @@ -132,7 +132,7 @@ async function updateJob(jobId, jobInfo) { mergedParams.ramp_to = null; break; case JOB_TYPE_LOAD_TEST: - if (!jobInfo.arrival_rate) { + if (!mergedParams.arrival_rate) { const error = new Error('arrival_rate is mandatory when updating job to load_test'); error.statusCode = 400; throw error; diff --git a/tests/integration-tests/jobs/createJobKubernetes-test.js b/tests/integration-tests/jobs/createJobKubernetes-test.js index 16fa5a1bf..17bb08e74 100644 --- a/tests/integration-tests/jobs/createJobKubernetes-test.js +++ b/tests/integration-tests/jobs/createJobKubernetes-test.js @@ -185,6 +185,16 @@ describe('Create job specific kubernetes tests', async function () { }); }); + it('Get the job and verify it is enabled', async () => { + jobId = createJobResponse.body.id; + getJobsFromService = await schedulerRequestCreator.getJob(jobId, { + 'Content-Type': 'application/json' + }); + + should(getJobsFromService.status).eql(200); + should(getJobsFromService.body.enabled).eql(true); + }); + it('Wait 4 seconds to let scheduler run the job', (done) => { setTimeout(done, 4000); }); From e8b38b773291effdc4ea3dbe5f83cdd5193d0d67 Mon Sep 17 00:00:00 2001 From: NivLipetz Date: Sat, 5 Sep 2020 13:02:29 +0300 Subject: [PATCH 19/20] test: fix update job --- .../integration-tests/jobs/updateJob-test.js | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/tests/integration-tests/jobs/updateJob-test.js b/tests/integration-tests/jobs/updateJob-test.js index 386bdfd63..08878b4f5 100644 --- a/tests/integration-tests/jobs/updateJob-test.js +++ b/tests/integration-tests/jobs/updateJob-test.js @@ -230,13 +230,13 @@ describe('Update scheduled job', function () { }); describe('Unsuccessful Updates', () => { - let jobId; + let jobId, functionalJobId; before(() => { nock.cleanAll(); }); before(async () => { - let validBody = { + const validBody = { test_id: testId, arrival_rate: 1, duration: 1, @@ -245,10 +245,24 @@ describe('Update scheduled job', function () { run_immediately: false, cron_expression: '* * * * * *' }; - let createJobResponse = await schedulerRequestCreator.createJob(validBody, { + const createJobResponse = await schedulerRequestCreator.createJob(validBody, { 'Content-Type': 'application/json' }); jobId = createJobResponse.body.id; + + const validFunctionalJobBody = { + test_id: testId, + arrival_count: 1, + duration: 1, + type: 'functional_test', + environment: 'test', + run_immediately: false, + cron_expression: '* * * * * *' + } + const createFunctionalJobResponse = await schedulerRequestCreator.createJob(validFunctionalJobBody, { + 'Content-Type': 'application/json' + }); + functionalJobId = createFunctionalJobResponse.body.id; }); it('Update job with wrong type', async () => { @@ -259,7 +273,7 @@ describe('Update scheduled job', function () { updateJobResponse.body.should.eql({ message: 'job type is in an unsupported value: mickey' } ); }); - it('Update job to functional_test with arrival_rate', async () => { + it('Update load_test job to functional_test with arrival_rate', async () => { let updateJobResponse = await schedulerRequestCreator.updateJob(jobId, { type: 'functional_test', arrival_rate: 5 }, { 'Content-Type': 'application/json' }); @@ -267,8 +281,8 @@ describe('Update scheduled job', function () { updateJobResponse.body.should.eql({ message: 'arrival_count is mandatory when updating job to functional_test' } ); }); - it('Update job to functional_test with arrival_rate', async () => { - let updateJobResponse = await schedulerRequestCreator.updateJob(jobId, { type: 'load_test', arrival_count: 5 }, { + it('Update functional_test job to load_test with arrival_count', async () => { + let updateJobResponse = await schedulerRequestCreator.updateJob(functionalJobId, { type: 'load_test', arrival_count: 5 }, { 'Content-Type': 'application/json' }); updateJobResponse.statusCode.should.eql(400); From 341c23f0fb4afc7094d4cfcbd4f10993694d149e Mon Sep 17 00:00:00 2001 From: NivLipetz Date: Sat, 5 Sep 2020 13:15:22 +0300 Subject: [PATCH 20/20] test: fix sqlite storage name --- src/env.js | 8 ++++---- tests/configurations/sqliteConfiguration.sh | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/env.js b/src/env.js index 810fa8d65..3dadca0a6 100644 --- a/src/env.js +++ b/src/env.js @@ -1,4 +1,4 @@ -let log = require('../src/common/logger'); +let logger = require('../src/common/logger'); let env = {}; const BY_PLATFORM_MANDATORY_VARS = { METRONOME: ['METRONOME_URL'], @@ -21,12 +21,12 @@ const SUPPORTED_DATABASES = Object.keys(BY_DATABASE_MANDATORY_VARS); env.init = function () { if (!SUPPORTED_PLATFORMS.includes(String(process.env.JOB_PLATFORM).toUpperCase())) { - log.error(`JOB_PLATFORM should be one of: ${SUPPORTED_PLATFORMS}`); + logger.error(`JOB_PLATFORM should be one of: ${SUPPORTED_PLATFORMS}`); process.exit(1); } if (process.env.DATABASE_TYPE && !SUPPORTED_DATABASES.includes(String(process.env.DATABASE_TYPE).toUpperCase())) { - log.error(`DATABASE_TYPE should be one of: ${SUPPORTED_DATABASES}`); + logger.error(`DATABASE_TYPE should be one of: ${SUPPORTED_DATABASES}`); process.exit(1); } @@ -46,7 +46,7 @@ env.init = function () { }); if (missingFields.length > 0) { - log.error('Missing mandatory environment variables', missingFields); + logger.error(missingFields, 'Missing mandatory environment variables'); process.exit(1); } diff --git a/tests/configurations/sqliteConfiguration.sh b/tests/configurations/sqliteConfiguration.sh index c91ad3706..15a8e8170 100755 --- a/tests/configurations/sqliteConfiguration.sh +++ b/tests/configurations/sqliteConfiguration.sh @@ -5,4 +5,4 @@ export DATABASE_NAME=predator export DATABASE_ADDRESS=localhost export DATABASE_USERNAME=root export DATABASE_PASSWORD=password -export SQLITE_STORAGE=predator \ No newline at end of file +export SQLITE_STORAGE=predator-$(date +%s) \ No newline at end of file