GET /jobs/{id} served a succeeded idea job's stored result as it was, so
a result stored before sources were made safe still showed a
token-bearing source_url and a site_name taken from the link's host
(BASE-01-R1). jobs.Kind.FailedResult becomes ShownResult, applied to
every stored result with the job's status: ideas_from_ingredients and
quick_ideas results show no ideas when failed and, otherwise, each
idea's source through dinners.SourceOf, the one rule, so no job old or
new serves an unsafe source. Other kinds' results are untouched.
dinners.SourceOf now parses the link before reading the site name, so a
link that does not parse is an error with or without a stored name, and
an idea job grounded in one fails instead of succeeding (BASE-01-R2).
Task: c15ed4b5-25ae-43c6-8d36-f4a6dd51e5af
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
77 lines
2.2 KiB
Go
77 lines
2.2 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
|