Files
ARTEX/server/llmretry_test.go
BaaRai e233c02314 Translate all Chinese text to English
Comments, doc comments, UI labels, log and error messages, LLM prompt
strings, markdown docs, test data and assertions. Identifiers, enum
keys, routes, placeholders and code structure are unchanged.

Notes:
- docs/漏洞流量证据.md renamed to docs/vulnerability-traffic-evidence.md
- tests that exercised CJK specific handling (GBK zip names, Chinese
  full text search) now use ASCII equivalents; go build passes and the
  test suite matches the pre translation baseline (remaining failures
  need a PostgreSQL DSN and fail identically on the original)
- frontend mention syntax now uses English kinds (finding, asset, ...)
  matching the backend, chat mentions tests pass
2026-10-08 23:14:34 +02:00

98 lines
3.5 KiB
Go

package server
import (
"testing"
"time"
"github.com/Autumn-27/artex/agent"
"github.com/Autumn-27/artex/db"
)
// With no configuration at all, the resolved result must be all zeros — i.e. the
// built-in defaults of the SDK and task_llm, byte-for-byte identical to before the "configurable retries" feature landed.
func TestResolveRetryUnconfigured(t *testing.T) {
got := resolveRetry(db.RetryOverride{}, db.LLMRetryPolicy{})
if got != (agent.RetryConfig{}) {
t.Fatalf("resolveRetry=%+v, want zero", got)
}
retries, backoff := sameProviderRetryPolicy(got)
if retries != sameProviderStreamRetries {
t.Fatalf("retries=%d, want %d", retries, sameProviderStreamRetries)
}
if d := backoff(1); d != time.Second {
t.Fatalf("backoff(1)=%v, want 1s (the default ladder)", d)
}
}
// The global policy applies to a profile that overrides nothing.
func TestResolveRetryFromGlobal(t *testing.T) {
pol := db.LLMRetryPolicy{
Connect: db.RetryRule{Attempts: 5, IntervalMS: 2000},
Empty: db.RetryRule{Attempts: -1},
Stream: db.RetryRule{Attempts: 4, IntervalMS: 1500},
}
got := resolveRetry(db.RetryOverride{}, pol)
want := agent.RetryConfig{
ConnectAttempts: 5, ConnectInterval: 2 * time.Second,
EmptyAttempts: -1,
StreamAttempts: 4, StreamInterval: 1500 * time.Millisecond,
}
if got != want {
t.Fatalf("resolveRetry=%+v, want %+v", got, want)
}
retries, backoff := sameProviderRetryPolicy(got)
if retries != 4 {
t.Fatalf("retries=%d, want 4", retries)
}
for _, attempt := range []int{0, 3} {
if d := backoff(attempt); d != 1500*time.Millisecond {
t.Fatalf("backoff(%d)=%v, want a fixed 1.5s", attempt, d)
}
}
}
// A profile override wins field by field: the pinned count replaces the global
// one, while the interval it left alone still comes from the global policy.
func TestResolveRetryProfileOverridesPerField(t *testing.T) {
pol := db.LLMRetryPolicy{
Connect: db.RetryRule{Attempts: 5, IntervalMS: 2000},
Stream: db.RetryRule{Attempts: 4, IntervalMS: 1500},
}
over := db.RetryOverride{
Connect: db.RetryRule{Attempts: 1},
Stream: db.RetryRule{IntervalMS: 250},
}
got := resolveRetry(over, pol)
if got.ConnectAttempts != 1 || got.ConnectInterval != 2*time.Second {
t.Fatalf("connect=%d/%v, want 1 attempt inheriting the 2s interval", got.ConnectAttempts, got.ConnectInterval)
}
if got.StreamAttempts != 4 || got.StreamInterval != 250*time.Millisecond {
t.Fatalf("stream=%d/%v, want the global 4 attempts with a pinned 250ms", got.StreamAttempts, got.StreamInterval)
}
}
// -1 turns the same-provider layer off entirely (0 retries), rather than being
// mistaken for "unset".
func TestSameProviderRetryDisabled(t *testing.T) {
retries, _ := sameProviderRetryPolicy(agent.RetryConfig{StreamAttempts: -1})
if retries != 0 {
t.Fatalf("retries=%d, want 0 (disabled)", retries)
}
}
// Values beyond the sane range are clamped on the way into the DB, so a hostile
// or fat-fingered payload can't park a worker for a day.
func TestRetryRuleClamp(t *testing.T) {
pol := db.LLMRetryPolicy{
Connect: db.RetryRule{Attempts: -50, IntervalMS: -1},
Stream: db.RetryRule{Attempts: 9999, IntervalMS: 99_999_999},
}
got := resolveRetry(db.RetryOverride{}, pol.Clamped())
if got.ConnectAttempts != -1 || got.ConnectInterval != 0 {
t.Fatalf("connect=%d/%v, want -1 attempts and no interval", got.ConnectAttempts, got.ConnectInterval)
}
if got.StreamAttempts != 20 || got.StreamInterval != time.Hour {
t.Fatalf("stream=%d/%v, want the 20-attempt / 1h caps", got.StreamAttempts, got.StreamInterval)
}
}