From 82519381200bddbf1a607b4b3fe7db55b1e29bb5 Mon Sep 17 00:00:00 2001 From: Bikash Subba Date: Thu, 4 Feb 2021 09:49:04 +0100 Subject: [PATCH 1/9] TSERV-861:Added error exit code --- bin/jobs_functions.js | 27 +++++++++++++++++++-------- bin/license_functions.js | 13 ++++++++++--- bin/readyapi_project.js | 23 +++++++++++++++-------- bin/run_functions.js | 18 ++++++++++-------- bin/user_functions.js | 19 +++++++++++-------- 5 files changed, 65 insertions(+), 35 deletions(-) diff --git a/bin/jobs_functions.js b/bin/jobs_functions.js index 1220d4e..c6527d2 100644 --- a/bin/jobs_functions.js +++ b/bin/jobs_functions.js @@ -5,6 +5,7 @@ const request = require('superagent'); const config = require('./config').config; const sprintf = require('sprintf-js').sprintf; const fs = require('fs'); +const process = require('process'); module.exports = { dispatcher: function (args) { @@ -43,7 +44,7 @@ module.exports = { break; } case 'report': { - if (args.length < 3) { + if (args.length < 4) { printModuleHelp(); } else { let jobId = args[args.length - 1]; @@ -77,7 +78,7 @@ module.exports = { break; default: util.error("Unknown operatation"); - break; + process.exit(1); } }, reportForTestJob: reportForTestJob @@ -116,6 +117,7 @@ function terminateTestJob(testjobId) { } else { util.error(err); } + process.exit(1); } else { util.output('Successfully canceled job'); } @@ -146,6 +148,7 @@ function deleteTestJob(testjobId) { } else { util.error(err); } + process.exit(1); } else { util.output('Successfully deleted job'); } @@ -168,7 +171,7 @@ function printReport (testjobId) { } else { util.output(err.status + ': ' + err.message); } - return 1 + process.exit(1); } util.output(utility.inspect(jsonReport, { showHidden: false, depth: null})); }); @@ -210,11 +213,11 @@ function reportForTestJob(testjobId, outputFolder, fileName, format) { default: util.error("Invalid format: " + format); contentType = ''; - break; + process.exit(1); } } else { util.error("Output folder exists but is not a directory"); - return; + process.exit(1); } } if (contentType !== '') { @@ -235,6 +238,13 @@ function reportForTestJob(testjobId, outputFolder, fileName, format) { if (reportFileName) { fs.unlinkSync(reportFileName) } + util.error(`Status code: ${response.status}`); + process.exit(1) + } + + if (response.status === 200) { + util.output('Report created successfully'); + process.exit(0); } }).send(); if (stream) { @@ -256,6 +266,7 @@ function reportForTestJob(testjobId, outputFolder, fileName, format) { } else { util.error(err); } + process.exit(1); } }) } @@ -272,7 +283,7 @@ function listJobs(options) { .end((err, res) => { if (err !== null) { util.output(err.status + ': ' + err.message); - return 1 + process.exit(1); } let dataFromServer = res.body; if (Array.isArray(dataFromServer) && 'status' in options) { @@ -294,7 +305,7 @@ function listJobs(options) { break; default: util.error('Unrecognized format'); - break; + process.exit(1); } }); } @@ -329,7 +340,7 @@ function pruneJobs(options) { else util.output(err.status + ': ' + err.message); } - return 1 + process.exit(1); } let jobsPruned = JSON.parse(res.request.response.body); util.output("Pruned " + jobsPruned + " jobs from the database.") diff --git a/bin/license_functions.js b/bin/license_functions.js index e3f3940..00d4ea6 100644 --- a/bin/license_functions.js +++ b/bin/license_functions.js @@ -5,6 +5,7 @@ const config = require('./config').config; const util = require('./shared_utils'); const fs = require('fs'); const path = require('path'); +const process = require('process'); module.exports.dispatcher = function (args) { if (args.length === 0) @@ -41,7 +42,7 @@ module.exports.dispatcher = function (args) { break; default: util.error("Unknown operatation"); - break; + process.exit(100); } }; @@ -69,7 +70,7 @@ function installLicense(options, licenseOrLicenseServer) { break; default: util.error("Error: Specifying fixed or floating license is mandatory"); - return; + process.exit(100); } } @@ -95,6 +96,7 @@ function uninstallLicense() { return; } } + process.exit(100); } }); } @@ -140,14 +142,17 @@ function installFixedLicense(options, licenseFile) { } else { util.error(err); } + process.exit(100); } }); }); readStream.on('error', function (err) { util.error("Error: " + err.message); let ext = path.extname(licenseFile).toLowerCase(); - if ((ext !== '.key') && (ext !== '.zip')) + if ((ext !== '.key') && (ext !== '.zip')) { util.error('"' + licenseFile + '" does not seem to be a .zip or .key file'); + } + process.exit(100); }); } @@ -183,6 +188,7 @@ function installFloatingLicense(licenseServerHost, licenseServerPort) { } else { util.error(err); } + process.exit(100); } }); } @@ -215,6 +221,7 @@ function showLicenseInfo() { } else { util.error(err); } + process.exit(100); } }); diff --git a/bin/readyapi_project.js b/bin/readyapi_project.js index e5713a8..769531d 100644 --- a/bin/readyapi_project.js +++ b/bin/readyapi_project.js @@ -4,6 +4,7 @@ const util = require('./shared_utils'); const parser = require('fast-xml-parser'); const fs = require('fs'); const path = require('path'); +const process = require('process'); const xmlParserOptions = { attributeNamePrefix: "@_", @@ -26,10 +27,12 @@ module.exports.parse = function (filename) { let jsonProject = parser.parse(fs.readFileSync(filename, {encoding: 'utf8'}), xmlParserOptions); if (!('con:soapui-project' in jsonProject)) { - throw "'" + filename + "' does not seem to be a ReadyAPI project file"; + util.error(`${filename} does not seem to be a ReadyAPI project file`); + process.exit(1); } - if ('con:encryptedContent' in jsonProject['con:soapui-project']) { - throw "'" + filename + "' is encrypted and may have to be sent to the server as a zip file"; + if ('con:encryptedContent' in jsonProject[ 'con:soapui-project' ]) { + util.error(`${filename} is encrypted and may have to be sent to the server as a zip file`); + process.exit(1); } if ("con:soapui-project" in jsonProject) { result = postProcessStructure(jsonProject); @@ -42,7 +45,7 @@ module.exports.parse = function (filename) { result['projectFiles'] = [filename]; } else { util.error("File doesn't seem to be a ReadyAPI project"); - return null; + process.exit(1); } return result; }; @@ -54,16 +57,20 @@ module.exports.parseComposite = function (pathname) { let jsonProject; if (!fs.lstatSync(pathname).isDirectory()) { - throw pathname + ' doesn\'t point to a directory'; + util.error(`${pathname} doesn't point to a directory`); + process.exit(1); } if (!fs.existsSync(pathname + path.sep + 'settings.xml')) { - throw pathname + ' doesn\'t point to a composite project (settings.xml missing)'; + util.error(`${pathname} doesn't point to a composite project (settings.xml missing)`); + process.exit(1); } if (!fs.existsSync(pathname + path.sep + 'element.order')) { - throw pathname + ' doesn\'t point to a composite project (element.order missing)'; + util.error(`${pathname} doesn't point to a composite project (element.order missing)`); + process.exit(1); } if (!fs.existsSync(pathname + path.sep + 'project.content')) { - throw pathname + ' doesn\'t point to a composite project (project.content missing)'; + util.error(`${pathname} doesn't point to a composite project (project.content missing)`); + process.exit(1); } let filename = pathname + path.sep + 'settings.xml'; jsonProject = parser.parse(fs.readFileSync(filename, {encoding: 'utf8'}), xmlParserOptions); diff --git a/bin/run_functions.js b/bin/run_functions.js index 13eb01e..bbcf016 100644 --- a/bin/run_functions.js +++ b/bin/run_functions.js @@ -157,7 +157,7 @@ function runProject(filename, options) { } } else { util.error("Cannot open file: " + filename); - + process.exit(1) } } @@ -249,7 +249,7 @@ function executeProject(filename, project, options) { async.series([ // First create a zip file, if needed. // - function (callback) { + function (callback) { if (!isZipFile && (project !== null) && ((files.length > 0) || (project['projectFiles'].length > 1))) { // We depend on files, we need to create and send a zip file let projectRootPath = ''; @@ -400,20 +400,21 @@ function executeProject(filename, project, options) { } break; case 400: - util.error('Error: ' + result.body['message']); + util.error('Error: ' + result.body[ 'message' ]); + process.exit(1); break; default: callback(err); - return; } } else { util.error(err); + process.exit(100); } } callback(); }); }, - function (callback) { + function (callback) { if ('async' in options) { callback(); return; @@ -438,7 +439,6 @@ function executeProject(filename, project, options) { await util.sleep(200); }, function () { - // callback(); if ((websocket !== null) && (websocket.readyState !== 0)) { websocket.close(); } @@ -456,9 +456,11 @@ function executeProject(filename, project, options) { if ('code' in res) { if (res.code === 'ECONNREFUSED') { util.error(sprintf("Connection refused: %s:%d", res.address, res.port)); + } else if (res.code === 'ENOTFOUND') { + const { host, port } = res; + util.error(`Host ${host}:${port} does not exist.`); } else { util.error(res); - process.exit(1); } } else if ('status' in res) { if ('message' in res.response.body) { @@ -466,8 +468,8 @@ function executeProject(filename, project, options) { } else { util.error(res.response.text); } - process.exit(); } + process.exit(100); } else { if (!options.async || !('async' in options)) { // If status isn't CANCELED, PENDING or DISCONNECTED and we have an output directory, store reports there diff --git a/bin/user_functions.js b/bin/user_functions.js index 3388d86..260f1a9 100644 --- a/bin/user_functions.js +++ b/bin/user_functions.js @@ -6,6 +6,7 @@ const sprintf = require('sprintf-js').sprintf; const csv = require('csvtojson'); const fs = require('fs'); const util = require('./shared_utils'); +const process = require('process'); module.exports.dispatcher = function(args) { if (args.length === 0) @@ -60,7 +61,7 @@ module.exports.dispatcher = function(args) { break; default: util.error("Unknown operatation"); - break; + process.exit(100); } }; @@ -101,7 +102,7 @@ function addUser(username, password, isAdmin = false, silent = false, callback = } else { switch (err.status) { case 422: - util.error("Username or password is incorrect"); + util.error(err.response.body.message); break; case 409: util.error('User "' + username + '" already exists.'); @@ -110,6 +111,7 @@ function addUser(username, password, isAdmin = false, silent = false, callback = util.output(err.status + ': ' + err.message); } } + process.exit(100); } else { util.output('Created ' + (isAdmin ? 'admin ' : '') + 'user "' + username + '"'); } @@ -158,7 +160,8 @@ function importUsers(fileOrURL) { user['admin'] ? 1 : 0)); } else { util.error('User ' + user['username'] + ' could not be imported'); - util.error(err.status + ': ' + err.message); + util.error(err.status + ': ' + err.response.body.message); + process.exit(100); } }); } @@ -192,7 +195,7 @@ function updateUser(username, options) { } else { util.output(err.status + ': ' + err.message); } - return 1 + process.exit(100); } util.output('User "' + username + '"successfully updated'); }); @@ -206,9 +209,9 @@ function deleteUser(username) { .end((err) => { if (err !== null) { util.output(err.status + ': ' + err.message); - return 1 + process.exit(100); } - util.output('User "' + username + '"successfully deleted'); + util.output('User "' + username + '" successfully deleted'); }); } @@ -229,7 +232,7 @@ function listUsers(options) { } else { util.output(err.status + ': ' + err.message); } - return 1 + process.exit(100); } switch (format) { case 'csv': @@ -240,7 +243,7 @@ function listUsers(options) { break; default: util.error('Unrecognized format'); - break; + process.exit(1) } }); } From 7a17f85135dadbbd9ba0de888598e8561830a039 Mon Sep 17 00:00:00 2001 From: Bikash Subba Date: Thu, 4 Feb 2021 10:44:38 +0100 Subject: [PATCH 2/9] TSERV-861:Fixed type --- bin/auditlog_functions.js | 5 +++-- bin/jobs_functions.js | 2 +- bin/license_functions.js | 2 +- bin/user_functions.js | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/bin/auditlog_functions.js b/bin/auditlog_functions.js index 66b34c8..c7e9c3e 100644 --- a/bin/auditlog_functions.js +++ b/bin/auditlog_functions.js @@ -4,6 +4,7 @@ const request = require('superagent'); const config = require('./config').config; const sprintf = require('sprintf-js').sprintf; const util = require('./shared_utils'); +const process = require('process'); module.exports.dispatcher = function (args) { if (args.length === 0) @@ -24,8 +25,8 @@ module.exports.dispatcher = function (args) { printModuleHelp(); break; default: - util.error("Unknown operatation"); - break; + util.error("Unknown operation"); + process.exit(100); } }; diff --git a/bin/jobs_functions.js b/bin/jobs_functions.js index c6527d2..f453979 100644 --- a/bin/jobs_functions.js +++ b/bin/jobs_functions.js @@ -77,7 +77,7 @@ module.exports = { printModuleHelp(); break; default: - util.error("Unknown operatation"); + util.error("Unknown operation"); process.exit(1); } }, diff --git a/bin/license_functions.js b/bin/license_functions.js index 00d4ea6..5f7d9a0 100644 --- a/bin/license_functions.js +++ b/bin/license_functions.js @@ -41,7 +41,7 @@ module.exports.dispatcher = function (args) { printModuleHelp(); break; default: - util.error("Unknown operatation"); + util.error("Unknown operation"); process.exit(100); } }; diff --git a/bin/user_functions.js b/bin/user_functions.js index 260f1a9..7f7d9cd 100644 --- a/bin/user_functions.js +++ b/bin/user_functions.js @@ -60,7 +60,7 @@ module.exports.dispatcher = function(args) { printModuleHelp(); break; default: - util.error("Unknown operatation"); + util.error("Unknown operation"); process.exit(100); } }; From 11c70a552440243cf29f2b091a51130b2e8f2493 Mon Sep 17 00:00:00 2001 From: Bikash Subba Date: Mon, 8 Feb 2021 14:23:16 +0100 Subject: [PATCH 3/9] TSERV-861:200 for unknown operation --- bin/auditlog_functions.js | 4 +--- bin/jobs_functions.js | 3 +-- bin/license_functions.js | 3 +-- bin/run_functions.js | 3 +-- bin/shared_utils.js | 5 +++++ bin/user_functions.js | 3 +-- 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/bin/auditlog_functions.js b/bin/auditlog_functions.js index c7e9c3e..3e8d1b7 100644 --- a/bin/auditlog_functions.js +++ b/bin/auditlog_functions.js @@ -4,7 +4,6 @@ const request = require('superagent'); const config = require('./config').config; const sprintf = require('sprintf-js').sprintf; const util = require('./shared_utils'); -const process = require('process'); module.exports.dispatcher = function (args) { if (args.length === 0) @@ -25,8 +24,7 @@ module.exports.dispatcher = function (args) { printModuleHelp(); break; default: - util.error("Unknown operation"); - process.exit(100); + util.exitForUnknownOperation(); } }; diff --git a/bin/jobs_functions.js b/bin/jobs_functions.js index f453979..7cd291a 100644 --- a/bin/jobs_functions.js +++ b/bin/jobs_functions.js @@ -77,8 +77,7 @@ module.exports = { printModuleHelp(); break; default: - util.error("Unknown operation"); - process.exit(1); + util.exitForUnknownOperation(); } }, reportForTestJob: reportForTestJob diff --git a/bin/license_functions.js b/bin/license_functions.js index 5f7d9a0..86920d3 100644 --- a/bin/license_functions.js +++ b/bin/license_functions.js @@ -41,8 +41,7 @@ module.exports.dispatcher = function (args) { printModuleHelp(); break; default: - util.error("Unknown operation"); - process.exit(100); + util.exitForUnknownOperation(); } }; diff --git a/bin/run_functions.js b/bin/run_functions.js index bbcf016..82da084 100644 --- a/bin/run_functions.js +++ b/bin/run_functions.js @@ -51,8 +51,7 @@ module.exports.dispatcher = function (args) { printModuleHelp(); break; default: - util.error("Unknown operation"); - break; + util.exitForUnknownOperation(); } }; diff --git a/bin/shared_utils.js b/bin/shared_utils.js index 6991751..ea90a36 100644 --- a/bin/shared_utils.js +++ b/bin/shared_utils.js @@ -118,3 +118,8 @@ module.exports.optionsFromArgs = function (args, validArguments = null) { return ret; }; +module.exports.exitForUnknownOperation = function () { + module.exports.error("Unknown operation"); + process.exit(200); +} + diff --git a/bin/user_functions.js b/bin/user_functions.js index 7f7d9cd..cf31024 100644 --- a/bin/user_functions.js +++ b/bin/user_functions.js @@ -60,8 +60,7 @@ module.exports.dispatcher = function(args) { printModuleHelp(); break; default: - util.error("Unknown operation"); - process.exit(100); + util.exitForUnknownOperation(); } }; From 4edd3252cbeb50b6d6f9c6b927a48f5ca7581b3e Mon Sep 17 00:00:00 2001 From: Jonathan Lundholm Date: Tue, 9 Feb 2021 16:29:21 +0100 Subject: [PATCH 4/9] TSERV-861 adding status code 1 if testjob fails. --- bin/run_functions.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bin/run_functions.js b/bin/run_functions.js index 82da084..c5fc66a 100644 --- a/bin/run_functions.js +++ b/bin/run_functions.js @@ -477,6 +477,9 @@ function executeProject(filename, project, options) { if (config.showProgress) util.output(''); util.output("Result: " + status); + if(status === 'FAILED') { + process.exit(1); + } if ((jobId !== null) && ((status !== 'CANCELED') From 25320eda4407cf53599223cdc189566f0b6164c4 Mon Sep 17 00:00:00 2001 From: Jonathan Lundholm Date: Thu, 11 Feb 2021 13:39:15 +0100 Subject: [PATCH 5/9] TSERV-861 added a test script together with resources to make it easier to test status codes and see if something is broken. Updated all status codes to be '1' and added them to a few places to ensure everything works properly. --- bin/auditlog_functions.js | 11 ++-- bin/jobs_functions.js | 89 +++++++++++--------------------- bin/license_functions.js | 47 +++++++---------- bin/readyapi_project.js | 24 +++------ bin/run_functions.js | 33 +++++------- bin/shared_utils.js | 11 ++-- bin/user_functions.js | 50 +++++++++--------- test/admin.config | 5 ++ test/regularUser.config | 5 ++ test/runtimeerror.xml | 62 +++++++++++++++++++++++ test/slow.xml | 62 +++++++++++++++++++++++ test/successful.xml | 74 +++++++++++++++++++++++++++ test/testScript.py | 103 ++++++++++++++++++++++++++++++++++++++ test/validationerror.xml | 65 ++++++++++++++++++++++++ 14 files changed, 482 insertions(+), 159 deletions(-) create mode 100644 test/admin.config create mode 100644 test/regularUser.config create mode 100644 test/runtimeerror.xml create mode 100644 test/slow.xml create mode 100644 test/successful.xml create mode 100644 test/testScript.py create mode 100644 test/validationerror.xml diff --git a/bin/auditlog_functions.js b/bin/auditlog_functions.js index 3e8d1b7..a46f2e2 100644 --- a/bin/auditlog_functions.js +++ b/bin/auditlog_functions.js @@ -24,7 +24,7 @@ module.exports.dispatcher = function (args) { printModuleHelp(); break; default: - util.exitForUnknownOperation(); + util.printErrorAndExit("Unknown operation"); } }; @@ -63,14 +63,13 @@ function dumpAuditLog(options) { if (err !== null) { if ('code' in err) { if (err.code === 'ECONNREFUSED') { - util.error(sprintf("Connection refused: %s:%d", err.address, err.port)); + util.printErrorAndExit(sprintf("Connection refused: %s:%d", err.address, err.port)); } else { - util.error(sprintf("Error: %s:%s", err.code, err.message)); + util.printErrorAndExit(sprintf("Error: %s:%s", err.code, err.message)); } } else { - util.output(err.status + ': ' + err.message); + util.printErrorAndExit(err.status + ': ' + err.message); } - return 1 } if (format === 'json') { if ('limit' in options) { @@ -81,7 +80,7 @@ function dumpAuditLog(options) { } else { printAuditLogHeader(format); let counter = 0; - let maxItems = 'limit' in options?options['limit']:1e10; + let maxItems = 'limit' in options ? options['limit'] : 1e10; let isoTime = 'iso' in options; for (let line of result.body) { printAuditLogLine(line, format, isoTime); diff --git a/bin/jobs_functions.js b/bin/jobs_functions.js index 7cd291a..43feebd 100644 --- a/bin/jobs_functions.js +++ b/bin/jobs_functions.js @@ -58,7 +58,7 @@ module.exports = { if (args.length < 2) { printModuleHelp(); } else { - const testJobId = args[ args.length - 1 ]; + const testJobId = args[args.length - 1]; printReport(testJobId); } break; @@ -77,7 +77,7 @@ module.exports = { printModuleHelp(); break; default: - util.exitForUnknownOperation(); + util.printErrorAndExit("Unknown operation"); } }, reportForTestJob: reportForTestJob @@ -96,8 +96,8 @@ function printModuleHelp() { } function terminateTestJob(testjobId) { - let url = config.server + '/api/v1/testjobs'+ '/' + testjobId; - util.output('Canceling job: '+testjobId); + let url = config.server + '/api/v1/testjobs' + '/' + testjobId; + util.output('Canceling job: ' + testjobId); request.delete(url) .auth(config.username, config.password) .accept('application/junit+xml') @@ -105,18 +105,10 @@ function terminateTestJob(testjobId) { .end((err, result) => { if (err !== null) { if (('status' in err) && ('message' in result.body)) { - switch (err['status']) { - case 403: - util.error(err['status'] + ': ' + result.body['message']); - break; - default: - util.error(err['status'] + ': ' + result.body['message']); - return; - } + util.printErrorAndExit(err['status'] + ': ' + result.body['message']); } else { - util.error(err); + util.printErrorAndExit(err); } - process.exit(1); } else { util.output('Successfully canceled job'); } @@ -124,8 +116,8 @@ function terminateTestJob(testjobId) { } function deleteTestJob(testjobId) { - let url = config.server + '/api/v1/testjobs'+ '/' + testjobId + '/delete'; - util.output('Deleting job: '+testjobId); + let url = config.server + '/api/v1/testjobs' + '/' + testjobId + '/delete'; + util.output('Deleting job: ' + testjobId); request.delete(url) .auth(config.username, config.password) .accept('application/junit+xml') @@ -134,27 +126,22 @@ function deleteTestJob(testjobId) { if (err !== null) { if (('status' in err) && ('message' in result.body)) { switch (err['status']) { - case 403: - util.error(err['status'] + ': ' + result.body['message']); - break; case 404: - util.output(`${err['status']}: Testjob not found`); + util.printErrorAndExit(`${err['status']}: Testjob not found`); break; default: - util.error(err['status'] + ': ' + result.body['message']); - return; + util.printErrorAndExit(err['status'] + ': ' + result.body['message']); } } else { - util.error(err); + util.printErrorAndExit(err); } - process.exit(1); } else { util.output('Successfully deleted job'); } }) } -function printReport (testjobId) { +function printReport(testjobId) { const endPoint = config.server + '/api/v1/testjobs'; const url = endPoint + '/' + testjobId + '/report'; util.output(`Printing report for ${testjobId} ...`); @@ -166,13 +153,12 @@ function printReport (testjobId) { const jsonReport = res.body; if (err !== null) { if (err.status === 404) { - util.output(`Testjob with id ${testjobId} not found`); + util.printErrorAndExit(`Testjob with id ${testjobId} not found`); } else { - util.output(err.status + ': ' + err.message); + util.printErrorAndExit(err.status + ': ' + err.message); } - process.exit(1); } - util.output(utility.inspect(jsonReport, { showHidden: false, depth: null})); + util.output(utility.inspect(jsonReport, {showHidden: false, depth: null})); }); } @@ -210,17 +196,13 @@ function reportForTestJob(testjobId, outputFolder, fileName, format) { reportFilename += '.pdf'; break; default: - util.error("Invalid format: " + format); - contentType = ''; - process.exit(1); + util.printErrorAndExit("Invalid format: " + format); } } else { - util.error("Output folder exists but is not a directory"); - process.exit(1); + util.printErrorAndExit("Output folder exists but is not a directory"); } } if (contentType !== '') { - let success = true; let url = endPoint + '/' + testjobId + '/report'; let stream; let reportFileName; @@ -233,15 +215,11 @@ function reportForTestJob(testjobId, outputFolder, fileName, format) { .accept(contentType) .on('response', function (response) { if (response.status !== 200) { - success = false; if (reportFileName) { fs.unlinkSync(reportFileName) } - util.error(`Status code: ${response.status}`); - process.exit(1) - } - - if (response.status === 200) { + util.printErrorAndExit(`Status code: ${response.status}`); + } else { util.output('Report created successfully'); process.exit(0); } @@ -254,18 +232,10 @@ function reportForTestJob(testjobId, outputFolder, fileName, format) { util.output('Status of job ' + testjobId + ': ' + result.body.status); } else { if (('status' in err) && ('message' in result.body)) { - switch (err['status']) { - case 403: - util.error(err['status'] + ': ' + result.body['message']); - break; - default: - util.error(err['status'] + ': ' + result.body['message']); - return; - } + util.printErrorAndExit(err['status'] + ': ' + result.body['message']); } else { - util.error(err); + util.printErrorAndExit(err); } - process.exit(1); } }) } @@ -281,8 +251,7 @@ function listJobs(options) { .send() .end((err, res) => { if (err !== null) { - util.output(err.status + ': ' + err.message); - process.exit(1); + util.printErrorAndExit(err.status + ': ' + err.message); } let dataFromServer = res.body; if (Array.isArray(dataFromServer) && 'status' in options) { @@ -303,8 +272,7 @@ function listJobs(options) { dumpArrayAsJson(dataFromServer); break; default: - util.error('Unrecognized format'); - process.exit(1); + util.printErrorAndExit('Unrecognized format'); } }); } @@ -318,7 +286,7 @@ function pruneJobs(options) { let date = new Date(parseInt(matchResult[1]), parseInt(matchResult[2]) - 1, parseInt(matchResult[3])); let tmpDate = date.toISOString(); tmpDate = tmpDate.replace('.000Z', 'Z'); - url += '?before='+encodeURIComponent(tmpDate); + url += '?before=' + encodeURIComponent(tmpDate); } } request.delete(url) @@ -329,17 +297,16 @@ function pruneJobs(options) { if (err !== null) { if ('code' in err) { if (err.code === 'ECONNREFUSED') { - util.error(sprintf("Connection refused: %s:%d", err.address, err.port)); + util.printErrorAndExit(sprintf("Connection refused: %s:%d", err.address, err.port)); } else { - util.error(sprintf("Error: %s:%s", err.code, err.message)); + util.printErrorAndExit(sprintf("Error: %s:%s", err.code, err.message)); } } else { if ('message' in res.body) - util.output(res.body['message']); + util.printErrorAndExit(res.body['message']); else - util.output(err.status + ': ' + err.message); + util.printErrorAndExit(err.status + ': ' + err.message); } - process.exit(1); } let jobsPruned = JSON.parse(res.request.response.body); util.output("Pruned " + jobsPruned + " jobs from the database.") diff --git a/bin/license_functions.js b/bin/license_functions.js index 86920d3..a9716ff 100644 --- a/bin/license_functions.js +++ b/bin/license_functions.js @@ -41,7 +41,7 @@ module.exports.dispatcher = function (args) { printModuleHelp(); break; default: - util.exitForUnknownOperation(); + util.printErrorAndExit("Unknown operation"); } }; @@ -68,9 +68,7 @@ function installLicense(options, licenseOrLicenseServer) { installFixedLicense(options, licenseOrLicenseServer); break; default: - util.error("Error: Specifying fixed or floating license is mandatory"); - process.exit(100); - + util.printErrorAndExit("Error: Specifying fixed or floating license is mandatory"); } } @@ -88,14 +86,12 @@ function uninstallLicense() { if ('status' in err) { switch (err['status']) { case 403: - util.error("User doesn't have enough credentials to uninstall a license"); + util.printErrorAndExit("User doesn't have permission to uninstall a license"); break; default: - util.error(err['status'] + ': ' + result.body['message']); - return; + util.printErrorAndExit(err['status'] + ': ' + result.body['message']); } } - process.exit(100); } }); } @@ -125,23 +121,22 @@ function installFixedLicense(options, licenseFile) { if ('status' in err) { switch (err['status']) { case 403: - util.error("User doesn't have enough credentials to install a license"); + util.printErrorAndExit("User doesn't have permission to install a license"); break; case 400: - util.error("Failed to install license, error: " + result.body['message']); + util.printErrorAndExit("Failed to install license, error: " + result.body['message']); break; default: if ('message' in result.body) { - util.error(err['status'] + ': ' + result.body['message']); + util.printErrorAndExit(err['status'] + ': ' + result.body['message']); } else { - util.error(err['status'] + ': ' + err['message']); + util.printErrorAndExit(err['status'] + ': ' + err['message']); } return; } } else { - util.error(err); + util.printErrorAndExit(err); } - process.exit(100); } }); }); @@ -151,7 +146,7 @@ function installFixedLicense(options, licenseFile) { if ((ext !== '.key') && (ext !== '.zip')) { util.error('"' + licenseFile + '" does not seem to be a .zip or .key file'); } - process.exit(100); + process.exit(1); }); } @@ -175,19 +170,17 @@ function installFloatingLicense(licenseServerHost, licenseServerPort) { if ('status' in err) { switch (err['status']) { case 403: - util.error("User doesn't have enough credentials to install a license"); + util.printErrorAndExit("User doesn't have enough credentials to install a license"); break; case 400: - util.error("Failed to install license, error: " + result.body['message']); + util.printErrorAndExit("Failed to install license, error: " + result.body['message']); break; default: - util.error(err['status'] + ': ' + err['message']); - return; + util.printErrorAndExit(err['status'] + ': ' + err['message']); } } else { - util.error(err); + util.printErrorAndExit(err); } - process.exit(100); } }); } @@ -208,19 +201,17 @@ function showLicenseInfo() { switch (err['status']) { case 401: case 403: - util.error("User doesn't have credentials to show license"); + util.printErrorAndExit("User doesn't have credentials to show license"); break; case 404: - util.error("No license installed"); + util.printErrorAndExit("No license installed"); break; default: - util.error(err['status'] + ': ' + err['message']); - return; + util.printErrorAndExit(err['status'] + ': ' + err['message']); } } else { - util.error(err); + util.printErrorAndExit(err); } - process.exit(100); } }); @@ -232,4 +223,4 @@ function licenseInfoToString(licenseInfo) { "Organization: " + licenseInfo['organization'] + "\n" + "Expires: " + licenseInfo['expireDate'] + "\n" + "Max Concurrent TestJobs: " + licenseInfo['maxConcurrentJobs']; -} \ No newline at end of file +} diff --git a/bin/readyapi_project.js b/bin/readyapi_project.js index 769531d..7af487f 100644 --- a/bin/readyapi_project.js +++ b/bin/readyapi_project.js @@ -4,7 +4,6 @@ const util = require('./shared_utils'); const parser = require('fast-xml-parser'); const fs = require('fs'); const path = require('path'); -const process = require('process'); const xmlParserOptions = { attributeNamePrefix: "@_", @@ -27,12 +26,10 @@ module.exports.parse = function (filename) { let jsonProject = parser.parse(fs.readFileSync(filename, {encoding: 'utf8'}), xmlParserOptions); if (!('con:soapui-project' in jsonProject)) { - util.error(`${filename} does not seem to be a ReadyAPI project file`); - process.exit(1); + util.printErrorAndExit(`${filename} does not seem to be a ReadyAPI project file`); } if ('con:encryptedContent' in jsonProject[ 'con:soapui-project' ]) { - util.error(`${filename} is encrypted and may have to be sent to the server as a zip file`); - process.exit(1); + util.printErrorAndExit(`${filename} is encrypted and may have to be sent to the server as a zip file`); } if ("con:soapui-project" in jsonProject) { result = postProcessStructure(jsonProject); @@ -44,33 +41,26 @@ module.exports.parse = function (filename) { result['resourceRoot'] = resourceRoot; result['projectFiles'] = [filename]; } else { - util.error("File doesn't seem to be a ReadyAPI project"); - process.exit(1); + util.printErrorAndExit("File doesn't seem to be a ReadyAPI project"); } return result; }; module.exports.parseComposite = function (pathname) { - let result; - let jsonProject; if (!fs.lstatSync(pathname).isDirectory()) { - util.error(`${pathname} doesn't point to a directory`); - process.exit(1); + util.printErrorAndExit(`${pathname} doesn't point to a directory`); } if (!fs.existsSync(pathname + path.sep + 'settings.xml')) { - util.error(`${pathname} doesn't point to a composite project (settings.xml missing)`); - process.exit(1); + util.printErrorAndExit(`${pathname} doesn't point to a composite project (settings.xml missing)`); } if (!fs.existsSync(pathname + path.sep + 'element.order')) { - util.error(`${pathname} doesn't point to a composite project (element.order missing)`); - process.exit(1); + util.printErrorAndExit(`${pathname} doesn't point to a composite project (element.order missing)`); } if (!fs.existsSync(pathname + path.sep + 'project.content')) { - util.error(`${pathname} doesn't point to a composite project (project.content missing)`); - process.exit(1); + util.printErrorAndExit(`${pathname} doesn't point to a composite project (project.content missing)`); } let filename = pathname + path.sep + 'settings.xml'; jsonProject = parser.parse(fs.readFileSync(filename, {encoding: 'utf8'}), xmlParserOptions); diff --git a/bin/run_functions.js b/bin/run_functions.js index c5fc66a..06c8543 100644 --- a/bin/run_functions.js +++ b/bin/run_functions.js @@ -40,9 +40,7 @@ module.exports.dispatcher = function (args) { 'proxyPassword', 'projectPassword']); - if (conflictingOptionsCheck(options) === false) { - return; - } + conflictingOptionsCheck(options); switch (args[0].toLowerCase()) { case 'project': runProject(args[args.length - 1], options); @@ -51,7 +49,7 @@ module.exports.dispatcher = function (args) { printModuleHelp(); break; default: - util.exitForUnknownOperation(); + util.printErrorAndExit("Unknown operation"); } }; @@ -66,22 +64,17 @@ function printModuleHelp() { function conflictingOptionsCheck(options) { if (('securitytest' in options) && (('testcase' in options) || ('testsuite' in options))) { - util.error('Error: Parameters testsuite and testcase are not allowed when securitytest is used'); - return false; + util.printErrorAndExit('Error: Parameters testsuite and testcase are not allowed when securitytest is used'); } if ('tags' in options) { if (('testsuite' in options) || ('testcase' in options)) { - util.error('Error: tags cannot be used together with testcase/testsuite '); - return false; + util.printErrorAndExit('Error: tags cannot be used together with testcase/testsuite '); } } if (('testcase' in options) && !('testsuite' in options)) { util.error('Warning: Specifying testscase without testsuite can cause unpredictable results'); - return true; } - - return true; } function extractFilesFromJsonRepresentation(data, options) { @@ -148,7 +141,7 @@ function runProject(filename, options) { if (typeof err === 'string') { if (err.match(/is encrypted/)) { if (!('projectPassword' in options)) - util.error('Error: Submitting encrypted projects without projectPassword will not work'); + util.printErrorAndExit('Error: Submitting encrypted projects without projectPassword will not work'); else executeProject(filename, null, options); } @@ -394,13 +387,12 @@ function executeProject(filename, project, options) { if (Array.isArray(result.body)) { util.error("Project cannot be accepted, files missing:"); for (let missingFile of result.body) { - util.error(' ' + missingFile['fileName']); + util.printErrorAndExit(' ' + missingFile['fileName']); } } break; case 400: - util.error('Error: ' + result.body[ 'message' ]); - process.exit(1); + util.printErrorAndExit('Error: ' + result.body[ 'message' ]); break; default: callback(err); @@ -454,21 +446,20 @@ function executeProject(filename, project, options) { if (res) { if ('code' in res) { if (res.code === 'ECONNREFUSED') { - util.error(sprintf("Connection refused: %s:%d", res.address, res.port)); + util.printErrorAndExit(sprintf("Connection refused: %s:%d", res.address, res.port)); } else if (res.code === 'ENOTFOUND') { const { host, port } = res; - util.error(`Host ${host}:${port} does not exist.`); + util.printErrorAndExit(`Host ${host}:${port} does not exist.`); } else { - util.error(res); + util.printErrorAndExit(res); } } else if ('status' in res) { if ('message' in res.response.body) { - util.error("Error: " + res.response.body['message']); + util.printErrorAndExit("Error: " + res.response.body['message']); } else { - util.error(res.response.text); + util.printErrorAndExit(res.response.text); } } - process.exit(100); } else { if (!options.async || !('async' in options)) { // If status isn't CANCELED, PENDING or DISCONNECTED and we have an output directory, store reports there diff --git a/bin/shared_utils.js b/bin/shared_utils.js index ea90a36..a0de1cf 100644 --- a/bin/shared_utils.js +++ b/bin/shared_utils.js @@ -118,8 +118,13 @@ module.exports.optionsFromArgs = function (args, validArguments = null) { return ret; }; -module.exports.exitForUnknownOperation = function () { - module.exports.error("Unknown operation"); - process.exit(200); +module.exports.printErrorAndExit = function (errorMessage) { + module.exports.error(errorMessage); + process.exit(1); } +// module.exports.exitForUnknownOperation = function () { +// module.exports.error("Unknown operation"); +// process.exit(200); +// } + diff --git a/bin/user_functions.js b/bin/user_functions.js index cf31024..f0c9a6e 100644 --- a/bin/user_functions.js +++ b/bin/user_functions.js @@ -8,7 +8,7 @@ const fs = require('fs'); const util = require('./shared_utils'); const process = require('process'); -module.exports.dispatcher = function(args) { +module.exports.dispatcher = function (args) { if (args.length === 0) return printModuleHelp(); @@ -60,7 +60,7 @@ module.exports.dispatcher = function(args) { printModuleHelp(); break; default: - util.exitForUnknownOperation(); + util.printErrorAndExit("Unknown operation") } }; @@ -88,32 +88,31 @@ function addUser(username, password, isAdmin = false, silent = false, callback = .type('application/json') .send(payload) .end((err) => { - if (!silent) + if (!silent) { if (err !== null) { util.error('Failed to create ' + (isAdmin ? 'admin ' : '') + 'user "' + username + '"'); if ('code' in err) { if (err.code === 'ECONNREFUSED') { - util.error(sprintf("Connection refused: %s:%d", err.address, err.port)); + util.printErrorAndExit(sprintf("Connection refused: %s:%d", err.address, err.port)); } else { - util.error(sprintf("Error: %s:%s", err.code, err.message)); + util.printErrorAndExit(sprintf("Error: %s:%s", err.code, err.message)); } - return 1 } else { switch (err.status) { case 422: - util.error(err.response.body.message); + util.printErrorAndExit(err.response.body.message); break; case 409: - util.error('User "' + username + '" already exists.'); + util.printErrorAndExit('User "' + username + '" already exists.'); break; default: - util.output(err.status + ': ' + err.message); + util.printErrorAndExit(err.status + ': ' + err.message); } } - process.exit(100); } else { util.output('Created ' + (isAdmin ? 'admin ' : '') + 'user "' + username + '"'); } + } if (callback) { callback(err) } @@ -122,6 +121,7 @@ function addUser(username, password, isAdmin = false, silent = false, callback = function importUsers(fileOrURL) { let urlRegExp = /^[a-z]{1,5}[:][/]{2}/; + let failedImport = false; let stream = null; if (fileOrURL.match(urlRegExp) !== null) { @@ -160,11 +160,18 @@ function importUsers(fileOrURL) { } else { util.error('User ' + user['username'] + ' could not be imported'); util.error(err.status + ': ' + err.response.body.message); - process.exit(100); + failedImport = true; } }); } - }) + }).on('done', (error) => { + if (error) { + util.error(error) + } + if (failedImport) { + process.exit(1); + } + }); } function updateUser(username, options) { @@ -187,14 +194,13 @@ function updateUser(username, options) { if (err !== null) { if ('code' in err) { if (err.code === 'ECONNREFUSED') { - util.error(sprintf("Connection refused: %s:%d", err.address, err.port)); + util.printErrorAndExit(sprintf("Connection refused: %s:%d", err.address, err.port)); } else { - util.error(sprintf("Error: %s:%s", err.code, err.message)); + util.printErrorAndExit(sprintf("Error: %s:%s", err.code, err.message)); } } else { - util.output(err.status + ': ' + err.message); + util.printErrorAndExit(err.status + ': ' + err.message); } - process.exit(100); } util.output('User "' + username + '"successfully updated'); }); @@ -207,8 +213,7 @@ function deleteUser(username) { .send() .end((err) => { if (err !== null) { - util.output(err.status + ': ' + err.message); - process.exit(100); + util.printErrorAndExit(err.status + ': ' + err.message); } util.output('User "' + username + '" successfully deleted'); }); @@ -224,14 +229,13 @@ function listUsers(options) { if (err !== null) { if ('code' in err) { if (err.code === 'ECONNREFUSED') { - util.error(sprintf("Connection refused: %s:%d", err.address, err.port)); + util.printErrorAndExit(sprintf("Connection refused: %s:%d", err.address, err.port)); } else { - util.error(sprintf("Error: %s:%s", err.code, err.message)); + util.printErrorAndExit(sprintf("Error: %s:%s", err.code, err.message)); } } else { - util.output(err.status + ': ' + err.message); + util.printErrorAndExit(err.status + ': ' + err.message); } - process.exit(100); } switch (format) { case 'csv': @@ -265,4 +269,4 @@ function dumpArrayAsCSV(array) { function createRandomPassword(length = 8) { return Math.random().toString(36).slice(-1 * length); -} \ No newline at end of file +} diff --git a/test/admin.config b/test/admin.config new file mode 100644 index 0000000..c93a43a --- /dev/null +++ b/test/admin.config @@ -0,0 +1,5 @@ +{ + "username": "admin", + "password": "password", + "host": "http://localhost:8080" +} diff --git a/test/regularUser.config b/test/regularUser.config new file mode 100644 index 0000000..0b24807 --- /dev/null +++ b/test/regularUser.config @@ -0,0 +1,5 @@ +{ + "username": "regular", + "password": "asdasd", + "host": "http://localhost:8080" +} diff --git a/test/runtimeerror.xml b/test/runtimeerror.xml new file mode 100644 index 0000000..6e8e79a --- /dev/null +++ b/test/runtimeerror.xml @@ -0,0 +1,62 @@ + + + + + + SEQUENTIAL + + + + + + + + + + + + + + + + + + + + + + + + + + // Sample event script to add custom HTTP header to all outgoing REST, SOAP and HTTP(S) calls +// This code is often used for adding custom authentication to ReadyAPI functional tests + +// If hardcoding the token, uncomment and change line 5 +// token = '4567' + +// If your token is parameterized in Project level custom property, uncomment line 8 +// token = request.parent.testCase.testSuite.project.getProperty('auth_token').getValue() + +// To modify all outgoing calls, remove comments from lines 11 to 16 +// headers = request.requestHeaders +// if (headers.containsKey('auth_token2') == false) { +// headers.put('auth_token2', token) +// request.requestHeaders = headers +// } + + + // Save all test step results into files +// Change the directory path in line 5 to a location where you want to store details +// then uncomment lines 5 to 10 + +// filePath = 'C:\\tempOutputDirectory\\' +// fos = new java.io.FileOutputStream(filePath + testStepResult.testStep.label + '.txt', true) +// pw = new java.io.PrintWriter(fos) +// testStepResult.writeTo(pw) +// pw.close() +// fos.close() + + + + diff --git a/test/slow.xml b/test/slow.xml new file mode 100644 index 0000000..1889298 --- /dev/null +++ b/test/slow.xml @@ -0,0 +1,62 @@ + + + + + + SEQUENTIAL + + + + + + 5000 + + + + + + + + + + + + + + + + + + + + // Sample event script to add custom HTTP header to all outgoing REST, SOAP and HTTP(S) calls +// This code is often used for adding custom authentication to ReadyAPI functional tests + +// If hardcoding the token, uncomment and change line 5 +// token = '4567' + +// If your token is parameterized in Project level custom property, uncomment line 8 +// token = request.parent.testCase.testSuite.project.getProperty('auth_token').getValue() + +// To modify all outgoing calls, remove comments from lines 11 to 16 +// headers = request.requestHeaders +// if (headers.containsKey('auth_token2') == false) { +// headers.put('auth_token2', token) +// request.requestHeaders = headers +// } + + + // Save all test step results into files +// Change the directory path in line 5 to a location where you want to store details +// then uncomment lines 5 to 10 + +// filePath = 'C:\\tempOutputDirectory\\' +// fos = new java.io.FileOutputStream(filePath + testStepResult.testStep.label + '.txt', true) +// pw = new java.io.PrintWriter(fos) +// testStepResult.writeTo(pw) +// pw.close() +// fos.close() + + + + diff --git a/test/successful.xml b/test/successful.xml new file mode 100644 index 0000000..f14da13 --- /dev/null +++ b/test/successful.xml @@ -0,0 +1,74 @@ + + + + + + 1 + SEQUENTIAL + + + 1 + + + + + <xml-fragment/> + + http://localhost:8080 + + + No Authorization + No Authorization + + + + + + + + + + + + + + + + + + + + + + + // Sample event script to add custom HTTP header to all outgoing REST, SOAP and HTTP(S) calls +// This code is often used for adding custom authentication to ReadyAPI functional tests + +// If hardcoding the token, uncomment and change line 5 +// token = '4567' + +// If your token is parameterized in Project level custom property, uncomment line 8 +// token = request.parent.testCase.testSuite.project.getProperty('auth_token').getValue() + +// To modify all outgoing calls, remove comments from lines 11 to 16 +// headers = request.requestHeaders +// if (headers.containsKey('auth_token2') == false) { +// headers.put('auth_token2', token) +// request.requestHeaders = headers +// } + + + // Save all test step results into files +// Change the directory path in line 5 to a location where you want to store details +// then uncomment lines 5 to 10 + +// filePath = 'C:\\tempOutputDirectory\\' +// fos = new java.io.FileOutputStream(filePath + testStepResult.testStep.label + '.txt', true) +// pw = new java.io.PrintWriter(fos) +// testStepResult.writeTo(pw) +// pw.close() +// fos.close() + + + + diff --git a/test/testScript.py b/test/testScript.py new file mode 100644 index 0000000..09afd93 --- /dev/null +++ b/test/testScript.py @@ -0,0 +1,103 @@ +import os +from subprocess import Popen + +baseCli = 'node ../bin/testengine.js' +licenseServer = "localhost:1194" + +def startJob(projectPath): + startJob = ' '.join([baseCli, 'run project', projectPath, '-c admin.config']) + extractTestJobId = baseCli + " jobs list -c admin.config -c admin.config|sed -n 3p |sed 's/ *$//g'|rev|cut -d ' ' -f 2|rev" + os.system(startJob) + jobId = os.popen(extractTestJobId).read().strip() + return jobId + +def runAllCombinations(commands, flags, function): + for command in commands: + for flag in flags: + function(command, flag) + +def runCli(command, flag, jobId=''): + cli = ' '.join([baseCli, command, jobId, flag]) + print('\n' + cli) + os.system(cli+ '; echo exit status $?') + +if __name__ == '__main__': + commands = ['auditlog', + 'auditlog dump', + 'auditlog help', + + 'user list', + 'user add', + 'user add hej', + 'user add hej pw', + 'user add hej password', + 'user add hej password moar', + 'user edit hej2', + 'user edit hej admin=true', + 'user edit hej admin=false', + 'user edit hej password=pw', + 'user edit hej nope=asda', + 'user edit nope', + 'user delete', + 'user delete nope', + 'user delete hej', + + 'run', + 'run help', + 'run project', + 'run project help', + 'run project noneExisting.xml', + 'run project runtimeerror.xml', + 'run project validationerror.xml', + 'run project successful.xml', + + 'jobs list user=lol', + 'jobs list user=admin', + 'jobs list user=regular', + 'jobs help', + 'jobs prune before=2018-01-01', + 'jobs prune before=dasdasdas', + 'license install', + 'license install type=floating', + 'license install type=fixed', + 'license install type=noneExisting', + 'license install type=floating', + 'license install type=floating', + 'license uninstall', + 'license install type=floating ' + licenseServer, + 'license install type=floating noneExisting:1234', + 'license install type=floating file.txt', + 'license install type=floating noneExisting=text ' + licenseServer, + 'license install type=floating email=notMail ' + licenseServer, + 'license install type=floating firstName=oskar ' + licenseServer, + 'license install type=floating lastName=oskarsson ' + licenseServer, + 'license install type=floating email=oskar@oskarsson.com ' + licenseServer, + 'license install type=floating firstName=oskar lastName=oskarsson email=oskar@oskarsson.com ' + licenseServer + ] + + flags = ['-C', + '-c', + '-C admin.config', + '-H localhost:1231', + '-H localhost:8080', + '-c regularUser.config', + '-c admin.config'] + + jobCommands = ['jobs status', + 'jobs printReport', + 'jobs report', + 'jobs report output=.', + 'jobs report output=noneExisting', + 'jobs report output=. reportFileName=report', + 'jobs report output=output noneExisting=report.txt', + 'jobs report output=output reportFileName=report format=junit', + 'jobs report output=output reportFileName=report format=excel', + 'jobs report output=output reportFileName=report format=json', + 'jobs report output=output reportFileName=report format=pdf', + 'jobs report output=. reportFileName=report format=noneExisting' + ] + + runAllCombinations(commands, flags, lambda command, flag : runCli(command, flag)) + testJobId = startJob('successful.xml') + runAllCombinations(jobCommands, flags, lambda command, flag : runCli(command, flag, testJobId)) + runAllCombinations(['jobs cancel'], flags, lambda command, flag : runCli(command, flag, startJob('slow.xml'))) diff --git a/test/validationerror.xml b/test/validationerror.xml new file mode 100644 index 0000000..2a5c152 --- /dev/null +++ b/test/validationerror.xml @@ -0,0 +1,65 @@ + + + + + + SEQUENTIAL + + + + + + /home/jonathan/thefile.txt + 0 + 0 + false + + + + + + + + + + + + + + + + + + + + // Sample event script to add custom HTTP header to all outgoing REST, SOAP and HTTP(S) calls +// This code is often used for adding custom authentication to ReadyAPI functional tests + +// If hardcoding the token, uncomment and change line 5 +// token = '4567' + +// If your token is parameterized in Project level custom property, uncomment line 8 +// token = request.parent.testCase.testSuite.project.getProperty('auth_token').getValue() + +// To modify all outgoing calls, remove comments from lines 11 to 16 +// headers = request.requestHeaders +// if (headers.containsKey('auth_token2') == false) { +// headers.put('auth_token2', token) +// request.requestHeaders = headers +// } + + + // Save all test step results into files +// Change the directory path in line 5 to a location where you want to store details +// then uncomment lines 5 to 10 + +// filePath = 'C:\\tempOutputDirectory\\' +// fos = new java.io.FileOutputStream(filePath + testStepResult.testStep.label + '.txt', true) +// pw = new java.io.PrintWriter(fos) +// testStepResult.writeTo(pw) +// pw.close() +// fos.close() + + + + From 1f9e9838478df8e60ba8bc01a02e40101be12144 Mon Sep 17 00:00:00 2001 From: Jonathan Lundholm Date: Fri, 12 Feb 2021 13:07:46 +0100 Subject: [PATCH 6/9] TSERV-861 Removing some code duplication, adding a few more tests to the testScript and ensure that we return the correct status codes whenever we return print the usage. --- bin/auditlog_functions.js | 20 ++-- bin/jobs_functions.js | 17 +++- bin/license_functions.js | 8 +- bin/run_functions.js | 3 +- bin/shared_utils.js | 22 +++-- bin/testengine.js | 1 + bin/user_functions.js | 94 ++++++++----------- test/testScript.py | 190 +++++++++++++++++++++----------------- test/users.csv | 10 ++ 9 files changed, 197 insertions(+), 168 deletions(-) create mode 100644 test/users.csv diff --git a/bin/auditlog_functions.js b/bin/auditlog_functions.js index a46f2e2..88f453d 100644 --- a/bin/auditlog_functions.js +++ b/bin/auditlog_functions.js @@ -4,15 +4,19 @@ const request = require('superagent'); const config = require('./config').config; const sprintf = require('sprintf-js').sprintf; const util = require('./shared_utils'); +const process = require('process'); module.exports.dispatcher = function (args) { - if (args.length === 0) - return printModuleHelp(); + if (args.length === 0) { + printModuleHelp(); + process.exit(1); + } switch (args[0].toLowerCase()) { case 'dump': if (args.length < 1) { printModuleHelp(); + process.exit(1); } else { let options = util.optionsFromArgs(args.splice(1), [ 'format', 'date', 'user', 'limit', '=iso']); @@ -60,17 +64,7 @@ function dumpAuditLog(options) { .type('application/json') .send() .end((err, result) => { - if (err !== null) { - if ('code' in err) { - if (err.code === 'ECONNREFUSED') { - util.printErrorAndExit(sprintf("Connection refused: %s:%d", err.address, err.port)); - } else { - util.printErrorAndExit(sprintf("Error: %s:%s", err.code, err.message)); - } - } else { - util.printErrorAndExit(err.status + ': ' + err.message); - } - } + util.handleError(err); if (format === 'json') { if ('limit' in options) { util.output(JSON.stringify(result.body.slice(0, options['limit']))); diff --git a/bin/jobs_functions.js b/bin/jobs_functions.js index 43feebd..f1e132b 100644 --- a/bin/jobs_functions.js +++ b/bin/jobs_functions.js @@ -9,8 +9,10 @@ const process = require('process'); module.exports = { dispatcher: function (args) { - if (args.length === 0) - return printModuleHelp(); + if (args.length === 0) { + printModuleHelp(); + process.exit(1); + } switch (args[0].toLowerCase()) { case 'list': { @@ -22,6 +24,7 @@ module.exports = { case 'cancel': { if (args.length < 2) { printModuleHelp(); + process.exit(1); } else { terminateTestJob(args[1]); } @@ -30,6 +33,7 @@ module.exports = { case 'delete': { if (args.length < 2) { printModuleHelp(); + process.exit(1); } else { deleteTestJob(args[1]); } @@ -38,6 +42,7 @@ module.exports = { case 'status': { if (args.length < 2) { printModuleHelp(); + process.exit(1); } else { reportForTestJob(args[1]); } @@ -46,6 +51,7 @@ module.exports = { case 'report': { if (args.length < 4) { printModuleHelp(); + process.exit(1); } else { let jobId = args[args.length - 1]; let options = util.optionsFromArgs(args.splice(1), [ @@ -57,6 +63,7 @@ module.exports = { case 'printreport': { if (args.length < 2) { printModuleHelp(); + process.exit(1); } else { const testJobId = args[args.length - 1]; printReport(testJobId); @@ -150,7 +157,6 @@ function printReport(testjobId) { .accept('application/json') .send() .end((err, res) => { - const jsonReport = res.body; if (err !== null) { if (err.status === 404) { util.printErrorAndExit(`Testjob with id ${testjobId} not found`); @@ -158,7 +164,10 @@ function printReport(testjobId) { util.printErrorAndExit(err.status + ': ' + err.message); } } - util.output(utility.inspect(jsonReport, {showHidden: false, depth: null})); + if (res) { + const jsonReport = res.body; + util.output(utility.inspect(jsonReport, {showHidden: false, depth: null})); + } }); } diff --git a/bin/license_functions.js b/bin/license_functions.js index a9716ff..0fcbc82 100644 --- a/bin/license_functions.js +++ b/bin/license_functions.js @@ -8,8 +8,10 @@ const path = require('path'); const process = require('process'); module.exports.dispatcher = function (args) { - if (args.length === 0) - return printModuleHelp(); + if (args.length === 0) { + printModuleHelp(); + process.exit(1); + } switch (args[0].toLowerCase()) { case 'install': { @@ -21,6 +23,7 @@ module.exports.dispatcher = function (args) { 'email']); if (args.length < 2) { printModuleHelp(); + process.exit(1); } else { installLicense(options, args[args.length - 1]); } @@ -29,6 +32,7 @@ module.exports.dispatcher = function (args) { case 'uninstall': if (args.length < 1) { printModuleHelp(); + process.exit(1); } else { uninstallLicense() } diff --git a/bin/run_functions.js b/bin/run_functions.js index 06c8543..c8f8c3c 100644 --- a/bin/run_functions.js +++ b/bin/run_functions.js @@ -17,7 +17,8 @@ const utility = require('util'); module.exports.dispatcher = function (args) { if (args.length === 0) { - return printModuleHelp(); + printModuleHelp(); + process.exit(1); } let argsWithoutFilename = args.splice(1, args.length - 2); let options = util.optionsFromArgs(argsWithoutFilename, [ diff --git a/bin/shared_utils.js b/bin/shared_utils.js index a0de1cf..b0d033e 100644 --- a/bin/shared_utils.js +++ b/bin/shared_utils.js @@ -2,6 +2,7 @@ const config = require('./config').config; const process = require('process'); +const sprintf = require('sprintf-js').sprintf; module.exports.csvQuoteQuotes = function (stringValue) { return stringValue.replace(/["]/g, '""'); @@ -16,7 +17,7 @@ module.exports.booleanValue = function (unknownValue) { }; -module.exports.output = function (message, appendNewLine=true) { +module.exports.output = function (message, appendNewLine = true) { if (!config.quiet) { process.stdout.write(message); if (appendNewLine) @@ -118,13 +119,22 @@ module.exports.optionsFromArgs = function (args, validArguments = null) { return ret; }; +module.exports.handleError = function (err) { + if (err !== null) { + if ('code' in err) { + if (err.code === 'ECONNREFUSED') { + module.exports.printErrorAndExit(sprintf("Connection refused: %s:%d", err.address, err.port)); + } else { + module.exports.printErrorAndExit(sprintf("Error: %s:%s", err.code, err.message)); + } + } else { + module.exports.printErrorAndExit(err.status + ': ' + err.message); + } + } +} + module.exports.printErrorAndExit = function (errorMessage) { module.exports.error(errorMessage); process.exit(1); } -// module.exports.exitForUnknownOperation = function () { -// module.exports.error("Unknown operation"); -// process.exit(200); -// } - diff --git a/bin/testengine.js b/bin/testengine.js index 35d9aa7..690bf76 100755 --- a/bin/testengine.js +++ b/bin/testengine.js @@ -61,6 +61,7 @@ if (program.args.length > 0) { break; default: program.outputHelp(); + process.exit(1); break; } } diff --git a/bin/user_functions.js b/bin/user_functions.js index f0c9a6e..b29e6b7 100644 --- a/bin/user_functions.js +++ b/bin/user_functions.js @@ -9,13 +9,15 @@ const util = require('./shared_utils'); const process = require('process'); module.exports.dispatcher = function (args) { - if (args.length === 0) - return printModuleHelp(); + if (args.length === 0) { + printModuleHelp(); + process.exit(1); + } switch (args[0].toLowerCase()) { case 'add': if (args.length < 3) { - util.error("Usage: testengine user add "); + util.printErrorAndExit("Usage: testengine user add "); } else { addUser(args[1], args[2]) } @@ -23,7 +25,7 @@ module.exports.dispatcher = function (args) { case 'import': if (args.length < 2) { - util.error("Usage: testengine user import "); + util.printErrorAndExit("Usage: tes tengine user import "); } else { importUsers(args[1]) } @@ -31,7 +33,7 @@ module.exports.dispatcher = function (args) { case 'edit': if (args.length < 3) { - util.error("Usage: testengine user edit [password=newpassword] [admin=true/false]"); + util.printErrorAndExit("Usage: testengine user edit [password=newpassword] [admin=true/false]"); } else { let options = util.optionsFromArgs(args.splice(2), [ 'password', 'admin']); @@ -51,7 +53,7 @@ module.exports.dispatcher = function (args) { case 'del': case 'delete': if (args.length < 2) { - return util.error("Usage: testengine user delete "); + util.printErrorAndExit("Usage: testengine user delete "); } else { deleteUser(args[1]); } @@ -141,35 +143,35 @@ function importUsers(fileOrURL) { } } } - }).fromStream(stream) - .then((jsonObj) => { - for (let user of jsonObj) { - let isAdmin = false; - if ('admin' in user) { - isAdmin = user['admin']; - } - if (!('password' in user)) { - user['password'] = createRandomPassword(); - } - addUser(user['username'], user['password'], isAdmin, true, (err) => { - if (err == null) { - util.output(sprintf("%s,%s,%d", - util.csvQuoteQuotes(user['username']), - util.csvQuoteQuotes(user['password']), - user['admin'] ? 1 : 0)); - } else { - util.error('User ' + user['username'] + ' could not be imported'); + }).fromStream(stream).then((jsonObj) => { + for (let i = 0; i < jsonObj.length; ++i) { + let user = jsonObj[i]; + let isAdmin = false; + if ('admin' in user) { + isAdmin = user['admin']; + } + if (!('password' in user)) { + user['password'] = createRandomPassword(); + } + addUser(user['username'], user['password'], isAdmin, true, (err) => { + if (err == null) { + util.output(sprintf("%s,%s,%d", + util.csvQuoteQuotes(user['username']), + util.csvQuoteQuotes(user['password']), + user['admin'] ? 1 : 0)); + } else { + util.error('User ' + user['username'] + ' could not be imported'); + if (err.response) { util.error(err.status + ': ' + err.response.body.message); - failedImport = true; + } else { + util.error(err); } - }); - } - }).on('done', (error) => { - if (error) { - util.error(error) - } - if (failedImport) { - process.exit(1); + failedImport = true; + } + if (failedImport && i === jsonObj.length - 1) { + process.exit(1); + } + }); } }); } @@ -191,18 +193,8 @@ function updateUser(username, options) { .type('application/json') .send(payload) .end((err) => { - if (err !== null) { - if ('code' in err) { - if (err.code === 'ECONNREFUSED') { - util.printErrorAndExit(sprintf("Connection refused: %s:%d", err.address, err.port)); - } else { - util.printErrorAndExit(sprintf("Error: %s:%s", err.code, err.message)); - } - } else { - util.printErrorAndExit(err.status + ': ' + err.message); - } - } - util.output('User "' + username + '"successfully updated'); + util.handleError(err); + util.output('User "' + username + '" successfully updated'); }); } @@ -226,17 +218,7 @@ function listUsers(options) { .accept('application/json') .send() .end((err, res) => { - if (err !== null) { - if ('code' in err) { - if (err.code === 'ECONNREFUSED') { - util.printErrorAndExit(sprintf("Connection refused: %s:%d", err.address, err.port)); - } else { - util.printErrorAndExit(sprintf("Error: %s:%s", err.code, err.message)); - } - } else { - util.printErrorAndExit(err.status + ': ' + err.message); - } - } + util.handleError(err); switch (format) { case 'csv': dumpArrayAsCSV(res.body); diff --git a/test/testScript.py b/test/testScript.py index 09afd93..86be424 100644 --- a/test/testScript.py +++ b/test/testScript.py @@ -1,103 +1,121 @@ import os -from subprocess import Popen baseCli = 'node ../bin/testengine.js' licenseServer = "localhost:1194" + def startJob(projectPath): - startJob = ' '.join([baseCli, 'run project', projectPath, '-c admin.config']) - extractTestJobId = baseCli + " jobs list -c admin.config -c admin.config|sed -n 3p |sed 's/ *$//g'|rev|cut -d ' ' -f 2|rev" - os.system(startJob) - jobId = os.popen(extractTestJobId).read().strip() - return jobId + startJob = ' '.join([baseCli, 'run project', projectPath, '-c admin.config']) + extractTestJobId = baseCli + " jobs list -c admin.config -c admin.config|sed -n 3p |sed 's/ *$//g'|rev|cut -d ' ' -f 2|rev" + os.system(startJob) + jobId = os.popen(extractTestJobId).read().strip() + return jobId + def runAllCombinations(commands, flags, function): for command in commands: for flag in flags: function(command, flag) + def runCli(command, flag, jobId=''): cli = ' '.join([baseCli, command, jobId, flag]) print('\n' + cli) - os.system(cli+ '; echo exit status $?') + os.system(cli + '; echo exit status $?') + +def startSlowJobAndThenRunCli(command, flag): + testJobId = startJob('slow.xml') + runCli(command, flag, testJobId) + if __name__ == '__main__': - commands = ['auditlog', - 'auditlog dump', - 'auditlog help', - - 'user list', - 'user add', - 'user add hej', - 'user add hej pw', - 'user add hej password', - 'user add hej password moar', - 'user edit hej2', - 'user edit hej admin=true', - 'user edit hej admin=false', - 'user edit hej password=pw', - 'user edit hej nope=asda', - 'user edit nope', - 'user delete', - 'user delete nope', - 'user delete hej', - - 'run', - 'run help', - 'run project', - 'run project help', - 'run project noneExisting.xml', - 'run project runtimeerror.xml', - 'run project validationerror.xml', - 'run project successful.xml', - - 'jobs list user=lol', - 'jobs list user=admin', - 'jobs list user=regular', - 'jobs help', - 'jobs prune before=2018-01-01', - 'jobs prune before=dasdasdas', - 'license install', - 'license install type=floating', - 'license install type=fixed', - 'license install type=noneExisting', - 'license install type=floating', - 'license install type=floating', - 'license uninstall', - 'license install type=floating ' + licenseServer, - 'license install type=floating noneExisting:1234', - 'license install type=floating file.txt', - 'license install type=floating noneExisting=text ' + licenseServer, - 'license install type=floating email=notMail ' + licenseServer, - 'license install type=floating firstName=oskar ' + licenseServer, - 'license install type=floating lastName=oskarsson ' + licenseServer, - 'license install type=floating email=oskar@oskarsson.com ' + licenseServer, - 'license install type=floating firstName=oskar lastName=oskarsson email=oskar@oskarsson.com ' + licenseServer - ] - - flags = ['-C', - '-c', - '-C admin.config', - '-H localhost:1231', - '-H localhost:8080', - '-c regularUser.config', - '-c admin.config'] - - jobCommands = ['jobs status', - 'jobs printReport', - 'jobs report', - 'jobs report output=.', - 'jobs report output=noneExisting', - 'jobs report output=. reportFileName=report', - 'jobs report output=output noneExisting=report.txt', - 'jobs report output=output reportFileName=report format=junit', - 'jobs report output=output reportFileName=report format=excel', - 'jobs report output=output reportFileName=report format=json', - 'jobs report output=output reportFileName=report format=pdf', - 'jobs report output=. reportFileName=report format=noneExisting' - ] - - runAllCombinations(commands, flags, lambda command, flag : runCli(command, flag)) - testJobId = startJob('successful.xml') - runAllCombinations(jobCommands, flags, lambda command, flag : runCli(command, flag, testJobId)) - runAllCombinations(['jobs cancel'], flags, lambda command, flag : runCli(command, flag, startJob('slow.xml'))) + commands = ['auditlog', + 'auditlog dump', + 'auditlog help', + + 'user list', + 'user add', + 'user add hej', + 'user add hej pw', + 'user add hej password', + 'user add hej password moar', + 'user edit hej2', + 'user edit hej admin=true', + 'user edit hej admin=false', + 'user edit hej password=pw', + 'user edit hej nope=asda', + 'user edit nope', + 'user delete', + 'user delete nope', + 'user delete hej', + 'user import users.csv', + + 'run', + 'run help', + 'run project', + 'run project help', + 'run project noneExisting.xml', + 'run project runtimeerror.xml', + 'run project validationerror.xml', + 'run project successful.xml', + 'run project successful.xml testsuite="TestSuite 1"', + 'run project successful.xml testsuite="TestSuite 1" securitytest="blah"', + 'run project successful.xml testsuite="TestSuite 1" testcase="TestCase 1"', + 'run project successful.xml testcase="TestCase 1"', + 'run project successful.xml testcase="TestCase 1" securitytest="blah"', + 'run project testsuite="TestSuite 1" successful.xml', + 'run project testsuite="TestSuite 1" securitytest="blah" successful.xml', + 'run project testsuite="TestSuite 1" testcase="TestCase 1" successful.xml', + 'run project testcase="TestCase 1" successful.xml', + 'run project testcase="TestCase 1" securitytest="blah" successful.xml', + 'run project successful.xml printReport', + 'run project successful.xml printReport async', + + 'jobs list user=lol', + 'jobs list user=admin', + 'jobs list user=regular', + 'jobs help', + 'jobs prune before=2018-01-01', + 'jobs prune before=dasdasdas', + 'license install', + 'license install type=floating', + 'license install type=fixed', + 'license install type=noneExisting', + 'license install type=floating', + 'license install type=floating', + 'license uninstall', + 'license install type=floating ' + licenseServer, + 'license install type=floating noneExisting:1234', + 'license install type=floating file.txt', + 'license install type=floating noneExisting=text ' + licenseServer, + 'license install type=floating email=notMail ' + licenseServer, + 'license install type=floating firstName=oskar ' + licenseServer, + 'license install type=floating lastName=oskarsson ' + licenseServer, + 'license install type=floating email=oskar@oskarsson.com ' + licenseServer, + 'license install type=floating firstName=oskar lastName=oskarsson email=oskar@oskarsson.com ' + licenseServer] + + flags = ['-C', + '-c', + '-C admin.config', + '-H localhost:1231', + '-H localhost:8080', + '-c regularUser.config', + '-c admin.config'] + + jobCommands = ['jobs status', + 'jobs printReport', + 'jobs report', + 'jobs report output=.', + 'jobs report output=noneExisting', + 'jobs report output=. reportFileName=report', + 'jobs report output=output noneExisting=report.txt', + 'jobs report output=output reportFileName=report format=junit', + 'jobs report output=output reportFileName=report format=excel', + 'jobs report output=output reportFileName=report format=json', + 'jobs report output=output reportFileName=report format=pdf', + 'jobs report output=. reportFileName=report format=noneExisting'] + + runAllCombinations(commands, flags, lambda command, flag: runCli(command, flag)) + testJobId = startJob('successful.xml') + runAllCombinations(jobCommands, flags, lambda command, flag: runCli(command, flag, testJobId)) + runAllCombinations(['jobs cancel'], flags, startSlowJobAndThenRunCli) diff --git a/test/users.csv b/test/users.csv new file mode 100644 index 0000000..e21915c --- /dev/null +++ b/test/users.csv @@ -0,0 +1,10 @@ +username,password,admin +correctAdmin,thepassword,true +correctRegularUser,thepassword,false +longrow,password,false,more +shortrow,password +shortpassword,pw,true +,nousername,false +nopassword,,false +incorrectAdminString,password,blargh +noadminstring,password, From 7a21788b120cd795578bf122b9ea3f37171c7ed9 Mon Sep 17 00:00:00 2001 From: Jonathan Lundholm Date: Mon, 15 Feb 2021 15:14:34 +0100 Subject: [PATCH 7/9] TSERV-861 adding README information. --- README.md | 4 ++++ test/successful.xml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8715266..66fd9ce 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,10 @@ When a config file is present, it is possible to override the values using the c There is currently no support for encrypting the config file but normal file system security should make it possible to restrict reading it to the user running the tool. +TestEngine-CLI will return with exit status code 0 if it successfully carried out the operation. It will return with +exit status code 1 if it failed to execute the command or parts of, including if a test job fails when it tries to run +a project or some user couldn't be added while importing. + ## Test Jobs The tool can submit test jobs, list jobs which has been submitted (only admins can see other users' jobs) and purge old jobs from the server. diff --git a/test/successful.xml b/test/successful.xml index f14da13..279d826 100644 --- a/test/successful.xml +++ b/test/successful.xml @@ -1,5 +1,5 @@ - + From 25f2abfe6cdd24f8227df0d1ab74d3528232132d Mon Sep 17 00:00:00 2001 From: Jonathan Lundholm Date: Mon, 15 Feb 2021 17:47:25 +0100 Subject: [PATCH 8/9] TSERV-861 Porting testscript from python to js, adding a comment that describes how to run it. Fixing minor errors. --- bin/user_functions.js | 4 +- test/testScript.js | 136 ++++++++++++++++++++++++++++++++++++++++++ test/testScript.py | 121 ------------------------------------- 3 files changed, 138 insertions(+), 123 deletions(-) create mode 100644 test/testScript.js delete mode 100644 test/testScript.py diff --git a/bin/user_functions.js b/bin/user_functions.js index b29e6b7..3bb7450 100644 --- a/bin/user_functions.js +++ b/bin/user_functions.js @@ -25,7 +25,7 @@ module.exports.dispatcher = function (args) { case 'import': if (args.length < 2) { - util.printErrorAndExit("Usage: tes tengine user import "); + util.printErrorAndExit("Usage: testengine user import "); } else { importUsers(args[1]) } @@ -62,7 +62,7 @@ module.exports.dispatcher = function (args) { printModuleHelp(); break; default: - util.printErrorAndExit("Unknown operation") + util.printErrorAndExit("Unknown operation"); } }; diff --git a/test/testScript.js b/test/testScript.js new file mode 100644 index 0000000..4c12d17 --- /dev/null +++ b/test/testScript.js @@ -0,0 +1,136 @@ +/** This script is used to test all commands in testengine. It will run most operations in testengine-cli with a few flag + * combinations and print it to screen. A tester can then read the output to see how the cli behaves. Together with the + * script there are a few readyapi-projects and login configurations for testengine. Assumes the testengine instance is + * running at localhost:8080 and has the logins admin/password, regularUser/asdasd. + * To run the script you need node.js. Ensure the working directory is the test-folder and run: + * node testScript.js + */ + +const {execSync, exec} = require('child_process'); + +const baseCli = 'node ../bin/testengine.js'; +const licenseServer = 'localhost:1194'; + +function startJob(projectPath) { + let startJob = [baseCli, 'run project', projectPath, '-c admin.config'].join(' '); + let extractTestJobId = baseCli + " jobs list -c admin.config -c admin.config|sed -n 3p |sed 's/ *$//g'|rev|cut -d ' ' -f 2|rev" + exec(startJob) + let jobId = execSync(extractTestJobId).toString().trim() + return jobId +} + +function runAllCombinations(commands, flags, fn) { + for (let i = 0; i < commands.length; ++i) { + for (let j = 0; j < flags.length; ++j) { + fn(commands[i], flags[j]) + } + } +} + +function runCli(command, flag, jobId = '') { + let cli = [baseCli, command, jobId, flag].join(' '); + console.log('\n' + cli); + try { + console.log(execSync(cli).toString() + 'exit status 0'); + } catch (error) { + console.log('' + error.stdout + 'exit status ' + error.status); + } +} + + +function startSlowJobAndThenRunCli(command, flag) { + let testJobId = startJob('slow.xml') + runCli(command, flag, testJobId) +} + + +let commands = ['auditlog', + 'auditlog dump', + 'auditlog help', + + 'user list', + 'user add', + 'user add hej', + 'user add hej pw', + 'user add hej password', + 'user add hej password moar', + 'user edit hej2', + 'user edit hej admin=true', + 'user edit hej admin=false', + 'user edit hej password=pw', + 'user edit hej nope=asda', + 'user edit nope', + 'user delete', + 'user delete nope', + 'user delete hej', + 'user import users.csv', + + 'run', + 'run help', + 'run project', + 'run project help', + 'run project noneExisting.xml', + 'run project runtimeerror.xml', + 'run project validationerror.xml', + 'run project successful.xml', + 'run project successful.xml testsuite="TestSuite 1"', + 'run project successful.xml testsuite="TestSuite 1" securitytest="blah"', + 'run project successful.xml testsuite="TestSuite 1" testcase="TestCase 1"', + 'run project successful.xml testcase="TestCase 1"', + 'run project successful.xml testcase="TestCase 1" securitytest="blah"', + 'run project testsuite="TestSuite 1" successful.xml', + 'run project testsuite="TestSuite 1" securitytest="blah" successful.xml', + 'run project testsuite="TestSuite 1" testcase="TestCase 1" successful.xml', + 'run project testcase="TestCase 1" successful.xml', + 'run project testcase="TestCase 1" securitytest="blah" successful.xml', + 'run project successful.xml printReport', + 'run project successful.xml printReport async', + + 'jobs list user=lol', + 'jobs list user=admin', + 'jobs list user=regular', + 'jobs help', + 'jobs prune before=2018-01-01', + 'jobs prune before=dasdasdas', + 'license install', + 'license install type=floating', + 'license install type=fixed', + 'license install type=noneExisting', + 'license install type=floating', + 'license install type=floating', + 'license uninstall', + 'license install type=floating ' + licenseServer, + 'license install type=floating noneExisting:1234', + 'license install type=floating file.txt', + 'license install type=floating noneExisting=text ' + licenseServer, + 'license install type=floating email=notMail ' + licenseServer, + 'license install type=floating firstName=oskar ' + licenseServer, + 'license install type=floating lastName=oskarsson ' + licenseServer, + 'license install type=floating email=oskar@oskarsson.com ' + licenseServer, + 'license install type=floating firstName=oskar lastName=oskarsson email=oskar@oskarsson.com ' + licenseServer] + +let flags = ['-C', + '-c', + '-C admin.config', + '-H localhost:1231', + '-H localhost:8080', + '-c regularUser.config', + '-c admin.config'] + +let jobCommands = ['jobs status', + 'jobs printReport', + 'jobs report', + 'jobs report output=.', + 'jobs report output=noneExisting', + 'jobs report output=. reportFileName=report', + 'jobs report output=output noneExisting=report.txt', + 'jobs report output=output reportFileName=report format=junit', + 'jobs report output=output reportFileName=report format=excel', + 'jobs report output=output reportFileName=report format=json', + 'jobs report output=output reportFileName=report format=pdf', + 'jobs report output=. reportFileName=report format=noneExisting'] + +runAllCombinations(commands, flags, (command, flag) => runCli(command, flag)); +let testJobId = startJob('successful.xml'); +runAllCombinations(jobCommands, flags, (command, flag) => runCli(command, flag, testJobId)); +runAllCombinations(['jobs cancel'], flags, startSlowJobAndThenRunCli) diff --git a/test/testScript.py b/test/testScript.py deleted file mode 100644 index 86be424..0000000 --- a/test/testScript.py +++ /dev/null @@ -1,121 +0,0 @@ -import os - -baseCli = 'node ../bin/testengine.js' -licenseServer = "localhost:1194" - - -def startJob(projectPath): - startJob = ' '.join([baseCli, 'run project', projectPath, '-c admin.config']) - extractTestJobId = baseCli + " jobs list -c admin.config -c admin.config|sed -n 3p |sed 's/ *$//g'|rev|cut -d ' ' -f 2|rev" - os.system(startJob) - jobId = os.popen(extractTestJobId).read().strip() - return jobId - - -def runAllCombinations(commands, flags, function): - for command in commands: - for flag in flags: - function(command, flag) - - -def runCli(command, flag, jobId=''): - cli = ' '.join([baseCli, command, jobId, flag]) - print('\n' + cli) - os.system(cli + '; echo exit status $?') - -def startSlowJobAndThenRunCli(command, flag): - testJobId = startJob('slow.xml') - runCli(command, flag, testJobId) - - -if __name__ == '__main__': - commands = ['auditlog', - 'auditlog dump', - 'auditlog help', - - 'user list', - 'user add', - 'user add hej', - 'user add hej pw', - 'user add hej password', - 'user add hej password moar', - 'user edit hej2', - 'user edit hej admin=true', - 'user edit hej admin=false', - 'user edit hej password=pw', - 'user edit hej nope=asda', - 'user edit nope', - 'user delete', - 'user delete nope', - 'user delete hej', - 'user import users.csv', - - 'run', - 'run help', - 'run project', - 'run project help', - 'run project noneExisting.xml', - 'run project runtimeerror.xml', - 'run project validationerror.xml', - 'run project successful.xml', - 'run project successful.xml testsuite="TestSuite 1"', - 'run project successful.xml testsuite="TestSuite 1" securitytest="blah"', - 'run project successful.xml testsuite="TestSuite 1" testcase="TestCase 1"', - 'run project successful.xml testcase="TestCase 1"', - 'run project successful.xml testcase="TestCase 1" securitytest="blah"', - 'run project testsuite="TestSuite 1" successful.xml', - 'run project testsuite="TestSuite 1" securitytest="blah" successful.xml', - 'run project testsuite="TestSuite 1" testcase="TestCase 1" successful.xml', - 'run project testcase="TestCase 1" successful.xml', - 'run project testcase="TestCase 1" securitytest="blah" successful.xml', - 'run project successful.xml printReport', - 'run project successful.xml printReport async', - - 'jobs list user=lol', - 'jobs list user=admin', - 'jobs list user=regular', - 'jobs help', - 'jobs prune before=2018-01-01', - 'jobs prune before=dasdasdas', - 'license install', - 'license install type=floating', - 'license install type=fixed', - 'license install type=noneExisting', - 'license install type=floating', - 'license install type=floating', - 'license uninstall', - 'license install type=floating ' + licenseServer, - 'license install type=floating noneExisting:1234', - 'license install type=floating file.txt', - 'license install type=floating noneExisting=text ' + licenseServer, - 'license install type=floating email=notMail ' + licenseServer, - 'license install type=floating firstName=oskar ' + licenseServer, - 'license install type=floating lastName=oskarsson ' + licenseServer, - 'license install type=floating email=oskar@oskarsson.com ' + licenseServer, - 'license install type=floating firstName=oskar lastName=oskarsson email=oskar@oskarsson.com ' + licenseServer] - - flags = ['-C', - '-c', - '-C admin.config', - '-H localhost:1231', - '-H localhost:8080', - '-c regularUser.config', - '-c admin.config'] - - jobCommands = ['jobs status', - 'jobs printReport', - 'jobs report', - 'jobs report output=.', - 'jobs report output=noneExisting', - 'jobs report output=. reportFileName=report', - 'jobs report output=output noneExisting=report.txt', - 'jobs report output=output reportFileName=report format=junit', - 'jobs report output=output reportFileName=report format=excel', - 'jobs report output=output reportFileName=report format=json', - 'jobs report output=output reportFileName=report format=pdf', - 'jobs report output=. reportFileName=report format=noneExisting'] - - runAllCombinations(commands, flags, lambda command, flag: runCli(command, flag)) - testJobId = startJob('successful.xml') - runAllCombinations(jobCommands, flags, lambda command, flag: runCli(command, flag, testJobId)) - runAllCombinations(['jobs cancel'], flags, startSlowJobAndThenRunCli) From 1ec2d8a636c456ae6bfdef955ee90923cf51730b Mon Sep 17 00:00:00 2001 From: Jonathan Lundholm Date: Mon, 15 Feb 2021 18:48:24 +0100 Subject: [PATCH 9/9] TSERV-861 adding semicolons --- test/testScript.js | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/test/testScript.js b/test/testScript.js index 4c12d17..9e13eb6 100644 --- a/test/testScript.js +++ b/test/testScript.js @@ -13,16 +13,16 @@ const licenseServer = 'localhost:1194'; function startJob(projectPath) { let startJob = [baseCli, 'run project', projectPath, '-c admin.config'].join(' '); - let extractTestJobId = baseCli + " jobs list -c admin.config -c admin.config|sed -n 3p |sed 's/ *$//g'|rev|cut -d ' ' -f 2|rev" - exec(startJob) - let jobId = execSync(extractTestJobId).toString().trim() - return jobId + let extractTestJobId = baseCli + " jobs list -c admin.config -c admin.config|sed -n 3p |sed 's/ *$//g'|rev|cut -d ' ' -f 2|rev"; + exec(startJob); + let jobId = execSync(extractTestJobId).toString().trim(); + return jobId; } function runAllCombinations(commands, flags, fn) { for (let i = 0; i < commands.length; ++i) { for (let j = 0; j < flags.length; ++j) { - fn(commands[i], flags[j]) + fn(commands[i], flags[j]); } } } @@ -37,13 +37,11 @@ function runCli(command, flag, jobId = '') { } } - function startSlowJobAndThenRunCli(command, flag) { - let testJobId = startJob('slow.xml') - runCli(command, flag, testJobId) + let testJobId = startJob('slow.xml'); + runCli(command, flag, testJobId); } - let commands = ['auditlog', 'auditlog dump', 'auditlog help', @@ -107,7 +105,7 @@ let commands = ['auditlog', 'license install type=floating firstName=oskar ' + licenseServer, 'license install type=floating lastName=oskarsson ' + licenseServer, 'license install type=floating email=oskar@oskarsson.com ' + licenseServer, - 'license install type=floating firstName=oskar lastName=oskarsson email=oskar@oskarsson.com ' + licenseServer] + 'license install type=floating firstName=oskar lastName=oskarsson email=oskar@oskarsson.com ' + licenseServer]; let flags = ['-C', '-c', @@ -115,7 +113,7 @@ let flags = ['-C', '-H localhost:1231', '-H localhost:8080', '-c regularUser.config', - '-c admin.config'] + '-c admin.config']; let jobCommands = ['jobs status', 'jobs printReport', @@ -128,9 +126,9 @@ let jobCommands = ['jobs status', 'jobs report output=output reportFileName=report format=excel', 'jobs report output=output reportFileName=report format=json', 'jobs report output=output reportFileName=report format=pdf', - 'jobs report output=. reportFileName=report format=noneExisting'] + 'jobs report output=. reportFileName=report format=noneExisting']; runAllCombinations(commands, flags, (command, flag) => runCli(command, flag)); let testJobId = startJob('successful.xml'); runAllCombinations(jobCommands, flags, (command, flag) => runCli(command, flag, testJobId)); -runAllCombinations(['jobs cancel'], flags, startSlowJobAndThenRunCli) +runAllCombinations(['jobs cancel'], flags, startSlowJobAndThenRunCli);