diff --git a/sdk/cliproxy/auth/conductor_registry_reconcile_test.go b/sdk/cliproxy/auth/conductor_registry_reconcile_test.go deleted file mode 100644 index dc4b95a9..00000000 --- a/sdk/cliproxy/auth/conductor_registry_reconcile_test.go +++ /dev/null @@ -1,182 +0,0 @@ -package auth - -import ( - "context" - "errors" - "net/http" - "testing" - "time" - - cliproxyexecutor "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/executor" -) - -func TestManager_ReconcileRegistryModelStates_ClearsStaleSupportedModelErrors(t *testing.T) { - ctx := context.Background() - manager := NewManager(nil, &RoundRobinSelector{}, nil) - - auth := &Auth{ - ID: "reconcile-auth", - Provider: "codex", - ModelStates: map[string]*ModelState{ - "gpt-5.4": { - Status: StatusError, - StatusMessage: "not_found", - Unavailable: true, - NextRetryAfter: time.Now().Add(12 * time.Hour), - LastError: &Error{HTTPStatus: http.StatusNotFound, Message: "not_found"}, - }, - }, - } - if _, errRegister := manager.Register(ctx, auth); errRegister != nil { - t.Fatalf("register auth: %v", errRegister) - } - - registerSchedulerModels(t, "codex", "gpt-5.4", auth.ID) - manager.RefreshSchedulerEntry(auth.ID) - - got, errPick := manager.scheduler.pickSingle(ctx, "codex", "gpt-5.4", cliproxyexecutor.Options{}, nil) - var authErr *Error - if !errors.As(errPick, &authErr) || authErr == nil { - t.Fatalf("pickSingle() before reconcile error = %v, want auth_unavailable", errPick) - } - if authErr.Code != "auth_unavailable" { - t.Fatalf("pickSingle() before reconcile code = %q, want %q", authErr.Code, "auth_unavailable") - } - if got != nil { - t.Fatalf("pickSingle() before reconcile auth = %v, want nil", got) - } - - manager.ReconcileRegistryModelStates(ctx, auth.ID) - - got, errPick = manager.scheduler.pickSingle(ctx, "codex", "gpt-5.4", cliproxyexecutor.Options{}, nil) - if errPick != nil { - t.Fatalf("pickSingle() after reconcile error = %v", errPick) - } - if got == nil || got.ID != auth.ID { - t.Fatalf("pickSingle() after reconcile auth = %v, want %q", got, auth.ID) - } - - reconciled, ok := manager.GetByID(auth.ID) - if !ok || reconciled == nil { - t.Fatalf("expected auth to still exist") - } - state := reconciled.ModelStates["gpt-5.4"] - if state == nil { - t.Fatalf("expected reconciled model state to exist") - } - if state.Unavailable { - t.Fatalf("state.Unavailable = true, want false") - } - if state.Status != StatusActive { - t.Fatalf("state.Status = %q, want %q", state.Status, StatusActive) - } - if !state.NextRetryAfter.IsZero() { - t.Fatalf("state.NextRetryAfter = %v, want zero", state.NextRetryAfter) - } - if state.LastError != nil { - t.Fatalf("state.LastError = %v, want nil", state.LastError) - } -} - -func TestManager_ReconcileRegistryModelStates_PrunesUnsupportedModelStates(t *testing.T) { - ctx := context.Background() - manager := NewManager(nil, &RoundRobinSelector{}, nil) - - nextRetry := time.Now().Add(30 * time.Minute) - auth := &Auth{ - ID: "reconcile-unsupported-auth", - Provider: "codex", - Status: StatusError, - Unavailable: true, - StatusMessage: "payment_required", - LastError: &Error{HTTPStatus: http.StatusPaymentRequired, Message: "payment_required"}, - ModelStates: map[string]*ModelState{ - "gpt-5.4": { - Status: StatusError, - StatusMessage: "payment_required", - Unavailable: true, - NextRetryAfter: nextRetry, - }, - }, - } - if _, errRegister := manager.Register(ctx, auth); errRegister != nil { - t.Fatalf("register auth: %v", errRegister) - } - - registerSchedulerModels(t, "codex", "gpt-5.5", auth.ID) - manager.ReconcileRegistryModelStates(ctx, auth.ID) - - reconciled, ok := manager.GetByID(auth.ID) - if !ok || reconciled == nil { - t.Fatalf("expected auth to still exist") - } - if len(reconciled.ModelStates) != 0 { - t.Fatalf("expected stale unsupported model state to be pruned, got %+v", reconciled.ModelStates) - } - if reconciled.Unavailable { - t.Fatalf("auth.Unavailable = true, want false") - } - if reconciled.Status != StatusActive { - t.Fatalf("auth.Status = %q, want %q", reconciled.Status, StatusActive) - } - if reconciled.StatusMessage != "" { - t.Fatalf("auth.StatusMessage = %q, want empty", reconciled.StatusMessage) - } - if reconciled.LastError != nil { - t.Fatalf("auth.LastError = %v, want nil", reconciled.LastError) - } - if !reconciled.NextRetryAfter.IsZero() { - t.Fatalf("auth.NextRetryAfter = %v, want zero", reconciled.NextRetryAfter) - } -} - -func TestManager_ReconcileRegistryModelStates_ClearsRemovedModelStateWhenRegistryIsEmpty(t *testing.T) { - ctx := context.Background() - manager := NewManager(nil, &RoundRobinSelector{}, nil) - - auth := &Auth{ - ID: "reconcile-empty-registry-auth", - Provider: "codex", - Status: StatusError, - Unavailable: true, - StatusMessage: "not_found", - LastError: &Error{HTTPStatus: http.StatusNotFound, Message: "not_found"}, - ModelStates: map[string]*ModelState{ - "gpt-5.4": { - Status: StatusError, - StatusMessage: "not_found", - Unavailable: true, - NextRetryAfter: time.Now().Add(12 * time.Hour), - LastError: &Error{HTTPStatus: http.StatusNotFound, Message: "not_found"}, - }, - }, - } - if _, errRegister := manager.Register(ctx, auth); errRegister != nil { - t.Fatalf("register auth: %v", errRegister) - } - - manager.ReconcileRegistryModelStates(ctx, auth.ID) - - reconciled, ok := manager.GetByID(auth.ID) - if !ok || reconciled == nil { - t.Fatalf("expected auth to still exist") - } - if len(reconciled.ModelStates) != 0 { - t.Fatalf("expected stale model state to be pruned when registry is empty, got %+v", reconciled.ModelStates) - } - if reconciled.Unavailable { - t.Fatalf("auth.Unavailable = true, want false") - } - if reconciled.Status != StatusActive { - t.Fatalf("auth.Status = %q, want %q", reconciled.Status, StatusActive) - } - if reconciled.StatusMessage != "" { - t.Fatalf("auth.StatusMessage = %q, want empty", reconciled.StatusMessage) - } - if reconciled.LastError != nil { - t.Fatalf("auth.LastError = %v, want nil", reconciled.LastError) - } - if !reconciled.NextRetryAfter.IsZero() { - t.Fatalf("auth.NextRetryAfter = %v, want zero", reconciled.NextRetryAfter) - } -}