Files
worker/app/models/inventory_test.go
Gleb Tv 2c884c5612
Некоторые проверки не удались
CI / test (push) Successful in 2m5s
Docker / Build and publish worker image (push) Failing after 31s
refactor: adopt worker module path
2026-07-13 17:56:12 +03:00

223 строки
6.6 KiB
Go

package models_test
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gorm.io/gorm"
"rocketgit.ru/rsmon/worker/app/models"
)
func TestServer_RotateToken(t *testing.T) {
models.Drop()
models.Migrate()
acc := &models.Account{Name: "rotate-token-account"}
require.NoError(t, models.DB().Create(acc).Error)
srv := &models.Server{
AccountID: acc.ID,
Name: "rotate-target",
Slug: "rotate-target",
Region: "local",
}
require.NoError(t, models.DB().Create(srv).Error)
t1 := models.GenerateServerToken()
require.NoError(t, models.RotateServerToken(nil, srv.ID, t1))
got, err := models.FindServerByToken(t1)
require.NoError(t, err)
assert.Equal(t, srv.ID, got.ID)
t2 := models.GenerateServerToken()
require.NoError(t, models.RotateServerToken(nil, srv.ID, t2))
// Old token no longer matches.
_, err = models.FindServerByToken(t1)
assert.ErrorIs(t, err, gorm.ErrRecordNotFound)
got2, err := models.FindServerByToken(t2)
require.NoError(t, err)
assert.Equal(t, srv.ID, got2.ID)
// Generated tokens are hex-encoded 32 bytes (64 chars).
assert.Len(t, t1, 64)
assert.NotEqual(t, t1, t2)
}
func TestServer_InventoryFields_Default(t *testing.T) {
models.Drop()
models.Migrate()
acc := &models.Account{Name: "inv-defaults"}
require.NoError(t, models.DB().Create(acc).Error)
srv := &models.Server{
AccountID: acc.ID,
Name: "fresh-server",
Slug: "fresh-server",
Region: "local",
}
require.NoError(t, models.DB().Create(srv).Error)
got := models.Server{}
require.NoError(t, models.DB().First(&got, srv.ID).Error)
assert.Equal(t, models.ServerKindProduction, got.Kind)
assert.Equal(t, 0, got.PriceCents)
assert.False(t, got.Paused)
}
func TestServer_KindEnum_OnlyAllowsValidValues(t *testing.T) {
models.Drop()
models.Migrate()
acc := &models.Account{Name: "inv-enum"}
require.NoError(t, models.DB().Create(acc).Error)
srv := &models.Server{
AccountID: acc.ID,
Name: "kinder",
Slug: "kinder",
Region: "local",
Kind: models.ServerKindStaging,
}
require.NoError(t, models.DB().Create(srv).Error)
got := models.Server{}
require.NoError(t, models.DB().First(&got, srv.ID).Error)
assert.Equal(t, models.ServerKindStaging, got.Kind)
// Inserting an invalid value via raw SQL fails the enum check.
err := models.DB().Exec(
"INSERT INTO servers (account_id, name, slug, region, kind) VALUES (?, ?, ?, ?, ?)",
acc.ID, "bad-kinder", "bad-kinder", "local", "scrapped",
).Error
require.Error(t, err)
assert.Contains(t, err.Error(), "invalid input value for enum")
}
func TestSite_Slugify(t *testing.T) {
cases := []struct {
in, want string
}{
{"Cafe", "cafe"}, // cyrillic stripped (latin-only rule, see Slugify)
{" Spaces Everywhere ", "spaces-everywhere"},
{"dots.and-dashes_and spaces", "dots-and-dashes-and-spaces"},
{"", "site"},
{"-leading-and-trailing-", "leading-and-trailing"},
{"mix_of.dots-dashes spaces", "mix-of-dots-dashes-spaces"},
}
for _, c := range cases {
t.Run(c.in, func(t *testing.T) {
assert.Equal(t, c.want, models.SiteSlugify(c.in))
})
}
}
func TestSite_FindOrCreateBySlug(t *testing.T) {
models.Drop()
models.Migrate()
acc := &models.Account{Name: "site-foc"}
require.NoError(t, models.DB().Create(acc).Error)
got, err := models.FindOrCreateSiteBySlug(nil, acc.ID, "my-site")
require.NoError(t, err)
require.NotZero(t, got.ID, "row should be persisted")
assert.Equal(t, "my-site", got.Slug)
assert.Equal(t, "production", got.Kind)
assert.True(t, got.IsActive)
// Second call returns the same row (idempotent).
got2, err := models.FindOrCreateSiteBySlug(nil, acc.ID, "my-site")
require.NoError(t, err)
assert.Equal(t, got.ID, got2.ID)
}
func TestDeployment_UpsertNginx_MatchesByConfigPath(t *testing.T) {
models.Drop()
models.Migrate()
acc := &models.Account{Name: "dep-upsert"}
require.NoError(t, models.DB().Create(acc).Error)
srv := &models.Server{
AccountID: acc.ID, Name: "host1", Slug: "host1", Region: "local",
}
require.NoError(t, models.DB().Create(srv).Error)
d1, err := models.UpsertNginxDeployment(nil, acc.ID, srv.ID, "/etc/nginx/sites-enabled/a.conf")
require.NoError(t, err)
require.NoError(t, models.DB().Save(d1).Error)
// Second call with the same config_path returns the existing row.
d2, err := models.UpsertNginxDeployment(nil, acc.ID, srv.ID, "/etc/nginx/sites-enabled/a.conf")
require.NoError(t, err)
assert.Equal(t, d1.ID, d2.ID, "should reuse the same row on identical config_path")
// Different config_path creates a new row.
d3, err := models.UpsertNginxDeployment(nil, acc.ID, srv.ID, "/etc/nginx/sites-enabled/b.conf")
require.NoError(t, err)
assert.NotEqual(t, d1.ID, d3.ID)
}
func TestDeployment_ReconcileMissing_FlipsAction(t *testing.T) {
models.Drop()
models.Migrate()
acc := &models.Account{Name: "reconcile"}
require.NoError(t, models.DB().Create(acc).Error)
srv := &models.Server{
AccountID: acc.ID, Name: "rec", Slug: "rec", Region: "local",
}
require.NoError(t, models.DB().Create(srv).Error)
old := time.Now().Add(-2 * time.Hour)
fresh := models.Deployment{
AccountID: acc.ID,
ServerID: &srv.ID,
Kind: models.DeploymentKindProduction,
Mode: models.DeploymentModeDedicated,
Action: models.DeploymentActionOk,
ConfigPath: ptr("/etc/nginx/old.conf"),
LastSeenAt: &old,
}
require.NoError(t, models.DB().Create(&fresh).Error)
recent := models.Deployment{
AccountID: acc.ID,
ServerID: &srv.ID,
Kind: models.DeploymentKindProduction,
Mode: models.DeploymentModeDedicated,
Action: models.DeploymentActionOk,
ConfigPath: ptr("/etc/nginx/recent.conf"),
LastSeenAt: ptrTime(time.Now()),
}
require.NoError(t, models.DB().Create(&recent).Error)
cutoff := time.Now().Add(-90 * time.Second)
marked, err := models.ReconcileMissingDeployments(srv.ID, models.DeploymentModeDedicated, cutoff)
require.NoError(t, err)
assert.EqualValues(t, 1, marked, "only the old row should flip")
var oldAfter models.Deployment
require.NoError(t, models.DB().First(&oldAfter, fresh.ID).Error)
assert.Equal(t, models.DeploymentActionMissing, oldAfter.Action)
var recentAfter models.Deployment
require.NoError(t, models.DB().First(&recentAfter, recent.ID).Error)
assert.Equal(t, models.DeploymentActionOk, recentAfter.Action, "fresh row stays ok")
// Re-running with the same cutoff is a no-op.
marked2, err := models.ReconcileMissingDeployments(srv.ID, models.DeploymentModeDedicated, cutoff)
require.NoError(t, err)
assert.EqualValues(t, 0, marked2)
}
func ptr(s string) *string { return &s }
func ptrTime(t time.Time) *time.Time { return &t }