Skip to content
Draft
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ vcpkg_installed/

# Temporary folder to refresh SDK with TypeSpec.
TempTypeSpecFiles/
test-results/
125 changes: 125 additions & 0 deletions eng/scripts/Convert-TestResultsToJUnit.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#!/usr/bin/env pwsh

#Requires -Version 7.0
<#
.SYNOPSIS
Converts cargo test JSON output to JUnit XML format using cargo2junit.

.DESCRIPTION
This script converts the JSON output files from cargo test (captured by Test-Packages.ps1 in CI mode)
to JUnit XML format suitable for publishing to Azure DevOps test results using the cargo2junit tool.

.PARAMETER TestResultsDirectory
The directory containing JSON test result files. Defaults to test-results in the repo root.

.PARAMETER OutputDirectory
The directory where JUnit XML files should be written. Defaults to test-results/junit in the repo root.

.EXAMPLE
./eng/scripts/Convert-TestResultsToJUnit.ps1

.EXAMPLE
./eng/scripts/Convert-TestResultsToJUnit.ps1 -TestResultsDirectory ./test-results -OutputDirectory ./junit-results
#>

param(
[string]$TestResultsDirectory,
[string]$OutputDirectory
)

$ErrorActionPreference = 'Stop'
Set-StrictMode -Version 2.0

# Get repo root
$RepoRoot = Resolve-Path (Join-Path $PSScriptRoot .. ..)

# Set default directories
if (!$TestResultsDirectory) {
$TestResultsDirectory = Join-Path $RepoRoot "test-results"
}

if (!$OutputDirectory) {
$OutputDirectory = Join-Path $RepoRoot "test-results" "junit"
}

Write-Host "Converting test results from JSON to JUnit XML using cargo2junit"
Write-Host " Input directory: $TestResultsDirectory"
Write-Host " Output directory: $OutputDirectory"

# Check if test results directory exists
if (!(Test-Path $TestResultsDirectory)) {
Write-Warning "Test results directory not found: $TestResultsDirectory"
Write-Host "No test results to convert."
exit 0
}

# Create output directory if it doesn't exist
if (!(Test-Path $OutputDirectory)) {
New-Item -ItemType Directory -Path $OutputDirectory | Out-Null
Write-Host "Created output directory: $OutputDirectory"
}

# Check if cargo2junit is installed
$cargo2junitPath = Get-Command cargo2junit -ErrorAction SilentlyContinue
if (!$cargo2junitPath) {
Write-Host "cargo2junit not found. Installing..."
cargo install cargo2junit
if ($LASTEXITCODE -ne 0) {
Write-Error "Failed to install cargo2junit"
exit 1
}
Write-Host "cargo2junit installed successfully"
}

# Get all JSON files in the test results directory
$jsonFiles = @(Get-ChildItem -Path $TestResultsDirectory -Filter "*.json" -File)

if ($jsonFiles.Count -eq 0) {
Write-Warning "No JSON files found in $TestResultsDirectory"
Write-Host "No test results to convert."
exit 0
}

Write-Host "`nConverting $($jsonFiles.Count) JSON file(s) to JUnit XML..."

$convertedCount = 0
$failedCount = 0

foreach ($jsonFile in $jsonFiles) {
$baseName = [System.IO.Path]::GetFileNameWithoutExtension($jsonFile.Name)
$junitFile = Join-Path $OutputDirectory "$baseName.xml"

Write-Host " Converting: $($jsonFile.Name) -> $([System.IO.Path]::GetFileName($junitFile))"

try {
# Convert JSON to JUnit XML using cargo2junit
Get-Content $jsonFile.FullName | cargo2junit > $junitFile

if ($LASTEXITCODE -ne 0) {
Write-Warning " cargo2junit returned exit code $LASTEXITCODE for $($jsonFile.Name)"
$failedCount++
}
else {
$convertedCount++
}
}
catch {
Write-Warning " Failed to convert $($jsonFile.Name): $_"
$failedCount++
}
}

Write-Host "`nConversion complete:"
Write-Host " Successfully converted: $convertedCount"
if ($failedCount -gt 0) {
Write-Host " Failed to convert: $failedCount" -ForegroundColor Yellow
}

Write-Host "`nJUnit XML files are available in: $OutputDirectory"

# Exit with error if any conversions failed
if ($failedCount -gt 0) {
exit 1
}

exit 0
150 changes: 150 additions & 0 deletions eng/scripts/TEST-RESULTS-README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# Test Results Reporting

This directory contains scripts for capturing cargo test results and converting them to JUnit XML format for Azure DevOps.

## Overview

The test results reporting uses:
1. **Nightly Rust's native JSON test output** (`cargo +nightly test -- --format json -Z unstable-options`)
2. **cargo2junit** tool to convert JSON to JUnit XML

## Scripts

### Test-Packages.ps1

Enhanced to support CI mode with `-CI` switch parameter.

**CI Mode (`-CI` flag):**
- Uses `cargo +nightly test -- --format json -Z unstable-options`
- Captures JSON output to uniquely named files in `test-results/` directory
- Parses JSON and displays human-readable summaries
- Shows pass/fail/ignored counts and lists failed tests

**Standard Mode (no `-CI` flag):**
- Original behavior using `Invoke-LoggedCommand`
- Human-readable output directly to console

**Usage:**
```powershell
# CI mode
./eng/scripts/Test-Packages.ps1 -PackageInfoDirectory ./PackageInfo -CI

# Standard mode
./eng/scripts/Test-Packages.ps1 -PackageInfoDirectory ./PackageInfo
```

### Convert-TestResultsToJUnit.ps1

Converts JSON test results to JUnit XML format using cargo2junit.

**Features:**
- Automatically installs cargo2junit if not present
- Processes all JSON files in test-results directory
- Outputs JUnit XML to test-results/junit directory
- Compatible with Azure DevOps PublishTestResults task

**Usage:**
```powershell
./eng/scripts/Convert-TestResultsToJUnit.ps1

# Or with custom directories
./eng/scripts/Convert-TestResultsToJUnit.ps1 -TestResultsDirectory ./test-results -OutputDirectory ./junit
```

## Pipeline Integration

Example Azure DevOps pipeline YAML:

```yaml
# Run tests with JSON output capture
- task: Powershell@2
displayName: "Test Packages"
inputs:
pwsh: true
filePath: $(Build.SourcesDirectory)/eng/scripts/Test-Packages.ps1
arguments: >
-PackageInfoDirectory '$(Build.ArtifactStagingDirectory)/PackageInfo'
-CI

# Convert JSON to JUnit XML
- task: Powershell@2
displayName: "Convert Test Results to JUnit XML"
condition: succeededOrFailed()
inputs:
pwsh: true
filePath: $(Build.SourcesDirectory)/eng/scripts/Convert-TestResultsToJUnit.ps1

# Publish test results to Azure DevOps
- task: PublishTestResults@2
displayName: "Publish Test Results"
condition: succeededOrFailed()
inputs:
testResultsFormat: 'JUnit'
testResultsFiles: '**/test-results/junit/*.xml'
testRunTitle: 'Rust Tests'
mergeTestResults: true
failTaskOnFailedTests: false
```

## Requirements

- **PowerShell 7.0+** (already required by existing scripts)
- **Nightly Rust toolchain** (installed automatically by rustup when using `cargo +nightly`)
- **cargo2junit** (installed automatically by Convert-TestResultsToJUnit.ps1 if needed)

## Test Results Format

### Directory Structure
```
test-results/
├── {package}-doctest-{timestamp}.json # JSON test output from doc tests
├── {package}-alltargets-{timestamp}.json # JSON test output from all-targets tests
└── junit/
├── {package}-doctest-{timestamp}.xml # JUnit XML for doc tests
└── {package}-alltargets-{timestamp}.xml # JUnit XML for all-targets tests
```

### JSON Format

Nightly Rust outputs newline-delimited JSON with events like:
```json
{ "type": "test", "event": "started", "name": "test_name" }
{ "type": "test", "name": "test_name", "event": "ok" }
{ "type": "suite", "event": "ok", "passed": 30, "failed": 0, "ignored": 0 }
```

### JUnit XML Format

cargo2junit converts to standard JUnit XML:
```xml
<testsuites>
<testsuite name="..." tests="30" errors="0" failures="0">
<testcase name="test_name" classname="module::tests" />
</testsuite>
</testsuites>
```

## Troubleshooting

### Nightly Rust not installed
If you see errors about nightly not being available:
```bash
rustup toolchain install nightly
```

### cargo2junit not found
The Convert-TestResultsToJUnit.ps1 script automatically installs it, but you can manually install:
```bash
cargo install cargo2junit
```

### No test results generated
Make sure the `-CI` flag is passed to Test-Packages.ps1 when running in CI mode.

## Benefits of This Approach

1. **Native Format**: Uses Rust's native JSON test output format (no custom parsing)
2. **Reliable**: cargo2junit is purpose-built for this conversion
3. **Simple**: Minimal code, leverages existing tools
4. **Maintainable**: Less custom code to maintain
5. **Feature-Rich**: Gets full test metadata from Rust's test harness
Loading