Skip to content

Commit 9343d2a

Browse files
Max CharlambCopilot
andcommitted
[cDAC] Attach each stress log to its per-debuggee test sub-result
The legacy Helix->ADO reporter models a [Theory] as a single test result with one sub-result per data row. Attaching all logs to the parent result put them on the top-level test instead of each debuggee's run. Parse the debuggee from each sub-result's display name (debuggeeName) and attach that debuggee's log to the matching sub-result via testSubResultId; single-row theories (Windows-only PInvoke) attach to the result directly. Unmapped logs fall back to run level. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent e588333 commit 9343d2a

1 file changed

Lines changed: 70 additions & 20 deletions

File tree

eng/pipelines/cdac/attach-cdac-stress-logs.ps1

Lines changed: 70 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616
1. Finds this leg's test run for the build (matched by the unique
1717
TestRunNamePrefix set in cdac-stress-helix.proj).
1818
2. Extracts the per-debuggee logs from the downloaded tarball.
19-
3. Attaches each log to the run's GCStress test result(s) via the Azure
20-
DevOps Test Attachments REST API (falling back to a run-level attachment
21-
if no matching result is found).
19+
3. Attaches each log to its own per-debuggee test result. The legacy
20+
reporter models a [Theory] as one result with a sub-result per data row,
21+
so each debuggee's log is attached to its sub-result (via
22+
testSubResultId); single-row theories are attached to the result itself.
23+
Anything that can't be mapped is attached at the run level so no log is
24+
lost.
2225
2326
Failures here are non-fatal: the build artifact remains the source of truth,
2427
so the script logs warnings and always exits 0.
@@ -104,42 +107,89 @@ try {
104107
return $name
105108
}
106109

110+
# Pull the debuggee name out of an xUnit display name like
111+
# '...GCStress_AllVerificationsPass(debuggeeName: "BasicAlloc")'.
112+
function Get-Debuggee([string]$name) {
113+
if ([string]::IsNullOrEmpty($name)) { return $null }
114+
$m = [regex]::Match($name, 'debuggeeName:\s*\\?"(?<d>[^"\\]+)')
115+
if ($m.Success) { return $m.Groups['d'].Value }
116+
return $null
117+
}
118+
119+
# Map each downloaded log to its debuggee (case-insensitive) so we can attach
120+
# it to the matching per-debuggee test result / sub-result.
121+
$logByDebuggee = @{}
122+
foreach ($log in $logFiles) {
123+
$m = [regex]::Match($log.Name, '^cdac-gcstress-(?<d>.+?)-[0-9a-fA-F]{32}\.txt$')
124+
if ($m.Success) { $logByDebuggee[$m.Groups['d'].Value.ToLowerInvariant()] = $log }
125+
}
126+
107127
foreach ($run in $matchingRuns) {
108128
$runId = $run.id
109129
$resultsUri = "$baseUrl/_apis/test/runs/$runId/results?api-version=7.1"
110130
$results = Invoke-RestMethod -Headers $headers -Uri $resultsUri -Method Get
111131
$gcStressResults = @($results.value | Where-Object { $_.automatedTestName -match 'GCStress' })
112132

113133
$attached = 0
114-
if ($gcStressResults.Count -gt 0) {
115-
# Attach every log to each GCStress result so they appear in the
116-
# result's Attachments pane (the data-driven theory collapses to a
117-
# single result, so over-attaching is both harmless and complete).
118-
foreach ($res in $gcStressResults) {
119-
$uri = "$baseUrl/_apis/test/Runs/$runId/Results/$($res.id)/attachments?api-version=$apiVer"
120-
foreach ($log in $logFiles) {
134+
$usedDebuggees = New-Object 'System.Collections.Generic.HashSet[string]'
135+
136+
# Attach each debuggee's log to its own test result. The legacy reporter
137+
# models a [Theory] as a single result with one sub-result per data row,
138+
# so the per-debuggee runs are sub-results (attach via testSubResultId).
139+
# A single-row theory (e.g. the Windows-only PInvoke case) stays as a
140+
# standalone result with the arg in its name (attach to the result).
141+
foreach ($res in $gcStressResults) {
142+
$detail = Invoke-RestMethod -Headers $headers -Uri "$baseUrl/_apis/test/runs/$runId/results/$($res.id)?detailsToInclude=SubResults&api-version=7.1" -Method Get
143+
$subs = @($detail.subResults)
144+
145+
if ($subs.Count -gt 0) {
146+
foreach ($sub in $subs) {
147+
$d = Get-Debuggee $sub.displayName
148+
if ($d -and $logByDebuggee.ContainsKey($d.ToLowerInvariant())) {
149+
$log = $logByDebuggee[$d.ToLowerInvariant()]
150+
$uri = "$baseUrl/_apis/test/Runs/$runId/Results/$($res.id)/attachments?testSubResultId=$($sub.id)&api-version=$apiVer"
151+
try {
152+
Add-Attachment -uri $uri -fileName "$d.txt" -filePath $log.FullName
153+
$attached++; [void]$usedDebuggees.Add($d.ToLowerInvariant())
154+
} catch {
155+
Write-Warn "Failed to attach '$($log.Name)' to run $runId result $($res.id) sub $($sub.id): $($_.Exception.Message)"
156+
}
157+
} else {
158+
Write-Warn "No log found for sub-result debuggee '$d' (result $($res.id))."
159+
}
160+
}
161+
} else {
162+
$d = Get-Debuggee $res.automatedTestName
163+
if ($d -and $logByDebuggee.ContainsKey($d.ToLowerInvariant())) {
164+
$log = $logByDebuggee[$d.ToLowerInvariant()]
165+
$uri = "$baseUrl/_apis/test/Runs/$runId/Results/$($res.id)/attachments?api-version=$apiVer"
121166
try {
122-
Add-Attachment -uri $uri -fileName (Get-CleanName $log.Name) -filePath $log.FullName
123-
$attached++
167+
Add-Attachment -uri $uri -fileName "$d.txt" -filePath $log.FullName
168+
$attached++; [void]$usedDebuggees.Add($d.ToLowerInvariant())
124169
} catch {
125170
Write-Warn "Failed to attach '$($log.Name)' to run $runId result $($res.id): $($_.Exception.Message)"
126171
}
127172
}
128173
}
129-
Write-Info "Run $runId ('$($run.name)'): attached $attached log(s) across $($gcStressResults.Count) GCStress result(s)."
130-
} else {
131-
# Fallback: attach at the run level.
132-
$uri = "$baseUrl/_apis/test/Runs/$runId/attachments?api-version=$apiVer"
133-
foreach ($log in $logFiles) {
174+
}
175+
176+
# Fallback: any log we couldn't map to a result/sub-result (e.g. a
177+
# debuggee that crashed before producing a result) is attached at the run
178+
# level so nothing is silently lost.
179+
foreach ($kv in $logByDebuggee.GetEnumerator()) {
180+
if (-not $usedDebuggees.Contains($kv.Key)) {
181+
$uri = "$baseUrl/_apis/test/Runs/$runId/attachments?api-version=$apiVer"
134182
try {
135-
Add-Attachment -uri $uri -fileName (Get-CleanName $log.Name) -filePath $log.FullName
183+
Add-Attachment -uri $uri -fileName (Get-CleanName $kv.Value.Name) -filePath $kv.Value.FullName
136184
$attached++
185+
Write-Warn "Debuggee '$($kv.Key)' had no matching test result; attached '$($kv.Value.Name)' at run level."
137186
} catch {
138-
Write-Warn "Failed to attach '$($log.Name)' to run ${runId}: $($_.Exception.Message)"
187+
Write-Warn "Failed to attach unmatched '$($kv.Value.Name)' to run ${runId}: $($_.Exception.Message)"
139188
}
140189
}
141-
Write-Info "Run $runId ('$($run.name)'): no GCStress result found; attached $attached log(s) at run level."
142190
}
191+
192+
Write-Info "Run $runId ('$($run.name)'): attached $attached log(s) ($($usedDebuggees.Count) mapped to per-debuggee results)."
143193
}
144194
}
145195
catch {

0 commit comments

Comments
 (0)