Some checks are pending
Security Checks / security (push) Waiting to run
统一 frontend、backend、test、test-log 和 out 目录,更新构建、部署及测试入口;纳入配置管理兼容与首次安全引导修复;排除本机配置、密钥和测试产物。
117 lines
4.4 KiB
Go
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)
|
|
}
|
|
}
|