Files
wg-portal/internal/adapters/database_created_at_test.go

169 lines
5.1 KiB
Go
Raw Normal View History

package adapters
import (
"context"
"testing"
"time"
"github.com/glebarez/sqlite"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gorm.io/gorm"
"github.com/h44z/wg-portal/internal/config"
"github.com/h44z/wg-portal/internal/domain"
)
func newTestDB(t *testing.T) *gorm.DB {
t.Helper()
db, err := gorm.Open(sqlite.Open("file::memory:"), &gorm.Config{})
require.NoError(t, err)
return db
}
func TestUpsertUser_SetsCreatedAtWhenZero(t *testing.T) {
db := newTestDB(t)
require.NoError(t, db.AutoMigrate(&domain.User{}, &domain.UserAuthentication{}, &domain.UserWebauthnCredential{}))
repo := &SqlRepo{db: db, cfg: &config.Config{}}
ui := domain.SystemAdminContextUserInfo()
user := &domain.User{
Identifier: "test-user",
Email: "test@example.com",
// CreatedAt is zero
}
err := repo.upsertUser(ui, db, user)
require.NoError(t, err)
assert.False(t, user.CreatedAt.IsZero(), "CreatedAt should be set when it was zero")
assert.Equal(t, ui.UserId(), user.UpdatedBy, "UpdatedBy should be set when it was empty")
assert.WithinDuration(t, user.UpdatedAt, user.CreatedAt, time.Second,
"CreatedAt should be close to UpdatedAt for new user")
}
func TestUpsertUser_PreservesExistingCreatedAt(t *testing.T) {
db := newTestDB(t)
require.NoError(t, db.AutoMigrate(&domain.User{}, &domain.UserAuthentication{}, &domain.UserWebauthnCredential{}))
repo := &SqlRepo{db: db, cfg: &config.Config{}}
ui := domain.SystemAdminContextUserInfo()
originalTime := time.Date(2025, 1, 1, 12, 0, 0, 0, time.UTC)
user := &domain.User{
Identifier: "test-user",
Email: "test@example.com",
BaseModel: domain.BaseModel{
CreatedAt: originalTime,
CreatedBy: "original-creator",
},
}
err := repo.upsertUser(ui, db, user)
require.NoError(t, err)
assert.Equal(t, originalTime, user.CreatedAt, "CreatedAt should not be overwritten")
assert.Equal(t, "original-creator", user.CreatedBy, "CreatedBy should not be overwritten")
}
func TestSaveUser_NewUserGetsCreatedAt(t *testing.T) {
db := newTestDB(t)
require.NoError(t, db.AutoMigrate(&domain.User{}, &domain.UserAuthentication{}, &domain.UserWebauthnCredential{}))
repo := &SqlRepo{db: db, cfg: &config.Config{}}
ctx := domain.SetUserInfo(context.Background(), domain.SystemAdminContextUserInfo())
before := time.Now().Add(-time.Second)
err := repo.SaveUser(ctx, "new-user", func(u *domain.User) (*domain.User, error) {
u.Email = "new@example.com"
return u, nil
})
require.NoError(t, err)
var saved domain.User
require.NoError(t, db.First(&saved, "identifier = ?", "new-user").Error)
assert.False(t, saved.CreatedAt.IsZero(), "CreatedAt should not be zero")
assert.True(t, saved.CreatedAt.After(before), "CreatedAt should be recent")
assert.NotEmpty(t, saved.CreatedBy, "CreatedBy should be set")
}
func TestMigration_FixesZeroCreatedAt(t *testing.T) {
db := newTestDB(t)
// Manually create tables and seed schema version 3
require.NoError(t, db.AutoMigrate(
&SysStat{},
&domain.User{},
&domain.UserAuthentication{},
&domain.Interface{},
&domain.Cidr{},
&domain.Peer{},
&domain.AuditEntry{},
&domain.UserWebauthnCredential{},
))
// Insert schema versions 1, 2, 3 so migration starts at 3
for v := uint64(1); v <= 3; v++ {
require.NoError(t, db.Create(&SysStat{SchemaVersion: v, MigratedAt: time.Now()}).Error)
}
updatedAt := time.Date(2025, 6, 15, 10, 0, 0, 0, time.UTC)
// Insert a user with zero created_at but valid updated_at
require.NoError(t, db.Exec(
"INSERT INTO users (identifier, email, created_at, updated_at) VALUES (?, ?, ?, ?)",
"zero-user", "zero@example.com", time.Time{}, updatedAt,
).Error)
// Run migration
repo := &SqlRepo{db: db, cfg: &config.Config{}}
require.NoError(t, repo.migrate())
// Verify created_at was backfilled from updated_at
var user domain.User
require.NoError(t, db.First(&user, "identifier = ?", "zero-user").Error)
assert.Equal(t, updatedAt, user.CreatedAt, "created_at should be backfilled from updated_at")
// Verify schema version advanced to 4
var latest SysStat
require.NoError(t, db.Order("schema_version DESC").First(&latest).Error)
assert.Equal(t, uint64(4), latest.SchemaVersion)
}
func TestMigration_DoesNotTouchValidCreatedAt(t *testing.T) {
db := newTestDB(t)
require.NoError(t, db.AutoMigrate(
&SysStat{},
&domain.User{},
&domain.UserAuthentication{},
&domain.Interface{},
&domain.Cidr{},
&domain.Peer{},
&domain.AuditEntry{},
&domain.UserWebauthnCredential{},
))
for v := uint64(1); v <= 3; v++ {
require.NoError(t, db.Create(&SysStat{SchemaVersion: v, MigratedAt: time.Now()}).Error)
}
createdAt := time.Date(2024, 3, 1, 8, 0, 0, 0, time.UTC)
updatedAt := time.Date(2025, 6, 15, 10, 0, 0, 0, time.UTC)
require.NoError(t, db.Exec(
"INSERT INTO users (identifier, email, created_at, updated_at) VALUES (?, ?, ?, ?)",
"valid-user", "valid@example.com", createdAt, updatedAt,
).Error)
repo := &SqlRepo{db: db, cfg: &config.Config{}}
require.NoError(t, repo.migrate())
var user domain.User
require.NoError(t, db.First(&user, "identifier = ?", "valid-user").Error)
assert.Equal(t, createdAt, user.CreatedAt, "valid created_at should not be modified")
}