Files
nezha_domains/service/singleton/user_test.go
T
2026-05-25 10:17:34 +00:00

91 lines
2.9 KiB
Go

package singleton
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/nezhahq/nezha/model"
"github.com/nezhahq/nezha/pkg/i18n"
)
func setupOnUserDeleteFixture(t *testing.T) (*ServerTransferClass, func()) {
t.Helper()
c, transferCleanup := setupTransferFixture(t)
require.NoError(t, DB.AutoMigrate(&model.Cron{}, &model.Transfer{}, &model.ServerGroupServer{}))
originalCronShared := CronShared
CronShared = &CronClass{
class: class[uint64, *model.Cron]{list: map[uint64]*model.Cron{}},
}
originalLocalizer := Localizer
Localizer = i18n.NewLocalizer("zh_CN", domain, "translations", i18n.Translations)
cleanup := func() {
Localizer = originalLocalizer
CronShared = originalCronShared
transferCleanup()
}
return c, cleanup
}
func TestOnUserDeleteCancelsPendingTransfersAwayFromDeletedUser(t *testing.T) {
c, cleanup := setupOnUserDeleteFixture(t)
defer cleanup()
const fromUser = uint64(100)
const toUser = uint64(200)
const serverID = uint64(1)
seedServerForTransfer(t, serverID, fromUser)
require.NoError(t, DB.AutoMigrate(&model.User{}))
require.NoError(t, DB.Create(&model.User{
Common: model.Common{ID: fromUser},
Username: "alice",
AgentSecret: "alice-secret",
}).Error)
require.NoError(t, DB.Create(&model.User{
Common: model.Common{ID: toUser},
Username: "bob",
AgentSecret: "bob-secret",
}).Error)
UserLock.Lock()
UserInfoMap[fromUser] = model.UserInfo{Role: model.RoleMember, AgentSecret: "alice-secret"}
UserInfoMap[toUser] = model.UserInfo{Role: model.RoleMember, AgentSecret: "bob-secret"}
UserLock.Unlock()
tr := initiateAndRegister(t, c, serverID, fromUser, toUser, fromUser)
require.True(t, c.HasPending(serverID), "precondition: pending transfer published")
srv, ok := ServerShared.Get(serverID)
require.True(t, ok)
require.Equal(t, toUser, srv.GetUserID(), "precondition: pending transfer flipped owner to ToUserID")
require.NoError(t, OnUserDelete([]uint64{fromUser}, func(format string, args ...any) error {
return nil
}))
if c.HasPending(serverID) {
t.Fatal("OnUserDelete on the transfer FromUserID must terminate the pending transfer so a later Cancel/Fail/Timeout cannot revert ownership to the deleted user")
}
if srv, ok := ServerShared.Get(serverID); ok {
require.NotEqual(t, fromUser, srv.GetUserID(),
"server owner must not be reverted to the deleted FromUserID; got owner=%d", srv.GetUserID())
}
if _, err := c.Cancel(tr.ID); err == nil {
var refreshed model.ServerTransfer
if err := DB.First(&refreshed, tr.ID).Error; err == nil {
require.NotEqual(t, model.ServerTransferStatusPending, refreshed.Status,
"after OnUserDelete a subsequent Cancel must not leave the transfer Pending")
if srv, ok := ServerShared.Get(serverID); ok {
require.NotEqual(t, fromUser, srv.GetUserID(),
"a late Cancel against the terminated transfer must not revert server.UserID to the deleted FromUserID; got owner=%d", srv.GetUserID())
}
}
}
}