package store import ( "errors" "testing" ) func seedWorkload(t *testing.T, s *Store, name string) Workload { t.Helper() w, err := s.CreateWorkload(Workload{Kind: "project", RefID: name, Name: name}) if err != nil { t.Fatalf("CreateWorkload(%s): %v", name, err) } return w } func TestDeployHistory_InsertListGet(t *testing.T) { s := newTestStore(t) w := seedWorkload(t, s, "app1") first, err := s.InsertDeployHistory(DeployHistoryEntry{ WorkloadID: w.ID, SourceKind: "image", Reference: "v1", Reason: "manual", TriggeredBy: "admin", Outcome: "success", }) if err != nil { t.Fatalf("InsertDeployHistory: %v", err) } if first.ID == 0 { t.Fatal("expected non-zero id") } if first.StartedAt == "" || first.FinishedAt == "" { t.Fatal("expected timestamps to be defaulted") } second, _ := s.InsertDeployHistory(DeployHistoryEntry{ WorkloadID: w.ID, SourceKind: "image", Reference: "v2", Reason: "registry-push", Outcome: "success", }) list, err := s.ListDeployHistory(w.ID, 10, 0) if err != nil { t.Fatalf("ListDeployHistory: %v", err) } if len(list) != 2 { t.Fatalf("expected 2 rows, got %d", len(list)) } // Newest-first ordering. if list[0].ID != second.ID || list[1].ID != first.ID { t.Fatalf("expected newest-first ordering, got %d then %d", list[0].ID, list[1].ID) } got, err := s.GetDeployHistory(first.ID) if err != nil { t.Fatalf("GetDeployHistory: %v", err) } if got.Reference != "v1" || got.SourceKind != "image" { t.Fatalf("unexpected row: %+v", got) } } func TestDeployHistory_GetNotFound(t *testing.T) { s := newTestStore(t) _, err := s.GetDeployHistory(999) if !errors.Is(err, ErrNotFound) { t.Fatalf("expected ErrNotFound, got %v", err) } } func TestDeployHistory_ListScopedToWorkload(t *testing.T) { s := newTestStore(t) a := seedWorkload(t, s, "a") b := seedWorkload(t, s, "b") s.InsertDeployHistory(DeployHistoryEntry{WorkloadID: a.ID, Outcome: "success"}) s.InsertDeployHistory(DeployHistoryEntry{WorkloadID: b.ID, Outcome: "success"}) list, _ := s.ListDeployHistory(a.ID, 10, 0) if len(list) != 1 || list[0].WorkloadID != a.ID { t.Fatalf("expected only workload a's rows, got %+v", list) } } func TestDeployHistory_Pagination(t *testing.T) { s := newTestStore(t) w := seedWorkload(t, s, "paged") for i := 0; i < 5; i++ { s.InsertDeployHistory(DeployHistoryEntry{WorkloadID: w.ID, Outcome: "success"}) } page1, _ := s.ListDeployHistory(w.ID, 2, 0) page2, _ := s.ListDeployHistory(w.ID, 2, 2) if len(page1) != 2 || len(page2) != 2 { t.Fatalf("expected 2 per page, got %d and %d", len(page1), len(page2)) } if page1[0].ID == page2[0].ID { t.Fatal("expected distinct rows across pages") } } func TestDeployHistory_Prune(t *testing.T) { s := newTestStore(t) w := seedWorkload(t, s, "noisy") for i := 0; i < 10; i++ { s.InsertDeployHistory(DeployHistoryEntry{WorkloadID: w.ID, Outcome: "success"}) } if err := s.PruneDeployHistory(w.ID, 3); err != nil { t.Fatalf("PruneDeployHistory: %v", err) } list, _ := s.ListDeployHistory(w.ID, 100, 0) if len(list) != 3 { t.Fatalf("expected 3 rows after prune, got %d", len(list)) } // Prune keeps the newest rows. all, _ := s.ListDeployHistory(w.ID, 100, 0) for i := 1; i < len(all); i++ { if all[i-1].ID < all[i].ID { t.Fatal("expected newest-first after prune") } } } func TestDeployHistory_CascadeOnWorkloadDelete(t *testing.T) { s := newTestStore(t) w := seedWorkload(t, s, "doomed") s.InsertDeployHistory(DeployHistoryEntry{WorkloadID: w.ID, Outcome: "success"}) s.InsertDeployHistory(DeployHistoryEntry{WorkloadID: w.ID, Outcome: "failure"}) if err := s.DeleteWorkload(w.ID); err != nil { t.Fatalf("DeleteWorkload: %v", err) } list, _ := s.ListDeployHistory(w.ID, 100, 0) if len(list) != 0 { t.Fatalf("expected history removed with workload, got %d rows", len(list)) } }