diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d3bcdfb490..39eb314637 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,8 @@ jobs: strategy: matrix: os: [windows-latest, ubuntu-latest] - test-category: [ Default, SqlServer, SqlServerPersistence, AzureServiceBus, RabbitMQ, AzureStorageQueues, MSMQ, SQS, PrimaryRavenAcceptance, PrimaryRavenPersistence, PostgreSQL, PostgreSQLPersistence, IBMMQ ] + # Categories are declared by the property in each test project. + test-category: [ DefaultCore, DefaultAudit, DefaultMonitoring, SqlServer, SqlServerPersistence, AzureServiceBus, RabbitMQClassicConventional, RabbitMQClassicDirect, RabbitMQQuorumConventional, RabbitMQQuorumDirect, AzureStorageQueues, MSMQ, SQS, PrimaryRavenAcceptance, PrimaryRavenPersistence, PostgreSql, PostgreSqlPersistence, IBMMQ ] include: - os: windows-latest os-name: Windows @@ -27,8 +28,6 @@ jobs: exclude: - os: ubuntu-latest test-category: MSMQ - - os: windows-latest - test-category: IBMMQ fail-fast: false steps: - name: Check for secrets @@ -43,34 +42,31 @@ jobs: uses: actions/setup-dotnet@v6.0.0 with: global-json-file: global.json - - parallel: - - name: Setup WSL - uses: Particular/setup-wsl-action@v1.1.0 - - name: Download RavenDB Server - run: ./tools/download-ravendb-server.ps1 + - name: Select test projects + id: select + run: ./tools/select-test-projects.ps1 -Category ${{ matrix.test-category }} + - name: Download RavenDB Server + if: matrix.test-category == 'DefaultCore' + run: ./tools/download-ravendb-server.ps1 - name: Build - run: dotnet build src --configuration Release -graph - - name: Zip PowerShell module - run: | - New-Item assets\PowerShellModules -ItemType Directory - Compress-Archive -Path deploy\PowerShellModules\Particular.ServiceControl.Management\* -DestinationPath assets\PowerShellModules\Particular.ServiceControl.Management.zip - - name: Upload assets - uses: actions/upload-artifact@v7.0.1 - if: matrix.test-category == 'Default' + id: build + background: true + run: dotnet build tests.proj --configuration Release -graph + # Provisions the WSL2 Docker host that the SQL Server, PostgreSQL, RabbitMQ and IBM MQ containers + # run in on Windows. A no-op on Linux, but still run there so those actions see the same + # environment variables on both runners. + - name: Setup WSL + if: startsWith(matrix.test-category, 'RabbitMQ') || contains(fromJSON('["SqlServer", "SqlServerPersistence", "PostgreSql", "PostgreSqlPersistence", "IBMMQ"]'), matrix.test-category) + uses: Particular/setup-wsl-action@v1.2.0 with: - name: ${{ matrix.os-name }}-assets - path: | - nugets/ - zip/ - assets/ - retention-days: 1 - - name: Smoke test PowerShell module import - if: matrix.os-name == 'Windows' - run: Import-Module ./deploy/PowerShellModules/Particular.ServiceControl.Management + # The action defaults to 4GB. The runner has 16GB and the build runs concurrently with the + # container starting up, so give the VM real headroom. + memory: 8GB # there is an issue with az cli and python 3.14, so for now we need to pin it # once the issue is resolved it should be able to be re-floated - # https://github.com/Azure/azure-cli/issues/32980 + # https://github.com/Azure/azure-cli/issues/32980. + # This can be removed once https://github.com/Azure/azure-cli/issues/32869 is supported. - name: Set Python 3.13 (Linux) if: matrix.os-name == 'Linux' && matrix.test-category == 'AzureServiceBus' uses: actions/setup-python@v5 @@ -84,11 +80,6 @@ jobs: python -m pip install --user "azure-cli==2.64.0" echo "$HOME/.local/bin" >> "$GITHUB_PATH" - - name: Azure login - uses: azure/login@v3.0.1 - if: matrix.test-category == 'AzureServiceBus' || matrix.test-category == 'AzureStorageQueues' || matrix.test-category == 'RabbitMQ' || matrix.test-category == 'PostgreSQL' || matrix.test-category == 'PostgreSQLPersistence' - with: - creds: ${{ secrets.AZURE_ACI_CREDENTIALS }} - name: Setup SQL Server uses: Particular/install-sql-server-action@v3.0.0 if: matrix.test-category == 'SqlServer' @@ -104,25 +95,49 @@ jobs: enable-full-text-search: true - name: Setup PostgreSQL uses: Particular/setup-postgres-action@v3.0.0 - if: matrix.test-category == 'PostgreSQL' + if: matrix.test-category == 'PostgreSql' with: connection-string-name: ServiceControl_TransportTests_PostgreSQL_ConnectionString registry-username: ${{ secrets.DOCKERHUB_USERNAME }} registry-password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Setup PostgreSQL persistence uses: Particular/setup-postgres-action@v3.0.0 - if: matrix.test-category == 'PostgreSQLPersistence' + if: matrix.test-category == 'PostgreSqlPersistence' with: connection-string-name: ServiceControl_Persistence_PostgreSql_ConnectionString registry-username: ${{ secrets.DOCKERHUB_USERNAME }} registry-password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Setup RabbitMQ uses: Particular/setup-rabbitmq-action@v2.0.0 - if: matrix.test-category == 'RabbitMQ' + if: startsWith(matrix.test-category, 'RabbitMQ') with: connection-string-name: ServiceControl_TransportTests_RabbitMQ_ConnectionString registry-username: ${{ secrets.DOCKERHUB_USERNAME }} registry-password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Setup IBM MQ + uses: Particular/setup-ibmmq-action@75b6087748fcdaef474574ca1fbe2b440141f07f + if: matrix.test-category == 'IBMMQ' + with: + connection-string-name: ServiceControl_TransportTests_IBMMQ_ConnectionString + - name: Setup SQS environment variables + if: matrix.test-category == 'SQS' + run: | + echo "AWS_REGION=${{ secrets.AWS_REGION }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append + echo "AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append + echo "AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append + + # Cleanup of queues starting with `GHA-` handled by https://github.com/Particular/NServiceBus.AmazonSQS/blob/master/.github/workflows/tests-cleanup.yml + $connectString = "AccessKeyId=${{ secrets.AWS_ACCESS_KEY_ID }};SecretAccessKey=${{ secrets.AWS_SECRET_ACCESS_KEY }};Region=${{ secrets.AWS_REGION }};QueueNamePrefix=GHA-${{ github.run_id }}" + echo "ServiceControl_TransportTests_SQS_ConnectionString=$connectString" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append + # Everything above provisions local containers, so it overlaps the build freely. The Azure steps + # below create real cloud resources, so they sit behind the wait too. + - name: Wait for build + wait: build + - name: Azure login + uses: azure/login@v3.0.1 + if: matrix.test-category == 'AzureServiceBus' || matrix.test-category == 'AzureStorageQueues' + with: + creds: ${{ secrets.AZURE_ACI_CREDENTIALS }} - name: Setup Azure Service Bus uses: Particular/setup-azureservicebus-action@v2.5.0 if: matrix.test-category == 'AzureServiceBus' @@ -137,35 +152,43 @@ jobs: connection-string-name: ServiceControl_TransportTests_ASQ_ConnectionString azure-credentials: ${{ secrets.AZURE_ACI_CREDENTIALS }} tag: ServiceControl - - name: Setup IBM MQ - if: matrix.test-category == 'IBMMQ' - run: | - docker run --name ibmmq -d -p 1414:1414 -p 9443:9443 ` - --health-cmd "dspmq" --health-interval 10s --health-timeout 5s --health-retries 10 --health-start-period 30s ` - -e LICENSE=accept -e MQ_QMGR_NAME=QM1 -e MQ_ADMIN_PASSWORD=passw0rd ` - icr.io/ibm-messaging/mq:latest - # Wait for container health check to pass - while ((docker inspect --format '{{.State.Health.Status}}' ibmmq) -ne 'healthy') { - Start-Sleep -Seconds 2 - } - echo "ServiceControl_TransportTests_IBMMQ_ConnectionString=mq://admin:passw0rd@localhost:1414/QM1?channel=DEV.ADMIN.SVRCONN&topicprefix=DEV" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append - - name: Setup SQS environment variables - if: matrix.test-category == 'SQS' - run: | - echo "AWS_REGION=${{ secrets.AWS_REGION }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append - echo "AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append - echo "AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append - - # Cleanup of queues starting with `GHA-` handled by https://github.com/Particular/NServiceBus.AmazonSQS/blob/master/.github/workflows/tests-cleanup.yml - $connectString = "AccessKeyId=${{ secrets.AWS_ACCESS_KEY_ID }};SecretAccessKey=${{ secrets.AWS_SECRET_ACCESS_KEY }};Region=${{ secrets.AWS_REGION }};QueueNamePrefix=GHA-${{ github.run_id }}" - echo "ServiceControl_TransportTests_SQS_ConnectionString=$connectString" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append - name: Run tests - uses: Particular/run-tests-action@v1.7.0 + run: ./tools/run-tests.ps1 -Projects $Env:TEST_PROJECTS env: + TEST_PROJECTS: ${{ steps.select.outputs.test-projects }} ServiceControl_TESTS_FILTER: ${{ matrix.test-category }} PARTICULARSOFTWARE_LICENSE: ${{ secrets.LICENSETEXT }} AZURE_ACI_CREDENTIALS: ${{ secrets.AZURE_ACI_CREDENTIALS }} + compile: + name: ${{ matrix.os-name }}-Compile + runs-on: ${{ matrix.os }} + strategy: + matrix: + include: + - os: windows-latest + os-name: Windows + - os: ubuntu-latest + os-name: Linux + fail-fast: false + steps: + - name: Check for secrets + env: + SECRETS_AVAILABLE: ${{ secrets.SECRETS_AVAILABLE }} + run: exit $(If ($env:SECRETS_AVAILABLE -eq 'true') { 0 } Else { 1 }) + - name: Checkout + uses: actions/checkout@v7.0.1 + with: + fetch-depth: 0 + - name: Setup .NET SDK + uses: actions/setup-dotnet@v6.0.0 + with: + global-json-file: global.json + - name: Download RavenDB Server + run: ./tools/download-ravendb-server.ps1 + - name: Build + run: dotnet build src --configuration Release -graph + windows-installers: uses: ./.github/workflows/build-windows.yml secrets: inherit diff --git a/.gitignore b/.gitignore index 1653797127..b3b621401f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ /binaries /deploy /nugets +# Generated by tools/select-test-projects.ps1 +/tests.proj build32 *.vshost.* .nu diff --git a/README.md b/README.md index bdff9eb042..8db5a58c80 100644 --- a/README.md +++ b/README.md @@ -46,17 +46,58 @@ Testing using the [CI workflow](/.github/workflows/ci.yml) depends on the follow Running all tests all the times takes a lot of resources. Tests are filtered based on the `ServiceControl_TESTS_FILTER` environment variable. To run only a subset, e.g., SQS transport tests, define the variable as `ServiceControl_TESTS_FILTER=SQS`. The following list contains all the possible `ServiceControl_TESTS_FILTER` values: -- `Default` - runs only non-transport-specific tests +Non-transport-specific: + +- `DefaultCore` +- `DefaultAudit` +- `DefaultMonitoring` + +Transports: + - `AzureServiceBus` - `AzureStorageQueues` +- `IBMMQ` - `MSMQ` -- `RabbitMQ` +- `PostgreSql` +- `RabbitMQClassicConventional` +- `RabbitMQClassicDirect` +- `RabbitMQQuorumConventional` +- `RabbitMQQuorumDirect` - `SqlServer` -- `SqlServerPersistence` -- `PostgresSqlPersistence` - `SQS` -NOTE: If no variable is defined all tests will be executed. +Persisters: + +- `PostgreSqlPersistence` +- `PrimaryRavenAcceptance` +- `PrimaryRavenPersistence` +- `SqlServerPersistence` + +> [!NOTE] +> If no variable is defined all tests will be executed. + +Each category is declared once, by the `` property in the test project. CI reads that property to build and run only the projects belonging to the category under test, and the build generates the assembly-level `IncludeInTestCategory` attribute from it, which is what `ServiceControl_TESTS_FILTER` matches against at run time. + +### Adding a test project + +> [!IMPORTANT] +> Every test project must set `` in its `.csproj`, alongside `TargetFramework`: +> +> ```xml +> +> net10.0 +> DefaultCore +> +> ``` +> +> CI selects projects by that property alone, so a test project without it is never built and never run. The tests would simply not exist as far as CI is concerned, and nothing would go red. `tools/select-test-projects.ps1` fails the build if a project references `Microsoft.NET.Test.Sdk` without declaring a category, so this cannot be forgotten silently. + +Use an existing category from the list above where the tests fit. + +> [!WARNING] +> Introducing a *new* category also means adding it to the `test-category` matrix in [ci.yml](.github/workflows/ci.yml), otherwise no job ever selects it and the tests never run. + +Run `./tools/select-test-projects.ps1 -List` to see every category and the projects it selects. ## Security Configuration diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 3291fe2654..c175513774 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -31,6 +31,18 @@ + + + + <_Parameter1>$(TestCategory) + + + diff --git a/src/Particular.LicensingComponent.UnitTests/Particular.LicensingComponent.UnitTests.csproj b/src/Particular.LicensingComponent.UnitTests/Particular.LicensingComponent.UnitTests.csproj index b0094aab94..529a3f226c 100644 --- a/src/Particular.LicensingComponent.UnitTests/Particular.LicensingComponent.UnitTests.csproj +++ b/src/Particular.LicensingComponent.UnitTests/Particular.LicensingComponent.UnitTests.csproj @@ -2,6 +2,7 @@ net10.0 + DefaultCore diff --git a/src/Particular.LicensingComponent.UnitTests/TestsFilter.cs b/src/Particular.LicensingComponent.UnitTests/TestsFilter.cs deleted file mode 100644 index cbb64ab1fc..0000000000 --- a/src/Particular.LicensingComponent.UnitTests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInDefaultTests()] \ No newline at end of file diff --git a/src/ServiceControl.AcceptanceTests.RavenDB/ServiceControl.AcceptanceTests.RavenDB.csproj b/src/ServiceControl.AcceptanceTests.RavenDB/ServiceControl.AcceptanceTests.RavenDB.csproj index 0cf6c7efa5..26650ebe99 100644 --- a/src/ServiceControl.AcceptanceTests.RavenDB/ServiceControl.AcceptanceTests.RavenDB.csproj +++ b/src/ServiceControl.AcceptanceTests.RavenDB/ServiceControl.AcceptanceTests.RavenDB.csproj @@ -2,6 +2,7 @@ net10.0 + PrimaryRavenAcceptance diff --git a/src/ServiceControl.AcceptanceTests.RavenDB/TestsFilter.cs b/src/ServiceControl.AcceptanceTests.RavenDB/TestsFilter.cs deleted file mode 100644 index d5e5dfd11e..0000000000 --- a/src/ServiceControl.AcceptanceTests.RavenDB/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInTestCategory("PrimaryRavenAcceptance")] \ No newline at end of file diff --git a/src/ServiceControl.Audit.AcceptanceTests.RavenDB/ServiceControl.Audit.AcceptanceTests.RavenDB.csproj b/src/ServiceControl.Audit.AcceptanceTests.RavenDB/ServiceControl.Audit.AcceptanceTests.RavenDB.csproj index 223e117c20..a71d5defe6 100644 --- a/src/ServiceControl.Audit.AcceptanceTests.RavenDB/ServiceControl.Audit.AcceptanceTests.RavenDB.csproj +++ b/src/ServiceControl.Audit.AcceptanceTests.RavenDB/ServiceControl.Audit.AcceptanceTests.RavenDB.csproj @@ -2,6 +2,7 @@ net10.0 + DefaultAudit @@ -26,7 +27,6 @@ - diff --git a/src/ServiceControl.Audit.AcceptanceTests.RavenDB/TestsFilter.cs b/src/ServiceControl.Audit.AcceptanceTests.RavenDB/TestsFilter.cs deleted file mode 100644 index cbb64ab1fc..0000000000 --- a/src/ServiceControl.Audit.AcceptanceTests.RavenDB/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInDefaultTests()] \ No newline at end of file diff --git a/src/ServiceControl.Audit.AcceptanceTests/ServiceControl.Audit.AcceptanceTests.csproj b/src/ServiceControl.Audit.AcceptanceTests/ServiceControl.Audit.AcceptanceTests.csproj index 2bbf59bc45..2388115142 100644 --- a/src/ServiceControl.Audit.AcceptanceTests/ServiceControl.Audit.AcceptanceTests.csproj +++ b/src/ServiceControl.Audit.AcceptanceTests/ServiceControl.Audit.AcceptanceTests.csproj @@ -2,6 +2,7 @@ net10.0 + DefaultAudit diff --git a/src/ServiceControl.Audit.AcceptanceTests/TestsFilter.cs b/src/ServiceControl.Audit.AcceptanceTests/TestsFilter.cs deleted file mode 100644 index cbb64ab1fc..0000000000 --- a/src/ServiceControl.Audit.AcceptanceTests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInDefaultTests()] \ No newline at end of file diff --git a/src/ServiceControl.Audit.Persistence.Tests.RavenDB/ServiceControl.Audit.Persistence.Tests.RavenDB.csproj b/src/ServiceControl.Audit.Persistence.Tests.RavenDB/ServiceControl.Audit.Persistence.Tests.RavenDB.csproj index 7b0f2fbb6a..26a098607b 100644 --- a/src/ServiceControl.Audit.Persistence.Tests.RavenDB/ServiceControl.Audit.Persistence.Tests.RavenDB.csproj +++ b/src/ServiceControl.Audit.Persistence.Tests.RavenDB/ServiceControl.Audit.Persistence.Tests.RavenDB.csproj @@ -2,6 +2,7 @@ net10.0 + DefaultAudit @@ -24,7 +25,6 @@ - diff --git a/src/ServiceControl.Audit.Persistence.Tests.RavenDB/TestsFilter.cs b/src/ServiceControl.Audit.Persistence.Tests.RavenDB/TestsFilter.cs deleted file mode 100644 index cbb64ab1fc..0000000000 --- a/src/ServiceControl.Audit.Persistence.Tests.RavenDB/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInDefaultTests()] \ No newline at end of file diff --git a/src/ServiceControl.Audit.Persistence.Tests/ServiceControl.Audit.Persistence.Tests.csproj b/src/ServiceControl.Audit.Persistence.Tests/ServiceControl.Audit.Persistence.Tests.csproj index b7f6909c1f..ece853badc 100644 --- a/src/ServiceControl.Audit.Persistence.Tests/ServiceControl.Audit.Persistence.Tests.csproj +++ b/src/ServiceControl.Audit.Persistence.Tests/ServiceControl.Audit.Persistence.Tests.csproj @@ -2,6 +2,7 @@ net10.0 + DefaultAudit diff --git a/src/ServiceControl.Audit.Persistence.Tests/TestsFilter.cs b/src/ServiceControl.Audit.Persistence.Tests/TestsFilter.cs deleted file mode 100644 index cbb64ab1fc..0000000000 --- a/src/ServiceControl.Audit.Persistence.Tests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInDefaultTests()] \ No newline at end of file diff --git a/src/ServiceControl.Audit.UnitTests/ServiceControl.Audit.UnitTests.csproj b/src/ServiceControl.Audit.UnitTests/ServiceControl.Audit.UnitTests.csproj index ec6be43716..44a4d9efa0 100644 --- a/src/ServiceControl.Audit.UnitTests/ServiceControl.Audit.UnitTests.csproj +++ b/src/ServiceControl.Audit.UnitTests/ServiceControl.Audit.UnitTests.csproj @@ -2,6 +2,7 @@ net10.0 + DefaultAudit diff --git a/src/ServiceControl.Audit.UnitTests/TestsFilter.cs b/src/ServiceControl.Audit.UnitTests/TestsFilter.cs deleted file mode 100644 index cbb64ab1fc..0000000000 --- a/src/ServiceControl.Audit.UnitTests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInDefaultTests()] \ No newline at end of file diff --git a/src/ServiceControl.Audit/ServiceControl.Audit.csproj b/src/ServiceControl.Audit/ServiceControl.Audit.csproj index f88c753d1b..a16a75c832 100644 --- a/src/ServiceControl.Audit/ServiceControl.Audit.csproj +++ b/src/ServiceControl.Audit/ServiceControl.Audit.csproj @@ -59,6 +59,7 @@ + diff --git a/src/ServiceControl.Config.Tests/ServiceControl.Config.Tests.csproj b/src/ServiceControl.Config.Tests/ServiceControl.Config.Tests.csproj index 8bafc4ae31..6c0a7c644b 100644 --- a/src/ServiceControl.Config.Tests/ServiceControl.Config.Tests.csproj +++ b/src/ServiceControl.Config.Tests/ServiceControl.Config.Tests.csproj @@ -2,6 +2,7 @@ net10.0-windows10.0.19041.0 + DefaultCore x64 true diff --git a/src/ServiceControl.Config.Tests/TestsFilter.cs b/src/ServiceControl.Config.Tests/TestsFilter.cs deleted file mode 100644 index cbb64ab1fc..0000000000 --- a/src/ServiceControl.Config.Tests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInDefaultTests()] \ No newline at end of file diff --git a/src/ServiceControl.Infrastructure.Tests/ServiceControl.Infrastructure.Tests.csproj b/src/ServiceControl.Infrastructure.Tests/ServiceControl.Infrastructure.Tests.csproj index 7664d8aa63..5c53d4918f 100644 --- a/src/ServiceControl.Infrastructure.Tests/ServiceControl.Infrastructure.Tests.csproj +++ b/src/ServiceControl.Infrastructure.Tests/ServiceControl.Infrastructure.Tests.csproj @@ -2,6 +2,7 @@ net10.0 + DefaultCore diff --git a/src/ServiceControl.Infrastructure.Tests/TestsFilter.cs b/src/ServiceControl.Infrastructure.Tests/TestsFilter.cs deleted file mode 100644 index cbb64ab1fc..0000000000 --- a/src/ServiceControl.Infrastructure.Tests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInDefaultTests()] \ No newline at end of file diff --git a/src/ServiceControl.Monitoring.AcceptanceTests/ServiceControl.Monitoring.AcceptanceTests.csproj b/src/ServiceControl.Monitoring.AcceptanceTests/ServiceControl.Monitoring.AcceptanceTests.csproj index 19e62962ab..dd95e8cfad 100644 --- a/src/ServiceControl.Monitoring.AcceptanceTests/ServiceControl.Monitoring.AcceptanceTests.csproj +++ b/src/ServiceControl.Monitoring.AcceptanceTests/ServiceControl.Monitoring.AcceptanceTests.csproj @@ -2,6 +2,7 @@ net10.0 + DefaultMonitoring diff --git a/src/ServiceControl.Monitoring.AcceptanceTests/TestsFilter.cs b/src/ServiceControl.Monitoring.AcceptanceTests/TestsFilter.cs deleted file mode 100644 index cbb64ab1fc..0000000000 --- a/src/ServiceControl.Monitoring.AcceptanceTests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInDefaultTests()] \ No newline at end of file diff --git a/src/ServiceControl.Monitoring.UnitTests/ServiceControl.Monitoring.UnitTests.csproj b/src/ServiceControl.Monitoring.UnitTests/ServiceControl.Monitoring.UnitTests.csproj index 14236ddac2..9261529433 100644 --- a/src/ServiceControl.Monitoring.UnitTests/ServiceControl.Monitoring.UnitTests.csproj +++ b/src/ServiceControl.Monitoring.UnitTests/ServiceControl.Monitoring.UnitTests.csproj @@ -2,6 +2,7 @@ net10.0 + DefaultMonitoring diff --git a/src/ServiceControl.Monitoring.UnitTests/TestsFilter.cs b/src/ServiceControl.Monitoring.UnitTests/TestsFilter.cs deleted file mode 100644 index cbb64ab1fc..0000000000 --- a/src/ServiceControl.Monitoring.UnitTests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInDefaultTests()] \ No newline at end of file diff --git a/src/ServiceControl.MultiInstance.AcceptanceTests/ServiceControl.MultiInstance.AcceptanceTests.csproj b/src/ServiceControl.MultiInstance.AcceptanceTests/ServiceControl.MultiInstance.AcceptanceTests.csproj index 10b78c9ba4..cbaba829ae 100644 --- a/src/ServiceControl.MultiInstance.AcceptanceTests/ServiceControl.MultiInstance.AcceptanceTests.csproj +++ b/src/ServiceControl.MultiInstance.AcceptanceTests/ServiceControl.MultiInstance.AcceptanceTests.csproj @@ -2,6 +2,7 @@ net10.0 + DefaultCore diff --git a/src/ServiceControl.MultiInstance.AcceptanceTests/SetupFixture.cs b/src/ServiceControl.MultiInstance.AcceptanceTests/SetupFixture.cs index 4c74e8dcc9..a2b3d0c746 100644 --- a/src/ServiceControl.MultiInstance.AcceptanceTests/SetupFixture.cs +++ b/src/ServiceControl.MultiInstance.AcceptanceTests/SetupFixture.cs @@ -3,9 +3,12 @@ namespace ServiceControl.MultiInstance.AcceptanceTests; using System; using System.Diagnostics; using System.Runtime.InteropServices; +using System.Runtime.Versioning; using System.Threading; using System.Threading.Tasks; using NUnit.Framework; +using AuditEventSourceCreator = global::ServiceControl.Audit.Infrastructure.EventSourceCreator; +using PrimaryEventSourceCreator = ServiceBus.Management.Infrastructure.Installers.EventSourceCreator; [SetUpFixture] public class SetupFixture @@ -13,17 +16,30 @@ public class SetupFixture [OneTimeSetUp] public async Task Setup() { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - ServiceBus.Management.Infrastructure.Installers.EventSourceCreator.Create(); + return; + } + + // These tests host a primary and an audit instance, so both event sources have to exist before + // either instance runs its setup. The audit source used to be created as a side effect of the + // audit acceptance tests running earlier in the same CI job, which is no longer the case. + PrimaryEventSourceCreator.Create(); + AuditEventSourceCreator.Create(); + + await WaitForSource(PrimaryEventSourceCreator.SourceName); + await WaitForSource(AuditEventSourceCreator.SourceName); + } - //There is a delay for this becoming true, tests will fall over if they interleave in the wrong way. - var cts = new CancellationTokenSource(TimeSpan.FromSeconds(60)); - while (!EventLog.SourceExists(ServiceBus.Management.Infrastructure.Installers.EventSourceCreator.SourceName)) - { - cts.Token.ThrowIfCancellationRequested(); - await Task.Delay(500, CancellationToken.None); - } + //There is a delay for this becoming true, tests will fall over if they interleave in the wrong way. + [SupportedOSPlatform("windows")] + static async Task WaitForSource(string sourceName) + { + var cts = new CancellationTokenSource(TimeSpan.FromSeconds(60)); + while (!EventLog.SourceExists(sourceName)) + { + cts.Token.ThrowIfCancellationRequested(); + await Task.Delay(500, CancellationToken.None); } } -} \ No newline at end of file +} diff --git a/src/ServiceControl.MultiInstance.AcceptanceTests/TestsFilter.cs b/src/ServiceControl.MultiInstance.AcceptanceTests/TestsFilter.cs deleted file mode 100644 index cbb64ab1fc..0000000000 --- a/src/ServiceControl.MultiInstance.AcceptanceTests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInDefaultTests()] \ No newline at end of file diff --git a/src/ServiceControl.Persistence.RavenDB/Editing/NotificationsManager.cs b/src/ServiceControl.Persistence.RavenDB/Editing/NotificationsManager.cs index 57e8d2b454..6531b6ed7b 100644 --- a/src/ServiceControl.Persistence.RavenDB/Editing/NotificationsManager.cs +++ b/src/ServiceControl.Persistence.RavenDB/Editing/NotificationsManager.cs @@ -1,6 +1,5 @@ namespace ServiceControl.Persistence.RavenDB.Editing { - using System; using System.Threading.Tasks; using Notifications; using Raven.Client.Documents.Session; @@ -8,11 +7,12 @@ class NotificationsManager(IAsyncDocumentSession session) : AbstractSessionManager(session), INotificationsManager { const string SingleDocumentId = "NotificationsSettings/All"; - static readonly TimeSpan CacheTimeout = TimeSpan.FromMinutes(5); // Raven requires this to be at least 1 second public async Task LoadSettings() { - using var aggressivelyCacheFor = await Session.Advanced.DocumentStore.AggressivelyCacheForAsync(CacheTimeout); + // Deliberately not aggressively cached. These settings are read rarely and edited by hand, + // and aggressive caching invalidates asynchronously via the Changes API, so a read straight + // after a save can return the pre-save document. var settings = await Session .LoadAsync(SingleDocumentId); diff --git a/src/ServiceControl.Persistence.Tests.InMemory/ServiceControl.Persistence.Tests.InMemory.csproj b/src/ServiceControl.Persistence.Tests.InMemory/ServiceControl.Persistence.Tests.InMemory.csproj index 5854e9fa05..7bf877fa51 100644 --- a/src/ServiceControl.Persistence.Tests.InMemory/ServiceControl.Persistence.Tests.InMemory.csproj +++ b/src/ServiceControl.Persistence.Tests.InMemory/ServiceControl.Persistence.Tests.InMemory.csproj @@ -2,6 +2,7 @@ net10.0 + DefaultCore diff --git a/src/ServiceControl.Persistence.Tests.InMemory/TestsFilter.cs b/src/ServiceControl.Persistence.Tests.InMemory/TestsFilter.cs deleted file mode 100644 index cbb64ab1fc..0000000000 --- a/src/ServiceControl.Persistence.Tests.InMemory/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInDefaultTests()] \ No newline at end of file diff --git a/src/ServiceControl.Persistence.Tests.PostgreSql/PersistenceTestsContext.cs b/src/ServiceControl.Persistence.Tests.PostgreSql/PersistenceTestsContext.cs index b99a86b59b..30bc5ae750 100644 --- a/src/ServiceControl.Persistence.Tests.PostgreSql/PersistenceTestsContext.cs +++ b/src/ServiceControl.Persistence.Tests.PostgreSql/PersistenceTestsContext.cs @@ -11,7 +11,6 @@ namespace ServiceControl.Persistence.Tests; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Time.Testing; using Npgsql; using ServiceControl.Persistence.EFCore.Abstractions; using ServiceControl.Persistence.EFCore.Infrastructure; @@ -22,8 +21,6 @@ public partial class PersistenceTestsContext : IPersistenceTestsContext string databaseName; string bodyStoragePath; - public FakeTimeProvider FakeTime { get; } = new(DateTimeOffset.UtcNow); - public async Task Setup(IHostApplicationBuilder hostBuilder) { databaseName = $"sc_test_{Guid.NewGuid():n}"; diff --git a/src/ServiceControl.Persistence.Tests.PostgreSql/ServiceControl.Persistence.Tests.PostgreSql.csproj b/src/ServiceControl.Persistence.Tests.PostgreSql/ServiceControl.Persistence.Tests.PostgreSql.csproj index e585bb53be..46290f8252 100644 --- a/src/ServiceControl.Persistence.Tests.PostgreSql/ServiceControl.Persistence.Tests.PostgreSql.csproj +++ b/src/ServiceControl.Persistence.Tests.PostgreSql/ServiceControl.Persistence.Tests.PostgreSql.csproj @@ -2,6 +2,7 @@ net10.0 + PostgreSqlPersistence diff --git a/src/ServiceControl.Persistence.Tests.PostgreSql/TestsFilter.cs b/src/ServiceControl.Persistence.Tests.PostgreSql/TestsFilter.cs deleted file mode 100644 index c2971486f6..0000000000 --- a/src/ServiceControl.Persistence.Tests.PostgreSql/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInTestCategory("PostgreSqlPersistence")] diff --git a/src/ServiceControl.Persistence.Tests.RavenDB/ServiceControl.Persistence.Tests.RavenDB.csproj b/src/ServiceControl.Persistence.Tests.RavenDB/ServiceControl.Persistence.Tests.RavenDB.csproj index 85d3b51c65..4b8c1de262 100644 --- a/src/ServiceControl.Persistence.Tests.RavenDB/ServiceControl.Persistence.Tests.RavenDB.csproj +++ b/src/ServiceControl.Persistence.Tests.RavenDB/ServiceControl.Persistence.Tests.RavenDB.csproj @@ -2,6 +2,7 @@ net10.0 + PrimaryRavenPersistence diff --git a/src/ServiceControl.Persistence.Tests.RavenDB/TestsFilter.cs b/src/ServiceControl.Persistence.Tests.RavenDB/TestsFilter.cs deleted file mode 100644 index 2d1b7a5ce1..0000000000 --- a/src/ServiceControl.Persistence.Tests.RavenDB/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInTestCategory("PrimaryRavenPersistence")] \ No newline at end of file diff --git a/src/ServiceControl.Persistence.Tests.SqlServer/PersistenceTestsContext.cs b/src/ServiceControl.Persistence.Tests.SqlServer/PersistenceTestsContext.cs index 412ff6364a..5ebccb8177 100644 --- a/src/ServiceControl.Persistence.Tests.SqlServer/PersistenceTestsContext.cs +++ b/src/ServiceControl.Persistence.Tests.SqlServer/PersistenceTestsContext.cs @@ -11,7 +11,6 @@ namespace ServiceControl.Persistence.Tests; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Time.Testing; using ServiceControl.Persistence.EFCore.Abstractions; using ServiceControl.Persistence.EFCore.Infrastructure; @@ -21,8 +20,6 @@ public partial class PersistenceTestsContext : IPersistenceTestsContext string databaseName; string bodyStoragePath; - public FakeTimeProvider FakeTime { get; } = new(DateTimeOffset.UtcNow); - public async Task Setup(IHostApplicationBuilder hostBuilder) { databaseName = $"sc_test_{Guid.NewGuid():n}"; diff --git a/src/ServiceControl.Persistence.Tests.SqlServer/ServiceControl.Persistence.Tests.SqlServer.csproj b/src/ServiceControl.Persistence.Tests.SqlServer/ServiceControl.Persistence.Tests.SqlServer.csproj index 2ed196baf4..e268e9acdc 100644 --- a/src/ServiceControl.Persistence.Tests.SqlServer/ServiceControl.Persistence.Tests.SqlServer.csproj +++ b/src/ServiceControl.Persistence.Tests.SqlServer/ServiceControl.Persistence.Tests.SqlServer.csproj @@ -2,6 +2,7 @@ net10.0 + SqlServerPersistence diff --git a/src/ServiceControl.Persistence.Tests.SqlServer/TestsFilter.cs b/src/ServiceControl.Persistence.Tests.SqlServer/TestsFilter.cs deleted file mode 100644 index d37d903ffb..0000000000 --- a/src/ServiceControl.Persistence.Tests.SqlServer/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInTestCategory("SqlServerPersistence")] diff --git a/src/ServiceControl.Persistence.Tests/EFCore/PersistenceTestsContext.cs b/src/ServiceControl.Persistence.Tests/EFCore/PersistenceTestsContext.cs index f7b0de3b11..5744d6ec3b 100644 --- a/src/ServiceControl.Persistence.Tests/EFCore/PersistenceTestsContext.cs +++ b/src/ServiceControl.Persistence.Tests/EFCore/PersistenceTestsContext.cs @@ -11,11 +11,24 @@ namespace ServiceControl.Persistence.Tests; using EFCore.Infrastructure; using MessageFailures; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Time.Testing; using NServiceBus; using Operations; public partial class PersistenceTestsContext { + public FakeTimeProvider FakeTime { get; } = new(StorableUtcNow()); + + // PostgreSQL timestamps only keep microseconds, so a clock seeded straight from + // DateTimeOffset.UtcNow carries a 100ns tick that no longer compares equal once a + // timestamp stamped from it has been through the database. + static DateTimeOffset StorableUtcNow() + { + var now = DateTimeOffset.UtcNow; + + return now.AddTicks(-(now.Ticks % TimeSpan.TicksPerMillisecond)); + } + static async Task InsertFailedMessagesDirect(IServiceProvider serviceProvider, FailedMessage[] messages) { await using var scope = serviceProvider.CreateAsyncScope(); diff --git a/src/ServiceControl.Transports.ASBS.Tests/ServiceControl.Transports.ASBS.Tests.csproj b/src/ServiceControl.Transports.ASBS.Tests/ServiceControl.Transports.ASBS.Tests.csproj index a7d3313ad3..14ce97e5ce 100644 --- a/src/ServiceControl.Transports.ASBS.Tests/ServiceControl.Transports.ASBS.Tests.csproj +++ b/src/ServiceControl.Transports.ASBS.Tests/ServiceControl.Transports.ASBS.Tests.csproj @@ -2,6 +2,7 @@ net10.0 + AzureServiceBus @@ -29,7 +30,6 @@ - \ No newline at end of file diff --git a/src/ServiceControl.Transports.ASBS.Tests/TestsFilter.cs b/src/ServiceControl.Transports.ASBS.Tests/TestsFilter.cs deleted file mode 100644 index d7eead1f29..0000000000 --- a/src/ServiceControl.Transports.ASBS.Tests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInAzureServiceBusTests()] \ No newline at end of file diff --git a/src/ServiceControl.Transports.ASQ.Tests/ServiceControl.Transports.ASQ.Tests.csproj b/src/ServiceControl.Transports.ASQ.Tests/ServiceControl.Transports.ASQ.Tests.csproj index 6a9f7fb7e9..6af65de105 100644 --- a/src/ServiceControl.Transports.ASQ.Tests/ServiceControl.Transports.ASQ.Tests.csproj +++ b/src/ServiceControl.Transports.ASQ.Tests/ServiceControl.Transports.ASQ.Tests.csproj @@ -1,7 +1,8 @@ - + net10.0 + AzureStorageQueues @@ -25,7 +26,6 @@ - \ No newline at end of file diff --git a/src/ServiceControl.Transports.ASQ.Tests/TestsFilter.cs b/src/ServiceControl.Transports.ASQ.Tests/TestsFilter.cs deleted file mode 100644 index 9af29ba3a2..0000000000 --- a/src/ServiceControl.Transports.ASQ.Tests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInAzureStorageQueuesTests()] \ No newline at end of file diff --git a/src/ServiceControl.Transports.IBMMQ.Tests/ServiceControl.Transports.IBMMQ.Tests.csproj b/src/ServiceControl.Transports.IBMMQ.Tests/ServiceControl.Transports.IBMMQ.Tests.csproj index f441f9cf89..e3635c34b1 100644 --- a/src/ServiceControl.Transports.IBMMQ.Tests/ServiceControl.Transports.IBMMQ.Tests.csproj +++ b/src/ServiceControl.Transports.IBMMQ.Tests/ServiceControl.Transports.IBMMQ.Tests.csproj @@ -2,6 +2,7 @@ net10.0 + IBMMQ @@ -27,7 +28,6 @@ - \ No newline at end of file diff --git a/src/ServiceControl.Transports.IBMMQ.Tests/TestsFilter.cs b/src/ServiceControl.Transports.IBMMQ.Tests/TestsFilter.cs deleted file mode 100644 index 76ebf15442..0000000000 --- a/src/ServiceControl.Transports.IBMMQ.Tests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInIBMMQTests()] \ No newline at end of file diff --git a/src/ServiceControl.Transports.Msmq.Tests/ServiceControl.Transports.Msmq.Tests.csproj b/src/ServiceControl.Transports.Msmq.Tests/ServiceControl.Transports.Msmq.Tests.csproj index e94380b92c..9921927a33 100644 --- a/src/ServiceControl.Transports.Msmq.Tests/ServiceControl.Transports.Msmq.Tests.csproj +++ b/src/ServiceControl.Transports.Msmq.Tests/ServiceControl.Transports.Msmq.Tests.csproj @@ -2,6 +2,7 @@ net10.0-windows + MSMQ @@ -26,7 +27,6 @@ - diff --git a/src/ServiceControl.Transports.Msmq.Tests/TestsFilter.cs b/src/ServiceControl.Transports.Msmq.Tests/TestsFilter.cs deleted file mode 100644 index dd67f84a24..0000000000 --- a/src/ServiceControl.Transports.Msmq.Tests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInMsmqTests()] \ No newline at end of file diff --git a/src/ServiceControl.Transports.PostgreSql.Tests/ServiceControl.Transports.PostgreSql.Tests.csproj b/src/ServiceControl.Transports.PostgreSql.Tests/ServiceControl.Transports.PostgreSql.Tests.csproj index 3071023ee0..cb7a91727d 100644 --- a/src/ServiceControl.Transports.PostgreSql.Tests/ServiceControl.Transports.PostgreSql.Tests.csproj +++ b/src/ServiceControl.Transports.PostgreSql.Tests/ServiceControl.Transports.PostgreSql.Tests.csproj @@ -2,6 +2,7 @@ net10.0 + PostgreSql @@ -27,7 +28,6 @@ - \ No newline at end of file diff --git a/src/ServiceControl.Transports.PostgreSql.Tests/TestsFilter.cs b/src/ServiceControl.Transports.PostgreSql.Tests/TestsFilter.cs deleted file mode 100644 index aaa9ec7659..0000000000 --- a/src/ServiceControl.Transports.PostgreSql.Tests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInPostgreSqlTests()] \ No newline at end of file diff --git a/src/ServiceControl.Transports.RabbitMQClassicConventionalRouting.Tests/ServiceControl.Transports.RabbitMQClassicConventionalRoutingTests.csproj b/src/ServiceControl.Transports.RabbitMQClassicConventionalRouting.Tests/ServiceControl.Transports.RabbitMQClassicConventionalRoutingTests.csproj index 3bd02418c1..6fd23a7ba6 100644 --- a/src/ServiceControl.Transports.RabbitMQClassicConventionalRouting.Tests/ServiceControl.Transports.RabbitMQClassicConventionalRoutingTests.csproj +++ b/src/ServiceControl.Transports.RabbitMQClassicConventionalRouting.Tests/ServiceControl.Transports.RabbitMQClassicConventionalRoutingTests.csproj @@ -1,7 +1,8 @@ - + net10.0 + RabbitMQClassicConventional @@ -27,7 +28,6 @@ - \ No newline at end of file diff --git a/src/ServiceControl.Transports.RabbitMQClassicConventionalRouting.Tests/TestsFilter.cs b/src/ServiceControl.Transports.RabbitMQClassicConventionalRouting.Tests/TestsFilter.cs deleted file mode 100644 index 3d1ec7f59c..0000000000 --- a/src/ServiceControl.Transports.RabbitMQClassicConventionalRouting.Tests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInRabbitMQTests()] \ No newline at end of file diff --git a/src/ServiceControl.Transports.RabbitMQClassicDirectRouting.Tests/ServiceControl.Transports.RabbitMQClassicDirectRouting.Tests.csproj b/src/ServiceControl.Transports.RabbitMQClassicDirectRouting.Tests/ServiceControl.Transports.RabbitMQClassicDirectRouting.Tests.csproj index d5bf028a66..2164ec1d26 100644 --- a/src/ServiceControl.Transports.RabbitMQClassicDirectRouting.Tests/ServiceControl.Transports.RabbitMQClassicDirectRouting.Tests.csproj +++ b/src/ServiceControl.Transports.RabbitMQClassicDirectRouting.Tests/ServiceControl.Transports.RabbitMQClassicDirectRouting.Tests.csproj @@ -1,7 +1,8 @@ - + net10.0 + RabbitMQClassicDirect @@ -26,7 +27,6 @@ - \ No newline at end of file diff --git a/src/ServiceControl.Transports.RabbitMQClassicDirectRouting.Tests/TestsFilter.cs b/src/ServiceControl.Transports.RabbitMQClassicDirectRouting.Tests/TestsFilter.cs deleted file mode 100644 index 3d1ec7f59c..0000000000 --- a/src/ServiceControl.Transports.RabbitMQClassicDirectRouting.Tests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInRabbitMQTests()] \ No newline at end of file diff --git a/src/ServiceControl.Transports.RabbitMQQuorumConventionalRouting.Tests/ServiceControl.Transports.RabbitMQQuorumConventionalRouting.Tests.csproj b/src/ServiceControl.Transports.RabbitMQQuorumConventionalRouting.Tests/ServiceControl.Transports.RabbitMQQuorumConventionalRouting.Tests.csproj index d5bf028a66..be4eea22f0 100644 --- a/src/ServiceControl.Transports.RabbitMQQuorumConventionalRouting.Tests/ServiceControl.Transports.RabbitMQQuorumConventionalRouting.Tests.csproj +++ b/src/ServiceControl.Transports.RabbitMQQuorumConventionalRouting.Tests/ServiceControl.Transports.RabbitMQQuorumConventionalRouting.Tests.csproj @@ -1,7 +1,8 @@ - + net10.0 + RabbitMQQuorumConventional @@ -26,7 +27,6 @@ - \ No newline at end of file diff --git a/src/ServiceControl.Transports.RabbitMQQuorumConventionalRouting.Tests/TestsFilter.cs b/src/ServiceControl.Transports.RabbitMQQuorumConventionalRouting.Tests/TestsFilter.cs deleted file mode 100644 index 3d1ec7f59c..0000000000 --- a/src/ServiceControl.Transports.RabbitMQQuorumConventionalRouting.Tests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInRabbitMQTests()] \ No newline at end of file diff --git a/src/ServiceControl.Transports.RabbitMQQuorumDirectRouting.Tests/ServiceControl.Transports.RabbitMQQuorumDirectRouting.Tests.csproj b/src/ServiceControl.Transports.RabbitMQQuorumDirectRouting.Tests/ServiceControl.Transports.RabbitMQQuorumDirectRouting.Tests.csproj index 3bd02418c1..5f5b275050 100644 --- a/src/ServiceControl.Transports.RabbitMQQuorumDirectRouting.Tests/ServiceControl.Transports.RabbitMQQuorumDirectRouting.Tests.csproj +++ b/src/ServiceControl.Transports.RabbitMQQuorumDirectRouting.Tests/ServiceControl.Transports.RabbitMQQuorumDirectRouting.Tests.csproj @@ -1,7 +1,8 @@ - + net10.0 + RabbitMQQuorumDirect @@ -27,7 +28,6 @@ - \ No newline at end of file diff --git a/src/ServiceControl.Transports.RabbitMQQuorumDirectRouting.Tests/TestsFilter.cs b/src/ServiceControl.Transports.RabbitMQQuorumDirectRouting.Tests/TestsFilter.cs deleted file mode 100644 index 3d1ec7f59c..0000000000 --- a/src/ServiceControl.Transports.RabbitMQQuorumDirectRouting.Tests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInRabbitMQTests()] \ No newline at end of file diff --git a/src/ServiceControl.Transports.SQS.Tests/ServiceControl.Transports.SQS.Tests.csproj b/src/ServiceControl.Transports.SQS.Tests/ServiceControl.Transports.SQS.Tests.csproj index cee5fd3419..c6039e8713 100644 --- a/src/ServiceControl.Transports.SQS.Tests/ServiceControl.Transports.SQS.Tests.csproj +++ b/src/ServiceControl.Transports.SQS.Tests/ServiceControl.Transports.SQS.Tests.csproj @@ -2,6 +2,7 @@ net10.0 + SQS @@ -29,7 +30,6 @@ - \ No newline at end of file diff --git a/src/ServiceControl.Transports.SQS.Tests/TestsFilter.cs b/src/ServiceControl.Transports.SQS.Tests/TestsFilter.cs deleted file mode 100644 index 1e15cac6b6..0000000000 --- a/src/ServiceControl.Transports.SQS.Tests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInAmazonSqsTests()] \ No newline at end of file diff --git a/src/ServiceControl.Transports.SqlServer.Tests/ServiceControl.Transports.SqlServer.Tests.csproj b/src/ServiceControl.Transports.SqlServer.Tests/ServiceControl.Transports.SqlServer.Tests.csproj index 62fe2403f2..3eed2f8333 100644 --- a/src/ServiceControl.Transports.SqlServer.Tests/ServiceControl.Transports.SqlServer.Tests.csproj +++ b/src/ServiceControl.Transports.SqlServer.Tests/ServiceControl.Transports.SqlServer.Tests.csproj @@ -2,6 +2,7 @@ net10.0 + SqlServer @@ -28,7 +29,6 @@ - \ No newline at end of file diff --git a/src/ServiceControl.Transports.SqlServer.Tests/TestsFilter.cs b/src/ServiceControl.Transports.SqlServer.Tests/TestsFilter.cs deleted file mode 100644 index cf47333a84..0000000000 --- a/src/ServiceControl.Transports.SqlServer.Tests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInSqlServerTests()] \ No newline at end of file diff --git a/src/ServiceControl.Transports.Tests/ServiceControl.Transports.Tests.csproj b/src/ServiceControl.Transports.Tests/ServiceControl.Transports.Tests.csproj index 261cccf063..fd649e1b60 100644 --- a/src/ServiceControl.Transports.Tests/ServiceControl.Transports.Tests.csproj +++ b/src/ServiceControl.Transports.Tests/ServiceControl.Transports.Tests.csproj @@ -2,6 +2,7 @@ net10.0 + DefaultCore diff --git a/src/ServiceControl.Transports.Tests/TestsFilter.cs b/src/ServiceControl.Transports.Tests/TestsFilter.cs deleted file mode 100644 index cbb64ab1fc..0000000000 --- a/src/ServiceControl.Transports.Tests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInDefaultTests()] \ No newline at end of file diff --git a/src/ServiceControl.UnitTests/ServiceControl.UnitTests.csproj b/src/ServiceControl.UnitTests/ServiceControl.UnitTests.csproj index 5c3a965155..280ef9eced 100644 --- a/src/ServiceControl.UnitTests/ServiceControl.UnitTests.csproj +++ b/src/ServiceControl.UnitTests/ServiceControl.UnitTests.csproj @@ -2,6 +2,7 @@ net10.0 + DefaultCore diff --git a/src/ServiceControl.UnitTests/TestsFilter.cs b/src/ServiceControl.UnitTests/TestsFilter.cs deleted file mode 100644 index cbb64ab1fc..0000000000 --- a/src/ServiceControl.UnitTests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInDefaultTests()] \ No newline at end of file diff --git a/src/ServiceControlInstaller.Engine.UnitTests/ServiceControlInstaller.Engine.UnitTests.csproj b/src/ServiceControlInstaller.Engine.UnitTests/ServiceControlInstaller.Engine.UnitTests.csproj index 3247d3f367..3908dc1ba1 100644 --- a/src/ServiceControlInstaller.Engine.UnitTests/ServiceControlInstaller.Engine.UnitTests.csproj +++ b/src/ServiceControlInstaller.Engine.UnitTests/ServiceControlInstaller.Engine.UnitTests.csproj @@ -2,6 +2,7 @@ net10.0-windows + DefaultCore diff --git a/src/ServiceControlInstaller.Engine.UnitTests/TestsFilter.cs b/src/ServiceControlInstaller.Engine.UnitTests/TestsFilter.cs deleted file mode 100644 index cbb64ab1fc..0000000000 --- a/src/ServiceControlInstaller.Engine.UnitTests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInDefaultTests()] \ No newline at end of file diff --git a/src/ServiceControlInstaller.Packaging.UnitTests/ServiceControlInstaller.Packaging.UnitTests.csproj b/src/ServiceControlInstaller.Packaging.UnitTests/ServiceControlInstaller.Packaging.UnitTests.csproj index be95909ae0..38dd4fbc7d 100644 --- a/src/ServiceControlInstaller.Packaging.UnitTests/ServiceControlInstaller.Packaging.UnitTests.csproj +++ b/src/ServiceControlInstaller.Packaging.UnitTests/ServiceControlInstaller.Packaging.UnitTests.csproj @@ -2,6 +2,7 @@ net10.0 + DefaultCore diff --git a/src/ServiceControlInstaller.Packaging.UnitTests/TestsFilter.cs b/src/ServiceControlInstaller.Packaging.UnitTests/TestsFilter.cs deleted file mode 100644 index cbb64ab1fc..0000000000 --- a/src/ServiceControlInstaller.Packaging.UnitTests/TestsFilter.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: IncludeInDefaultTests()] \ No newline at end of file diff --git a/src/TestHelper/IncludeInAmazonSqsTestsAttribute.cs b/src/TestHelper/IncludeInAmazonSqsTestsAttribute.cs deleted file mode 100644 index c1d8825d57..0000000000 --- a/src/TestHelper/IncludeInAmazonSqsTestsAttribute.cs +++ /dev/null @@ -1,4 +0,0 @@ -public class IncludeInAmazonSqsTestsAttribute : IncludeInTestsAttribute -{ - protected override string Filter => "SQS"; -} diff --git a/src/TestHelper/IncludeInAzureServiceBusTestsAttribute.cs b/src/TestHelper/IncludeInAzureServiceBusTestsAttribute.cs deleted file mode 100644 index ca89724c59..0000000000 --- a/src/TestHelper/IncludeInAzureServiceBusTestsAttribute.cs +++ /dev/null @@ -1,4 +0,0 @@ -public class IncludeInAzureServiceBusTestsAttribute : IncludeInTestsAttribute -{ - protected override string Filter => "AzureServiceBus"; -} diff --git a/src/TestHelper/IncludeInAzureStorageQueuesTestsAttribute.cs b/src/TestHelper/IncludeInAzureStorageQueuesTestsAttribute.cs deleted file mode 100644 index 80488efc96..0000000000 --- a/src/TestHelper/IncludeInAzureStorageQueuesTestsAttribute.cs +++ /dev/null @@ -1,4 +0,0 @@ -public class IncludeInAzureStorageQueuesTestsAttribute : IncludeInTestsAttribute -{ - protected override string Filter => "AzureStorageQueues"; -} diff --git a/src/TestHelper/IncludeInDefaultTestsAttribute.cs b/src/TestHelper/IncludeInDefaultTestsAttribute.cs deleted file mode 100644 index 83442d9b40..0000000000 --- a/src/TestHelper/IncludeInDefaultTestsAttribute.cs +++ /dev/null @@ -1,4 +0,0 @@ -public class IncludeInDefaultTestsAttribute : IncludeInTestsAttribute -{ - protected override string Filter => "Default"; -} \ No newline at end of file diff --git a/src/TestHelper/IncludeInIBMMQTestsAttribute.cs b/src/TestHelper/IncludeInIBMMQTestsAttribute.cs deleted file mode 100644 index 2bb18aeb93..0000000000 --- a/src/TestHelper/IncludeInIBMMQTestsAttribute.cs +++ /dev/null @@ -1,4 +0,0 @@ -public class IncludeInIBMMQTestsAttribute : IncludeInTestsAttribute -{ - protected override string Filter => "IBMMQ"; -} diff --git a/src/TestHelper/IncludeInMsmqTestsAttribute.cs b/src/TestHelper/IncludeInMsmqTestsAttribute.cs deleted file mode 100644 index a4946e59d3..0000000000 --- a/src/TestHelper/IncludeInMsmqTestsAttribute.cs +++ /dev/null @@ -1,4 +0,0 @@ -public class IncludeInMsmqTestsAttribute : IncludeInTestsAttribute -{ - protected override string Filter => "MSMQ"; -} diff --git a/src/TestHelper/IncludeInPostgreSqlTestsAttribute.cs b/src/TestHelper/IncludeInPostgreSqlTestsAttribute.cs deleted file mode 100644 index 4691a26412..0000000000 --- a/src/TestHelper/IncludeInPostgreSqlTestsAttribute.cs +++ /dev/null @@ -1,4 +0,0 @@ -public class IncludeInPostgreSqlTestsAttribute : IncludeInTestsAttribute -{ - protected override string Filter => "PostgreSql"; -} diff --git a/src/TestHelper/IncludeInRabbitMQTestsAttribute.cs b/src/TestHelper/IncludeInRabbitMQTestsAttribute.cs deleted file mode 100644 index 23002f4336..0000000000 --- a/src/TestHelper/IncludeInRabbitMQTestsAttribute.cs +++ /dev/null @@ -1,4 +0,0 @@ -public class IncludeInRabbitMQTestsAttribute : IncludeInTestsAttribute -{ - protected override string Filter => "RabbitMQ"; -} diff --git a/src/TestHelper/IncludeInSqlServerTestsAttribute.cs b/src/TestHelper/IncludeInSqlServerTestsAttribute.cs deleted file mode 100644 index 4240d8ea0a..0000000000 --- a/src/TestHelper/IncludeInSqlServerTestsAttribute.cs +++ /dev/null @@ -1,4 +0,0 @@ -public class IncludeInSqlServerTestsAttribute : IncludeInTestsAttribute -{ - protected override string Filter => "SqlServer"; -} diff --git a/tools/run-tests.ps1 b/tools/run-tests.ps1 new file mode 100644 index 0000000000..5927f0d073 --- /dev/null +++ b/tools/run-tests.ps1 @@ -0,0 +1,60 @@ +# Runs dotnet test against an explicit list of test projects, rather than discovering every test +# project under src. The list comes from tools/select-test-projects.ps1, so a job only pays for the +# assemblies belonging to its test category. +# +# This is a scoped replacement for Particular/run-tests-action, which has no way to be told which +# projects to run. It should fold back into that action once it grows a 'projects' input. + +param( + [Parameter(Mandatory)] + [string]$Projects, + + [string]$TargetPlatform = 'x64', + + [switch]$ReportWarnings +) + +$ErrorActionPreference = 'Stop' + +$projectPaths = $Projects -split "`n" | ForEach-Object { $_.Trim() } | Where-Object { $_ } + +if ($projectPaths.Count -eq 0) { + throw 'No test projects were supplied.' +} + +Write-Output "Target Platform = $TargetPlatform" + +$reportWarningsValue = if ($ReportWarnings) { 'true' } else { 'false' } +$isUnix = $PSVersionTable.Platform -eq 'Unix' +$exitCode = 0 + +foreach ($project in $projectPaths) { + $frameworks = @( + (Select-Xml -Path $project -XPath "/Project/PropertyGroup/TargetFramework").Node.InnerText + (Select-Xml -Path $project -XPath "/Project/PropertyGroup/TargetFrameworks").Node.InnerText -split ';' + ) | Where-Object { $_ } + + if ($frameworks.Count -eq 0) { + throw "Could not determine a target framework for $project." + } + + foreach ($framework in $frameworks) { + if ($isUnix -and ($framework.StartsWith('net4') -or $framework.Contains('-windows'))) { + Write-Output "Skipping $(Split-Path $project -Leaf) ($framework) because it cannot run on this platform." + continue + } + + Write-Output "::group::Running $(Split-Path $project -Leaf) ($framework)" + + dotnet test $project --configuration Release --no-build --framework $framework --logger "GitHubActions;report-warnings=$reportWarningsValue" -- RunConfiguration.TreatNoTestsAsError=true "RunConfiguration.TargetPlatform=$TargetPlatform" + + Write-Output '::endgroup::' + + if ($LASTEXITCODE -ne 0) { + Write-Output "::error::Exit code = $LASTEXITCODE" + $exitCode = 1 + } + } +} + +exit $exitCode diff --git a/tools/select-test-projects.ps1 b/tools/select-test-projects.ps1 new file mode 100644 index 0000000000..d1f5704f6f --- /dev/null +++ b/tools/select-test-projects.ps1 @@ -0,0 +1,102 @@ +# Selects the test projects belonging to a test category, so that CI can build and run only those +# rather than the whole solution. The category is declared by the property in each test +# project. +# +# Writes the selected project paths to $GITHUB_OUTPUT as 'test-projects', and generates an MSBuild +# traversal project so that `dotnet build` can build the whole selection in one graph. +# +# Use -List to print every category and its projects without writing any files. + +[CmdletBinding(DefaultParameterSetName = 'Select')] +param( + [Parameter(Mandatory, ParameterSetName = 'Select')] + [string]$Category, + + [Parameter(ParameterSetName = 'Select')] + [string]$TraversalProjectPath = 'tests.proj', + + [Parameter(Mandatory, ParameterSetName = 'List')] + [switch]$List +) + +$ErrorActionPreference = 'Stop' + +$projectsByCategory = @{} +$uncategorized = New-Object Collections.Generic.List[String] + +# -Filter rather than -Include: the provider applies it during traversal, which is dramatically faster +# on a tree that already contains bin/obj output. +Get-ChildItem -Path src -Filter '*.csproj' -Recurse -File | ForEach-Object { + $testCategory = (Select-Xml -Path $_.FullName -XPath "/Project/PropertyGroup/TestCategory").Node.InnerText + + if ([string]::IsNullOrWhiteSpace($testCategory)) { + # A project referencing the test SDK but declaring no category would never be selected by any + # job, so its tests would silently not run rather than fail. Catch that here instead. + $isTestProject = $null -ne (Select-Xml -Path $_.FullName -XPath "/Project/ItemGroup/PackageReference[@Include='Microsoft.NET.Test.Sdk']") + if ($isTestProject) { + $uncategorized.Add((Resolve-Path -Relative $_.FullName)) + } + return + } + + if (-not $projectsByCategory.ContainsKey($testCategory)) { + $projectsByCategory[$testCategory] = New-Object Collections.Generic.List[String] + } + + $projectsByCategory[$testCategory].Add((Resolve-Path -Relative $_.FullName)) +} + +if ($uncategorized.Count -gt 0) { + # Not named $list: PowerShell variables are case-insensitive, so that would overwrite the [switch]$List parameter. + $formatted = ($uncategorized | Sort-Object | ForEach-Object { " $_" }) -join [Environment]::NewLine + throw "These test projects declare no , so CI would never build or run them:$([Environment]::NewLine)$formatted" +} + +if ($List) { + foreach ($key in $projectsByCategory.Keys | Sort-Object) { + Write-Output "$key" + $projectsByCategory[$key] | Sort-Object | ForEach-Object { Write-Output " $_" } + } + return +} + +if (-not $projectsByCategory.ContainsKey($Category)) { + $known = ($projectsByCategory.Keys | Sort-Object) -join ', ' + throw "No test project declares $Category. Known categories: $known" +} + +$projects = $projectsByCategory[$Category] | Sort-Object + +Write-Output "Test category '$Category' selects $($projects.Count) project(s):" +$projects | ForEach-Object { Write-Output " $_" } + +# ReferenceOutputAssembly is irrelevant here because the traversal project produces nothing itself. +# TargetFramework is undefined per reference so that projects targeting net10.0-windows are not forced +# onto the traversal project's own framework, matching the convention in ProjectReferences.Transports.props. +$references = $projects | ForEach-Object { + " " +} + +$traversal = @" + + + + + net10.0 + + + +$($references -join [Environment]::NewLine) + + + +"@ + +Set-Content -Path $TraversalProjectPath -Value $traversal -Encoding utf8 +Write-Output "Wrote traversal project to $TraversalProjectPath" + +if ($Env:GITHUB_OUTPUT) { + "test-projects<