240 lines
10 KiB
PowerShell
240 lines
10 KiB
PowerShell
# 配置文件专项测试:验证 daili.ini 的生成、解析、覆盖与各项生效
|
||
# 用法: powershell -NoProfile -ExecutionPolicy Bypass -File scripts\config-test.ps1
|
||
param(
|
||
[string]$Exe = '',
|
||
[string]$Work = '',
|
||
[string]$LanIp = ''
|
||
)
|
||
|
||
$Root = Split-Path -Parent $PSScriptRoot
|
||
if (-not $Exe) { $Exe = Join-Path $Root 'daili.exe' }
|
||
if (-not $Work) { $Work = Join-Path $Root 'config-run' }
|
||
$Evidence = Join-Path $Root 'test-evidence'
|
||
if (-not (Test-Path $Exe)) { throw "找不到被测程序:$Exe(先构建或已用 -Exe 指定)" }
|
||
|
||
$ErrorActionPreference = 'Continue'
|
||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||
Add-Type -AssemblyName System.Net.Http
|
||
|
||
$script:fail = 0
|
||
$script:results = @()
|
||
function Check {
|
||
param([string]$Id, [string]$Name, $Cond, [string]$Detail = '')
|
||
if ($Cond -eq $true) {
|
||
Write-Host (" [PASS] {0} {1}" -f $Id, $Name) -ForegroundColor Green
|
||
$script:results += "PASS|$Id|$Name|$Detail"
|
||
} else {
|
||
Write-Host (" [FAIL] {0} {1} {2}" -f $Id, $Name, $Detail) -ForegroundColor Red
|
||
$script:results += "FAIL|$Id|$Name|$Detail"
|
||
$script:fail++
|
||
}
|
||
}
|
||
|
||
function New-Client {
|
||
$h = New-Object System.Net.Http.HttpClientHandler
|
||
$h.UseCookies = $true
|
||
$h.AllowAutoRedirect = $true
|
||
$c = New-Object System.Net.Http.HttpClient($h)
|
||
$c.Timeout = [TimeSpan]::FromSeconds(10)
|
||
return $c
|
||
}
|
||
|
||
function Post-Form($client, $url, $kv) {
|
||
$pairs = New-Object 'System.Collections.Generic.List[System.Collections.Generic.KeyValuePair[string,string]]'
|
||
foreach ($k in $kv.Keys) {
|
||
$pairs.Add([System.Collections.Generic.KeyValuePair[string,string]]::new($k, [string]$kv[$k]))
|
||
}
|
||
return $client.PostAsync($url, [System.Net.Http.FormUrlEncodedContent]::new($pairs)).Result
|
||
}
|
||
|
||
function Get-Status($client, $url) {
|
||
try {
|
||
$r = $client.GetAsync($url).Result
|
||
return @{ Code = [int]$r.StatusCode; Path = $r.RequestMessage.RequestUri.AbsolutePath; Body = $r.Content.ReadAsStringAsync().Result }
|
||
} catch {
|
||
return @{ Code = 0; Path = ''; Body = '' }
|
||
}
|
||
}
|
||
|
||
function Wait-Up([int]$port, [int]$seconds = 15) {
|
||
$c = New-Client
|
||
for ($i = 0; $i -lt ($seconds * 4); $i++) {
|
||
$r = Get-Status $c "http://127.0.0.1:$port/healthz"
|
||
if ($r.Code -eq 200) { return $true }
|
||
Start-Sleep -Milliseconds 250
|
||
}
|
||
return $false
|
||
}
|
||
|
||
function Start-App([string]$dir, [string[]]$extra, [int]$port) {
|
||
$out = Join-Path $dir 'stdout.log'
|
||
$err = Join-Path $dir 'stderr.log'
|
||
$p = Start-Process -FilePath (Join-Path $dir 'daili.exe') -ArgumentList $extra -WorkingDirectory $dir `
|
||
-WindowStyle Hidden -PassThru -RedirectStandardOutput $out -RedirectStandardError $err
|
||
$ok = Wait-Up $port
|
||
return @{ Proc = $p; Out = $out; Err = $err; Up = $ok }
|
||
}
|
||
|
||
function Stop-App($h) {
|
||
if ($h -and $h.Proc) { Stop-Process -Id $h.Proc.Id -Force -ErrorAction SilentlyContinue }
|
||
Start-Sleep -Milliseconds 600
|
||
}
|
||
|
||
function New-CaseDir([string]$name) {
|
||
$dir = Join-Path $Work $name
|
||
Remove-Item -Recurse -Force $dir -ErrorAction SilentlyContinue
|
||
New-Item -ItemType Directory -Force -Path $dir | Out-Null
|
||
Copy-Item $Exe (Join-Path $dir 'daili.exe') -Force
|
||
return $dir
|
||
}
|
||
|
||
function Write-Conf([string]$dir, [string]$text) {
|
||
[System.IO.File]::WriteAllText((Join-Path $dir 'daili.ini'), $text, (New-Object System.Text.UTF8Encoding($false)))
|
||
}
|
||
|
||
if (-not $LanIp) {
|
||
$LanIp = @(Get-NetIPAddress -AddressFamily IPv4 -ErrorAction SilentlyContinue |
|
||
Where-Object { $_.IPAddress -notlike '127.*' -and $_.IPAddress -notlike '169.254.*' -and $_.PrefixOrigin -ne 'WellKnown' } |
|
||
Select-Object -First 1 -ExpandProperty IPAddress)
|
||
}
|
||
if (-not $LanIp) { $LanIp = '192.168.1.1' }
|
||
|
||
Remove-Item -Recurse -Force $Work -ErrorAction SilentlyContinue
|
||
New-Item -ItemType Directory -Force -Path $Work | Out-Null
|
||
|
||
Write-Host "`n=== 配置文件专项测试(LAN IP: $LanIp) ===" -ForegroundColor Cyan
|
||
$c = New-Client
|
||
|
||
# ---------- CFG-01 / CFG-02:首启生成默认配置 + 默认端口 17777 ----------
|
||
Write-Host "`n-- CFG-01/02 首次启动生成默认配置 --" -ForegroundColor Cyan
|
||
$d1 = New-CaseDir 'default'
|
||
$h = Start-App $d1 @('-no-open') 17777
|
||
$ini = Join-Path $d1 'daili.ini'
|
||
Check 'CFG-01a' '首次启动自动生成 daili.ini' (Test-Path $ini)
|
||
$iniText = Get-Content $ini -Raw -Encoding UTF8
|
||
Check 'CFG-01b' '默认配置含注释与默认监听' (($iniText -match '代打台 配置文件') -and ($iniText -match 'listen_ip = 0\.0\.0\.0') -and ($iniText -match 'listen_port = 17777') -and ($iniText -match 'screen_public = true'))
|
||
$r = Get-Status $c 'http://127.0.0.1:17777/healthz'
|
||
Check 'CFG-02' '默认监听 17777 可用' ($h.Up -and $r.Code -eq 200) "health=$($r.Code)"
|
||
Stop-App $h
|
||
$logDir = Join-Path $d1 'logs'
|
||
$logs = @(Get-ChildItem $logDir -Filter 'daili-*.log' -ErrorAction SilentlyContinue)
|
||
$logText = ''
|
||
if ($logs.Count -ge 1) { $logText = Get-Content $logs[0].FullName -Raw -Encoding UTF8 }
|
||
Check 'CFG-07' '运行日志按天落盘' ($logs.Count -ge 1 -and $logText.Length -gt 20) "files=$($logs.Count) bytes=$($logText.Length)"
|
||
|
||
# ---------- CFG-03:只监听本机 ----------
|
||
Write-Host "`n-- CFG-03 仅本机监听 --" -ForegroundColor Cyan
|
||
$d2 = New-CaseDir 'loopback'
|
||
Write-Conf $d2 @"
|
||
listen_ip = 127.0.0.1
|
||
listen_port = 17901
|
||
open_browser = false
|
||
log_enabled = false
|
||
backup_enabled = false
|
||
"@
|
||
$h = Start-App $d2 @('-no-open') 17901
|
||
$local = (Test-NetConnection -ComputerName 127.0.0.1 -Port 17901 -InformationLevel Quiet -WarningAction SilentlyContinue)
|
||
$lan = (Test-NetConnection -ComputerName $LanIp -Port 17901 -InformationLevel Quiet -WarningAction SilentlyContinue)
|
||
Check 'CFG-03' '127.0.0.1 只开本机,局域网不可连' ($h.Up -and $local -and -not $lan) "local=$local lan=$lan"
|
||
$banner = Get-Content (Join-Path $d2 'stdout.log') -Raw -Encoding UTF8
|
||
Check 'CFG-03b' '横幅不再打印局域网地址' (-not ($banner -match '局域网')) ""
|
||
Stop-App $h
|
||
|
||
# ---------- CFG-04:非法配置报错退出且不改文件 ----------
|
||
Write-Host "`n-- CFG-04 非法配置 --" -ForegroundColor Cyan
|
||
$d3 = New-CaseDir 'invalid'
|
||
Write-Conf $d3 "# 故意写错`nlisten_ip = 0.0.0.0`nlisten_port = 99999`n"
|
||
$badIni = Join-Path $d3 'daili.ini'
|
||
$hashBefore = (Get-FileHash $badIni -Algorithm SHA256).Hash
|
||
$outText = & (Join-Path $d3 'daili.exe') -no-open 2>&1 | Out-String
|
||
$code = $LASTEXITCODE
|
||
$hashAfter = (Get-FileHash $badIni -Algorithm SHA256).Hash
|
||
Check 'CFG-04a' '非法配置退出码为 1' ($code -eq 1) "code=$code"
|
||
Check 'CFG-04b' '错误信息指出行号' ($outText -match '第 3 行' -and $outText -match '1-65535') ""
|
||
Check 'CFG-04c' '原配置文件未被改动' ($hashBefore -eq $hashAfter) ""
|
||
|
||
# ---------- CFG-05:命令行覆盖配置 ----------
|
||
Write-Host "`n-- CFG-05 命令行覆盖 --" -ForegroundColor Cyan
|
||
$d4 = New-CaseDir 'override'
|
||
Write-Conf $d4 @"
|
||
listen_ip = 127.0.0.1
|
||
listen_port = 17902
|
||
open_browser = false
|
||
log_enabled = false
|
||
backup_enabled = false
|
||
"@
|
||
$h = Start-App $d4 @('-no-open', '-addr', '127.0.0.1:17903') 17903
|
||
$p17902 = (Test-NetConnection -ComputerName 127.0.0.1 -Port 17902 -InformationLevel Quiet -WarningAction SilentlyContinue)
|
||
Check 'CFG-05' '-addr 覆盖配置文件端口' ($h.Up -and -not $p17902) "up17903=$($h.Up) up17902=$p17902"
|
||
Stop-App $h
|
||
|
||
# ---------- CFG-06:大屏鉴权开关 ----------
|
||
Write-Host "`n-- CFG-06 大屏访问控制 --" -ForegroundColor Cyan
|
||
$d5 = New-CaseDir 'screen-private'
|
||
Write-Conf $d5 @"
|
||
listen_ip = 127.0.0.1
|
||
listen_port = 17904
|
||
open_browser = false
|
||
screen_public = false
|
||
log_enabled = false
|
||
backup_enabled = false
|
||
"@
|
||
$h = Start-App $d5 @('-no-open') 17904
|
||
$anon = New-Client
|
||
$r = Get-Status $anon 'http://127.0.0.1:17904/screen'
|
||
Check 'CFG-06' 'screen_public=false 时大屏需登录' (($r.Path -like '/login*') -or ($r.Path -eq '/setup')) "path=$($r.Path)"
|
||
Stop-App $h
|
||
|
||
# ---------- CFG-08:备份目录与保留份数来自配置 ----------
|
||
Write-Host "`n-- CFG-08 备份目录与保留份数 --" -ForegroundColor Cyan
|
||
$d6 = New-CaseDir 'backup'
|
||
$bdir = Join-Path $d6 'my-backup'
|
||
Write-Conf $d6 @"
|
||
listen_ip = 127.0.0.1
|
||
listen_port = 17905
|
||
open_browser = false
|
||
log_enabled = false
|
||
backup_enabled = true
|
||
backup_dir = $bdir
|
||
backup_keep = 1
|
||
"@
|
||
$h = Start-App $d6 @('-no-open') 17905
|
||
$c6 = New-Client
|
||
Post-Form $c6 'http://127.0.0.1:17905/setup' @{ username = 'admin'; display_name = '老板'; password = 'daili123'; password2 = 'daili123' } | Out-Null
|
||
Post-Form $c6 'http://127.0.0.1:17905/packages' @{ name = '包月日常'; unit = 'day'; default_amount = '30'; color = '#2F5D50'; sort_order = '1' } | Out-Null
|
||
Post-Form $c6 'http://127.0.0.1:17905/customers' @{ tail = '3001'; name = '备份客户'; game_name = ''; game_server = ''; contact = ''; tags = ''; source = ''; note = '' } | Out-Null
|
||
Start-Sleep -Milliseconds 1200
|
||
Post-Form $c6 'http://127.0.0.1:17905/settings/backup' @{} | Out-Null
|
||
Start-Sleep -Milliseconds 1200
|
||
Post-Form $c6 'http://127.0.0.1:17905/settings/backup' @{} | Out-Null
|
||
$files = @(Get-ChildItem $bdir -Filter '*.db' -ErrorAction SilentlyContinue)
|
||
Check 'CFG-08a' '备份写入配置指定的目录' ($files.Count -ge 1) "dir=$bdir files=$($files.Count)"
|
||
Check 'CFG-08b' 'backup_keep=1 时只保留 1 份' ($files.Count -eq 1) "files=$($files.Count)"
|
||
Stop-App $h
|
||
|
||
# ---------- CFG-09:时区固定 ----------
|
||
Write-Host "`n-- CFG-09 时区固定 --" -ForegroundColor Cyan
|
||
$d7 = New-CaseDir 'timezone'
|
||
Write-Conf $d7 @"
|
||
listen_ip = 127.0.0.1
|
||
listen_port = 17906
|
||
open_browser = false
|
||
log_enabled = true
|
||
backup_enabled = false
|
||
timezone = Asia/Shanghai
|
||
"@
|
||
$h = Start-App $d7 @('-no-open') 17906
|
||
$errText = Get-Content (Join-Path $d7 'stderr.log') -Raw -Encoding UTF8
|
||
Check 'CFG-09' '时区固定为 Asia/Shanghai 生效' ($errText -match '时区已固定为 Asia/Shanghai') ""
|
||
Stop-App $h
|
||
|
||
# ---------- 汇总 ----------
|
||
$pass = @($script:results | Where-Object { $_ -like 'PASS|*' }).Count
|
||
$fail = @($script:results | Where-Object { $_ -like 'FAIL|*' }).Count
|
||
Write-Host "`n=== 汇总:通过 $pass 项,失败 $fail 项 ===" -ForegroundColor ($(if ($fail -eq 0) { 'Green' } else { 'Red' }))
|
||
New-Item -ItemType Directory -Force -Path $Evidence | Out-Null
|
||
$script:results | Set-Content (Join-Path $Evidence 'config-result.txt') -Encoding UTF8
|
||
Remove-Item -Recurse -Force $Work -ErrorAction SilentlyContinue
|
||
if ($fail -gt 0) { exit 1 }
|
||
exit 0
|