Smail/server/internal/release/release_test.go
smail dd04bdb49e
Some checks are pending
Security Checks / security (push) Waiting to run
完成安全整改、配置重构与邮件认证优化
2026-08-28 14:33:13 +08:00

117 lines
4.4 KiB
Go

package release
import (
"errors"
"os"
"path/filepath"
"testing"
"time"
"git.pcux.cn/xuans/Smail/internal/buildinfo"
)
func TestNewManifestRejectsMismatchedPair(t *testing.T) {
mainInfo := buildinfo.Info{Version: "v1", GitHash: "abc", ProtocolVersion: buildinfo.ProtocolVersion}
adminInfo := buildinfo.Info{Version: "v2", GitHash: "abc", ProtocolVersion: buildinfo.ProtocolVersion}
if _, err := NewManifest(Pair{Main: mainInfo, Admin: adminInfo}, time.Now()); !errors.Is(err, ErrInvalidPair) {
t.Fatalf("NewManifest() error = %v", err)
}
}
func TestInstallPairWritesBothExecutablesAndManifest(t *testing.T) {
root := t.TempDir()
mainSource := filepath.Join(root, "main-source")
adminSource := filepath.Join(root, "admin-source")
if err := os.WriteFile(mainSource, []byte("main-v2"), 0600); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(adminSource, []byte("admin-v2"), 0600); err != nil {
t.Fatal(err)
}
mainInfo := buildinfo.Info{Version: "v2", GitHash: "abc", ProtocolVersion: buildinfo.ProtocolVersion}
target := filepath.Join(root, "bin")
if err := InstallPair(mainSource, adminSource, target, Pair{Main: mainInfo, Admin: mainInfo}); err != nil {
t.Fatal(err)
}
mainName, adminName := executableNames()
for _, name := range []string{mainName, adminName, "release.json"} {
if _, err := os.Stat(filepath.Join(target, name)); err != nil {
t.Fatalf("missing installed file %s: %v", name, err)
}
}
manifest, err := ReadManifest(target)
if err != nil {
t.Fatal(err)
}
if manifest.Version != "v2" || manifest.GitHash != "abc" {
t.Fatalf("unexpected manifest: %+v", manifest)
}
}
func TestInstallPairRollsBackWhenSecondTargetCannotBeReplaced(t *testing.T) {
root := t.TempDir()
mainSource := filepath.Join(root, "main-source")
adminSource := filepath.Join(root, "admin-source")
if err := os.WriteFile(mainSource, []byte("main-v2"), 0600); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(adminSource, []byte("admin-v2"), 0600); err != nil {
t.Fatal(err)
}
target := filepath.Join(root, "bin")
if err := os.MkdirAll(target, 0750); err != nil {
t.Fatal(err)
}
mainName, adminName := executableNames()
if err := os.WriteFile(filepath.Join(target, mainName), []byte("main-v1"), 0600); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(target, adminName), []byte("admin-v1"), 0600); err != nil {
t.Fatal(err)
}
originalRename := renamePath
t.Cleanup(func() { renamePath = originalRename })
renamePath = func(source, destination string) error {
if filepath.Base(source) == adminName && filepath.Dir(destination) == target && filepath.Ext(destination) == filepath.Ext(adminName) {
return errors.New("simulated replacement failure")
}
return originalRename(source, destination)
}
pair := buildinfo.Info{Version: "v2", GitHash: "abc", ProtocolVersion: buildinfo.ProtocolVersion}
if err := InstallPair(mainSource, adminSource, target, Pair{Main: pair, Admin: pair}); err == nil {
t.Fatal("expected replacement failure")
} else if !errors.Is(err, ErrUpgradeRollback) {
t.Fatalf("error = %v, want rollback marker", err)
}
content, err := os.ReadFile(filepath.Join(target, mainName))
if err != nil {
t.Fatal(err)
}
if string(content) != "main-v1" {
t.Fatalf("main executable was not restored: %q", content)
}
adminContent, err := os.ReadFile(filepath.Join(target, adminName))
if err != nil {
t.Fatal(err)
}
if string(adminContent) != "admin-v1" {
t.Fatalf("admin executable was not restored: %q", adminContent)
}
}
func TestValidateManifestRejectsInvalidTimestamp(t *testing.T) {
info := buildinfo.Info{Version: "v1", GitHash: "abc", ProtocolVersion: buildinfo.ProtocolVersion}
manifest := Manifest{Version: "v1", GitHash: "abc", ProtocolVersion: buildinfo.ProtocolVersion, CreatedAt: "not-a-timestamp"}
if err := ValidateManifest(manifest, Pair{Main: info, Admin: info}); !errors.Is(err, ErrInvalidPair) {
t.Fatalf("ValidateManifest() error = %v, want invalid pair", err)
}
}
func TestValidateManifestRejectsProtocolMismatch(t *testing.T) {
info := buildinfo.Info{Version: "v1", GitHash: "abc", ProtocolVersion: buildinfo.ProtocolVersion}
manifest := Manifest{Version: "v1", GitHash: "abc", ProtocolVersion: buildinfo.ProtocolVersion + 1, CreatedAt: time.Now().UTC().Format(time.RFC3339)}
if err := ValidateManifest(manifest, Pair{Main: info, Admin: info}); !errors.Is(err, ErrInvalidPair) {
t.Fatalf("ValidateManifest() error = %v, want invalid pair", err)
}
}