fix(store): cascade delete related rows when removing a site #92
@@ -152,10 +152,26 @@ func (s *SQLStore) UpdateSitePaused(id int, paused bool) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *SQLStore) DeleteSite(id int) error {
|
func (s *SQLStore) DeleteSite(id int) error {
|
||||||
_, err := s.db.Exec(s.q("DELETE FROM sites WHERE id=?"), id)
|
tx, err := s.db.Begin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer func() { _ = tx.Rollback() }()
|
||||||
|
|
||||||
|
for _, q := range []string{
|
||||||
|
"DELETE FROM maintenance_windows WHERE monitor_id = ?",
|
||||||
|
"DELETE FROM check_history WHERE site_id = ?",
|
||||||
|
"DELETE FROM state_changes WHERE site_id = ?",
|
||||||
|
"DELETE FROM sites WHERE id = ?",
|
||||||
|
} {
|
||||||
|
if _, err := tx.Exec(s.q(q), id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tx.Commit(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
s.dialect.ResetSequenceOnEmpty(s.db, "sites")
|
s.dialect.ResetSequenceOnEmpty(s.db, "sites")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package store
|
package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newTestStore(t *testing.T) *SQLStore {
|
func newTestStore(t *testing.T) *SQLStore {
|
||||||
@@ -229,3 +231,51 @@ func TestCheckHistory(t *testing.T) {
|
|||||||
t.Errorf("expected 1 up record for site 1, got %d", upCount)
|
t.Errorf("expected 1 up record for site 1, got %d", upCount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDeleteSiteCascade(t *testing.T) {
|
||||||
|
s := newTestStore(t)
|
||||||
|
|
||||||
|
site := models.Site{Name: "Cascade Test", URL: "https://example.com", Interval: 30}
|
||||||
|
if err := s.AddSite(site); err != nil {
|
||||||
|
t.Fatalf("AddSite: %v", err)
|
||||||
|
}
|
||||||
|
sites, _ := s.GetSites()
|
||||||
|
siteID := sites[0].ID
|
||||||
|
|
||||||
|
if err := s.SaveCheck(siteID, 1000, true); err != nil {
|
||||||
|
t.Fatalf("SaveCheck: %v", err)
|
||||||
|
}
|
||||||
|
if err := s.SaveStateChange(siteID, "UP", "DOWN", "timeout"); err != nil {
|
||||||
|
t.Fatalf("SaveStateChange: %v", err)
|
||||||
|
}
|
||||||
|
mw := models.MaintenanceWindow{
|
||||||
|
MonitorID: siteID,
|
||||||
|
Title: "Test MW",
|
||||||
|
Type: "maintenance",
|
||||||
|
StartTime: time.Now(),
|
||||||
|
}
|
||||||
|
if err := s.AddMaintenanceWindow(mw); err != nil {
|
||||||
|
t.Fatalf("AddMaintenanceWindow: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.DeleteSite(siteID); err != nil {
|
||||||
|
t.Fatalf("DeleteSite: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
history, _ := s.LoadAllHistory(100)
|
||||||
|
if len(history[siteID]) != 0 {
|
||||||
|
t.Errorf("expected 0 check_history rows, got %d", len(history[siteID]))
|
||||||
|
}
|
||||||
|
|
||||||
|
changes, _ := s.GetStateChanges(siteID, 100)
|
||||||
|
if len(changes) != 0 {
|
||||||
|
t.Errorf("expected 0 state_changes rows, got %d", len(changes))
|
||||||
|
}
|
||||||
|
|
||||||
|
windows, _ := s.GetActiveMaintenanceWindows()
|
||||||
|
for _, w := range windows {
|
||||||
|
if w.MonitorID == siteID {
|
||||||
|
t.Errorf("orphaned maintenance window found: id=%d", w.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user