Pace provider traffic and identify genuine foreground bank requests
This commit is contained in:
@@ -12,8 +12,63 @@ import (
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"finance-duck/internal/ratelimit"
|
||||
)
|
||||
|
||||
func TestProductionRatePolicyAcrossModelSnapshots(t *testing.T) {
|
||||
t.Run("successful classifications stay paced", func(t *testing.T) {
|
||||
f, d := fixture()
|
||||
arrivals := make(chan time.Time, 2)
|
||||
c := mockClient(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
arrivals <- time.Now()
|
||||
reply(w, validAnswer)
|
||||
})
|
||||
// Remove only the fixture's fast policy, exercising real lazy production
|
||||
// initialization and the same shared controller used by previews.
|
||||
c.rate.Store(nil)
|
||||
snapshot := c.WithModel("test/preview-model")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 6*time.Second)
|
||||
defer cancel()
|
||||
for _, client := range []*Client{c, snapshot} {
|
||||
p, err := client.Classify(ctx, f, d, true)
|
||||
if err != nil || p.Enrichment.Classification.Source != "openrouter" {
|
||||
t.Fatalf("production-paced classification failed: %+v, %v", p, err)
|
||||
}
|
||||
}
|
||||
first, second := <-arrivals, <-arrivals
|
||||
if gap := second.Sub(first); gap < 3*time.Second-25*time.Millisecond {
|
||||
t.Fatalf("model snapshots burst after success: %v", gap)
|
||||
}
|
||||
})
|
||||
t.Run("first failure retains conservative retry deadline", func(t *testing.T) {
|
||||
f, d := fixture()
|
||||
var calls atomic.Int32
|
||||
c := mockClient(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
calls.Add(1)
|
||||
w.WriteHeader(http.StatusTooManyRequests)
|
||||
})
|
||||
c.rate.Store(nil)
|
||||
snapshot := c.WithModel("test/preview-model")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
|
||||
defer cancel()
|
||||
_, err := c.Classify(ctx, f, d, true)
|
||||
var limit *ratelimit.RateLimitError
|
||||
if !errors.Is(err, context.DeadlineExceeded) || !errors.As(err, &limit) {
|
||||
t.Fatalf("production retry wait lost cancellation or quota identity: %v", err)
|
||||
}
|
||||
if delay := time.Until(limit.RetryAt()); delay < 14*time.Second {
|
||||
t.Fatalf("production retry used a short per-record fallback: %v", delay)
|
||||
}
|
||||
probeCtx, probeCancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer probeCancel()
|
||||
_, err = snapshot.Classify(probeCtx, f, d, true)
|
||||
if !errors.As(err, &limit) || errors.Is(err, context.DeadlineExceeded) || calls.Load() != 1 {
|
||||
t.Fatalf("preview discarded production cooldown: %v, calls=%d", err, calls.Load())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestRateLimitRetryPreservesPrivateRequest(t *testing.T) {
|
||||
f, d := fixture()
|
||||
f.Counterparty = "Alice Privateperson"
|
||||
|
||||
Reference in New Issue
Block a user