Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
"loc.input.help.codeCoverageEnabled": "Collect code coverage information from the test run.",
"loc.input.label.otherConsoleOptions": "Other console options",
"loc.input.help.otherConsoleOptions": "Other console options that can be passed to vstest.console.exe, as documented <a href=\"https://aka.ms/vstestotherconsoleoptions\" target=\"_blank\">here</a>. <p>These options are not supported and will be ignored when running tests using the ‘Multi agent’ parallel setting of an agent job or when running tests using ‘Test plan’ or 'Test run' option or when a custom batching option is selected. The options can be specified using a settings file instead.</p>",
"loc.input.label.vstestArchitecture": "Test runner architecture",
"loc.input.help.vstestArchitecture": "Optionally supply the architecture (x86, x64, arm64) of vstest.console.exe to run. Select arm64 to run tests natively on ARM64 Windows machines. Requires Visual Studio 2022 (17.0) or later.",
"loc.input.label.distributionBatchType": "Batch tests",
"loc.input.help.distributionBatchType": "A batch is a group of tests. A batch of tests runs its tests at the same time and results are published for the batch. If the job in which the task runs is set to use multiple agents, each agent picks up any available batches of tests to run in parallel.<br><br><b>Based on the number of tests and agents:</b> Simple batching based on the number of tests and agents participating in the test run.<br><br><b>Based on past running time of tests:</b> This batching considers past running time to create batches of tests such that each batch has approximately equal running time.<br><br><b>Based on test assemblies:</b> Tests from an assembly are batched together.",
"loc.input.label.batchingBasedOnAgentsOption": "Batch options",
Expand Down Expand Up @@ -114,6 +116,7 @@
"loc.messages.GenerateResponseFilePerfTime": "Total time taken to get response file: %d milliseconds.",
"loc.messages.UploadTestResultsPerfTime": "Total time taken to upload test results: %d milliseconds.",
"loc.messages.ErrorReadingVstestVersion": "Error reading the version of vstest.console.exe.",
"loc.messages.Arm64VstestNotFound": "ARM64 vstest.console.exe not found at '%s'. Falling back to x64 variant.",
"loc.messages.UnexpectedVersionString": "Unexpected version string detected for vstest.console.exe: %s.",
"loc.messages.UnexpectedVersionNumber": "Unexpected version number detected for vstest.console.exe: %s.",
"loc.messages.VstestDiagNotSupported": "vstest.console.exe version does not support the /diag flag. Enable diagnostics via the exe.config files",
Expand Down
77 changes: 77 additions & 0 deletions Tasks/VsTestV2/Tests/L0.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,4 +296,81 @@ describe('VsTestV2 – versionfinder.ts (PowerShell Get-ItemProperty change)', f
'should throw UnexpectedVersionNumber for non-numeric version parts'
);
});

// -----------------------------------------------------------------------
// ARM64 architecture tests
// -----------------------------------------------------------------------

it('uses arm64/vstest.console.exe when vstestArchitecture is arm64 and arm64 binary exists', function() {
setupMocks('17.0.33.0\n');
// Override helpers mock so arm64 path exists; also keep base location valid
libMocker.registerMock('./helpers', {
Helper: {
pathExistsAsFile: function(p: string) { return p === fakeVsTestLocation || p.includes('arm64'); },
pathExistsAsDirectory: function(_p: string) { return false; },
isNullOrWhitespace: function(s: string) {
return s === null || s === undefined || s.replace(/\s/g, '').length < 1;
},
trimString: function(s: string) { return s ? s.trim() : s; },
getVSVersion: function(v: number) { return v.toString(); },
isToolsInstallerFlow: function(_config: any) { return false; }
},
Constants: { vsTestLocationString: 'location', vsTestVersionString: 'version' }
});
const vf = loadVersionfinder();
const config = Object.assign(makeTestConfig('17.0'), { vstestArchitecture: 'arm64' });

vf.getVsTestRunnerDetails(config);

assert.ok(config.vsTestVersionDetails);
assert.strictEqual(config.vsTestVersionDetails.majorVersion, 17);
// vstest location must include the arm64 subdirectory
assert.ok(
config.vsTestVersionDetails.vstestExeLocation.includes('arm64'),
'vstestExeLocation should include arm64 subdirectory'
);
});

it('falls back to x64 vstest.console.exe when vstestArchitecture is arm64 but arm64 binary is absent', function() {
setupMocks('17.0.33.0\n');
// pathExistsAsFile returns false for arm64 path, true for x64 path
libMocker.registerMock('./helpers', {
Helper: {
pathExistsAsFile: function(p: string) { return !p.includes('arm64'); },
pathExistsAsDirectory: function(_p: string) { return false; },
isNullOrWhitespace: function(s: string) {
return s === null || s === undefined || s.replace(/\s/g, '').length < 1;
},
trimString: function(s: string) { return s ? s.trim() : s; },
getVSVersion: function(v: number) { return v.toString(); },
isToolsInstallerFlow: function(_config: any) { return false; }
},
Constants: { vsTestLocationString: 'location', vsTestVersionString: 'version' }
});
const vf = loadVersionfinder();
const config = Object.assign(makeTestConfig('17.0'), { vstestArchitecture: 'arm64' });

vf.getVsTestRunnerDetails(config);

assert.ok(config.vsTestVersionDetails);
// Should fall back: location must not include arm64 subdirectory
assert.ok(
!config.vsTestVersionDetails.vstestExeLocation.split('\\').includes('arm64'),
'vstestExeLocation should NOT use arm64 subdirectory on fallback'
);
});

it('uses regular vstest.console.exe when vstestArchitecture is x64 (default)', function() {
setupMocks('17.0.33.0\n');
const vf = loadVersionfinder();
const config = Object.assign(makeTestConfig('17.0'), { vstestArchitecture: 'x64' });

vf.getVsTestRunnerDetails(config);

assert.ok(config.vsTestVersionDetails);
assert.ok(
!config.vsTestVersionDetails.vstestExeLocation.split('\\').includes('arm64'),
'x64 path should not include arm64 subdirectory'
);
});
});
1 change: 1 addition & 0 deletions Tasks/VsTestV2/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface TestConfigurations {
vsTestLocationMethod: string;
vsTestVersion: string;
vsTestLocation: string;
vstestArchitecture: string;
vsTestVersionDetails: version.VSTestVersion;
pathtoCustomTestAdapters: string;
tiaConfig: TiaConfiguration;
Expand Down
19 changes: 16 additions & 3 deletions Tasks/VsTestV2/task.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"author": "Microsoft Corporation",
"version": {
"Major": 2,
"Minor": 272,
"Minor": 273,
"Patch": 0
},
"demands": [
Expand Down Expand Up @@ -304,8 +304,20 @@
"helpMarkDown": "Other console options that can be passed to vstest.console.exe, as documented <a href=\"https://aka.ms/vstestotherconsoleoptions\" target=\"_blank\">here</a>. <p>These options are not supported and will be ignored when running tests using the ‘Multi agent’ parallel setting of an agent job or when running tests using ‘Test plan’ or 'Test run' option or when a custom batching option is selected. The options can be specified using a settings file instead.</p>",
"groupName": "executionOptions"
},
{
"name": "distributionBatchType",
{ "name": "vstestArchitecture",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: please update indentation

"type": "pickList",
"label": "Test runner architecture",
"defaultValue": "x64",
"required": false,
"helpMarkDown": "Optionally supply the architecture (x86, x64, arm64) of vstest.console.exe to run. Select arm64 to run tests natively on ARM64 Windows machines. Requires Visual Studio 2022 (17.0) or later.",
"groupName": "executionOptions",
"options": {
"x86": "x86",
"x64": "x64",
"arm64": "arm64"
}
},
{ "name": "distributionBatchType",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: please update documentation

"type": "pickList",
"label": "Batch tests",
"defaultValue": "basedOnTestCases",
Expand Down Expand Up @@ -588,6 +600,7 @@
"GenerateResponseFilePerfTime": "Total time taken to get response file: %d milliseconds.",
"UploadTestResultsPerfTime": "Total time taken to upload test results: %d milliseconds.",
"ErrorReadingVstestVersion": "Error reading the version of vstest.console.exe.",
"Arm64VstestNotFound": "ARM64 vstest.console.exe not found at '%s'. Falling back to x64 variant.",
"UnexpectedVersionString": "Unexpected version string detected for vstest.console.exe: %s.",
"UnexpectedVersionNumber": "Unexpected version number detected for vstest.console.exe: %s.",
"VstestDiagNotSupported": "vstest.console.exe version does not support the /diag flag. Enable diagnostics via the exe.config files",
Expand Down
17 changes: 16 additions & 1 deletion Tasks/VsTestV2/task.loc.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"author": "Microsoft Corporation",
"version": {
"Major": 2,
"Minor": 272,
"Minor": 273,
"Patch": 0
},
"demands": [
Expand Down Expand Up @@ -304,6 +304,20 @@
"helpMarkDown": "ms-resource:loc.input.help.otherConsoleOptions",
"groupName": "executionOptions"
},
{
"name": "vstestArchitecture",
"type": "pickList",
"label": "ms-resource:loc.input.label.vstestArchitecture",
"defaultValue": "x64",
"required": false,
"helpMarkDown": "ms-resource:loc.input.help.vstestArchitecture",
"groupName": "executionOptions",
"options": {
"x86": "x86",
"x64": "x64",
"arm64": "arm64"
}
},
{
"name": "distributionBatchType",
"type": "pickList",
Expand Down Expand Up @@ -588,6 +602,7 @@
"GenerateResponseFilePerfTime": "ms-resource:loc.messages.GenerateResponseFilePerfTime",
"UploadTestResultsPerfTime": "ms-resource:loc.messages.UploadTestResultsPerfTime",
"ErrorReadingVstestVersion": "ms-resource:loc.messages.ErrorReadingVstestVersion",
"Arm64VstestNotFound": "ms-resource:loc.messages.Arm64VstestNotFound",
"UnexpectedVersionString": "ms-resource:loc.messages.UnexpectedVersionString",
"UnexpectedVersionNumber": "ms-resource:loc.messages.UnexpectedVersionNumber",
"VstestDiagNotSupported": "ms-resource:loc.messages.VstestDiagNotSupported",
Expand Down
3 changes: 3 additions & 0 deletions Tasks/VsTestV2/taskinputparser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ function initTestConfigurations(testConfiguration: models.TestConfigurations) {
testConfiguration.otherConsoleOptions = tl.getInput('otherConsoleOptions');
console.log(tl.loc('otherConsoleOptionsInput', testConfiguration.otherConsoleOptions));

testConfiguration.vstestArchitecture = tl.getInput('vstestArchitecture') || 'x64';
console.log('vstestArchitecture: ' + testConfiguration.vstestArchitecture);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't this also needs to be localized, similar to other logs?


testConfiguration.codeCoverageEnabled = tl.getBoolInput('codeCoverageEnabled');
console.log(tl.loc('codeCoverageInput', testConfiguration.codeCoverageEnabled));

Expand Down
14 changes: 13 additions & 1 deletion Tasks/VsTestV2/versionfinder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,19 @@ function locateVSTestConsole(testConfig: models.TestConfigurations): string {
const vstestExeFolder = locateTestWindow(testConfig);
let vstestExePath: string = vstestExeFolder;
if (vstestExeFolder) {
vstestExePath = path.join(vstestExeFolder, 'vstest.console.exe');
if (testConfig.vstestArchitecture && testConfig.vstestArchitecture.toLowerCase() === 'arm64') {
// ARM64 native vstest.console.exe resides in the arm64 subdirectory (VS 2022 / 17.0+)
const arm64Path = path.join(vstestExeFolder, 'arm64', 'vstest.console.exe');
if (utils.Helper.pathExistsAsFile(arm64Path)) {
tl.debug('Found ARM64 vstest.console.exe at: ' + arm64Path);
vstestExePath = arm64Path;
} else {
tl.warning(tl.loc('Arm64VstestNotFound', arm64Path));
vstestExePath = path.join(vstestExeFolder, 'vstest.console.exe');
}
} else {
vstestExePath = path.join(vstestExeFolder, 'vstest.console.exe');
}
}
return vstestExePath;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
"loc.input.help.codeCoverageEnabled": "Collect code coverage information from the test run.",
"loc.input.label.otherConsoleOptions": "Other console options",
"loc.input.help.otherConsoleOptions": "Other console options that can be passed to vstest.console.exe, as documented <a href=\"https://aka.ms/vstestotherconsoleoptions\" target=\"_blank\">here</a>. <p>These options are not supported and will be ignored when running tests using the ‘Multi agent’ parallel setting of an agent job or when running tests using ‘Test plan’ or 'Test run' option or when a custom batching option is selected. The options can be specified using a settings file instead.</p>",
"loc.input.label.vstestArchitecture": "Test runner architecture",
"loc.input.help.vstestArchitecture": "Optionally supply the architecture (x86, x64, arm64) of vstest.console.exe to run. Select arm64 to run tests natively on ARM64 Windows machines. Requires Visual Studio 2022 (17.0) or later.",
"loc.input.label.distributionBatchType": "Batch tests",
"loc.input.help.distributionBatchType": "A batch is a group of tests. A batch of tests runs its tests at the same time and results are published for the batch. If the job in which the task runs is set to use multiple agents, each agent picks up any available batches of tests to run in parallel.<br><br><b>Based on the number of tests and agents:</b> Simple batching based on the number of tests and agents participating in the test run.<br><br><b>Based on past running time of tests:</b> This batching considers past running time to create batches of tests such that each batch has approximately equal running time.<br><br><b>Based on test assemblies:</b> Tests from an assembly are batched together.",
"loc.input.label.batchingBasedOnAgentsOption": "Batch options",
Expand Down Expand Up @@ -120,6 +122,7 @@
"loc.messages.GenerateResponseFilePerfTime": "Total time taken to get response file: %d milliseconds.",
"loc.messages.UploadTestResultsPerfTime": "Total time taken to upload test results: %d milliseconds.",
"loc.messages.ErrorReadingVstestVersion": "Error reading the version of vstest.console.exe.",
"loc.messages.Arm64VstestNotFound": "ARM64 vstest.console.exe not found at '%s'. Falling back to x64 variant.",
"loc.messages.UnexpectedVersionString": "Unexpected version string detected for vstest.console.exe: %s.",
"loc.messages.UnexpectedVersionNumber": "Unexpected version number detected for vstest.console.exe: %s.",
"loc.messages.VstestDiagNotSupported": "vstest.console.exe version does not support the /diag flag. Enable diagnostics via the exe.config files",
Expand Down
77 changes: 77 additions & 0 deletions Tasks/VsTestV3/Tests/L0.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,4 +296,81 @@ describe('VsTestV3 – versionfinder.ts (PowerShell Get-ItemProperty change)', f
'should throw UnexpectedVersionNumber for non-numeric version parts'
);
});

// -----------------------------------------------------------------------
// ARM64 architecture tests
// -----------------------------------------------------------------------

it('uses arm64/vstest.console.exe when vstestArchitecture is arm64 and arm64 binary exists', function() {
setupMocks('17.0.33.0\n');
// Override helpers mock so arm64 path exists; also keep base location valid
libMocker.registerMock('./helpers', {
Helper: {
pathExistsAsFile: function(p: string) { return p === fakeVsTestLocation || p.includes('arm64'); },
pathExistsAsDirectory: function(_p: string) { return false; },
isNullOrWhitespace: function(s: string) {
return s === null || s === undefined || s.replace(/\s/g, '').length < 1;
},
trimString: function(s: string) { return s ? s.trim() : s; },
getVSVersion: function(v: number) { return v.toString(); },
isToolsInstallerFlow: function(_config: any) { return false; }
},
Constants: { vsTestLocationString: 'location', vsTestVersionString: 'version' }
});
const vf = loadVersionfinder();
const config = Object.assign(makeTestConfig('17.0'), { vstestArchitecture: 'arm64' });

vf.getVsTestRunnerDetails(config);

assert.ok(config.vsTestVersionDetails);
assert.strictEqual(config.vsTestVersionDetails.majorVersion, 17);
// vstest location must include the arm64 subdirectory
assert.ok(
config.vsTestVersionDetails.vstestExeLocation.includes('arm64'),
'vstestExeLocation should include arm64 subdirectory'
);
});

it('falls back to x64 vstest.console.exe when vstestArchitecture is arm64 but arm64 binary is absent', function() {
setupMocks('17.0.33.0\n');
// pathExistsAsFile returns false for arm64 path, true for x64 path
libMocker.registerMock('./helpers', {
Helper: {
pathExistsAsFile: function(p: string) { return !p.includes('arm64'); },
pathExistsAsDirectory: function(_p: string) { return false; },
isNullOrWhitespace: function(s: string) {
return s === null || s === undefined || s.replace(/\s/g, '').length < 1;
},
trimString: function(s: string) { return s ? s.trim() : s; },
getVSVersion: function(v: number) { return v.toString(); },
isToolsInstallerFlow: function(_config: any) { return false; }
},
Constants: { vsTestLocationString: 'location', vsTestVersionString: 'version' }
});
const vf = loadVersionfinder();
const config = Object.assign(makeTestConfig('17.0'), { vstestArchitecture: 'arm64' });

vf.getVsTestRunnerDetails(config);

assert.ok(config.vsTestVersionDetails);
// Should fall back: location must not include arm64 subdirectory
assert.ok(
!config.vsTestVersionDetails.vstestExeLocation.split('\\').includes('arm64'),
'vstestExeLocation should NOT use arm64 subdirectory on fallback'
);
});

it('uses regular vstest.console.exe when vstestArchitecture is x64 (default)', function() {
setupMocks('17.0.33.0\n');
const vf = loadVersionfinder();
const config = Object.assign(makeTestConfig('17.0'), { vstestArchitecture: 'x64' });

vf.getVsTestRunnerDetails(config);

assert.ok(config.vsTestVersionDetails);
assert.ok(
!config.vsTestVersionDetails.vstestExeLocation.split('\\').includes('arm64'),
'x64 path should not include arm64 subdirectory'
);
});
});
1 change: 1 addition & 0 deletions Tasks/VsTestV3/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface TestConfigurations {
vsTestLocationMethod: string;
vsTestVersion: string;
vsTestLocation: string;
vstestArchitecture: string;
vsTestVersionDetails: version.VSTestVersion;
pathtoCustomTestAdapters: string;
tiaConfig: TiaConfiguration;
Expand Down
Loading