2026-11-01 20:42:53 -05:00
|
|
|
|
[CmdletBinding()]
|
|
|
|
|
|
param([Parameter(Mandatory=$true)][string]$PythonPath, [Parameter(Mandatory=$true)][string]$TestRoot)
|
|
|
|
|
|
. (Join-Path $PSScriptRoot 'TaskHost.Common.ps1')
|
|
|
|
|
|
if (Test-Path -LiteralPath $TestRoot) { throw '请选择新的隔离测试目录,避免覆盖现有文件。' }
|
|
|
|
|
|
$root = [IO.Path]::GetFullPath($TestRoot)
|
|
|
|
|
|
$app = Join-Path $root 'backend/app'
|
|
|
|
|
|
New-Item -ItemType Directory -Path $app -Force | Out-Null
|
|
|
|
|
|
'' | Set-Content -LiteralPath (Join-Path $app '__init__.py') -Encoding UTF8
|
|
|
|
|
|
@'
|
|
|
|
|
|
import os,sys,time
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
if 'tplus-maintain' in sys.argv:
|
2026-11-03 04:18:48 -05:00
|
|
|
|
print('maintenance result')
|
|
|
|
|
|
print('maintenance error', file=sys.stderr)
|
2026-11-01 20:42:53 -05:00
|
|
|
|
raise SystemExit(7)
|
|
|
|
|
|
stop=Path(os.environ['T_PLUS_STOP_FILE'])
|
|
|
|
|
|
stop.parent.mkdir(parents=True,exist_ok=True)
|
|
|
|
|
|
(stop.parent/'worker.started').write_text('ready',encoding='utf-8')
|
|
|
|
|
|
while not stop.exists():
|
|
|
|
|
|
time.sleep(0.05)
|
|
|
|
|
|
(stop.parent/'worker.stopped').write_text('stopped',encoding='utf-8')
|
|
|
|
|
|
'@ | Set-Content -LiteralPath (Join-Path $app 'cli.py') -Encoding UTF8
|
|
|
|
|
|
$connection = Join-Path $root 'dummy reader.json'
|
|
|
|
|
|
'{}' | Set-Content -LiteralPath $connection -Encoding UTF8
|
|
|
|
|
|
$runtime = Join-Path $root 'runtime with spaces'
|
|
|
|
|
|
$shell = Join-Path $env:WINDIR 'System32/WindowsPowerShell/v1.0/powershell.exe'
|
|
|
|
|
|
$launcher = Join-Path $PSScriptRoot 'Run-PayrollHost.ps1'
|
|
|
|
|
|
function Start-TestHost([string]$Role) {
|
|
|
|
|
|
$argsText = '-NoProfile -NonInteractive -File ' + (Quote-TaskArgument $launcher) + ' -Role ' + $Role +
|
|
|
|
|
|
' -ProjectRoot ' + (Quote-TaskArgument $root) + ' -PythonPath ' + (Quote-TaskArgument $PythonPath) +
|
|
|
|
|
|
' -RuntimeDirectory ' + (Quote-TaskArgument $runtime) + ' -ConnectionFile ' + (Quote-TaskArgument $connection)
|
|
|
|
|
|
$child = Start-Process -FilePath $shell -ArgumentList $argsText -WindowStyle Hidden -PassThru `
|
|
|
|
|
|
-RedirectStandardOutput (Join-Path $root "$Role-host.out.log") -RedirectStandardError (Join-Path $root "$Role-host.err.log")
|
|
|
|
|
|
$null = $child.Handle
|
|
|
|
|
|
return $child
|
|
|
|
|
|
}
|
|
|
|
|
|
$taskHostProcess = Start-TestHost 'worker'
|
|
|
|
|
|
$deadline = (Get-Date).AddSeconds(20)
|
|
|
|
|
|
while (-not (Test-Path -LiteralPath (Join-Path $runtime 'worker.started')) -and (Get-Date) -lt $deadline) {
|
|
|
|
|
|
if ($taskHostProcess.HasExited) { throw '隔离worker未能启动,请检查测试目录日志。' }
|
|
|
|
|
|
Start-Sleep -Milliseconds 100
|
|
|
|
|
|
}
|
|
|
|
|
|
if (-not (Test-Path -LiteralPath (Join-Path $runtime 'worker.started'))) { throw '等待隔离worker启动超时。' }
|
|
|
|
|
|
'stop' | Set-Content -LiteralPath (Join-Path $runtime 'stop.requested') -Encoding UTF8
|
|
|
|
|
|
if (-not $taskHostProcess.WaitForExit(15000)) { throw '停止标记未能结束隔离worker。' }
|
|
|
|
|
|
if ($taskHostProcess.ExitCode -ne 0 -or -not (Test-Path -LiteralPath (Join-Path $runtime 'worker.stopped'))) {
|
|
|
|
|
|
throw '隔离worker未正常停止。'
|
|
|
|
|
|
}
|
|
|
|
|
|
Remove-Item -LiteralPath (Join-Path $runtime 'stop.requested')
|
|
|
|
|
|
$failureProcess = Start-TestHost 'maintenance'
|
|
|
|
|
|
if (-not $failureProcess.WaitForExit(15000)) { throw '隔离失败进程未退出。' }
|
|
|
|
|
|
if ($failureProcess.ExitCode -ne 7) { throw '启动器没有保留子进程失败退出码。' }
|
2026-11-03 04:18:48 -05:00
|
|
|
|
for ($attempt = 0; $attempt -lt 2; $attempt++) {
|
|
|
|
|
|
$failureProcess = Start-TestHost 'maintenance'
|
|
|
|
|
|
if (-not $failureProcess.WaitForExit(15000) -or $failureProcess.ExitCode -ne 7) {
|
|
|
|
|
|
throw '日志轮转后启动器没有保留子进程失败退出码。'
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
$maintenanceLogs = @(Get-ChildItem -LiteralPath (Join-Path $runtime 'logs') -Filter 'maintenance*.log')
|
|
|
|
|
|
if ($maintenanceLogs.Count -ne 4) { throw '维护任务日志没有限定为当前和上一次的四个文件。' }
|
|
|
|
|
|
foreach ($file in $maintenanceLogs) {
|
|
|
|
|
|
if ($file.Length -eq 0) { throw '轮转后日志内容丢失。' }
|
|
|
|
|
|
}
|
|
|
|
|
|
Write-Output 'Windows PowerShell5 隔离托管验证通过:含空格路径、隐藏子进程、停止标记、失败退出码及日志轮转;未注册计划任务或连接业务数据库。'
|