package test import ( "RenewCMS/api/pkg/apperr" domainPurge "RenewCMS/internal/domain/purge" "RenewCMS/internal/domain/user" "RenewCMS/internal/infrastructure/persistence/models" persistence "RenewCMS/internal/infrastructure/persistence/repositories" "net/http" "os/exec" "reflect" "strings" "testing" "time" ) func TestPurgeRoleGuardIsAnAllowlist(t *testing.T) { for _, role := range []string{"OWNER", "Admin", "superuser"} { for _, route := range []struct{ method, path string }{ {http.MethodGet, "/v1/media/purge-settings"}, {http.MethodPatch, "/v1/media/purge-settings"}, {http.MethodGet, "/v1/media/purge-preview"}, {http.MethodPost, "/v1/media/purge"}, } { t.Run(role+" "+route.method+" "+route.path, func(t *testing.T) { env := newPurgeEnv(t) env.users.users[20] = user.User{ID: 20, Username: "other", IsVerified: true, Role: user.Role(role)} rec := env.send(t, route.method, route.path, "", 20) expectRaw(t, rec, 403, apperr.OwnerOrAdminRequiredErrorMessage+"\n") if env.purgeSettings.getCalls != 0 || env.purgeSettings.saveCalls != 0 { t.Errorf("expected no purge setting access") } }) } } } func TestPurgeLayering(t *testing.T) { list := func(t *testing.T, format string, pkg string) []string { t.Helper() output, err := exec.Command("go", "list", "-tags", "nofrontend", "-f", format, pkg).CombinedOutput() if err != nil { t.Fatalf("go list failed: %v: %s", err, output) } return strings.Fields(string(output)) } t.Run("internal/domain/purge imports only the stdlib and other domain packages", func(t *testing.T) { for _, imported := range list(t, `{{join .Imports "\n"}}`, "RenewCMS/internal/domain/purge") { if strings.Contains(imported, ".") && !strings.HasPrefix(imported, "RenewCMS/internal/domain/") { t.Errorf("unexpected import %s", imported) } } }) t.Run("the use cases import no http, chi, gorm, persistence, mailer, models or api package", func(t *testing.T) { for _, imported := range list(t, `{{join .Imports "\n"}}`, "RenewCMS/internal/infrastructure/useCases") { for _, forbidden := range []string{"net/http", "go-chi", "gorm", "persistence", "mailer", "RenewCMS/api"} { if strings.Contains(imported, forbidden) { t.Errorf("useCases must not import %s", imported) } } } }) } func TestPurgeSettingsRepositoryRoundTrip(t *testing.T) { newRepo := func(t *testing.T) *persistence.PurgeSettingsRepository { t.Helper() db := openInMemoryDb(t) if err := db.AutoMigrate(&models.PurgeSettings{}); err != nil { t.Fatalf("failed to migrate: %v", err) } return persistence.NewPurgeSettingsRepository(db) } t.Run("Nothing saved yields the defaults", func(t *testing.T) { got, err := newRepo(t).Get() if err != nil || !reflect.DeepEqual(got, domainPurge.DefaultSettings()) { t.Errorf("expected defaults, got %+v, %v", got, err) } }) t.Run("Null and set timestamps survive a save", func(t *testing.T) { repo := newRepo(t) withNulls := domainPurge.Settings{AutoPurgeEnabled: true, AutoPurgeIntervalDays: 7} if err := repo.Save(withNulls); err != nil { t.Fatal(err) } got, err := repo.Get() if err != nil || !reflect.DeepEqual(got, withNulls) { t.Errorf("expected %+v, got %+v, %v", withNulls, got, err) } last := time.Date(2026, 9, 1, 9, 0, 0, 0, time.UTC) enabled := time.Date(2026, 10, 5, 9, 0, 0, 0, time.UTC) full := domainPurge.Settings{AutoPurgeEnabled: true, AutoPurgeIntervalDays: 365, LastPurgeAt: &last, LastPurgeMerged: 3, LastPurgeArticlesUpdated: 1, EnabledAt: &enabled} if err := repo.Save(full); err != nil { t.Fatal(err) } got, err = repo.Get() if err != nil || got.LastPurgeAt == nil || !got.LastPurgeAt.Equal(last) || got.EnabledAt == nil || !got.EnabledAt.Equal(enabled) || got.LastPurgeMerged != 3 || got.LastPurgeArticlesUpdated != 1 || got.AutoPurgeIntervalDays != 365 { t.Errorf("unexpected round trip %+v, %v", got, err) } }) t.Run("Repeated saves keep a single row", func(t *testing.T) { db := openInMemoryDb(t) if err := db.AutoMigrate(&models.PurgeSettings{}); err != nil { t.Fatal(err) } repo := persistence.NewPurgeSettingsRepository(db) for days := 1; days <= 3; days++ { if err := repo.Save(domainPurge.Settings{AutoPurgeIntervalDays: days}); err != nil { t.Fatal(err) } } var count int64 db.Model(&models.PurgeSettings{}).Count(&count) if count != 1 { t.Errorf("expected a single row, got %d", count) } }) }