lib/RunnerFiles/CreateAndRunTest.js (332 lines of code) (raw):

"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.CreateAndRunTest = void 0; const util_1 = require("util"); const PayloadModels_1 = require("../models/PayloadModels"); const LoadtestConfigUtil_1 = require("../Utils/LoadtestConfigUtil"); const CreateAndRunUtils_1 = require("../Utils/CreateAndRunUtils"); const UtilModels_1 = require("../models/UtilModels"); const TestKind_1 = require("../models/TestKind"); const Util = __importStar(require("../Utils/CommonUtils")); const CoreUtils = __importStar(require("../Utils/CoreUtils")); const FileUtils = __importStar(require("../Utils/FileUtils")); const FetchUtil = __importStar(require("../Utils/FetchUtils")); class CreateAndRunTest { constructor(apiService) { this.loadTestConfig = {}; this.isCreateTest = true; this.existingTestObj = null; this.existingParams = { secrets: {}, env: {}, passFailCriteria: {}, passFailServerMetrics: {}, appComponents: new Map() }; this.apiService = apiService; } createAndRunTest() { return __awaiter(this, void 0, void 0, function* () { var _a; yield this.initialize(); let testPayload = yield this.getTestPayload(); if (this.isCreateTest) { console.log("Creating a new load test " + this.loadTestConfig.testId); } let createdTestObj = yield this.apiService.createTestAPI(testPayload); this.isCreateTest ? console.log(`Created test with id ${createdTestObj.testId}`) : console.log("Test '" + createdTestObj.testId + "' already exists"); let testFiles = createdTestObj.inputArtifacts; let filesToDelete = testFiles ? (0, CreateAndRunUtils_1.getAllFileNamesTobeDeleted)(this.loadTestConfig, testFiles) : []; if (filesToDelete.length > 0) { console.log(`Deleting ${filesToDelete.length} existing test file(s) which is(are) not in the configuration yaml file.`); } for (const file of filesToDelete) { yield this.apiService.deleteFileAPI(file); } yield this.uploadAllTestFiles(this.loadTestConfig, this.apiService); let validatedTest = yield this.awaitTerminationForFileValidation(this.apiService); this.checkForValidationsOfTest(validatedTest); let appComponentsPayload = yield this.getAppComponentsPayload(); let appComponentsResp = yield this.apiService.patchAppComponents(appComponentsPayload); appComponentsResp && console.log("Updated app components successfully"); let serverMetricsConfigPayload = yield this.getServerMetricsConfigPayload(); yield this.apiService.patchServerMetricsConfig(serverMetricsConfigPayload); serverMetricsConfigPayload && console.log("Updated server metrics successfully"); console.log("Creating and running a testRun for the test"); let testRunPayload = yield this.getTestRunPayload(); let testRunResult = yield this.apiService.createTestRun(testRunPayload); this.printPortalUrl(testRunResult); CoreUtils.exportVariable(UtilModels_1.PostTaskParameters.runId, testRunResult.testRunId); yield this.awaitTerminationForTestRun(testRunResult.testRunId, this.apiService); testRunResult = (_a = yield this.awaitResultsPopulation(testRunResult.testRunId, this.apiService)) !== null && _a !== void 0 ? _a : testRunResult; CoreUtils.exportVariable(UtilModels_1.PostTaskParameters.isRunCompleted, 'true'); this.printMetrics(testRunResult); yield this.uploadResultsToPipeline(testRunResult); this.setTaskResults(testRunResult); this.setOutputVariable(testRunResult); }); } initialize() { return __awaiter(this, void 0, void 0, function* () { this.loadTestConfig = LoadtestConfigUtil_1.LoadtestConfigUtil.parseLoadtestConfigFile(); (0, CreateAndRunUtils_1.validateAndSetOverrideParams)(this.loadTestConfig); this.apiService.setTestId(this.loadTestConfig.testId); this.existingTestObj = yield this.apiService.getTestAPI(true); if (this.existingTestObj) { this.isCreateTest = false; } else { this.isCreateTest = true; } }); } // Marked public for testing getTestPayload() { return __awaiter(this, void 0, void 0, function* () { if (!this.isCreateTest) { this.existingTestObj && (0, CreateAndRunUtils_1.addExistingTestParameters)(this.existingTestObj, this.existingParams); } return (0, CreateAndRunUtils_1.getPayloadForTest)(this.loadTestConfig, this.existingParams); }); } getAppComponentsPayload() { return __awaiter(this, void 0, void 0, function* () { if (!this.isCreateTest) { let appComponentsObj = yield this.apiService.getAppComponents(); (0, CreateAndRunUtils_1.addExistingAppComponentParameters)(appComponentsObj, this.existingParams); } return (0, CreateAndRunUtils_1.getPayloadForAppcomponents)(this.loadTestConfig, this.existingParams); }); } getServerMetricsConfigPayload() { return __awaiter(this, void 0, void 0, function* () { let existingServerMetricsConfig = null; if (!this.isCreateTest) { existingServerMetricsConfig = yield this.apiService.getServerMetricsConfig(); } return (0, CreateAndRunUtils_1.getPayloadForServerMetricsConfig)(existingServerMetricsConfig, this.loadTestConfig); }); } getTestRunPayload() { return __awaiter(this, void 0, void 0, function* () { let runTimeParamsofTestRun = (0, CreateAndRunUtils_1.validateAndGetRunTimeParamsForTestRun)(this.loadTestConfig.testId); return (0, CreateAndRunUtils_1.getTestRunPayload)(runTimeParamsofTestRun); }); } /* * This function will wait for the validation of files to complete */ awaitTerminationForFileValidation(apiService) { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c; let minutesToAdd = 10; let startTime = new Date(); let maxAllowedTime = new Date(startTime.getTime() + minutesToAdd * 60000); let validationStatus = PayloadModels_1.FileStatus.VALIDATION_INITIATED; let testObj = null; let retry = 5; while (maxAllowedTime > (new Date()) && !Util.isTerminalFileStatus(validationStatus)) { yield Util.sleep(5000); try { testObj = yield apiService.getTestAPI(); let inputScriptFileInfo; testObj && (inputScriptFileInfo = testObj.kind == TestKind_1.TestKind.URL ? (_a = testObj.inputArtifacts) === null || _a === void 0 ? void 0 : _a.urlTestConfigFileInfo : (_b = testObj.inputArtifacts) === null || _b === void 0 ? void 0 : _b.testScriptFileInfo); validationStatus = (_c = inputScriptFileInfo === null || inputScriptFileInfo === void 0 ? void 0 : inputScriptFileInfo.validationStatus) !== null && _c !== void 0 ? _c : validationStatus; } catch (e) { retry--; if (retry == 0) { throw new Error("Unable to validate the test plan. Please retry. Failed with error :" + e); } } } return testObj; }); } /* * This function will wait for the test run to complete */ awaitTerminationForTestRun(id, apiService) { return __awaiter(this, void 0, void 0, function* () { var _a; let testRunStatus = "ACCEPTED"; let testRunObj = null; while (!Util.isTerminalTestStatus(testRunStatus)) { if (testRunStatus === "DEPROVISIONING" || testRunStatus === "DEPROVISIONED" || testRunStatus == "EXECUTED") yield Util.sleep(5000); else yield Util.sleep(20000); testRunObj = yield apiService.getTestRunAPI(id); testRunStatus = (_a = testRunObj.status) !== null && _a !== void 0 ? _a : testRunStatus; } return testRunObj; }); } // Marked public for testing awaitResultsPopulation(testRunId, apiService) { return __awaiter(this, void 0, void 0, function* () { let vusers = null; let count = 0; let reportsAvailable = false; let testRunObj = null; console.log("Test run completed. Polling for statistics and dashboard report to populate."); // Polling for max 5 min for statistics and pass fail criteria to populate while ((!reportsAvailable || (0, util_1.isNullOrUndefined)(vusers)) && count < 30) { yield Util.sleep(10000); testRunObj = yield apiService.getTestRunAPI(testRunId); vusers = testRunObj.virtualUsers; count++; let testReport = Util.getReportFolder(testRunObj.testArtifacts); if (testReport) { reportsAvailable = true; } } return testRunObj; }); } uploadAllTestFiles(loadTestConfig, apiService) { return __awaiter(this, void 0, void 0, function* () { let configFiles = loadTestConfig.configurationFiles; if (configFiles.length > 0) { console.log("Uploading the configuration files"); yield this.uploadFiles(configFiles, apiService, PayloadModels_1.FileType.ADDITIONAL_ARTIFACTS); console.log(`Uploaded ${configFiles.length} configuration file(s) for the test successfully.`); } let zipFiles = loadTestConfig.zipArtifacts; if (zipFiles.length > 0) { console.log("Uploading the zip artifacts"); yield this.uploadFiles(zipFiles, apiService, PayloadModels_1.FileType.ZIPPED_ARTIFACTS); console.log(`Uploaded ${zipFiles.length} zip artifact(s) for the test successfully.`); } let propertyFile = loadTestConfig.propertyFile; if (propertyFile != undefined && propertyFile != '') { console.log("Uploading the user properties file"); yield apiService.uploadFile(propertyFile, PayloadModels_1.FileType.USER_PROPERTIES); console.log(`Uploaded user properties file for the test successfully.`); } yield this.uploadTestScriptFile(loadTestConfig, apiService); }); } uploadFiles(configFiles, apiService, fileType) { return __awaiter(this, void 0, void 0, function* () { if (configFiles.length > 0) { for (let filepath of configFiles) { yield apiService.uploadFile(filepath, fileType); } ; } }); } uploadTestScriptFile(loadTestConfig, apiService) { return __awaiter(this, void 0, void 0, function* () { let testScriptFile = loadTestConfig.testPlan; let fileType = PayloadModels_1.FileType.TEST_SCRIPT; if (loadTestConfig.kind == TestKind_1.TestKind.URL) { fileType = PayloadModels_1.FileType.URL_TEST_CONFIG; } console.log("Uploading the test script file"); yield apiService.uploadFile(testScriptFile, fileType); console.log(`Uploaded test script file for the test successfully.`); }); } printPortalUrl(testRunObj) { let resourceId = this.apiService.authContext.taskParameters.resourceId; let subscriptionName = this.apiService.authContext.taskParameters.subscriptionName; let testDisplayName = this.loadTestConfig.displayName; console.log("\nView the load test run in Azure portal by following the steps:"); console.log("1. Go to your Azure Load Testing resource '" + Util.getResourceNameFromResourceId(resourceId) + "' in subscription '" + subscriptionName + "'"); console.log("2. On the Tests page, go to test '" + testDisplayName + "'"); console.log("3. Go to test run '" + testRunObj.displayName + "'\n"); } checkForValidationsOfTest(testObj) { var _a, _b, _c; let validationStatus = (_c = (_b = (_a = testObj.inputArtifacts) === null || _a === void 0 ? void 0 : _a.testScriptFileInfo) === null || _b === void 0 ? void 0 : _b.validationStatus) !== null && _c !== void 0 ? _c : PayloadModels_1.FileStatus.VALIDATION_INITIATED; console.log("Validation status of the test plan: " + validationStatus); if (Util.isTerminalFileStatusSucceeded(validationStatus)) { console.log(`Validated test plan for the test successfully.`); // Get errors from all files let fileErrors = Util.getAllFileErrors(testObj); if (Object.keys(fileErrors).length > 0) { console.log("Validation failed for the following files:"); for (const [file, error] of Object.entries(fileErrors)) { console.log(`File: ${file}, Error: ${error}`); } throw new Error("Validation of one or more files failed. Please correct the errors and try again."); } } else if (!Util.isTerminalFileStatus(validationStatus)) { throw new Error("TestPlan validation timeout. Please try again."); } else { throw new Error("TestPlan validation Failed."); } } printMetrics(testRunObj) { Util.printTestDuration(testRunObj); if (!(0, util_1.isNullOrUndefined)(testRunObj.passFailCriteria) && !(0, util_1.isNullOrUndefined)(testRunObj.passFailCriteria.passFailMetrics)) Util.printCriteria(testRunObj.passFailCriteria.passFailMetrics); if (testRunObj.testRunStatistics != null && testRunObj.testRunStatistics != undefined) Util.printClientMetrics(testRunObj.testRunStatistics); } uploadResultsToPipeline(testRunObj) { return __awaiter(this, void 0, void 0, function* () { let testResultUrl = Util.getResultFolder(testRunObj.testArtifacts); if (testResultUrl != null) { const response = yield FetchUtil.httpClientRetries(testResultUrl, {}, UtilModels_1.FetchCallType.get, 3, ""); if (response.message.statusCode != 200) { let respObj = yield Util.getResultObj(response); console.log(respObj ? respObj : Util.errorCorrection(response)); throw new Error("Error in fetching results "); } else { yield FileUtils.uploadFileToResultsFolder(response, UtilModels_1.resultZipFileName); } } let testReportUrl = Util.getReportFolder(testRunObj.testArtifacts); if (testReportUrl != null) { const response = yield FetchUtil.httpClientRetries(testReportUrl, {}, UtilModels_1.FetchCallType.get, 3, ""); if (response.message.statusCode != 200) { let respObj = yield Util.getResultObj(response); console.log(respObj ? respObj : Util.errorCorrection(response)); throw new Error("Error in fetching report "); } else { yield FileUtils.uploadFileToResultsFolder(response, UtilModels_1.reportZipFileName); } } }); } setTaskResults(testRunObj) { if (!(0, util_1.isNullOrUndefined)(testRunObj.testResult) && Util.isStatusFailed(testRunObj.testResult)) { CoreUtils.setFailed("TestResult: " + testRunObj.testResult); } if (!(0, util_1.isNullOrUndefined)(testRunObj.status) && Util.isStatusFailed(testRunObj.status)) { console.log("Please go to the Portal for more error details: " + testRunObj.portalUrl); CoreUtils.setFailed("TestStatus: " + testRunObj.status); } } setOutputVariable(testRunObj) { let outputVarName = (0, CreateAndRunUtils_1.validateAndGetOutPutVarName)(); let outputVar = { testRunId: testRunObj.testRunId }; CoreUtils.setOutput(`${outputVarName}.${UtilModels_1.OutPutVariablesConstants.testRunId}`, outputVar.testRunId); } } exports.CreateAndRunTest = CreateAndRunTest;