Repository navigation
Fix command admission and native verification #207
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and Tests | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| workflow_dispatch: | |
| inputs: | |
| mode: | |
| description: 'Select full qualification or sequential functional database gates' | |
| type: choice | |
| default: all | |
| options: [all, functional-gates] | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: keyload-build-tests-${{ github.event_name == 'pull_request' && github.ref || github.run_id }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| jobs: | |
| repository-checks: | |
| name: Check repository rules | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Download source code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Check repository rules | |
| run: node scripts/Features/RepositoryGovernance/verify.mjs | |
| analyzer-rules: | |
| name: Test code analyzers | |
| if: ${{ github.event_name != 'workflow_dispatch' || inputs.mode == 'all' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Download source code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Set up .NET | |
| uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 | |
| with: | |
| global-json-file: global.json | |
| - name: Restore .NET packages | |
| run: dotnet restore KeyLoad.slnx | |
| - name: Build analyzer tests | |
| run: | | |
| dotnet build build/KeyLoad.AppHost --no-restore -warnaserror | |
| dotnet build tests/KeyLoad.Analyzers.Tests --no-restore -warnaserror | |
| - name: Prepare source-bound analyzer coverage | |
| shell: pwsh | |
| run: | | |
| $root = $env:GITHUB_WORKSPACE | |
| $evidence = Join-Path $root 'artifacts/code-quality/analyzer-coverage' | |
| New-Item -ItemType Directory -Path $evidence -Force | Out-Null | |
| Copy-Item scripts/Features/CodeQuality/site-analyzer-coverage.settings.xml (Join-Path $evidence 'coverage.config.xml') | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/site-analyzer-coverage.ps1 ` | |
| -Mode Prepare -Repository $root ` | |
| -Contract (Join-Path $root 'scripts/Features/CodeQuality/site-analyzer-coverage.contract.json') ` | |
| -EvidenceRoot $evidence | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| - name: Run analyzer tests | |
| id: analyzers | |
| run: | | |
| node scripts/Features/TestInfrastructure/run-tests.mjs --KeyLoadTests:Suite=analyzers --KeyLoadTests:ResultsDirectory=TestResults/analyzers --KeyLoadTests:ReportTrx=true "--KeyLoadTests:CoverageSettings=$GITHUB_WORKSPACE/artifacts/code-quality/analyzer-coverage/coverage.config.xml" "--KeyLoadTests:CoverageOutput=$GITHUB_WORKSPACE/artifacts/code-quality/analyzer-coverage/coverage.cobertura.xml" | |
| - name: Verify every analyzer test passed | |
| if: ${{ !cancelled() && steps.analyzers.outcome != 'skipped' }} | |
| shell: pwsh | |
| run: | | |
| $root = $env:GITHUB_WORKSPACE | |
| $files = @(Get-ChildItem -LiteralPath (Join-Path $root 'TestResults/analyzers') -Filter '*.trx' -File) | |
| if ($files.Count -ne 1) { throw 'Expected exactly one analyzer TRX receipt' } | |
| [xml]$document = Get-Content -LiteralPath $files[0].FullName -Raw | |
| $counts = $document.TestRun.ResultSummary.Counters | |
| if ([int]$counts.total -le 0 -or [int]$counts.executed -ne [int]$counts.total -or | |
| [int]$counts.passed -ne [int]$counts.total) { | |
| throw 'Incomplete or failing analyzer qualification; skipped tests cannot pass' | |
| } | |
| [ordered]@{ | |
| sourceRevision = $env:GITHUB_SHA | |
| total = [int]$counts.total | |
| executed = [int]$counts.executed | |
| passed = [int]$counts.passed | |
| sha256 = (Get-FileHash -LiteralPath $files[0].FullName -Algorithm SHA256).Hash.ToLowerInvariant() | |
| } | ConvertTo-Json | Set-Content -LiteralPath (Join-Path $root 'artifacts/code-quality/analyzer-coverage/test-receipt.json') -Encoding utf8NoBOM | |
| - name: Verify source-bound analyzer coverage | |
| if: ${{ !cancelled() && steps.analyzers.outcome != 'skipped' }} | |
| shell: pwsh | |
| run: | | |
| $root = $env:GITHUB_WORKSPACE | |
| $evidence = Join-Path $root 'artifacts/code-quality/analyzer-coverage' | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/site-analyzer-coverage.ps1 ` | |
| -Mode Verify -Repository $root ` | |
| -Contract (Join-Path $root 'scripts/Features/CodeQuality/site-analyzer-coverage.contract.json') ` | |
| -EvidenceRoot $evidence -CoverageReport (Join-Path $evidence 'coverage.cobertura.xml') | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| - name: Save analyzer test results | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: always() | |
| with: | |
| name: analyzer-rule-evidence | |
| path: | | |
| TestResults/** | |
| tests/KeyLoad.Analyzers.Tests/**/TestResults/** | |
| artifacts/code-quality/** | |
| if-no-files-found: error | |
| verify: | |
| name: Build and test KeyLoad | |
| if: ${{ github.event_name != 'workflow_dispatch' || inputs.mode == 'all' }} | |
| needs: repository-checks | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-24.04] | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 120 | |
| steps: | |
| - name: Download source code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up .NET | |
| uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 | |
| with: | |
| global-json-file: global.json | |
| - name: Restore .NET packages | |
| run: dotnet restore KeyLoad.slnx | |
| - name: Build KeyLoad | |
| id: build | |
| run: dotnet build KeyLoad.slnx --no-restore -warnaserror | |
| - name: Prepare native source and native test assembly identity receipts | |
| id: native-source-identity | |
| if: ${{ !cancelled() && steps.build.outcome == 'success' }} | |
| shell: pwsh | |
| run: | | |
| $root = $env:GITHUB_WORKSPACE | |
| $evidence = Join-Path $root 'TestResults/native-source-identity' | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.production-source-manifest.ps1 ` | |
| -Mode prepare -Root $root -EvidenceRoot $evidence | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| - name: Verify the pinned native full-text package | |
| run: | | |
| node --input-type=module <<'JS' | |
| import fs from 'node:fs'; | |
| import path from 'node:path'; | |
| import crypto from 'node:crypto'; | |
| import { execFileSync, spawnSync } from 'node:child_process'; | |
| const cache = execFileSync('dotnet', ['nuget', 'locals', 'global-packages', '--list'], { encoding: 'utf8' }).trim(); | |
| const prefix = 'global-packages: '; | |
| if (!cache.startsWith(prefix) || cache.includes('\n')) throw new Error('Ambiguous NuGet package cache.'); | |
| const packagePath = path.join(cache.slice(prefix.length), 'zonetree.fulltextsearch', '1.0.9', 'zonetree.fulltextsearch.1.0.9.nupkg'); | |
| const digest = crypto.createHash('sha256').update(fs.readFileSync(packagePath)).digest('hex'); | |
| if (digest !== '7ea1fbb7aba0ad00391d78d2f414166b500335f5b1affe43c305d861b55719ff') throw new Error('Native FTS package differs from ADR-078.'); | |
| const verification = spawnSync('dotnet', ['nuget', 'verify', packagePath, '--all'], { encoding: 'utf8', maxBuffer: 1048576 }); | |
| fs.mkdirSync('artifacts/qualification', { recursive: true }); | |
| fs.writeFileSync('artifacts/qualification/native-full-text-package-signature.log', `Package SHA256: ${digest}\n${verification.stdout ?? ''}${verification.stderr ?? ''}`); | |
| process.stdout.write(verification.stdout ?? ''); | |
| process.stderr.write(verification.stderr ?? ''); | |
| if (verification.error || verification.status !== 0) throw verification.error ?? new Error('Native FTS package signature verification failed.'); | |
| JS | |
| - name: Build current Debug analyzer for native formatting | |
| run: dotnet build analyzers/KeyLoad.Analyzers/KeyLoad.Analyzers.csproj --no-restore --configuration Debug -warnaserror | |
| - name: Check code formatting | |
| run: dotnet format KeyLoad.slnx --verify-no-changes --no-restore | |
| - name: Check repository rules | |
| run: node scripts/Features/RepositoryGovernance/verify.mjs | |
| - name: Test native coverage source ownership | |
| id: source-ownership | |
| run: node scripts/Features/TestInfrastructure/run-tests.mjs --KeyLoadTests:Suite=unit '--KeyLoadTests:Filter=/*/*/(NativePathMapCompilerTests)|(ProductionSourceManifestSettlementTests)|(NativeSourceManifestChildSettlementTests)|(ProductionSourceManifestOperationTests)/*' --KeyLoadTests:ResultsDirectory=TestResults/native-source-ownership --KeyLoadTests:ReportTrx=true | |
| - name: Verify original source ownership test receipt | |
| if: ${{ !cancelled() && steps.source-ownership.outcome != 'skipped' }} | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| Set-StrictMode -Version Latest | |
| $reports = @(Get-ChildItem TestResults/native-source-ownership -Filter '*.trx' -Recurse -File) | |
| if ($reports.Count -ne 1) { throw 'Exactly one original source ownership TRX is required.' } | |
| [xml] $trx = Get-Content -LiteralPath $reports[0].FullName -Raw | |
| $counters = $trx.TestRun.ResultSummary.Counters | |
| if ([int] $counters.total -ne 10 -or [int] $counters.executed -ne 10 -or | |
| [int] $counters.passed -ne 10 -or [int] $counters.failed -ne 0) { | |
| throw 'Every native source ownership case must execute and pass.' | |
| } | |
| $receipt = [ordered]@{ | |
| source = $env:GITHUB_SHA; total = 10; executed = 10; passed = 10 | |
| originalTrxSha256 = (Get-FileHash -LiteralPath $reports[0].FullName -Algorithm SHA256).Hash.ToLowerInvariant() | |
| } | |
| $receipt | ConvertTo-Json | Set-Content TestResults/native-source-ownership/test-receipt.json | |
| - name: Run unit tests | |
| if: ${{ !cancelled() && steps.build.outcome == 'success' }} | |
| run: node scripts/Features/TestInfrastructure/run-tests.mjs --KeyLoadTests:Suite=unit --KeyLoadTests:ReportTrx=true | |
| - name: Test recovery after process crashes | |
| if: ${{ !cancelled() && steps.build.outcome == 'success' }} | |
| run: node scripts/Features/TestInfrastructure/run-tests.mjs --KeyLoadTests:Suite=recovery --KeyLoadTests:ReportTrx=true | |
| - name: Verify native source and native test assembly identity receipts | |
| if: ${{ !cancelled() && steps.build.outcome == 'success' && steps.native-source-identity.outcome == 'success' }} | |
| shell: pwsh | |
| run: | | |
| $root = $env:GITHUB_WORKSPACE | |
| $evidence = Join-Path $root 'TestResults/native-source-identity' | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.production-source-manifest.ps1 ` | |
| -Mode verify -Root $root -EvidenceRoot $evidence | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| - name: Save test results | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: always() | |
| with: | |
| name: test-results-${{ matrix.os }} | |
| path: | | |
| **/TestResults/** | |
| artifacts/qualification/** | |
| if-no-files-found: ignore | |
| - name: Save build diagnostics | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: always() | |
| with: | |
| name: code-quality-${{ matrix.os }} | |
| path: artifacts/code-quality/** | |
| if-no-files-found: error | |
| aspire-cluster: | |
| name: ${{ inputs.mode == 'functional-gates' && 'Test functional database gates (one then three nodes)' || 'Test three-node database' }} | |
| if: ${{ github.event_name != 'workflow_dispatch' || inputs.mode == 'all' || inputs.mode == 'functional-gates' }} | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 180 | |
| steps: | |
| - name: Download source code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Set up .NET | |
| uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 | |
| with: | |
| global-json-file: global.json | |
| - name: Check Docker for Azurite | |
| run: docker version | |
| - name: Find Chrome for admin tests | |
| shell: bash | |
| run: | | |
| admin_chrome=$(command -v google-chrome || command -v google-chrome-stable || command -v chromium || command -v chromium-browser) | |
| test -n "$admin_chrome" && test -x "$admin_chrome" | |
| "$admin_chrome" --version | |
| printf 'KEYLOAD_ADMIN_CHROME_PATH=%s\n' "$admin_chrome" >> "$GITHUB_ENV" | |
| - name: Restore .NET packages | |
| run: dotnet restore KeyLoad.slnx | |
| - name: Build the complete native coverage cohort | |
| run: dotnet build KeyLoad.slnx --no-restore -warnaserror | |
| - name: Prepare original source and native test assembly receipts | |
| id: coverage-source | |
| shell: pwsh | |
| run: | | |
| $root = $env:GITHUB_WORKSPACE | |
| $evidence = Join-Path $root 'TestResults/functional-coverage/cluster' | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.production-source-manifest.ps1 ` | |
| -Mode prepare -Root $root -EvidenceRoot $evidence | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| "KEYLOAD_PRODUCT_COVERAGE_SOURCE_MANIFEST=$evidence/functional-coverage.production-source-manifest.json" | Add-Content $env:GITHUB_ENV | |
| - name: Test functional database gate with 1 node(s) | |
| id: functional-single | |
| if: ${{ github.event_name == 'workflow_dispatch' && inputs.mode == 'functional-gates' }} | |
| shell: bash | |
| env: | |
| TMPDIR: ${{ runner.temp }}/functional-gates | |
| run: | | |
| evidence="TestResults/functional-gates/single" | |
| mkdir -p "$TMPDIR" "$evidence" | |
| if node scripts/Features/TestInfrastructure/run-tests.mjs --KeyLoadTests:Suite=cluster '--KeyLoadTests:Filter=/*/*/FunctionalDatabaseGateTests/SingleInstanceRunsEveryModelThroughSdkMcpAndSqlWithPersistedUsers' --KeyLoadTests:Execution:MaximumParallelTests=50 --KeyLoadTests:ResultsDirectory=TestResults/functional-gates/single --KeyLoadTests:ReportTrx=true > "$evidence/native.stdout.original.txt" 2> "$evidence/native.stderr.original.txt"; then | |
| native_exit=0 | |
| else | |
| native_exit=$? | |
| fi | |
| printf '%s\n' "$native_exit" > "$evidence/native-exit-code.txt" | |
| tail -c 65536 "$evidence/native.stdout.original.txt" | |
| tail -c 65536 "$evidence/native.stderr.original.txt" >&2 | |
| exit "$native_exit" | |
| - name: Verify original single functional gate receipt | |
| id: functional-single-receipt | |
| if: ${{ !cancelled() && inputs.mode == 'functional-gates' && (steps.functional-single.outcome == 'success' || steps.functional-single.outcome == 'failure') }} | |
| shell: pwsh | |
| env: | |
| NATIVE_OUTCOME: ${{ steps.functional-single.outcome }} | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| Set-StrictMode -Version Latest | |
| $directory = Join-Path $env:GITHUB_WORKSPACE 'TestResults/functional-gates/single' | |
| $reports = @(Get-ChildItem -LiteralPath $directory -Filter '*.trx' -Recurse -File) | |
| if ($reports.Count -ne 1 -or $reports[0].Length -le 0 -or $reports[0].Length -gt 16777216) { | |
| throw 'Exactly one bounded original functional gate TRX is required.' | |
| } | |
| [xml] $trx = Get-Content -LiteralPath $reports[0].FullName -Raw | |
| $ns = [Xml.XmlNamespaceManager]::new($trx.NameTable) | |
| $ns.AddNamespace('t', 'http://microsoft.com/schemas/VisualStudio/TeamTest/2010') | |
| $counts = $trx.SelectSingleNode('/t:TestRun/t:ResultSummary/t:Counters', $ns) | |
| $results = @($trx.SelectNodes('/t:TestRun/t:Results/t:UnitTestResult', $ns)) | |
| $definitions = @($trx.SelectNodes('/t:TestRun/t:TestDefinitions/t:UnitTest', $ns)) | |
| $nativeExit = (Get-Content -LiteralPath (Join-Path $directory 'native-exit-code.txt') -Raw).Trim() | |
| $valid = $env:NATIVE_OUTCOME -ceq 'success' -and $nativeExit -ceq '0' -and $null -ne $counts -and | |
| $results.Count -eq 1 -and $definitions.Count -eq 1 | |
| $valid = $valid -and [int]$counts.total -eq 1 -and [int]$counts.executed -eq 1 -and [int]$counts.passed -eq 1 | |
| foreach ($counter in $counts.Attributes) { | |
| if ($counter.Name -notin @('total','executed','passed') -and [long]$counter.Value -ne 0) { $valid = $false } | |
| } | |
| $method = 'SingleInstanceRunsEveryModelThroughSdkMcpAndSqlWithPersistedUsers' | |
| $valid = $valid -and $results[0].outcome -ceq 'Passed' -and $results[0].testName -ceq $method -and | |
| $results[0].testId -ceq $definitions[0].id -and $definitions[0].TestMethod.name -ceq $method -and | |
| $definitions[0].TestMethod.className -ceq 'KeyLoad.IntegrationTests.Features.DatabaseComposition.FunctionalDatabaseGateTests' | |
| $nativeProcessEvidence = & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.process-lifecycle.ps1 ` | |
| -Repository $env:GITHUB_WORKSPACE -ResultsDirectory $directory ` | |
| -SourceManifestPath $env:KEYLOAD_PRODUCT_COVERAGE_SOURCE_MANIFEST | ConvertFrom-Json | |
| if ($LASTEXITCODE -ne 0) { throw 'Original native process lifecycle verification failed.' } | |
| [ordered]@{ | |
| sourceRevision = $env:GITHUB_SHA; runId = $env:GITHUB_RUN_ID; runAttempt = $env:GITHUB_RUN_ATTEMPT | |
| method = $method; nodes = 1; maximumParallelTests = 50; nativeOutcome = $env:NATIVE_OUTCOME; nativeExitCode = $nativeExit; accepted = $valid | |
| stdoutSha256 = (Get-FileHash -LiteralPath (Join-Path $directory 'native.stdout.original.txt') -Algorithm SHA256).Hash.ToLowerInvariant() | |
| stderrSha256 = (Get-FileHash -LiteralPath (Join-Path $directory 'native.stderr.original.txt') -Algorithm SHA256).Hash.ToLowerInvariant() | |
| trxSha256 = (Get-FileHash -LiteralPath $reports[0].FullName -Algorithm SHA256).Hash.ToLowerInvariant() | |
| sourceManifestSha256 = (Get-FileHash -LiteralPath $env:KEYLOAD_PRODUCT_COVERAGE_SOURCE_MANIFEST -Algorithm SHA256).Hash.ToLowerInvariant() | |
| nativeProcessEvidence = $nativeProcessEvidence | |
| } | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath (Join-Path $directory 'functional-gate-receipt.json') -Encoding utf8NoBOM | |
| if (-not $valid) { throw 'The exact original functional case must execute once and pass without skips.' } | |
| - name: Test functional database gate with 3 node(s) | |
| id: functional-three | |
| if: ${{ success() && github.event_name == 'workflow_dispatch' && inputs.mode == 'functional-gates' && steps.functional-single-receipt.outcome == 'success' }} | |
| shell: bash | |
| env: | |
| TMPDIR: ${{ runner.temp }}/functional-gates | |
| run: | | |
| evidence="TestResults/functional-gates/three" | |
| mkdir -p "$TMPDIR" "$evidence" | |
| if node scripts/Features/TestInfrastructure/run-tests.mjs --KeyLoadTests:Suite=cluster '--KeyLoadTests:Filter=/*/*/FunctionalDatabaseGateTests/ThreeNodeClusterRunsSameEveryModelScenarioThroughSdkMcpAndSql' --KeyLoadTests:Execution:MaximumParallelTests=50 --KeyLoadTests:ResultsDirectory=TestResults/functional-gates/three --KeyLoadTests:ReportTrx=true > "$evidence/native.stdout.original.txt" 2> "$evidence/native.stderr.original.txt"; then | |
| native_exit=0 | |
| else | |
| native_exit=$? | |
| fi | |
| printf '%s\n' "$native_exit" > "$evidence/native-exit-code.txt" | |
| tail -c 65536 "$evidence/native.stdout.original.txt" | |
| tail -c 65536 "$evidence/native.stderr.original.txt" >&2 | |
| exit "$native_exit" | |
| - name: Verify original three functional gate receipt | |
| id: functional-three-receipt | |
| if: ${{ !cancelled() && inputs.mode == 'functional-gates' && (steps.functional-three.outcome == 'success' || steps.functional-three.outcome == 'failure') }} | |
| shell: pwsh | |
| env: | |
| NATIVE_OUTCOME: ${{ steps.functional-three.outcome }} | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| Set-StrictMode -Version Latest | |
| $directory = Join-Path $env:GITHUB_WORKSPACE 'TestResults/functional-gates/three' | |
| $reports = @(Get-ChildItem -LiteralPath $directory -Filter '*.trx' -Recurse -File) | |
| if ($reports.Count -ne 1 -or $reports[0].Length -le 0 -or $reports[0].Length -gt 16777216) { | |
| throw 'Exactly one bounded original functional gate TRX is required.' | |
| } | |
| [xml] $trx = Get-Content -LiteralPath $reports[0].FullName -Raw | |
| $ns = [Xml.XmlNamespaceManager]::new($trx.NameTable) | |
| $ns.AddNamespace('t', 'http://microsoft.com/schemas/VisualStudio/TeamTest/2010') | |
| $counts = $trx.SelectSingleNode('/t:TestRun/t:ResultSummary/t:Counters', $ns) | |
| $results = @($trx.SelectNodes('/t:TestRun/t:Results/t:UnitTestResult', $ns)) | |
| $definitions = @($trx.SelectNodes('/t:TestRun/t:TestDefinitions/t:UnitTest', $ns)) | |
| $nativeExit = (Get-Content -LiteralPath (Join-Path $directory 'native-exit-code.txt') -Raw).Trim() | |
| $valid = $env:NATIVE_OUTCOME -ceq 'success' -and $nativeExit -ceq '0' -and $null -ne $counts -and | |
| $results.Count -eq 1 -and $definitions.Count -eq 1 | |
| $valid = $valid -and [int]$counts.total -eq 1 -and [int]$counts.executed -eq 1 -and [int]$counts.passed -eq 1 | |
| foreach ($counter in $counts.Attributes) { | |
| if ($counter.Name -notin @('total','executed','passed') -and [long]$counter.Value -ne 0) { $valid = $false } | |
| } | |
| $method = 'ThreeNodeClusterRunsSameEveryModelScenarioThroughSdkMcpAndSql' | |
| $valid = $valid -and $results[0].outcome -ceq 'Passed' -and $results[0].testName -ceq $method -and | |
| $results[0].testId -ceq $definitions[0].id -and $definitions[0].TestMethod.name -ceq $method -and | |
| $definitions[0].TestMethod.className -ceq 'KeyLoad.IntegrationTests.Features.DatabaseComposition.FunctionalDatabaseGateTests' | |
| $nativeProcessEvidence = & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.process-lifecycle.ps1 ` | |
| -Repository $env:GITHUB_WORKSPACE -ResultsDirectory $directory ` | |
| -SourceManifestPath $env:KEYLOAD_PRODUCT_COVERAGE_SOURCE_MANIFEST | ConvertFrom-Json | |
| if ($LASTEXITCODE -ne 0) { throw 'Original native process lifecycle verification failed.' } | |
| [ordered]@{ | |
| sourceRevision = $env:GITHUB_SHA; runId = $env:GITHUB_RUN_ID; runAttempt = $env:GITHUB_RUN_ATTEMPT | |
| method = $method; nodes = 3; maximumParallelTests = 50; nativeOutcome = $env:NATIVE_OUTCOME; nativeExitCode = $nativeExit; accepted = $valid | |
| stdoutSha256 = (Get-FileHash -LiteralPath (Join-Path $directory 'native.stdout.original.txt') -Algorithm SHA256).Hash.ToLowerInvariant() | |
| stderrSha256 = (Get-FileHash -LiteralPath (Join-Path $directory 'native.stderr.original.txt') -Algorithm SHA256).Hash.ToLowerInvariant() | |
| trxSha256 = (Get-FileHash -LiteralPath $reports[0].FullName -Algorithm SHA256).Hash.ToLowerInvariant() | |
| sourceManifestSha256 = (Get-FileHash -LiteralPath $env:KEYLOAD_PRODUCT_COVERAGE_SOURCE_MANIFEST -Algorithm SHA256).Hash.ToLowerInvariant() | |
| nativeProcessEvidence = $nativeProcessEvidence | |
| } | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath (Join-Path $directory 'functional-gate-receipt.json') -Encoding utf8NoBOM | |
| if (-not $valid) { throw 'The exact original functional case must execute once and pass without skips.' } | |
| - name: Test native cold profile and selector preconditions | |
| id: functional-cold-preconditions | |
| if: ${{ success() && github.event_name == 'workflow_dispatch' && inputs.mode == 'functional-gates' && steps.functional-three-receipt.outcome == 'success' }} | |
| shell: bash | |
| run: | | |
| evidence="TestResults/functional-gates/cold-preconditions" | |
| mkdir -p "$evidence" | |
| if node scripts/Features/TestInfrastructure/run-tests.mjs --KeyLoadTests:Suite=unit '--KeyLoadTests:Filter=/*/*/(FunctionalColdReopenProfileTests|NativeTUnitSelectionTests)/*' --KeyLoadTests:Execution:MaximumParallelTests=50 --KeyLoadTests:ResultsDirectory=TestResults/functional-gates/cold-preconditions --KeyLoadTests:ReportTrx=true > "$evidence/native.stdout.original.txt" 2> "$evidence/native.stderr.original.txt"; then | |
| native_exit=0 | |
| else | |
| native_exit=$? | |
| fi | |
| printf '%s\n' "$native_exit" > "$evidence/native-exit-code.txt" | |
| tail -c 65536 "$evidence/native.stdout.original.txt" | |
| tail -c 65536 "$evidence/native.stderr.original.txt" >&2 | |
| exit "$native_exit" | |
| - name: Verify original native cold precondition receipt | |
| id: functional-cold-preconditions-receipt | |
| if: ${{ !cancelled() && inputs.mode == 'functional-gates' && (steps.functional-cold-preconditions.outcome == 'success' || steps.functional-cold-preconditions.outcome == 'failure') }} | |
| shell: pwsh | |
| env: | |
| NATIVE_OUTCOME: ${{ steps.functional-cold-preconditions.outcome }} | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| Set-StrictMode -Version Latest | |
| $directory = Join-Path $env:GITHUB_WORKSPACE 'TestResults/functional-gates/cold-preconditions' | |
| $reports = @(Get-ChildItem -LiteralPath $directory -Filter '*.trx' -Recurse -File) | |
| if ($reports.Count -ne 1 -or $reports[0].Length -le 0 -or $reports[0].Length -gt 16777216) { | |
| throw 'Exactly one bounded original cold precondition TRX is required.' | |
| } | |
| [xml] $trx = Get-Content -LiteralPath $reports[0].FullName -Raw | |
| $ns = [Xml.XmlNamespaceManager]::new($trx.NameTable) | |
| $ns.AddNamespace('t', 'http://microsoft.com/schemas/VisualStudio/TeamTest/2010') | |
| $counts = $trx.SelectSingleNode('/t:TestRun/t:ResultSummary/t:Counters', $ns) | |
| $results = @($trx.SelectNodes('/t:TestRun/t:Results/t:UnitTestResult', $ns)) | |
| $definitions = @($trx.SelectNodes('/t:TestRun/t:TestDefinitions/t:UnitTest', $ns)) | |
| $nativeExit = (Get-Content -LiteralPath (Join-Path $directory 'native-exit-code.txt') -Raw).Trim() | |
| $valid = $env:NATIVE_OUTCOME -ceq 'success' -and $nativeExit -ceq '0' -and $null -ne $counts -and | |
| $results.Count -eq 10 -and $definitions.Count -eq 10 | |
| $valid = $valid -and [int]$counts.total -eq 10 -and [int]$counts.executed -eq 10 -and [int]$counts.passed -eq 10 | |
| foreach ($counter in $counts.Attributes) { | |
| if ($counter.Name -notin @('total','executed','passed') -and [long]$counter.Value -ne 0) { $valid = $false } | |
| } | |
| $expected = [ordered]@{ | |
| 'FunctionalColdReopenProfileTests.ActualNativeModelKeepsFaultCommandsExclusiveToSelectedProfiles' = 5 | |
| 'FunctionalColdReopenProfileTests.InvalidColdAndConflictingSelectionsRefuseBeforeResourcesThenHealthyModelWorks' = 1 | |
| 'NativeTUnitSelectionTests.NativeEntryPreservesOriginalTUnitArgumentsAndRejectsInvalidSelections' = 4 | |
| } | |
| $observed = [Collections.Generic.Dictionary[string,int]]::new([StringComparer]::Ordinal) | |
| $resultIds = [Collections.Generic.HashSet[string]]::new([StringComparer]::Ordinal) | |
| $definitionIds = [Collections.Generic.HashSet[string]]::new([StringComparer]::Ordinal) | |
| $displays = [Collections.Generic.HashSet[string]]::new([StringComparer]::Ordinal) | |
| foreach ($definition in $definitions) { | |
| if (-not $definitionIds.Add([string]$definition.id)) { $valid = $false } | |
| $class = [string]$definition.TestMethod.className | |
| $method = [string]$definition.TestMethod.name | |
| $prefix = 'KeyLoad.UnitTests.Features.TestInfrastructure.' | |
| if (-not $class.StartsWith($prefix, [StringComparison]::Ordinal)) { $valid = $false; continue } | |
| $key = $class.Substring($prefix.Length) + '.' + $method | |
| if ($key -cnotin @($expected.Keys)) { $valid = $false; continue } | |
| if (-not $observed.ContainsKey($key)) { $observed[$key] = 0 } | |
| $observed[$key]++ | |
| $matching = @($results | Where-Object { $_.testId -ceq $definition.id }) | |
| if ($matching.Count -ne 1) { $valid = $false; continue } | |
| $result = $matching[0] | |
| if ($result.outcome -cne 'Passed' -or $result.testName -cne $definition.name -or | |
| -not $resultIds.Add([string]$result.testId) -or -not $displays.Add($key + ':' + $result.testName)) { $valid = $false } | |
| } | |
| foreach ($key in $expected.Keys) { | |
| if (-not $observed.ContainsKey($key) -or $observed[$key] -ne $expected[$key]) { $valid = $false } | |
| } | |
| [ordered]@{ | |
| sourceRevision = $env:GITHUB_SHA; runId = $env:GITHUB_RUN_ID; runAttempt = $env:GITHUB_RUN_ATTEMPT | |
| methods = $expected; maximumParallelTests = 50; nativeOutcome = $env:NATIVE_OUTCOME; nativeExitCode = $nativeExit; accepted = $valid | |
| stdoutSha256 = (Get-FileHash -LiteralPath (Join-Path $directory 'native.stdout.original.txt') -Algorithm SHA256).Hash.ToLowerInvariant() | |
| stderrSha256 = (Get-FileHash -LiteralPath (Join-Path $directory 'native.stderr.original.txt') -Algorithm SHA256).Hash.ToLowerInvariant() | |
| trxSha256 = (Get-FileHash -LiteralPath $reports[0].FullName -Algorithm SHA256).Hash.ToLowerInvariant() | |
| sourceManifestSha256 = (Get-FileHash -LiteralPath $env:KEYLOAD_PRODUCT_COVERAGE_SOURCE_MANIFEST -Algorithm SHA256).Hash.ToLowerInvariant() | |
| } | ConvertTo-Json | Set-Content -LiteralPath (Join-Path $directory 'functional-gate-receipt.json') -Encoding utf8NoBOM | |
| if (-not $valid) { throw 'Every original cold profile and selector precondition must execute exactly once and pass without skips.' } | |
| - name: Test cold functional database gate with 1 node(s) | |
| id: functional-cold-single | |
| if: ${{ success() && github.event_name == 'workflow_dispatch' && inputs.mode == 'functional-gates' && steps.functional-cold-preconditions-receipt.outcome == 'success' }} | |
| shell: bash | |
| env: | |
| TMPDIR: ${{ runner.temp }}/functional-gates | |
| run: | | |
| evidence="TestResults/functional-gates/cold-single" | |
| mkdir -p "$TMPDIR" "$evidence" | |
| if node scripts/Features/TestInfrastructure/run-tests.mjs --KeyLoadTests:Suite=cluster '--KeyLoadTests:Filter=/*/*/FunctionalDatabaseColdReopenTests/SingleInstanceColdReopensAllModelsAndReplaysOriginalPublicCommands' --KeyLoadTests:Execution:MaximumParallelTests=50 --KeyLoadTests:ResultsDirectory=TestResults/functional-gates/cold-single --KeyLoadTests:ReportTrx=true > "$evidence/native.stdout.original.txt" 2> "$evidence/native.stderr.original.txt"; then | |
| native_exit=0 | |
| else | |
| native_exit=$? | |
| fi | |
| printf '%s\n' "$native_exit" > "$evidence/native-exit-code.txt" | |
| tail -c 65536 "$evidence/native.stdout.original.txt" | |
| tail -c 65536 "$evidence/native.stderr.original.txt" >&2 | |
| exit "$native_exit" | |
| - name: Verify original single cold functional gate receipt | |
| id: functional-cold-single-receipt | |
| if: ${{ !cancelled() && inputs.mode == 'functional-gates' && (steps.functional-cold-single.outcome == 'success' || steps.functional-cold-single.outcome == 'failure') }} | |
| shell: pwsh | |
| env: | |
| NATIVE_OUTCOME: ${{ steps.functional-cold-single.outcome }} | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| Set-StrictMode -Version Latest | |
| $directory = Join-Path $env:GITHUB_WORKSPACE 'TestResults/functional-gates/cold-single' | |
| $reports = @(Get-ChildItem -LiteralPath $directory -Filter '*.trx' -Recurse -File) | |
| if ($reports.Count -ne 1 -or $reports[0].Length -le 0 -or $reports[0].Length -gt 16777216) { | |
| throw 'Exactly one bounded original functional gate TRX is required.' | |
| } | |
| [xml] $trx = Get-Content -LiteralPath $reports[0].FullName -Raw | |
| $ns = [Xml.XmlNamespaceManager]::new($trx.NameTable) | |
| $ns.AddNamespace('t', 'http://microsoft.com/schemas/VisualStudio/TeamTest/2010') | |
| $counts = $trx.SelectSingleNode('/t:TestRun/t:ResultSummary/t:Counters', $ns) | |
| $results = @($trx.SelectNodes('/t:TestRun/t:Results/t:UnitTestResult', $ns)) | |
| $definitions = @($trx.SelectNodes('/t:TestRun/t:TestDefinitions/t:UnitTest', $ns)) | |
| $nativeExit = (Get-Content -LiteralPath (Join-Path $directory 'native-exit-code.txt') -Raw).Trim() | |
| $valid = $env:NATIVE_OUTCOME -ceq 'success' -and $nativeExit -ceq '0' -and $null -ne $counts -and | |
| $results.Count -eq 1 -and $definitions.Count -eq 1 | |
| $valid = $valid -and [int]$counts.total -eq 1 -and [int]$counts.executed -eq 1 -and [int]$counts.passed -eq 1 | |
| foreach ($counter in $counts.Attributes) { | |
| if ($counter.Name -notin @('total','executed','passed') -and [long]$counter.Value -ne 0) { $valid = $false } | |
| } | |
| $method = 'SingleInstanceColdReopensAllModelsAndReplaysOriginalPublicCommands' | |
| $valid = $valid -and $results[0].outcome -ceq 'Passed' -and $results[0].testName -ceq $method -and | |
| $results[0].testId -ceq $definitions[0].id -and $definitions[0].TestMethod.name -ceq $method -and | |
| $definitions[0].TestMethod.className -ceq 'KeyLoad.IntegrationTests.Features.DatabaseComposition.FunctionalDatabaseColdReopenTests' | |
| $nativeProcessEvidence = & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.process-lifecycle.ps1 ` | |
| -Repository $env:GITHUB_WORKSPACE -ResultsDirectory $directory ` | |
| -SourceManifestPath $env:KEYLOAD_PRODUCT_COVERAGE_SOURCE_MANIFEST | ConvertFrom-Json | |
| if ($LASTEXITCODE -ne 0) { throw 'Original native process lifecycle verification failed.' } | |
| [ordered]@{ | |
| sourceRevision = $env:GITHUB_SHA; runId = $env:GITHUB_RUN_ID; runAttempt = $env:GITHUB_RUN_ATTEMPT | |
| method = $method; nodes = 1; maximumParallelTests = 50; nativeOutcome = $env:NATIVE_OUTCOME; nativeExitCode = $nativeExit; accepted = $valid | |
| stdoutSha256 = (Get-FileHash -LiteralPath (Join-Path $directory 'native.stdout.original.txt') -Algorithm SHA256).Hash.ToLowerInvariant() | |
| stderrSha256 = (Get-FileHash -LiteralPath (Join-Path $directory 'native.stderr.original.txt') -Algorithm SHA256).Hash.ToLowerInvariant() | |
| trxSha256 = (Get-FileHash -LiteralPath $reports[0].FullName -Algorithm SHA256).Hash.ToLowerInvariant() | |
| sourceManifestSha256 = (Get-FileHash -LiteralPath $env:KEYLOAD_PRODUCT_COVERAGE_SOURCE_MANIFEST -Algorithm SHA256).Hash.ToLowerInvariant() | |
| nativeProcessEvidence = $nativeProcessEvidence | |
| } | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath (Join-Path $directory 'functional-gate-receipt.json') -Encoding utf8NoBOM | |
| if (-not $valid) { throw 'The exact original functional case must execute once and pass without skips.' } | |
| - name: Test cold functional database gate with 3 node(s) | |
| id: functional-cold-three | |
| if: ${{ success() && github.event_name == 'workflow_dispatch' && inputs.mode == 'functional-gates' && steps.functional-cold-single-receipt.outcome == 'success' }} | |
| shell: bash | |
| env: | |
| TMPDIR: ${{ runner.temp }}/functional-gates | |
| run: | | |
| evidence="TestResults/functional-gates/cold-three" | |
| mkdir -p "$TMPDIR" "$evidence" | |
| if node scripts/Features/TestInfrastructure/run-tests.mjs --KeyLoadTests:Suite=cluster '--KeyLoadTests:Filter=/*/*/FunctionalDatabaseColdReopenTests/ThreeNodeColdReopensAllModelsAndReplaysOriginalPublicCommands' --KeyLoadTests:Execution:MaximumParallelTests=50 --KeyLoadTests:ResultsDirectory=TestResults/functional-gates/cold-three --KeyLoadTests:ReportTrx=true > "$evidence/native.stdout.original.txt" 2> "$evidence/native.stderr.original.txt"; then | |
| native_exit=0 | |
| else | |
| native_exit=$? | |
| fi | |
| printf '%s\n' "$native_exit" > "$evidence/native-exit-code.txt" | |
| tail -c 65536 "$evidence/native.stdout.original.txt" | |
| tail -c 65536 "$evidence/native.stderr.original.txt" >&2 | |
| exit "$native_exit" | |
| - name: Verify original three cold functional gate receipt | |
| id: functional-cold-three-receipt | |
| if: ${{ !cancelled() && inputs.mode == 'functional-gates' && (steps.functional-cold-three.outcome == 'success' || steps.functional-cold-three.outcome == 'failure') }} | |
| shell: pwsh | |
| env: | |
| NATIVE_OUTCOME: ${{ steps.functional-cold-three.outcome }} | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| Set-StrictMode -Version Latest | |
| $directory = Join-Path $env:GITHUB_WORKSPACE 'TestResults/functional-gates/cold-three' | |
| $reports = @(Get-ChildItem -LiteralPath $directory -Filter '*.trx' -Recurse -File) | |
| if ($reports.Count -ne 1 -or $reports[0].Length -le 0 -or $reports[0].Length -gt 16777216) { | |
| throw 'Exactly one bounded original functional gate TRX is required.' | |
| } | |
| [xml] $trx = Get-Content -LiteralPath $reports[0].FullName -Raw | |
| $ns = [Xml.XmlNamespaceManager]::new($trx.NameTable) | |
| $ns.AddNamespace('t', 'http://microsoft.com/schemas/VisualStudio/TeamTest/2010') | |
| $counts = $trx.SelectSingleNode('/t:TestRun/t:ResultSummary/t:Counters', $ns) | |
| $results = @($trx.SelectNodes('/t:TestRun/t:Results/t:UnitTestResult', $ns)) | |
| $definitions = @($trx.SelectNodes('/t:TestRun/t:TestDefinitions/t:UnitTest', $ns)) | |
| $nativeExit = (Get-Content -LiteralPath (Join-Path $directory 'native-exit-code.txt') -Raw).Trim() | |
| $valid = $env:NATIVE_OUTCOME -ceq 'success' -and $nativeExit -ceq '0' -and $null -ne $counts -and | |
| $results.Count -eq 1 -and $definitions.Count -eq 1 | |
| $valid = $valid -and [int]$counts.total -eq 1 -and [int]$counts.executed -eq 1 -and [int]$counts.passed -eq 1 | |
| foreach ($counter in $counts.Attributes) { | |
| if ($counter.Name -notin @('total','executed','passed') -and [long]$counter.Value -ne 0) { $valid = $false } | |
| } | |
| $method = 'ThreeNodeColdReopensAllModelsAndReplaysOriginalPublicCommands' | |
| $valid = $valid -and $results[0].outcome -ceq 'Passed' -and $results[0].testName -ceq $method -and | |
| $results[0].testId -ceq $definitions[0].id -and $definitions[0].TestMethod.name -ceq $method -and | |
| $definitions[0].TestMethod.className -ceq 'KeyLoad.IntegrationTests.Features.DatabaseComposition.FunctionalDatabaseColdReopenTests' | |
| $nativeProcessEvidence = & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.process-lifecycle.ps1 ` | |
| -Repository $env:GITHUB_WORKSPACE -ResultsDirectory $directory ` | |
| -SourceManifestPath $env:KEYLOAD_PRODUCT_COVERAGE_SOURCE_MANIFEST | ConvertFrom-Json | |
| if ($LASTEXITCODE -ne 0) { throw 'Original native process lifecycle verification failed.' } | |
| [ordered]@{ | |
| sourceRevision = $env:GITHUB_SHA; runId = $env:GITHUB_RUN_ID; runAttempt = $env:GITHUB_RUN_ATTEMPT | |
| method = $method; nodes = 3; maximumParallelTests = 50; nativeOutcome = $env:NATIVE_OUTCOME; nativeExitCode = $nativeExit; accepted = $valid | |
| stdoutSha256 = (Get-FileHash -LiteralPath (Join-Path $directory 'native.stdout.original.txt') -Algorithm SHA256).Hash.ToLowerInvariant() | |
| stderrSha256 = (Get-FileHash -LiteralPath (Join-Path $directory 'native.stderr.original.txt') -Algorithm SHA256).Hash.ToLowerInvariant() | |
| trxSha256 = (Get-FileHash -LiteralPath $reports[0].FullName -Algorithm SHA256).Hash.ToLowerInvariant() | |
| sourceManifestSha256 = (Get-FileHash -LiteralPath $env:KEYLOAD_PRODUCT_COVERAGE_SOURCE_MANIFEST -Algorithm SHA256).Hash.ToLowerInvariant() | |
| nativeProcessEvidence = $nativeProcessEvidence | |
| } | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath (Join-Path $directory 'functional-gate-receipt.json') -Encoding utf8NoBOM | |
| if (-not $valid) { throw 'The exact original functional case must execute once and pass without skips.' } | |
| - name: Test distinct native files and exclusive-owner refusal with 3 nodes | |
| id: functional-file-ownership-three | |
| if: ${{ success() && github.event_name == 'workflow_dispatch' && inputs.mode == 'functional-gates' && steps.functional-cold-three-receipt.outcome == 'success' }} | |
| shell: bash | |
| env: | |
| TMPDIR: ${{ runner.temp }}/functional-gates | |
| run: | | |
| evidence="TestResults/functional-gates/file-ownership-three" | |
| mkdir -p "$TMPDIR" "$evidence" | |
| if node scripts/Features/TestInfrastructure/run-tests.mjs --KeyLoadTests:Suite=cluster '--KeyLoadTests:Filter=/*/*/FunctionalFileOwnershipClusterTests/DistinctNativeFilesRetainAllModelsAcrossCompetingOwnersAndTwoColdReopens' --KeyLoadTests:Execution:MaximumParallelTests=50 --KeyLoadTests:ResultsDirectory=TestResults/functional-gates/file-ownership-three --KeyLoadTests:ReportTrx=true > "$evidence/native.stdout.original.txt" 2> "$evidence/native.stderr.original.txt"; then | |
| native_exit=0 | |
| else | |
| native_exit=$? | |
| fi | |
| printf '%s\n' "$native_exit" > "$evidence/native-exit-code.txt" | |
| tail -c 65536 "$evidence/native.stdout.original.txt" | |
| tail -c 65536 "$evidence/native.stderr.original.txt" >&2 | |
| exit "$native_exit" | |
| - name: Verify original distinct-files and exclusive-owner refusal receipt | |
| id: functional-file-ownership-three-receipt | |
| if: ${{ !cancelled() && github.event_name == 'workflow_dispatch' && inputs.mode == 'functional-gates' && steps.functional-cold-three-receipt.outcome == 'success' && (steps.functional-file-ownership-three.outcome == 'success' || steps.functional-file-ownership-three.outcome == 'failure') }} | |
| shell: pwsh | |
| env: | |
| NATIVE_OUTCOME: ${{ steps.functional-file-ownership-three.outcome }} | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| Set-StrictMode -Version Latest | |
| $directory = Join-Path $env:GITHUB_WORKSPACE 'TestResults/functional-gates/file-ownership-three' | |
| $reports = @(Get-ChildItem -LiteralPath $directory -Filter '*.trx' -Recurse -File) | |
| if ($reports.Count -ne 1 -or $reports[0].Length -le 0 -or $reports[0].Length -gt 16777216) { | |
| throw 'Exactly one bounded original functional gate TRX is required.' | |
| } | |
| [xml] $trx = Get-Content -LiteralPath $reports[0].FullName -Raw | |
| $ns = [Xml.XmlNamespaceManager]::new($trx.NameTable) | |
| $ns.AddNamespace('t', 'http://microsoft.com/schemas/VisualStudio/TeamTest/2010') | |
| $counts = $trx.SelectSingleNode('/t:TestRun/t:ResultSummary/t:Counters', $ns) | |
| $results = @($trx.SelectNodes('/t:TestRun/t:Results/t:UnitTestResult', $ns)) | |
| $definitions = @($trx.SelectNodes('/t:TestRun/t:TestDefinitions/t:UnitTest', $ns)) | |
| $nativeExit = (Get-Content -LiteralPath (Join-Path $directory 'native-exit-code.txt') -Raw).Trim() | |
| $valid = $env:NATIVE_OUTCOME -ceq 'success' -and $nativeExit -ceq '0' -and $null -ne $counts -and | |
| $results.Count -eq 1 -and $definitions.Count -eq 1 | |
| $valid = $valid -and [int]$counts.total -eq 1 -and [int]$counts.executed -eq 1 -and [int]$counts.passed -eq 1 | |
| foreach ($counter in $counts.Attributes) { | |
| if ($counter.Name -notin @('total','executed','passed') -and [long]$counter.Value -ne 0) { $valid = $false } | |
| } | |
| $method = 'DistinctNativeFilesRetainAllModelsAcrossCompetingOwnersAndTwoColdReopens' | |
| $valid = $valid -and $results[0].outcome -ceq 'Passed' -and $results[0].testName -ceq $method -and | |
| $results[0].testId -ceq $definitions[0].id -and $definitions[0].TestMethod.name -ceq $method -and | |
| $definitions[0].TestMethod.className -ceq 'KeyLoad.IntegrationTests.Features.DatabaseComposition.FunctionalFileOwnershipClusterTests' | |
| $nativeProcessEvidence = & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.process-lifecycle.ps1 ` | |
| -Repository $env:GITHUB_WORKSPACE -ResultsDirectory $directory ` | |
| -SourceManifestPath $env:KEYLOAD_PRODUCT_COVERAGE_SOURCE_MANIFEST | ConvertFrom-Json | |
| if ($LASTEXITCODE -ne 0) { throw 'Original native process lifecycle verification failed.' } | |
| [ordered]@{ | |
| sourceRevision = $env:GITHUB_SHA; runId = $env:GITHUB_RUN_ID; runAttempt = $env:GITHUB_RUN_ATTEMPT | |
| method = $method; nodes = 3; maximumParallelTests = 50; nativeOutcome = $env:NATIVE_OUTCOME; nativeExitCode = $nativeExit; accepted = $valid | |
| stdoutSha256 = (Get-FileHash -LiteralPath (Join-Path $directory 'native.stdout.original.txt') -Algorithm SHA256).Hash.ToLowerInvariant() | |
| stderrSha256 = (Get-FileHash -LiteralPath (Join-Path $directory 'native.stderr.original.txt') -Algorithm SHA256).Hash.ToLowerInvariant() | |
| trxSha256 = (Get-FileHash -LiteralPath $reports[0].FullName -Algorithm SHA256).Hash.ToLowerInvariant() | |
| sourceManifestSha256 = (Get-FileHash -LiteralPath $env:KEYLOAD_PRODUCT_COVERAGE_SOURCE_MANIFEST -Algorithm SHA256).Hash.ToLowerInvariant() | |
| nativeProcessEvidence = $nativeProcessEvidence | |
| } | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath (Join-Path $directory 'functional-gate-receipt.json') -Encoding utf8NoBOM | |
| if (-not $valid) { throw 'The exact original functional case must execute once and pass without skips.' } | |
| - name: Test three-node database with .NET and MCP clients | |
| id: cluster-required | |
| if: ${{ inputs.mode != 'functional-gates' }} | |
| run: node scripts/Features/TestInfrastructure/run-tests.mjs --KeyLoadTests:Suite=cluster --KeyLoadTests:ResultsDirectory=TestResults/cluster-required --KeyLoadTests:ReportTrx=true | |
| - name: Check original three-node reports for diagnostic upload | |
| id: cluster-original-reports | |
| if: ${{ inputs.mode != 'functional-gates' && !cancelled() && (steps.cluster-required.outcome == 'success' || steps.cluster-required.outcome == 'failure') }} | |
| shell: bash | |
| run: | | |
| test -d TestResults/cluster-required | |
| original_trx=$(find TestResults/cluster-required -type f -name '*.trx' -size +0c -print -quit) | |
| test -n "$original_trx" | |
| printf '%s\n' "$original_trx" | |
| - name: Save original three-node diagnostics before covered suites | |
| if: ${{ inputs.mode != 'functional-gates' && !cancelled() && steps.cluster-original-reports.outcome == 'success' }} | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: aspire-cluster-original-diagnostics | |
| path: | | |
| TestResults/cluster-required/** | |
| TestResults/functional-coverage/cluster/** | |
| if-no-files-found: error | |
| - name: Reconcile original native full and five-group discovery in both modes | |
| id: native-census | |
| if: ${{ inputs.mode != 'functional-gates' && !cancelled() && steps.coverage-source.outcome == 'success' }} | |
| shell: pwsh | |
| run: | | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.workflow-discovery.ps1 ` | |
| -Repository $env:GITHUB_WORKSPACE ` | |
| -EvidenceRoot (Join-Path $env:GITHUB_WORKSPACE 'TestResults/functional-coverage/cluster') | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| - name: Execute full censuses and twelve original covered suite inputs | |
| id: functional-coverage | |
| if: ${{ inputs.mode != 'functional-gates' && !cancelled() && steps.native-census.outcome == 'success' }} | |
| shell: pwsh | |
| run: | | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.workflow-collect.ps1 ` | |
| -Repository $env:GITHUB_WORKSPACE ` | |
| -EvidenceRoot (Join-Path $env:GITHUB_WORKSPACE 'TestResults/functional-coverage/cluster') ` | |
| -SourceManifestPath $env:KEYLOAD_PRODUCT_COVERAGE_SOURCE_MANIFEST | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| - name: Verify original coverage source and native test assembly receipts after all children settle | |
| id: coverage-source-after | |
| if: ${{ !cancelled() && steps.coverage-source.outcome == 'success' }} | |
| shell: pwsh | |
| run: | | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.production-source-manifest.ps1 ` | |
| -Mode verify -Root $env:GITHUB_WORKSPACE ` | |
| -EvidenceRoot (Join-Path $env:GITHUB_WORKSPACE 'TestResults/functional-coverage/cluster') | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| - name: Assemble product descriptor from original reports | |
| id: product-descriptor | |
| if: ${{ inputs.mode != 'functional-gates' && success() }} | |
| shell: pwsh | |
| env: | |
| RECOVERY_EXIT_CODE: ${{ steps.functional-coverage.outputs.recovery_exit_code }} | |
| CLUSTER_EXIT_CODE: ${{ steps.functional-coverage.outputs.cluster_exit_code }} | |
| run: | | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.native-product-descriptor.ps1 ` | |
| -Repository $env:GITHUB_WORKSPACE ` | |
| -SourceManifestPath $env:KEYLOAD_PRODUCT_COVERAGE_SOURCE_MANIFEST ` | |
| -ResultsRoot (Join-Path $env:GITHUB_WORKSPACE 'TestResults/functional-coverage/cluster') ` | |
| -UnitRunStatusPath (Join-Path $env:GITHUB_WORKSPACE 'TestResults/functional-coverage/cluster/functional-coverage.unit-run-status.v1.json') ` | |
| -RecoveryExitCode ([int]$env:RECOVERY_EXIT_CODE) -ClusterExitCode ([int]$env:CLUSTER_EXIT_CODE) | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| - name: Exercise original product admission and copied TRX denial with healthy re-admission | |
| id: product-admission | |
| if: ${{ inputs.mode != 'functional-gates' && success() }} | |
| env: | |
| KEYLOAD_NATIVE_PRODUCT_ADMISSION_REQUIRED: 'true' | |
| KEYLOAD_NATIVE_PRODUCT_DESCRIPTOR_PATH: ${{ github.workspace }}/TestResults/functional-coverage/cluster/functional-coverage.native-product-descriptor.v1.json | |
| run: node scripts/Features/TestInfrastructure/run-tests.mjs --KeyLoadTests:Suite=unit '--KeyLoadTests:Filter=/*/*/NativeCoverageMergeTests/*' --KeyLoadTests:ResultsDirectory=TestResults/native-product-admission --KeyLoadTests:ReportTrx=true | |
| - name: Verify original product-admission test and closed phase receipt | |
| if: ${{ inputs.mode != 'functional-gates' && !cancelled() && steps.product-admission.outcome != 'skipped' }} | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| Set-StrictMode -Version Latest | |
| $directory = Join-Path $env:GITHUB_WORKSPACE 'TestResults/native-product-admission' | |
| $reports = @(Get-ChildItem -LiteralPath $directory -Filter '*.trx' -File -Recurse) | |
| $receipts = @(Get-ChildItem -LiteralPath $directory -Filter 'native-product-admission-phase.v1.json' -File -Recurse) | |
| if ($reports.Count -ne 1 -or $receipts.Count -ne 1 -or $receipts[0].Length -le 0 -or $receipts[0].Length -gt 65536) { | |
| throw 'Exactly one original TRX and bounded product-admission receipt are required.' | |
| } | |
| [xml] $trx = Get-Content -LiteralPath $reports[0].FullName -Raw | |
| $counts = $trx.TestRun.ResultSummary.Counters | |
| if ([int] $counts.total -ne 1 -or [int] $counts.executed -ne 1 -or [int] $counts.passed -ne 1 -or [int] $counts.failed -ne 0) { | |
| throw 'The real product-admission whole operation must execute and pass.' | |
| } | |
| . ./scripts/Features/CodeQuality/functional-coverage.native-merge.inputs.ps1 | |
| $bytes = [IO.File]::ReadAllBytes($receipts[0].FullName) | |
| $document = [Text.Json.JsonDocument]::Parse([ReadOnlyMemory[byte]]::new($bytes)) | |
| try { Assert-FcNativeJsonUnique $document.RootElement } | |
| finally { $document.Dispose() } | |
| $phase = ConvertFrom-Json ([Text.Encoding]::UTF8.GetString($bytes)) -AsHashtable | |
| Assert-FcNativeExactKeys $phase @('schemaVersion','phase','descriptorSha256','healthyAdmissions','rejectedAdmissions','rejectedOutcome') | |
| $descriptor = Join-Path $env:GITHUB_WORKSPACE 'TestResults/functional-coverage/cluster/functional-coverage.native-product-descriptor.v1.json' | |
| foreach ($name in @('schemaVersion','healthyAdmissions','rejectedAdmissions')) { | |
| if ($phase[$name] -isnot [int] -and $phase[$name] -isnot [long]) { throw 'Invalid product phase integer.' } | |
| } | |
| if ($phase.schemaVersion -ne 1 -or $phase.phase -cne 'product-admission' -or | |
| $phase.descriptorSha256 -cne (Get-FileHash $descriptor -Algorithm SHA256).Hash.ToLowerInvariant() -or | |
| $phase.healthyAdmissions -ne 2 -or $phase.rejectedAdmissions -ne 1 -or | |
| $phase.rejectedOutcome -cne 'An original native test outcome report does not match the exact contributor inventory.') { | |
| throw 'The product-admission phase does not bind the original descriptor and complete flow.' | |
| } | |
| - name: Validate and merge native product coverage | |
| if: ${{ inputs.mode != 'functional-gates' && success() }} | |
| shell: pwsh | |
| run: | | |
| $root = $env:GITHUB_WORKSPACE | |
| $evidence = Join-Path $root 'TestResults/functional-coverage/cluster' | |
| $descriptorPath = Join-Path $evidence 'functional-coverage.native-product-descriptor.v1.json' | |
| $boundsPath = Join-Path $evidence 'functional-coverage.native-options.v1.json' | |
| $descriptor = Get-Content -LiteralPath $descriptorPath -Raw | ConvertFrom-Json | |
| $nativeOptions = Get-Content -LiteralPath $boundsPath -Raw | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.native-merge.ps1 ` | |
| -Mode Product -Repository $root -EvidenceRoot $evidence -DescriptorPath $descriptorPath ` | |
| -ToolPackageRoot $descriptor.tool.packageRoot -ToolVersion $descriptor.tool.version ` | |
| -NativeOptionsJson $nativeOptions | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| - name: Verify original native process teardown evidence | |
| id: native-cleanup | |
| if: ${{ always() && steps.coverage-source.outcome == 'success' }} | |
| shell: pwsh | |
| run: | | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.process-lifecycle.ps1 ` | |
| -Repository $env:GITHUB_WORKSPACE ` | |
| -ResultsDirectory (Join-Path $env:GITHUB_WORKSPACE 'TestResults') ` | |
| -SourceManifestPath $env:KEYLOAD_PRODUCT_COVERAGE_SOURCE_MANIFEST | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| - name: Retain focused functional gate outcomes after cleanup | |
| if: ${{ always() && inputs.mode == 'functional-gates' }} | |
| shell: pwsh | |
| env: | |
| SINGLE_OUTCOME: ${{ steps.functional-single.outcome }} | |
| SINGLE_RECEIPT: ${{ steps.functional-single-receipt.outcome }} | |
| THREE_OUTCOME: ${{ steps.functional-three.outcome }} | |
| THREE_RECEIPT: ${{ steps.functional-three-receipt.outcome }} | |
| FILE_OWNERSHIP_OUTCOME: ${{ steps.functional-file-ownership-three.outcome }} | |
| FILE_OWNERSHIP_RECEIPT: ${{ steps.functional-file-ownership-three-receipt.outcome }} | |
| COLD_PRECONDITIONS_OUTCOME: ${{ steps.functional-cold-preconditions.outcome }} | |
| COLD_PRECONDITIONS_RECEIPT: ${{ steps.functional-cold-preconditions-receipt.outcome }} | |
| COLD_SINGLE_OUTCOME: ${{ steps.functional-cold-single.outcome }} | |
| COLD_SINGLE_RECEIPT: ${{ steps.functional-cold-single-receipt.outcome }} | |
| COLD_THREE_OUTCOME: ${{ steps.functional-cold-three.outcome }} | |
| COLD_THREE_RECEIPT: ${{ steps.functional-cold-three-receipt.outcome }} | |
| SOURCE_VERIFY: ${{ steps.coverage-source-after.outcome }} | |
| NATIVE_CLEANUP: ${{ steps.native-cleanup.outcome }} | |
| run: | | |
| $directory = Join-Path $env:GITHUB_WORKSPACE 'TestResults/functional-gates' | |
| New-Item -ItemType Directory -Path $directory -Force | Out-Null | |
| $outcomes = [ordered]@{ | |
| sourceRevision = $env:GITHUB_SHA; runId = $env:GITHUB_RUN_ID; runAttempt = $env:GITHUB_RUN_ATTEMPT | |
| single = $env:SINGLE_OUTCOME; singleReceipt = $env:SINGLE_RECEIPT | |
| three = $env:THREE_OUTCOME; threeReceipt = $env:THREE_RECEIPT | |
| fileOwnershipThree = $env:FILE_OWNERSHIP_OUTCOME; fileOwnershipThreeReceipt = $env:FILE_OWNERSHIP_RECEIPT | |
| coldPreconditions = $env:COLD_PRECONDITIONS_OUTCOME; coldPreconditionsReceipt = $env:COLD_PRECONDITIONS_RECEIPT | |
| coldSingle = $env:COLD_SINGLE_OUTCOME; coldSingleReceipt = $env:COLD_SINGLE_RECEIPT | |
| coldThree = $env:COLD_THREE_OUTCOME; coldThreeReceipt = $env:COLD_THREE_RECEIPT | |
| sourceVerify = $env:SOURCE_VERIFY; nativeCleanup = $env:NATIVE_CLEANUP | |
| } | |
| $outcomes | ConvertTo-Json | Set-Content -LiteralPath (Join-Path $directory 'functional-gates-outcomes.json') -Encoding utf8NoBOM | |
| foreach ($name in @('single','singleReceipt','three','threeReceipt','fileOwnershipThree','fileOwnershipThreeReceipt','coldPreconditions','coldPreconditionsReceipt','coldSingle','coldSingleReceipt','coldThree','coldThreeReceipt','sourceVerify','nativeCleanup')) { | |
| if ($outcomes[$name] -cne 'success') { throw 'Both original normal gates, native file-ownership gate and receipt, cold preconditions, both cold gates and joined identity/cleanup checks must pass.' } | |
| } | |
| - name: Save three-node database test results | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: always() | |
| with: | |
| name: ${{ inputs.mode == 'functional-gates' && 'functional-gates-qualification' || 'aspire-cluster-qualification' }} | |
| path: | | |
| TestResults/** | |
| ${{ runner.temp }}/functional-gates/**/native-resource-logs/** | |
| tests/KeyLoad.IntegrationTests/**/TestResults/** | |
| artifacts/qualification/** | |
| if-no-files-found: error | |
| - name: Save three-node build diagnostics | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: always() | |
| with: | |
| name: code-quality-aspire-cluster | |
| path: artifacts/code-quality/** | |
| if-no-files-found: error |