@@ -46,6 +46,36 @@ func (e ineffectiveRefreshExecutor) HttpRequest(context.Context, *Auth, *http.Re
4646 return nil , nil
4747}
4848
49+ type successfulRefreshExecutor struct {
50+ provider string
51+ }
52+
53+ func (e successfulRefreshExecutor ) Identifier () string { return e .provider }
54+
55+ func (e successfulRefreshExecutor ) Execute (context.Context , * Auth , cliproxyexecutor.Request , cliproxyexecutor.Options ) (cliproxyexecutor.Response , error ) {
56+ return cliproxyexecutor.Response {}, nil
57+ }
58+
59+ func (e successfulRefreshExecutor ) ExecuteStream (context.Context , * Auth , cliproxyexecutor.Request , cliproxyexecutor.Options ) (* cliproxyexecutor.StreamResult , error ) {
60+ return nil , nil
61+ }
62+
63+ func (e successfulRefreshExecutor ) Refresh (_ context.Context , auth * Auth ) (* Auth , error ) {
64+ if auth .Metadata == nil {
65+ auth .Metadata = make (map [string ]any )
66+ }
67+ auth .Metadata ["access_token" ] = "new-access-token"
68+ return auth , nil
69+ }
70+
71+ func (e successfulRefreshExecutor ) CountTokens (context.Context , * Auth , cliproxyexecutor.Request , cliproxyexecutor.Options ) (cliproxyexecutor.Response , error ) {
72+ return cliproxyexecutor.Response {}, nil
73+ }
74+
75+ func (e successfulRefreshExecutor ) HttpRequest (context.Context , * Auth , * http.Request ) (* http.Response , error ) {
76+ return nil , nil
77+ }
78+
4979type metadataMutatingExecutor struct {
5080 provider string
5181}
@@ -339,6 +369,49 @@ func TestManager_Update_ActiveInheritsModelStates(t *testing.T) {
339369 }
340370}
341371
372+ func TestManager_RefreshAuth_ClearsInheritedRuntimeBlockAfterSuccessfulRefresh (t * testing.T ) {
373+ m := NewManager (nil , nil , nil )
374+ executor := successfulRefreshExecutor {provider : "claude" }
375+ m .RegisterExecutor (executor )
376+
377+ now := time .Now ().UTC ()
378+ if _ , errRegister := m .Register (context .Background (), & Auth {
379+ ID : "auth-refresh-success" ,
380+ Provider : "claude" ,
381+ Status : StatusError ,
382+ Metadata : map [string ]any {
383+ "access_token" : "old-access-token" ,
384+ },
385+ ModelStates : map [string ]* ModelState {
386+ "claude-sonnet" : {
387+ Status : StatusError ,
388+ Unavailable : true ,
389+ NextRetryAfter : now .Add (30 * time .Minute ),
390+ LastError : & Error {Message : "unauthorized" , HTTPStatus : http .StatusUnauthorized },
391+ UpdatedAt : now ,
392+ },
393+ },
394+ }); errRegister != nil {
395+ t .Fatalf ("register auth: %v" , errRegister )
396+ }
397+
398+ m .refreshAuth (context .Background (), "auth-refresh-success" )
399+
400+ updated , ok := m .GetByID ("auth-refresh-success" )
401+ if ! ok || updated == nil {
402+ t .Fatalf ("expected auth to be present after refresh" )
403+ }
404+ if got := updated .Metadata ["access_token" ]; got != "new-access-token" {
405+ t .Fatalf ("access_token = %v, want new-access-token" , got )
406+ }
407+ if updated .Unavailable || ! updated .NextRetryAfter .IsZero () || len (updated .ModelStates ) != 0 {
408+ t .Fatalf ("expected successful refresh to clear runtime block, got unavailable=%v next_retry=%s model_states=%d" , updated .Unavailable , updated .NextRetryAfter , len (updated .ModelStates ))
409+ }
410+ if updated .LastRefreshedAt .IsZero () {
411+ t .Fatal ("expected LastRefreshedAt to be set" )
412+ }
413+ }
414+
342415func TestManager_RefreshAuth_SetsBackoffWhenRefreshIsIneffective (t * testing.T ) {
343416 m := NewManager (nil , nil , nil )
344417 executor := ineffectiveRefreshExecutor {provider : "claude" }
0 commit comments