Skip to content

Commit 3fb90a5

Browse files
westey-mrogerbarretocrickmaneavanvalkenburgCopilot
authored
.NET: CI Build time end to end improvement (#4208)
* .NET: Upgrade to XUnit 3 and Microsoft Testing Platform (#4176) * Fix copilot studio integration tests failure (#4209) * Fix anthropic integration tests and skip reason (#4211) * Remove accidental add of code coverage for integration tests (#4219) * Add solution filtered parallel test run (#4226) * Fix build paths (#4228) * Fix coverage settings path and trait filter (#4229) * Add project name filter to solution (#4231) * Increase Integration Test Parallelism (#4241) * Increase integration tests threads to 4x (#4242) * Separate build and test into parallel jobs (#4243) * Filter src by framework for tests build (#4244) * Separate build and test into parallel jobs * Filter source projects by framework for tests build * Pre-build samples via tests to avoid timeouts (#4245) * Separate build from run for console sample validation (#4251) * Address PR comments (#4255) * Merge and move scripts (#4308) * .NET: Add Microsoft Fabric sample #3674 (#4230) Co-authored-by: Chris <66376200+crickman@users.noreply.github.com> * Python: Phase 2: Embedding clients for Ollama, Bedrock, and Azure AI Inference (#4207) * Phase 2: Embedding clients for Ollama, Bedrock, and Azure AI Inference Add embedding client implementations to existing provider packages: - OllamaEmbeddingClient: Text embeddings via Ollama's embed API - BedrockEmbeddingClient: Text embeddings via Amazon Titan on Bedrock - AzureAIInferenceEmbeddingClient: Text and image embeddings via Azure AI Inference, supporting Content | str input with separate model IDs for text (AZURE_AI_INFERENCE_EMBEDDING_MODEL_ID) and image (AZURE_AI_INFERENCE_IMAGE_EMBEDDING_MODEL_ID) endpoints Additional changes: - Rename EmbeddingCoT -> EmbeddingT, EmbeddingOptionsCoT -> EmbeddingOptionsT - Add otel_provider_name passthrough to all embedding clients - Register integration pytest marker in all packages - Add lazy-loading namespace exports for Ollama and Bedrock embeddings - Add image embedding sample using Cohere-embed-v3-english - Add azure-ai-inference dependency to azure-ai package Part of #1188 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix mypy duplicate name and ruff lint issues - Rename second 'vector' variable to 'img_vector' in image embedding loop - Combine nested with statements in tests - Remove unused result assignments in tests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * updates from feedback * Fix CI failures in embedding usage handling - Fix Azure AI embedding mypy issues by normalizing vectors to list[float], safely accumulating optional usage token fields, and filtering None entries before constructing GeneratedEmbeddings - Avoid Bandit false positive by initializing usage details as an empty dict - Update OpenAI embedding tests to assert canonical usage keys (input_token_count/total_token_count) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * [Purview] Mark responses as responses and fix epoch bug for python long overflow (#4225) * .NET: Support InvokeMcpTool for declarative workflows (#4204) * Initial implementation of InvokeMcpTool in declarative workflow * Cleaned up sample implementation * Updated sample comments. * Added missing executor routing attribute * Fix PR comments. * Updated based on PR comments. * Updated based on PR comments. * Removed unnecessary using statement. * Update Python package versions to rc2 (#4258) - Bump core and azure-ai to 1.0.0rc2 - Bump preview packages to 1.0.0b260225 - Update dependencies to >=1.0.0rc2 - Add CHANGELOG entries for changes since rc1 - Update uv.lock Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * .NET: Fixing issue where OpenTelemetry span is never exported in .NET in-process workflow execution (#4196) * 1. Add reproduction test for issue #4155: workflow.run Activity never stopped in streaming OffThread path The WorkflowRunActivity_IsStopped_Streaming_OffThread test demonstrates that the workflow.run OpenTelemetry Activity created in StreamingRunEventStream.RunLoopAsync is started but never stopped when using the OffThread/Default streaming execution. The background run loop keeps running after event consumption completes, so the using Activity? declaration never disposes until explicit StopAsync() is called. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> 2. Fix workflow.run Activity never stopped in streaming OffThread execution (#4155) The workflow.run OpenTelemetry Activity in StreamingRunEventStream.RunLoopAsync was scoped to the method lifetime via 'using'. Since the run loop only exits on cancellation, the Activity was never stopped/exported until explicit disposal. Fix: Remove 'using' and explicitly dispose the Activity when the workflow reaches Idle status (all supersteps complete). A safety-net disposal in the finally block handles cancellation and error paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add root-level workflow.session activity spanning run loop lifetime\n\nImplements two-level telemetry hierarchy per PR feedback from lokitoth:\n- workflow.session: spans the entire run loop / stream lifetime\n- workflow_invoke: per input-to-halt cycle, nested within the session\n\nThis ensures the session activity stays open across multiple turns,\nwhile individual run activities are created and disposed per cycle.\n\nAlso fixes linkedSource CancellationTokenSource disposal leak in\nStreamingRunEventStream (added using declaration)." * Address Copilot review: fix Activity/CTS disposal, rename activity, add error tag\n\n1. LockstepRunEventStream: Remove 'using' from Activity in async iterator\n and manually dispose in finally block (fixes #4155 pattern). Also dispose\n linkedSource CTS in finally to prevent leak.\n2. Tags.cs: Add ErrorMessage (\"error.message\") tag for runtime errors,\n distinct from BuildErrorMessage (\"build.error.message\").\n3. ActivityNames: Rename WorkflowRun from \"workflow_invoke\" to \"workflow.run\"\n for cross-language consistency.\n4. WorkflowTelemetryContext: Fix XML doc to say \"outer/parent span\" instead\n of \"root-level span\".\n5. ObservabilityTests: Assert WorkflowSession absence when DisableWorkflowRun\n is true.\n6. WorkflowRunActivityStopTests: Fix streaming test race by disposing\n StreamingRun before asserting activities are stopped.\n7. StreamingRunEventStream/LockstepRunEventStream: Use Tags.ErrorMessage\n instead of Tags.BuildErrorMessage for runtime error events." * Review fixes: revert workflow_invoke rename, use 'using' for linkedSource, move SessionStarted earlier\n\n- Revert ActivityNames.WorkflowRun back to \"workflow_invoke\" (OTEL semantic convention contract)\n- Use 'using' declaration for linkedSource CTS in LockstepRunEventStream (no timing sensitivity)\n- Move SessionStarted event before WaitForInputAsync in StreamingRunEventStream to match Lockstep behavior" * Improve naming and comments in WorkflowRunActivityStopTests" * Prevent session Activity.Current leak in lockstep mode, add nesting test Save and restore Activity.Current in LockstepRunEventStream.Start() so the session activity doesn't leak into caller code via AsyncLocal. Re-establish Activity.Current = sessionActivity before creating the run activity in TakeEventStreamAsync to preserve parent-child nesting. Add test verifying app activities after RunAsync are not parented under the session, and that the workflow_invoke activity nests under the session." * Fix stale XML doc: WorkflowRun -> WorkflowInvoke in ObservabilityTests --------- Co-authored-by: alliscode <bentho@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python / .NET Samples - Restructure and Improve Samples (Feature Branc… (#4092) * Python: .NET Samples - Restructure and Improve Samples (Feature Branch) (#4091) * Moved by agent (#4094) * Fix readme links * .NET Samples - Create `04-hosting` learning path step (#4098) * Agent move * Agent reorderd * Remove A2A section from README Removed A2A section from the Getting Started README. * Agent fixed links * Fix broken sample links in durable-agents README (#4101) * Initial plan * Fix broken internal links in documentation Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> * Revert template link changes; keep only durable-agents README fix Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> * .NET Samples - Create `03-workflows` learning path step (#4102) * Fix solution project path * Python: Fix broken markdown links to repo resources (outside /docs) (#4105) * Initial plan * Fix broken markdown links to repo resources Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> * Update README to rename .NET Workflows Samples section --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> * .NET Samples - Create `02-agents` learning path step (#4107) * .NET: Fix broken relative link in GroupChatToolApproval README (#4108) * Initial plan * Fix broken link in GroupChatToolApproval README Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> * Update labeler configuration for workflow samples * .NET - Reorder Agents samples to start from Step01 instead of Step04 (#4110) * Fix solution * Resolve new sample paths * Move new AgentSkills and AgentWithMemory_Step04 samples * Fix link * Fix readme path * fix: update stale dotnet/samples/Durable path reference in AGENTS.md Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> * Moved new sample * Update solution * Resolve merge (new sample) * Sync to new sample - FoundryAgents_Step21_BingCustomSearch * Updated README * .NET Samples - Configuration Naming Update (#4149) * .NET: Restore AzureFunctions index parity with ConsoleApps under DurableAgents samples (#4221) * Clean-up `05_host_your_agent` * Config setting consistency * Refine samples * AGENTS.md * Move new samples * Re-order samples * Move new project and fixup solution * Fixup model config * Fix up new UT project --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> * Python: Fix Bedrock embedding test stub missing meta attribute (#4287) * Fix Bedrock embedding test stub missing meta attribute * Increase test coverage so gate passes * Python: (ag-ui): fix approval payloads being re-processed on subsequent conversation turns (#4232) * Fix ag-ui tool call issue * Safe json fix * Python: Update workflow orchestration samples to use AzureOpenAIResponsesClient (#4285) * Update workflow orchestration samples to use AzureOpenAIResponsesClient * Fix broken link * Move scripts to scripts folder --------- Co-authored-by: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com> Co-authored-by: Chris <66376200+crickman@users.noreply.github.com> Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Rishabh Chawla <rishabhchawla1995@gmail.com> Co-authored-by: Peter Ibekwe <109177538+peibekwe@users.noreply.github.com> Co-authored-by: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com> Co-authored-by: Ben Thomas <ben.thomas@microsoft.com> Co-authored-by: alliscode <bentho@microsoft.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com> * Fix encoding (#4309) * Disable Parallelization for WorkflowRunActivityStopTests (#4313) * Revert parallel disable (#4324) * .NET: Disable flakey Workflow Observability tests (#4416) * Disable flakey OffThread test * Disable additional OffThread test * Disable a further test * Disable all observability tests --------- Co-authored-by: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com> Co-authored-by: Chris <66376200+crickman@users.noreply.github.com> Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Rishabh Chawla <rishabhchawla1995@gmail.com> Co-authored-by: Peter Ibekwe <109177538+peibekwe@users.noreply.github.com> Co-authored-by: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com> Co-authored-by: Ben Thomas <ben.thomas@microsoft.com> Co-authored-by: alliscode <bentho@microsoft.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com>
1 parent 56bba79 commit 3fb90a5

120 files changed

Lines changed: 739 additions & 434 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/dotnet-build-and-test.yml

Lines changed: 108 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -59,20 +59,20 @@ jobs:
5959
if: steps.filter.outputs.dotnet != 'true'
6060
run: echo "NOT dotnet file"
6161

62-
dotnet-build-and-test:
62+
# Build the full solution (including samples) on all TFMs. No tests.
63+
dotnet-build:
6364
needs: paths-filter
6465
if: needs.paths-filter.outputs.dotnetChanges == 'true'
6566
strategy:
6667
fail-fast: false
6768
matrix:
6869
include:
69-
- { targetFramework: "net10.0", os: "ubuntu-latest", configuration: Release, integration-tests: true, environment: "integration" }
70+
- { targetFramework: "net10.0", os: "ubuntu-latest", configuration: Release }
7071
- { targetFramework: "net9.0", os: "windows-latest", configuration: Debug }
7172
- { targetFramework: "net8.0", os: "ubuntu-latest", configuration: Release }
72-
- { targetFramework: "net472", os: "windows-latest", configuration: Release, integration-tests: true, environment: "integration" }
73+
- { targetFramework: "net472", os: "windows-latest", configuration: Release }
7374

7475
runs-on: ${{ matrix.os }}
75-
environment: ${{ matrix.environment }}
7676
steps:
7777
- uses: actions/checkout@v6
7878
with:
@@ -84,16 +84,6 @@ jobs:
8484
python
8585
workflow-samples
8686
87-
# Start Cosmos DB Emulator for all integration tests and only for unit tests when CosmosDB changes happened)
88-
- name: Start Azure Cosmos DB Emulator
89-
if: ${{ runner.os == 'Windows' && (needs.paths-filter.outputs.cosmosDbChanges == 'true' || (github.event_name != 'pull_request' && matrix.integration-tests)) }}
90-
shell: pwsh
91-
run: |
92-
Write-Host "Launching Azure Cosmos DB Emulator"
93-
Import-Module "$env:ProgramFiles\Azure Cosmos DB Emulator\PSModules\Microsoft.Azure.CosmosDB.Emulator"
94-
Start-CosmosDbEmulator -NoUI -Key "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
95-
echo "COSMOSDB_EMULATOR_AVAILABLE=true" >> $env:GITHUB_ENV
96-
9787
- name: Setup dotnet
9888
uses: actions/setup-dotnet@v5.1.0
9989
with:
@@ -140,25 +130,98 @@ jobs:
140130
popd
141131
rm -rf "$TEMP_DIR"
142132
143-
- name: Run Unit Tests
133+
# Build src+tests only (no samples) for a single TFM and run tests.
134+
dotnet-test:
135+
needs: paths-filter
136+
if: needs.paths-filter.outputs.dotnetChanges == 'true'
137+
strategy:
138+
fail-fast: false
139+
matrix:
140+
include:
141+
- { targetFramework: "net10.0", os: "ubuntu-latest", configuration: Release, integration-tests: true, environment: "integration" }
142+
- { targetFramework: "net472", os: "windows-latest", configuration: Release, integration-tests: true, environment: "integration" }
143+
144+
runs-on: ${{ matrix.os }}
145+
environment: ${{ matrix.environment }}
146+
steps:
147+
- uses: actions/checkout@v6
148+
with:
149+
persist-credentials: false
150+
sparse-checkout: |
151+
.
152+
.github
153+
dotnet
154+
python
155+
workflow-samples
156+
157+
# Start Cosmos DB Emulator for all integration tests and only for unit tests when CosmosDB changes happened)
158+
- name: Start Azure Cosmos DB Emulator
159+
if: ${{ runner.os == 'Windows' && (needs.paths-filter.outputs.cosmosDbChanges == 'true' || (github.event_name != 'pull_request' && matrix.integration-tests)) }}
160+
shell: pwsh
161+
run: |
162+
Write-Host "Launching Azure Cosmos DB Emulator"
163+
Import-Module "$env:ProgramFiles\Azure Cosmos DB Emulator\PSModules\Microsoft.Azure.CosmosDB.Emulator"
164+
Start-CosmosDbEmulator -NoUI -Key "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
165+
echo "COSMOSDB_EMULATOR_AVAILABLE=true" >> $env:GITHUB_ENV
166+
167+
- name: Setup dotnet
168+
uses: actions/setup-dotnet@v5.1.0
169+
with:
170+
global-json-file: ${{ github.workspace }}/dotnet/global.json
171+
172+
- name: Generate test solution (no samples)
173+
shell: pwsh
174+
run: |
175+
./dotnet/eng/scripts/New-FilteredSolution.ps1 `
176+
-Solution dotnet/agent-framework-dotnet.slnx `
177+
-TargetFramework ${{ matrix.targetFramework }} `
178+
-Configuration ${{ matrix.configuration }} `
179+
-ExcludeSamples `
180+
-OutputPath dotnet/filtered.slnx `
181+
-Verbose
182+
183+
- name: Build src and tests
144184
shell: bash
185+
run: dotnet build dotnet/filtered.slnx -c ${{ matrix.configuration }} -f ${{ matrix.targetFramework }} --warnaserror
186+
187+
- name: Generate test-type filtered solutions
188+
shell: pwsh
145189
run: |
146-
export UT_PROJECTS=$(find ./dotnet -type f -name "*.UnitTests.csproj" | tr '\n' ' ')
147-
for project in $UT_PROJECTS; do
148-
# Query the project's target frameworks using MSBuild with the current configuration
149-
target_frameworks=$(dotnet msbuild $project -getProperty:TargetFrameworks -p:Configuration=${{ matrix.configuration }} -nologo 2>/dev/null | tr -d '\r')
150-
151-
# Check if the project supports the target framework
152-
if [[ "$target_frameworks" == *"${{ matrix.targetFramework }}"* ]]; then
153-
if [[ "${{ matrix.targetFramework }}" == "${{ env.COVERAGE_FRAMEWORK }}" ]]; then
154-
dotnet test -f ${{ matrix.targetFramework }} -c ${{ matrix.configuration }} $project --no-build -v Normal --logger trx --collect:"XPlat Code Coverage" --results-directory:"TestResults/Coverage/" -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.ExcludeByAttribute=GeneratedCodeAttribute,CompilerGeneratedAttribute,ExcludeFromCodeCoverageAttribute
155-
else
156-
dotnet test -f ${{ matrix.targetFramework }} -c ${{ matrix.configuration }} $project --no-build -v Normal --logger trx
157-
fi
158-
else
159-
echo "Skipping $project - does not support target framework ${{ matrix.targetFramework }} (supports: $target_frameworks)"
160-
fi
161-
done
190+
$commonArgs = @{
191+
Solution = "dotnet/filtered.slnx"
192+
TargetFramework = "${{ matrix.targetFramework }}"
193+
Configuration = "${{ matrix.configuration }}"
194+
Verbose = $true
195+
}
196+
./dotnet/eng/scripts/New-FilteredSolution.ps1 @commonArgs `
197+
-TestProjectNameFilter "*UnitTests*" `
198+
-OutputPath dotnet/filtered-unit.slnx
199+
./dotnet/eng/scripts/New-FilteredSolution.ps1 @commonArgs `
200+
-TestProjectNameFilter "*IntegrationTests*" `
201+
-OutputPath dotnet/filtered-integration.slnx
202+
203+
- name: Run Unit Tests
204+
shell: pwsh
205+
working-directory: dotnet
206+
run: |
207+
$coverageSettings = Join-Path $PWD "tests/coverage.runsettings"
208+
$coverageArgs = @()
209+
if ("${{ matrix.targetFramework }}" -eq "${{ env.COVERAGE_FRAMEWORK }}") {
210+
$coverageArgs = @(
211+
"--coverage",
212+
"--coverage-output-format", "cobertura",
213+
"--coverage-settings", $coverageSettings,
214+
"--results-directory", "../TestResults/Coverage/"
215+
)
216+
}
217+
218+
dotnet test --solution ./filtered-unit.slnx `
219+
-f ${{ matrix.targetFramework }} `
220+
-c ${{ matrix.configuration }} `
221+
--no-build -v Normal `
222+
--report-xunit-trx `
223+
--ignore-exit-code 8 `
224+
@coverageArgs
162225
env:
163226
# Cosmos DB Emulator connection settings
164227
COSMOSDB_ENDPOINT: https://localhost:8081
@@ -185,21 +248,19 @@ jobs:
185248
id: azure-functions-setup
186249

187250
- name: Run Integration Tests
188-
shell: bash
251+
shell: pwsh
252+
working-directory: dotnet
189253
if: github.event_name != 'pull_request' && matrix.integration-tests
190254
run: |
191-
export INTEGRATION_TEST_PROJECTS=$(find ./dotnet -type f -name "*IntegrationTests.csproj" | tr '\n' ' ')
192-
for project in $INTEGRATION_TEST_PROJECTS; do
193-
# Query the project's target frameworks using MSBuild with the current configuration
194-
target_frameworks=$(dotnet msbuild $project -getProperty:TargetFrameworks -p:Configuration=${{ matrix.configuration }} -nologo 2>/dev/null | tr -d '\r')
195-
196-
# Check if the project supports the target framework
197-
if [[ "$target_frameworks" == *"${{ matrix.targetFramework }}"* ]]; then
198-
dotnet test -f ${{ matrix.targetFramework }} -c ${{ matrix.configuration }} $project --no-build -v Normal --logger trx --filter "Category!=IntegrationDisabled"
199-
else
200-
echo "Skipping $project - does not support target framework ${{ matrix.targetFramework }} (supports: $target_frameworks)"
201-
fi
202-
done
255+
dotnet test --solution ./filtered-integration.slnx `
256+
-f ${{ matrix.targetFramework }} `
257+
-c ${{ matrix.configuration }} `
258+
--no-build -v Normal `
259+
--report-xunit-trx `
260+
--ignore-exit-code 8 `
261+
--filter-not-trait "Category=IntegrationDisabled" `
262+
--parallel-algorithm aggressive `
263+
--max-threads 2.0x
203264
env:
204265
# Cosmos DB Emulator connection settings
205266
COSMOSDB_ENDPOINT: https://localhost:8081
@@ -222,7 +283,7 @@ jobs:
222283
if: matrix.targetFramework == env.COVERAGE_FRAMEWORK
223284
uses: danielpalme/ReportGenerator-GitHub-Action@5.5.1
224285
with:
225-
reports: "./TestResults/Coverage/**/coverage.cobertura.xml"
286+
reports: "./TestResults/Coverage/**/*.cobertura.xml"
226287
targetdir: "./TestResults/Reports"
227288
reporttypes: "HtmlInline;JsonSummary"
228289

@@ -236,13 +297,13 @@ jobs:
236297
- name: Check coverage
237298
if: matrix.targetFramework == env.COVERAGE_FRAMEWORK
238299
shell: pwsh
239-
run: .github/workflows/dotnet-check-coverage.ps1 -JsonReportPath "TestResults/Reports/Summary.json" -CoverageThreshold $env:COVERAGE_THRESHOLD
300+
run: ./dotnet/eng/scripts/dotnet-check-coverage.ps1 -JsonReportPath "TestResults/Reports/Summary.json" -CoverageThreshold $env:COVERAGE_THRESHOLD
240301

241302
# This final job is required to satisfy the merge queue. It must only run (or succeed) if no tests failed
242303
dotnet-build-and-test-check:
243304
if: always()
244305
runs-on: ubuntu-latest
245-
needs: [dotnet-build-and-test]
306+
needs: [dotnet-build, dotnet-test]
246307
steps:
247308
- name: Get Date
248309
shell: bash

dotnet/.github/skills/build-and-test/SKILL.md

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,17 @@ dotnet format # Auto-fix formatting for all projects
1717

1818
# Build/test/format a specific project (preferred for isolated/internal changes)
1919
dotnet build src/Microsoft.Agents.AI.<Package> --tl:off
20-
dotnet test tests/Microsoft.Agents.AI.<Package>.UnitTests
20+
dotnet test --project tests/Microsoft.Agents.AI.<Package>.UnitTests
2121
dotnet format src/Microsoft.Agents.AI.<Package>
2222

2323
# Run a single test
24-
dotnet test --filter "FullyQualifiedName~Namespace.TestClassName.TestMethodName"
24+
# Replace the filter values with the appropriate assembly, namespace, class, and method names for the test you want to run and use * as a wildcard elsewhere, e.g. "/*/*/HttpClientTests/GetAsync_ReturnsSuccessStatusCode"
25+
# Use `--ignore-exit-code 8` to avoid failing the build when no tests are found for some projects
26+
dotnet test --filter-query "/<assemblyFilter>/<namespaceFilter>/<classFilter>/<methodFilter>" --ignore-exit-code 8
2527

2628
# Run unit tests only
27-
dotnet test --filter FullyQualifiedName\~UnitTests
29+
# Use `--ignore-exit-code 8` to avoid failing the build when no tests are found for integration test projects
30+
dotnet test --filter-query "/*UnitTests*/*/*/*" --ignore-exit-code 8
2831
```
2932

3033
Use `--tl:off` when building to avoid flickering when running commands in the agent.
@@ -56,15 +59,15 @@ Example: Running tests for a single project using .NET 10.
5659

5760
```bash
5861
# From dotnet/ directory
59-
dotnet test ./tests/Microsoft.Agents.AI.Abstractions.UnitTests -f net10.0
62+
dotnet test --project ./tests/Microsoft.Agents.AI.Abstractions.UnitTests -f net10.0
6063
```
6164

6265
Example: Running a single test in a specific project using .NET 10.
6366
Provide the full namespace, class name, and method name for the test you want to run:
6467

6568
```bash
6669
# From dotnet/ directory
67-
dotnet test ./tests/Microsoft.Agents.AI.Abstractions.UnitTests -f net10.0 --filter "FullyQualifiedName~Microsoft.Agents.AI.Abstractions.UnitTests.AgentRunOptionsTests.CloningConstructorCopiesProperties"
70+
dotnet test --project ./tests/Microsoft.Agents.AI.Abstractions.UnitTests -f net10.0 --filter-query "/*/Microsoft.Agents.AI.Abstractions.UnitTests/AgentRunOptionsTests/CloningConstructorCopiesProperties"
6871
```
6972

7073
### Multi-target framework tip
@@ -83,3 +86,45 @@ Just remember to run `dotnet restore` after pulling changes, making changes to p
8386
Unit tests target both .NET Framework as well as .NET Core. When running on Linux, only the .NET Core tests can be run, as .NET Framework is not supported on Linux.
8487

8588
To run only the .NET Core tests, use the `-f net10.0` option with `dotnet test`.
89+
90+
### Microsoft Testing Platform (MTP)
91+
92+
Tests use the [Microsoft Testing Platform](https://learn.microsoft.com/dotnet/core/testing/unit-testing-platform-intro) via xUnit v3. Key differences from the legacy VSTest runner:
93+
94+
- **`dotnet test` requires `--project`** to specify a test project directly (positional arguments are no longer supported).
95+
- **Test output** uses the MTP format (e.g., `[✓112/x0/↓0]` progress and `Test run summary: Passed!`).
96+
- **TRX reports** use `--report-xunit-trx` instead of `--logger trx`.
97+
- **Code coverage** uses `Microsoft.Testing.Extensions.CodeCoverage` with `--coverage --coverage-output-format cobertura`.
98+
- **Running a test project directly** is supported via `dotnet run --project <test-project>`. This bypasses the `dotnet test` infrastructure and runs the test executable directly with the MTP command line.
99+
100+
- **Running tests across the solution** with a filter may cause some projects to match zero tests, which MTP treats as a failure (exit code 8). Use `--ignore-exit-code 8` to suppress this:
101+
102+
```bash
103+
# Run all unit tests across the solution, ignoring projects with no matching tests
104+
dotnet test --solution ./agent-framework-dotnet.slnx --no-build -f net10.0 --ignore-exit-code 8
105+
```
106+
107+
- **Running tests with `--solution` for a specific TFM** requires all projects in the solution to support that TFM. Not all projects target every framework (e.g., some are `net10.0`-only). Use `./dotnet/eng/scripts/New-FilteredSolution.ps1` to generate a filtered solution:
108+
109+
```powershell
110+
# Generate a filtered solution for net472 and run tests
111+
$filtered = ./dotnet/eng/scripts/New-FilteredSolution.ps1 -Solution dotnet/agent-framework-dotnet.slnx -TargetFramework net472
112+
dotnet test --solution $filtered --no-build -f net472 --ignore-exit-code 8
113+
114+
# Exclude samples and keep only unit test projects
115+
./dotnet/eng/scripts/New-FilteredSolution.ps1 -Solution dotnet/agent-framework-dotnet.slnx -TargetFramework net10.0 -ExcludeSamples -TestProjectNameFilter "*UnitTests*" -OutputPath dotnet/filtered-unit.slnx
116+
```
117+
118+
```bash
119+
# Run tests via dotnet test (uses MTP under the hood)
120+
dotnet test --project ./tests/Microsoft.Agents.AI.UnitTests -f net10.0
121+
122+
# Run tests with code coverage (Cobertura format)
123+
dotnet test --project ./tests/Microsoft.Agents.AI.UnitTests -f net10.0 --coverage --coverage-output-format cobertura --coverage-settings ./tests/coverage.runsettings
124+
125+
# Run tests directly via dotnet run (MTP native command line)
126+
dotnet run --project ./tests/Microsoft.Agents.AI.UnitTests -f net10.0
127+
128+
# Show MTP command line help
129+
dotnet run --project ./tests/Microsoft.Agents.AI.UnitTests -f net10.0 -- -?
130+
```

dotnet/Directory.Packages.props

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,10 @@
140140
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Condition="'$(TargetFramework)' == 'net10.0'" Version="10.0.0" />
141141
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
142142
<PackageVersion Include="Moq" Version="[4.18.4]" />
143-
<PackageVersion Include="xunit" Version="2.9.3" />
144-
<PackageVersion Include="xunit.abstractions" Version="2.0.3" />
145-
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.3" />
146-
<PackageVersion Include="Xunit.SkippableFact" Version="1.5.23" />
147-
<PackageVersion Include="xretry" Version="1.9.0" />
148-
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
143+
<PackageVersion Include="xunit.v3.mtp-v2" Version="3.2.2" />
144+
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
145+
<PackageVersion Include="xRetry.v3" Version="1.0.0-rc3" />
146+
<PackageVersion Include="Microsoft.Testing.Extensions.CodeCoverage" Version="18.4.1" />
149147
<!-- Symbols -->
150148
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
151149
<!-- Toolset -->

dotnet/agent-framework-dotnet.slnx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,6 @@
313313
</Folder>
314314
<Folder Name="/Solution Items/.github/workflows/">
315315
<File Path="../.github/workflows/dotnet-build-and-test.yml" />
316-
<File Path="../.github/workflows/dotnet-check-coverage.ps1" />
317316
<File Path="../.github/workflows/dotnet-format.yml" />
318317
</Folder>
319318
<Folder Name="/Solution Items/demos/">
@@ -350,6 +349,10 @@
350349
<File Path="eng/MSBuild/Shared.props" />
351350
<File Path="eng/MSBuild/Shared.targets" />
352351
</Folder>
352+
<Folder Name="/Solution Items/eng/scripts/">
353+
<File Path="eng/scripts/dotnet-check-coverage.ps1" />
354+
<File Path="eng/scripts/New-FilteredSolution.ps1" />
355+
</Folder>
353356
<Folder Name="/Solution Items/nuget/">
354357
<File Path="nuget/icon.png" />
355358
<File Path="nuget/nuget-package.props" />

0 commit comments

Comments
 (0)