Skip to content
quarry Artifact [046c51ac14]
Login

Artifact [046c51ac14]

Artifact 046c51ac14ce47224c3aeae54af816320a3faaf4a6591bc45e0d00e0dc876ae4:


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)
	}
}