feat(benchmarks): Add EntityFrameworkCore BenchmarkDotNet tests (#564) #397
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: .NET Quality Gate | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| workflow_dispatch: | |
| env: | |
| DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true | |
| DOTNET_NOLOGO: true | |
| DOTNET_SDK_VERSION: "10.0.x" | |
| jobs: | |
| # Quick quality checks - format and build | |
| quality-check: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Setup .NET SDK | |
| uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_SDK_VERSION }} | |
| - name: Cache NuGet packages | |
| uses: actions/cache@v5 | |
| with: | |
| path: ~/.nuget/packages | |
| key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/Directory.*.props') }} | |
| restore-keys: | | |
| ${{ runner.os }}-nuget- | |
| - name: Restore | |
| run: dotnet restore Encina.slnx | |
| - name: Enforce formatting | |
| run: dotnet format Encina.slnx --verify-no-changes | |
| - name: Build with analyzers | |
| run: dotnet build Encina.slnx --configuration Release --no-restore -warnaserror | |
| # Run tests in parallel using matrix strategy (excluding integration tests) | |
| test: | |
| needs: quality-check | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| permissions: | |
| contents: read | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| test-project: | |
| # Unit tests split into shards by namespace for parallel execution | |
| # Shard 1: Testing (~1827 tests) | |
| - name: UnitTests-Shard1 | |
| project: tests/Encina.UnitTests/Encina.UnitTests.csproj | |
| filter: "FullyQualifiedName~Encina.UnitTests.Testing" | |
| # Shard 2: Messaging + Caching (~1274 tests) | |
| - name: UnitTests-Shard2 | |
| project: tests/Encina.UnitTests/Encina.UnitTests.csproj | |
| filter: "FullyQualifiedName~Encina.UnitTests.Messaging|FullyQualifiedName~Encina.UnitTests.Caching" | |
| # Shard 3: Data providers (~576 tests) | |
| - name: UnitTests-Shard3 | |
| project: tests/Encina.UnitTests/Encina.UnitTests.csproj | |
| filter: "FullyQualifiedName~Encina.UnitTests.EntityFrameworkCore|FullyQualifiedName~Encina.UnitTests.Dapper|FullyQualifiedName~Encina.UnitTests.ADO|FullyQualifiedName~Encina.UnitTests.MongoDB|FullyQualifiedName~Encina.UnitTests.Marten" | |
| # Shard 4a: Azure + Polly (~420 tests) - these tests tend to be slower | |
| - name: UnitTests-Shard4a | |
| project: tests/Encina.UnitTests/Encina.UnitTests.csproj | |
| filter: "FullyQualifiedName~Encina.UnitTests.AzureFunctions|FullyQualifiedName~Encina.UnitTests.AzureServiceBus|FullyQualifiedName~Encina.UnitTests.Polly" | |
| # Shard 4b: AWS + Aspire + Observability (~180 tests) | |
| # Note: DistributedLock tests excluded due to hanging (see issue #531) | |
| - name: UnitTests-Shard4b | |
| project: tests/Encina.UnitTests/Encina.UnitTests.csproj | |
| filter: "FullyQualifiedName~Encina.UnitTests.AwsLambda|FullyQualifiedName~Encina.UnitTests.Aspire|FullyQualifiedName~Encina.UnitTests.OpenTelemetry" | |
| # Remaining namespaces split to balance load | |
| - name: UnitTests-Remaining | |
| project: tests/Encina.UnitTests/Encina.UnitTests.csproj | |
| filter: "FullyQualifiedName~Encina.UnitTests.Core|FullyQualifiedName~Encina.UnitTests.DomainModeling|FullyQualifiedName~Encina.UnitTests.AspNetCore|FullyQualifiedName~Encina.UnitTests.gRPC|FullyQualifiedName~Encina.UnitTests.SignalR|FullyQualifiedName~Encina.UnitTests.GuardClauses|FullyQualifiedName~Encina.UnitTests.MQTT|FullyQualifiedName~Encina.UnitTests.NATS|FullyQualifiedName~Encina.UnitTests.RabbitMQ|FullyQualifiedName~Encina.UnitTests.AmazonSQS|FullyQualifiedName~Encina.UnitTests.Kafka|FullyQualifiedName~Encina.UnitTests.Workflows|FullyQualifiedName~Encina.UnitTests.MiniValidator|FullyQualifiedName~Encina.UnitTests.FluentValidation|FullyQualifiedName~Encina.UnitTests.DataAnnotations|FullyQualifiedName~Encina.UnitTests.Quartz|FullyQualifiedName~Encina.UnitTests.Hangfire|FullyQualifiedName~Encina.UnitTests.Extensions|FullyQualifiedName~Encina.UnitTests.Refit|FullyQualifiedName~Encina.UnitTests.Cli" | |
| # Other test projects (excluding IntegrationTests which has its own sharded job) | |
| - name: ContractTests | |
| project: tests/Encina.ContractTests/Encina.ContractTests.csproj | |
| filter: "" | |
| - name: PropertyTests | |
| project: tests/Encina.PropertyTests/Encina.PropertyTests.csproj | |
| filter: "" | |
| - name: GuardTests | |
| project: tests/Encina.GuardTests/Encina.GuardTests.csproj | |
| filter: "" | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Setup .NET SDK | |
| uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_SDK_VERSION }} | |
| - name: Cache NuGet packages | |
| uses: actions/cache@v5 | |
| with: | |
| path: ~/.nuget/packages | |
| key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/Directory.*.props') }} | |
| restore-keys: | | |
| ${{ runner.os }}-nuget- | |
| - name: Restore | |
| run: dotnet restore Encina.slnx | |
| - name: Build | |
| run: dotnet build Encina.slnx --configuration Release --no-restore | |
| - name: Test ${{ matrix.test-project.name }} | |
| id: test | |
| run: | | |
| FILTER="${{ matrix.test-project.filter }}" | |
| if [ -n "$FILTER" ]; then | |
| dotnet test ${{ matrix.test-project.project }} -c Release --no-build \ | |
| --filter "$FILTER" \ | |
| --collect "XPlat Code Coverage" \ | |
| --results-directory artifacts/test-results/${{ matrix.test-project.name }} \ | |
| --logger "trx;LogFileName=${{ matrix.test-project.name }}.trx" \ | |
| -- xunit.parallelizeTestCollections=true | |
| else | |
| dotnet test ${{ matrix.test-project.project }} -c Release --no-build \ | |
| --collect "XPlat Code Coverage" \ | |
| --results-directory artifacts/test-results/${{ matrix.test-project.name }} \ | |
| --logger "trx;LogFileName=${{ matrix.test-project.name }}.trx" \ | |
| -- xunit.parallelizeTestCollections=true | |
| fi | |
| continue-on-error: true | |
| - name: Upload test results | |
| if: always() | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: test-results-${{ matrix.test-project.name }} | |
| path: artifacts/test-results/${{ matrix.test-project.name }} | |
| if-no-files-found: ignore | |
| - name: Check test outcome | |
| if: steps.test.outcome == 'failure' | |
| run: | | |
| echo "::warning::Tests in ${{ matrix.test-project.name }} failed. Check artifacts for details." | |
| # Integration tests - split into shards for parallel execution and reduced disk usage | |
| test-integration: | |
| needs: quality-check | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| permissions: | |
| contents: read | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| shard: | |
| - name: ADO | |
| filter: "FullyQualifiedName~IntegrationTests.ADO" | |
| - name: Dapper | |
| filter: "FullyQualifiedName~IntegrationTests.Dapper" | |
| - name: EFCore | |
| filter: "FullyQualifiedName~IntegrationTests.Infrastructure" | |
| steps: | |
| - name: Free disk space | |
| run: | | |
| echo "=== Disk space before cleanup ===" | |
| df -h / | |
| sudo rm -rf /usr/share/dotnet/shared/Microsoft.AspNetCore.App/6.0.* || true | |
| sudo rm -rf /usr/share/dotnet/shared/Microsoft.AspNetCore.App/7.0.* || true | |
| sudo rm -rf /usr/share/dotnet/shared/Microsoft.AspNetCore.App/8.0.* || true | |
| sudo rm -rf /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.* || true | |
| sudo rm -rf /usr/share/dotnet/shared/Microsoft.NETCore.App/7.0.* || true | |
| sudo rm -rf /usr/share/dotnet/shared/Microsoft.NETCore.App/8.0.* || true | |
| sudo rm -rf /usr/local/lib/android || true | |
| sudo rm -rf /opt/ghc || true | |
| sudo rm -rf /opt/hostedtoolcache/CodeQL || true | |
| echo "=== Disk space after cleanup ===" | |
| df -h / | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Setup .NET SDK | |
| uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_SDK_VERSION }} | |
| - name: Cache NuGet packages | |
| uses: actions/cache@v5 | |
| with: | |
| path: ~/.nuget/packages | |
| key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/Directory.*.props') }} | |
| restore-keys: | | |
| ${{ runner.os }}-nuget- | |
| - name: Restore | |
| run: dotnet restore Encina.slnx | |
| - name: Build | |
| run: dotnet build Encina.slnx --configuration Release --no-restore | |
| - name: Run Integration tests (${{ matrix.shard.name }}) | |
| id: test | |
| run: | | |
| dotnet test tests/Encina.IntegrationTests/Encina.IntegrationTests.csproj -c Release --no-build \ | |
| --filter "${{ matrix.shard.filter }}" \ | |
| --collect "XPlat Code Coverage" \ | |
| --results-directory artifacts/test-results/IntegrationTests-${{ matrix.shard.name }} \ | |
| --logger "trx;LogFileName=IntegrationTests-${{ matrix.shard.name }}.trx" \ | |
| -- xunit.parallelizeTestCollections=true | |
| continue-on-error: true | |
| - name: Upload test results | |
| if: always() | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: test-results-IntegrationTests-${{ matrix.shard.name }} | |
| path: artifacts/test-results/IntegrationTests-${{ matrix.shard.name }} | |
| if-no-files-found: ignore | |
| - name: Check test outcome | |
| if: steps.test.outcome == 'failure' | |
| run: | | |
| echo "::warning::Integration tests (${{ matrix.shard.name }}) failed. Check artifacts for details." | |
| # Aggregate coverage after all tests complete | |
| coverage: | |
| needs: [test, test-integration] | |
| runs-on: ubuntu-latest | |
| if: always() | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Setup .NET SDK | |
| uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_SDK_VERSION }} | |
| - name: Download all test results | |
| uses: actions/download-artifact@v7 | |
| with: | |
| path: artifacts/test-results | |
| pattern: test-results-* | |
| merge-multiple: true | |
| - name: Restore .NET tools | |
| run: dotnet tool restore | |
| - name: Generate coverage report | |
| run: | | |
| dotnet tool run reportgenerator \ | |
| -reports:"artifacts/test-results/**/coverage.cobertura.xml" \ | |
| -targetdir:"artifacts/coverage" \ | |
| -reporttypes:"Html;HtmlSummary;TextSummary;JsonSummary" || true | |
| - name: Publish coverage summary | |
| if: always() | |
| run: | | |
| if [ -f "artifacts/coverage/Summary.txt" ]; then | |
| { | |
| echo '## Coverage Summary' | |
| echo '```' | |
| cat artifacts/coverage/Summary.txt | |
| echo '```' | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| fi | |
| - name: Upload coverage artifact | |
| if: always() | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: coverage-report | |
| path: artifacts/coverage | |
| if-no-files-found: ignore |