Skip to content

Commit f113906

Browse files
Implementing try catch for execution and publishing in AzureTestPlanV0 (#19748)
* Implementing try catch for execution and publishing * Adding Promise to applicable places * Upgrading Task Version * Removing extra lines * Addressing comments --------- Co-authored-by: triptijain2112 <[email protected]>
1 parent fd95edd commit f113906

31 files changed

+376
-253
lines changed

Tasks/AzureTestPlanV0/Invokers/gradleinvoker.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import { spawn } from '../testexecutor'
21
import tl = require('azure-pipelines-task-lib/task');
32
import utils = require('../utils');
43
import constants = require('../constants');
54
import { execGradleBuild } from '../testLibExecutor';
65

7-
export async function executegradletests(testsToBeExecuted: string[]) {
6+
export async function executeGradleTests(testsToBeExecuted: string[]):Promise<number> {
87

98
//public doc link: https://docs.gradle.org/current/userguide/command_line_interface.html
109
//gradle command like "gradlew clean test --tests <package.className.testName> --tests <package.className.testName>"
@@ -26,5 +25,5 @@ export async function executegradletests(testsToBeExecuted: string[]) {
2625

2726
var status = await execGradleBuild(args);
2827

29-
return { exitCode: status ?? 1 }
28+
return status ?? 1;
3029
}

Tasks/AzureTestPlanV0/Invokers/maveninvoker.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import utils = require('../utils');
44
import constants = require('../constants');
55
import { execMavenBuild } from '../testLibExecutor';
66

7-
export async function executemaventests(testsToBeExecuted: string[]) {
7+
export async function executeMavenTests(testsToBeExecuted: string[]):Promise<number> {
88

99
//public doc link: https://maven.apache.org/surefire/maven-surefire-plugin/examples/single-test.html
1010
//maven command like "mvn test -Dtest=<package.className#testName>,<package.className#testName1>"
@@ -31,5 +31,7 @@ export async function executemaventests(testsToBeExecuted: string[]) {
3131
tl.debug("Executing java maven tests with executable : " + executable);
3232
tl.debug("Executing java maven tests with args :" + args);
3333

34-
await execMavenBuild(args);
34+
let status = await execMavenBuild(args);
35+
36+
return status ?? 1;
3537
}

Tasks/AzureTestPlanV0/Invokers/pythoninvoker.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ import { spawn, SpawnResult } from '../testexecutor';
22
import tl = require('azure-pipelines-task-lib/task');
33
import constants = require('../constants');
44

5-
export async function executepythontests(testsToBeExecuted: string[]) {
5+
export async function executePythonTests(testsToBeExecuted: string[]):Promise<number> {
66
// Perform test discovery
77
const discoveryArgs: string[] = ['--collect-only'];
88
const discoveryResult = await runPytestCommand(discoveryArgs);
99

1010
if (discoveryResult.status !== 0) {
1111
tl.error("Error occurred during test discovery: " + (discoveryResult.error ? discoveryResult.error.message : "Unknown error"));
12-
return { exitCode: 1 };
12+
return 1;
1313
}
1414

1515
// Extract discovered tests from stdout
@@ -20,7 +20,7 @@ export async function executepythontests(testsToBeExecuted: string[]) {
2020

2121
if (testsToRun.length === 0) {
2222
tl.warning("No common tests found between specified tests and discovered tests.");
23-
return { exitCode: 0 };
23+
return 0;
2424
}
2525

2626
console.log(`Found ${testsToRun.length} tests to run`);
@@ -34,10 +34,10 @@ export async function executepythontests(testsToBeExecuted: string[]) {
3434

3535
if (error) {
3636
tl.error("Error executing pytest command: " + error.message);
37-
return { exitCode: 1 };
37+
return 1;
3838
}
3939

40-
return { exitCode: status ?? 1 };
40+
return status ?? 1;
4141
}
4242

4343
async function runPytestCommand(args: string[]): Promise<SpawnResult> {
+18-9
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import * as tl from 'azure-pipelines-task-lib/task'
2-
import { executepythontests } from './Invokers/pythoninvoker'
3-
import { executemaventests } from './Invokers/maveninvoker'
4-
import { executegradletests } from './Invokers/gradleinvoker'
2+
import { executePythonTests } from './Invokers/pythoninvoker'
3+
import { executeMavenTests } from './Invokers/maveninvoker'
4+
import { executeGradleTests } from './Invokers/gradleinvoker'
55

6-
export async function testInvoker(testsToBeExecuted: string[]) {
6+
export async function testInvoker(testsToBeExecuted: string[]): Promise<number> {
77

88
const testLanguageStrings = tl.getDelimitedInput('testLanguageInput', ',', true);
99

10+
let exitStatusCode = 0;
11+
1012
for (const testLanguage of testLanguageStrings) {
13+
let exitCode = 0;
1114

1215
if (testLanguage === null || testLanguage === undefined) {
1316
console.log("Please select the test framework language from the task dropdown list to execute automated tests");
@@ -16,21 +19,27 @@ export async function testInvoker(testsToBeExecuted: string[]) {
1619

1720
switch (testLanguage) {
1821
case 'Java-Maven':
19-
await executemaventests(testsToBeExecuted);
22+
exitCode = await executeMavenTests(testsToBeExecuted);
23+
tl.debug(`Execution Status Code for Maven: ${exitCode}`);
2024
break;
2125

2226
case 'Java-Gradle':
23-
await executegradletests(testsToBeExecuted);
27+
exitCode = await executeGradleTests(testsToBeExecuted);
28+
tl.debug(`Execution Status Code for Gradle: ${exitCode}`);
2429
break;
2530

2631
case 'Python':
27-
await executepythontests(testsToBeExecuted);
32+
exitCode = await executePythonTests(testsToBeExecuted);
33+
tl.debug(`Execution Status Code for Python: ${exitCode}`);
2834
break;
2935

3036
default:
3137
console.log('Invalid test Language Input selected.');
3238
}
33-
39+
40+
exitStatusCode = exitStatusCode || exitCode;
3441
}
35-
42+
43+
tl.debug(`Execution Status Code for Automated Execution Flow: ${exitStatusCode}`);
44+
return exitStatusCode;
3645
}
+31-20
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,39 @@
11
import tl = require('azure-pipelines-task-lib/task');
2-
import { testInvoker } from './automatedTestInvoker'
3-
import { TestPlanData } from './testPlanData'
4-
import { publishAutomatedTestResult } from './publishAutomatedTests'
2+
import { testInvoker } from './automatedTestInvoker';
3+
import { TestPlanData } from './testPlanData';
4+
import { publishAutomatedTestResult } from './publishAutomatedTests';
55

6+
export async function automatedTestsFlow(testPlanInfo: TestPlanData, testSelectorInput: string): Promise<number> {
7+
let listOfTestsToBeExecuted: string[] = testPlanInfo.listOfFQNOfTestCases;
8+
let testInvokerStatusCode = 0;
69

7-
export async function automatedTestsFlow(testPlanInfo: TestPlanData, testSelectorInput: string) {
10+
if (listOfTestsToBeExecuted !== null && listOfTestsToBeExecuted !== undefined && listOfTestsToBeExecuted.length > 0) {
11+
tl.debug('Invoking test execution for tests: ' + listOfTestsToBeExecuted);
812

9-
let listOfTestsToBeExecuted: string[] = testPlanInfo.listOfFQNOfTestCases;
10-
11-
console.log(tl.loc('automatedTestTriggered'));
12-
13-
if (listOfTestsToBeExecuted !== null && listOfTestsToBeExecuted !== undefined && listOfTestsToBeExecuted.length > 0) {
14-
tl.debug("Invoking test execution for tests: " + listOfTestsToBeExecuted);
15-
await testInvoker(listOfTestsToBeExecuted);
16-
publishAutomatedTestResult(JSON.stringify(testPlanInfo.listOfAutomatedTestPoints));
13+
try {
14+
testInvokerStatusCode = await testInvoker(listOfTestsToBeExecuted);
15+
} catch (err) {
16+
tl.debug(`Unable to invoke automated test execution. Err:( ${err} )`);
17+
testInvokerStatusCode = 1;
1718
}
18-
else {
19-
console.log("No automated tests found for given test plan inputs ");
20-
if (testSelectorInput === 'automatedTests') {
21-
tl.setResult(tl.TaskResult.Failed, tl.loc('ErrorFailTaskOnNoAutomatedTestsFound'));
22-
}
23-
else {
24-
tl.setResult(tl.TaskResult.Succeeded, "Successfully triggered manual test execution");
25-
}
19+
20+
try {
21+
await publishAutomatedTestResult(JSON.stringify(testPlanInfo.listOfAutomatedTestPoints));
22+
} catch (err) {
23+
tl.error(`Error while publishing automated Test Results with err : ( ${err} )`);
24+
return 1;
2625
}
2726

27+
tl.debug(`Execution Status Code for test Invoker: ${testInvokerStatusCode}`);
28+
return testInvokerStatusCode;
29+
} else {
30+
console.log('No automated tests found for given test plan inputs ');
31+
if (testSelectorInput === 'automatedTests') {
32+
tl.setResult(tl.TaskResult.Failed, tl.loc('ErrorFailTaskOnNoAutomatedTestsFound'));
33+
return 1;
34+
} else {
35+
tl.setResult(tl.TaskResult.Succeeded, 'Successfully triggered manual test execution');
36+
return 0;
37+
}
38+
}
2839
}

Tasks/AzureTestPlanV0/manualTests.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
import tl = require('azure-pipelines-task-lib/task');
22
import { TestPlanData, createManualTestRun, ManualTestRunData } from './testPlanData';
33

4-
export async function manualTestsFlow(testPlanInfo: TestPlanData) {
4+
export async function manualTestsFlow(testPlanInfo: TestPlanData):Promise<number> {
55

66
let manualTestRun: ManualTestRunData = { testRunId: 0, runUrl: "" };
77

8-
manualTestRun = await createManualTestRun(testPlanInfo);
9-
8+
try{
9+
manualTestRun = await createManualTestRun(testPlanInfo);
10+
}
11+
catch (err){
12+
tl.debug(`Unable to create Manual Test Run. Err:( ${err} )`);
13+
return 1;
14+
}
15+
1016
console.log('Test run id created: ', manualTestRun.testRunId);
1117
console.log('Test run url: ', manualTestRun.runUrl);
1218

19+
return 0;
1320
}

Tasks/AzureTestPlanV0/runTestPlan.ts

+11-2
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,21 @@ export async function run() {
1010

1111
const testPlanInfo = await getTestPlanData();
1212

13+
let manualTestFlowReturnCode = 0;
14+
let automatedTestFlowReturnCode = 0;
15+
1316
// trigger manual, automated or both tests based on user's input
1417
if (testSelectorInput.includes('manualTests')) {
15-
await manualTestsFlow(testPlanInfo);
18+
manualTestFlowReturnCode = await manualTestsFlow(testPlanInfo);
19+
tl.debug(`Execution Status Code for Manual Test Flow is ${manualTestFlowReturnCode}`);
1620
}
1721
if (testSelectorInput.includes('automatedTests')) {
18-
await automatedTestsFlow(testPlanInfo, testSelectorInput);
22+
automatedTestFlowReturnCode = await automatedTestsFlow(testPlanInfo, testSelectorInput);
23+
tl.debug(`Execution Status Code for Automated Test Flow is ${automatedTestFlowReturnCode}`);
24+
}
25+
26+
if( manualTestFlowReturnCode || automatedTestFlowReturnCode){
27+
tl.setResult(tl.TaskResult.Failed, "Faced error in execution.");
1928
}
2029
}
2130

Tasks/AzureTestPlanV0/task.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"version": {
1515
"Major": 0,
1616
"Minor": 238,
17-
"Patch": 6
17+
"Patch": 8
1818
},
1919
"preview": true,
2020
"demands": [],

Tasks/AzureTestPlanV0/task.loc.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"version": {
1515
"Major": 0,
1616
"Minor": 238,
17-
"Patch": 6
17+
"Patch": 8
1818
},
1919
"preview": true,
2020
"demands": [],

Tasks/AzureTestPlanV0/testLibExecutor.ts

+39-35
Original file line numberDiff line numberDiff line change
@@ -54,35 +54,32 @@ function getExecOptions(): tr.IExecOptions {
5454
* @param args Arguments to execute via mvn
5555
* @returns execution Status Code
5656
*/
57-
export async function execMavenBuild(args: string[]) {
58-
57+
export async function execMavenBuild(args: string[]): Promise<number> {
5958
var mvnExec = getMavenExec();
6059

6160
// Setup tool runner that executes Maven only to retrieve its version
6261
var mvnGetVersion = tl.tool(mvnExec);
6362
mvnGetVersion.arg('-version');
6463

65-
// 1. Check that Maven exists by executing it to retrieve its version.
66-
await mvnGetVersion.exec()
67-
.fail(function (err) {
68-
console.error("Maven is not installed on the agent");
69-
tl.setResult(tl.TaskResult.Failed, "Maven is not installed."); // tl.exit sets the step result but does not stop execution
70-
process.exit(1);
71-
})
72-
.then(async function (code) {
73-
// Setup Maven Executable to run list of test runs provided as input
74-
var mvnRun = tl.tool(mvnExec);
75-
mvnRun.arg('-ntp');
76-
mvnRun.arg(args);
77-
78-
// 3. Run Maven. Compilation or test errors will cause this to fail.
79-
return mvnRun.exec(getExecOptions());
80-
})
81-
.fail(function (err) {
82-
console.error(err.message);
83-
tl.setResult(tl.TaskResult.Failed, "Build failed."); // tl.exit sets the step result but does not stop execution
84-
process.exit(1);
85-
});
64+
try {
65+
// 1. Check that Maven exists by executing it to retrieve its version.
66+
await mvnGetVersion.exec();
67+
68+
// Setup Maven Executable to run list of test runs provided as input
69+
var mvnRun = tl.tool(mvnExec);
70+
mvnRun.arg('-ntp');
71+
mvnRun.arg(args);
72+
73+
// 3. Run Maven. Compilation or test errors will cause this to fail.
74+
await mvnRun.exec(getExecOptions());
75+
76+
// Maven build succeeded
77+
return 0; // Return 0 indicating success
78+
} catch (err) {
79+
console.error(err.message);
80+
tl.setResult(tl.TaskResult.Failed, "Build failed.");
81+
return 1; // Return 1 indicating failure
82+
}
8683
}
8784

8885
function getGradlewExec() {
@@ -105,14 +102,16 @@ function getGradlewExec() {
105102

106103
if (gradlewPath.length == 0) {
107104
tl.setResult(tl.TaskResult.Failed, "Missing gradlew file");
105+
return "";
108106
}
109107

108+
var gradlewExec: string = gradlewPath[0];
109+
110110
if (gradlewPath.length > 1) {
111111
tl.warning(tl.loc('MultipleMatchingGradlewFound'));
112+
tl.debug(gradlewExec);
112113
}
113114

114-
var gradlewExec: string = gradlewPath[0];
115-
116115
if (isWindows) {
117116
tl.debug('Append .bat extension name to gradlew script.');
118117
gradlewExec += '.bat';
@@ -136,22 +135,27 @@ function getGradlewExec() {
136135
* @param args Arguments to execute via mvn
137136
* @returns execution Status Code
138137
*/
139-
export async function execGradleBuild(args: string[]) {
138+
export async function execGradleBuild(args: string[]): Promise<number> {
140139
var gradleExec = getGradlewExec();
141140

142-
// Setup tool runner that executes Maven only to retrieve its version
141+
if (!gradleExec || gradleExec == "") {
142+
return 1; // Return 1 indicating failure
143+
}
144+
145+
// Setup tool runner that executes Gradle
143146
var gradleRunner = tl.tool(gradleExec);
144147

145148
// Add args prepared by invoker for executing individual test cases
146149
gradleRunner.arg('clean');
147150
gradleRunner.arg(args);
148151

149-
var statusCode = await gradleRunner.exec(getExecOptions())
150-
.fail(function (err) {
151-
console.error(err.message);
152-
tl.setResult(tl.TaskResult.Failed, "Build failed."); // tl.exit sets the step result but does not stop execution
153-
process.exit(1);
154-
});
155-
156-
return statusCode;
152+
try {
153+
await gradleRunner.exec(getExecOptions());
154+
// Gradle build succeeded
155+
return 0; // Return 0 indicating success
156+
} catch (err) {
157+
console.error(err.message);
158+
tl.setResult(tl.TaskResult.Failed, "Build failed."); // Set the step result to Failed
159+
return 1; // Return 1 indicating failure
160+
}
157161
}
+2-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
Default|0.238.6
2-
Node20-225|0.238.7
1+
Default|0.238.8
2+
Node20-225|0.238.9

_generated/AzureTestPlanV0/Invokers/gradleinvoker.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import { spawn } from '../testexecutor'
21
import tl = require('azure-pipelines-task-lib/task');
32
import utils = require('../utils');
43
import constants = require('../constants');
54
import { execGradleBuild } from '../testLibExecutor';
65

7-
export async function executegradletests(testsToBeExecuted: string[]) {
6+
export async function executeGradleTests(testsToBeExecuted: string[]):Promise<number> {
87

98
//public doc link: https://docs.gradle.org/current/userguide/command_line_interface.html
109
//gradle command like "gradlew clean test --tests <package.className.testName> --tests <package.className.testName>"
@@ -26,5 +25,5 @@ export async function executegradletests(testsToBeExecuted: string[]) {
2625

2726
var status = await execGradleBuild(args);
2827

29-
return { exitCode: status ?? 1 }
28+
return status ?? 1;
3029
}

0 commit comments

Comments
 (0)