# Persona Engine - test stage # # Separate from validate.yml because the two answer different questions. Validation # asks "is this repository well-formed?" and gates every pull request. This asks "does # the engine behave correctly?" and publishes evidence. # # The Integration suite is present but disabled by default. It needs a delegated # read-only connection to a real tenant (Stage A2), which a shared build agent cannot # hold without storing credentials - and NFR-006 puts no secrets in source control. # Enable it only on an agent with an interactive or workload-identity connection, # never by adding a secret to this file. trigger: none pr: none schedules: - cron: '0 6 * * 1-5' displayName: 'Weekday morning regression' branches: include: - main always: false pool: vmImage: windows-latest parameters: - name: runIntegration displayName: 'Run the Integration suite (requires a tenant connection)' type: boolean default: false variables: pesterVersion: '5.6.1' stages: - stage: OfflineSuites displayName: 'Offline and safety suites' jobs: - job: Offline displayName: 'Offline suite' steps: - checkout: self - task: PowerShell@2 displayName: 'Install pinned Pester' inputs: pwsh: true targetType: inline script: | Set-PSRepository -Name PSGallery -InstallationPolicy Trusted Install-Module Pester -RequiredVersion $(pesterVersion) -Force -SkipPublisherCheck -Scope CurrentUser - task: PowerShell@2 displayName: 'Offline suite' inputs: pwsh: true targetType: inline script: | $ErrorActionPreference = 'Stop' $config = & ./tests/PesterConfiguration.ps1 -Suite Offline $config.Run.Exit = $false $config.Run.PassThru = $true $config.TestResult.Enabled = $true $config.TestResult.OutputPath = './testResults.offline.xml' $config.CodeCoverage.Enabled = $true $config.CodeCoverage.Path = @('./src') $config.CodeCoverage.OutputPath = './coverage.offline.xml' $config.Output.Verbosity = 'Normal' $result = Invoke-Pester -Configuration $config if ($result.TotalCount -eq 0) { throw 'The offline suite ran no tests.' } if ($result.FailedCount -gt 0) { throw "$($result.FailedCount) offline test(s) failed." } - task: PublishTestResults@2 displayName: 'Publish offline results' condition: succeededOrFailed() inputs: testResultsFormat: NUnit testResultsFiles: './testResults.offline.xml' testRunTitle: 'Persona Engine - offline suite' - task: PublishCodeCoverageResults@2 displayName: 'Publish coverage' condition: succeededOrFailed() inputs: summaryFileLocation: './coverage.offline.xml' - job: Safety displayName: 'Safety suite' dependsOn: Offline steps: - checkout: self - task: PowerShell@2 displayName: 'Install pinned Pester' inputs: pwsh: true targetType: inline script: | Set-PSRepository -Name PSGallery -InstallationPolicy Trusted Install-Module Pester -RequiredVersion $(pesterVersion) -Force -SkipPublisherCheck -Scope CurrentUser - task: PowerShell@2 displayName: 'Safety suite (SC-002, SC-004, SC-005)' inputs: pwsh: true targetType: inline script: | $ErrorActionPreference = 'Stop' $config = & ./tests/PesterConfiguration.ps1 -Suite Safety $config.Run.Exit = $false $config.Run.PassThru = $true $config.TestResult.Enabled = $true $config.TestResult.OutputPath = './testResults.safety.xml' $config.Output.Verbosity = 'Detailed' $result = Invoke-Pester -Configuration $config # The safety suite running zero tests is the most dangerous possible # green build: it is exactly what a mis-tagged file looks like, and the # assertions it drops are the zero-write and single-attribute ones. if ($result.TotalCount -eq 0) { throw 'The safety suite ran no tests. Check the Safety tag.' } if ($result.FailedCount -gt 0) { throw "$($result.FailedCount) safety test(s) failed. Do not deploy." } Write-Host "Safety suite: $($result.PassedCount) passed." - task: PublishTestResults@2 displayName: 'Publish safety results' condition: succeededOrFailed() inputs: testResultsFormat: NUnit testResultsFiles: './testResults.safety.xml' testRunTitle: 'Persona Engine - safety suite' - stage: IntegrationSuite displayName: 'Integration suite (tenant required)' dependsOn: OfflineSuites condition: and(succeeded(), eq('${{ parameters.runIntegration }}', true)) jobs: - job: Integration displayName: 'Integration suite' steps: - checkout: self - task: PowerShell@2 displayName: 'Integration suite' inputs: pwsh: true targetType: inline script: | $ErrorActionPreference = 'Stop' # No credential handling here by design. The agent must already hold a # delegated read-only connection; if it does not, this fails loudly # rather than prompting or falling back to a stored secret. if (-not (Get-Module -ListAvailable Microsoft.Graph.Authentication)) { throw 'Microsoft.Graph.Authentication is not available on this agent.' } $config = & ./tests/PesterConfiguration.ps1 -Suite Integration $config.Run.Exit = $false $config.Run.PassThru = $true $config.TestResult.Enabled = $true $config.TestResult.OutputPath = './testResults.integration.xml' $result = Invoke-Pester -Configuration $config if ($result.FailedCount -gt 0) { throw "$($result.FailedCount) integration test(s) failed." } - task: PublishTestResults@2 displayName: 'Publish integration results' condition: succeededOrFailed() inputs: testResultsFormat: NUnit testResultsFiles: './testResults.integration.xml' testRunTitle: 'Persona Engine - integration suite'