package spindle

import (
	"context"
	"testing"
	"time"
)

func TestAKickedRepoStillWaitsOutItsBackoff(t *testing.T) {
	env := newEnsureEnv(t)
	env.serve("repo")
	env.ensure(t)
	if err := env.s.markRepo(testRepoDid); err != nil {
		t.Fatal(err)
	}
	env.knot.failing = true
	env.s.runRepoJob(context.Background(), testRepoDid)
	if attempts, marked, err := env.s.db.RepoRetryRow(testRepoDid); err != nil || !marked || attempts != 1 {
		t.Fatalf("setup: attempts %d, exists %v, %v, want one failed refresh", attempts, marked, err)
	}
	before := env.knot.count()

	env.s.runRepoJob(context.Background(), testRepoDid)
	if got := env.knot.count(); got != before {
		t.Fatalf("a repo that is backing off made %d knot requests when it was kicked", got-before)
	}
	if attempts, _, err := env.s.db.RepoRetryRow(testRepoDid); err != nil || attempts != 1 {
		t.Fatalf("attempts = %d, %v, want the backoff left at one failure", attempts, err)
	}

	// a new event doesn't skip the backoff, it only pulls the due time to a few seconds out
	if err := env.s.markRepo(testRepoDid); err != nil {
		t.Fatal(err)
	}
	env.s.runRepoJob(context.Background(), testRepoDid)
	if got := env.knot.count(); got != before {
		t.Fatalf("a fresh mark on a repo backing off made %d knot requests", got-before)
	}

	// once those few seconds pass the mark gets answered, long before the backoff ends
	env.knot.failing = false
	env.s.retries.now = func() time.Time { return time.Now().Add(6 * time.Second) }
	env.s.runRepoJob(context.Background(), testRepoDid)
	if env.knot.count() == before {
		t.Fatal("a mark that waited out the backoff didn't make the repo refresh")
	}
}
