Files
worker/app/models/monitor_transfer_test.go
Gleb Tv 2c7a0236da feat: publish standalone worker
Separate worker packaging and service lifecycle from the control plane.
2026-07-13 17:55:14 +03:00

95 строки
3.3 KiB
Go

package models_test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gorm.io/datatypes"
"rsgit.ru/rsmon/rsmon/app/models"
)
// TestMonitorTransferGroupSwap verifies that swapping a monitor's
// group_id between two accounts correctly re-homes the monitor without
// touching any other monitor data. This is the database primitive that
// POST /api/v1/monitors/:id/transfer relies on.
func TestMonitorTransferGroupSwap(t *testing.T) {
models.Drop()
models.Migrate()
plan := models.Plan{Name: "test", Default: true}
require.NoError(t, models.DB().Create(&plan).Error)
// Two accounts, each with their own default group.
accA := models.Account{Name: "A", PlanID: &plan.ID}
require.NoError(t, models.DB().Create(&accA).Error)
accB := models.Account{Name: "B", PlanID: &plan.ID}
require.NoError(t, models.DB().Create(&accB).Error)
groupA := models.Group{AccountID: accA.ID, Name: "A-default"}
require.NoError(t, models.DB().Create(&groupA).Error)
groupB := models.Group{AccountID: accB.ID, Name: "B-default"}
require.NoError(t, models.DB().Create(&groupB).Error)
// Monitor lives in account A with one HTTP check.
monitor := models.Monitor{
GroupID: groupA.ID,
Host: "example-a.test",
}
require.NoError(t, models.DB().Create(&monitor).Error)
check := models.Check{
MonitorID: monitor.ID,
Kind: "http",
URL: ptrString("https://example-a.test/"),
Interval: 300,
Settings: datatypes.JSON([]byte("{}")),
}
require.NoError(t, models.DB().Create(&check).Error)
// Simulate the controller-side update.
require.NoError(t, models.DB().
Model(&models.Monitor{}).
Where("id = ?", monitor.ID).
Update("group_id", groupB.ID).Error)
// Monitor now lives in B; check follows by FK on monitor_id.
var reloaded models.Monitor
require.NoError(t, models.DB().Preload("Group").First(&reloaded, monitor.ID).Error)
assert.Equal(t, groupB.ID, reloaded.GroupID, "monitor group_id should now point at account B's group")
assert.Equal(t, accB.ID, reloaded.Group.AccountID, "preloaded group should belong to account B")
var checkCount int64
require.NoError(t, models.DB().Model(&models.Check{}).
Where("monitor_id = ?", monitor.ID).Count(&checkCount).Error)
assert.Equal(t, int64(1), checkCount, "check rows must follow the monitor across the move")
}
// TestMonitorTransferSameAccountGuard documents the early-return path: the
// controller must not silently no-op when the caller picks the current
// account, and the test exercises that the DB stays untouched.
func TestMonitorTransferSameAccountGuard(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: "only", PlanID: &plan.ID}
require.NoError(t, models.DB().Create(&acc).Error)
group := models.Group{AccountID: acc.ID, Name: "only"}
require.NoError(t, models.DB().Create(&group).Error)
monitor := models.Monitor{GroupID: group.ID, Host: "x.test"}
require.NoError(t, models.DB().Create(&monitor).Error)
// No update is issued because the controller rejects same-account moves
// before the SQL UPDATE. Verify the row is unchanged.
var reloaded models.Monitor
require.NoError(t, models.DB().First(&reloaded, monitor.ID).Error)
assert.Equal(t, group.ID, reloaded.GroupID)
}
func ptrString(s string) *string { return &s }