Smail/backend/cmd/smail-admin/windows_deployment_policy_test.go
smail ca28fa982e 增加需确认的全新部署流程
默认升级保留 Smail 运行数据;Linux 和 Windows 的全新部署均要求输入确认词,先备份后仅清理 Smail 专属目录,并补充部署策略回归用例。
2026-10-01 11:48:03 +08:00

103 lines
3.2 KiB
Go

package main
import (
"os"
"path/filepath"
"strings"
"testing"
)
func TestWindowsDeploymentScriptsKeepAdminChannelManual(t *testing.T) {
root := filepath.Clean(filepath.Join("..", "..", ".."))
installer, err := os.ReadFile(filepath.Join(root, "deploy", "install-windows.ps1"))
if err != nil {
t.Fatal(err)
}
content := string(installer)
for _, required := range []string{
"sc.exe",
"smail-admin.exe",
"Set-RestrictedAcl",
"sidtype",
"$PackageRoot = $null",
"$PackageRoot = Split-Path -Parent $PSScriptRoot",
"NT SERVICE\\Smail:(F)",
".backup-",
"$mainBackup",
"$adminBackup",
"不会自动注册或启动服务",
} {
if !strings.Contains(content, required) {
t.Fatalf("Windows installer is missing %q", required)
}
}
if !hasUTF8BOM(installer) {
t.Fatal("Windows installer must be encoded as UTF-8 with BOM for Windows PowerShell")
}
serviceSetup := strings.Index(content, `"sidtype", "Smail", "unrestricted"`)
aclSetup := strings.Index(content, "Set-RestrictedAcl -Root $resolvedInstallRoot")
if serviceSetup < 0 || aclSetup < 0 || serviceSetup > aclSetup {
t.Fatal("Windows installer must create the service SID before applying service ACLs")
}
for _, forbidden := range []string{
"create SmailAdmin",
"Start-Service -Name \"SmailAdmin\"",
"start= auto" + "\n" + "start= auto",
} {
if strings.Contains(content, forbidden) {
t.Fatalf("Windows installer contains forbidden admin-service action %q", forbidden)
}
}
}
func TestWindowsInstallerRequiresExplicitFreshReset(t *testing.T) {
root := filepath.Clean(filepath.Join("..", "..", ".."))
installer, err := os.ReadFile(filepath.Join(root, "deploy", "install-windows.ps1"))
if err != nil {
t.Fatal(err)
}
content := string(installer)
for _, required := range []string{
"[switch]$Fresh",
"确认全新部署 Smail",
".smail-fresh-backup-",
"Copy-Item -LiteralPath $item.FullName -Destination (Join-Path $backupRoot $item.Name) -Recurse -Force",
"Remove-Item -LiteralPath $item.FullName -Recurse -Force",
} {
if !strings.Contains(content, required) {
t.Fatalf("Windows installer is missing explicit fresh-reset behavior %q", required)
}
}
if strings.Contains(content, "全新部署已停止:$existing 不是空目录") {
t.Fatal("Windows installer must not reject existing data without an explicit fresh-reset request")
}
}
func hasUTF8BOM(data []byte) bool {
return len(data) >= 3 && data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF
}
func TestWindowsUninstallerPreservesData(t *testing.T) {
root := filepath.Clean(filepath.Join("..", "..", ".."))
uninstaller, err := os.ReadFile(filepath.Join(root, "deploy", "uninstall-windows.ps1"))
if err != nil {
t.Fatal(err)
}
content := string(uninstaller)
if !hasUTF8BOM(uninstaller) {
t.Fatal("Windows uninstaller must be encoded as UTF-8 with BOM for Windows PowerShell")
}
if strings.Contains(content, "Remove-Item -LiteralPath $resolvedInstallRoot -Recurse") {
t.Fatal("Windows uninstaller recursively removes the data root")
}
for _, required := range []string{
"smail.exe",
"smail-admin.exe",
"配置、数据库、证书和用户数据未删除",
} {
if !strings.Contains(content, required) {
t.Fatalf("Windows uninstaller is missing %q", required)
}
}
}