1 | "use strict";
|
2 |
|
3 | const Promise = require('bluebird');
|
4 | const _ = require('lodash');
|
5 | const constants = require('../commons/constants');
|
6 | const TESTIM_RUN_STATUS = constants.testStatus;
|
7 | const {CLI_MODE} = constants;
|
8 | const reporter = require("../reports/reporter");
|
9 | const RealDataService = require('../commons/socket/realDataService');
|
10 | const testimCustomToken = require('../commons/testimCustomToken');
|
11 | const BaseRunner = require('./BaseRunner');
|
12 | const TestRunStatus = require('../testRunStatus');
|
13 | const config = require('../commons/config');
|
14 | const utils = require('../utils');
|
15 | const guid = utils.guid;
|
16 | const {StopRunOnError} = require('../errors');
|
17 | const Logger = require('../commons/logger');
|
18 | const perf = require('../commons/performance-logger');
|
19 |
|
20 | class BaseTestPlanRunner extends BaseRunner {
|
21 | constructor(strategy) {
|
22 | super(strategy);
|
23 | this.runTestPlan = Promise.method(this.runTestPlan);
|
24 | }
|
25 | runTestAllPhases(beforeTests, tests, afterTests, branchToUse, tpOptions, executionId, testStatus) {
|
26 | let executionResults = {};
|
27 | const authData = testimCustomToken.getTokenV3UserData();
|
28 |
|
29 | const runBeforeTests = (beforeTests, testStatus, executionId, tpOptions, branchToUse, authData) => {
|
30 | const workerCount = 1;
|
31 | const stopOnError = true;
|
32 | return this.strategy.runTests(beforeTests, testStatus, executionId, tpOptions, branchToUse, authData, workerCount, stopOnError)
|
33 | .then(beforeTestsResults => Object.assign(executionResults, beforeTestsResults));
|
34 | };
|
35 |
|
36 | const runTestPlanTests = (tests, testStatus, executionId, tpOptions, branchToUse, authData) => {
|
37 | const workerCount = config.TESTIM_CONCURRENT_WORKER_COUNT || tpOptions.parallel;
|
38 | const stopOnError = false;
|
39 | perf.log('right before this.strategy.runTests')
|
40 | return this.strategy.runTests(tests, testStatus, executionId, tpOptions, branchToUse, authData, workerCount, stopOnError)
|
41 | .log('right after this.strategy.runTests')
|
42 | .then(testsResults => Object.assign(executionResults, testsResults));
|
43 | };
|
44 |
|
45 | const runAfterTests = (afterTests, testStatus, executionId, tpOptions, branchToUse, authData) => {
|
46 | const workerCount = 1;
|
47 | const stopOnError = false;
|
48 | return this.strategy.runTests(afterTests, testStatus, executionId, tpOptions, branchToUse, authData, workerCount, stopOnError)
|
49 | .then(afterTestsResults => Object.assign(executionResults, afterTestsResults));
|
50 | };
|
51 |
|
52 | function catchBeforeTestsFailed(executionId) {
|
53 | return testStatus.markAllQueuedTests(executionId, utils.TestStatus.ABORTED, "aborted", false);
|
54 | }
|
55 |
|
56 | const sessionType = utils.getSessionType(tpOptions);
|
57 | this.analyticsExecsStart({authData, executionId, projectId: tpOptions.project, sessionType});
|
58 | perf.log('right before runBeforeTests');
|
59 | return runBeforeTests(beforeTests, testStatus, executionId, tpOptions, branchToUse, authData)
|
60 | .log('right before runTestPlanTests')
|
61 | .then(() => runTestPlanTests(tests, testStatus, executionId, tpOptions, branchToUse, authData))
|
62 | .log('right after runTestPlanTests')
|
63 | .then(() => runAfterTests(afterTests, testStatus, executionId, tpOptions, branchToUse, authData))
|
64 | .then(() => executionResults)
|
65 | .catch(StopRunOnError, () => catchBeforeTestsFailed(executionId));
|
66 | }
|
67 |
|
68 | prepareForTestResources(tpOptions) {
|
69 | if (tpOptions.mode !== CLI_MODE.APPIUM && !(this.strategy.constructor.name === 'DeviceFarmStrategy')) {
|
70 | return Promise.resolve();
|
71 | }
|
72 | const apkUploaderFactory = require('../commons/apkUploader/apkUploaderFactory');
|
73 | return apkUploaderFactory.uploadApk(tpOptions);
|
74 | }
|
75 |
|
76 | async initRealDataService(projectId) {
|
77 | const realDataService = new RealDataService();
|
78 | await realDataService.init(projectId);
|
79 | return realDataService;
|
80 | }
|
81 |
|
82 | async listenToTestCreatedInFile(realDataService, projectId, runId, testStatus) {
|
83 | const childTestResults = {};
|
84 | realDataService.joinToTestResultsByRunId(runId, projectId);
|
85 | const promise = new Promise(resolve => {
|
86 |
|
87 | realDataService.listenToTestResultsByRunId(runId, testResult => {
|
88 | const resultId = testResult.id;
|
89 | if (!testStatus.getTestResult(resultId)) {
|
90 | const prevTestResult = childTestResults[resultId];
|
91 | const mergedTestResult = _.merge({}, prevTestResult, testResult, {resultId});
|
92 | childTestResults[resultId] = mergedTestResult;
|
93 | if (!prevTestResult || prevTestResult.status !== testResult.status) {
|
94 | const parentTestResult = testStatus.getTestResult(mergedTestResult.parentResultId) || {workerId: 1};
|
95 | const workerId = parentTestResult.workerId;
|
96 | if ([TESTIM_RUN_STATUS.RUNNING].includes(testResult.status)) {
|
97 | reporter.onTestStarted(mergedTestResult, workerId);
|
98 | }
|
99 | if ([TESTIM_RUN_STATUS.COMPLETED].includes(testResult.status)) {
|
100 | mergedTestResult.duration = (mergedTestResult.endTime - mergedTestResult.startTime) || 0;
|
101 | reporter.onTestFinished(mergedTestResult, workerId);
|
102 | }
|
103 | }
|
104 | }
|
105 |
|
106 | const allChildTestResultCompleted = !(Object.values(childTestResults)
|
107 | .some(result => ["QUEUED", "RUNNING"].includes(result.runnerStatus)));
|
108 |
|
109 | const allParentTestResultCompleted = !(Object.values(testStatus.getAllTestResults())
|
110 | .some(result => ["QUEUED", "RUNNING"].includes(result.status)));
|
111 |
|
112 | if(allChildTestResultCompleted && allParentTestResultCompleted) {
|
113 | return resolve(Object.values(childTestResults));
|
114 | }
|
115 |
|
116 | if(allParentTestResultCompleted && !allChildTestResultCompleted) {
|
117 |
|
118 | return Promise.delay(10000)
|
119 | .then(() => {
|
120 | if(promise.isPending()) {
|
121 |
|
122 |
|
123 |
|
124 | resolve(childTestResults);
|
125 | }
|
126 | })
|
127 | }
|
128 | });
|
129 | });
|
130 |
|
131 | return await promise;
|
132 | };
|
133 |
|
134 | async runTestPlan(beforeTests, tests, afterTests, tpOptions, testPlanName, branch, isAnonymous) {
|
135 | const executionId = guid();
|
136 | const projectId = tpOptions.project;
|
137 | Logger.setExecutionId(executionId);
|
138 | beforeTests.map(test => test.isBeforeTestPlan = true);
|
139 | afterTests.map(test => test.isAfterTestPlan = true);
|
140 | const testStatus = new TestRunStatus(_.concat(beforeTests, tests, afterTests), tpOptions, branch);
|
141 |
|
142 | const configs = _(_.concat(beforeTests, tests, afterTests)).map(test => test.overrideTestConfig && test.overrideTestConfig.name || "").uniq().filter(Boolean).value();
|
143 | const configName = configs && configs.length === 1 ? configs[0] : null;
|
144 |
|
145 | const isCodeMode = tpOptions.files.length > 0;
|
146 |
|
147 | if (isCodeMode && tpOptions.mode === constants.CLI_MODE.SELENIUM) {
|
148 |
|
149 | testStatus.setAsyncReporting(true);
|
150 | }
|
151 | const testListInfoPromise = testStatus.executionStart(executionId, projectId, this.startTime, testPlanName);
|
152 | let childTestResults = Promise.resolve();
|
153 | if (isCodeMode) {
|
154 | childTestResults = Promise.try(async () => {
|
155 | const realDataService = await this.initRealDataService(projectId);
|
156 | return this.listenToTestCreatedInFile(realDataService, projectId, executionId, testStatus);
|
157 | });
|
158 | }
|
159 | const testListInfo = await testListInfoPromise;
|
160 | reporter.onTestPlanStarted(testListInfo.beforeTests, testListInfo.tests, testListInfo.afterTests, testPlanName, executionId, isAnonymous, configName, isCodeMode);
|
161 | const results = await this.runTestAllPhases(testListInfo.beforeTests, testListInfo.tests, testListInfo.afterTests, branch, tpOptions, executionId, testStatus);
|
162 | const childResults = await childTestResults;
|
163 | await testStatus.executionEnd(executionId);
|
164 | return {results, executionId, testPlanName, configName, childTestResults: childResults };
|
165 | }
|
166 | }
|
167 |
|
168 | module.exports = BaseTestPlanRunner;
|