133 lines
4.1 KiB
Go
133 lines
4.1 KiB
Go
package setup
|
|
|
|
import (
|
|
"errors"
|
|
"path/filepath"
|
|
"sync"
|
|
"testing"
|
|
|
|
"git.pcux.cn/xuans/Smail/config"
|
|
"git.pcux.cn/xuans/Smail/db"
|
|
"git.pcux.cn/xuans/Smail/models"
|
|
appcontext "git.pcux.cn/xuans/Smail/utils/context"
|
|
)
|
|
|
|
func prepareUniqueAdminDatabase(t *testing.T) {
|
|
t.Helper()
|
|
oldConfig, oldSnapshot := config.Instance, config.CurrentConfig()
|
|
oldManager, oldDB := config.CurrentManager(), db.Instance
|
|
config.Instance = &config.Config{DbType: config.DBTypeSQLite, DbDSN: filepath.Join(t.TempDir(), "setup.db")}
|
|
config.PublishConfigSnapshot(config.Instance)
|
|
config.SetRuntimeManager(nil)
|
|
db.Instance = nil
|
|
t.Setenv("SMAIL_ENABLE_LEGACY_SYNC2", "0")
|
|
t.Cleanup(func() {
|
|
if db.Instance != nil && db.Instance != oldDB {
|
|
_ = db.Instance.Close()
|
|
}
|
|
db.Instance = oldDB
|
|
config.Instance = oldConfig
|
|
config.PublishConfigSnapshot(oldSnapshot)
|
|
config.SetRuntimeManager(oldManager)
|
|
})
|
|
if err := db.Init(""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestConcurrentAdministratorInitialization(t *testing.T) {
|
|
prepareUniqueAdminDatabase(t)
|
|
var group sync.WaitGroup
|
|
results := make(chan error, 4)
|
|
for _, account := range []string{"first", "second", "third", "fourth"} {
|
|
group.Add(1)
|
|
go func(account string) {
|
|
defer group.Done()
|
|
results <- SetAdminPassword(&appcontext.Context{}, account, "StrongP12")
|
|
}(account)
|
|
}
|
|
group.Wait()
|
|
close(results)
|
|
successes := 0
|
|
for err := range results {
|
|
if err == nil {
|
|
successes++
|
|
}
|
|
}
|
|
if successes != 1 {
|
|
t.Fatalf("初始化成功次数:%d", successes)
|
|
}
|
|
if err := db.ValidateSuperAdmin(db.Instance); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestSetupRejectsMissingMigrationLock(t *testing.T) {
|
|
prepareUniqueAdminDatabase(t)
|
|
// 仅破坏本测试的临时迁移记录,不读取或清空运行数据库。
|
|
if _, err := db.Instance.Exec("DELETE FROM schema_migration WHERE version = 1"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := SetAdminPassword(&appcontext.Context{}, "root", "StrongP12"); err == nil {
|
|
t.Fatal("缺少锁记录仍创建了账号")
|
|
}
|
|
count, err := db.Instance.Count(new(models.User))
|
|
if err != nil || count != 0 {
|
|
t.Fatalf("失败初始化写入了账号:%d %v", count, err)
|
|
}
|
|
}
|
|
|
|
func TestSetupDoesNotPromoteSoleOrdinaryAccount(t *testing.T) {
|
|
prepareUniqueAdminDatabase(t)
|
|
user := models.User{Account: "ordinary", Name: "ordinary", Password: "unused", Role: "user"}
|
|
if _, err := db.Instance.Insert(&user); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := db.Instance.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
db.Instance = nil
|
|
if err := db.Init(""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
account, err := GetAdminPassword(&appcontext.Context{})
|
|
if err != nil || account != "" {
|
|
t.Fatalf("把普通用户当作超级管理员:%q %v", account, err)
|
|
}
|
|
if err := db.ValidateSuperAdmin(db.Instance); !errors.Is(err, db.ErrSuperAdminInvariant) {
|
|
t.Fatal("普通用户被自动提权")
|
|
}
|
|
if err := SetAdminPassword(&appcontext.Context{}, "root", "StrongP12"); err == nil {
|
|
t.Fatal("非空库重新初始化")
|
|
}
|
|
for _, account := range []string{"root", "duplicate"} {
|
|
if _, err := db.Instance.Insert(&models.User{Account: account, Name: account, Password: "unused", Role: "super_admin"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err := GetAdminPassword(&appcontext.Context{})
|
|
if account == "root" && (err != nil || got != "root") {
|
|
t.Fatalf("超级管理员查询错误:%q %v", got, err)
|
|
}
|
|
if account == "duplicate" && !errors.Is(err, db.ErrSuperAdminInvariant) {
|
|
t.Fatal("重复超级管理员没有被拒绝")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFinishRejectsDuplicateSuperAdminBeforeWritingConfiguration(t *testing.T) {
|
|
prepareFinishConfigTest(t)
|
|
if err := config.WriteConfig(&config.Config{SetupState: config.SetupStateBootstrap}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := db.Instance.Insert(&models.User{Account: "duplicate", Name: "test", Password: "unused", Role: "super_admin"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := Finish(); !errors.Is(err, db.ErrSuperAdminInvariant) {
|
|
t.Fatal("初始化完成时未验证唯一超级管理员")
|
|
}
|
|
cfg, err := config.ReadConfig()
|
|
if err != nil || cfg.IsInit || cfg.SetupState != config.SetupStateBootstrap {
|
|
t.Fatal("非法账号状态仍完成了初始化")
|
|
}
|
|
}
|