package oltp
import "testing"
func addHook(t *testing.T, d *DB, repo string) Webhook {
t.Helper()
w, err := d.AddWebhook(repo, "https://example.test/h", "*")
if err != nil {
t.Fatal(err)
}
return w
}
// Five deliveries in a row that each ran out of retries pause the
// endpoint, and say why and when. The fourth does not.
func TestFiveSettledFailuresPauseTheEndpoint(t *testing.T) {
d := excDB(t)
w := addHook(t, d, "alpha")
for i := 1; i < PauseAfter; i++ {
if paused, err := d.SettleDelivery(w.ID, false, "endpoint answered 503"); err != nil || paused {
t.Fatalf("failure %d: paused=%v err=%v", i, paused, err)
}
}
got, _ := d.WebhookByID(w.ID)
if !got.Active || got.FailStreak != PauseAfter-1 || got.PausedAt != "" {
t.Fatalf("before the threshold: %+v", got)
}
paused, err := d.SettleDelivery(w.ID, false, "endpoint answered 503")
if err != nil || !paused {
t.Fatalf("threshold failure: paused=%v err=%v", paused, err)
}
got, _ = d.WebhookByID(w.ID)
if got.Active || got.PausedAt == "" || got.PausedWhy == "" || got.FailStreak != PauseAfter {
t.Fatalf("after the threshold: %+v", got)
}
if got.LastErr != "endpoint answered 503" {
t.Errorf("last error = %q", got.LastErr)
}
// It no longer appears among the endpoints to deliver to.
if act, _ := d.ActiveWebhooks("alpha"); len(act) != 0 {
t.Errorf("%d active endpoints after auto-pause", len(act))
}
}
// One success in the middle starts the count again.
func TestASuccessResetsTheFailureCount(t *testing.T) {
d := excDB(t)
w := addHook(t, d, "alpha")
for i := 0; i < PauseAfter-1; i++ {
d.SettleDelivery(w.ID, false, "x")
}
if _, err := d.SettleDelivery(w.ID, true, ""); err != nil {
t.Fatal(err)
}
for i := 0; i < PauseAfter-1; i++ {
if paused, _ := d.SettleDelivery(w.ID, false, "x"); paused {
t.Fatal("paused although a success intervened")
}
}
got, _ := d.WebhookByID(w.ID)
if !got.Active || got.FailStreak != PauseAfter-1 {
t.Fatalf("%+v", got)
}
}
// Resume clears the pause, its reason and the counter; a manual pause
// is not recorded as automatic.
func TestResumeClearsAutoPause(t *testing.T) {
d := excDB(t)
w := addHook(t, d, "alpha")
for i := 0; i < PauseAfter; i++ {
d.SettleDelivery(w.ID, false, "x")
}
if err := d.SetWebhookActive(w.ID, true); err != nil {
t.Fatal(err)
}
got, _ := d.WebhookByID(w.ID)
if !got.Active || got.FailStreak != 0 || got.PausedAt != "" || got.PausedWhy != "" {
t.Fatalf("after resume: %+v", got)
}
if err := d.SetWebhookActive(w.ID, false); err != nil {
t.Fatal(err)
}
got, _ = d.WebhookByID(w.ID)
if got.Active || got.PausedAt != "" {
t.Fatalf("a manual pause was recorded as automatic: %+v", got)
}
}
// The fleet list: paused or failing endpoints of every repository,
// worst first; healthy ones are absent.
func TestFailingWebhooksAcrossRepositories(t *testing.T) {
d := excDB(t)
healthy := addHook(t, d, "alpha")
flaky := addHook(t, d, "beta")
dead := addHook(t, d, "gamma")
manual := addHook(t, d, "alpha")
d.SettleDelivery(flaky.ID, false, "boom")
for i := 0; i < PauseAfter; i++ {
d.SettleDelivery(dead.ID, false, "gone")
}
d.SetWebhookActive(manual.ID, false)
got, err := d.FailingWebhooks()
if err != nil {
t.Fatal(err)
}
var ids []int64
for _, w := range got {
ids = append(ids, w.ID)
if w.ID == healthy.ID {
t.Error("a healthy endpoint is listed")
}
}
if len(ids) != 3 || ids[0] != dead.ID || ids[1] != flaky.ID || ids[2] != manual.ID {
t.Fatalf("order = %v, want %d %d %d", ids, dead.ID, flaky.ID, manual.ID)
}
if got[0].Repo != "gamma" {
t.Errorf("repo = %q", got[0].Repo)
}
}