From 93930eeea4b04d07b134ac30bcce3d4f87b67b4e Mon Sep 17 00:00:00 2001 From: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com> Date: Fri, 20 Feb 2026 16:13:56 -0800 Subject: [PATCH] Created dedicated workflows for integration tests --- .github/workflows/dotnet-build-and-test.yml | 31 ++--- .../workflows/dotnet-integration-tests.yml | 102 ++++++++++++++++ .../workflows/integration-tests-manual.yml | 8 +- .../workflows/python-integration-tests.yml | 112 ++++++++++++++++++ .github/workflows/python-merge-tests.yml | 24 +--- 5 files changed, 227 insertions(+), 50 deletions(-) create mode 100644 .github/workflows/dotnet-integration-tests.yml create mode 100644 .github/workflows/python-integration-tests.yml diff --git a/.github/workflows/dotnet-build-and-test.yml b/.github/workflows/dotnet-build-and-test.yml index ae8dcf5c21..95842e703a 100644 --- a/.github/workflows/dotnet-build-and-test.yml +++ b/.github/workflows/dotnet-build-and-test.yml @@ -7,18 +7,6 @@ name: dotnet-build-and-test on: workflow_dispatch: - workflow_call: - inputs: - checkout-ref: - description: "Git ref to checkout (e.g., a commit SHA from a PR)" - required: false - type: string - default: "" - integration-only: - description: "Run only integration tests (skip unit tests, coverage, and non-integration matrix entries)" - required: false - type: boolean - default: false pull_request: branches: ["main", "feature*"] merge_group: @@ -47,14 +35,11 @@ jobs: contents: read pull-requests: read outputs: - dotnetChanges: ${{ inputs.checkout-ref != '' && 'true' || steps.filter.outputs.dotnet }} - cosmosDbChanges: ${{ inputs.checkout-ref != '' && 'true' || steps.filter.outputs.cosmosdb }} + dotnetChanges: ${{ steps.filter.outputs.dotnet }} + cosmosDbChanges: ${{ steps.filter.outputs.cosmosdb }} steps: - uses: actions/checkout@v6 - with: - ref: ${{ inputs.checkout-ref }} - uses: dorny/paths-filter@v3 - if: ${{ inputs.checkout-ref == '' }} id: filter with: filters: | @@ -76,7 +61,7 @@ jobs: dotnet-build-and-test: needs: paths-filter - if: needs.paths-filter.outputs.dotnetChanges == 'true' && (inputs.integration-only != true || matrix.integration-tests) + if: needs.paths-filter.outputs.dotnetChanges == 'true' strategy: fail-fast: false matrix: @@ -91,7 +76,6 @@ jobs: steps: - uses: actions/checkout@v6 with: - ref: ${{ inputs.checkout-ref }} persist-credentials: false sparse-checkout: | . @@ -125,7 +109,7 @@ jobs: shell: bash # All frameworks are only built for the release configuration, so we only run this step for the release configuration # and dotnet new doesn't support net472 - if: inputs.integration-only != true && matrix.configuration == 'Release' && matrix.targetFramework != 'net472' + if: matrix.configuration == 'Release' && matrix.targetFramework != 'net472' run: | TEMP_DIR=$(mktemp -d) @@ -157,7 +141,6 @@ jobs: rm -rf "$TEMP_DIR" - name: Run Unit Tests - if: inputs.integration-only != true shell: bash run: | export UT_PROJECTS=$(find ./dotnet -type f -name "*.UnitTests.csproj" | tr '\n' ' ') @@ -239,7 +222,7 @@ jobs: # Generate test reports and check coverage - name: Generate test reports - if: inputs.integration-only != true && matrix.targetFramework == env.COVERAGE_FRAMEWORK + if: matrix.targetFramework == env.COVERAGE_FRAMEWORK uses: danielpalme/ReportGenerator-GitHub-Action@5.5.1 with: reports: "./TestResults/Coverage/**/coverage.cobertura.xml" @@ -247,14 +230,14 @@ jobs: reporttypes: "HtmlInline;JsonSummary" - name: Upload coverage report artifact - if: inputs.integration-only != true && matrix.targetFramework == env.COVERAGE_FRAMEWORK + if: matrix.targetFramework == env.COVERAGE_FRAMEWORK uses: actions/upload-artifact@v6 with: name: CoverageReport-${{ matrix.os }}-${{ matrix.targetFramework }}-${{ matrix.configuration }} # Artifact name path: ./TestResults/Reports # Directory containing files to upload - name: Check coverage - if: inputs.integration-only != true && matrix.targetFramework == env.COVERAGE_FRAMEWORK + if: matrix.targetFramework == env.COVERAGE_FRAMEWORK shell: pwsh run: .github/workflows/dotnet-check-coverage.ps1 -JsonReportPath "TestResults/Reports/Summary.json" -CoverageThreshold $env:COVERAGE_THRESHOLD diff --git a/.github/workflows/dotnet-integration-tests.yml b/.github/workflows/dotnet-integration-tests.yml new file mode 100644 index 0000000000..364fb9732d --- /dev/null +++ b/.github/workflows/dotnet-integration-tests.yml @@ -0,0 +1,102 @@ +# +# Dedicated .NET integration tests workflow, called from the manual integration test orchestrator. +# Only runs integration test matrix entries (net10.0 and net472). No unit tests, no coverage. +# + +name: dotnet-integration-tests + +on: + workflow_call: + inputs: + checkout-ref: + description: "Git ref to checkout (e.g., refs/pull/123/head)" + required: true + type: string + +permissions: + contents: read + id-token: write + +jobs: + dotnet-integration-tests: + strategy: + fail-fast: false + matrix: + include: + - { targetFramework: "net10.0", os: "ubuntu-latest", configuration: Release } + - { targetFramework: "net472", os: "windows-latest", configuration: Release } + runs-on: ${{ matrix.os }} + environment: integration + timeout-minutes: 60 + steps: + - uses: actions/checkout@v6 + with: + ref: ${{ inputs.checkout-ref }} + persist-credentials: false + sparse-checkout: | + . + .github + dotnet + python + workflow-samples + + - name: Start Azure Cosmos DB Emulator + if: runner.os == 'Windows' + shell: pwsh + run: | + Write-Host "Launching Azure Cosmos DB Emulator" + Import-Module "$env:ProgramFiles\Azure Cosmos DB Emulator\PSModules\Microsoft.Azure.CosmosDB.Emulator" + Start-CosmosDbEmulator -NoUI -Key "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==" + echo "COSMOS_EMULATOR_AVAILABLE=true" >> $env:GITHUB_ENV + + - name: Setup dotnet + uses: actions/setup-dotnet@v5.1.0 + with: + global-json-file: ${{ github.workspace }}/dotnet/global.json + + - name: Build dotnet solutions + shell: bash + run: | + export SOLUTIONS=$(find ./dotnet/ -type f -name "*.slnx" | tr '\n' ' ') + for solution in $SOLUTIONS; do + dotnet build $solution -c ${{ matrix.configuration }} --warnaserror + done + + - 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 + if: matrix.os == 'ubuntu-latest' + uses: ./.github/actions/azure-functions-integration-setup + + - name: Run Integration Tests + shell: bash + run: | + export INTEGRATION_TEST_PROJECTS=$(find ./dotnet -type f -name "*IntegrationTests.csproj" | tr '\n' ' ') + for project in $INTEGRATION_TEST_PROJECTS; do + target_frameworks=$(dotnet msbuild $project -getProperty:TargetFrameworks -p:Configuration=${{ matrix.configuration }} -nologo 2>/dev/null | tr -d '\r') + if [[ "$target_frameworks" == *"${{ matrix.targetFramework }}"* ]]; then + dotnet test -f ${{ matrix.targetFramework }} -c ${{ matrix.configuration }} $project --no-build -v Normal --logger trx --filter "Category!=IntegrationDisabled" + else + echo "Skipping $project - does not support target framework ${{ matrix.targetFramework }} (supports: $target_frameworks)" + fi + done + env: + COSMOSDB_ENDPOINT: https://localhost:8081 + COSMOSDB_KEY: C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw== + OpenAI__ApiKey: ${{ secrets.OPENAI__APIKEY }} + OpenAI__ChatModelId: ${{ vars.OPENAI__CHATMODELID }} + OpenAI__ChatReasoningModelId: ${{ vars.OPENAI__CHATREASONINGMODELID }} + AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }} + AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }} + AzureAI__Endpoint: ${{ secrets.AZUREAI__ENDPOINT }} + AzureAI__DeploymentName: ${{ vars.AZUREAI__DEPLOYMENTNAME }} + AzureAI__BingConnectionId: ${{ vars.AZUREAI__BINGCONECTIONID }} + FOUNDRY_PROJECT_ENDPOINT: ${{ vars.FOUNDRY_PROJECT_ENDPOINT }} + FOUNDRY_MEDIA_DEPLOYMENT_NAME: ${{ vars.FOUNDRY_MEDIA_DEPLOYMENT_NAME }} + FOUNDRY_MODEL_DEPLOYMENT_NAME: ${{ vars.FOUNDRY_MODEL_DEPLOYMENT_NAME }} + FOUNDRY_CONNECTION_GROUNDING_TOOL: ${{ vars.FOUNDRY_CONNECTION_GROUNDING_TOOL }} diff --git a/.github/workflows/integration-tests-manual.yml b/.github/workflows/integration-tests-manual.yml index 28866c39ff..d3d617fa68 100644 --- a/.github/workflows/integration-tests-manual.yml +++ b/.github/workflows/integration-tests-manual.yml @@ -2,7 +2,7 @@ # This workflow allows manually running integration tests against an open PR or a branch. # Go to Actions → "Integration Tests (Manual)" → Run workflow → enter a PR number or branch name. # -# It reuses the existing dotnet-build-and-test and python-merge-tests workflows, +# It calls dedicated integration-only workflows (dotnet-integration-tests and python-integration-tests), # passing a ref so they check out and test the correct code. # Changed paths are detected here so only the relevant test suites run. # @@ -119,18 +119,16 @@ jobs: name: .NET Integration Tests needs: resolve-ref if: needs.resolve-ref.outputs.dotnet-changes == 'true' - uses: ./.github/workflows/dotnet-build-and-test.yml + uses: ./.github/workflows/dotnet-integration-tests.yml with: checkout-ref: ${{ needs.resolve-ref.outputs.checkout-ref }} - integration-only: true secrets: inherit python-integration-tests: name: Python Integration Tests needs: resolve-ref if: needs.resolve-ref.outputs.python-changes == 'true' - uses: ./.github/workflows/python-merge-tests.yml + uses: ./.github/workflows/python-integration-tests.yml with: checkout-ref: ${{ needs.resolve-ref.outputs.checkout-ref }} - integration-only: true secrets: inherit diff --git a/.github/workflows/python-integration-tests.yml b/.github/workflows/python-integration-tests.yml new file mode 100644 index 0000000000..7897cb6fe6 --- /dev/null +++ b/.github/workflows/python-integration-tests.yml @@ -0,0 +1,112 @@ +# +# Dedicated Python integration tests workflow, called from the manual integration test orchestrator. +# Only runs integration tests (core + Azure AI). No sample tests, no paths filtering. +# + +name: python-integration-tests + +on: + workflow_call: + inputs: + checkout-ref: + description: "Git ref to checkout (e.g., refs/pull/123/head)" + required: true + type: string + +permissions: + contents: read + id-token: write + +env: + UV_CACHE_DIR: /tmp/.uv-cache + +jobs: + python-tests-core: + name: Python Integration Tests - Core + runs-on: ubuntu-latest + environment: integration + timeout-minutes: 60 + env: + UV_PYTHON: "3.10" + OPENAI_CHAT_MODEL_ID: ${{ vars.OPENAI__CHATMODELID }} + OPENAI_RESPONSES_MODEL_ID: ${{ vars.OPENAI__RESPONSESMODELID }} + OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }} + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + ANTHROPIC_CHAT_MODEL_ID: ${{ vars.ANTHROPIC_CHAT_MODEL_ID }} + AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }} + AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} + AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }} + LOCAL_MCP_URL: ${{ vars.LOCAL_MCP__URL }} + FUNCTIONS_WORKER_RUNTIME: "python" + DURABLE_TASK_SCHEDULER_CONNECTION_STRING: "Endpoint=http://localhost:8080;TaskHub=default;Authentication=None" + AzureWebJobsStorage: "UseDevelopmentStorage=true" + defaults: + run: + working-directory: python + steps: + - uses: actions/checkout@v6 + with: + ref: ${{ inputs.checkout-ref }} + + - name: Set up python and install the project + id: python-setup + uses: ./.github/actions/python-setup + with: + python-version: "3.10" + os: ${{ runner.os }} + env: + UV_CACHE_DIR: /tmp/.uv-cache + + - 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 Azure Functions Integration Test Emulators + uses: ./.github/actions/azure-functions-integration-setup + id: azure-functions-setup + + - name: Test with pytest + run: uv run poe all-tests -n logical --dist loadfile --dist worksteal --timeout=120 --session-timeout=900 --timeout_method thread --retries 2 --retry-delay 5 + working-directory: ./python + + python-tests-azure-ai: + name: Python Integration Tests - Azure AI + runs-on: ubuntu-latest + environment: integration + timeout-minutes: 60 + env: + UV_PYTHON: "3.10" + AZURE_AI_PROJECT_ENDPOINT: ${{ secrets.AZUREAI__ENDPOINT }} + AZURE_AI_MODEL_DEPLOYMENT_NAME: ${{ vars.AZUREAI__DEPLOYMENTNAME }} + LOCAL_MCP_URL: ${{ vars.LOCAL_MCP__URL }} + defaults: + run: + working-directory: python + steps: + - uses: actions/checkout@v6 + with: + ref: ${{ inputs.checkout-ref }} + + - name: Set up python and install the project + id: python-setup + uses: ./.github/actions/python-setup + with: + python-version: "3.10" + os: ${{ runner.os }} + env: + UV_CACHE_DIR: /tmp/.uv-cache + + - 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: Test with pytest + timeout-minutes: 15 + run: uv run --directory packages/azure-ai poe integration-tests -n logical --dist loadfile --dist worksteal --timeout=120 --session-timeout=900 --timeout_method thread --retries 2 --retry-delay 5 + working-directory: ./python diff --git a/.github/workflows/python-merge-tests.yml b/.github/workflows/python-merge-tests.yml index 3ac5cf6846..8c0a0189c1 100644 --- a/.github/workflows/python-merge-tests.yml +++ b/.github/workflows/python-merge-tests.yml @@ -2,18 +2,6 @@ name: Python - Merge - Tests on: workflow_dispatch: - workflow_call: - inputs: - checkout-ref: - description: "Git ref to checkout (e.g., a commit SHA from a PR)" - required: false - type: string - default: "" - integration-only: - description: "Run only integration tests (skip sample tests)" - required: false - type: boolean - default: false pull_request: branches: ["main"] merge_group: @@ -38,12 +26,10 @@ jobs: contents: read pull-requests: read outputs: - pythonChanges: ${{ inputs.checkout-ref != '' && 'true' || steps.filter.outputs.python }} + pythonChanges: ${{ steps.filter.outputs.python }} steps: - uses: actions/checkout@v6 - if: ${{ inputs.checkout-ref == '' }} - uses: dorny/paths-filter@v3 - if: ${{ inputs.checkout-ref == '' }} id: filter with: filters: | @@ -90,8 +76,6 @@ jobs: working-directory: python steps: - uses: actions/checkout@v6 - with: - ref: ${{ inputs.checkout-ref }} - name: Set up python and install the project id: python-setup uses: ./.github/actions/python-setup @@ -116,7 +100,7 @@ jobs: working-directory: ./python - name: Test core samples timeout-minutes: 10 - if: inputs.integration-only != true && env.RUN_SAMPLES_TESTS == 'true' + if: env.RUN_SAMPLES_TESTS == 'true' run: uv run pytest tests/samples/ -m "openai" -m "azure" working-directory: ./python - name: Surface failing tests @@ -151,8 +135,6 @@ jobs: working-directory: python steps: - uses: actions/checkout@v6 - with: - ref: ${{ inputs.checkout-ref }} - name: Set up python and install the project id: python-setup uses: ./.github/actions/python-setup @@ -175,7 +157,7 @@ jobs: working-directory: ./python - name: Test Azure AI samples timeout-minutes: 10 - if: inputs.integration-only != true && env.RUN_SAMPLES_TESTS == 'true' + if: env.RUN_SAMPLES_TESTS == 'true' run: uv run pytest tests/samples/ -m "azure-ai" working-directory: ./python - name: Surface failing tests