Add live Azure DevOps test result publishing#8297
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds opt-in live Azure DevOps test-result publishing to the existing Azure DevOps reporting extension, using REST APIs plus multi-process run coordination.
Changes:
- Adds new
--publish-azdo-*CLI options and wires the live publisher intoAddAzureDevOpsProvider(). - Implements REST client, result batching, run-id coordination, and localized resource strings.
- Adds unit coverage and updates all-extensions help/info expectations.
Show a summary per file
| File | Description |
|---|---|
Directory.Packages.props |
Adds System.Text.Json package version. |
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/Microsoft.Testing.Extensions.AzureDevOpsReport.csproj |
References System.Text.Json. |
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/AzureDevOpsCommandLineOptions.cs |
Adds live publishing option names. |
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/AzureDevOpsCommandLineProvider.cs |
Registers and validates new CLI options. |
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/AzureDevOpsExtensions.cs |
Wires publisher as data consumer and session lifetime handler. |
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/AzureDevOpsLivePublishingModels.cs |
Adds live publishing constants and DTOs. |
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/AzureDevOpsRunIdCoordinator.cs |
Adds multi-process run-id coordination. |
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/AzureDevOpsTestResultsClient.cs |
Adds Azure DevOps REST client. |
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/AzureDevOpsTestResultsPublisher.cs |
Adds live result publishing lifecycle and batching. |
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/IAzureDevOpsTestResultsClient.cs |
Adds internal client abstraction. |
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/Resources/AzureDevOpsResources.resx |
Adds localized strings for options and warnings. |
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/Resources/xlf/AzureDevOpsResources.cs.xlf |
Updates Czech localization resources. |
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/Resources/xlf/AzureDevOpsResources.de.xlf |
Updates German localization resources. |
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/Resources/xlf/AzureDevOpsResources.es.xlf |
Updates Spanish localization resources. |
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/Resources/xlf/AzureDevOpsResources.fr.xlf |
Updates French localization resources. |
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/Resources/xlf/AzureDevOpsResources.it.xlf |
Updates Italian localization resources. |
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/Resources/xlf/AzureDevOpsResources.ja.xlf |
Updates Japanese localization resources. |
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/Resources/xlf/AzureDevOpsResources.ko.xlf |
Updates Korean localization resources. |
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/Resources/xlf/AzureDevOpsResources.pl.xlf |
Updates Polish localization resources. |
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/Resources/xlf/AzureDevOpsResources.pt-BR.xlf |
Updates Portuguese localization resources. |
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/Resources/xlf/AzureDevOpsResources.ru.xlf |
Updates Russian localization resources. |
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/Resources/xlf/AzureDevOpsResources.tr.xlf |
Updates Turkish localization resources. |
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/Resources/xlf/AzureDevOpsResources.zh-Hans.xlf |
Updates Simplified Chinese localization resources. |
src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/Resources/xlf/AzureDevOpsResources.zh-Hant.xlf |
Updates Traditional Chinese localization resources. |
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/HelpInfoAllExtensionsTests.cs |
Updates help/info expectations for new options. |
test/UnitTests/Microsoft.Testing.Extensions.UnitTests/AzureDevOpsLivePublishingTests.cs |
Adds live publishing unit tests. |
Copilot's findings
- Files reviewed: 26/26 changed files
- Comments generated: 6
| TryDeleteFile(runIdFilePath); | ||
| TryDeleteFile(ownerFilePath); |
| private static bool ShouldRetry(Exception exception, CancellationToken userCancellationToken, CancellationToken requestCancellationToken, int attempt) | ||
| => attempt < MaxAttempts | ||
| && !userCancellationToken.IsCancellationRequested | ||
| && !requestCancellationToken.IsCancellationRequested | ||
| && exception is HttpRequestException or IOException or SocketException or TaskCanceledException; |
| await _runIdCoordinator.FinalizeRunAsync( | ||
| _coordinatedRun, | ||
| cancellationToken => _client.UpdateTestRunStateAsync(_publishConfiguration, CurrentRunId.Value, finalState, cancellationToken), | ||
| testSessionContext.CancellationToken).ConfigureAwait(false); |
|
|
||
| testApplicationModuleInfo ??= new Mock<ITestApplicationModuleInfo>(); | ||
| testApplicationModuleInfo.Setup(x => x.TryGetAssemblyName()).Returns("MyTests"); | ||
| testApplicationModuleInfo.Setup(x => x.GetCurrentTestApplicationFullPath()).Returns("Q:\\src\\testfx-worktrees\\azdo-live\\artifacts\\MyTests.dll"); |
| configuration.AccessToken, | ||
| new CreateTestRunRequest(configuration.RunName, true, new BuildReference(configuration.BuildId), AzureDevOpsLivePublishingConstants.InProgressTestRunState)); | ||
|
|
||
| CreateTestRunResponse response = await SendAsync<CreateTestRunResponse>(request, cancellationToken).ConfigureAwait(false); |
| </data> | ||
| <data name="OptionDescription" xml:space="preserve"> | ||
| <value>Eanble Azure DevOps report generator to write errors to the output in a way that AzureDev Ops understands.</value> | ||
| <value>Enable Azure DevOps report generator to write errors to the output in a way that AzureDev Ops understands.</value> |
|
@copilot address review comments |
…n id validation, cleanup token, cross-platform path, resx typo Co-authored-by: Evangelink <11340282+Evangelink@users.noreply.github.com>
All six review comments addressed in commit
|
|
@copilot address review comments |
There was a problem hiding this comment.
Copilot's findings
Comments suppressed due to low confidence (2)
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/HelpInfoAllExtensionsTests.cs:360
- This expected provider description still uses
AzureDev Ops, while the resource string now usesAzure DevOps; the--infoacceptance expectation should be updated to the corrected spelling.
Description: Azure DevOps report generator to write errors to the output in a way that AzureDev Ops understands.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/HelpInfoAllExtensionsTests.cs:373
- This expected option description still uses
AzureDev Ops, but the option resource now saysAzure DevOps, so this--infoexpectation will not match the generated output.
Description: Enable Azure DevOps report generator to write errors to the output in a way that AzureDev Ops understands.
- Files reviewed: 26/26 changed files
- Comments generated: 3
| --publish-azdo-test-results | ||
| Publish test results live to the Azure DevOps Tests tab. | ||
| --report-azdo | ||
| Enable Azure DevOps report generator to write errors to the output in a way that AzureDev Ops understands. |
| catch (Exception ex) when (ex is not OperationCanceledException) | ||
| { |
| await _runIdCoordinator.RenewLeaseAsync(_coordinatedRun, cancellationToken).ConfigureAwait(false); | ||
| _pendingResults.Enqueue(testCaseResult); |
|
@copilot address review comments |
All six review comments were already addressed in commit |
|
@copilot address review comments |
… OCE in flush, add background flush loop Co-authored-by: Evangelink <11340282+Evangelink@users.noreply.github.com>
…ore OCE filter on second catch Co-authored-by: Evangelink <11340282+Evangelink@users.noreply.github.com>
All three review comments addressed across two commits: Issue A — Acceptance test string fix (
Issue B — OCE preventing finalization (
Issue C — Background flush loop (
Using real All 34 AzureDevOps unit tests still pass (0 warnings, 0 errors). |
All three open review comments are addressed in the existing commits (
Build: 0 warnings, 0 errors. Unit tests: 34/34 passed. |
Part 1 of the brainstorm in #5951 — adds opt-in live test-result publishing to the Azure DevOps Tests tab via the REST API. No
Microsoft.TeamFoundationServer.Clientdependency; justHttpClient+System.Text.Json.Why
Today, getting results into the AzDO Tests tab requires generating a TRX and adding a downstream
PublishTestResults@2task. Two real problems:This PR publishes results to a single AzDO run as tests finish, with no TRX dependency.
What
Two new opt-in CLI options on
Microsoft.Testing.Extensions.AzureDevOpsReport:--publish-azdo-test-resultsSYSTEM_ACCESSTOKEN/SYSTEM_COLLECTIONURI/SYSTEM_TEAMPROJECTis missing.--publish-azdo-run-name <name><assembly> (<tfm>) on <agent>(or<stage>/<job>when present, sanitized). Requires--publish-azdo-test-results.Wired into the existing
AddAzureDevOpsProvider()— no new public API.How it works
Authorization: Basic base64(":<SYSTEM_ACCESSTOKEN>")(AzDO's standard PAT-as-basic-auth pattern). Token never logged.POST {project}/_apis/test/runs?api-version=7.1at session start, batchedPOST .../results?api-version=7.1asTestNodeUpdateMessages flow in,PATCH .../runs/{id}?api-version=7.1toCompleted(orAbortedon cancellation) at session end.AzureDevOpsRunIdCoordinatorwrites aazdo-runid.<buildId>.{owner,json,participant.<pid>.json}set underTestResultsDirectory. The first process creates the run; joiners read the id and publish into the same run. The owner waits for participants to drain (bounded timeout, defaults to 30s) before finalizing.HttpRequestException,IOException,SocketException, andTaskCanceledException(3 attempts, exponential backoff, 429 honorsRetry-After). All callbacks catchException ex when ex is not OperationCanceledExceptionand log a warning — publishing failures never fail the test run.Timeoutand per-request linkedCancellationTokenSource(15s).Highlights from the expert-reviewer round
Implementation went through one full round of
expert-reviewer. Critical/major issues addressed:FinalizeRunAsyncwait (no infinite hang on recycled PIDs).azdo-runid.jsonfrom a prior build no longer poisons the next build (ExpiresAtvalidated; coordination filenames keyed byBUILD_BUILDID; owner failures clean up the owner file).Exception ex when ex is not OperationCanceledExceptionsoJsonException/IOException/SocketExceptionno longer escapeIDataConsumercallbacks.HttpClient.Timeout+ per-request linked CTS — eliminates publisher-wide deadlock on a hung endpoint._lastFlushTimeis nowlong ticks+Interlocked.Read/Exchange(no tornDateTimeOffsetreads).ReadAsByteArrayAsync(ct)/ReadAsStringAsync(ct)under#if NET.HttpRequestException or IOException or SocketException or TaskCanceledException.[JsonPropertyName]on every wire DTO (request and response).automatedTestStoragenow strips the extension so it matches legacy TRX-uploaded history keys.Environment.ProcessId/int.MaxValuefor alive/dead PIDs and unique temp dirs underPath.GetTempPath()with cleanup-on-failure.Owner re-election on owner-process crash is deferred behind a clear
TODO(AzureDevOpsRunIdCoordinator.cs) with periodic lease renewal so a clean run never trips the bounded wait.Tests
127 unit tests pass. New coverage in
test/UnitTests/Microsoft.Testing.Extensions.UnitTests/AzureDevOpsLivePublishingTests.cs:Retry-After.HelpInfoAllExtensionsTestsexpectations updated for the new options (both--helpand--infoblocks, alphabetical order preserved).Build status (local)
.\.dotnet\dotnet.exe build src\Platform\Microsoft.Testing.Extensions.AzureDevOpsReport\Microsoft.Testing.Extensions.AzureDevOpsReport.csproj -c Debug— 0 warnings, 0 errors..\.dotnet\dotnet.exe test test\UnitTests\Microsoft.Testing.Extensions.UnitTests\Microsoft.Testing.Extensions.UnitTests.csproj— 127/127 passed..\build.cmd -pack— 0 warnings, 0 errors.Out of scope (deliberate)
Checklist
/t:UpdateXlf, not hand-edited).\build.cmdgreen (0 warnings, 0 errors)Refs #5951