Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 120 additions & 10 deletions .github/workflows/dotnet-build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ jobs:
dotnetChanges: ${{ steps.filter.outputs.dotnet }}
cosmosDbChanges: ${{ steps.filter.outputs.cosmosdb }}
foundryHostingChanges: ${{ steps.filter.outputs.foundryHosting }}
functionsChanged: ${{ steps.filter.outputs.functions }}
coreChanged: ${{ steps.filter.outputs.core }}
steps:
- uses: actions/checkout@v6
- uses: dorny/paths-filter@v3
Expand All @@ -63,6 +65,22 @@ jobs:
- 'dotnet/Directory.Packages.props'
- 'dotnet/tests/Foundry.Hosting.IntegrationTests/scripts/it-build-image.ps1'
- '.github/workflows/dotnet-build-and-test.yml'
functions:
- 'dotnet/src/Microsoft.Agents.AI.DurableTask/**'
- 'dotnet/src/Microsoft.Agents.AI.Hosting.AzureFunctions/**'
- 'dotnet/tests/Microsoft.Agents.AI.DurableTask.IntegrationTests/**'
- 'dotnet/tests/Microsoft.Agents.AI.Hosting.AzureFunctions.IntegrationTests/**'
- '.github/actions/azure-functions-integration-setup/**'
core:
- 'dotnet/src/Microsoft.Agents.AI/**'
- 'dotnet/src/Microsoft.Agents.AI.Abstractions/**'
- 'dotnet/src/Microsoft.Agents.AI.OpenAI/**'
- 'dotnet/src/Microsoft.Agents.AI.Workflows/**'
- 'dotnet/src/Microsoft.Agents.AI.Workflows.Generators/**'
- 'dotnet/eng/scripts/New-FilteredSolution.ps1'
- 'dotnet/tests/Directory.Build.props'
- 'dotnet/Directory.Packages.props'
- 'dotnet/global.json'
# run only if 'dotnet' files were changed
- name: dotnet tests
if: steps.filter.outputs.dotnet == 'true'
Expand Down Expand Up @@ -214,6 +232,7 @@ jobs:
-OutputPath dotnet/filtered-unit.slnx
./dotnet/eng/scripts/New-FilteredSolution.ps1 @commonArgs `
-TestProjectNameFilter "*IntegrationTests*" `
-TestProjectNameExclude "*DurableTask.IntegrationTests*","*AzureFunctions.IntegrationTests*" `
-OutputPath dotnet/filtered-integration.slnx

- name: Run Unit Tests
Expand Down Expand Up @@ -255,14 +274,6 @@ jobs:
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

# This setup action is required for both Durable Task and Azure Functions integration tests.
# We only run it on Ubuntu since the Durable Task and Azure Functions features are not available
# on .NET Framework (net472) which is what we use the Windows runner for.
- name: Set up Durable Task and Azure Functions Integration Test Emulators
if: github.event_name != 'pull_request' && matrix.integration-tests && matrix.os == 'ubuntu-latest'
uses: ./.github/actions/azure-functions-integration-setup
id: azure-functions-setup

- name: Run Integration Tests
shell: pwsh
working-directory: dotnet
Expand Down Expand Up @@ -428,11 +439,110 @@ jobs:
AZURE_AI_MODEL_DEPLOYMENT_NAME: ${{ vars.IT_HOSTED_AGENT_MODEL_DEPLOYMENT_NAME }}
# IT_HOSTED_AGENT_IMAGE was exported into $GITHUB_ENV by the previous step.

# DurableTask and AzureFunctions integration tests (ubuntu/net10.0 only).
# Split from main dotnet-test job for path-based filtering and parallelism.
dotnet-test-functions:
needs: [paths-filter]
if: >
github.event_name != 'pull_request' &&
(needs.paths-filter.outputs.functionsChanged == 'true' ||
needs.paths-filter.outputs.coreChanged == 'true' ||
github.event_name == 'schedule' ||
github.event_name == 'workflow_dispatch')
Comment thread
giles17 marked this conversation as resolved.
runs-on: ubuntu-latest
environment: integration
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
sparse-checkout: |
.
.github
dotnet
python
declarative-agents

- name: Setup dotnet
uses: actions/setup-dotnet@v5.2.0
with:
global-json-file: ${{ github.workspace }}/dotnet/global.json

- name: Build functions integration test projects
shell: bash
working-directory: dotnet
run: |
dotnet build ./tests/Microsoft.Agents.AI.DurableTask.IntegrationTests -c Release -f net10.0 --warnaserror
dotnet build ./tests/Microsoft.Agents.AI.Hosting.AzureFunctions.IntegrationTests -c Release -f net10.0 --warnaserror

- name: Azure CLI Login
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

- name: Set up Durable Task and Azure Functions Integration Test Emulators
uses: ./.github/actions/azure-functions-integration-setup
id: azure-functions-setup

- name: Run Functions Integration Tests
shell: pwsh
working-directory: dotnet
run: |
# Run DurableTask integration tests
dotnet test `
--project ./tests/Microsoft.Agents.AI.DurableTask.IntegrationTests `
-f net10.0 `
-c Release `
--no-build -v Normal `
--report-xunit-trx `
--report-junit `
--results-directory ../IntegrationTestResults/ `
--ignore-exit-code 8 `
--filter-not-trait "Category=IntegrationDisabled" `
--parallel-algorithm aggressive `
--max-threads 2.0x

# Run AzureFunctions integration tests
dotnet test `
--project ./tests/Microsoft.Agents.AI.Hosting.AzureFunctions.IntegrationTests `
-f net10.0 `
-c Release `
--no-build -v Normal `
--report-xunit-trx `
--report-junit `
--results-directory ../IntegrationTestResults/ `
--ignore-exit-code 8 `
--filter-not-trait "Category=IntegrationDisabled" `
--parallel-algorithm aggressive `
--max-threads 2.0x
env:
# OpenAI Models
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENAI_CHAT_MODEL_NAME: ${{ vars.OPENAI_CHAT_MODEL_NAME }}
OPENAI_REASONING_MODEL_NAME: ${{ vars.OPENAI_REASONING_MODEL_NAME }}
# Azure OpenAI Models
AZURE_OPENAI_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_DEPLOYMENT_NAME }}
AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_DEPLOYMENT_NAME }}
AZURE_OPENAI_ENDPOINT: ${{ vars.AZURE_OPENAI_ENDPOINT }}
# Azure AI Foundry
AZURE_AI_PROJECT_ENDPOINT: ${{ vars.AZURE_AI_PROJECT_ENDPOINT }}
AZURE_AI_MODEL_DEPLOYMENT_NAME: ${{ vars.AZURE_AI_MODEL_DEPLOYMENT_NAME }}
AZURE_AI_BING_CONNECTION_ID: ${{ vars.AZURE_AI_BING_CONNECTION_ID }}

- name: Upload functions test results
if: always()
uses: actions/upload-artifact@v7
with:
name: dotnet-test-results-functions-net10.0-ubuntu-latest
path: IntegrationTestResults/**/*.junit
if-no-files-found: ignore

# This final job is required to satisfy the merge queue. It must only run (or succeed) if no tests failed
dotnet-build-and-test-check:
if: always()
runs-on: ubuntu-latest
needs: [dotnet-build, dotnet-test, dotnet-foundry-hosted-it]
needs: [dotnet-build, dotnet-test, dotnet-foundry-hosted-it, dotnet-test-functions]
steps:
- name: Get Date
shell: bash
Expand Down Expand Up @@ -479,7 +589,7 @@ jobs:
github.event_name != 'pull_request' &&
(contains(join(needs.*.result, ','), 'success') ||
contains(join(needs.*.result, ','), 'failure'))
needs: [dotnet-test]
needs: [dotnet-test, dotnet-test-functions]
runs-on: ubuntu-latest
defaults:
run:
Expand Down
2 changes: 1 addition & 1 deletion dotnet/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</PropertyGroup>
<ItemGroup>
<!-- Aspire.* -->
<PackageVersion Include="Anthropic" Version="12.13.0" />
<PackageVersion Include="Anthropic" Version="12.20.0" />
<PackageVersion Include="Anthropic.Foundry" Version="0.5.0" />
<PackageVersion Include="Aspire.Hosting" Version="$(AspireAppHostSdkVersion)" />
<PackageVersion Include="Aspire.Azure.AI.OpenAI" Version="13.0.0-preview.1.25560.3" />
Expand Down
28 changes: 28 additions & 0 deletions dotnet/eng/scripts/New-FilteredSolution.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
Optional wildcard pattern to filter test project names (e.g., *UnitTests*, *IntegrationTests*).
When specified, only test projects whose filename matches this pattern are kept.

.PARAMETER TestProjectNameExclude
Optional wildcard pattern(s) to exclude test projects by name (e.g., *DurableTask.IntegrationTests*).
When specified, test projects whose filename matches any of these patterns are removed.
Applied after TestProjectNameFilter. Can be a single string or an array of strings.

.PARAMETER ExcludeSamples
When specified, removes all projects under the samples/ directory from the solution.

Expand All @@ -43,6 +48,10 @@
.EXAMPLE
# Inline usage with dotnet test (PowerShell)
dotnet test --solution (./dotnet/eng/scripts/New-FilteredSolution.ps1 -Solution dotnet/agent-framework-dotnet.slnx -TargetFramework net472) --no-build -f net472

.EXAMPLE
# Generate integration tests excluding DurableTask and AzureFunctions
./dotnet/eng/scripts/New-FilteredSolution.ps1 -Solution dotnet/agent-framework-dotnet.slnx -TargetFramework net10.0 -TestProjectNameFilter "*IntegrationTests*" -TestProjectNameExclude "*DurableTask.IntegrationTests*","*AzureFunctions.IntegrationTests*" -OutputPath filtered-other-integration.slnx
#>

[CmdletBinding()]
Expand All @@ -57,6 +66,8 @@ param(

[string]$TestProjectNameFilter,

[string[]]$TestProjectNameExclude,

[switch]$ExcludeSamples,

[string]$OutputPath
Expand Down Expand Up @@ -107,6 +118,23 @@ foreach ($proj in $allProjects) {
continue
}

# Exclude test projects matching any exclusion pattern
if ($isTestProject -and $TestProjectNameExclude) {
$excluded = $false
foreach ($pattern in $TestProjectNameExclude) {
if ($projFileName -like $pattern) {
$excluded = $true
break
}
}
if ($excluded) {
Write-Verbose "Removing (exclude filter): $projRelPath"
$removed += $projRelPath
$proj.ParentNode.RemoveChild($proj) | Out-Null
continue
}
}

if (-not (Test-Path $projFullPath)) {
Write-Verbose "Project not found, keeping in solution: $projRelPath"
$kept += $projRelPath
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<RootNamespace>Microsoft.Agents.AI</RootNamespace>
<NoWarn>$(NoWarn);MEAI001</NoWarn>
<NoWarn>$(NoWarn);MEAI001;RT0003</NoWarn>
<IsReleased>true</IsReleased>
</PropertyGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,6 @@ public Task DeleteSessionAsync(AgentSession session) =>

public async ValueTask InitializeAsync()
{
// Temporarily disabled: Anthropic SDK has a binary incompatibility with the current
// Microsoft.Extensions.AI version (WebSearchToolResultContent.Results method not found).
// See: https://github.com/microsoft/agent-framework/pull/5515
Assert.Skip("Anthropic integration tests temporarily disabled due to SDK incompatibility with Microsoft.Extensions.AI");

try
{
_ = TestConfiguration.GetRequiredValue(TestSettings.AnthropicApiKey);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@ namespace AnthropicChatCompletion.IntegrationTests;
/// Integration tests for Anthropic Skills functionality.
/// These tests are designed to be run locally with a valid Anthropic API key.
/// </summary>
/// <remarks>
/// Temporarily disabled due to Anthropic SDK binary incompatibility with
/// the current Microsoft.Extensions.AI version (WebSearchToolResultContent.Results).
/// </remarks>
[Trait("Category", "IntegrationDisabled")]
public sealed class AnthropicSkillsIntegrationTests
{
[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ and report the SECRET_NUMBER value it prints. Respond only with the number.
/// invokes the server-side OpenAPI function through <c>RunAsync</c>.
/// Regression test for https://github.com/microsoft/agent-framework/issues/4883.
/// </summary>
[RetryFact(Constants.RetryCount, Constants.RetryDelay, Skip = "For manual testing only")]
[RetryFact(Constants.RetryCount, Constants.RetryDelay)]
public async Task AsAIAgent_WithOpenAPITool_NativeSDKCreation_InvokesServerSideToolAsync()
{
// Arrange — create agent version with OpenAPI tool using native Azure.AI.Projects SDK types.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,8 @@ public TestAnthropicChatClient()

public IBetaService Beta => this.BetaService;

public string? WebhookKey { get => throw new NotImplementedException(); init => throw new NotImplementedException(); }

public IBetaService BetaService { get; }

IMessageService IAnthropicClient.Messages => new Mock<IMessageService>().Object;
Expand Down Expand Up @@ -491,6 +493,12 @@ public TestBetaService(IAnthropicClient client)

public global::Anthropic.Services.Beta.IVaultService Vaults => throw new NotImplementedException();

public global::Anthropic.Services.Beta.IMemoryStoreService MemoryStores => throw new NotImplementedException();

public global::Anthropic.Services.Beta.IWebhookService Webhooks => throw new NotImplementedException();

public global::Anthropic.Services.Beta.IUserProfileService UserProfiles => throw new NotImplementedException();

public IBetaService WithOptions(Func<ClientOptions, ClientOptions> modifier)
{
throw new NotImplementedException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ public TestAnthropicChatClient()

public IBetaService Beta => throw new NotImplementedException();

public string? WebhookKey { get => throw new NotImplementedException(); init => throw new NotImplementedException(); }

public IAnthropicClient WithOptions(Func<ClientOptions, ClientOptions> modifier)
{
throw new NotImplementedException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests;
public sealed class DeclarativeCodeGenTest(ITestOutputHelper output) : WorkflowTest(output)
{
[Theory]
[InlineData("CheckSystem.yaml", "CheckSystem.json", Skip = "Temporarily skipped")]
[InlineData("CheckSystem.yaml", "CheckSystem.json")]
[InlineData("SendActivity.yaml", "SendActivity.json")]
[InlineData("InvokeAgent.yaml", "InvokeAgent.json")]
[InlineData("InvokeAgent.yaml", "InvokeAgent.json", true)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests;
public sealed class DeclarativeWorkflowTest(ITestOutputHelper output) : WorkflowTest(output)
{
[Theory]
[InlineData("CheckSystem.yaml", "CheckSystem.json", Skip = "Temporarily skipped")]
[InlineData("CheckSystem.yaml", "CheckSystem.json")]
[InlineData("ConversationMessages.yaml", "ConversationMessages.json")]
[InlineData("ConversationMessages.yaml", "ConversationMessages.json", true)]
[InlineData("InputArguments.yaml", "InputArguments.json")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
"conversation_count": 1,
"min_action_count": 2,
"max_action_count": -1,
"min_response_count": 0,
"min_response_count": 1,
"max_response_count": 1,
"min_message_count": 0,
"max_message_count": 0,
"actions": {
"start": [
"check_system"
Expand Down
Loading