package test import ( "RenewCMS/internal/domain/role" "RenewCMS/internal/infrastructure/persistence/database" "RenewCMS/internal/infrastructure/persistence/models" persistence "RenewCMS/internal/infrastructure/persistence/repositories" "errors" "testing" ) func TestRoleRepositoryFailures(t *testing.T) { broken := func(t *testing.T, table string) *persistence.RoleRepository { t.Helper() db := openMigratedRolesDB(t) if err := db.Migrator().DropTable(table); err != nil { t.Fatal(err) } return persistence.NewRoleRepository(db) } t.Run("List fails when the roles table is missing", func(t *testing.T) { if _, err := broken(t, "roles").List(); err == nil { t.Error("expected error") } }) t.Run("Get distinguishes a missing role from a storage failure", func(t *testing.T) { repo := persistence.NewRoleRepository(openMigratedRolesDB(t)) if _, err := repo.Get(9999); !errors.Is(err, role.ErrRoleNotFound) { t.Errorf("want ErrRoleNotFound, got %v", err) } if _, err := broken(t, "roles").Get(1); err == nil || errors.Is(err, role.ErrRoleNotFound) { t.Errorf("want storage error, got %v", err) } }) t.Run("GetByName reports a missing role", func(t *testing.T) { repo := persistence.NewRoleRepository(openMigratedRolesDB(t)) if _, err := repo.GetByName("Nobody"); !errors.Is(err, role.ErrRoleNotFound) { t.Errorf("want ErrRoleNotFound, got %v", err) } }) t.Run("List and role loading fail when grants cannot be read", func(t *testing.T) { repo := broken(t, "role_permissions") if _, err := repo.List(); err == nil { t.Error("List: expected error") } if _, err := repo.Get(1); err == nil { t.Error("Get: expected error") } }) t.Run("Create persists grants and returns them", func(t *testing.T) { db := openMigratedRolesDB(t) repo := persistence.NewRoleRepository(db) created, err := repo.Create(role.Role{Name: "Contributor", Version: 1, Grants: []role.Grant{{Key: "content.read", Scope: role.ScopeAll}}}) if err != nil { t.Fatal(err) } if len(created.Grants) != 1 || created.Grants[0].Key != "content.read" { t.Errorf("returned grants: %+v", created.Grants) } if countRows(t, db, &models.RolePermission{}) != 73 { t.Errorf("grant rows not stored") } }) t.Run("Create rolls back when the grants cannot be stored", func(t *testing.T) { db := openMigratedRolesDB(t) if err := db.Migrator().DropTable("role_permissions"); err != nil { t.Fatal(err) } repo := persistence.NewRoleRepository(db) before := countRows(t, db, &models.Role{}) _, err := repo.Create(role.Role{Name: "Contributor", Version: 1, Grants: []role.Grant{{Key: "content.read", Scope: role.ScopeAll}}}) if err == nil { t.Fatal("expected error") } if countRows(t, db, &models.Role{}) != before { t.Errorf("role row not rolled back") } }) t.Run("Create fails when the roles table is missing", func(t *testing.T) { if _, err := broken(t, "roles").Create(role.Role{Name: "X", Version: 1}); err == nil { t.Error("expected error") } }) t.Run("Save returns the stored role with its new grants", func(t *testing.T) { db := openMigratedRolesDB(t) repo := persistence.NewRoleRepository(db) writer := storedRole(t, db, "Writer") writer.Grants = []role.Grant{{Key: "media.delete", Scope: role.ScopeOwn}} saved, err := repo.Save(writer) if err != nil { t.Fatal(err) } if saved.ID != writer.ID || len(saved.Grants) != 1 || saved.Grants[0].Key != "media.delete" { t.Errorf("saved: %+v", saved) } }) t.Run("Save reports a missing role and storage failures", func(t *testing.T) { repo := persistence.NewRoleRepository(openMigratedRolesDB(t)) if _, err := repo.Save(role.Role{ID: 9999, Name: "Ghost", Version: 1}); !errors.Is(err, role.ErrRoleNotFound) { t.Errorf("want ErrRoleNotFound, got %v", err) } db := openMigratedRolesDB(t) writer := storedRole(t, db, "Writer") if err := db.Migrator().DropTable("role_permissions"); err != nil { t.Fatal(err) } if _, err := persistence.NewRoleRepository(db).Save(writer); err == nil { t.Error("expected storage error") } }) } func TestBackfillUserRoleIDsWithoutBuiltInRoles(t *testing.T) { db := openUnmigratedSQLite(t) if err := db.AutoMigrate(&models.Role{}, &models.RolePermission{}, &models.User{}); err != nil { t.Fatal(err) } createUserRow(t, db, 1, "owner", nil) if err := database.BackfillUserRoleIDs(db); err != nil { t.Fatal(err) } if userRow(t, db, 1).RoleID != nil { t.Errorf("role_id must stay unset when no built-in role exists") } }