############################################################################### # gitlab-smoke-tests.ps1 - Verify GitLab instance health after upgrades # # PowerShell port of gitlab-smoke-tests.sh. Zero external dependencies # beyond PowerShell 5.1+ and git. Runs on Windows, Linux, and macOS. # # Author: Phil Connor # Contact: contact@mylinux.work # License: MIT # Version 1.00 # # Usage: # $env:GITLAB_URL = "https://gitlab.example.com" # $env:GITLAB_TOKEN = "glpat-xxxxxxxxxxxx" # .\gitlab-smoke-tests.ps1 # .\gitlab-smoke-tests.ps1 -SkipGit -SkipRegistry # .\gitlab-smoke-tests.ps1 -Insecure -Format junit # .\gitlab-smoke-tests.ps1 -Format tap ############################################################################### [CmdletBinding()] param( [string]$GitLabUrl = $env:GITLAB_URL, [string]$GitLabToken = $env:GITLAB_TOKEN, [string]$GitLabUser = $(if ($env:GITLAB_USER) { $env:GITLAB_USER } else { "root" }), [string]$HealthToken = $env:GITLAB_HEALTH_TOKEN, [string]$ProjectPrefix = $(if ($env:SMOKE_PROJECT_PREFIX) { $env:SMOKE_PROJECT_PREFIX } else { "smoke-test" }), [int]$Timeout = $(if ($env:CURL_TIMEOUT) { [int]$env:CURL_TIMEOUT } else { 10 }), [switch]$Insecure, [switch]$SkipGit, [switch]$SkipRegistry, [switch]$SkipCleanup, [ValidateSet("text","tap","junit")] [string]$Format = "text", [string]$JunitFile = "smoke-results.xml", [switch]$NoColor ) $ErrorActionPreference = "Continue" # ============================================================================ # STATE # ============================================================================ $script:Pass = 0 $script:Fail = 0 $script:Skip = 0 $script:Total = 0 $script:Results = @() $script:CleanupProjectId = "" $script:TmpDir = "" $script:StartTime = $null $script:GitCloneOk = $false # ============================================================================ # COLORS # ============================================================================ function Write-Color { param([string]$Text, [string]$Color = "White") if ($NoColor) { Write-Host $Text } else { Write-Host $Text -ForegroundColor $Color } } function Write-Log { param([string]$Msg) Write-Color "[INFO] $Msg" "Cyan" } function Write-Warn { param([string]$Msg) Write-Color "[WARN] $Msg" "Yellow" } function Write-Err { param([string]$Msg) Write-Color "[ERROR] $Msg" "Red" } # ============================================================================ # TEST RESULT RECORDING # ============================================================================ function Record-Pass { param([string]$Name, [string]$Detail = "") $script:Pass++ $script:Total++ $script:Results += [PSCustomObject]@{ Status="PASS"; Name=$Name; Detail=$Detail } if ($Format -eq "tap") { Write-Host "ok $($script:Total) - $Name" } else { $msg = " $(if($NoColor){'[PASS]'}else{[char]0x2713}) $Name" if ($Detail) { $msg += " - $Detail" } Write-Color $msg "Green" } } function Record-Fail { param([string]$Name, [string]$Detail = "") $script:Fail++ $script:Total++ $script:Results += [PSCustomObject]@{ Status="FAIL"; Name=$Name; Detail=$Detail } if ($Format -eq "tap") { Write-Host "not ok $($script:Total) - $Name" if ($Detail) { Write-Host " # $Detail" } } else { $msg = " $(if($NoColor){'[FAIL]'}else{[char]0x2717}) $Name" if ($Detail) { $msg += " - $Detail" } Write-Color $msg "Red" } } function Record-Skip { param([string]$Name, [string]$Reason = "") $script:Skip++ $script:Total++ $script:Results += [PSCustomObject]@{ Status="SKIP"; Name=$Name; Detail=$Reason } if ($Format -eq "tap") { Write-Host "ok $($script:Total) - $Name # SKIP $Reason" } else { $msg = " $(if($NoColor){'[SKIP]'}else{[char]0x2298}) $Name" if ($Reason) { $msg += " - $Reason" } Write-Color $msg "Yellow" } } # ============================================================================ # HTTP HELPERS # ============================================================================ function Invoke-GitLabApi { param( [string]$Method, [string]$Endpoint, [string]$Body = $null, [switch]$StatusOnly ) $uri = "$GitLabUrl/api/v4$Endpoint" $headers = @{ "Content-Type" = "application/json" } if ($GitLabToken) { $headers["PRIVATE-TOKEN"] = $GitLabToken } $params = @{ Uri = $uri Method = $Method Headers = $headers TimeoutSec = $Timeout UseBasicParsing = $true ErrorAction = "Stop" } if ($Insecure -and $PSVersionTable.PSVersion.Major -ge 7) { $params["SkipCertificateCheck"] = $true } if ($Body) { $params["Body"] = $Body } try { if ($StatusOnly) { $response = Invoke-WebRequest @params return [int]$response.StatusCode } else { return Invoke-RestMethod @params } } catch { if ($StatusOnly) { if ($_.Exception.Response) { return [int]$_.Exception.Response.StatusCode } return 0 } return $null } } function Invoke-HealthCheck { param([string]$Path) $uri = "$GitLabUrl$Path" if ($HealthToken) { $uri += "?token=$HealthToken" } $params = @{ Uri = $uri Method = "GET" TimeoutSec = $Timeout UseBasicParsing = $true ErrorAction = "Stop" } if ($Insecure -and $PSVersionTable.PSVersion.Major -ge 7) { $params["SkipCertificateCheck"] = $true } try { $response = Invoke-WebRequest @params return [int]$response.StatusCode } catch { if ($_.Exception.Response) { return [int]$_.Exception.Response.StatusCode } return 0 } } # ============================================================================ # TLS HELPER # ============================================================================ function Get-TlsCertExpiry { param([string]$HostName, [int]$Port = 443) try { $tcpClient = New-Object System.Net.Sockets.TcpClient $tcpClient.ReceiveTimeout = $Timeout * 1000 $tcpClient.SendTimeout = $Timeout * 1000 $tcpClient.Connect($HostName, $Port) $sslStream = New-Object System.Net.Security.SslStream( $tcpClient.GetStream(), $false, { param($s,$c,$ch,$e) return $true } ) $sslStream.AuthenticateAsClient($HostName) $cert = $sslStream.RemoteCertificate $expiry = [DateTime]$cert.GetExpirationDateString() $sslStream.Dispose() $tcpClient.Dispose() return $expiry } catch { return $null } } # ============================================================================ # TEST SUITES # ============================================================================ # -- 1. Connectivity -------------------------------------------------------- function Test-Connectivity { Write-Host "" Write-Color "Connectivity" "White" # 1a. Health endpoint $code = Invoke-HealthCheck "/-/health" if ($code -eq 200) { Record-Pass "GitLab health endpoint reachable" "HTTP $code" } else { Record-Fail "GitLab health endpoint reachable" "HTTP $code" } # 1b. Readiness $code = Invoke-HealthCheck "/-/readiness" if ($code -eq 200) { Record-Pass "GitLab readiness check" "HTTP $code" } else { Record-Fail "GitLab readiness check" "HTTP $code" } # 1c. Liveness $code = Invoke-HealthCheck "/-/liveness" if ($code -eq 200) { Record-Pass "GitLab liveness check" "HTTP $code" } else { Record-Fail "GitLab liveness check" "HTTP $code" } # 1d. TLS certificate if ($GitLabUrl -match "^https://") { $hostPart = $GitLabUrl -replace "^https://", "" -replace "/.*", "" -replace ":.*", "" $portPart = 443 if ($GitLabUrl -match ":(\d+)") { $portPart = [int]$Matches[1] } $expiry = Get-TlsCertExpiry -HostName $hostPart -Port $portPart if ($expiry) { $daysLeft = [math]::Floor(($expiry - (Get-Date)).TotalDays) if ($daysLeft -gt 30) { Record-Pass "TLS certificate valid" "$daysLeft days remaining" } elseif ($daysLeft -gt 0) { Record-Pass "TLS certificate valid" "$daysLeft days remaining (renew soon)" } else { Record-Fail "TLS certificate valid" "expired or expiring in $daysLeft days" } } else { Record-Skip "TLS certificate check" "could not retrieve certificate" } } else { Record-Skip "TLS certificate check" "not using HTTPS" } } # -- 2. API ---------------------------------------------------------------- function Test-Api { Write-Host "" Write-Color "API" "White" # 2a. Version $versionData = Invoke-GitLabApi -Method GET -Endpoint "/version" if ($versionData -and $versionData.version) { Record-Pass "API version endpoint" "GitLab $($versionData.version) ($($versionData.revision))" } else { Record-Fail "API version endpoint" "no version returned" } # 2b. Authentication $authStatus = Invoke-GitLabApi -Method GET -Endpoint "/user" -StatusOnly if ($authStatus -eq 200) { $userData = Invoke-GitLabApi -Method GET -Endpoint "/user" Record-Pass "API authentication" "authenticated as $($userData.username)" } elseif ($authStatus -eq 401) { Record-Fail "API authentication" "token rejected (HTTP 401)" } else { Record-Fail "API authentication" "HTTP $authStatus" } # 2c. List projects $projStatus = Invoke-GitLabApi -Method GET -Endpoint "/projects?per_page=1" -StatusOnly if ($projStatus -eq 200) { Record-Pass "API list projects" "database responding" } else { Record-Fail "API list projects" "HTTP $projStatus" } # 2d. List users $userStatus = Invoke-GitLabApi -Method GET -Endpoint "/users?per_page=1" -StatusOnly if ($userStatus -eq 200) { Record-Pass "API list users" "user directory accessible" } else { Record-Fail "API list users" "HTTP $userStatus" } # 2e. Sidekiq $sidekiq = Invoke-GitLabApi -Method GET -Endpoint "/sidekiq/compound_metrics" if ($sidekiq -and -not $sidekiq.error) { $procCount = 0 if ($sidekiq.processes) { $procCount = @($sidekiq.processes).Count } Record-Pass "Sidekiq running" "$procCount process(es) responding" } else { Record-Fail "Sidekiq running" "could not query Sidekiq metrics" } # 2f. Runners $runnerStatus = Invoke-GitLabApi -Method GET -Endpoint "/runners/all?per_page=1" -StatusOnly if ($runnerStatus -eq 200) { Record-Pass "API runners endpoint" "runner management accessible" } elseif ($runnerStatus -eq 403) { Record-Skip "API runners endpoint" "token lacks admin scope" } else { Record-Fail "API runners endpoint" "HTTP $runnerStatus" } # 2g. Search $searchStatus = Invoke-GitLabApi -Method GET -Endpoint "/search?scope=projects&search=test" -StatusOnly if ($searchStatus -eq 200) { Record-Pass "API search" "search index responding" } elseif ($searchStatus -eq 403) { Record-Skip "API search" "search disabled or token lacks scope" } else { Record-Fail "API search" "HTTP $searchStatus" } } # -- 3. Git Operations ----------------------------------------------------- function Test-Git { if ($SkipGit) { Write-Host "" Write-Color "Git Operations" "White" Record-Skip "Git clone" "SkipGit specified" Record-Skip "Git push" "SkipGit specified" return } Write-Host "" Write-Color "Git Operations" "White" # Create test project $projectName = "$ProjectPrefix-$([DateTimeOffset]::UtcNow.ToUnixTimeSeconds())" $body = @{ name = $projectName; visibility = "private"; initialize_with_readme = $true } | ConvertTo-Json $project = Invoke-GitLabApi -Method POST -Endpoint "/projects" -Body $body if (-not $project -or -not $project.id) { Record-Fail "Create test project" "API returned no project ID" Record-Skip "Git clone" "no test project" Record-Skip "Git push" "no test project" return } $script:CleanupProjectId = $project.id Record-Pass "Create test project" "$projectName (ID: $($project.id))" # Build clone URL $httpUrl = $project.http_url_to_repo if (-not $httpUrl) { $httpUrl = "$GitLabUrl/$GitLabUser/$projectName.git" } # Rewrite origin if API returns an internal hostname $apiOrigin = if ($httpUrl -match "^(https?://[^/]+)") { $Matches[1] } else { "" } if ($apiOrigin -and $apiOrigin -ne $GitLabUrl) { $httpUrl = $httpUrl -replace [regex]::Escape($apiOrigin), $GitLabUrl } # Inject token if ($httpUrl -match "^https://") { $cloneUrl = $httpUrl -replace "^https://", "https://oauth2:${GitLabToken}@" } elseif ($httpUrl -match "^http://") { $cloneUrl = $httpUrl -replace "^http://", "http://oauth2:${GitLabToken}@" } else { $cloneUrl = $httpUrl } # Temp directory $script:TmpDir = Join-Path ([System.IO.Path]::GetTempPath()) "gitlab-smoke-$([guid]::NewGuid().ToString('N').Substring(0,8))" New-Item -ItemType Directory -Path $script:TmpDir -Force | Out-Null # Wait for repo init Start-Sleep -Seconds 2 # Clone $gitArgs = @("clone") if ($Insecure) { $env:GIT_SSL_NO_VERIFY = "true" } $repoDir = Join-Path $script:TmpDir "repo" $cloneOutput = & git clone $cloneUrl $repoDir 2>&1 $cloneRc = $LASTEXITCODE if ($cloneRc -eq 0) { $script:GitCloneOk = $true Record-Pass "Git clone (HTTPS)" "Gitaly responding" } else { $shortErr = ($cloneOutput | Select-String -Pattern "fatal|error" | Select-Object -First 1) -replace [regex]::Escape($GitLabToken), "[REDACTED]" Record-Fail "Git clone (HTTPS)" "$shortErr" return } # Push Push-Location $repoDir try { & git config user.email "smoke-test@example.com" & git config user.name "Smoke Test" "smoke test $(Get-Date -Format 'yyyy-MM-ddTHH:mm:ssZ')" | Out-File -FilePath "smoke-test.txt" -Encoding utf8 & git add smoke-test.txt & git commit -m "smoke test commit" 2>&1 | Out-Null $pushOutput = & git push origin main 2>&1 $pushRc = $LASTEXITCODE if ($pushRc -ne 0) { $pushOutput = & git push origin master 2>&1 $pushRc = $LASTEXITCODE } if ($pushRc -eq 0) { Record-Pass "Git push (HTTPS)" "write to Gitaly succeeded" } else { Record-Fail "Git push (HTTPS)" "push failed" } } finally { Pop-Location } } # -- 4. Container Registry ------------------------------------------------- function Test-Registry { if ($SkipRegistry) { Write-Host "" Write-Color "Container Registry" "White" Record-Skip "Registry API" "SkipRegistry specified" return } Write-Host "" Write-Color "Container Registry" "White" # Check if registry is enabled $registryEnabled = "" $settings = Invoke-GitLabApi -Method GET -Endpoint "/application/settings" if ($settings) { $registryEnabled = $settings.container_registry_enabled } if ($registryEnabled -eq $false) { Record-Skip "Registry API reachable" "container registry disabled in application settings" Record-Skip "Registry project endpoint" "container registry disabled in application settings" return } # Try registry v2 API $hostPart = $GitLabUrl -replace "^https?://", "" -replace "/.*", "" $registryStatus = 0 $registryUrls = @( "$GitLabUrl`:5050/v2/", "https://${hostPart}:5050/v2/", "https://registry.${hostPart}/v2/" ) foreach ($regUrl in $registryUrls) { try { $params = @{ Uri = $regUrl Method = "GET" TimeoutSec = $Timeout UseBasicParsing = $true ErrorAction = "Stop" } if ($Insecure -and $PSVersionTable.PSVersion.Major -ge 7) { $params["SkipCertificateCheck"] = $true } $response = Invoke-WebRequest @params $registryStatus = [int]$response.StatusCode break } catch { if ($_.Exception.Response) { $registryStatus = [int]$_.Exception.Response.StatusCode if ($registryStatus -eq 401) { break } } } } if ($registryStatus -eq 200 -or $registryStatus -eq 401) { Record-Pass "Registry API reachable" "HTTP $registryStatus" } elseif ($registryStatus -eq 0) { if ($registryEnabled -eq $true) { Record-Fail "Registry API reachable" "enabled in settings but not reachable at standard ports/hosts" } else { Record-Skip "Registry API reachable" "not found at standard ports/hosts (settings unreadable - may need admin token)" } } else { Record-Fail "Registry API reachable" "HTTP $registryStatus" } # Project-level registry if ($script:CleanupProjectId) { $regStatus = Invoke-GitLabApi -Method GET -Endpoint "/projects/$($script:CleanupProjectId)/registry/repositories" -StatusOnly if ($regStatus -eq 200) { Record-Pass "Registry project endpoint" "project registry accessible" } elseif ($regStatus -eq 404) { Record-Skip "Registry project endpoint" "container registry not enabled for project" } else { Record-Fail "Registry project endpoint" "HTTP $regStatus" } } } # -- 5. CI/CD -------------------------------------------------------------- function Test-CICD { Write-Host "" Write-Color "CI/CD" "White" # Runners $runners = Invoke-GitLabApi -Method GET -Endpoint "/runners/all?per_page=100" if ($runners -is [array]) { $runnerCount = $runners.Count $onlineCount = @($runners | Where-Object { $_.status -eq "online" }).Count if ($onlineCount -gt 0) { Record-Pass "CI/CD runners online" "$onlineCount/$runnerCount runners online" } elseif ($runnerCount -gt 0) { Record-Fail "CI/CD runners online" "0/$runnerCount runners online" } else { Record-Skip "CI/CD runners online" "no runners registered" } } else { Record-Skip "CI/CD runners" "could not query runners (admin token required)" } # CI/CD settings $cicdStatus = Invoke-GitLabApi -Method GET -Endpoint "/application/settings" -StatusOnly if ($cicdStatus -eq 200) { Record-Pass "CI/CD settings accessible" "application settings readable" } elseif ($cicdStatus -eq 403) { Record-Skip "CI/CD settings accessible" "admin token required" } else { Record-Fail "CI/CD settings accessible" "HTTP $cicdStatus" } } # -- 6. Background Migrations ---------------------------------------------- function Test-Migrations { Write-Host "" Write-Color "Background Migrations" "White" $migrations = Invoke-GitLabApi -Method GET -Endpoint "/admin/batched_background_migrations?database=main" if ($migrations -is [array]) { $totalMig = $migrations.Count $failedMig = @($migrations | Where-Object { $_.status -eq "failed" }).Count $activeMig = @($migrations | Where-Object { $_.status -eq "active" }).Count $pausedMig = @($migrations | Where-Object { $_.status -eq "paused" }).Count $finishedMig = @($migrations | Where-Object { $_.status -eq "finished" }).Count if ($failedMig -gt 0) { Record-Fail "Background migrations" "$failedMig failed, $activeMig active, $pausedMig paused, $finishedMig finished of $totalMig" } elseif ($pausedMig -gt 0) { Record-Fail "Background migrations" "$pausedMig paused, $activeMig active, $finishedMig finished of $totalMig" } elseif ($activeMig -gt 0) { Record-Pass "Background migrations" "$activeMig active, $finishedMig finished of $totalMig (in progress)" } else { Record-Pass "Background migrations" "all $totalMig finished" } } else { $migStatus = Invoke-GitLabApi -Method GET -Endpoint "/admin/batched_background_migrations?database=main" -StatusOnly if ($migStatus -eq 403) { Record-Skip "Background migrations" "admin token required" } else { Record-Skip "Background migrations" "could not query (HTTP $migStatus)" } } } # -- 7. Components --------------------------------------------------------- function Test-Components { Write-Host "" Write-Color "Components" "White" # Metadata $metadata = Invoke-GitLabApi -Method GET -Endpoint "/metadata" if ($metadata -and $metadata.version) { $edition = if ($metadata.enterprise -eq $true) { "EE" } else { "CE" } Record-Pass "GitLab metadata" "$($metadata.version) $edition" } elseif ($metadata) { Record-Pass "GitLab metadata" "endpoint reachable" } else { Record-Skip "GitLab metadata" "metadata endpoint not available" } # Statistics $stats = Invoke-GitLabApi -Method GET -Endpoint "/application/statistics" if ($stats -and $stats.active_users) { Record-Pass "Instance statistics" "$($stats.active_users) users, $($stats.projects) projects, $($stats.groups) groups" } elseif ($stats) { Record-Pass "Instance statistics" "endpoint reachable" } else { Record-Skip "Instance statistics" "admin token required" } # Gitaly (inferred) if ($script:GitCloneOk) { Record-Pass "Gitaly storage" "project created and cloned successfully" } elseif ($script:CleanupProjectId) { Record-Skip "Gitaly storage" "project created but clone was not tested or failed" } # PostgreSQL (inferred) $pgStatus = Invoke-GitLabApi -Method GET -Endpoint "/projects?per_page=1&order_by=updated_at" -StatusOnly if ($pgStatus -eq 200) { Record-Pass "PostgreSQL" "database queries succeeding" } else { Record-Fail "PostgreSQL" "sorted query failed (HTTP $pgStatus)" } # Redis (inferred) $redisStatus = Invoke-GitLabApi -Method GET -Endpoint "/user" -StatusOnly if ($redisStatus -eq 200) { Record-Pass "Redis" "session/cache operational (auth succeeded)" } else { Record-Skip "Redis" "cannot verify independently" } } # ============================================================================ # OUTPUT # ============================================================================ function Write-Summary { $duration = [math]::Floor(((Get-Date) - $script:StartTime).TotalSeconds) Write-Host "" $separator = [string]::new([char]0x2500, 40) Write-Color $separator "White" Write-Color "Summary $GitLabUrl" "White" $summaryLine = " $($script:Pass) passed $($script:Fail) failed $($script:Skip) skipped (${duration}s)" Write-Host $summaryLine Write-Color $separator "White" if ($script:Fail -eq 0) { Write-Color "All tests passed." "Green" } else { Write-Color "$($script:Fail) test(s) failed." "Red" } } function Write-TapHeader { Write-Host "TAP version 13" } function Write-TapFooter { Write-Host "1..$($script:Total)" Write-Host "# pass $($script:Pass)" Write-Host "# fail $($script:Fail)" Write-Host "# skip $($script:Skip)" } function Write-JunitReport { $duration = [math]::Floor(((Get-Date) - $script:StartTime).TotalSeconds) $xml = @" "@ foreach ($r in $script:Results) { $safeName = $r.Name -replace '&','&' -replace '<','<' -replace '>','>' -replace '"','"' $safeDetail = $r.Detail -replace '&','&' -replace '<','<' -replace '>','>' -replace '"','"' switch ($r.Status) { "PASS" { $xml += "`n " if ($r.Detail) { $xml += "`n $safeDetail" } $xml += "`n " } "FAIL" { $xml += "`n " $xml += "`n FAILED: $safeName - $safeDetail" $xml += "`n " } "SKIP" { $xml += "`n " $xml += "`n " $xml += "`n " } } } $xml += "`n " $xml += "`n" $xml | Out-File -FilePath $JunitFile -Encoding utf8 Write-Log "JUnit report written to $JunitFile" } # ============================================================================ # CLEANUP # ============================================================================ function Invoke-Cleanup { if ($script:CleanupProjectId -and -not $SkipCleanup) { try { Invoke-GitLabApi -Method DELETE -Endpoint "/projects/$($script:CleanupProjectId)" | Out-Null } catch { } } if ($script:TmpDir -and (Test-Path $script:TmpDir)) { Remove-Item -Recurse -Force $script:TmpDir -ErrorAction SilentlyContinue } if ($env:GIT_SSL_NO_VERIFY) { Remove-Item Env:\GIT_SSL_NO_VERIFY -ErrorAction SilentlyContinue } } # ============================================================================ # MAIN # ============================================================================ function Show-Usage { @" Usage: .\gitlab-smoke-tests.ps1 [OPTIONS] Smoke-test a GitLab instance. PowerShell 5.1+, git only. Designed for air-gapped environments. Required environment variables: GITLAB_URL GitLab base URL (https://gitlab.example.com) GITLAB_TOKEN Personal access token (api scope; admin for full coverage) Optional environment variables: GITLAB_HEALTH_TOKEN Health check access token GITLAB_USER Username for git operations (default: root) Parameters: -SkipGit Skip git clone/push tests -SkipRegistry Skip container registry tests -SkipCleanup Don't delete the test project after run -Insecure Allow self-signed TLS certificates -Timeout N HTTP timeout in seconds (default: 10) -Format FORMAT Output: text (default), tap, junit -JunitFile FILE JUnit output path (default: smoke-results.xml) -NoColor Disable colored output -Verbose Show debug output Examples: `$env:GITLAB_URL = "https://gitlab.example.com" `$env:GITLAB_TOKEN = "glpat-xxxxxxxxxxxx" .\gitlab-smoke-tests.ps1 .\gitlab-smoke-tests.ps1 -Insecure -Format junit .\gitlab-smoke-tests.ps1 -SkipGit -SkipRegistry .\gitlab-smoke-tests.ps1 -Format tap "@ } # Handle PS 5.1 TLS and self-signed certs if ($PSVersionTable.PSVersion.Major -lt 7) { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 if ($Insecure) { Add-Type @" using System.Net; using System.Security.Cryptography.X509Certificates; public class TrustAll : ICertificatePolicy { public bool CheckValidationResult(ServicePoint sp, X509Certificate cert, WebRequest req, int problem) { return true; } } "@ -ErrorAction SilentlyContinue [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAll } } # Validate if (-not $GitLabUrl) { Write-Err "GITLAB_URL is required" Write-Host "" Show-Usage exit 1 } if (-not $GitLabToken) { Write-Err "GITLAB_TOKEN is required" Write-Host "" Show-Usage exit 1 } $GitLabUrl = $GitLabUrl.TrimEnd("/") $script:StartTime = Get-Date if ($Format -eq "tap") { Write-TapHeader } else { Write-Host "" Write-Color "GitLab Smoke Tests" "White" Write-Host "Target: $GitLabUrl" Write-Host "Time: $(Get-Date -Format 'yyyy-MM-ddTHH:mm:ssZ')" Write-Host "" } try { Test-Connectivity Test-Api Test-Git Test-Registry Test-CICD Test-Migrations Test-Components } finally { Invoke-Cleanup } if ($Format -eq "tap") { Write-TapFooter } elseif ($Format -eq "junit") { Write-Summary Write-JunitReport } else { Write-Summary } if ($script:Fail -eq 0) { exit 0 } else { exit 1 }