Некоторые проверки не удались
CI / test (push) Successful in 2m5s
Docker / Build and publish worker image (push) Failing after 31s
182 строки
7.1 KiB
Go
182 строки
7.1 KiB
Go
package models_test
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"rocketgit.ru/rsmon/worker/app/models"
|
|
)
|
|
|
|
// makeStaleUser inserts a user whose LastActiveAt is older than the
|
|
// 3-month cutoff used by the cleanup filter. The returned user is what
|
|
// the candidates query should pick up.
|
|
func makeStaleUser(t *testing.T, email string, lastActive *time.Time) *models.User {
|
|
t.Helper()
|
|
u := &models.User{
|
|
Email: &email,
|
|
Name: "stale " + email,
|
|
Enabled: true,
|
|
Confirmed: true,
|
|
LastActiveAt: lastActive,
|
|
}
|
|
require.NoError(t, models.DB().Create(u).Error)
|
|
return u
|
|
}
|
|
|
|
// TestFindStaleAccounts_EmptyWhenNoCandidates checks the obvious
|
|
// negative case: a fresh account with an active owner is not eligible.
|
|
func TestFindStaleAccounts_EmptyWhenNoCandidates(t *testing.T) {
|
|
models.Drop()
|
|
models.Migrate()
|
|
|
|
plan := models.Plan{Name: "test", Default: true}
|
|
require.NoError(t, models.DB().Create(&plan).Error)
|
|
|
|
acc := models.Account{Name: "fresh", PlanID: &plan.ID}
|
|
require.NoError(t, models.DB().Create(&acc).Error)
|
|
|
|
// Group + owner access + active user
|
|
group := models.Group{AccountID: acc.ID, Name: "default"}
|
|
require.NoError(t, models.DB().Create(&group).Error)
|
|
|
|
recent := time.Now().Add(-1 * time.Hour)
|
|
user := makeStaleUser(t, "active@example.com", &recent)
|
|
access := models.Access{AccountID: acc.ID, UserID: &user.ID, Kind: "account", Role: "owner"}
|
|
require.NoError(t, models.DB().Create(&access).Error)
|
|
|
|
got, err := models.FindStaleAccounts()
|
|
require.NoError(t, err)
|
|
assert.Empty(t, got, "an account with an active owner is not stale")
|
|
}
|
|
|
|
// TestFindStaleAccounts_PicksStaleEmptyAccount checks the happy path:
|
|
// account with no monitors + single user + last login > 3 months ago.
|
|
func TestFindStaleAccounts_PicksStaleEmptyAccount(t *testing.T) {
|
|
models.Drop()
|
|
models.Migrate()
|
|
|
|
plan := models.Plan{Name: "test", Default: true}
|
|
require.NoError(t, models.DB().Create(&plan).Error)
|
|
|
|
acc := models.Account{Name: "ghost", PlanID: &plan.ID}
|
|
require.NoError(t, models.DB().Create(&acc).Error)
|
|
|
|
group := models.Group{AccountID: acc.ID, Name: "default"}
|
|
require.NoError(t, models.DB().Create(&group).Error)
|
|
|
|
neverLoggedIn := (*time.Time)(nil)
|
|
user := makeStaleUser(t, "ghost@example.com", neverLoggedIn)
|
|
access := models.Access{AccountID: acc.ID, UserID: &user.ID, Kind: "account", Role: "owner"}
|
|
require.NoError(t, models.DB().Create(&access).Error)
|
|
|
|
got, err := models.FindStaleAccounts()
|
|
require.NoError(t, err)
|
|
require.Len(t, got, 1, "the empty stale account should be picked up")
|
|
assert.Equal(t, acc.ID, got[0].AccountID)
|
|
assert.Equal(t, user.ID, got[0].UserID)
|
|
}
|
|
|
|
// TestFindStaleAccounts_SkipsAccountWithMonitors makes sure the
|
|
// "zero monitors" gate is enforced.
|
|
func TestFindStaleAccounts_SkipsAccountWithMonitors(t *testing.T) {
|
|
models.Drop()
|
|
models.Migrate()
|
|
|
|
plan := models.Plan{Name: "test", Default: true}
|
|
require.NoError(t, models.DB().Create(&plan).Error)
|
|
|
|
acc := models.Account{Name: "active", PlanID: &plan.ID}
|
|
require.NoError(t, models.DB().Create(&acc).Error)
|
|
|
|
group := models.Group{AccountID: acc.ID, Name: "default"}
|
|
require.NoError(t, models.DB().Create(&group).Error)
|
|
|
|
// One monitor → account is NOT eligible even if the user is stale.
|
|
monitor := models.Monitor{GroupID: group.ID, Host: "example.com"}
|
|
require.NoError(t, models.DB().Create(&monitor).Error)
|
|
|
|
stale := time.Now().Add(-365 * 24 * time.Hour)
|
|
user := makeStaleUser(t, "owner@example.com", &stale)
|
|
access := models.Access{AccountID: acc.ID, UserID: &user.ID, Kind: "account", Role: "owner"}
|
|
require.NoError(t, models.DB().Create(&access).Error)
|
|
|
|
got, err := models.FindStaleAccounts()
|
|
require.NoError(t, err)
|
|
assert.Empty(t, got)
|
|
}
|
|
|
|
// TestFindStaleAccounts_SkipsUserWithMultipleAccounts verifies that a
|
|
// user holding two accounts disqualifies BOTH accounts.
|
|
func TestFindStaleAccounts_SkipsUserWithMultipleAccounts(t *testing.T) {
|
|
models.Drop()
|
|
models.Migrate()
|
|
|
|
plan := models.Plan{Name: "test", Default: true}
|
|
require.NoError(t, models.DB().Create(&plan).Error)
|
|
|
|
acc1 := models.Account{Name: "acc1", PlanID: &plan.ID}
|
|
require.NoError(t, models.DB().Create(&acc1).Error)
|
|
acc2 := models.Account{Name: "acc2", PlanID: &plan.ID}
|
|
require.NoError(t, models.DB().Create(&acc2).Error)
|
|
models.DB().Create(&models.Group{AccountID: acc1.ID, Name: "g1"})
|
|
models.DB().Create(&models.Group{AccountID: acc2.ID, Name: "g2"})
|
|
|
|
stale := time.Now().Add(-365 * 24 * time.Hour)
|
|
user := makeStaleUser(t, "shared@example.com", &stale)
|
|
require.NoError(t, models.DB().Create(&models.Access{AccountID: acc1.ID, UserID: &user.ID, Kind: "account", Role: "owner"}).Error)
|
|
require.NoError(t, models.DB().Create(&models.Access{AccountID: acc2.ID, UserID: &user.ID, Kind: "account", Role: "owner"}).Error)
|
|
|
|
got, err := models.FindStaleAccounts()
|
|
require.NoError(t, err)
|
|
assert.Empty(t, got, "user with two accounts disqualifies both accounts")
|
|
}
|
|
|
|
// TestCleanupStaleAccounts_HardDeletesEligibleAndOrphans verifies the
|
|
// end-to-end cleanup: matching account + user are removed, and
|
|
// recently-active accounts survive.
|
|
func TestCleanupStaleAccounts_HardDeletesEligibleAndOrphans(t *testing.T) {
|
|
models.Drop()
|
|
models.Migrate()
|
|
|
|
plan := models.Plan{Name: "test", Default: true}
|
|
require.NoError(t, models.DB().Create(&plan).Error)
|
|
|
|
// Stale account with a stale user that has only this one account.
|
|
staleAcc := models.Account{Name: "ghost", PlanID: &plan.ID}
|
|
require.NoError(t, models.DB().Create(&staleAcc).Error)
|
|
staleGroup := models.Group{AccountID: staleAcc.ID, Name: "g"}
|
|
require.NoError(t, models.DB().Create(&staleGroup).Error)
|
|
staleUser := makeStaleUser(t, "ghost@example.com", nil)
|
|
require.NoError(t, models.DB().Create(&models.Access{AccountID: staleAcc.ID, UserID: &staleUser.ID, Kind: "account", Role: "owner"}).Error)
|
|
|
|
// Active account with a recent user — must NOT be touched.
|
|
freshAcc := models.Account{Name: "fresh", PlanID: &plan.ID}
|
|
require.NoError(t, models.DB().Create(&freshAcc).Error)
|
|
require.NoError(t, models.DB().Create(&models.Group{AccountID: freshAcc.ID, Name: "g"}).Error)
|
|
recent := time.Now().Add(-1 * time.Hour)
|
|
freshUser := makeStaleUser(t, "fresh@example.com", &recent)
|
|
require.NoError(t, models.DB().Create(&models.Access{AccountID: freshAcc.ID, UserID: &freshUser.ID, Kind: "account", Role: "owner"}).Error)
|
|
|
|
deleted, err := models.CleanupStaleAccounts()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 1, deleted, "only the stale empty account should be deleted")
|
|
|
|
// Stale account is gone.
|
|
var count int64
|
|
require.NoError(t, models.DB().Model(&models.Account{}).Where("id = ?", staleAcc.ID).Count(&count).Error)
|
|
assert.Equal(t, int64(0), count)
|
|
|
|
// Stale user is orphaned → also hard-deleted by the cleanup pass.
|
|
require.NoError(t, models.DB().Model(&models.User{}).Where("id = ?", staleUser.ID).Count(&count).Error)
|
|
assert.Equal(t, int64(0), count)
|
|
|
|
// Fresh account and user survive.
|
|
require.NoError(t, models.DB().Model(&models.Account{}).Where("id = ?", freshAcc.ID).Count(&count).Error)
|
|
assert.Equal(t, int64(1), count)
|
|
require.NoError(t, models.DB().Model(&models.User{}).Where("id = ?", freshUser.ID).Count(&count).Error)
|
|
assert.Equal(t, int64(1), count)
|
|
}
|