UNPKG

loadmill

Version:

A node.js module for running load tests and functional tests on loadmill.com

233 lines (232 loc) 14.1 kB
"use strict"; exports.__esModule = true; var tslib_1 = require("tslib"); var Loadmill = require("./index"); var program = require("commander"); var utils_1 = require("./utils"); var reporter_1 = require("./reporter"); program .usage("<testPlanId | load-config-file> -t <token> [options] [parameter=value...]") .description("Run a test plan (default option) or a load test on loadmill.com.\n " + "You may set parameter values by passing space-separated 'name=value' pairs, e.g. 'host=www.myapp.com port=80' or supply a file using --parameters-file.\n\n " + "Learn more at https://www.npmjs.com/package/loadmill#cli") .option("-t, --token <token>", "Loadmill API Token. You must provide a token in order to run tests.") .option("-l, --load-test", "Launch a load test.") .option("--test-plan", "Launch a test plan (default option).") .option("-p, --parallel <parallel>", "Set the concurrency of a running test suites in a test plan") .option("--additional-description <description>", "Add an additional description at the end of the current suite's description - available only for test suites.") .option("--labels <labels>", "Run flows that are assigned to a specific label (when running a test suite).. Multiple labels can be provided by seperated them with ',' (e.g. 'label1,label2').") .option("--labels-expression <labelsExpression>", "Run a test plan's suites with flows that match the labels expression. An expression may contain the characters ( ) & | ! (e.g. '(label1 | label2) & !label3')") .option("--pool <pool>", "Execute tests from a dedicated agent's pool (when using private agent)") .option("--tags <tags>", "Tag a test plan run with a comma separated list of tags (e.g. 'tag1,tag2')") .option("-w, --wait", "Wait for the test to finish.") .option("-n, --no-bail", "Return exit code 0 even if test fails.") .option("-q, --quiet", "Do not print out anything (except errors).") .option("-v, --verbose", "Print out extra information for debugging.") .option("-r, --report", "Print out Test Suite Flow Runs report when the plan has ended.") .option("--errors-report", "Print out Test Suite Flow Runs errors report when the plan has ended.") .option("-j, --junit-report", "Create Test Suite (junit style) report when the suite has ended.") .option("--junit-report-path <junitReportPath>", "Save junit styled report to a path (defaults to current location).") .option("-m, --mochawesome-report", "Create Test Suite (mochawesome style) report when the suite has ended.") .option("--mochawesome-report-path <mochawesomeReportPath>", "Save JSON mochawesome styled report to a path (defaults to current location).") .option("--colors", "Print test results in color") .option("-b, --branch <branch>", "Run the test plan's suites from a GitHub branch. The latest version of the selected Git branch will be used as the test configuration for the chosen Test Plan") .option("--retry-failed-flows <numberOfRetries>", "Configure the test plan to re-run failed flows in case your tested system is unstable. Tests that pass after a retry will be considered successful.") .option("--parameters-file <parametersFile>", "Supply a file with parameters to override. File format should be 'name=value' divided by new line.") .option("--inlineParameterOverride", "Override parameters strategy: by default, overrided parameters are appended to the end of the parameters list. Using this flag will replace the parameters inline.") .option("--apiCatalogService <apiCatalogService>", "Use the provided service when mapping the APIs in the catalog. Service will be created if not exist") .option("--turbo-parallel", "Run the test plan in turbo mode") .parse(process.argv); start()["catch"](function (err) { console.error(err); process.exit(2); }); function start() { return tslib_1.__awaiter(this, void 0, void 0, function () { var wait, bail, quiet, token, verbose, colors, report, errorsReport, junitReport, junitReportPath, mochawesomeReport, mochawesomeReportPath, parallel, loadTest, testPlan, additionalDescription, labels, labelsExpression, pool, tags, branch, retryFailedFlows, parametersFile, inlineParameterOverride, apiCatalogService, turboParallel, _a, input, rawParams, logger, parameters, loadmill, testFailed, testStopped, res, planLabels, planTags, running, e_1, extInfo, configFile, res_1, id; return tslib_1.__generator(this, function (_b) { switch (_b.label) { case 0: wait = program.wait, bail = program.bail, quiet = program.quiet, token = program.token, verbose = program.verbose, colors = program.colors, report = program.report, errorsReport = program.errorsReport, junitReport = program.junitReport, junitReportPath = program.junitReportPath, mochawesomeReport = program.mochawesomeReport, mochawesomeReportPath = program.mochawesomeReportPath, parallel = program.parallel, loadTest = program.loadTest, testPlan = program.testPlan, additionalDescription = program.additionalDescription, labels = program.labels, labelsExpression = program.labelsExpression, pool = program.pool, tags = program.tags, branch = program.branch, retryFailedFlows = program.retryFailedFlows, parametersFile = program.parametersFile, inlineParameterOverride = program.inlineParameterOverride, apiCatalogService = program.apiCatalogService, turboParallel = program.turboParallel, _a = program.args, input = _a[0], rawParams = _a.slice(1); logger = utils_1.getLogger({ verbose: verbose, colors: colors }); if (!token) { validationFailed("No API token provided."); } parameters = toParams(rawParams, parametersFile); if (verbose) { // verbose trumps quiet: quiet = false; logger.log("Inputs:", { wait: wait, bail: bail, quiet: quiet, token: token, verbose: verbose, colors: colors, report: report, errorsReport: errorsReport, junitReport: junitReport, junitReportPath: junitReportPath, mochawesomeReport: mochawesomeReport, mochawesomeReportPath: mochawesomeReportPath, parallel: parallel, input: input, loadTest: loadTest, testPlan: testPlan, additionalDescription: additionalDescription, labels: labels, labelsExpression: labelsExpression, pool: pool, tags: tags, branch: branch, retryFailedFlows: retryFailedFlows, inlineParameterOverride: inlineParameterOverride, apiCatalogService: apiCatalogService, turboParallel: turboParallel, parameters: parameters }); } loadmill = Loadmill({ token: token }); testFailed = function (msg) { logger.log(""); logger.error("\u274C " + msg + "."); if (bail) { process.exit(1); } }; testStopped = function (msg) { logger.log(""); logger.error("\u270B " + msg + "."); if (bail) { process.exit(1); } }; if (!(testPlan || !loadTest)) return [3 /*break*/, 13]; if (!utils_1.isUUID(input)) { //if test plan flag is on then the input should be uuid validationFailed("Test plan run flag is on but no valid test plan id was provided."); } planLabels = utils_1.convertStrToArr(labels); planTags = utils_1.convertStrToArr(tags); _b.label = 1; case 1: _b.trys.push([1, 11, , 12]); logger.verbose("Executing test plan with id " + input); return [4 /*yield*/, loadmill.runTestPlan({ id: input, options: { additionalDescription: additionalDescription, labels: planLabels, labelsExpression: labelsExpression, pool: pool, tags: planTags, parallel: parallel, branch: branch, maxFlakyFlowRetries: retryFailedFlows, inlineParameterOverride: inlineParameterOverride, apiCatalogService: apiCatalogService, turboParallel: turboParallel } }, parameters)]; case 2: running = _b.sent(); if (!(running && running.id)) return [3 /*break*/, 9]; if (!wait) return [3 /*break*/, 8]; logger.verbose("Waiting for test plan run with id", running.id); return [4 /*yield*/, loadmill.wait(running)]; case 3: res = _b.sent(); if (!quiet) { logger.log(res ? utils_1.getObjectAsString(res, colors) : running.id); } if (report && res.testSuitesRuns) { utils_1.printTestSuitesRunsReport(res.description, res.testSuitesRuns, logger, colors); } if (errorsReport && res.testSuitesRuns) { utils_1.printOnlyFailedFlowRunsReport(res.testSuitesRuns, logger, colors); } if (!res) return [3 /*break*/, 7]; if (!junitReport) return [3 /*break*/, 5]; return [4 /*yield*/, reporter_1.junitReport(res, token, junitReportPath)]; case 4: _b.sent(); _b.label = 5; case 5: if (!mochawesomeReport) return [3 /*break*/, 7]; return [4 /*yield*/, reporter_1.mochawesomeReport(res, token, mochawesomeReportPath)]; case 6: _b.sent(); _b.label = 7; case 7: if (res && res.status === 'STOPPED') { testStopped("Test plan with id " + (res.id || input) + " has stopped"); } if (res && res.passed != null && !res.passed) { testFailed("Test plan with id " + (res.id || input) + " has failed"); } _b.label = 8; case 8: return [3 /*break*/, 10]; case 9: testFailed("Couldn't run test plan with id " + input); _b.label = 10; case 10: return [3 /*break*/, 12]; case 11: e_1 = _b.sent(); if (verbose) { logger.error(e_1); } extInfo = e_1.response && e_1.response.res && e_1.response.res.text; testFailed("Couldn't run test plan with id " + input + " " + (extInfo ? extInfo : '')); return [3 /*break*/, 12]; case 12: return [3 /*break*/, 17]; case 13: configFile = input; if (!configFile) { validationFailed("No configuration file were provided."); } logger.verbose("Launching " + configFile + " as load test"); return [4 /*yield*/, loadmill.run(configFile, parameters)]; case 14: id = _b.sent(); if (!(wait && loadTest)) return [3 /*break*/, 16]; logger.verbose("Waiting for test:", res_1 ? res_1.id : id); return [4 /*yield*/, loadmill.wait(res_1 || id)]; case 15: res_1 = _b.sent(); _b.label = 16; case 16: if (!quiet) { logger.log(JSON.stringify(res_1, null, 4) || id); } if (res_1 && res_1.passed != null && !res_1.passed) { logger.error("\u274C Test " + configFile + " failed."); if (bail) { process.exit(1); } } _b.label = 17; case 17: return [2 /*return*/]; } }); }); } function validationFailed() { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } console.log(''); console.error.apply(console, args); console.log(''); program.outputHelp(); process.exit(3); } function toParams(rawParams, filePath) { try { var paramsArray = filePath ? tslib_1.__spreadArray(tslib_1.__spreadArray([], utils_1.readRawParams(filePath)), rawParams) : rawParams; return utils_1.toLoadmillParams(paramsArray); } catch (err) { validationFailed(err.message); return {}; } }