package db import "testing" func TestSetSiteCompleteAndListCompletedSiteIndices(t *testing.T) { d, ctx := newTestDB(t) if err := d.SeedQueue(ctx, []string{"1.2.3.4"}); err != nil { t.Fatalf("seed queue: %v", err) } ip, err := d.GetIPByAddress(ctx, "1.2.3.4") if err != nil { t.Fatalf("get ip: %v", err) } for _, idx := range []int{1, 2, 4} { if err := d.SetSiteComplete(ctx, ip.ID, idx); err != nil { t.Fatalf("set site %d complete: %v", idx, err) } } completed, err := d.ListCompletedSiteIndices(ctx, ip.ID, ip.AttemptNumber) if err != nil { t.Fatalf("list completed site indices: %v", err) } for _, idx := range []int{1, 2, 4} { if !completed[idx] { t.Fatalf("expected site %d complete, got %+v", idx, completed) } } if completed[3] { t.Fatalf("expected site 3 not complete, got %+v", completed) } // Idempotent re-mark doesn't error or duplicate. if err := d.SetSiteComplete(ctx, ip.ID, 1); err != nil { t.Fatalf("re-mark site 1 complete: %v", err) } } // TestNewAttemptStartsWithNoCompletedSites confirms a bumped // attempt_number (via SubmitIPs requeue) starts with an empty completed // set even though the previous attempt had rows — proving no explicit // reset is needed on retry, unlike the old fixed-3-column design. func TestNewAttemptStartsWithNoCompletedSites(t *testing.T) { d, ctx := newTestDB(t) if err := d.SeedQueue(ctx, []string{"1.2.3.4"}); err != nil { t.Fatalf("seed queue: %v", err) } ip, err := d.GetIPByAddress(ctx, "1.2.3.4") if err != nil { t.Fatalf("get ip: %v", err) } if err := d.SetSiteComplete(ctx, ip.ID, 1); err != nil { t.Fatalf("set site complete: %v", err) } // Force the IP to a terminal state, then requeue via SubmitIPs — the // same path an admin-triggered recheck takes — to bump attempt_number. if _, err := d.ExecContext(ctx, `UPDATE ip_queue SET state=? WHERE id=?`, IPFailed, ip.ID); err != nil { t.Fatalf("force failed: %v", err) } if _, err := d.SubmitIPs(ctx, []string{"1.2.3.4"}); err != nil { t.Fatalf("resubmit: %v", err) } requeued, err := d.GetIP(ctx, ip.ID) if err != nil { t.Fatalf("get ip after requeue: %v", err) } if requeued.AttemptNumber != ip.AttemptNumber+1 { t.Fatalf("expected attempt_number bumped, got %d", requeued.AttemptNumber) } completed, err := d.ListCompletedSiteIndices(ctx, ip.ID, requeued.AttemptNumber) if err != nil { t.Fatalf("list completed site indices for new attempt: %v", err) } if len(completed) != 0 { t.Fatalf("expected no completed sites for the new attempt, got %+v", completed) } // The old attempt's row is still there as history, not wiped. old, err := d.ListCompletedSiteIndices(ctx, ip.ID, ip.AttemptNumber) if err != nil { t.Fatalf("list completed site indices for old attempt: %v", err) } if !old[1] { t.Fatalf("expected old attempt's completion to remain as history, got %+v", old) } }