Task 36c40130-a69a-46ed-a047-2cdc5ee2d2e0, remediation of review findings F23-1 and F23-2 (PR #205). F23-1: StartPhotoBackfill now checks, in the same write transaction that enqueues, for a full backfill_dinner_photos job already queued or running (new GetActivePhotoBackfillJob query) and returns its id instead of enqueuing another, as plan.StartDraft does with GetActiveDraftJob. The claim is the stored job row, so it holds across restarts; a job left running by a stopped process is failed at boot and no longer blocks. F23-2: a dinner whose outcome write fails is still reported failed with grounding_error and the remaining dinners still run, but the job then fails (internal_error, as a ground_dinner job's failed write does) with the per-dinner outcomes published as its result, so it never reports success for state it did not store. Tests: overlapping triggers while queued, after a restart and while running return the one job; a refused dinner write fails the job. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
92 lines
2.7 KiB
Go
92 lines
2.7 KiB
Go
package dinners
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// SetGroundTimeout sets the deadline of grounding by hand until t ends. A
|
|
// test calling it must not run in parallel.
|
|
func SetGroundTimeout(t *testing.T, d time.Duration) {
|
|
old := groundTimeout
|
|
groundTimeout = d
|
|
t.Cleanup(func() { groundTimeout = old })
|
|
}
|
|
|
|
// SetOfferLifetime sets how long candidates ground a dinner until t ends.
|
|
// A test calling it must not run in parallel.
|
|
func SetOfferLifetime(t *testing.T, d time.Duration) {
|
|
old := offerLifetime
|
|
offerLifetime = d
|
|
t.Cleanup(func() { offerLifetime = old })
|
|
}
|
|
|
|
// SetUpdateCommitted runs f in Update once a rename is committed, before
|
|
// the dinner's offers are cleared, until t ends. A test calling it must
|
|
// not run in parallel.
|
|
func SetUpdateCommitted(t *testing.T, f func()) {
|
|
old := updateCommitted
|
|
updateCommitted = f
|
|
t.Cleanup(func() { updateCommitted = old })
|
|
}
|
|
|
|
// AdvanceClock moves the service's clock d ahead of real time until t
|
|
// ends, without firing any timer. A test calling it must not run in
|
|
// parallel.
|
|
func AdvanceClock(t *testing.T, d time.Duration) {
|
|
old := now
|
|
now = func() time.Time { return old().Add(d) }
|
|
t.Cleanup(func() { now = old })
|
|
}
|
|
|
|
// HasOffers reports whether the service holds candidates offered for
|
|
// dinner id.
|
|
func (s *Service) HasOffers(id string) bool {
|
|
s.offersMu.Lock()
|
|
defer s.offersMu.Unlock()
|
|
_, ok := s.offers[id]
|
|
return ok
|
|
}
|
|
|
|
// StoreOffers stores urls as dinner id's offers, as a Candidates search
|
|
// that read the dinner at grounding_revision revision would on finishing.
|
|
func (s *Service) StoreOffers(id string, urls map[string]string, revision int64) {
|
|
keep, done := s.trackOffers(id)
|
|
defer done()
|
|
keep(urls, revision)
|
|
}
|
|
|
|
// OfferCount is the number of dinners whose candidates the service holds.
|
|
func (s *Service) OfferCount() int {
|
|
s.offersMu.Lock()
|
|
defer s.offersMu.Unlock()
|
|
return len(s.offers)
|
|
}
|
|
|
|
// RunGroundJob runs the KindGroundDinner handler for p in the caller's
|
|
// goroutine, as the job runner would, and returns the grounding status it
|
|
// reports.
|
|
func (s *Service) RunGroundJob(ctx context.Context, p GroundJob) (string, error) {
|
|
r, err := s.runGroundJob(ctx, p, nil)
|
|
return r.GroundingStatus, err
|
|
}
|
|
|
|
// SafeSourceURL is safeSourceURL.
|
|
var SafeSourceURL = safeSourceURL
|
|
|
|
// RunBackfillJob runs the KindBackfillPhotos handler for p in the caller's
|
|
// goroutine, as the job runner would, and returns its outcomes: on an
|
|
// error, those it last published.
|
|
func (s *Service) RunBackfillJob(ctx context.Context, p BackfillJob) ([]BackfillOutcome, error) {
|
|
var published backfillResult
|
|
r, err := s.runBackfillJob(ctx, p, func(partial backfillResult) error {
|
|
published = partial
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return published.Dinners, err
|
|
}
|
|
return r.Dinners, nil
|
|
}
|