diff --git a/tests/AfterAll.ps1 b/tests/AfterAll.ps1 new file mode 100644 index 000000000..c872e9bc6 --- /dev/null +++ b/tests/AfterAll.ps1 @@ -0,0 +1,17 @@ +[CmdletBinding()] +param() + +LogGroup 'AfterAll - Global Test Teardown' { + + + switch ($OwnerType) { + 'user' { + Get-GitHubRepository | Where-Object { $_.Name -like "$repoPrefix*" } | Remove-GitHubRepository -Confirm:$false + } + 'organization' { + Get-GitHubRepository -Organization $Owner | Where-Object { $_.Name -like "$repoPrefix*" } | Remove-GitHubRepository -Confirm:$false + } + } + Get-GitHubContext -ListAvailable | Disconnect-GitHubAccount -Silent + Write-Host ('-' * 60) +} diff --git a/tests/BeforeAll.ps1 b/tests/BeforeAll.ps1 new file mode 100644 index 000000000..81208c9e2 --- /dev/null +++ b/tests/BeforeAll.ps1 @@ -0,0 +1,46 @@ +[CmdletBinding()] +param() + +LogGroup 'BeforeAll - Global Test Setup' { + $authCases = . "$PSScriptRoot/Data/AuthCases.ps1" + + $prefix = 'Test' + $os = $env:RUNNER_OS + $id = $env:GITHUB_RUN_ID + + foreach ($authCase in $authCases) { + $authCase.GetEnumerator() | ForEach-Object { Set-Variable -Name $_.Key -Value $_.Value } + + LogGroup 'Repository setup' { + $context = Connect-GitHubAccount @connectParams -PassThru -Silent + Write-Host ($context | Out-String) + if ($AuthType -eq 'APP') { + $context = Connect-GitHubApp @connectAppParams -PassThru -Default -Silent + Write-Host ($context | Format-List | Out-String) + } + + $repoPrefix = "$prefix-$os-$TokenType" + $repoName = "$repoPrefix-$id" + + switch ($OwnerType) { + 'user' { + Get-GitHubRepository | Where-Object { $_.Name -like "$repoPrefix*" } | Remove-GitHubRepository -Confirm:$false + New-GitHubRepository -Name $repoName -Confirm:$false + } + 'organization' { + Get-GitHubRepository -Organization $Owner | Where-Object { $_.Name -like "$repoPrefix*" } | Remove-GitHubRepository -Confirm:$false + New-GitHubRepository -Organization $Owner -Name $repoName -Confirm:$false + } + } + } + LogGroup 'Environment setup' { + $environmentName = "$prefix-$os-$TokenType-$id" + } + LogGroup 'Variables setup' { + + } + LogGroup 'Secrets setup' { + + } + } +} diff --git a/tests/Environments.Tests.ps1 b/tests/Environments.Tests.ps1 index 762eab550..3a4794270 100644 --- a/tests/Environments.Tests.ps1 +++ b/tests/Environments.Tests.ps1 @@ -22,7 +22,7 @@ param() BeforeAll { $testName = 'EnvironmentsTests' $os = $env:RUNNER_OS - $guid = [guid]::NewGuid().ToString() + $id = $env:GITHUB_RUN_ID } Describe 'Environments' { @@ -40,34 +40,17 @@ Describe 'Environments' { Write-Host ($context | Format-List | Out-String) } } - $repoPrefix = "$testName-$os-$TokenType" - $repoName = "$repoPrefix-$guid" - $environmentName = "$testName-$os-$TokenType-$guid" + $repoPrefix = "Test-$os-$TokenType" + $repoName = "$repoPrefix-$id" + $environmentName = "$testName-$os-$TokenType-$id" - switch ($OwnerType) { - 'user' { - Get-GitHubRepository | Where-Object { $_.Name -like "$repoPrefix*" } | Remove-GitHubRepository -Confirm:$false - $repo = New-GitHubRepository -Name $repoName -Confirm:$false - } - 'organization' { - Get-GitHubRepository -Organization $Owner | Where-Object { $_.Name -like "$repoPrefix*" } | Remove-GitHubRepository -Confirm:$false - $repo = New-GitHubRepository -Organization $owner -Name $repoName -Confirm:$false - } - } - LogGroup "Repository - [$repoName]" { + LogGroup "Using Repository - [$repoName]" { + $repo = Get-GitHubRepository -Owner $Owner -Repository $repoName Write-Host ($repo | Select-Object * | Out-String) } } AfterAll { - switch ($OwnerType) { - 'user' { - Get-GitHubRepository | Where-Object { $_.Name -like "$repoPrefix*" } | Remove-GitHubRepository -Confirm:$false - } - 'organization' { - Get-GitHubRepository -Organization $Owner | Where-Object { $_.Name -like "$repoPrefix*" } | Remove-GitHubRepository -Confirm:$false - } - } Get-GitHubContext -ListAvailable | Disconnect-GitHubAccount -Silent Write-Host ('-' * 60) } diff --git a/tests/Apps.Tests.ps1 b/tmp/Apps.Tests.ps1 similarity index 100% rename from tests/Apps.Tests.ps1 rename to tmp/Apps.Tests.ps1 diff --git a/tests/Artifacts.Tests.ps1 b/tmp/Artifacts.Tests.ps1 similarity index 100% rename from tests/Artifacts.Tests.ps1 rename to tmp/Artifacts.Tests.ps1 diff --git a/tests/Emojis.Tests.ps1 b/tmp/Emojis.Tests.ps1 similarity index 87% rename from tests/Emojis.Tests.ps1 rename to tmp/Emojis.Tests.ps1 index ff3100a2e..92d5308f4 100644 --- a/tests/Emojis.Tests.ps1 +++ b/tmp/Emojis.Tests.ps1 @@ -28,26 +28,18 @@ Describe 'Emojis' { LogGroup 'Context' { Write-Host ($context | Format-List | Out-String) } - } - AfterAll { - Get-GitHubContext -ListAvailable | Disconnect-GitHubAccount -Silent - Write-Host ('-' * 60) - } - - # Tests for APP goes here - if ($AuthType -eq 'APP') { - It 'Connect-GitHubApp - Connects as a GitHub App to ' { + if ($AuthType -eq 'APP') { $context = Connect-GitHubApp @connectAppParams -PassThru -Default -Silent LogGroup 'Context' { Write-Host ($context | Format-List | Out-String) } } } + AfterAll { + Get-GitHubContext -ListAvailable | Disconnect-GitHubAccount -Silent + Write-Host ('-' * 60) + } - # Tests for runners goes here - if ($Type -eq 'GitHub Actions') {} - - # Tests for IAT UAT and PAT goes here It 'Get-GitHubEmoji - Gets a list of all emojis' { $emojis = Get-GitHubEmoji LogGroup 'emojis' { diff --git a/tests/Enterprise.Tests.ps1 b/tmp/Enterprise.Tests.ps1 similarity index 98% rename from tests/Enterprise.Tests.ps1 rename to tmp/Enterprise.Tests.ps1 index b6b7a73dd..df7444c43 100644 --- a/tests/Enterprise.Tests.ps1 +++ b/tmp/Enterprise.Tests.ps1 @@ -19,10 +19,6 @@ [CmdletBinding()] param() -BeforeAll { - # DEFAULTS ACCROSS ALL TESTS -} - Describe 'Template' { $authCases = . "$PSScriptRoot/Data/AuthCases.ps1" diff --git a/tests/GitHub.Tests.ps1 b/tmp/GitHub.Tests.ps1 similarity index 100% rename from tests/GitHub.Tests.ps1 rename to tmp/GitHub.Tests.ps1 diff --git a/tests/GitHubFormatter.Tests.ps1 b/tmp/GitHubFormatter.Tests.ps1 similarity index 100% rename from tests/GitHubFormatter.Tests.ps1 rename to tmp/GitHubFormatter.Tests.ps1 diff --git a/tests/Organizations.Tests.ps1 b/tmp/Organizations.Tests.ps1 similarity index 100% rename from tests/Organizations.Tests.ps1 rename to tmp/Organizations.Tests.ps1 diff --git a/tests/Permissions.Tests.ps1 b/tmp/Permissions.Tests.ps1 similarity index 100% rename from tests/Permissions.Tests.ps1 rename to tmp/Permissions.Tests.ps1 diff --git a/tmp/README-SETUP-TEARDOWN.md b/tmp/README-SETUP-TEARDOWN.md new file mode 100644 index 000000000..227cd06dd --- /dev/null +++ b/tmp/README-SETUP-TEARDOWN.md @@ -0,0 +1,159 @@ +# Test Setup/Teardown Scripts + +This document describes the global test setup and teardown scripts used in the GitHub module test suite. + +## Overview + +The GitHub module uses Process-PSModule's BeforeAll/AfterAll support to optimize test execution and reduce rate limiting issues. + +### Key Concepts + +1. **BeforeAll.ps1** - Runs once before all parallel test jobs + - Cleans up stale resources from previous failed test runs + - Reduces rate limiting by removing orphaned artifacts upfront + - Does NOT replace individual test BeforeAll blocks + +2. **AfterAll.ps1** - Runs once after all parallel test jobs complete + - Performs final cleanup of any remaining test resources + - Provides a safety net for resources missed by individual tests + - Generates a cleanup report + +3. **Individual Test Files** - Keep their existing BeforeAll/AfterAll blocks + - Handle authentication (Connect-GitHubAccount, Connect-GitHubApp) + - Create and clean up their own isolated resources + - Support parallel execution across different auth scenarios + +## How It Works + +### Before Tests Run + +``` +Process-PSModule Workflow + ↓ +BeforeAll.ps1 (runs once) + ↓ +Parallel Test Matrix + ├─ Test File 1 → BeforeAll → Tests → AfterAll + ├─ Test File 2 → BeforeAll → Tests → AfterAll + └─ Test File 3 → BeforeAll → Tests → AfterAll + ↓ +AfterAll.ps1 (runs once) +``` + +### What Gets Cleaned Up + +Both BeforeAll.ps1 and AfterAll.ps1 clean up test resources across all authentication scenarios: + +- **Repositories**: Any repository with test name prefixes (e.g., `RepositoriesTests-*`) +- **Teams**: Teams created during tests (organization contexts only) +- **Secrets**: Organization secrets created during tests +- **Variables**: Organization variables created during tests +- **App Installations**: GitHub App installations on test organizations (APP auth only) + +### Resource Naming Convention + +Tests use a consistent naming pattern that allows the cleanup scripts to identify test resources: + +```powershell +$testName = 'RepositoriesTests' # Test file identifier +$os = $env:RUNNER_OS # Linux, Windows, macOS +$tokenType = 'USER_FG_PAT' # Auth type identifier +$guid = [guid]::NewGuid() # Unique run identifier + +$resourceName = "$testName-$os-$tokenType-$guid" +``` + +Examples: +- `RepositoriesTests-Linux-USER_FG_PAT-a1b2c3d4` +- `TeamsTests-Windows-APP_ORG-e5f6g7h8` + +The cleanup scripts look for resources matching the test name prefixes (e.g., `RepositoriesTests-*`). + +## Benefits + +1. **Speed**: Pre-cleanup ensures tests don't encounter conflicts with stale resources +2. **Rate Limiting**: Significantly fewer API calls by removing orphaned resources upfront +3. **Reliability**: Consistent test environment across all test runs +4. **Cost**: Fewer parallel operations hitting API rate limits +5. **Maintainability**: Centralized cleanup logic in two files + +## Test Prefixes + +The following test prefixes are recognized by the cleanup scripts: + +- `RepositoriesTests` +- `TeamsTests` +- `EnvironmentsTests` +- `SecretsTests` +- `VariablesTests` +- `AppsTests` +- `ArtifactsTests` +- `ReleasesTests` +- `PermissionsTests` +- `MsxOrgTests` +- `GitHubTests` + +## Authentication Scenarios + +The cleanup scripts process all authentication scenarios defined in `tests/Data/AuthCases.ps1`: + +1. **Fine-grained PAT** - User account (`psmodule-user`) +2. **Fine-grained PAT** - Organization account (`psmodule-test-org2`) +3. **Classic PAT** - User account (`psmodule-user`) +4. **GitHub Actions Token** - Repository context (`PSModule/GitHub`) +5. **GitHub App** - Organization installation (`psmodule-test-org`) +6. **GitHub App** - Enterprise installation (`psmodule-test-org3`) +7. **GitHub App** - Enterprise context (`msx`) + +## Cleanup Statistics + +Both scripts generate statistics showing: +- Number of repositories removed +- Number of teams removed +- Number of secrets removed +- Number of variables removed +- Number of app installations removed +- Number of errors encountered + +## Example Output + +``` +BeforeAll - Global Test Setup + Cleanup - psmodule-user (user) using USER_FG_PAT + Connecting to GitHub as psmodule-user... + Checking for stale repositories... + Found 3 stale repositories to remove + Removing repository: psmodule-user/RepositoriesTests-Linux-USER_FG_PAT-old1 + Removing repository: psmodule-user/TeamsTests-Linux-USER_FG_PAT-old2 + Removing repository: psmodule-user/SecretsTests-Linux-USER_FG_PAT-old3 + No stale teams found + + Cleanup Summary + Repositories removed: 12 + Teams removed: 5 + Secrets removed: 3 + Variables removed: 2 + App installations removed: 0 + Errors encountered: 0 + + All cleanup operations completed successfully. +``` + +## Troubleshooting + +### Tests Fail Due to Missing Resources + +The cleanup scripts only remove resources that match test name prefixes. If your tests are failing due to missing resources, ensure your test is creating its own resources in the BeforeAll block. + +### Cleanup Script Errors + +If the cleanup scripts encounter errors, they will continue processing other resources. Check the error messages in the workflow logs to identify the issue. Common causes: +- Insufficient permissions for the authentication token +- Rate limiting (should be rare with pre-cleanup) +- Network connectivity issues + +### Resources Not Being Cleaned + +Ensure your test resources follow the naming convention: `{TestName}-{OS}-{TokenType}-{GUID}` + +The cleanup scripts look for resources starting with the test name prefixes listed above. diff --git a/tests/README.md b/tmp/README.md similarity index 100% rename from tests/README.md rename to tmp/README.md diff --git a/tests/Releases.Tests.ps1 b/tmp/Releases.Tests.ps1 similarity index 100% rename from tests/Releases.Tests.ps1 rename to tmp/Releases.Tests.ps1 diff --git a/tests/Repositories.Tests.ps1 b/tmp/Repositories.Tests.ps1 similarity index 100% rename from tests/Repositories.Tests.ps1 rename to tmp/Repositories.Tests.ps1 diff --git a/tests/Secrets.Tests.ps1 b/tmp/Secrets.Tests.ps1 similarity index 100% rename from tests/Secrets.Tests.ps1 rename to tmp/Secrets.Tests.ps1 diff --git a/tests/TEMPLATE.ps1 b/tmp/TEMPLATE.ps1 similarity index 100% rename from tests/TEMPLATE.ps1 rename to tmp/TEMPLATE.ps1 diff --git a/tests/Teams.Tests.ps1 b/tmp/Teams.Tests.ps1 similarity index 100% rename from tests/Teams.Tests.ps1 rename to tmp/Teams.Tests.ps1 diff --git a/tests/Users.Tests.ps1 b/tmp/Users.Tests.ps1 similarity index 95% rename from tests/Users.Tests.ps1 rename to tmp/Users.Tests.ps1 index f4cb7cc32..d3d7247da 100644 --- a/tests/Users.Tests.ps1 +++ b/tmp/Users.Tests.ps1 @@ -24,23 +24,18 @@ Describe 'Users' { LogGroup 'Context' { Write-Host ($context | Format-List | Out-String) } - } - AfterAll { - Get-GitHubContext -ListAvailable | Disconnect-GitHubAccount -Silent - Write-Host ('-' * 60) - } - - # Tests for APP goes here - if ($AuthType -eq 'APP') { - It 'Connect-GitHubApp - Connects as a GitHub App to ' { + if ($AuthType -eq 'APP') { $context = Connect-GitHubApp @connectAppParams -PassThru -Default -Silent LogGroup 'Context' { Write-Host ($context | Format-List | Out-String) } } } + AfterAll { + Get-GitHubContext -ListAvailable | Disconnect-GitHubAccount -Silent + Write-Host ('-' * 60) + } - # Tests for IAT UAT and PAT goes here It 'Get-GitHubUser - Get the specified user' { { Get-GitHubUser -Name 'Octocat' } | Should -Not -Throw } diff --git a/tests/Variables.Tests.ps1 b/tmp/Variables.Tests.ps1 similarity index 100% rename from tests/Variables.Tests.ps1 rename to tmp/Variables.Tests.ps1