216 lines
9.3 KiB
PowerShell
216 lines
9.3 KiB
PowerShell
# 端到端冒烟测试:真实 HTTP 走一遍主要流程
|
||
# 用法: powershell -NoProfile -ExecutionPolicy Bypass -File scripts\smoke.ps1 -Base http://127.0.0.1:18080
|
||
param(
|
||
[string]$Base = 'http://127.0.0.1:18080',
|
||
[string]$User = 'admin',
|
||
[string]$Pass = 'daili123'
|
||
)
|
||
|
||
$ErrorActionPreference = 'Stop'
|
||
$script:fail = 0
|
||
$session = New-Object Microsoft.PowerShell.Commands.WebRequestSession
|
||
|
||
function Send {
|
||
param([string]$Method, [string]$Path, $Body)
|
||
$p = @{
|
||
Uri = "$Base$Path"
|
||
WebSession = $session
|
||
UseBasicParsing = $true
|
||
MaximumRedirection = 5
|
||
Method = $Method
|
||
}
|
||
if ($null -ne $Body) { $p.Body = $Body }
|
||
try {
|
||
return Invoke-WebRequest @p
|
||
} catch [System.Net.WebException] {
|
||
$resp = $_.Exception.Response
|
||
if ($null -eq $resp) { throw }
|
||
$sr = New-Object System.IO.StreamReader($resp.GetResponseStream())
|
||
$body = $sr.ReadToEnd()
|
||
$sr.Close()
|
||
return [pscustomobject]@{
|
||
StatusCode = [int]$resp.StatusCode
|
||
Content = $body
|
||
BaseResponse = [pscustomobject]@{ ResponseUri = $resp.ResponseUri }
|
||
}
|
||
}
|
||
}
|
||
|
||
function Check {
|
||
param([bool]$Cond, [string]$Msg)
|
||
if ($Cond) {
|
||
Write-Host (" [ok] " + $Msg) -ForegroundColor Green
|
||
} else {
|
||
Write-Host (" [FAIL] " + $Msg) -ForegroundColor Red
|
||
$script:fail++
|
||
}
|
||
}
|
||
|
||
function Final-Path($resp) {
|
||
if ($resp.PSObject.Properties.Name -contains 'BaseResponse' -and $resp.BaseResponse -and $resp.BaseResponse.ResponseUri) {
|
||
return $resp.BaseResponse.ResponseUri.AbsolutePath
|
||
}
|
||
return ''
|
||
}
|
||
|
||
$now = Get-Date
|
||
$today = $now.ToString('yyyy-MM-dd')
|
||
$tail = Get-Random -Minimum 1000 -Maximum 9999
|
||
Write-Host "`n=== 代打台冒烟测试 @ $Base ($today / 尾号 $tail) ===" -ForegroundColor Cyan
|
||
|
||
# 1. 初始化管理员(或登录)
|
||
$r = Send 'GET' '/setup'
|
||
if ($r.Content -match '创建第一个管理员') {
|
||
$r = Send 'POST' '/setup' @{ username = $User; display_name = '老板'; password = $Pass; password2 = $Pass }
|
||
Check ($r.StatusCode -eq 200) '创建管理员并自动登录'
|
||
Check ((Final-Path $r) -like '/packages*') '初始化后跳转到套餐页'
|
||
} else {
|
||
$r = Send 'POST' '/login' @{ username = $User; password = $Pass; next = '/calendar' }
|
||
Check ($r.StatusCode -eq 200 -and (Final-Path $r) -like '/calendar*') '已存在管理员,登录成功'
|
||
}
|
||
|
||
# 2. 套餐
|
||
$r = Send 'GET' '/packages'
|
||
Check ($r.StatusCode -eq 200) '套餐页可访问'
|
||
$colors = @('#2F5D50', '#6B4E9B')
|
||
$pkgs = @(
|
||
@{ name = '包月日常'; unit = 'day'; default_amount = 30; price = 300; note = '每天日常 + 周常' },
|
||
@{ name = '深渊十次'; unit = 'count'; default_amount = 10; price = 180; note = '按次结算' }
|
||
)
|
||
for ($i = 0; $i -lt $pkgs.Count; $i++) {
|
||
$p = $pkgs[$i]
|
||
$r = Send 'POST' '/packages' @{
|
||
name = $p.name; unit = $p.unit; default_amount = "$($p.default_amount)"
|
||
price = "$($p.price)"; color = $colors[$i]; note = $p.note; sort_order = "$($i + 1)"
|
||
}
|
||
Check ($r.Content -match '套餐已保存|套餐已创建|套餐') "提交套餐 $($p.name)"
|
||
}
|
||
$r = Send 'GET' '/packages'
|
||
Check ($r.Content -match '包月日常' -and $r.Content -match '深渊十次') '套餐列表包含两个套餐'
|
||
$r = Send 'GET' '/packages/1/edit'
|
||
Check ($r.StatusCode -eq 200 -and $r.Content -match '包月日常') '套餐编辑页可打开'
|
||
|
||
# 3. 客户
|
||
$r = Send 'POST' '/customers' @{
|
||
tail = "$tail"; name = '老张'; game_name = '王者荣耀'; game_server = '微信区'
|
||
contact = 'wx: laozhang'; tags = '老客户,包月'; source = '抖音'; note = '喜欢晚上打'
|
||
}
|
||
$custPath = Final-Path $r
|
||
Check ($custPath -like '/customers/*') "新建客户成功 -> $custPath"
|
||
$custID = ($custPath -split '/')[-1]
|
||
|
||
$r = Send 'GET' "/customers?q=$tail"
|
||
Check ($r.Content -match '老张') "尾号 $tail 搜索命中老张"
|
||
|
||
$r = Send 'POST' '/customers' @{ tail = "$tail"; name = '老张' }
|
||
Check ($r.StatusCode -eq 400 -and $r.Content -match '已存在') '重复客户被拒绝并提示'
|
||
|
||
# 4. 订阅(按日 + 按次)
|
||
$r = Send 'POST' "/customers/$custID/subscriptions" @{ package_id = '1'; start_date = $today; days = '30'; note = '首单' }
|
||
Check ($r.Content -match '已开通') '开通按日订阅'
|
||
$r = Send 'POST' "/customers/$custID/subscriptions" @{ package_id = '1'; start_date = $today; days = '30' }
|
||
Check ($r.Content -match '追加时长') '同一套餐重复订阅被拦截'
|
||
|
||
$r = Send 'POST' "/customers/$custID/subscriptions" @{
|
||
package_id = '2'; start_date = $today; total_count = '10'; end_date = $now.AddDays(10).ToString('yyyy-MM-dd')
|
||
}
|
||
Check ($r.Content -match '已开通') '开通按次订阅'
|
||
|
||
$r = Send 'GET' "/customers/$custID"
|
||
$subIDs = [regex]::Matches($r.Content, 'id="sub-(\d+)"') | ForEach-Object { [int]$_.Groups[1].Value }
|
||
Check ($subIDs.Count -ge 2) "客户页出现 2 张订阅卡(实际 $($subIDs.Count))"
|
||
$daySub = $subIDs[0]
|
||
$cntSub = $subIDs[1]
|
||
|
||
# 5. 追加时长(日历手动选终止日:今天 +45 天)
|
||
$newEnd = $now.AddDays(45)
|
||
$oldEnd = $now.AddDays(29)
|
||
$expectDays = ($newEnd.Date - $oldEnd.Date).Days
|
||
$r = Send 'POST' "/subscriptions/$daySub/extend" @{
|
||
new_end_date = $newEnd.ToString('yyyy-MM-dd'); note = '微信转账续费'; back = "/customers/$custID"
|
||
}
|
||
Check ($r.Content -match "已追加 $expectDays 天") "追加时长反算正确(期望 $expectDays 天)"
|
||
|
||
$r = Send 'GET' "/customers/$custID"
|
||
Check ($r.Content -match '剩 46 天') '客户页剩余天数更新为 46 天'
|
||
Check ($r.Content -match '微信转账续费') '追加记录已留痕(备注)'
|
||
Check ($r.Content -match '追加天数') '追加记录标注类型'
|
||
|
||
# 6. 日历
|
||
$r = Send 'GET' "/calendar?y=$($now.Year)&m=$($now.Month)&d=$today"
|
||
Check ($r.StatusCode -eq 200) '日历页可打开'
|
||
Check ($r.Content -match '老张') '日历当天出现该客户色签'
|
||
Check ($r.Content -match '当日待打') '日历抽屉存在'
|
||
|
||
# 7. 打卡(按日)
|
||
$r = Send 'POST' "/subscriptions/$daySub/checkin" @{ date = $today; status = 'done'; note = '打完'; back = "/calendar?d=$today" }
|
||
Check ($r.Content -match '已记录') '按日打卡成功'
|
||
|
||
# 8. 按次打卡扣次
|
||
$r = Send 'POST' "/subscriptions/$cntSub/checkin" @{ date = $today; status = 'done'; back = "/customers/$custID" }
|
||
Check ($r.Content -match '已记录') '按次打卡成功(应扣 1 次)'
|
||
$r = Send 'GET' "/customers/$custID"
|
||
Check ($r.Content -match '剩 9 / 10 次') '按次剩余次数扣减为 9'
|
||
|
||
# 9. 暂停 / 恢复
|
||
$r = Send 'POST' "/subscriptions/$daySub/pause" @{ back = "/customers/$custID" }
|
||
Check ($r.Content -match '已暂停') '暂停订阅'
|
||
$r = Send 'GET' "/customers/$custID"
|
||
Check ($r.Content -match '暂停中') '客户页显示暂停中'
|
||
$r = Send 'POST' "/subscriptions/$daySub/resume" @{ back = "/customers/$custID" }
|
||
Check ($r.Content -match '已恢复') '恢复订阅'
|
||
|
||
# 9.5 无有效期的按次订阅:靠客户页「今日打卡」扣次
|
||
$r = Send 'POST' '/packages' @{
|
||
name = '副本五次'; unit = 'count'; default_amount = '5'; price = '120'; color = '#41556B'; note = '无有效期'; sort_order = '3'
|
||
}
|
||
Check ($r.Content -match '套餐') '新建第三个套餐(按次、无有效期)'
|
||
$r = Send 'GET' '/packages'
|
||
$pkgIDs = [regex]::Matches($r.Content, '/packages/(\d+)/edit') | ForEach-Object { [int]$_.Groups[1].Value }
|
||
$newPkg = ($pkgIDs | Measure-Object -Maximum).Maximum
|
||
$r = Send 'POST' "/customers/$custID/subscriptions" @{ package_id = "$newPkg"; start_date = $today; total_count = '5' }
|
||
Check ($r.Content -match '已开通') '开通无有效期的按次订阅'
|
||
|
||
$r = Send 'GET' "/customers/$custID"
|
||
Check ($r.Content -match '今日打卡') '订阅卡片出现「今日打卡」按钮'
|
||
$ids3 = [regex]::Matches($r.Content, 'id="sub-(\d+)"') | ForEach-Object { [int]$_.Groups[1].Value }
|
||
$thirdSub = $ids3[-1]
|
||
$r = Send 'POST' "/subscriptions/$thirdSub/checkin" @{ date = $today; status = 'done'; back = "/customers/$custID" }
|
||
Check ($r.Content -match '已记录') '无有效期按次订阅打卡成功'
|
||
$r = Send 'GET' "/customers/$custID"
|
||
Check ($r.Content -match '剩 4 / 5 次') '打卡后次数扣减为 4'
|
||
|
||
# 10. 大屏
|
||
$r = Send 'GET' '/screen'
|
||
Check ($r.StatusCode -eq 200) '大屏可访问'
|
||
Check ($r.Content -match '即将到期 TOP 10') '大屏含 TOP 榜'
|
||
Check ($r.Content -match '到期热力') '大屏含热力月历'
|
||
Check ($r.Content -match "$tail") '大屏显示该客户尾号'
|
||
|
||
# 11. 日志 / 设置 / 导出
|
||
$r = Send 'GET' '/logs'
|
||
Check ($r.Content -match '追加时长') '操作日志含追加记录'
|
||
$r = Send 'GET' '/settings'
|
||
Check ($r.StatusCode -eq 200 -and $r.Content -match '基础设置') '设置页可打开'
|
||
$r = Send 'GET' '/export/customers.csv'
|
||
Check ($r.StatusCode -eq 200 -and $r.Content -match '手机尾号') '客户 CSV 导出正常'
|
||
$r = Send 'GET' '/export/subscriptions.csv'
|
||
Check ($r.StatusCode -eq 200 -and $r.Content -match '剩余') '订阅 CSV 导出正常'
|
||
$r = Send 'GET' '/export/logs.csv'
|
||
Check ($r.StatusCode -eq 200 -and $r.Content -match '操作人') '日志 CSV 导出正常'
|
||
|
||
# 12. 静态资源与健康检查
|
||
$r = Send 'GET' '/static/app.css'
|
||
Check ($r.StatusCode -eq 200 -and $r.Content -match 'ticket') '静态样式可访问'
|
||
$r = Send 'GET' '/healthz'
|
||
Check ($r.Content -match 'ok') '健康检查正常'
|
||
|
||
Write-Host ""
|
||
if ($script:fail -eq 0) {
|
||
Write-Host "全部通过" -ForegroundColor Green
|
||
exit 0
|
||
} else {
|
||
Write-Host ("失败 $script:fail 项") -ForegroundColor Red
|
||
exit 1
|
||
}
|