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
24 changes: 12 additions & 12 deletions .azure-pipelines/ci-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ extends:
os: windows
demands:
- msbuild
- vstest
customBuildTags:
- ES365AIMigrationTooling
stages:
Expand Down Expand Up @@ -111,19 +110,20 @@ extends:
projects: '$(Build.SourcesDirectory)\Microsoft.OpenApi.OData.sln'
arguments: '--configuration $(BuildConfiguration) --no-incremental'

# Both suites are in the solution, but SDK10 cannot run MTP via VSTest.
# Keep OData on VSTest and invoke the hidi MTP executable separately (#885).
- task: DotNetCoreCLI@2
displayName: 'test'
inputs:
command: test
projects: '$(Build.SourcesDirectory)\test\Microsoft.OpenAPI.OData.Reader.Tests\Microsoft.OpenAPI.OData.Reader.Tests.csproj'
arguments: '--configuration $(BuildConfiguration) --no-build'

- pwsh: |
dotnet run --project test\Microsoft.OpenApi.Hidi.Tests\Microsoft.OpenApi.Hidi.Tests.csproj -c $(BuildConfiguration) --no-build -- --minimum-expected-tests 1
dotnet test --solution Microsoft.OpenApi.OData.sln -c $(buildConfiguration) --no-build --results-directory '$(Agent.TempDirectory)\TestResults' -- --minimum-expected-tests 1 --report-trx --report-azdo
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
displayName: 'Test hidi (Microsoft.Testing.Platform)'
displayName: 'Test solution (Microsoft.Testing.Platform)'

- task: PublishTestResults@2
displayName: 'Publish solution test results'
condition: succeededOrFailed()
inputs:
testResultsFormat: VSTest
testResultsFiles: '$(Agent.TempDirectory)\TestResults\*.trx'
mergeTestResults: true
failTaskOnFailedTests: true
failTaskOnMissingResultsFile: true

- task: EsrpCodeSigning@6
displayName: 'ESRP CodeSigning'
Expand Down
17 changes: 15 additions & 2 deletions .azure-pipelines/hidi-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -135,16 +135,29 @@ extends:
$ErrorActionPreference = 'Stop'
dotnet build src\Microsoft.OpenApi.Hidi\Microsoft.OpenApi.Hidi.csproj -c $(buildConfiguration) -p:GeneratePackageOnBuild=false
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
dotnet run --project test\Microsoft.OpenApi.Hidi.Tests\Microsoft.OpenApi.Hidi.Tests.csproj -c $(buildConfiguration) -- --minimum-expected-tests 1
displayName: Build hidi
- pwsh: |
dotnet test --solution Microsoft.OpenApi.OData.sln -c $(buildConfiguration) --results-directory '$(Agent.TempDirectory)\TestResults' -- --minimum-expected-tests 1 --report-trx --report-azdo
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
displayName: Test solution (Microsoft.Testing.Platform)
- task: PublishTestResults@2
displayName: Publish solution test results
condition: succeededOrFailed()
inputs:
testResultsFormat: VSTest
testResultsFiles: '$(Agent.TempDirectory)\TestResults\*.trx'
mergeTestResults: true
failTaskOnFailedTests: true
failTaskOnMissingResultsFile: true
- pwsh: |
dotnet publish src\Microsoft.OpenApi.Hidi\Microsoft.OpenApi.Hidi.csproj -c $(buildConfiguration) -r win-x64 --self-contained true -p:PublishSingleFile=true -p:PackAsTool=false -p:GeneratePackageOnBuild=false -o artifacts\hidi\win-x64
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& .\artifacts\hidi\win-x64\Microsoft.OpenApi.Hidi.exe --help
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
New-Item -ItemType Directory -Force artifacts\hidi\signing | Out-Null
Copy-Item src\Microsoft.OpenApi.Hidi\bin\$(buildConfiguration)\net8.0\Microsoft.OpenApi.Hidi.dll artifacts\hidi\signing
Copy-Item artifacts\hidi\win-x64\Microsoft.OpenApi.Hidi.exe artifacts\hidi\signing
displayName: Build, test and stage hidi binaries
displayName: Stage hidi binaries
- task: EsrpCodeSigning@6
displayName: Sign hidi DLL and Windows executable
inputs:
Expand Down
24 changes: 10 additions & 14 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,22 +89,18 @@ jobs:
id: run_unit_tests
shell: pwsh
run: |
$testProjectsArray = @(
'.\test\Microsoft.OpenAPI.OData.Reader.Tests\Microsoft.OpenAPI.OData.Reader.Tests.csproj'
)

$testProjectsArray | ForEach-Object {
dotnet test $PSItem `
-c Release
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
}

- name: Run hidi tests (Microsoft.Testing.Platform)
shell: pwsh
run: |
dotnet run --project .\test\Microsoft.OpenApi.Hidi.Tests\Microsoft.OpenApi.Hidi.Tests.csproj -c Release -- --minimum-expected-tests 1
$resultsDirectory = Join-Path $PWD 'artifacts' 'test-results'
dotnet test --solution Microsoft.OpenApi.OData.sln -c Release -p:EnableWindowsTargeting=true --results-directory $resultsDirectory -- --minimum-expected-tests 1 --report-trx --report-gh
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

- name: Upload test results
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: test-results
path: artifacts/test-results
if-no-files-found: error

- name: Pack and install hidi locally
shell: pwsh
run: |
Expand Down
48 changes: 32 additions & 16 deletions .github/workflows/sonarcloud.yml
Original file line number Diff line number Diff line change
Expand Up @@ -122,30 +122,46 @@ jobs:
- name: Build and analyze
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
CollectCoverage: true
CoverletOutputFormat: 'opencover' # https://github.com/microsoft/vstest/issues/4014#issuecomment-1307913682
shell: pwsh
run: |
dotnet tool run dotnet-sonarscanner begin /k:"microsoft_OpenAPI.NET.OData" /o:"microsoft" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths="test/**/coverage.net8.0.opencover.xml,artifacts/hidi/coverage/*opencover*.xml" /d:sonar.coverageReportPaths="artifacts/hidi/powershell-coverage/sonar-coverage.xml"
dotnet tool run dotnet-sonarscanner begin /k:"microsoft_OpenAPI.NET.OData" /o:"microsoft" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths="artifacts/test-results/*opencover*.xml" /d:sonar.coverageReportPaths="artifacts/hidi/powershell-coverage/sonar-coverage.xml"
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
dotnet workload restore
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
dotnet build
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
dotnet test test\Microsoft.OpenAPI.OData.Reader.Tests\Microsoft.OpenAPI.OData.Reader.Tests.csproj --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover
dotnet test --solution Microsoft.OpenApi.OData.sln --no-build --results-directory artifacts\test-results -- --minimum-expected-tests 1 --report-trx --report-gh --coverlet --coverlet-output-format opencover --coverlet-include "[Microsoft.OpenApi.OData.Reader]*" --coverlet-include "[Microsoft.OpenApi.Hidi]*"
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
dotnet run --project test\Microsoft.OpenApi.Hidi.Tests\Microsoft.OpenApi.Hidi.Tests.csproj --no-build -- --minimum-expected-tests 1 --coverlet --coverlet-output-format opencover --coverlet-include "[Microsoft.OpenApi.Hidi]*" --results-directory artifacts\hidi\coverage
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
$reports = @(Get-ChildItem artifacts\hidi\coverage -Filter '*opencover*.xml')
if ($reports.Count -eq 0) { throw "Hidi OpenCover report was not generated." }
$hidiModules = @($reports | ForEach-Object {
([xml](Get-Content $_.FullName -Raw)).CoverageSession.Modules.Module
} | Where-Object { $_.ModuleName -eq 'Microsoft.OpenApi.Hidi' })
if (-not ($hidiModules | Where-Object {
$_.SelectNodes('./Classes/Class/Methods/Method/SequencePoints/SequencePoint').Count -gt 0 -and
$_.SelectNodes('./Classes/Class/Methods/Method/SequencePoints/SequencePoint[@vc > 0]').Count -gt 0
})) {
throw "Hidi OpenCover report contains no covered Hidi sequence points."
$reports = @(Get-ChildItem artifacts\test-results -Filter '*opencover*.xml')
if ($reports.Count -ne 2) { throw "Expected an OpenCover report from each test project." }
$modules = @($reports | ForEach-Object {
$report = [xml](Get-Content $_.FullName -Raw)
if ($report.SelectNodes('//SequencePoint').Count -eq 0 -or
$report.SelectNodes('//SequencePoint[@vc > 0]').Count -eq 0) {
throw "OpenCover report contains no covered sequence points: $($_.Name)"
}
$report.CoverageSession.Modules.Module
})
$expectedModules = @('Microsoft.OpenApi.OData.Reader', 'Microsoft.OpenApi.Hidi')
if ($modules | Where-Object { $_.ModuleName -notin $expectedModules }) {
throw "OpenCover reports contain unexpected modules."
}
foreach ($moduleName in $expectedModules) {
if (-not ($modules | Where-Object {
$_.ModuleName -eq $moduleName -and
$_.SelectNodes('./Classes/Class/Methods/Method/SequencePoints/SequencePoint').Count -gt 0 -and
$_.SelectNodes('./Classes/Class/Methods/Method/SequencePoints/SequencePoint[@vc > 0]').Count -gt 0
})) {
throw "OpenCover reports contain no covered sequence points for $moduleName."
}
}
dotnet tool run dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}"
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

- name: Upload test and coverage results
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: sonar-test-results
path: artifacts/test-results
if-no-files-found: error
31 changes: 21 additions & 10 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,21 @@
"group": "test",
"args": [
"test",
"--solution",
"${workspaceFolder}/Microsoft.OpenApi.OData.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary",
"--collect:\"XPlat Code Coverage\""
"-p:EnableWindowsTargeting=true",
"--results-directory",
"${workspaceFolder}/artifacts/test-results",
"--",
"--minimum-expected-tests",
"1",
"--coverlet",
"--coverlet-output-format",
"cobertura",
"--coverlet-include",
"[Microsoft.OpenApi.OData.Reader]*",
"--coverlet-include",
"[Microsoft.OpenApi.Hidi]*"
],
"problemMatcher": "$msCompile"
},
Expand All @@ -35,15 +46,15 @@
"linux": {
"command": "rm",
"args": [
"-r",
"${workspaceFolder}/test/Microsoft.OpenAPI.OData.Reader.Tests/TestResults"
"-rf",
"${workspaceFolder}/artifacts/test-results"
]
},
"windows": {
"command": "powershell",
"args": [
"-command",
"Remove-Item -Recurse -Include TestResults -Path ${workspaceFolder}/tests"
"if (Test-Path -LiteralPath '${workspaceFolder}/artifacts/test-results') { Remove-Item -Recurse -LiteralPath '${workspaceFolder}/artifacts/test-results' }"
]
}
},
Expand All @@ -54,14 +65,14 @@
"linux":{
"command": "reportgenerator",
"args": [
"-reports:${workspaceFolder}/tests/**/coverage.cobertura.xml",
"-reports:${workspaceFolder}/artifacts/test-results/*cobertura*.xml",
"-targetdir:${workspaceFolder}/reports/coverage"
],
},
"windows": {
"command": "reportgenerator",
"args": [
"-reports:${workspaceFolder}\\test\\**\\coverage.cobertura.xml",
"-reports:${workspaceFolder}\\artifacts\\test-results\\*cobertura*.xml",
"-targetdir:${workspaceFolder}\\reports\\coverage"
]
},
Expand All @@ -72,7 +83,7 @@
"dependsOrder": "sequence"
},
{
"label": "coverage:launch",
"label": "coverage:open",
"type": "shell",
"linux": {
"command": "xdg-open",
Expand Down Expand Up @@ -100,7 +111,7 @@
"dependsOrder": "sequence",
"dependsOn": [
"coverage:unit",
"coverage:launch"
"coverage:open"
]
},
{
Expand Down
33 changes: 33 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,39 @@ OpenAPI.net.OData is a mono-repo containing source code for the following packag
|----------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [Microsoft.OpenAPI.OData](./README.md) | [![NuGet Version](https://img.shields.io/nuget/vpre/Microsoft.OpenAPI.OData?label=Latest&logo=nuget)](https://www.nuget.org/packages/Microsoft.OpenAPI.OData/) |

## Building and testing

[Microsoft.OpenApi.Hidi](src/Microsoft.OpenApi.Hidi/readme.md) is a .NET tool,
not an OData library package. Install the .NET 10 SDK and .NET 8 runtime to build
and test both projects. Both test projects use xUnit v3 and
Microsoft.Testing.Platform, selected by `global.json`. Reader tests still target
.NET 8; Hidi tests target .NET 10.

```powershell
dotnet build Microsoft.OpenApi.OData.sln -c Release
dotnet test --solution Microsoft.OpenApi.OData.sln -c Release --no-build -- --minimum-expected-tests 1
```

On non-Windows hosts, pass `-p:EnableWindowsTargeting=true` to both commands
because the solution also contains the Windows-only GUI project.
Use `--project <path>` instead of `--solution <path>` for a single test project.
MTP options replace VSTest's `--logger`, `--collect`, and MSBuild coverage options:

```powershell
dotnet test --solution Microsoft.OpenApi.OData.sln -c Release --no-build --results-directory artifacts\test-results -- --minimum-expected-tests 1 --report-trx --coverlet --coverlet-output-format cobertura --coverlet-include "[Microsoft.OpenApi.OData.Reader]*" --coverlet-include "[Microsoft.OpenApi.Hidi]*"
```

This produces separate TRX and coverage reports for each test assembly.
CI uses `--report-gh` for GitHub Actions and `--report-azdo` with TRX publication
for Azure DevOps. SonarCloud collects OpenCover reports for both projects in
`artifacts/test-results`, alongside the separately measured Pester helper coverage.

Each test project's `testconfig.json` explicitly includes its product assembly.
Keep these files copied to the output directory: CLI include filters alone can
produce an empty Reader report with Coverlet's dynamic namespace exclusions.
SonarCloud rejects empty reports and unexpected modules, and requires covered
sequence points for both Reader and Hidi.

OpenAPI.net.OData is open to contributions. There are a couple of different recommended paths to get contributions into the released version of this library.

__NOTE__ A signed a contribution license agreement is required for all contributions, and is checked automatically on new pull requests. Please read and sign [the agreement](https://cla.microsoft.com/) before starting any work for this repository.
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ are accepted, a fresh official publish-disabled build verifies the packaged
Hidi DLL's signature and hash, and the source main publisher is retired for
cutover. See [the release prerequisites](src/Microsoft.OpenApi.Hidi/readme.md#release-cutover-prerequisites).

Both test projects use xUnit v3 and
Microsoft.Testing.Platform; OData tests still target .NET 8. Run them together
with `dotnet test --solution Microsoft.OpenApi.OData.sln -c Release -- --minimum-expected-tests 1`
(add `-p:EnableWindowsTargeting=true` on non-Windows hosts). See
[contributing](CONTRIBUTING.md#building-and-testing) for coverage and reporting commands.

---

# Contributing
Expand Down
23 changes: 4 additions & 19 deletions build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,7 @@ ForEach ($ver in $SNVersions)
}

# Other variables
$ProductProj = $ENLISTMENT_ROOT + "\src\Microsoft.OpenAPI.OData.Reader\Microsoft.OpenApi.OData.Reader.csproj"
$TESTProj = $ENLISTMENT_ROOT + "\test\Microsoft.OpenAPI.OData.Reader.Tests\Microsoft.OpenApi.OData.Reader.Tests.csproj"
$HidiProj = $ENLISTMENT_ROOT + "\src\Microsoft.OpenApi.Hidi\Microsoft.OpenApi.Hidi.csproj"
$HidiTESTProj = $ENLISTMENT_ROOT + "\test\Microsoft.OpenApi.Hidi.Tests\Microsoft.OpenApi.Hidi.Tests.csproj"
$Solution = $ENLISTMENT_ROOT + "\Microsoft.OpenApi.OData.sln"

$TESTDIR = $ENLISTMENT_ROOT + "\bin\$Configuration\Test\net472"
$PRODUCTDIR = $ENLISTMENT_ROOT + "\bin\$Configuration\net472"
Expand Down Expand Up @@ -188,18 +185,9 @@ Function BuildProcess

$script:BUILD_START_TIME = Get-Date

Write-Host "Build Product ..."
Write-Host "Build Solution ..."

& dotnet.exe build $ProductProj -c $Configuration

Write-Host "Build Test ..."

& dotnet.exe build $TESTProj -c $Configuration

Write-Host "Build Hidi ..."
& dotnet.exe build $HidiProj -c $Configuration
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& dotnet.exe build $HidiTESTProj -c $Configuration
& dotnet.exe build $Solution -c $Configuration
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

Write-Host "Build Done" -ForegroundColor $Success
Expand All @@ -212,10 +200,7 @@ Function TestProcess

$script:TEST_START_TIME = Get-Date

& dotnet test $TESTProj -c $Configuration
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

& dotnet run --project $HidiTESTProj -c $Configuration --no-build -- --minimum-expected-tests 1
& dotnet test --solution $Solution -c $Configuration --no-build -- --minimum-expected-tests 1
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

Write-Host "Test Done" -ForegroundColor $Success
Expand Down
3 changes: 3 additions & 0 deletions global.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@
"version": "10.0.100",
"rollForward": "latestFeature",
"allowPrerelease": false
},
"test": {
"runner": "Microsoft.Testing.Platform"
}
}
Loading
Loading