From 4e9036e36fd43764d8955cf801ba29b2ab4fb746 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 05:00:55 +0000 Subject: [PATCH 01/41] Initial plan From 7236d3812934756d0efa87222e7a8e2b8f1a2801 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 05:12:04 +0000 Subject: [PATCH 02/41] Add .NET 10 (preview) as a TFM for multi-targeting builds Co-authored-by: aaronpowell <434140+aaronpowell@users.noreply.github.com> --- Directory.Build.props | 2 +- Directory.Packages.props | 4 ++++ ...CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.csproj | 2 +- ...ommunityToolkit.Aspire.Hosting.SqlServer.Extensions.csproj | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 974adbf17..57f2c17f9 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,7 +5,7 @@ net8.0 $(DefaultTargetFramework) - $(DefaultTargetFramework);net9.0 + $(DefaultTargetFramework);net9.0;net10.0 latest enable diff --git a/Directory.Packages.props b/Directory.Packages.props index 763e8b6c2..d2352dfa6 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -117,4 +117,8 @@ + + + + \ No newline at end of file diff --git a/src/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.csproj b/src/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.csproj index 07512d831..52ffde0ba 100644 --- a/src/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.csproj +++ b/src/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.csproj @@ -24,7 +24,7 @@ - + diff --git a/src/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions.csproj b/src/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions.csproj index 4d6914c83..e4cccaf2e 100644 --- a/src/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions.csproj +++ b/src/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions.csproj @@ -20,7 +20,7 @@ - + From 303a76f7145656d12117ce9edf459fa4a07616c1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 05:27:27 +0000 Subject: [PATCH 03/41] Change default TFM to .NET 10 and update GitHub Actions to install .NET 10 Co-authored-by: aaronpowell <434140+aaronpowell@users.noreply.github.com> --- .github/workflows/codeql.yml | 1 + .github/workflows/dotnet-main.yml | 2 +- .github/workflows/dotnet-release.yml | 2 +- .github/workflows/generate-api-diffs.yml | 3 ++- .github/workflows/package.yml | 1 + Directory.Build.props | 4 ++-- global.json | 2 +- 7 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index fee7c86ce..ab79da1cf 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -69,6 +69,7 @@ jobs: dotnet-version: | 8.0.x 9.0.x + 10.0.x # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v4 diff --git a/.github/workflows/dotnet-main.yml b/.github/workflows/dotnet-main.yml index 7339a0d28..8fc4c9dce 100644 --- a/.github/workflows/dotnet-main.yml +++ b/.github/workflows/dotnet-main.yml @@ -6,7 +6,7 @@ on: workflow_dispatch: env: - DEFAULT_DOTNET_VERSION: "8.0.x" + DEFAULT_DOTNET_VERSION: "10.0.x" permissions: contents: read diff --git a/.github/workflows/dotnet-release.yml b/.github/workflows/dotnet-release.yml index 2f149c0d8..1f2ec0c5c 100644 --- a/.github/workflows/dotnet-release.yml +++ b/.github/workflows/dotnet-release.yml @@ -6,7 +6,7 @@ on: - "v*" env: - DEFAULT_DOTNET_VERSION: "8.0.x" + DEFAULT_DOTNET_VERSION: "10.0.x" jobs: build: diff --git a/.github/workflows/generate-api-diffs.yml b/.github/workflows/generate-api-diffs.yml index 8a165d0aa..47d18e868 100644 --- a/.github/workflows/generate-api-diffs.yml +++ b/.github/workflows/generate-api-diffs.yml @@ -21,12 +21,13 @@ jobs: dotnet-version: | 8.0.x 9.0.x + 10.0.x - name: Restore and build run: | find src -type f -name "*.csproj" | while read -r csproj; do - dotnet build "$csproj" -f net8.0 --configuration Release --no-incremental -t:Build -t:GenAPIGenerateReferenceAssemblySource + dotnet build "$csproj" -f net10.0 --configuration Release --no-incremental -t:Build -t:GenAPIGenerateReferenceAssemblySource done continue-on-error: true diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index 44ab545f8..3bdf02475 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -24,6 +24,7 @@ jobs: dotnet-version: | 8.0.x 9.0.x + 10.0.x - name: Get git tag id: git_tag diff --git a/Directory.Build.props b/Directory.Build.props index 57f2c17f9..6844bf2a9 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -3,9 +3,9 @@ - net8.0 + net10.0 $(DefaultTargetFramework) - $(DefaultTargetFramework);net9.0;net10.0 + $(DefaultTargetFramework);net8.0;net9.0 latest enable diff --git a/global.json b/global.json index a8ab760dd..20dc84cd1 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "allowPrerelease": false + "allowPrerelease": true } } \ No newline at end of file From c6b19fca7818f9a66b6fc3548093650e864e981f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 05:42:38 +0000 Subject: [PATCH 04/41] Update devcontainer to install .NET 10 as preview Co-authored-by: aaronpowell <434140+aaronpowell@users.noreply.github.com> --- .devcontainer/devcontainer.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index cc803f382..388762fb9 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -4,8 +4,9 @@ "features": { "ghcr.io/azure/azure-dev/azd:latest": {}, "ghcr.io/devcontainers/features/dotnet:latest": { - "version": "8.0", - "additionalVersions": "9.0" + "version": "10.0", + "additionalVersions": "8.0,9.0", + "installUsingApt": false }, "ghcr.io/devcontainers/features/github-cli:latest": {}, "ghcr.io/devcontainers/features/java:1": { From 1e4e20dcdaf9d68c95863303aabd5b21edc89095 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 05:56:31 +0000 Subject: [PATCH 05/41] Add .NET 10 to setup-runtimes-caching action Co-authored-by: aaronpowell <434140+aaronpowell@users.noreply.github.com> --- .github/actions/setup-runtimes-caching/action.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/setup-runtimes-caching/action.yml b/.github/actions/setup-runtimes-caching/action.yml index a92919c74..31fe1a33b 100644 --- a/.github/actions/setup-runtimes-caching/action.yml +++ b/.github/actions/setup-runtimes-caching/action.yml @@ -22,6 +22,7 @@ runs: dotnet-version: | 8.0.x 9.0.x + 10.0.x - name: Set up Python uses: actions/setup-python@v5 From ac50650b3271e0a07e526b104d4301b75daf37f6 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Thu, 6 Nov 2025 22:55:05 +0000 Subject: [PATCH 06/41] Fixing some versioning --- Directory.Build.props | 2 +- Directory.Packages.props | 12 +++--------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 6844bf2a9..42e996108 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -16,7 +16,7 @@ $(AspireVersion) preview.1.25522.3 9.0.0 - 9.0.10 + 10.0.0-rc.2.25502.107 1.12.0 4.7.0 9.9.0 diff --git a/Directory.Packages.props b/Directory.Packages.props index d2352dfa6..ce41a4a4a 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -44,11 +44,12 @@ - + + @@ -73,6 +74,7 @@ + @@ -113,12 +115,4 @@ - - - - - - - - \ No newline at end of file From 94417949dc1a8d84a1083b196175fd1a0d84c2e1 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Thu, 6 Nov 2025 22:55:56 +0000 Subject: [PATCH 07/41] Hard coding an update to use Apache.NMS.AMQP@2.4.0 as 2.2.0 has a CVE but the MassTransit.ActiveMQ package isn't updated yet Tracked: https://github.com/MassTransit/MassTransit/issues/6133 --- ...ommunityToolkit.Aspire.Hosting.ActiveMQ.MassTransit.csproj | 1 + .../CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests.csproj | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.MassTransit/CommunityToolkit.Aspire.Hosting.ActiveMQ.MassTransit.csproj b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.MassTransit/CommunityToolkit.Aspire.Hosting.ActiveMQ.MassTransit.csproj index 815a154dc..a611be36d 100644 --- a/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.MassTransit/CommunityToolkit.Aspire.Hosting.ActiveMQ.MassTransit.csproj +++ b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.MassTransit/CommunityToolkit.Aspire.Hosting.ActiveMQ.MassTransit.csproj @@ -9,6 +9,7 @@ + diff --git a/tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests.csproj b/tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests.csproj index e7c0115f7..a76ecb91d 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests.csproj +++ b/tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests.csproj @@ -12,4 +12,8 @@ + + + + From ef89379b33b8519480fcb6293f83dfc6c7b8f6e7 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Thu, 6 Nov 2025 23:54:58 +0000 Subject: [PATCH 08/41] Fixing some projects that specified their own TFM and trying to address ambiguous referencing --- Directory.Packages.props | 7 +++++++ ...Toolkit.Aspire.MassTransit.RabbitMQ.MessageTypes.csproj | 3 --- ...ityToolkit.Aspire.MassTransit.RabbitMQ.Publisher.csproj | 3 --- .../CommunityToolkit.Aspire.PowerShell.AppHost.csproj | 3 --- .../CommunityToolkit.Aspire.Hosting.KurrentDB.csproj | 7 +++++++ tests-app-hosts/Ollama.AppHost/Ollama.AppHost.csproj | 2 +- 6 files changed, 15 insertions(+), 10 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index ce41a4a4a..7f6ab35c8 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -115,4 +115,11 @@ + + + + all + + + \ No newline at end of file diff --git a/examples/masstransit-rabbitmq/CommunityToolkit.Aspire.MassTransit.RabbitMQ.MessageTypes/CommunityToolkit.Aspire.MassTransit.RabbitMQ.MessageTypes.csproj b/examples/masstransit-rabbitmq/CommunityToolkit.Aspire.MassTransit.RabbitMQ.MessageTypes/CommunityToolkit.Aspire.MassTransit.RabbitMQ.MessageTypes.csproj index abae6f43d..78b3f4709 100644 --- a/examples/masstransit-rabbitmq/CommunityToolkit.Aspire.MassTransit.RabbitMQ.MessageTypes/CommunityToolkit.Aspire.MassTransit.RabbitMQ.MessageTypes.csproj +++ b/examples/masstransit-rabbitmq/CommunityToolkit.Aspire.MassTransit.RabbitMQ.MessageTypes/CommunityToolkit.Aspire.MassTransit.RabbitMQ.MessageTypes.csproj @@ -1,9 +1,6 @@  - net8.0 - enable - enable Messaging diff --git a/examples/masstransit-rabbitmq/CommunityToolkit.Aspire.MassTransit.RabbitMQ.Publisher/CommunityToolkit.Aspire.MassTransit.RabbitMQ.Publisher.csproj b/examples/masstransit-rabbitmq/CommunityToolkit.Aspire.MassTransit.RabbitMQ.Publisher/CommunityToolkit.Aspire.MassTransit.RabbitMQ.Publisher.csproj index 047ceb190..1eaa00f58 100644 --- a/examples/masstransit-rabbitmq/CommunityToolkit.Aspire.MassTransit.RabbitMQ.Publisher/CommunityToolkit.Aspire.MassTransit.RabbitMQ.Publisher.csproj +++ b/examples/masstransit-rabbitmq/CommunityToolkit.Aspire.MassTransit.RabbitMQ.Publisher/CommunityToolkit.Aspire.MassTransit.RabbitMQ.Publisher.csproj @@ -2,9 +2,6 @@ Exe - net8.0 - enable - enable diff --git a/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/CommunityToolkit.Aspire.PowerShell.AppHost.csproj b/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/CommunityToolkit.Aspire.PowerShell.AppHost.csproj index 63aed919d..780f57a93 100644 --- a/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/CommunityToolkit.Aspire.PowerShell.AppHost.csproj +++ b/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/CommunityToolkit.Aspire.PowerShell.AppHost.csproj @@ -4,9 +4,6 @@ Exe - net8.0 - enable - enable true bc193f31-c9f7-4e3d-b70a-0dc39ec3047f diff --git a/src/CommunityToolkit.Aspire.Hosting.KurrentDB/CommunityToolkit.Aspire.Hosting.KurrentDB.csproj b/src/CommunityToolkit.Aspire.Hosting.KurrentDB/CommunityToolkit.Aspire.Hosting.KurrentDB.csproj index 4480a050d..24cd4a68b 100644 --- a/src/CommunityToolkit.Aspire.Hosting.KurrentDB/CommunityToolkit.Aspire.Hosting.KurrentDB.csproj +++ b/src/CommunityToolkit.Aspire.Hosting.KurrentDB/CommunityToolkit.Aspire.Hosting.KurrentDB.csproj @@ -14,4 +14,11 @@ + + + all + + + + diff --git a/tests-app-hosts/Ollama.AppHost/Ollama.AppHost.csproj b/tests-app-hosts/Ollama.AppHost/Ollama.AppHost.csproj index a690e00c6..ca4a2b973 100644 --- a/tests-app-hosts/Ollama.AppHost/Ollama.AppHost.csproj +++ b/tests-app-hosts/Ollama.AppHost/Ollama.AppHost.csproj @@ -3,7 +3,7 @@ Exe - net8.0 + net10.0 enable enable true From e66de71765399293f314db145b116f57e3d5f78f Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Fri, 7 Nov 2025 03:11:01 +0000 Subject: [PATCH 09/41] Using an improved approach approach to adding system.linq.asyncenumerable --- Directory.Packages.props | 6 ++---- .../CommunityToolkit.Aspire.Hosting.KurrentDB.csproj | 4 ++-- .../CommunityToolkit.Aspire.KurrentDB.csproj | 6 ++++++ .../CommunityToolkit.Aspire.KurrentDB.Tests.csproj | 7 +++++++ 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 7f6ab35c8..92765cc7c 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -116,10 +116,8 @@ - - - all - + + \ No newline at end of file diff --git a/src/CommunityToolkit.Aspire.Hosting.KurrentDB/CommunityToolkit.Aspire.Hosting.KurrentDB.csproj b/src/CommunityToolkit.Aspire.Hosting.KurrentDB/CommunityToolkit.Aspire.Hosting.KurrentDB.csproj index 24cd4a68b..2d0d68eb5 100644 --- a/src/CommunityToolkit.Aspire.Hosting.KurrentDB/CommunityToolkit.Aspire.Hosting.KurrentDB.csproj +++ b/src/CommunityToolkit.Aspire.Hosting.KurrentDB/CommunityToolkit.Aspire.Hosting.KurrentDB.csproj @@ -14,11 +14,11 @@ - + all - + diff --git a/src/CommunityToolkit.Aspire.KurrentDB/CommunityToolkit.Aspire.KurrentDB.csproj b/src/CommunityToolkit.Aspire.KurrentDB/CommunityToolkit.Aspire.KurrentDB.csproj index 886e876f5..c9164e06f 100644 --- a/src/CommunityToolkit.Aspire.KurrentDB/CommunityToolkit.Aspire.KurrentDB.csproj +++ b/src/CommunityToolkit.Aspire.KurrentDB/CommunityToolkit.Aspire.KurrentDB.csproj @@ -16,4 +16,10 @@ + + + all + + + diff --git a/tests/CommunityToolkit.Aspire.KurrentDB.Tests/CommunityToolkit.Aspire.KurrentDB.Tests.csproj b/tests/CommunityToolkit.Aspire.KurrentDB.Tests/CommunityToolkit.Aspire.KurrentDB.Tests.csproj index fabc6da45..72ed754f7 100644 --- a/tests/CommunityToolkit.Aspire.KurrentDB.Tests/CommunityToolkit.Aspire.KurrentDB.Tests.csproj +++ b/tests/CommunityToolkit.Aspire.KurrentDB.Tests/CommunityToolkit.Aspire.KurrentDB.Tests.csproj @@ -9,4 +9,11 @@ + + + + all + + + From 51e57ba867ab691d3fda3f2997624bfc93264a16 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 10 Nov 2025 00:49:38 +0000 Subject: [PATCH 10/41] Updating how dev certs are setup --- .devcontainer/post-create.sh | 3 +-- .github/actions/setup-runtimes-caching/action.yml | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.devcontainer/post-create.sh b/.devcontainer/post-create.sh index 6096ba239..dcd64df77 100755 --- a/.devcontainer/post-create.sh +++ b/.devcontainer/post-create.sh @@ -5,8 +5,7 @@ sudo apt-get update && \ sudo rm -rf /var/lib/apt/lists/* echo Install .NET dev certs -dotnet tool update -g linux-dev-certs -dotnet linux-dev-certs install +dotnet dev-certs https --trust echo Install JS monorepo tools npm install -g turbo diff --git a/.github/actions/setup-runtimes-caching/action.yml b/.github/actions/setup-runtimes-caching/action.yml index 31fe1a33b..a4d38f6ef 100644 --- a/.github/actions/setup-runtimes-caching/action.yml +++ b/.github/actions/setup-runtimes-caching/action.yml @@ -85,8 +85,7 @@ runs: shell: bash if: ${{ matrix.os == 'ubuntu-latest' }} run: | - dotnet tool update -g linux-dev-certs - dotnet linux-dev-certs install + dotnet dev-certs https --trust - name: Setup Node globals shell: bash @@ -118,3 +117,4 @@ runs: run: | dapr init --runtime-version=${{ env.DAPR_VERSION }} dapr --version + From f3ff1ffb9e3ecb81c670ce8ec5d8a06b951f346f Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 10 Nov 2025 01:01:39 +0000 Subject: [PATCH 11/41] Turns out you can't upgrade around the CVE, so we now suppress it I feel dirty doing that... --- Directory.Build.props | 4 ++++ Directory.Packages.props | 1 - ...ommunityToolkit.Aspire.Hosting.ActiveMQ.MassTransit.csproj | 1 - .../CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests.csproj | 4 ---- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 42e996108..7d9be405f 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -46,4 +46,8 @@ $(AspireMajorVersion).$(ToolkitMinorVersion).$(ToolkitPatchVersion) + + + + diff --git a/Directory.Packages.props b/Directory.Packages.props index 92765cc7c..30934a6be 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -74,7 +74,6 @@ - diff --git a/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.MassTransit/CommunityToolkit.Aspire.Hosting.ActiveMQ.MassTransit.csproj b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.MassTransit/CommunityToolkit.Aspire.Hosting.ActiveMQ.MassTransit.csproj index a611be36d..815a154dc 100644 --- a/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.MassTransit/CommunityToolkit.Aspire.Hosting.ActiveMQ.MassTransit.csproj +++ b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.MassTransit/CommunityToolkit.Aspire.Hosting.ActiveMQ.MassTransit.csproj @@ -9,7 +9,6 @@ - diff --git a/tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests.csproj b/tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests.csproj index a76ecb91d..e7c0115f7 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests.csproj +++ b/tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests.csproj @@ -12,8 +12,4 @@ - - - - From df16921e24064ecbd5b1d0270997b4f69581b86e Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 10 Nov 2025 05:11:50 +0000 Subject: [PATCH 12/41] Update to xunit v3 --- Directory.Packages.props | 11 +-- nuget.config | 2 +- ...AspireGoFeatureFlagClientExtensionsTest.cs | 1 + .../ConformanceTests.cs | 1 + .../GoFeatureFlagContainerFixture.cs | 5 +- .../AddAdminerTests.cs | 1 + .../AddDbGateTests.cs | 1 + .../GoFeatureFlagFunctionalTests.cs | 3 +- .../KeycloakWithPostgresIntegrationTest.cs | 1 + .../KurrentDBFunctionalTests.cs | 2 +- .../AppHostTests.cs | 2 +- .../MeilisearchFunctionalTests.cs | 1 - .../MinioFunctionalTests.cs | 2 +- .../ResourceCreationTests.cs | 2 +- .../FunctionalTests.cs | 5 +- .../SqlServerContainerFixture.cs | 4 +- .../SurrealDbFunctionalTests.cs | 1 - .../AspireKurrentDBClientExtensionsTest.cs | 1 + .../ConformanceTests.cs | 1 + .../KurrentDBContainerFixture.cs | 5 +- .../AspireMeilisearchClientExtensionsTest.cs | 1 + .../ConformanceTests.cs | 1 + .../MeilisearchContainerFixture.cs | 5 +- .../ConformanceTests.cs | 1 + .../MinioContainerFeature.cs | 5 +- .../ConformanceTests.cs | 1 + .../OllamaContainerFeature.cs | 5 +- .../RavenDbServerFixture.cs | 6 +- .../AspireSurrealClientExtensionsTest.cs | 1 + .../ConformanceTests.cs | 9 +- .../SurrealDbContainerFixture.cs | 5 +- .../AspireIntegrationTest.cs | 4 +- .../CommunityToolkit.Aspire.Testing.csproj | 12 +-- .../ConformanceTests.cs | 86 ++++++++++++------- ...utedApplicationTestingBuilderExtensions.cs | 1 - .../PlatformDetection.cs | 13 ++- .../RequiresDockerAttribute.cs | 24 ++++-- .../RequiresDockerDiscoverer.cs | 20 ----- .../RequiresLinuxAttribute.cs | 14 ++- .../RequiresLinuxDiscoverer.cs | 20 ----- .../RequiresWindowsAttribute.cs | 20 ++++- .../RequiresWindowsDiscoverer.cs | 15 ---- .../TestDistributedApplicationBuilder.cs | 1 - tests/Directory.Build.props | 9 +- 44 files changed, 178 insertions(+), 153 deletions(-) delete mode 100644 tests/CommunityToolkit.Aspire.Testing/RequiresDockerDiscoverer.cs delete mode 100644 tests/CommunityToolkit.Aspire.Testing/RequiresLinuxDiscoverer.cs delete mode 100644 tests/CommunityToolkit.Aspire.Testing/RequiresWindowsDiscoverer.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index 30934a6be..6ca1758e4 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -100,12 +100,13 @@ - + - - - - + + + + + diff --git a/nuget.config b/nuget.config index 16a6b5139..8d6946030 100644 --- a/nuget.config +++ b/nuget.config @@ -14,7 +14,7 @@ - + diff --git a/tests/CommunityToolkit.Aspire.GoFeatureFlag.Tests/AspireGoFeatureFlagClientExtensionsTest.cs b/tests/CommunityToolkit.Aspire.GoFeatureFlag.Tests/AspireGoFeatureFlagClientExtensionsTest.cs index 4d07a5cf9..a7e134ba2 100644 --- a/tests/CommunityToolkit.Aspire.GoFeatureFlag.Tests/AspireGoFeatureFlagClientExtensionsTest.cs +++ b/tests/CommunityToolkit.Aspire.GoFeatureFlag.Tests/AspireGoFeatureFlagClientExtensionsTest.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Components.Common.Tests; +using CommunityToolkit.Aspire.Testing; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Hosting; diff --git a/tests/CommunityToolkit.Aspire.GoFeatureFlag.Tests/ConformanceTests.cs b/tests/CommunityToolkit.Aspire.GoFeatureFlag.Tests/ConformanceTests.cs index e5942de1a..65c5ae4ff 100644 --- a/tests/CommunityToolkit.Aspire.GoFeatureFlag.Tests/ConformanceTests.cs +++ b/tests/CommunityToolkit.Aspire.GoFeatureFlag.Tests/ConformanceTests.cs @@ -3,6 +3,7 @@ using Aspire.Components.Common.Tests; using Aspire.Components.ConformanceTests; +using CommunityToolkit.Aspire.Testing; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using OpenFeature.Contrib.Providers.GOFeatureFlag; diff --git a/tests/CommunityToolkit.Aspire.GoFeatureFlag.Tests/GoFeatureFlagContainerFixture.cs b/tests/CommunityToolkit.Aspire.GoFeatureFlag.Tests/GoFeatureFlagContainerFixture.cs index 591ece83c..5c5db3936 100644 --- a/tests/CommunityToolkit.Aspire.GoFeatureFlag.Tests/GoFeatureFlagContainerFixture.cs +++ b/tests/CommunityToolkit.Aspire.GoFeatureFlag.Tests/GoFeatureFlagContainerFixture.cs @@ -6,6 +6,7 @@ using Aspire.Hosting; using DotNet.Testcontainers.Builders; using DotNet.Testcontainers.Containers; +using CommunityToolkit.Aspire.Testing; namespace CommunityToolkit.Aspire.GoFeatureFlag.Tests; @@ -22,7 +23,7 @@ public string GetConnectionString() return $"Endpoint={endpoint}"; } - public async Task InitializeAsync() + public async ValueTask InitializeAsync() { if (RequiresDockerAttribute.IsSupported) { @@ -38,7 +39,7 @@ public async Task InitializeAsync() } } - public async Task DisposeAsync() + public async ValueTask DisposeAsync() { if (Container is not null) { diff --git a/tests/CommunityToolkit.Aspire.Hosting.Adminer.Tests/AddAdminerTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Adminer.Tests/AddAdminerTests.cs index 963891292..6be67fb81 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.Adminer.Tests/AddAdminerTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.Adminer.Tests/AddAdminerTests.cs @@ -3,6 +3,7 @@ using Aspire.Components.Common.Tests; using Aspire.Hosting; using Aspire.Hosting.Utils; +using CommunityToolkit.Aspire.Testing; namespace CommunityToolkit.Aspire.Hosting.Adminer.Tests; diff --git a/tests/CommunityToolkit.Aspire.Hosting.DbGate.Tests/AddDbGateTests.cs b/tests/CommunityToolkit.Aspire.Hosting.DbGate.Tests/AddDbGateTests.cs index ec0cbd1a1..2b03401ec 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.DbGate.Tests/AddDbGateTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.DbGate.Tests/AddDbGateTests.cs @@ -3,6 +3,7 @@ using Aspire.Hosting; using Aspire.Hosting.ApplicationModel; using Aspire.Hosting.Utils; +using CommunityToolkit.Aspire.Testing; namespace CommunityToolkit.Aspire.Hosting.DbGate.Tests; diff --git a/tests/CommunityToolkit.Aspire.Hosting.GoFeatureFlag.Tests/GoFeatureFlagFunctionalTests.cs b/tests/CommunityToolkit.Aspire.Hosting.GoFeatureFlag.Tests/GoFeatureFlagFunctionalTests.cs index 0eb202a15..e6a044049 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.GoFeatureFlag.Tests/GoFeatureFlagFunctionalTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.GoFeatureFlag.Tests/GoFeatureFlagFunctionalTests.cs @@ -1,14 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Aspire.Components.Common.Tests; using Aspire.Hosting; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Hosting; -using Xunit.Abstractions; using Aspire.Hosting.Utils; using OpenFeature.Contrib.Providers.GOFeatureFlag; using OpenFeature.Model; +using CommunityToolkit.Aspire.Testing; namespace CommunityToolkit.Aspire.Hosting.GoFeatureFlag.Tests; diff --git a/tests/CommunityToolkit.Aspire.Hosting.Keycloak.Extensions.Tests/KeycloakWithPostgresIntegrationTest.cs b/tests/CommunityToolkit.Aspire.Hosting.Keycloak.Extensions.Tests/KeycloakWithPostgresIntegrationTest.cs index a295d9f91..f39c25bd7 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.Keycloak.Extensions.Tests/KeycloakWithPostgresIntegrationTest.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.Keycloak.Extensions.Tests/KeycloakWithPostgresIntegrationTest.cs @@ -1,6 +1,7 @@ using Aspire.Components.Common.Tests; using Aspire.Hosting; using Aspire.Hosting.Utils; +using CommunityToolkit.Aspire.Testing; namespace CommunityToolkit.Aspire.Hosting.Keycloak.Extensions.Tests; diff --git a/tests/CommunityToolkit.Aspire.Hosting.KurrentDB.Tests/KurrentDBFunctionalTests.cs b/tests/CommunityToolkit.Aspire.Hosting.KurrentDB.Tests/KurrentDBFunctionalTests.cs index 3b1b431f8..b4653823e 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.KurrentDB.Tests/KurrentDBFunctionalTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.KurrentDB.Tests/KurrentDBFunctionalTests.cs @@ -1,12 +1,12 @@ using Aspire.Components.Common.Tests; using Aspire.Hosting; using Aspire.Hosting.Utils; +using CommunityToolkit.Aspire.Testing; using KurrentDB.Client; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Hosting; using System.Text; using System.Text.Json; -using Xunit.Abstractions; namespace CommunityToolkit.Aspire.Hosting.KurrentDB.Tests; diff --git a/tests/CommunityToolkit.Aspire.Hosting.McpInspector.Tests/AppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.McpInspector.Tests/AppHostTests.cs index 3fdb35c32..3b9a88cb2 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.McpInspector.Tests/AppHostTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.McpInspector.Tests/AppHostTests.cs @@ -3,7 +3,7 @@ namespace CommunityToolkit.Aspire.Hosting.McpInspector.Tests; // Forcing linux only due to: https://github.com/modelcontextprotocol/inspector/issues/893 -[RequiresLinux] +[RequiresWindows] public class AppHostTests(AspireIntegrationTestFixture fixture) : IClassFixture> { [Fact] diff --git a/tests/CommunityToolkit.Aspire.Hosting.Meilisearch.Tests/MeilisearchFunctionalTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Meilisearch.Tests/MeilisearchFunctionalTests.cs index 01d4e1d4a..e409ce007 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.Meilisearch.Tests/MeilisearchFunctionalTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.Meilisearch.Tests/MeilisearchFunctionalTests.cs @@ -6,7 +6,6 @@ using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Hosting; using Polly; -using Xunit.Abstractions; using Meilisearch; using Aspire.Hosting.Utils; using CommunityToolkit.Aspire.Testing; diff --git a/tests/CommunityToolkit.Aspire.Hosting.Minio.Tests/MinioFunctionalTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Minio.Tests/MinioFunctionalTests.cs index 1ccdc8641..3a164b54f 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.Minio.Tests/MinioFunctionalTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.Minio.Tests/MinioFunctionalTests.cs @@ -1,10 +1,10 @@ using Aspire.Components.Common.Tests; using Aspire.Hosting; using Aspire.Hosting.Utils; +using CommunityToolkit.Aspire.Testing; using Microsoft.Extensions.Hosting; using Minio; using Minio.DataModel.Args; -using Xunit.Abstractions; namespace CommunityToolkit.Aspire.Hosting.Minio.Tests; diff --git a/tests/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.Tests/ResourceCreationTests.cs b/tests/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.Tests/ResourceCreationTests.cs index b259b6448..5ea684801 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.Tests/ResourceCreationTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.Tests/ResourceCreationTests.cs @@ -1,7 +1,7 @@ using Aspire.Components.Common.Tests; using Aspire.Hosting; using Aspire.Hosting.Utils; -using Xunit.Abstractions; +using CommunityToolkit.Aspire.Testing; namespace CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.Tests; diff --git a/tests/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests/FunctionalTests.cs b/tests/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests/FunctionalTests.cs index ca481bfe2..9409da302 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests/FunctionalTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests/FunctionalTests.cs @@ -1,9 +1,8 @@ -using Aspire.Components.Common.Tests; -using Aspire.Hosting; +using Aspire.Hosting; using Aspire.Hosting.Utils; +using CommunityToolkit.Aspire.Testing; using Microsoft.Data.SqlClient; using Microsoft.Extensions.Diagnostics.HealthChecks; -using Xunit.Abstractions; namespace CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests; diff --git a/tests/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests/SqlServerContainerFixture.cs b/tests/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests/SqlServerContainerFixture.cs index aa7cce6da..9890da7d7 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests/SqlServerContainerFixture.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests/SqlServerContainerFixture.cs @@ -15,9 +15,9 @@ public sealed class SqlServerContainerFixture : IAsyncLifetime public string GetConnectionString() => Container?.GetConnectionString() ?? throw new InvalidOperationException("The test container was not initialized."); - public async Task InitializeAsync() => Container = await CreateContainerAsync(); + public async ValueTask InitializeAsync() => Container = await CreateContainerAsync(); - public async Task DisposeAsync() + public async ValueTask DisposeAsync() { if (Container is not null) await Container.DisposeAsync(); diff --git a/tests/CommunityToolkit.Aspire.Hosting.SurrealDb.Tests/SurrealDbFunctionalTests.cs b/tests/CommunityToolkit.Aspire.Hosting.SurrealDb.Tests/SurrealDbFunctionalTests.cs index 2c3afd26b..4f92c4573 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.SurrealDb.Tests/SurrealDbFunctionalTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.SurrealDb.Tests/SurrealDbFunctionalTests.cs @@ -13,7 +13,6 @@ using SurrealDb.Net; using SurrealDb.Net.Exceptions; using System.Data; -using Xunit.Abstractions; using SurrealRecord = SurrealDb.Net.Models.Record; namespace CommunityToolkit.Aspire.Hosting.SurrealDb.Tests; diff --git a/tests/CommunityToolkit.Aspire.KurrentDB.Tests/AspireKurrentDBClientExtensionsTest.cs b/tests/CommunityToolkit.Aspire.KurrentDB.Tests/AspireKurrentDBClientExtensionsTest.cs index 56509b7d7..94ef94b04 100644 --- a/tests/CommunityToolkit.Aspire.KurrentDB.Tests/AspireKurrentDBClientExtensionsTest.cs +++ b/tests/CommunityToolkit.Aspire.KurrentDB.Tests/AspireKurrentDBClientExtensionsTest.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Components.Common.Tests; +using CommunityToolkit.Aspire.Testing; using KurrentDB.Client; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Diagnostics.HealthChecks; diff --git a/tests/CommunityToolkit.Aspire.KurrentDB.Tests/ConformanceTests.cs b/tests/CommunityToolkit.Aspire.KurrentDB.Tests/ConformanceTests.cs index db9b5d412..144f2940b 100644 --- a/tests/CommunityToolkit.Aspire.KurrentDB.Tests/ConformanceTests.cs +++ b/tests/CommunityToolkit.Aspire.KurrentDB.Tests/ConformanceTests.cs @@ -3,6 +3,7 @@ using Aspire.Components.Common.Tests; using Aspire.Components.ConformanceTests; +using CommunityToolkit.Aspire.Testing; using KurrentDB.Client; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; diff --git a/tests/CommunityToolkit.Aspire.KurrentDB.Tests/KurrentDBContainerFixture.cs b/tests/CommunityToolkit.Aspire.KurrentDB.Tests/KurrentDBContainerFixture.cs index 9dfa41495..8bba0a4b5 100644 --- a/tests/CommunityToolkit.Aspire.KurrentDB.Tests/KurrentDBContainerFixture.cs +++ b/tests/CommunityToolkit.Aspire.KurrentDB.Tests/KurrentDBContainerFixture.cs @@ -3,6 +3,7 @@ using Aspire.Components.Common.Tests; using CommunityToolkit.Aspire.Hosting.KurrentDB; +using CommunityToolkit.Aspire.Testing; using DotNet.Testcontainers.Builders; using DotNet.Testcontainers.Containers; @@ -22,7 +23,7 @@ public string GetConnectionString() return $"{endpoint}?tls=false"; } - public async Task InitializeAsync() + public async ValueTask InitializeAsync() { if (RequiresDockerAttribute.IsSupported) { @@ -39,7 +40,7 @@ public async Task InitializeAsync() } } - public async Task DisposeAsync() + public async ValueTask DisposeAsync() { if (Container is not null) { diff --git a/tests/CommunityToolkit.Aspire.Meilisearch.Tests/AspireMeilisearchClientExtensionsTest.cs b/tests/CommunityToolkit.Aspire.Meilisearch.Tests/AspireMeilisearchClientExtensionsTest.cs index 7048a0e42..add49d2e9 100644 --- a/tests/CommunityToolkit.Aspire.Meilisearch.Tests/AspireMeilisearchClientExtensionsTest.cs +++ b/tests/CommunityToolkit.Aspire.Meilisearch.Tests/AspireMeilisearchClientExtensionsTest.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Components.Common.Tests; +using CommunityToolkit.Aspire.Testing; using Meilisearch; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; diff --git a/tests/CommunityToolkit.Aspire.Meilisearch.Tests/ConformanceTests.cs b/tests/CommunityToolkit.Aspire.Meilisearch.Tests/ConformanceTests.cs index 684d5e764..b25d5cc9b 100644 --- a/tests/CommunityToolkit.Aspire.Meilisearch.Tests/ConformanceTests.cs +++ b/tests/CommunityToolkit.Aspire.Meilisearch.Tests/ConformanceTests.cs @@ -3,6 +3,7 @@ using Aspire.Components.Common.Tests; using Aspire.Components.ConformanceTests; +using CommunityToolkit.Aspire.Testing; using Meilisearch; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; diff --git a/tests/CommunityToolkit.Aspire.Meilisearch.Tests/MeilisearchContainerFixture.cs b/tests/CommunityToolkit.Aspire.Meilisearch.Tests/MeilisearchContainerFixture.cs index e263b9c52..4d7d13ef9 100644 --- a/tests/CommunityToolkit.Aspire.Meilisearch.Tests/MeilisearchContainerFixture.cs +++ b/tests/CommunityToolkit.Aspire.Meilisearch.Tests/MeilisearchContainerFixture.cs @@ -8,6 +8,7 @@ using DotNet.Testcontainers.Containers; using Xunit; using System.Linq.Expressions; +using CommunityToolkit.Aspire.Testing; namespace CommunityToolkit.Aspire.Meilisearch.Tests; @@ -25,7 +26,7 @@ public string GetConnectionString() return $"Endpoint={endpoint};MasterKey={_masterKey}"; } - public async Task InitializeAsync() + public async ValueTask InitializeAsync() { if (RequiresDockerAttribute.IsSupported) { @@ -55,7 +56,7 @@ public async Task InitializeAsync() } } - public async Task DisposeAsync() + public async ValueTask DisposeAsync() { if (Container is not null) { diff --git a/tests/CommunityToolkit.Aspire.Minio.Client.Tests/ConformanceTests.cs b/tests/CommunityToolkit.Aspire.Minio.Client.Tests/ConformanceTests.cs index 5012126fb..442732cf8 100644 --- a/tests/CommunityToolkit.Aspire.Minio.Client.Tests/ConformanceTests.cs +++ b/tests/CommunityToolkit.Aspire.Minio.Client.Tests/ConformanceTests.cs @@ -1,5 +1,6 @@ using Aspire.Components.Common.Tests; using Aspire.Components.ConformanceTests; +using CommunityToolkit.Aspire.Testing; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Minio; diff --git a/tests/CommunityToolkit.Aspire.Minio.Client.Tests/MinioContainerFeature.cs b/tests/CommunityToolkit.Aspire.Minio.Client.Tests/MinioContainerFeature.cs index 3feee2c66..01c92b12a 100644 --- a/tests/CommunityToolkit.Aspire.Minio.Client.Tests/MinioContainerFeature.cs +++ b/tests/CommunityToolkit.Aspire.Minio.Client.Tests/MinioContainerFeature.cs @@ -1,5 +1,6 @@ using Aspire.Components.Common.Tests; using CommunityToolkit.Aspire.Hosting.Minio; +using CommunityToolkit.Aspire.Testing; using DotNet.Testcontainers.Builders; using DotNet.Testcontainers.Containers; @@ -19,7 +20,7 @@ public string GetContainerEndpoint() return endpoint; } - public async Task InitializeAsync() + public async ValueTask InitializeAsync() { if (RequiresDockerAttribute.IsSupported) { @@ -39,7 +40,7 @@ public async Task InitializeAsync() } } - public async Task DisposeAsync() + public async ValueTask DisposeAsync() { if (Container is not null) { diff --git a/tests/CommunityToolkit.Aspire.OllamaSharp.Tests/ConformanceTests.cs b/tests/CommunityToolkit.Aspire.OllamaSharp.Tests/ConformanceTests.cs index f6d784e0c..42229f208 100644 --- a/tests/CommunityToolkit.Aspire.OllamaSharp.Tests/ConformanceTests.cs +++ b/tests/CommunityToolkit.Aspire.OllamaSharp.Tests/ConformanceTests.cs @@ -1,5 +1,6 @@ using Aspire.Components.Common.Tests; using Aspire.Components.ConformanceTests; +using CommunityToolkit.Aspire.Testing; using Microsoft.Extensions.AI; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; diff --git a/tests/CommunityToolkit.Aspire.OllamaSharp.Tests/OllamaContainerFeature.cs b/tests/CommunityToolkit.Aspire.OllamaSharp.Tests/OllamaContainerFeature.cs index 2df093fad..93fe77692 100644 --- a/tests/CommunityToolkit.Aspire.OllamaSharp.Tests/OllamaContainerFeature.cs +++ b/tests/CommunityToolkit.Aspire.OllamaSharp.Tests/OllamaContainerFeature.cs @@ -1,5 +1,6 @@ using Aspire.Components.Common.Tests; using CommunityToolkit.Aspire.Hosting.Ollama; +using CommunityToolkit.Aspire.Testing; using DotNet.Testcontainers.Builders; using DotNet.Testcontainers.Containers; @@ -18,7 +19,7 @@ public string GetContainerEndpoint() return endpoint; } - public async Task InitializeAsync() + public async ValueTask InitializeAsync() { if (RequiresDockerAttribute.IsSupported) { @@ -32,7 +33,7 @@ public async Task InitializeAsync() } } - public async Task DisposeAsync() + public async ValueTask DisposeAsync() { if (Container is not null) { diff --git a/tests/CommunityToolkit.Aspire.RavenDB.Client.Tests/RavenDbServerFixture.cs b/tests/CommunityToolkit.Aspire.RavenDB.Client.Tests/RavenDbServerFixture.cs index 2df45c921..0e9dda06d 100644 --- a/tests/CommunityToolkit.Aspire.RavenDB.Client.Tests/RavenDbServerFixture.cs +++ b/tests/CommunityToolkit.Aspire.RavenDB.Client.Tests/RavenDbServerFixture.cs @@ -9,7 +9,7 @@ public sealed class RavenDbServerFixture : IAsyncLifetime, IDisposable public IDocumentStore? Store { get; private set; } public string? ConnectionString { get; private set; } - public async Task InitializeAsync() + public async ValueTask InitializeAsync() { Server.StartServer(); @@ -28,10 +28,10 @@ public void CreateDatabase(DatabaseOptions options) Store = Server.GetDocumentStore(options); } - public Task DisposeAsync() + public ValueTask DisposeAsync() { Dispose(); - return Task.CompletedTask; + return ValueTask.CompletedTask; } public void Dispose() diff --git a/tests/CommunityToolkit.Aspire.SurrealDb.Tests/AspireSurrealClientExtensionsTest.cs b/tests/CommunityToolkit.Aspire.SurrealDb.Tests/AspireSurrealClientExtensionsTest.cs index 20ab869b0..bbb8c6e2c 100644 --- a/tests/CommunityToolkit.Aspire.SurrealDb.Tests/AspireSurrealClientExtensionsTest.cs +++ b/tests/CommunityToolkit.Aspire.SurrealDb.Tests/AspireSurrealClientExtensionsTest.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Components.Common.Tests; +using CommunityToolkit.Aspire.Testing; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Hosting; diff --git a/tests/CommunityToolkit.Aspire.SurrealDb.Tests/ConformanceTests.cs b/tests/CommunityToolkit.Aspire.SurrealDb.Tests/ConformanceTests.cs index c0d49f471..69ad1c2e7 100644 --- a/tests/CommunityToolkit.Aspire.SurrealDb.Tests/ConformanceTests.cs +++ b/tests/CommunityToolkit.Aspire.SurrealDb.Tests/ConformanceTests.cs @@ -3,18 +3,19 @@ using Aspire.Components.Common.Tests; using Aspire.Components.ConformanceTests; +using CommunityToolkit.Aspire.Testing; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using SurrealDb.Net; namespace CommunityToolkit.Aspire.SurrealDb.Tests; -public class ConformanceTests : - ConformanceTests, +public class ConformanceTests : + ConformanceTests, IClassFixture { private readonly SurrealDbContainerFixture _containerFixture; - + protected override ServiceLifetime ServiceLifetime => ServiceLifetime.Singleton; protected override string ActivitySourceName => string.Empty; @@ -101,6 +102,6 @@ protected override void TriggerActivity(SurrealDbClient service) { using var source = new CancellationTokenSource(100); - service.Version(source.Token).Wait(); + Task.Run(() => service.Connect()); } } \ No newline at end of file diff --git a/tests/CommunityToolkit.Aspire.SurrealDb.Tests/SurrealDbContainerFixture.cs b/tests/CommunityToolkit.Aspire.SurrealDb.Tests/SurrealDbContainerFixture.cs index 560d17e75..9be69e084 100644 --- a/tests/CommunityToolkit.Aspire.SurrealDb.Tests/SurrealDbContainerFixture.cs +++ b/tests/CommunityToolkit.Aspire.SurrealDb.Tests/SurrealDbContainerFixture.cs @@ -4,6 +4,7 @@ using Aspire.Components.Common.Tests; using Aspire.Hosting; using Aspire.Hosting.Utils; +using CommunityToolkit.Aspire.Testing; using DotNet.Testcontainers.Builders; using DotNet.Testcontainers.Containers; @@ -28,7 +29,7 @@ public string GetConnectionString() return $"Endpoint={endpoint};Username={_username};Password={_password}"; } - public async Task InitializeAsync() + public async ValueTask InitializeAsync() { if (RequiresDockerAttribute.IsSupported) { @@ -60,7 +61,7 @@ public async Task InitializeAsync() } } - public async Task DisposeAsync() + public async ValueTask DisposeAsync() { if (Container is not null) { diff --git a/tests/CommunityToolkit.Aspire.Testing/AspireIntegrationTest.cs b/tests/CommunityToolkit.Aspire.Testing/AspireIntegrationTest.cs index 823ab73c0..29f3ab61b 100644 --- a/tests/CommunityToolkit.Aspire.Testing/AspireIntegrationTest.cs +++ b/tests/CommunityToolkit.Aspire.Testing/AspireIntegrationTest.cs @@ -71,7 +71,5 @@ public async override ValueTask DisposeAsync() } } - public Task InitializeAsync() => StartAsync().WaitAsync(TimeSpan.FromMinutes(10)); - - async Task IAsyncLifetime.DisposeAsync() => await DisposeAsync(); + public async ValueTask InitializeAsync() => await StartAsync().WaitAsync(TimeSpan.FromMinutes(10)); } \ No newline at end of file diff --git a/tests/CommunityToolkit.Aspire.Testing/CommunityToolkit.Aspire.Testing.csproj b/tests/CommunityToolkit.Aspire.Testing/CommunityToolkit.Aspire.Testing.csproj index e19371f19..78e05e644 100644 --- a/tests/CommunityToolkit.Aspire.Testing/CommunityToolkit.Aspire.Testing.csproj +++ b/tests/CommunityToolkit.Aspire.Testing/CommunityToolkit.Aspire.Testing.csproj @@ -13,19 +13,13 @@ - - - + + + diff --git a/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs b/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs index ec0c5ca6b..3e27b2495 100644 --- a/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs +++ b/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs @@ -3,9 +3,7 @@ using System.Diagnostics; using System.Text.Json.Nodes; -using Microsoft.DotNet.XUnitExtensions; using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; @@ -13,6 +11,7 @@ using OpenTelemetry.Metrics; using OpenTelemetry.Trace; using Xunit; +using Aspire.Components.Common.Tests; namespace Aspire.Components.ConformanceTests; @@ -45,6 +44,8 @@ public abstract class ConformanceTests protected virtual bool SupportsKeyedRegistrations => false; + protected virtual bool IsComponentBuiltBeforeHost => false; + protected bool MetricsAreSupported => CheckIfImplemented(SetMetrics); // every Component has to support health checks, this property is a temporary workaround @@ -54,6 +55,8 @@ protected virtual void DisableRetries(TOptions options) { } protected bool TracingIsSupported => CheckIfImplemented(SetTracing); + protected virtual bool CheckOptionClassSealed => true; + /// /// Calls the actual Component /// @@ -85,20 +88,26 @@ protected virtual void DisableRetries(TOptions options) { } /// protected abstract void SetMetrics(TOptions options, bool enabled); - [ConditionalFact] + [Fact] public void OptionsTypeIsSealed() { if (typeof(TOptions) == typeof(object)) { - throw new SkipTestException("Not implemented yet"); + Assert.Skip("Not implemented yet"); + } + + if (!CheckOptionClassSealed) + { + Assert.Skip("Opt-out of test"); } Assert.True(typeof(TOptions).IsSealed); } - [ConditionalTheory] + [Theory] [InlineData(true)] [InlineData(false)] + [ActiveIssue("https://github.com/dotnet/aspire/issues/11820", typeof(PlatformDetection), nameof(PlatformDetection.IsRunningFromAzdo))] public void HealthChecksRegistersHealthCheckService(bool enabled) { SkipIfHealthChecksAreNotSupported(); @@ -110,7 +119,7 @@ public void HealthChecksRegistersHealthCheckService(bool enabled) Assert.Equal(enabled, healthCheckService is not null); } - [ConditionalFact] + [Fact] public async Task EachKeyedComponentRegistersItsOwnHealthCheck() { SkipIfHealthChecksAreNotSupported(); @@ -124,18 +133,21 @@ public async Task EachKeyedComponentRegistersItsOwnHealthCheck() List registeredNames = new(); await healthCheckService.CheckHealthAsync(healthCheckRegistration => +#pragma warning disable xUnit1030 // Do not call ConfigureAwait(false) in test method { registeredNames.Add(healthCheckRegistration.Name); return false; }).ConfigureAwait(false); +#pragma warning restore xUnit1030 // Do not call ConfigureAwait(false) in test method Assert.Equal(2, registeredNames.Count); Assert.All(registeredNames, name => Assert.True(name.Contains(key1) || name.Contains(key2), $"{name} did not contain the key.")); } - [ConditionalTheory] + [Theory] [InlineData(true)] [InlineData(false)] + [ActiveIssue("https://github.com/dotnet/aspire/issues/11820", typeof(PlatformDetection), nameof(PlatformDetection.IsRunningFromAzdo))] public void TracingRegistersTraceProvider(bool enabled) { SkipIfTracingIsNotSupported(); @@ -148,9 +160,10 @@ public void TracingRegistersTraceProvider(bool enabled) Assert.Equal(enabled, tracer is not null); } - [ConditionalTheory] + [Theory] [InlineData(true)] [InlineData(false)] + [ActiveIssue("https://github.com/dotnet/aspire/issues/11820", typeof(PlatformDetection), nameof(PlatformDetection.IsRunningFromAzdo))] public void MetricsRegistersMeterProvider(bool enabled) { SkipIfMetricsAreNotSupported(); @@ -162,9 +175,10 @@ public void MetricsRegistersMeterProvider(bool enabled) Assert.Equal(enabled, meter is not null); } - [ConditionalTheory] + [Theory] [InlineData(true)] [InlineData(false)] + [ActiveIssue("https://github.com/dotnet/aspire/issues/11820", typeof(PlatformDetection), nameof(PlatformDetection.IsRunningFromAzdo))] public void ServiceLifetimeIsAsExpected(bool useKey) { SkipIfRequiredServerConnectionCanNotBeEstablished(); @@ -213,7 +227,7 @@ public void ServiceLifetimeIsAsExpected(bool useKey) : serviceProvider.GetKeyedService(key); } - [ConditionalFact] + [Fact] public void CanRegisterMultipleInstancesUsingDifferentKeys() { SkipIfKeyedRegistrationIsNotSupported(); @@ -229,7 +243,7 @@ public void CanRegisterMultipleInstancesUsingDifferentKeys() Assert.NotSame(serviceForKey1, serviceForKey2); } - [ConditionalFact] + [Fact] public void WhenKeyedRegistrationIsUsedThenItsImpossibleToResolveWithoutKey() { SkipIfKeyedRegistrationIsNotSupported(); @@ -249,11 +263,12 @@ public void WhenKeyedRegistrationIsUsedThenItsImpossibleToResolveWithoutKey() Assert.Throws(host.Services.GetRequiredService); } - [ConditionalTheory] + [Theory] [InlineData(true, true)] [InlineData(true, false)] [InlineData(false, true)] [InlineData(false, false)] + [ActiveIssue("https://github.com/dotnet/aspire/issues/11820", typeof(PlatformDetection), nameof(PlatformDetection.IsRunningFromAzdo))] public void LoggerFactoryIsUsedByRegisteredClient(bool registerAfterLoggerFactory, bool useKey) { SkipIfRequiredServerConnectionCanNotBeEstablished(); @@ -298,28 +313,29 @@ public void LoggerFactoryIsUsedByRegisteredClient(bool registerAfterLoggerFactor } } - [ConditionalTheory] + [Theory] [InlineData(null)] [InlineData("key")] - public async Task HealthCheckReportsExpectedStatus(string? key) + [ActiveIssue("https://github.com/dotnet/aspire/issues/11820", typeof(PlatformDetection), nameof(PlatformDetection.IsRunningFromAzdo))] + public virtual async Task HealthCheckReportsExpectedStatus(string? key) { SkipIfHealthChecksAreNotSupported(); // DisableRetries so the test doesn't take so long retrying when the server isn't available. using IHost host = CreateHostWithComponent(configureComponent: DisableRetries, key: key); - HealthCheckService healthCheckService = host.Services.GetRequiredService(); + var healthCheckService = host.Services.GetRequiredService(); - HealthReport healthReport = await healthCheckService.CheckHealthAsync().ConfigureAwait(false); + var healthReport = await healthCheckService.CheckHealthAsync(); - HealthStatus expected = CanConnectToServer ? HealthStatus.Healthy : HealthStatus.Unhealthy; + var expected = CanConnectToServer ? HealthStatus.Healthy : HealthStatus.Unhealthy; Assert.Equal(expected, healthReport.Status); Assert.NotEmpty(healthReport.Entries); Assert.Contains(healthReport.Entries, entry => entry.Value.Status == expected); } - [Fact(Skip = "https://github.com/CommunityToolkit/Aspire/issues/112")] + [Fact] public void ConfigurationSchemaValidJsonConfigTest() { var schema = JsonSchema.FromFile(JsonSchemaPath); @@ -330,7 +346,7 @@ public void ConfigurationSchemaValidJsonConfigTest() Assert.True(results.IsValid); } - [Fact(Skip = "https://github.com/CommunityToolkit/Aspire/issues/112")] + [Fact] public void ConfigurationSchemaInvalidJsonConfigTest() { var schema = JsonSchema.FromFile(JsonSchemaPath); @@ -350,13 +366,15 @@ public void ConfigurationSchemaInvalidJsonConfigTest() /// Ensures that when the connection information is missing, an exception isn't thrown before the host /// is built, so any exception can be logged with ILogger. /// - [ConditionalTheory] + [Theory] [InlineData(true)] [InlineData(false)] + [ActiveIssue("https://github.com/dotnet/aspire/issues/11820", typeof(PlatformDetection), nameof(PlatformDetection.IsRunningFromAzdo))] public void ConnectionInformationIsDelayValidated(bool useKey) { + SkipIfComponentIsBuiltBeforeHost(); + SetupConnectionInformationIsDelayValidated(); - SkipIfKeyedRegistrationIsNotSupported(useKey); var builder = Host.CreateEmptyApplicationBuilder(null); @@ -371,7 +389,7 @@ key is null : host.Services.GetRequiredKeyedService(key)); } - [ConditionalFact] + [Fact] public void FavorsNamedConfigurationOverTopLevelConfigurationWhenBothProvided_DisableTracing() { SkipIfNamedConfigNotSupported(); @@ -393,7 +411,7 @@ public void FavorsNamedConfigurationOverTopLevelConfigurationWhenBothProvided_Di Assert.Null(host.Services.GetService()); } - [ConditionalFact] + [Fact] public void FavorsNamedConfigurationOverTopLevelConfigurationWhenBothProvided_DisableHealthChecks() { SkipIfNamedConfigNotSupported(); @@ -481,7 +499,7 @@ protected void SkipIfHealthChecksAreNotSupported() { if (!HealthChecksAreSupported) { - throw new SkipTestException("Health checks aren't supported."); + Assert.Skip("Health checks aren't supported."); } } @@ -489,7 +507,7 @@ protected void SkipIfKeyedRegistrationIsNotSupported(bool useKey = true) { if (useKey && !SupportsKeyedRegistrations) { - throw new SkipTestException("Does not support Keyed Services"); + Assert.Skip("Does not support Keyed Services"); } } @@ -497,7 +515,7 @@ protected void SkipIfTracingIsNotSupported() { if (!TracingIsSupported) { - throw new SkipTestException("Tracing is not supported."); + Assert.Skip("Tracing is not supported."); } } @@ -505,7 +523,7 @@ protected void SkipIfMetricsAreNotSupported() { if (!MetricsAreSupported) { - throw new SkipTestException("Metrics are not supported."); + Assert.Skip("Metrics are not supported."); } } @@ -513,7 +531,7 @@ protected void SkipIfRequiredServerConnectionCanNotBeEstablished() { if (!CanCreateClientWithoutConnectingToServer && !CanConnectToServer) { - throw new SkipTestException("Unable to connect to the server."); + Assert.Skip("Unable to connect to the server."); } } @@ -521,7 +539,7 @@ protected void SkipIfCanNotConnectToServer() { if (!CanConnectToServer) { - throw new SkipTestException("Unable to connect to the server."); + Assert.Skip("Unable to connect to the server."); } } @@ -529,13 +547,21 @@ protected void SkipIfNamedConfigNotSupported() { if (!SupportsNamedConfig || ConfigurationSectionName is null) { - throw new SkipTestException("Named configuration is not supported."); + Assert.Skip("Named configuration is not supported."); } } public static string CreateConfigKey(string prefix, string? key, string suffix) => string.IsNullOrEmpty(key) ? $"{prefix}:{suffix}" : $"{prefix}:{key}:{suffix}"; + protected void SkipIfComponentIsBuiltBeforeHost() + { + if (IsComponentBuiltBeforeHost) + { + Assert.Skip("Component is built before host."); + } + } + protected HostApplicationBuilder CreateHostBuilder(HostApplicationBuilderSettings? hostSettings = null, string? key = null) { HostApplicationBuilder builder = Host.CreateEmptyApplicationBuilder(hostSettings); diff --git a/tests/CommunityToolkit.Aspire.Testing/DistributedApplicationTestingBuilderExtensions.cs b/tests/CommunityToolkit.Aspire.Testing/DistributedApplicationTestingBuilderExtensions.cs index 1b7d0bb5c..c7d12af9d 100644 --- a/tests/CommunityToolkit.Aspire.Testing/DistributedApplicationTestingBuilderExtensions.cs +++ b/tests/CommunityToolkit.Aspire.Testing/DistributedApplicationTestingBuilderExtensions.cs @@ -5,7 +5,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Xunit; -using Xunit.Abstractions; namespace Aspire.Hosting.Utils; diff --git a/tests/CommunityToolkit.Aspire.Testing/PlatformDetection.cs b/tests/CommunityToolkit.Aspire.Testing/PlatformDetection.cs index 9f29acb39..05a371a4c 100644 --- a/tests/CommunityToolkit.Aspire.Testing/PlatformDetection.cs +++ b/tests/CommunityToolkit.Aspire.Testing/PlatformDetection.cs @@ -2,5 +2,14 @@ namespace Aspire.Components.Common.Tests; public static class PlatformDetection { - public static bool IsRunningOnCI => Environment.GetEnvironmentVariable("CI") is not null; -} \ No newline at end of file + public static bool IsRunningOnAzdoBuildMachine => Environment.GetEnvironmentVariable("BUILD_BUILDID") is not null; + public static bool IsRunningOnHelix => Environment.GetEnvironmentVariable("HELIX_WORKITEM_ROOT") is not null; + public static bool IsRunningOnGithubActions => Environment.GetEnvironmentVariable("GITHUB_JOB") is not null; + public static bool IsRunningOnCI => IsRunningOnAzdoBuildMachine || IsRunningOnHelix || IsRunningOnGithubActions; + public static bool IsRunningFromAzdo => IsRunningOnAzdoBuildMachine || IsRunningOnHelix; + public static bool IsRunningPRValidation => IsRunningOnGithubActions; + + public static bool IsWindows => OperatingSystem.IsWindows(); + public static bool IsLinux => OperatingSystem.IsLinux(); + public static bool IsMacOS => OperatingSystem.IsMacOS(); +} diff --git a/tests/CommunityToolkit.Aspire.Testing/RequiresDockerAttribute.cs b/tests/CommunityToolkit.Aspire.Testing/RequiresDockerAttribute.cs index cbb20ed11..fbecc0bd1 100644 --- a/tests/CommunityToolkit.Aspire.Testing/RequiresDockerAttribute.cs +++ b/tests/CommunityToolkit.Aspire.Testing/RequiresDockerAttribute.cs @@ -1,13 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// Copied from: https://github.com/dotnet/aspire/blob/d31331d6132aeb22940dcd8834344956ba811373/tests/Aspire.Components.Common.Tests/RequiresDockerAttribute.cs +using Aspire.Components.Common.Tests; +using Microsoft.DotNet.XUnitExtensions; +using Xunit.v3; -using Xunit.Sdk; +namespace CommunityToolkit.Aspire.Testing; -namespace Aspire.Components.Common.Tests; - -[TraitDiscoverer("Aspire.Components.Common.Tests.RequiresDockerDiscoverer", "CommunityToolkit.Aspire.Testing")] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] public class RequiresDockerAttribute : Attribute, ITraitAttribute { @@ -23,12 +22,21 @@ public class RequiresDockerAttribute : Attribute, ITraitAttribute // - https://github.com/dotnet/aspire/issues/4291 // - Linux - Local, or CI: always assume that docker is installed public static bool IsSupported => - !OperatingSystem.IsWindows() || - !PlatformDetection.IsRunningOnCI; + OperatingSystem.IsLinux() || !PlatformDetection.IsRunningOnCI; // non-linux on CI does not support docker public string? Reason { get; init; } public RequiresDockerAttribute(string? reason = null) { Reason = reason; } -} + + public IReadOnlyCollection> GetTraits() + { + if (!IsSupported) + { + return [new KeyValuePair(XunitConstants.Category, "failing")]; + } + + return []; + } +} \ No newline at end of file diff --git a/tests/CommunityToolkit.Aspire.Testing/RequiresDockerDiscoverer.cs b/tests/CommunityToolkit.Aspire.Testing/RequiresDockerDiscoverer.cs deleted file mode 100644 index 64ef21d97..000000000 --- a/tests/CommunityToolkit.Aspire.Testing/RequiresDockerDiscoverer.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// Copied from: https://github.com/dotnet/aspire/blob/d31331d6132aeb22940dcd8834344956ba811373/tests/Aspire.Components.Common.Tests/RequiresDockerDiscoverer.cs - -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Aspire.Components.Common.Tests; - -public class RequiresDockerDiscoverer : ITraitDiscoverer -{ - public IEnumerable> GetTraits(IAttributeInfo traitAttribute) - { - if (!RequiresDockerAttribute.IsSupported) - { - yield return new KeyValuePair("category", "unsupported-platform"); - } - } -} \ No newline at end of file diff --git a/tests/CommunityToolkit.Aspire.Testing/RequiresLinuxAttribute.cs b/tests/CommunityToolkit.Aspire.Testing/RequiresLinuxAttribute.cs index a8c53fdc9..1fca3a5d6 100644 --- a/tests/CommunityToolkit.Aspire.Testing/RequiresLinuxAttribute.cs +++ b/tests/CommunityToolkit.Aspire.Testing/RequiresLinuxAttribute.cs @@ -1,4 +1,5 @@ -using Xunit.Sdk; +using Microsoft.DotNet.XUnitExtensions; +using Xunit.v3; namespace CommunityToolkit.Aspire.Testing; @@ -6,7 +7,6 @@ namespace CommunityToolkit.Aspire.Testing; /// Marks a test or test class as requiring a Linux operating system. /// Adds a trait so tests can be skipped or filtered when not running on Linux. /// -[TraitDiscoverer("CommunityToolkit.Aspire.Testing.RequiresLinuxDiscoverer", "CommunityToolkit.Aspire.Testing")] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] public class RequiresLinuxAttribute(string? reason = null) : Attribute, ITraitAttribute { @@ -15,4 +15,14 @@ public class RequiresLinuxAttribute(string? reason = null) : Attribute, ITraitAt /// Gets a value indicating whether the current OS is Linux. public static bool IsSupported => OperatingSystem.IsLinux(); + + public IReadOnlyCollection> GetTraits() + { + if (!IsSupported) + { + return [new KeyValuePair(XunitConstants.Category, "failing")]; + } + + return []; + } } diff --git a/tests/CommunityToolkit.Aspire.Testing/RequiresLinuxDiscoverer.cs b/tests/CommunityToolkit.Aspire.Testing/RequiresLinuxDiscoverer.cs deleted file mode 100644 index a252d5776..000000000 --- a/tests/CommunityToolkit.Aspire.Testing/RequiresLinuxDiscoverer.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace CommunityToolkit.Aspire.Testing; - -/// -/// Discovers traits for . -/// Adds a category trait of unsupported-platform when not running on Linux. -/// -public class RequiresLinuxDiscoverer : ITraitDiscoverer -{ - /// - public IEnumerable> GetTraits(IAttributeInfo traitAttribute) - { - if (!RequiresLinuxAttribute.IsSupported) - { - yield return new KeyValuePair("category", "unsupported-platform"); - } - } -} diff --git a/tests/CommunityToolkit.Aspire.Testing/RequiresWindowsAttribute.cs b/tests/CommunityToolkit.Aspire.Testing/RequiresWindowsAttribute.cs index 16414031c..860299cc9 100644 --- a/tests/CommunityToolkit.Aspire.Testing/RequiresWindowsAttribute.cs +++ b/tests/CommunityToolkit.Aspire.Testing/RequiresWindowsAttribute.cs @@ -1,12 +1,28 @@ -using Xunit.Sdk; +using Microsoft.DotNet.XUnitExtensions; +using Xunit.v3; namespace CommunityToolkit.Aspire.Testing; -[TraitDiscoverer("CommunityToolkit.Aspire.Testing.RequiresWindowsDiscoverer", "CommunityToolkit.Aspire.Testing")] +/// +/// Marks a test or test class as requiring a Linux operating system. +/// Adds a trait so tests can be skipped or filtered when not running on Linux. +/// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] public class RequiresWindowsAttribute(string? reason = null) : Attribute, ITraitAttribute { + /// Gets the optional reason why Windows is required. public string? Reason { get; init; } = reason; + /// Gets a value indicating whether the current OS is Windows. public static bool IsSupported => OperatingSystem.IsWindows(); + + public IReadOnlyCollection> GetTraits() + { + if (!IsSupported) + { + return [new KeyValuePair(XunitConstants.Category, "failing")]; + } + + return []; + } } diff --git a/tests/CommunityToolkit.Aspire.Testing/RequiresWindowsDiscoverer.cs b/tests/CommunityToolkit.Aspire.Testing/RequiresWindowsDiscoverer.cs deleted file mode 100644 index ae20e801b..000000000 --- a/tests/CommunityToolkit.Aspire.Testing/RequiresWindowsDiscoverer.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace CommunityToolkit.Aspire.Testing; - -public class RequiresWindowsDiscoverer : ITraitDiscoverer -{ - public IEnumerable> GetTraits(IAttributeInfo traitAttribute) - { - if (!RequiresWindowsAttribute.IsSupported) - { - yield return new KeyValuePair("category", "unsupported-platform"); - } - } -} \ No newline at end of file diff --git a/tests/CommunityToolkit.Aspire.Testing/TestDistributedApplicationBuilder.cs b/tests/CommunityToolkit.Aspire.Testing/TestDistributedApplicationBuilder.cs index aba9b5855..12b6fc6dd 100644 --- a/tests/CommunityToolkit.Aspire.Testing/TestDistributedApplicationBuilder.cs +++ b/tests/CommunityToolkit.Aspire.Testing/TestDistributedApplicationBuilder.cs @@ -3,7 +3,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Components.Common.TestUtilities; -using Xunit.Abstractions; namespace Aspire.Hosting.Utils; diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index 69221f9d8..3d38a4360 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -3,14 +3,19 @@ $(DefaultTargetFramework) + + + + + $(NoWarn);xUnit1051 - + - + From 1ac2ad3c7ebc37c01868f10f9e9a946ed462afe9 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 10 Nov 2025 05:19:03 +0000 Subject: [PATCH 13/41] Disabling JSON schema tests as we don't generate those files --- tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs b/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs index 3e27b2495..971471b42 100644 --- a/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs +++ b/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs @@ -335,7 +335,7 @@ public virtual async Task HealthCheckReportsExpectedStatus(string? key) Assert.Contains(healthReport.Entries, entry => entry.Value.Status == expected); } - [Fact] + [Fact(Skip = "https://github.com/CommunityToolkit/Aspire/issues/112")] public void ConfigurationSchemaValidJsonConfigTest() { var schema = JsonSchema.FromFile(JsonSchemaPath); @@ -346,7 +346,7 @@ public void ConfigurationSchemaValidJsonConfigTest() Assert.True(results.IsValid); } - [Fact] + [Fact(Skip = "https://github.com/CommunityToolkit/Aspire/issues/112")] public void ConfigurationSchemaInvalidJsonConfigTest() { var schema = JsonSchema.FromFile(JsonSchemaPath); From 5840c2e8e2f5def719c346f6fc20099661d8f62b Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 10 Nov 2025 05:29:59 +0000 Subject: [PATCH 14/41] Some adjustments to not be so aspire configured --- tests/CommunityToolkit.Aspire.Testing/PlatformDetection.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/CommunityToolkit.Aspire.Testing/PlatformDetection.cs b/tests/CommunityToolkit.Aspire.Testing/PlatformDetection.cs index 05a371a4c..b342739ec 100644 --- a/tests/CommunityToolkit.Aspire.Testing/PlatformDetection.cs +++ b/tests/CommunityToolkit.Aspire.Testing/PlatformDetection.cs @@ -2,12 +2,8 @@ namespace Aspire.Components.Common.Tests; public static class PlatformDetection { - public static bool IsRunningOnAzdoBuildMachine => Environment.GetEnvironmentVariable("BUILD_BUILDID") is not null; - public static bool IsRunningOnHelix => Environment.GetEnvironmentVariable("HELIX_WORKITEM_ROOT") is not null; public static bool IsRunningOnGithubActions => Environment.GetEnvironmentVariable("GITHUB_JOB") is not null; - public static bool IsRunningOnCI => IsRunningOnAzdoBuildMachine || IsRunningOnHelix || IsRunningOnGithubActions; - public static bool IsRunningFromAzdo => IsRunningOnAzdoBuildMachine || IsRunningOnHelix; - public static bool IsRunningPRValidation => IsRunningOnGithubActions; + public static bool IsRunningOnCI => IsRunningOnGithubActions || Environment.GetEnvironmentVariable("CI") is not null; public static bool IsWindows => OperatingSystem.IsWindows(); public static bool IsLinux => OperatingSystem.IsLinux(); From dcfbd732b99cc4a3bc906852320d704cf5602302 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 10 Nov 2025 05:33:08 +0000 Subject: [PATCH 15/41] Oh, some of that was used --- tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs b/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs index 971471b42..2b47c8042 100644 --- a/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs +++ b/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs @@ -107,7 +107,6 @@ public void OptionsTypeIsSealed() [Theory] [InlineData(true)] [InlineData(false)] - [ActiveIssue("https://github.com/dotnet/aspire/issues/11820", typeof(PlatformDetection), nameof(PlatformDetection.IsRunningFromAzdo))] public void HealthChecksRegistersHealthCheckService(bool enabled) { SkipIfHealthChecksAreNotSupported(); @@ -147,7 +146,6 @@ await healthCheckService.CheckHealthAsync(healthCheckRegistration => [Theory] [InlineData(true)] [InlineData(false)] - [ActiveIssue("https://github.com/dotnet/aspire/issues/11820", typeof(PlatformDetection), nameof(PlatformDetection.IsRunningFromAzdo))] public void TracingRegistersTraceProvider(bool enabled) { SkipIfTracingIsNotSupported(); @@ -163,7 +161,6 @@ public void TracingRegistersTraceProvider(bool enabled) [Theory] [InlineData(true)] [InlineData(false)] - [ActiveIssue("https://github.com/dotnet/aspire/issues/11820", typeof(PlatformDetection), nameof(PlatformDetection.IsRunningFromAzdo))] public void MetricsRegistersMeterProvider(bool enabled) { SkipIfMetricsAreNotSupported(); @@ -178,7 +175,6 @@ public void MetricsRegistersMeterProvider(bool enabled) [Theory] [InlineData(true)] [InlineData(false)] - [ActiveIssue("https://github.com/dotnet/aspire/issues/11820", typeof(PlatformDetection), nameof(PlatformDetection.IsRunningFromAzdo))] public void ServiceLifetimeIsAsExpected(bool useKey) { SkipIfRequiredServerConnectionCanNotBeEstablished(); @@ -268,7 +264,6 @@ public void WhenKeyedRegistrationIsUsedThenItsImpossibleToResolveWithoutKey() [InlineData(true, false)] [InlineData(false, true)] [InlineData(false, false)] - [ActiveIssue("https://github.com/dotnet/aspire/issues/11820", typeof(PlatformDetection), nameof(PlatformDetection.IsRunningFromAzdo))] public void LoggerFactoryIsUsedByRegisteredClient(bool registerAfterLoggerFactory, bool useKey) { SkipIfRequiredServerConnectionCanNotBeEstablished(); @@ -316,7 +311,6 @@ public void LoggerFactoryIsUsedByRegisteredClient(bool registerAfterLoggerFactor [Theory] [InlineData(null)] [InlineData("key")] - [ActiveIssue("https://github.com/dotnet/aspire/issues/11820", typeof(PlatformDetection), nameof(PlatformDetection.IsRunningFromAzdo))] public virtual async Task HealthCheckReportsExpectedStatus(string? key) { SkipIfHealthChecksAreNotSupported(); @@ -369,7 +363,6 @@ public void ConfigurationSchemaInvalidJsonConfigTest() [Theory] [InlineData(true)] [InlineData(false)] - [ActiveIssue("https://github.com/dotnet/aspire/issues/11820", typeof(PlatformDetection), nameof(PlatformDetection.IsRunningFromAzdo))] public void ConnectionInformationIsDelayValidated(bool useKey) { SkipIfComponentIsBuiltBeforeHost(); From 102aaabb0b889862f08ec79089ac111a6665865f Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 10 Nov 2025 05:54:09 +0000 Subject: [PATCH 16/41] Adding filter for failing tests to be skipped --- .../RequiresDockerAttribute.cs | 2 +- tests/Directory.Build.props | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/CommunityToolkit.Aspire.Testing/RequiresDockerAttribute.cs b/tests/CommunityToolkit.Aspire.Testing/RequiresDockerAttribute.cs index fbecc0bd1..2aa29dfaa 100644 --- a/tests/CommunityToolkit.Aspire.Testing/RequiresDockerAttribute.cs +++ b/tests/CommunityToolkit.Aspire.Testing/RequiresDockerAttribute.cs @@ -32,7 +32,7 @@ public RequiresDockerAttribute(string? reason = null) public IReadOnlyCollection> GetTraits() { - if (!IsSupported) + if (IsSupported) { return [new KeyValuePair(XunitConstants.Category, "failing")]; } diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index 3d38a4360..b8d5f25d6 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -34,4 +34,11 @@ $(MSBuildThisFileDirectory).runsettings + + $(TestRunnerAdditionalArguments) --filter-not-trait "category=failing" + + $(TestRunnerAdditionalArguments) --ignore-exit-code 8 + + \ No newline at end of file From 733964bf9384d0adf677d77147d174833798f0c2 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 10 Nov 2025 22:28:43 +0000 Subject: [PATCH 17/41] using dotnet to run tests rather than dotnet test --- .github/workflows/tests.yaml | 9 ++++++--- tests/.runsettings | 2 +- .../RequiresDockerAttribute.cs | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index e1f125e93..42ce57535 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -8,7 +8,7 @@ jobs: env: DOTNET_CONFIGURATION: Release DAPR_VERSION: "1.15.0" - TEST_PROJECT_PATH: tests/CommunityToolkit.Aspire.${{ matrix.name }}/CommunityToolkit.Aspire.${{ matrix.name }}.csproj + TEST_PROJECT_PATH: tests/CommunityToolkit.Aspire.${{ matrix.name }}/CommunityToolkit.Aspire.${{ matrix.name }} CI: true NPM_CONFIG_PACKAGE_LOCK: false runs-on: "${{ matrix.os }}" @@ -92,11 +92,11 @@ jobs: env: CI: false run: | - dotnet build ${{ github.workspace }}/${{ env.TEST_PROJECT_PATH }} /bl --configuration ${{ env.DOTNET_CONFIGURATION }} + dotnet build ${{ github.workspace }}/${{ env.TEST_PROJECT_PATH }} /bl --configuration ${{ env.DOTNET_CONFIGURATION }} -o ${{ github.workspace }}/artifacts/${{ matrix.name }} - name: Run tests run: >- - dotnet test ${{ github.workspace }}/${{ env.TEST_PROJECT_PATH }} + dotnet ${{ github.workspace }}/artifacts/${{ matrix.name }}/CommunityToolkit.Aspire.${{ matrix.name }}.dll --configuration ${{ env.DOTNET_CONFIGURATION }} --logger "console;verbosity=normal" --logger "trx" @@ -108,6 +108,9 @@ jobs: --collect "XPlat Code Coverage" --no-restore --no-build -- RunConfiguration.CollectSourceInformation=true + --filter-not-trait "category=failing" + --report-trx --report-trx-filename "${{ matrix.name }}-${{ matrix.os }}.trx" + --ignore-exit-code 8 env: CUSTOM_CONTAINER_REGISTRY: ${{ secrets.CUSTOM_CONTAINER_REGISTRY }} diff --git a/tests/.runsettings b/tests/.runsettings index 1ce761b64..edd22a9eb 100644 --- a/tests/.runsettings +++ b/tests/.runsettings @@ -2,6 +2,6 @@ - category!=unsupported-platform + category!=failing \ No newline at end of file diff --git a/tests/CommunityToolkit.Aspire.Testing/RequiresDockerAttribute.cs b/tests/CommunityToolkit.Aspire.Testing/RequiresDockerAttribute.cs index 2aa29dfaa..fbecc0bd1 100644 --- a/tests/CommunityToolkit.Aspire.Testing/RequiresDockerAttribute.cs +++ b/tests/CommunityToolkit.Aspire.Testing/RequiresDockerAttribute.cs @@ -32,7 +32,7 @@ public RequiresDockerAttribute(string? reason = null) public IReadOnlyCollection> GetTraits() { - if (IsSupported) + if (!IsSupported) { return [new KeyValuePair(XunitConstants.Category, "failing")]; } From f10b449d1ae0f587f247a0add294b99ba780448d Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 10 Nov 2025 22:39:21 +0000 Subject: [PATCH 18/41] forgot I made that change --- .github/workflows/tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 42ce57535..68c1d5dfa 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -8,7 +8,7 @@ jobs: env: DOTNET_CONFIGURATION: Release DAPR_VERSION: "1.15.0" - TEST_PROJECT_PATH: tests/CommunityToolkit.Aspire.${{ matrix.name }}/CommunityToolkit.Aspire.${{ matrix.name }} + TEST_PROJECT_PATH: tests/CommunityToolkit.Aspire.${{ matrix.name }}/CommunityToolkit.Aspire.${{ matrix.name }}.csproj CI: true NPM_CONFIG_PACKAGE_LOCK: false runs-on: "${{ matrix.os }}" From 425a39eabd4d7dab832e1cf52335945c6af8cd5d Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 10 Nov 2025 23:40:59 +0000 Subject: [PATCH 19/41] updating a few more deps --- .github/workflows/tests.yaml | 11 +++-- .vscode/tasks.json | 65 ++++++++++++++++----------- Directory.Packages.props | 9 ++-- eng/clean-bin-obj.sh | 85 ++++++++++++++++++++++++++++++++++++ tests/Directory.Build.props | 3 ++ 5 files changed, 140 insertions(+), 33 deletions(-) create mode 100755 eng/clean-bin-obj.sh diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 68c1d5dfa..0982a34b8 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -96,7 +96,7 @@ jobs: - name: Run tests run: >- - dotnet ${{ github.workspace }}/artifacts/${{ matrix.name }}/CommunityToolkit.Aspire.${{ matrix.name }}.dll + dotnet run ${{ github.workspace }}/${{ env.TEST_PROJECT_PATH }} --configuration ${{ env.DOTNET_CONFIGURATION }} --logger "console;verbosity=normal" --logger "trx" @@ -107,10 +107,15 @@ jobs: --results-directory testresults --collect "XPlat Code Coverage" --no-restore - --no-build -- RunConfiguration.CollectSourceInformation=true + --no-build --filter-not-trait "category=failing" - --report-trx --report-trx-filename "${{ matrix.name }}-${{ matrix.os }}.trx" + --report-trx + --report-trx-filename "${{ matrix.name }}-${{ matrix.os }}.trx" --ignore-exit-code 8 + -- RunConfiguration.CollectSourceInformation=true + --coverage + --coverage-output-format cobertura + --coverage-output coverage.cobertura.xml env: CUSTOM_CONTAINER_REGISTRY: ${{ secrets.CUSTOM_CONTAINER_REGISTRY }} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index c4fa0024b..4658de2bd 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -2,36 +2,49 @@ "version": "2.0.0", "tasks": [ { - "label": "build", - "command": "dotnet", - "type": "process", - "args": [ - "build", - "/property:GenerateFullPaths=true", - "/consoleloggerparameters:NoSummary;ForceNoAlign" - ], - "problemMatcher": "$msCompile" + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary;ForceNoAlign" + ], + "problemMatcher": "$msCompile" }, { - "label": "publish", - "command": "dotnet", - "type": "process", - "args": [ - "publish", - "/property:GenerateFullPaths=true", - "/consoleloggerparameters:NoSummary;ForceNoAlign" - ], - "problemMatcher": "$msCompile" + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary;ForceNoAlign" + ], + "problemMatcher": "$msCompile" }, { - "label": "watch", - "command": "dotnet", - "type": "process", - "args": [ - "watch", - "run" - ], - "problemMatcher": "$msCompile" + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "cleanup", + "type": "shell", + "command": "./eng/clean-bin-obj.sh", + "problemMatcher": [], + "linux": { + "options": { + "shell": { + "executable": "bash" + } + } + } } ], "inputs": [ diff --git a/Directory.Packages.props b/Directory.Packages.props index 6ca1758e4..c720c7e76 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -102,11 +102,12 @@ - - - - + + + + + diff --git a/eng/clean-bin-obj.sh b/eng/clean-bin-obj.sh new file mode 100755 index 000000000..f9b69649a --- /dev/null +++ b/eng/clean-bin-obj.sh @@ -0,0 +1,85 @@ +#!/usr/bin/env bash +# Recursively delete all `bin` and `obj` folders from the repository. +# Usage: ./eng/clean-bin-obj.sh +# Optional flags: +# --dry-run Show what would be removed without deleting. +# --quiet Suppress per-folder output; only show summary. +# --help Display help. +# +# The script resolves the repo root based on its own location so it can be +# invoked from any working directory. + +set -euo pipefail + +print_help() { + cat <<'EOF' +Clean bin/obj folders + +Deletes ALL directories named `bin` or `obj` under the repository root. + +Flags: + --dry-run List directories that would be deleted. + --quiet Only print summary information. + --help Show this help text. + +Examples: + ./eng/clean-bin-obj.sh + ./eng/clean-bin-obj.sh --dry-run + ./eng/clean-bin-obj.sh --quiet +EOF +} + +DRY_RUN=0 +QUIET=0 +for arg in "$@"; do + case "$arg" in + --dry-run) DRY_RUN=1 ;; + --quiet) QUIET=1 ;; + --help|-h) print_help; exit 0 ;; + *) echo "Unknown argument: $arg" >&2; exit 1 ;; + esac +done + +# Determine repo root (parent of this script's directory) +SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +REPO_ROOT=$(cd "${SCRIPT_DIR}/.." && pwd) + +cd "$REPO_ROOT" + +# Collect bin/obj directories excluding anything under .git to be safe. +# Use -prune to avoid descending into matched directories after they are found. +mapfile -t TARGETS < <(find . -type d \( -name bin -o -name obj \) -not -path '*/.git/*' -prune -print) + +COUNT=${#TARGETS[@]} +if [[ $COUNT -eq 0 ]]; then + [[ $QUIET -eq 0 ]] && echo "No bin/obj directories found under $REPO_ROOT." || true + exit 0 +fi + +if [[ $DRY_RUN -eq 1 ]]; then + [[ $QUIET -eq 0 ]] && printf '%s\n' "Dry run: the following $COUNT directories would be deleted:" || true + printf '%s\n' "${TARGETS[@]}" + exit 0 +fi + +# Delete directories. +DELETED=0 +for dir in "${TARGETS[@]}"; do + if [[ $QUIET -eq 0 ]]; then + echo "Removing: $dir" + fi + rm -rf "$dir" || { + echo "Failed to remove: $dir" >&2 + continue + } + # Increment without triggering set -e early exit (arithmetic exit status is 1 when result is 0 for post-increment) + ((DELETED++)) || true +done + +if [[ $QUIET -eq 0 ]]; then + echo "Removed $DELETED bin/obj directories under $REPO_ROOT." +else + echo "Removed $DELETED directories." # Always show a minimal summary in quiet mode. +fi + +exit 0 diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index b8d5f25d6..73e0970b8 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -18,6 +18,7 @@ + @@ -39,6 +40,8 @@ $(TestRunnerAdditionalArguments) --ignore-exit-code 8 + + \ No newline at end of file From 270aa58e1add5b7a03825d9aec6f75d3bb2ec46b Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 24 Nov 2025 05:47:26 +0000 Subject: [PATCH 20/41] Updating based on comments and using the new GitHubActionsTestLogger with MTP support --- .github/workflows/tests.yaml | 17 ++++++----------- Directory.Packages.props | 5 +++-- tests/.runsettings | 7 ------- ...tyToolkit.Aspire.RavenDB.Client.Tests.csproj | 2 -- .../ConformanceTests.cs | 1 + tests/Directory.Build.props | 7 ++++--- 6 files changed, 14 insertions(+), 25 deletions(-) delete mode 100644 tests/.runsettings diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 50879f02b..dbc1dddc3 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -98,24 +98,19 @@ jobs: run: >- dotnet run ${{ github.workspace }}/${{ env.TEST_PROJECT_PATH }} --configuration ${{ env.DOTNET_CONFIGURATION }} - --logger "console;verbosity=normal" - --logger "trx" --logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true" - --blame - --blame-hang-timeout 7m - --blame-crash - --results-directory testresults - --collect "XPlat Code Coverage" + --crashdump + --hangdump + --hangdump-timeout 7m + --results-directory "${{ github.workspace }}/testresults" + --collect --no-restore --no-build --filter-not-trait "category=failing" --report-trx --report-trx-filename "${{ matrix.name }}-${{ matrix.os }}.trx" --ignore-exit-code 8 - -- RunConfiguration.CollectSourceInformation=true - --coverage - --coverage-output-format cobertura - --coverage-output coverage.cobertura.xml + --report-github env: CUSTOM_CONTAINER_REGISTRY: ${{ secrets.CUSTOM_CONTAINER_REGISTRY }} diff --git a/Directory.Packages.props b/Directory.Packages.props index dff6c199e..e118f2905 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -103,13 +103,14 @@ - + - + + diff --git a/tests/.runsettings b/tests/.runsettings deleted file mode 100644 index edd22a9eb..000000000 --- a/tests/.runsettings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - category!=failing - - \ No newline at end of file diff --git a/tests/CommunityToolkit.Aspire.RavenDB.Client.Tests/CommunityToolkit.Aspire.RavenDB.Client.Tests.csproj b/tests/CommunityToolkit.Aspire.RavenDB.Client.Tests/CommunityToolkit.Aspire.RavenDB.Client.Tests.csproj index b4528f844..55c1a5d46 100644 --- a/tests/CommunityToolkit.Aspire.RavenDB.Client.Tests/CommunityToolkit.Aspire.RavenDB.Client.Tests.csproj +++ b/tests/CommunityToolkit.Aspire.RavenDB.Client.Tests/CommunityToolkit.Aspire.RavenDB.Client.Tests.csproj @@ -2,8 +2,6 @@ Exe - enable - enable diff --git a/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs b/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs index 5ac36f30d..df989a3b7 100644 --- a/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs +++ b/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs @@ -12,6 +12,7 @@ using OpenTelemetry.Trace; using Xunit; using Aspire.Components.Common.Tests; +using Microsoft.DotNet.XUnitExtensions; namespace Aspire.Components.ConformanceTests; diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index 73e0970b8..a6cc49957 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -15,10 +15,11 @@ - + - + + @@ -41,7 +42,7 @@ https://learn.microsoft.com/dotnet/core/testing/microsoft-testing-platform-exit-codes --> $(TestRunnerAdditionalArguments) --ignore-exit-code 8 - + true \ No newline at end of file From cb145d814c4049ba56de55349e92ee8b3b04cd33 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 24 Nov 2025 06:02:22 +0000 Subject: [PATCH 21/41] Missing a few packages --- .github/workflows/tests.yaml | 4 ++-- Directory.Packages.props | 2 ++ tests/Directory.Build.props | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index dbc1dddc3..1ae625923 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -96,9 +96,9 @@ jobs: - name: Run tests run: >- - dotnet run ${{ github.workspace }}/${{ env.TEST_PROJECT_PATH }} + dotnet run + --project "${{ github.workspace }}/${{ env.TEST_PROJECT_PATH }}" --configuration ${{ env.DOTNET_CONFIGURATION }} - --logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true" --crashdump --hangdump --hangdump-timeout 7m diff --git a/Directory.Packages.props b/Directory.Packages.props index e118f2905..0a59f0de0 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -110,6 +110,8 @@ + + diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index a6cc49957..f12bdc86e 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -20,6 +20,8 @@ + + From 31b4c7114308e9f2dd2bf8b4abec9621a3eb71ac Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 24 Nov 2025 06:06:18 +0000 Subject: [PATCH 22/41] fixing ignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d997c9787..959f23f3f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,7 @@ obj appsettings.*.json *.orig test-results -TestResults +[Tt]est[Rr]esults nuget .pnpm-store .DS_Store From d319e2fa6204ca87e56c8320f62de692f1a3a3ba Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 24 Nov 2025 06:06:26 +0000 Subject: [PATCH 23/41] Fixing coverage arguments --- .github/workflows/tests.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 1ae625923..33c14c135 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -99,16 +99,17 @@ jobs: dotnet run --project "${{ github.workspace }}/${{ env.TEST_PROJECT_PATH }}" --configuration ${{ env.DOTNET_CONFIGURATION }} + --no-restore + --no-build --crashdump --hangdump --hangdump-timeout 7m --results-directory "${{ github.workspace }}/testresults" - --collect - --no-restore - --no-build --filter-not-trait "category=failing" --report-trx --report-trx-filename "${{ matrix.name }}-${{ matrix.os }}.trx" + --coverage + --ignore-exit-code 8 --report-github env: From 587cacec5c531779c3e5f23dac96e8bb0ecf8cc5 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 24 Nov 2025 07:12:15 +0000 Subject: [PATCH 24/41] Running built binary --- .github/workflows/tests.yaml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 33c14c135..415aababf 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -96,11 +96,9 @@ jobs: - name: Run tests run: >- - dotnet run - --project "${{ github.workspace }}/${{ env.TEST_PROJECT_PATH }}" + dotnet + ${{ github.workspace }}/artifacts/${{ matrix.name }}/CommunityToolkit.Aspire.${{ matrix.name }}.dll --configuration ${{ env.DOTNET_CONFIGURATION }} - --no-restore - --no-build --crashdump --hangdump --hangdump-timeout 7m @@ -109,7 +107,7 @@ jobs: --report-trx --report-trx-filename "${{ matrix.name }}-${{ matrix.os }}.trx" --coverage - + --ignore-exit-code 8 --report-github env: From 874567a388143d936a82c8d8ffb3565c7430e6cc Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 24 Nov 2025 07:25:02 +0000 Subject: [PATCH 25/41] Don't need configuration on a run --- .github/workflows/tests.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 415aababf..0f005f01c 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -98,7 +98,6 @@ jobs: run: >- dotnet ${{ github.workspace }}/artifacts/${{ matrix.name }}/CommunityToolkit.Aspire.${{ matrix.name }}.dll - --configuration ${{ env.DOTNET_CONFIGURATION }} --crashdump --hangdump --hangdump-timeout 7m From 837d9efce834019fda3e358840d0ed8932283516 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 24 Nov 2025 07:28:06 +0000 Subject: [PATCH 26/41] Removing an artificial bail out --- tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs b/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs index df989a3b7..13e8441a8 100644 --- a/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs +++ b/tests/CommunityToolkit.Aspire.Testing/ConformanceTests.cs @@ -270,11 +270,6 @@ public void LoggerFactoryIsUsedByRegisteredClient(bool registerAfterLoggerFactor SkipIfRequiredServerConnectionCanNotBeEstablished(); SkipIfKeyedRegistrationIsNotSupported(useKey); - if (RequiredLogCategories.Length == 0 && NotAcceptableLogCategories.Length == 0) - { - throw new SkipTestException("No log categories specified to test against."); - } - string? key = useKey ? "key" : null; HostApplicationBuilder builder = CreateHostBuilder(key: key); From db8346874f4201debf472614ea1c33b4752f1927 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 24 Nov 2025 07:36:52 +0000 Subject: [PATCH 27/41] Removing flag --- .github/workflows/tests.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 0f005f01c..f703dba32 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -106,8 +106,6 @@ jobs: --report-trx --report-trx-filename "${{ matrix.name }}-${{ matrix.os }}.trx" --coverage - - --ignore-exit-code 8 --report-github env: CUSTOM_CONTAINER_REGISTRY: ${{ secrets.CUSTOM_CONTAINER_REGISTRY }} From 6d7a7784dc6fcf5b5a4fbde7d7d7efefeb132c1f Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 24 Nov 2025 07:40:40 +0000 Subject: [PATCH 28/41] going back to dotnet run --- .github/workflows/tests.yaml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index f703dba32..2cec8209e 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -92,12 +92,14 @@ jobs: env: CI: false run: | - dotnet build ${{ github.workspace }}/${{ env.TEST_PROJECT_PATH }} /bl --configuration ${{ env.DOTNET_CONFIGURATION }} -o ${{ github.workspace }}/artifacts/${{ matrix.name }} + dotnet build ${{ github.workspace }}/${{ env.TEST_PROJECT_PATH }} /bl --configuration ${{ env.DOTNET_CONFIGURATION }} - name: Run tests run: >- - dotnet - ${{ github.workspace }}/artifacts/${{ matrix.name }}/CommunityToolkit.Aspire.${{ matrix.name }}.dll + dotnet run + --project "${{ github.workspace }}/${{ env.TEST_PROJECT_PATH }}" + --no-build + --configuration ${{ env.DOTNET_CONFIGURATION }} --crashdump --hangdump --hangdump-timeout 7m From 239aca3cca7343523acf7fa4e54f5aa2b96b7dcc Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Tue, 25 Nov 2025 12:14:22 +1100 Subject: [PATCH 29/41] Removing reference to runsettings --- tests/Directory.Build.props | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index f12bdc86e..43584435c 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -35,7 +35,6 @@ false true - $(MSBuildThisFileDirectory).runsettings From 0ab87ce7a56545584fcb589e42e5ff769c14bde9 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Tue, 25 Nov 2025 12:15:16 +1100 Subject: [PATCH 30/41] Performing an earlier eval of the connection string It seems there are two different paths for resolving the reference expression that _should_ return the same, but in the tests they don't seem to, so we'll force eval --- .../MongoDBBuilderExtensions.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions/MongoDBBuilderExtensions.cs b/src/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions/MongoDBBuilderExtensions.cs index 30bd7777b..bc3bcb3a6 100644 --- a/src/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions/MongoDBBuilderExtensions.cs +++ b/src/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions/MongoDBBuilderExtensions.cs @@ -42,14 +42,14 @@ public static IResourceBuilder WithDbGate(this IResourceB var dbGateBuilder = DbGateBuilderExtensions.AddDbGate(builder.ApplicationBuilder, containerName); dbGateBuilder - .WithEnvironment(context => ConfigureDbGateContainer(context, builder.ApplicationBuilder)); + .WithEnvironment(async context => await ConfigureDbGateContainer(context, builder.ApplicationBuilder)); configureContainer?.Invoke(dbGateBuilder); return builder; } - private static void ConfigureDbGateContainer(EnvironmentCallbackContext context, IDistributedApplicationBuilder applicationBuilder) + private static async Task ConfigureDbGateContainer(EnvironmentCallbackContext context, IDistributedApplicationBuilder applicationBuilder) { var mongoDBInstances = applicationBuilder.Resources.OfType(); @@ -66,7 +66,9 @@ private static void ConfigureDbGateContainer(EnvironmentCallbackContext context, // DbGate assumes MongoDB is being accessed over a default Aspire container network and hardcodes the resource address // This will need to be refactored once updated service discovery APIs are available context.EnvironmentVariables.Add($"LABEL_mongodb{counter}", mongoDBServer.Name); - context.EnvironmentVariables.Add($"URL_mongodb{counter}", mongoDBServer.ConnectionStringExpression); + + // Forcing evaluation of the connection string here to avoid issues with late binding in DbGate + context.EnvironmentVariables.Add($"URL_mongodb{counter}", await mongoDBServer.ConnectionStringExpression.GetValueAsync(context.CancellationToken) ?? throw new InvalidOperationException($"Unable to resolve connection string for {mongoDBServer.Name}.")); context.EnvironmentVariables.Add($"ENGINE_mongodb{counter}", "mongo@dbgate-plugin-mongo"); counter++; From 82737718e167b85cba27e1ef72cc9a6273f8f92c Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Wed, 3 Dec 2025 05:23:28 +0000 Subject: [PATCH 31/41] Adjusting msbuild props --- tests/Directory.Build.props | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index 43584435c..c053eb938 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -38,10 +38,9 @@ - $(TestRunnerAdditionalArguments) --filter-not-trait "category=failing" - $(TestRunnerAdditionalArguments) --ignore-exit-code 8 + $(TestingPlatformCommandLineArguments) --ignore-exit-code 8 --filter-not-trait "category=failing" true From fb3743d6e2ae2e9fc2282fa720dfc7b91174297a Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Tue, 9 Dec 2025 04:51:59 +0000 Subject: [PATCH 32/41] Linux file systems are case sensitive - why has this ever worked? --- .../CommunityToolkit.Aspire.PowerShell.AppHost/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/Program.cs b/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/Program.cs index 57f4bb348..c2cbb48fa 100644 --- a/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/Program.cs +++ b/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/Program.cs @@ -39,7 +39,7 @@ az storage blob upload --connection-string $myblob -c demo --file ./scripts/scri // outputs "the sum of 2 and 3 is 5" var script2 = ps.AddScript("script2", """ - & ./scripts/script.ps1 @args + & ./Scripts/script.ps1 @args """) .WithArgs(2, 3) .WaitForCompletion(script1); From 91576a2d5e8e3bbedd408a66305b295763619f5b Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Tue, 9 Dec 2025 05:28:55 +0000 Subject: [PATCH 33/41] The path when the scripts run during tests is different to just running the app host --- .../Program.cs | 19 ++++++++++++++++--- .../AppHostTests.cs | 3 +-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/Program.cs b/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/Program.cs index c2cbb48fa..4814b6059 100644 --- a/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/Program.cs +++ b/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/Program.cs @@ -14,6 +14,7 @@ param($name) write-information "Hello, $name" + write-information $pwd # uncommenting this will hang the script if you don't attach the pwsh debugger # wait-debugger @@ -22,15 +23,19 @@ # only run this if Azure CLI is installed if ((gcm az -ErrorAction SilentlyContinue) -ne $null) { + # When in the tests the PWD is wrong so we should test for it and fix it + if ($pwd -like "*CommunityToolkit.Aspire.Hosting.PowerShell.Tests*") { + write-information "Fixing PWD from $pwd" + Set-Location (Join-Path $pwd "../../../../../examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost") + write-information "New PWD is $pwd" + } az storage container create --connection-string $myblob -n demo - az storage blob upload --connection-string $myblob -c demo --file ./scripts/script.ps1 + az storage blob upload --connection-string $myblob -c demo --file ./Scripts/script.ps1 write-information "Blob uploaded" } else { - write-warning "Azure CLI not found, skipping blob upload" - } write-information $pwd @@ -39,6 +44,14 @@ az storage blob upload --connection-string $myblob -c demo --file ./scripts/scri // outputs "the sum of 2 and 3 is 5" var script2 = ps.AddScript("script2", """ + write-information 'Getting there...' + if ($pwd -like "*CommunityToolkit.Aspire.Hosting.PowerShell.Tests*") { + write-information "Fixing PWD from $pwd" + Set-Location (Join-Path $pwd "../../../../../examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost") + write-information "New PWD is $pwd" + } + write-information $PWD + & ./Scripts/script.ps1 @args """) .WithArgs(2, 3) diff --git a/tests/CommunityToolkit.Aspire.Hosting.PowerShell.Tests/AppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.PowerShell.Tests/AppHostTests.cs index 284d5c7bd..6472b383b 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.PowerShell.Tests/AppHostTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.PowerShell.Tests/AppHostTests.cs @@ -1,4 +1,3 @@ -using Aspire.Components.Common.Tests; using CommunityToolkit.Aspire.Testing; namespace CommunityToolkit.Aspire.Hosting.PowerShell.Tests; @@ -14,7 +13,7 @@ public async Task PowerShellResourceStarts() await fixture.ResourceNotificationService .WaitForResourceAsync(resourceName, KnownResourceStates.Running) .WaitAsync(TimeSpan.FromSeconds(60)); - + Assert.True(true); } From 3a0368b3508c3b85eb9c2286d7916a4e51d7caef Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Thu, 11 Dec 2025 22:41:26 +0000 Subject: [PATCH 34/41] Allowing mcp tests to run on all OS's --- .../AppHostTests.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/CommunityToolkit.Aspire.Hosting.McpInspector.Tests/AppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.McpInspector.Tests/AppHostTests.cs index 3b9a88cb2..372cc547a 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.McpInspector.Tests/AppHostTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.McpInspector.Tests/AppHostTests.cs @@ -2,8 +2,6 @@ namespace CommunityToolkit.Aspire.Hosting.McpInspector.Tests; -// Forcing linux only due to: https://github.com/modelcontextprotocol/inspector/issues/893 -[RequiresWindows] public class AppHostTests(AspireIntegrationTestFixture fixture) : IClassFixture> { [Fact] From 0b37f60e84da6506ed7599bab6c0b62d3a67684e Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Thu, 18 Dec 2025 23:29:17 +0000 Subject: [PATCH 35/41] Fixing copiler error --- .../RequiresAuthenticatedToolAttribute.cs | 14 ++++++-- .../RequiresAuthenticatedToolDiscoverer.cs | 36 ------------------- 2 files changed, 12 insertions(+), 38 deletions(-) delete mode 100644 tests/CommunityToolkit.Aspire.Testing/RequiresAuthenticatedToolDiscoverer.cs diff --git a/tests/CommunityToolkit.Aspire.Testing/RequiresAuthenticatedToolAttribute.cs b/tests/CommunityToolkit.Aspire.Testing/RequiresAuthenticatedToolAttribute.cs index 2a343d15e..4176b3076 100644 --- a/tests/CommunityToolkit.Aspire.Testing/RequiresAuthenticatedToolAttribute.cs +++ b/tests/CommunityToolkit.Aspire.Testing/RequiresAuthenticatedToolAttribute.cs @@ -1,5 +1,6 @@ using Aspire.Components.Common.Tests; -using Xunit.Sdk; +using Microsoft.DotNet.XUnitExtensions; +using Xunit.v3; namespace CommunityToolkit.Aspire.Testing; @@ -7,7 +8,6 @@ namespace CommunityToolkit.Aspire.Testing; /// Marks a test or test class as requiring an authenticated external tool. /// Adds a trait to propagate the required tool name to the xUnit pipeline. /// -[TraitDiscoverer("CommunityToolkit.Aspire.Testing.RequiresAuthenticatedToolDiscoverer", "CommunityToolkit.Aspire.Testing")] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] public sealed class RequiresAuthenticatedToolAttribute : Attribute, ITraitAttribute { @@ -34,4 +34,14 @@ public RequiresAuthenticatedToolAttribute(string toolName, string? reason = null /// Gets a value indicating whether authenticated tools are supported in the current environment. public static bool IsSupported => !PlatformDetection.IsRunningOnCI; + + public IReadOnlyCollection> GetTraits() + { + if (!IsSupported) + { + return [new KeyValuePair(XunitConstants.Category, "failing")]; + } + + return []; + } } diff --git a/tests/CommunityToolkit.Aspire.Testing/RequiresAuthenticatedToolDiscoverer.cs b/tests/CommunityToolkit.Aspire.Testing/RequiresAuthenticatedToolDiscoverer.cs deleted file mode 100644 index 9acb5b20b..000000000 --- a/tests/CommunityToolkit.Aspire.Testing/RequiresAuthenticatedToolDiscoverer.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace CommunityToolkit.Aspire.Testing; - -/// -/// Discovers traits for . -/// Adds a RequiresTools trait with the tool name and -/// categorizes tests as unsupported-platform when authenticated tools are not supported. -/// -public sealed class RequiresAuthenticatedToolDiscoverer : ITraitDiscoverer -{ - /// - public IEnumerable> GetTraits(IAttributeInfo traitAttribute) - { - string? toolName = null; - foreach (object? argument in traitAttribute.GetConstructorArguments().Where(a => a is string)) - { - if (argument is string value) - { - toolName = value; - break; - } - } - - if (!string.IsNullOrWhiteSpace(toolName)) - { - yield return new KeyValuePair("RequiresTools", toolName); - } - - if (!RequiresAuthenticatedToolAttribute.IsSupported) - { - yield return new KeyValuePair("category", "unsupported-platform"); - } - } -} From c3fab495974eff84fd5c75c7675097b305f25b59 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Thu, 18 Dec 2025 23:34:01 +0000 Subject: [PATCH 36/41] Updated traits --- .../RequiresAuthenticatedToolAttribute.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/CommunityToolkit.Aspire.Testing/RequiresAuthenticatedToolAttribute.cs b/tests/CommunityToolkit.Aspire.Testing/RequiresAuthenticatedToolAttribute.cs index 4176b3076..ee697b080 100644 --- a/tests/CommunityToolkit.Aspire.Testing/RequiresAuthenticatedToolAttribute.cs +++ b/tests/CommunityToolkit.Aspire.Testing/RequiresAuthenticatedToolAttribute.cs @@ -37,11 +37,13 @@ public RequiresAuthenticatedToolAttribute(string toolName, string? reason = null public IReadOnlyCollection> GetTraits() { + IReadOnlyCollection> traits = [new("RequiresTools", ToolName)]; + if (!IsSupported) { - return [new KeyValuePair(XunitConstants.Category, "failing")]; + traits = [.. traits, new KeyValuePair(XunitConstants.Category, "unsupported-platform")]; } - return []; + return traits; } } From 4f896d39bb7af112d7771ea4fc687530ff70368b Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Wed, 14 Jan 2026 23:27:14 +0000 Subject: [PATCH 37/41] Fixing compiler errors --- .../CommunityToolkit.Aspire.Hosting.Sftp.Tests/AppHostTests.cs | 1 - .../SftpFunctionalTests.cs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/CommunityToolkit.Aspire.Hosting.Sftp.Tests/AppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Sftp.Tests/AppHostTests.cs index 7d9f08f99..04f529ca3 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.Sftp.Tests/AppHostTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.Sftp.Tests/AppHostTests.cs @@ -3,7 +3,6 @@ using Polly; using Projects; using Renci.SshNet; -using Xunit.Abstractions; namespace CommunityToolkit.Aspire.Hosting.Sftp.Tests; diff --git a/tests/CommunityToolkit.Aspire.Hosting.Sftp.Tests/SftpFunctionalTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Sftp.Tests/SftpFunctionalTests.cs index c9aa4fc1b..d29503c55 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.Sftp.Tests/SftpFunctionalTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.Sftp.Tests/SftpFunctionalTests.cs @@ -1,12 +1,12 @@ using Aspire.Components.Common.Tests; using Aspire.Hosting; using Aspire.Hosting.Utils; +using CommunityToolkit.Aspire.Testing; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Polly; using Renci.SshNet; using Renci.SshNet.Common; -using Xunit.Abstractions; namespace CommunityToolkit.Aspire.Hosting.Sftp.Tests; From 6107c687d99dd1f2c283c4cc2dce192daea4a4fe Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Thu, 15 Jan 2026 11:32:35 +1100 Subject: [PATCH 38/41] Fixing a few failing test suites --- .../ResourceCreationTests.cs | 2 +- .../ResourceCreationTests.cs | 2 +- .../AppHostTests.cs | 1 - .../RequiresAuthenticatedToolAttribute.cs | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/CommunityToolkit.Aspire.Hosting.Redis.Extensions.Tests/ResourceCreationTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Redis.Extensions.Tests/ResourceCreationTests.cs index c02a12420..5a5c27842 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.Redis.Extensions.Tests/ResourceCreationTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.Redis.Extensions.Tests/ResourceCreationTests.cs @@ -45,7 +45,7 @@ public async Task WithDbGateAddsAnnotations() { var redisUrl = redisResource.PasswordParameter is not null ? $"redis://:{await redisResource.PasswordParameter.GetValueAsync(default)}@{redisResource.Name}:{redisResource.PrimaryEndpoint.TargetPort}" : $"redis://{redisResource.Name}:{redisResource.PrimaryEndpoint.TargetPort}"; - Assert.Equal("URL_redis1", item.Key); + Assert.Equal("URL_redis", item.Key); Assert.Equal(redisUrl, item.Value); }, item => diff --git a/tests/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions.Tests/ResourceCreationTests.cs b/tests/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions.Tests/ResourceCreationTests.cs index 6fcd43bfa..fd885a83f 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions.Tests/ResourceCreationTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions.Tests/ResourceCreationTests.cs @@ -53,7 +53,7 @@ public async Task WithDbGateAddsAnnotations() }, async item => { - Assert.Equal("PASSWORD_sqlserver1", item.Key); + Assert.Equal("PASSWORD_sqlserver", item.Key); Assert.Equal(await sqlserverResource.PasswordParameter.GetValueAsync(default), item.Value); }, item => diff --git a/tests/CommunityToolkit.Aspire.Hosting.Stripe.Tests/AppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Stripe.Tests/AppHostTests.cs index 83901481a..17c8f84ea 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.Stripe.Tests/AppHostTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.Stripe.Tests/AppHostTests.cs @@ -1,4 +1,3 @@ -using Aspire.Components.Common.Tests; using CommunityToolkit.Aspire.Testing; namespace CommunityToolkit.Aspire.Hosting.Stripe.Tests; diff --git a/tests/CommunityToolkit.Aspire.Testing/RequiresAuthenticatedToolAttribute.cs b/tests/CommunityToolkit.Aspire.Testing/RequiresAuthenticatedToolAttribute.cs index ee697b080..0b53638b3 100644 --- a/tests/CommunityToolkit.Aspire.Testing/RequiresAuthenticatedToolAttribute.cs +++ b/tests/CommunityToolkit.Aspire.Testing/RequiresAuthenticatedToolAttribute.cs @@ -41,7 +41,7 @@ public IReadOnlyCollection> GetTraits() if (!IsSupported) { - traits = [.. traits, new KeyValuePair(XunitConstants.Category, "unsupported-platform")]; + traits = [.. traits, new KeyValuePair(XunitConstants.Category, "failing")]; } return traits; From 1d1b7306fc874673f9e9d832f0798718b2c00e0b Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Thu, 15 Jan 2026 14:49:43 +1100 Subject: [PATCH 39/41] Ensuring PowerShell terminates properly The PowerShell Runspace doesn't when the app host does, which I think is the underlying cause as to why the tests hang. This now monitors the script resources so that when they complete we force a dispose on them (thus freeing any process they may have used) and once all are completed the Runspace is disposed, releasing it and **I think** that should allow the test host to terminate --- .../PowerShellRunspacePoolResource.cs | 5 ++++ ...llRunspacePoolResourceBuilderExtensions.cs | 23 +++++++++++++++++++ .../AppHostTests.cs | 3 +++ 3 files changed, 31 insertions(+) diff --git a/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResource.cs b/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResource.cs index a0a90156d..ea8ed8b6f 100644 --- a/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResource.cs +++ b/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResource.cs @@ -37,6 +37,11 @@ public class PowerShellRunspacePoolResource( /// public RunspacePool? Pool { get; private set; } + private Dictionary scriptResourceCompletion = []; + internal void AddScriptResource(PowerShellScriptResource scriptResource) => scriptResourceCompletion.Add(scriptResource.Name, false); + internal void ScriptResourceCompleted(PowerShellScriptResource scriptResource) => scriptResourceCompletion[scriptResource.Name] = true; + internal bool ScriptsCompleted => scriptResourceCompletion.Any(r => r.Value == false); + internal Task StartAsync(InitialSessionState sessionState, ResourceNotificationService notificationService, ILogger logger, CancellationToken token = default) { logger.LogInformation( diff --git a/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResourceBuilderExtensions.cs b/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResourceBuilderExtensions.cs index 5ab6437b6..2497dcc4d 100644 --- a/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResourceBuilderExtensions.cs +++ b/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResourceBuilderExtensions.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System.Diagnostics.CodeAnalysis; +using System.Drawing; using System.Management.Automation; namespace CommunityToolkit.Aspire.Hosting.PowerShell; @@ -49,6 +50,26 @@ await builder.ApplicationBuilder.Eventing.PublishAsync( scriptLogger.LogInformation("Starting script '{ScriptName}'", scriptName); _ = scriptResource.StartAsync(scriptLogger, notificationService, ct); + + await notificationService.WaitForResourceAsync(scriptResource.Name, KnownResourceStates.Finished, ct); + + ((IDisposable)scriptResource).Dispose(); + + builder.Resource.ScriptResourceCompleted(scriptResource); + + if (builder.Resource.ScriptsCompleted) + { + await notificationService.PublishUpdateAsync(builder.Resource, state => state with + { + State = KnownResourceStates.Finished, + Properties = [ + .. state.Properties, + ], + StopTimeStamp = DateTime.Now, + }); + + ((IDisposable)builder.Resource).Dispose(); + } } catch (Exception ex) { @@ -56,6 +77,8 @@ await builder.ApplicationBuilder.Eventing.PublishAsync( } }); + builder.Resource.AddScriptResource(scriptResource); + return builder.ApplicationBuilder .AddResource(scriptResource) .WithParentRelationship(builder.Resource) diff --git a/tests/CommunityToolkit.Aspire.Hosting.PowerShell.Tests/AppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.PowerShell.Tests/AppHostTests.cs index 6472b383b..8e52a7f26 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.PowerShell.Tests/AppHostTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.PowerShell.Tests/AppHostTests.cs @@ -39,6 +39,9 @@ public async Task ScriptsExecuteSuccessfully() .WaitAsync(TimeSpan.FromSeconds(90)); await Task.WhenAll([ready1, ready2]); + + Assert.True(ready1.IsCompletedSuccessfully); + Assert.True(ready2.IsCompletedSuccessfully); } } From b93dc7c23020dba8a5ff88aa9587cc1034cb54f5 Mon Sep 17 00:00:00 2001 From: Oisin Grehan Date: Thu, 15 Jan 2026 12:20:58 -0500 Subject: [PATCH 40/41] Revert "Ensuring PowerShell terminates properly" This reverts commit 1d1b7306fc874673f9e9d832f0798718b2c00e0b. --- .../PowerShellRunspacePoolResource.cs | 5 ---- ...llRunspacePoolResourceBuilderExtensions.cs | 23 ------------------- .../AppHostTests.cs | 3 --- 3 files changed, 31 deletions(-) diff --git a/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResource.cs b/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResource.cs index ea8ed8b6f..a0a90156d 100644 --- a/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResource.cs +++ b/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResource.cs @@ -37,11 +37,6 @@ public class PowerShellRunspacePoolResource( /// public RunspacePool? Pool { get; private set; } - private Dictionary scriptResourceCompletion = []; - internal void AddScriptResource(PowerShellScriptResource scriptResource) => scriptResourceCompletion.Add(scriptResource.Name, false); - internal void ScriptResourceCompleted(PowerShellScriptResource scriptResource) => scriptResourceCompletion[scriptResource.Name] = true; - internal bool ScriptsCompleted => scriptResourceCompletion.Any(r => r.Value == false); - internal Task StartAsync(InitialSessionState sessionState, ResourceNotificationService notificationService, ILogger logger, CancellationToken token = default) { logger.LogInformation( diff --git a/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResourceBuilderExtensions.cs b/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResourceBuilderExtensions.cs index 2497dcc4d..5ab6437b6 100644 --- a/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResourceBuilderExtensions.cs +++ b/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResourceBuilderExtensions.cs @@ -3,7 +3,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System.Diagnostics.CodeAnalysis; -using System.Drawing; using System.Management.Automation; namespace CommunityToolkit.Aspire.Hosting.PowerShell; @@ -50,26 +49,6 @@ await builder.ApplicationBuilder.Eventing.PublishAsync( scriptLogger.LogInformation("Starting script '{ScriptName}'", scriptName); _ = scriptResource.StartAsync(scriptLogger, notificationService, ct); - - await notificationService.WaitForResourceAsync(scriptResource.Name, KnownResourceStates.Finished, ct); - - ((IDisposable)scriptResource).Dispose(); - - builder.Resource.ScriptResourceCompleted(scriptResource); - - if (builder.Resource.ScriptsCompleted) - { - await notificationService.PublishUpdateAsync(builder.Resource, state => state with - { - State = KnownResourceStates.Finished, - Properties = [ - .. state.Properties, - ], - StopTimeStamp = DateTime.Now, - }); - - ((IDisposable)builder.Resource).Dispose(); - } } catch (Exception ex) { @@ -77,8 +56,6 @@ await notificationService.PublishUpdateAsync(builder.Resource, state => state wi } }); - builder.Resource.AddScriptResource(scriptResource); - return builder.ApplicationBuilder .AddResource(scriptResource) .WithParentRelationship(builder.Resource) diff --git a/tests/CommunityToolkit.Aspire.Hosting.PowerShell.Tests/AppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.PowerShell.Tests/AppHostTests.cs index 8e52a7f26..6472b383b 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.PowerShell.Tests/AppHostTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.PowerShell.Tests/AppHostTests.cs @@ -39,9 +39,6 @@ public async Task ScriptsExecuteSuccessfully() .WaitAsync(TimeSpan.FromSeconds(90)); await Task.WhenAll([ready1, ready2]); - - Assert.True(ready1.IsCompletedSuccessfully); - Assert.True(ready2.IsCompletedSuccessfully); } } From 7ed360d5951d03710a3857172c8c6fce15c119ac Mon Sep 17 00:00:00 2001 From: Oisin Grehan Date: Mon, 19 Jan 2026 13:15:52 -0500 Subject: [PATCH 41/41] hook applicationstopping on host lifecycle to shutdown RS pool --- .../Program.cs | 9 +++- .../Properties/launchSettings.json | 1 + ...DistributedApplicationBuilderExtensions.cs | 44 ++++++++-------- .../PowerShellRunspacePoolResource.cs | 10 +++- ...llRunspacePoolResourceBuilderExtensions.cs | 52 ++++++++++--------- 5 files changed, 67 insertions(+), 49 deletions(-) diff --git a/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/Program.cs b/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/Program.cs index 4814b6059..dc33823bf 100644 --- a/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/Program.cs +++ b/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/Program.cs @@ -2,7 +2,13 @@ var builder = DistributedApplication.CreateBuilder(args); -var storage = builder.AddAzureStorage("storage").RunAsEmulator(); +var storage = builder.AddAzureStorage("storage") + // see: https://github.com/dotnet/aspire/issues/13811 + .RunAsEmulator(azurite => + { + azurite.WithArgs("--disableProductStyleUrl"); + }); + var blob = storage.AddBlobs("myblob"); var ps = builder.AddPowerShell("ps") @@ -57,5 +63,6 @@ az storage blob upload --connection-string $myblob -c demo --file ./Scripts/scri .WithArgs(2, 3) .WaitForCompletion(script1); + builder.Build().Run(); diff --git a/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/Properties/launchSettings.json b/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/Properties/launchSettings.json index 80e6457ea..64093b07a 100644 --- a/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/Properties/launchSettings.json +++ b/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/Properties/launchSettings.json @@ -7,6 +7,7 @@ "launchBrowser": true, "applicationUrl": "https://localhost:17118;http://localhost:15215", "environmentVariables": { + "DCP_DIAGNOSTICS_LOG_LEVEL": "debug", "ASPNETCORE_ENVIRONMENT": "Development", "DOTNET_ENVIRONMENT": "Development", "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21165", diff --git a/src/CommunityToolkit.Aspire.Hosting.PowerShell/DistributedApplicationBuilderExtensions.cs b/src/CommunityToolkit.Aspire.Hosting.PowerShell/DistributedApplicationBuilderExtensions.cs index baf5ce2b1..f2a3970a2 100644 --- a/src/CommunityToolkit.Aspire.Hosting.PowerShell/DistributedApplicationBuilderExtensions.cs +++ b/src/CommunityToolkit.Aspire.Hosting.PowerShell/DistributedApplicationBuilderExtensions.cs @@ -1,6 +1,7 @@ using Aspire.Hosting; using Aspire.Hosting.ApplicationModel; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using System.Diagnostics; using System.Management.Automation; using System.Management.Automation.Runspaces; @@ -34,23 +35,34 @@ public static IResourceBuilder AddPowerShell( var pool = new PowerShellRunspacePoolResource(name, languageMode, minRunspaces, maxRunspaces); + var poolBuilder = builder.AddResource(pool) + .WithInitialState(new() + { + ResourceType = "PowerShellRunspacePool", + State = KnownResourceStates.NotStarted, + Properties = [ - builder.Eventing.Subscribe(pool, async (e, ct) => - { - var poolResource = e.Resource as PowerShellRunspacePoolResource; - - Debug.Assert(poolResource is not null); + new ("LanguageMode", pool.LanguageMode.ToString()), + new ("MinRunspaces", pool.MinRunspaces.ToString()), + new ("MaxRunspaces", pool.MaxRunspaces.ToString()) + ] + }) + .ExcludeFromManifest(); + poolBuilder.OnInitializeResource(async (res, e, ct) => + { var loggerService = e.Services.GetRequiredService(); var notificationService = e.Services.GetRequiredService(); + var hostLifetime = e.Services.GetRequiredService(); var sessionState = InitialSessionState.CreateDefault(); + sessionState.UseFullLanguageModeInDebugger = true; // This will block until explicit and implied WaitFor calls are completed await builder.Eventing.PublishAsync( - new BeforeResourceStartedEvent(poolResource, e.Services), ct); + new BeforeResourceStartedEvent(res, e.Services), ct); - foreach (var annotation in poolResource.Annotations.OfType>()) + foreach (var annotation in res.Annotations.OfType>()) { if (annotation is { } reference) { @@ -62,24 +74,12 @@ await builder.Eventing.PublishAsync( } } - var poolName = poolResource.Name; + var poolName = res.Name; var poolLogger = loggerService.GetLogger(poolName); - _ = poolResource.StartAsync(sessionState, notificationService, poolLogger, ct); + _ = res.StartAsync(sessionState, notificationService, poolLogger, hostLifetime, ct); }); - return builder.AddResource(pool) - .WithInitialState(new() - { - ResourceType = "PowerShellRunspacePool", - State = KnownResourceStates.NotStarted, - Properties = [ - - new ("LanguageMode", pool.LanguageMode.ToString()), - new ("MinRunspaces", pool.MinRunspaces.ToString()), - new ("MaxRunspaces", pool.MaxRunspaces.ToString()) - ] - }) - .ExcludeFromManifest(); + return poolBuilder; } } \ No newline at end of file diff --git a/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResource.cs b/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResource.cs index a0a90156d..96831fe61 100644 --- a/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResource.cs +++ b/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResource.cs @@ -1,4 +1,5 @@ using Aspire.Hosting.ApplicationModel; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using System.Globalization; using System.Management.Automation; @@ -37,7 +38,7 @@ public class PowerShellRunspacePoolResource( /// public RunspacePool? Pool { get; private set; } - internal Task StartAsync(InitialSessionState sessionState, ResourceNotificationService notificationService, ILogger logger, CancellationToken token = default) + internal Task StartAsync(InitialSessionState sessionState, ResourceNotificationService notificationService, ILogger logger, IHostApplicationLifetime hostLifetime, CancellationToken token = default) { logger.LogInformation( "Starting PowerShell runspace pool '{PoolName}' with {MinRunspaces} to {MaxRunspaces} runspaces", @@ -48,6 +49,13 @@ internal Task StartAsync(InitialSessionState sessionState, ResourceNotificationS Pool = RunspaceFactory.CreateRunspacePool(MinRunspaces, MaxRunspaces, sessionState, new AspirePSHost(logger)); ConfigureStateChangeNotifications(notificationService, logger); + + hostLifetime.ApplicationStopping.Register(() => + { + // if we don't do this, xunit 3 will hang on exit because of open runspaces (foreground threads) + logger.LogInformation("Closing PowerShell runspace pool '{PoolName}'", Name); + Pool?.Close(); + }); return Task.Factory.FromAsync(Pool.BeginOpen, Pool.EndOpen, null); } diff --git a/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResourceBuilderExtensions.cs b/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResourceBuilderExtensions.cs index 5ab6437b6..695a8ce97 100644 --- a/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResourceBuilderExtensions.cs +++ b/src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunspacePoolResourceBuilderExtensions.cs @@ -32,31 +32,7 @@ public static IResourceBuilder AddScript( var scriptResource = new PowerShellScriptResource(name, scriptBlock, builder.Resource); - builder.ApplicationBuilder.Eventing.Subscribe(scriptResource, async (e, ct) => - { - var loggerService = e.Services.GetRequiredService(); - var notificationService = e.Services.GetRequiredService(); - - var scriptName = scriptResource.Name; - var scriptLogger = loggerService.GetLogger(scriptName); - - try - { - // this will block until the runspace pool is started, which is implied by the WaitFor call - await builder.ApplicationBuilder.Eventing.PublishAsync( - new BeforeResourceStartedEvent(scriptResource, e.Services), ct); - - scriptLogger.LogInformation("Starting script '{ScriptName}'", scriptName); - - _ = scriptResource.StartAsync(scriptLogger, notificationService, ct); - } - catch (Exception ex) - { - scriptLogger.LogError(ex, "Failed to start script '{ScriptName}'", scriptName); - } - }); - - return builder.ApplicationBuilder + var scriptBuilder = builder.ApplicationBuilder .AddResource(scriptResource) .WithParentRelationship(builder.Resource) .WaitFor(builder) @@ -88,6 +64,32 @@ await builder.ApplicationBuilder.Eventing.PublishAsync( ResourceCommandState.Disabled : ResourceCommandState.Enabled }); + + scriptBuilder.OnInitializeResource(async (res, e, ct) => + { + var loggerService = e.Services.GetRequiredService(); + var notificationService = e.Services.GetRequiredService(); + + var scriptName = res.Name; + var scriptLogger = loggerService.GetLogger(scriptName); + + try + { + // this will block until the runspace pool is started, which is implied by the WaitFor call + await builder.ApplicationBuilder.Eventing.PublishAsync( + new BeforeResourceStartedEvent(res, e.Services), ct); + + scriptLogger.LogInformation("Starting script '{ScriptName}'", scriptName); + + _ = res.StartAsync(scriptLogger, notificationService, ct); + } + catch (Exception ex) + { + scriptLogger.LogError(ex, "Failed to start script '{ScriptName}'", scriptName); + } + }); + + return scriptBuilder; } ///