UNPKG

loadmill

Version:

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

337 lines (336 loc) 15.8 kB
"use strict"; var tslib_1 = require("tslib"); require("./polyfills"); var fs = require("fs"); var http_request_1 = require("./http-request"); var utils_1 = require("./utils"); var reporter_1 = require("./reporter"); var TEST_PLAN_POLL_INTERVAL_IN_MS = 10 * 1000; // 10 seconds function Loadmill(options) { var _a = options, token = _a.token, _testingServerHost = _a._testingServerHost; var testingServer = _testingServerHost ? "https://" + _testingServerHost : utils_1.TESTING_ORIGIN; var testPlansAPI = testingServer + "/api/test-plans"; function _wait(testDefOrId, callback) { return tslib_1.__awaiter(this, void 0, void 0, function () { var resolve, reject, testDef, apiUrl, webUrl, retries, intervalId; var _this = this; return tslib_1.__generator(this, function (_a) { testDef = typeof testDefOrId === 'string' ? { id: testDefOrId, type: Loadmill.TYPES.LOAD } : testDefOrId; apiUrl = getTestAPIUrl(testDef, testingServer); webUrl = getTestWebUrl(testDef, testingServer); retries = 1; intervalId = setInterval(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () { var body, bodyWithFlows, testResult, err_1; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 5, , 6]); return [4 /*yield*/, http_request_1.sendHttpRequest({ url: apiUrl, token: token })]; case 1: body = (_a.sent()).body; if (!isTestInFinalState(body, testDef.type)) return [3 /*break*/, 4]; clearInterval(intervalId); if (!(testDef.type === Loadmill.TYPES.TEST_PLAN)) return [3 /*break*/, 3]; return [4 /*yield*/, http_request_1.sendHttpRequest({ url: apiUrl, query: { fetchAllFlows: true, groupFlowAttempts: true }, token: token })]; case 2: bodyWithFlows = (_a.sent()).body; body = bodyWithFlows; _a.label = 3; case 3: testResult = toTestResult(testDef, webUrl, body); redactData(testResult, body); if (callback) { callback(null, testResult); } else { resolve(testResult); } _a.label = 4; case 4: return [3 /*break*/, 6]; case 5: err_1 = _a.sent(); if (retries < 3) { retries++; return [2 /*return*/]; } else { clearInterval(intervalId); } if (callback) { callback(err_1, null); } else { reject(err_1); } return [3 /*break*/, 6]; case 6: return [2 /*return*/]; } }); }); }, TEST_PLAN_POLL_INTERVAL_IN_MS); return [2 /*return*/, callback ? null : new Promise(function (_resolve, _reject) { resolve = _resolve; reject = _reject; })]; }); }); } function _runTestPlan(testPlan, params) { var _a; return tslib_1.__awaiter(this, void 0, void 0, function () { var testPlanId, overrideParameters, labels, labelsExpression, additionalDescription, pool, tags, parallel, branch, inlineParameterOverride, maxFlakyFlowRetries, apiCatalogService, turboParallel, _b, testPlanRunId, err; return tslib_1.__generator(this, function (_c) { switch (_c.label) { case 0: testPlanId = testPlan.id; overrideParameters = toParams(params, (_a = testPlan.options) === null || _a === void 0 ? void 0 : _a.parametersFile); labels = testPlan.options && testPlan.options.labels && utils_1.filterLabels(testPlan.options.labels); labelsExpression = testPlan.options && testPlan.options.labelsExpression; additionalDescription = testPlan.options && testPlan.options.additionalDescription; pool = testPlan.options && testPlan.options.pool; tags = testPlan.options && testPlan.options.tags && utils_1.filterTags(testPlan.options.tags); parallel = testPlan.options && testPlan.options.parallel; branch = testPlan.options && testPlan.options.branch; inlineParameterOverride = !!(testPlan.options && testPlan.options.inlineParameterOverride); maxFlakyFlowRetries = testPlan.options && testPlan.options.maxFlakyFlowRetries; apiCatalogService = testPlan.options && testPlan.options.apiCatalogService; turboParallel = !!(testPlan.options && testPlan.options.turboParallel); return [4 /*yield*/, http_request_1.sendHttpRequest({ method: http_request_1.HttpMethods.POST, url: testPlansAPI + "/" + testPlanId + "/run", body: { overrideParameters: overrideParameters, additionalDescription: additionalDescription, labels: labels, pool: pool, parallel: parallel, tags: tags, branch: branch, maxFlakyFlowRetries: maxFlakyFlowRetries, labelsExpression: labelsExpression, inlineParameterOverride: inlineParameterOverride, apiCatalogService: apiCatalogService, turboParallel: turboParallel }, token: token })]; case 1: _b = (_c.sent()).body, testPlanRunId = _b.testPlanRunId, err = _b.err; if (err || !testPlanRunId) { console.error(err ? JSON.stringify(err) : "The server encountered an error while handling the request"); return [2 /*return*/]; } return [2 /*return*/, { id: testPlanRunId, type: Loadmill.TYPES.TEST_PLAN }]; } }); }); } function _junitReport(testResult, path) { return tslib_1.__awaiter(this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) { return [2 /*return*/, reporter_1.junitReport(testResult, token, path)]; }); }); } function _mochawesomeReport(testResult, path) { return tslib_1.__awaiter(this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) { return [2 /*return*/, reporter_1.mochawesomeReport(testResult, token, path)]; }); }); } return { run: function (config, paramsOrCallback, callback) { var _this = this; return wrap(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () { var testId; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: config = toConfig(config, paramsOrCallback); return [4 /*yield*/, http_request_1.sendHttpRequest({ method: http_request_1.HttpMethods.POST, url: testingServer + "/api/tests", body: config, token: token })]; case 1: testId = (_a.sent()).body.testId; return [4 /*yield*/, http_request_1.sendHttpRequest({ method: http_request_1.HttpMethods.PUT, url: testingServer + "/api/tests/" + testId + "/load", token: token })]; case 2: _a.sent(); return [2 /*return*/, testId]; } }); }); }, callback || paramsOrCallback); }, wait: function (testDefOrId, callback) { return _wait(testDefOrId, callback); }, runTestPlan: function (testPlan, params) { return tslib_1.__awaiter(this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) { return [2 /*return*/, _runTestPlan(testPlan, params)]; }); }); }, junitReport: function (testResult, path) { return tslib_1.__awaiter(this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) { return [2 /*return*/, _junitReport(testResult, path)]; }); }); }, mochawesomeReport: function (testResult, path) { return tslib_1.__awaiter(this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) { return [2 /*return*/, _mochawesomeReport(testResult, path)]; }); }); } }; } var isTestPassed = function (body, type) { switch (type) { case Loadmill.TYPES.SUITE: case Loadmill.TYPES.TEST_PLAN: return body.status === "PASSED"; default: //load return body.result === 'done'; } }; function toTestResult(testDef, webUrl, body) { return tslib_1.__assign(tslib_1.__assign({}, testDef), { url: webUrl, description: body && body.description, passed: isTestPassed(body, testDef.type), startTime: body.startTime, endTime: body.endTime, status: body.status }); } function redactData(testResult, body) { testResult.testSuitesRuns = reductTestSuitesRuns(body.testSuitesRuns); } function isTestInFinalState(body, runType) { if (runType === Loadmill.TYPES.TEST_PLAN) { if (body.testSuitesRuns.some(function (suite) { return suite.status === "RUNNING"; })) { return false; } } var trialResult = body.trialResult, result = body.result, status = body.status; return ((result || trialResult === false) || // load tests (status && status !== "RUNNING") // test suites or test plan ); } function getTestAPIUrl(_a, server) { var id = _a.id, type = _a.type; var prefix = server + "/api"; switch (type) { case Loadmill.TYPES.SUITE: return prefix + "/test-suites-runs/" + id; case Loadmill.TYPES.TEST_PLAN: return prefix + "/test-plans-runs/" + id; default: //load return prefix + "/tests/" + id; } } function getTestWebUrl(_a, server) { var id = _a.id, type = _a.type; var prefix = server + "/app"; switch (type) { case Loadmill.TYPES.SUITE: return prefix + "/api-tests/test-suite-runs/" + id; case Loadmill.TYPES.TEST_PLAN: return prefix + "/api-tests/test-plan-runs/" + id; default: //load return prefix + "/test/" + id; } } function reductTestSuitesRuns(suitesRuns) { if (suitesRuns) { return suitesRuns.map(function (s) { var suiteRun = { id: s.id, type: Loadmill.TYPES.SUITE, description: s.description, status: s.status, url: s.url, passed: s.status === "PASSED", startTime: s.startTime, endTime: s.endTime }; s.error && (suiteRun.error = s.error.message); if (Array.isArray(s.testSuiteFlowRuns)) { suiteRun.flowRuns = s.testSuiteFlowRuns.map(function (fr) { var _a; var flowRun = { id: fr.id, status: fr.status, description: fr.description, flowStatus: fr.testSuiteFlowStatus, duration: (fr.endTime - fr.startTime) || 0 }; if ((_a = fr.runs) === null || _a === void 0 ? void 0 : _a.length) { flowRun.retries = fr.runs.length - 1; flowRun.duration = fr.runs[fr.runs.length - 1].endTime - fr.runs[0].startTime; } return flowRun; }); } return suiteRun; }); } } function wrap(asyncFunction, paramsOrCallback) { var promise = asyncFunction(); if (typeof paramsOrCallback === 'function') { promise.then(function (res) { return paramsOrCallback(null, res); })["catch"](function (err) { return paramsOrCallback(err, null); }); } else { return promise; } } function toConfig(config, paramsOrCallback) { if (typeof config === 'string') { var text = fs.readFileSync(config).toString(); config = JSON.parse(text); } if (typeof paramsOrCallback === 'object' && paramsOrCallback != null) { var parameters = config.parameters; if (!parameters) { config.parameters = paramsOrCallback; } else if (typeof parameters.push === 'function') { parameters.push(paramsOrCallback); } else { config.parameters = [parameters, paramsOrCallback]; } } return config; } function toParams(params, filePath) { if (params === void 0) { params = {}; } if (filePath) { var fileParams = utils_1.toLoadmillParams(utils_1.readRawParams(filePath)); return tslib_1.__assign(tslib_1.__assign({}, fileParams), params); } return params; } (function (Loadmill) { var TYPES; (function (TYPES) { TYPES["LOAD"] = "load"; TYPES["SUITE"] = "test-suite"; TYPES["TEST_PLAN"] = "test-plan"; })(TYPES = Loadmill.TYPES || (Loadmill.TYPES = {})); ; })(Loadmill || (Loadmill = {})); module.exports = Loadmill;