Files
geo/server/internal/worker/generate/article_generation_recovery_test.go
T
root c1ef717d17
Deployment Config CI / Deployment Config (push) Successful in 24s
Backend CI / Backend (push) Successful in 14m33s
feat(cache,worker): overhaul cache layer and add generation task lease recovery
- shared/cache: add Options/L1/async/metrics/prefix decorators, multi-key ops, Redis pool tuning, and JSON readthrough metrics
- worker-generate: claim tasks via DB lease + heartbeat, requeue stale queued tasks, expire dead leases with refund/cache invalidation
- tenant: version article cache keys so worker recovery invalidations propagate cleanly
- shared/config: expand Redis (pool/timeouts/TLS) and Generation (lease/recovery) configs with defaults

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 02:02:39 +08:00

73 lines
2.2 KiB
Go

package generate
import (
"strings"
"testing"
"time"
"github.com/geo-platform/tenant-api/internal/shared/config"
)
func TestNormalizeGenerationTaskRecoveryConfigUsesGenerationDefaults(t *testing.T) {
cfg := normalizeGenerationTaskRecoveryConfig(config.GenerationConfig{
ArticleTimeout: 90 * time.Second,
})
if cfg.LeaseTTL != 3*time.Minute+30*time.Second {
t.Fatalf("expected lease ttl article_timeout+2m, got %s", cfg.LeaseTTL)
}
if cfg.RecoveryInterval != time.Minute {
t.Fatalf("expected recovery interval 1m, got %s", cfg.RecoveryInterval)
}
if cfg.RecoveryTimeout != 30*time.Second {
t.Fatalf("expected recovery timeout 30s, got %s", cfg.RecoveryTimeout)
}
if cfg.BatchSize != 100 {
t.Fatalf("expected batch size 100, got %d", cfg.BatchSize)
}
if cfg.QueuedStaleAfter != 2*time.Minute {
t.Fatalf("expected queued stale after 2m, got %s", cfg.QueuedStaleAfter)
}
if cfg.MaxAttempts != 3 {
t.Fatalf("expected max attempts 3, got %d", cfg.MaxAttempts)
}
}
func TestNormalizeGenerationTaskRecoveryConfigKeepsOverrides(t *testing.T) {
cfg := normalizeGenerationTaskRecoveryConfig(config.GenerationConfig{
ArticleTimeout: 5 * time.Minute,
TaskLeaseTTL: 7 * time.Minute,
TaskRecoveryInterval: 15 * time.Second,
TaskRecoveryTimeout: 10 * time.Second,
TaskRecoveryBatchSize: 12,
TaskQueuedStaleAfter: 45 * time.Second,
TaskMaxAttempts: 5,
})
if cfg.LeaseTTL != 7*time.Minute ||
cfg.RecoveryInterval != 15*time.Second ||
cfg.RecoveryTimeout != 10*time.Second ||
cfg.BatchSize != 12 ||
cfg.QueuedStaleAfter != 45*time.Second ||
cfg.MaxAttempts != 5 {
t.Fatalf("unexpected recovery config: %#v", cfg)
}
}
func TestGenerationWorkerOwnerIsBounded(t *testing.T) {
owner := generationWorkerOwner(strings.Repeat("x", 256))
if len(owner) > 128 {
t.Fatalf("expected owner to be bounded to 128 chars, got %d", len(owner))
}
if owner == "" {
t.Fatalf("expected non-empty owner")
}
}
func TestGenerationTaskRecoveryFailureMessage(t *testing.T) {
message := formatGenerationTaskRecoveryFailure()
if !strings.Contains(message, "worker_recovery") {
t.Fatalf("expected recovery marker in failure message, got %q", message)
}
}