mirror of
https://github.com/router-for-me/CLIProxyAPIPlus.git
synced 2026-03-29 16:54:41 +00:00
164 lines
5.2 KiB
Go
164 lines
5.2 KiB
Go
package auth
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/http"
|
|
"testing"
|
|
|
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/registry"
|
|
cliproxyexecutor "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/executor"
|
|
)
|
|
|
|
type schedulerProviderTestExecutor struct {
|
|
provider string
|
|
}
|
|
|
|
func (e schedulerProviderTestExecutor) Identifier() string { return e.provider }
|
|
|
|
func (e schedulerProviderTestExecutor) Execute(ctx context.Context, auth *Auth, req cliproxyexecutor.Request, opts cliproxyexecutor.Options) (cliproxyexecutor.Response, error) {
|
|
return cliproxyexecutor.Response{}, nil
|
|
}
|
|
|
|
func (e schedulerProviderTestExecutor) ExecuteStream(ctx context.Context, auth *Auth, req cliproxyexecutor.Request, opts cliproxyexecutor.Options) (*cliproxyexecutor.StreamResult, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (e schedulerProviderTestExecutor) Refresh(ctx context.Context, auth *Auth) (*Auth, error) {
|
|
return auth, nil
|
|
}
|
|
|
|
func (e schedulerProviderTestExecutor) CountTokens(ctx context.Context, auth *Auth, req cliproxyexecutor.Request, opts cliproxyexecutor.Options) (cliproxyexecutor.Response, error) {
|
|
return cliproxyexecutor.Response{}, nil
|
|
}
|
|
|
|
func (e schedulerProviderTestExecutor) HttpRequest(ctx context.Context, auth *Auth, req *http.Request) (*http.Response, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func TestManager_RefreshSchedulerEntry_RebuildsSupportedModelSetAfterModelRegistration(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
testCases := []struct {
|
|
name string
|
|
prime func(*Manager, *Auth) error
|
|
}{
|
|
{
|
|
name: "register",
|
|
prime: func(manager *Manager, auth *Auth) error {
|
|
_, errRegister := manager.Register(ctx, auth)
|
|
return errRegister
|
|
},
|
|
},
|
|
{
|
|
name: "update",
|
|
prime: func(manager *Manager, auth *Auth) error {
|
|
_, errRegister := manager.Register(ctx, auth)
|
|
if errRegister != nil {
|
|
return errRegister
|
|
}
|
|
updated := auth.Clone()
|
|
updated.Metadata = map[string]any{"updated": true}
|
|
_, errUpdate := manager.Update(ctx, updated)
|
|
return errUpdate
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, testCase := range testCases {
|
|
testCase := testCase
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
manager := NewManager(nil, &RoundRobinSelector{}, nil)
|
|
auth := &Auth{
|
|
ID: "refresh-entry-" + testCase.name,
|
|
Provider: "gemini",
|
|
}
|
|
if errPrime := testCase.prime(manager, auth); errPrime != nil {
|
|
t.Fatalf("prime auth %s: %v", testCase.name, errPrime)
|
|
}
|
|
|
|
registerSchedulerModels(t, "gemini", "scheduler-refresh-model", auth.ID)
|
|
|
|
got, errPick := manager.scheduler.pickSingle(ctx, "gemini", "scheduler-refresh-model", cliproxyexecutor.Options{}, nil)
|
|
var authErr *Error
|
|
if !errors.As(errPick, &authErr) || authErr == nil {
|
|
t.Fatalf("pickSingle() before refresh error = %v, want auth_not_found", errPick)
|
|
}
|
|
if authErr.Code != "auth_not_found" {
|
|
t.Fatalf("pickSingle() before refresh code = %q, want %q", authErr.Code, "auth_not_found")
|
|
}
|
|
if got != nil {
|
|
t.Fatalf("pickSingle() before refresh auth = %v, want nil", got)
|
|
}
|
|
|
|
manager.RefreshSchedulerEntry(auth.ID)
|
|
|
|
got, errPick = manager.scheduler.pickSingle(ctx, "gemini", "scheduler-refresh-model", cliproxyexecutor.Options{}, nil)
|
|
if errPick != nil {
|
|
t.Fatalf("pickSingle() after refresh error = %v", errPick)
|
|
}
|
|
if got == nil || got.ID != auth.ID {
|
|
t.Fatalf("pickSingle() after refresh auth = %v, want %q", got, auth.ID)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestManager_PickNext_RebuildsSchedulerAfterModelCooldownError(t *testing.T) {
|
|
ctx := context.Background()
|
|
manager := NewManager(nil, &RoundRobinSelector{}, nil)
|
|
manager.RegisterExecutor(schedulerProviderTestExecutor{provider: "gemini"})
|
|
|
|
registerSchedulerModels(t, "gemini", "scheduler-cooldown-rebuild-model", "cooldown-stale-old")
|
|
|
|
oldAuth := &Auth{
|
|
ID: "cooldown-stale-old",
|
|
Provider: "gemini",
|
|
}
|
|
if _, errRegister := manager.Register(ctx, oldAuth); errRegister != nil {
|
|
t.Fatalf("register old auth: %v", errRegister)
|
|
}
|
|
|
|
manager.MarkResult(ctx, Result{
|
|
AuthID: oldAuth.ID,
|
|
Provider: "gemini",
|
|
Model: "scheduler-cooldown-rebuild-model",
|
|
Success: false,
|
|
Error: &Error{HTTPStatus: http.StatusTooManyRequests, Message: "quota"},
|
|
})
|
|
|
|
newAuth := &Auth{
|
|
ID: "cooldown-stale-new",
|
|
Provider: "gemini",
|
|
}
|
|
if _, errRegister := manager.Register(ctx, newAuth); errRegister != nil {
|
|
t.Fatalf("register new auth: %v", errRegister)
|
|
}
|
|
|
|
reg := registry.GetGlobalRegistry()
|
|
reg.RegisterClient(newAuth.ID, "gemini", []*registry.ModelInfo{{ID: "scheduler-cooldown-rebuild-model"}})
|
|
t.Cleanup(func() {
|
|
reg.UnregisterClient(newAuth.ID)
|
|
})
|
|
|
|
got, errPick := manager.scheduler.pickSingle(ctx, "gemini", "scheduler-cooldown-rebuild-model", cliproxyexecutor.Options{}, nil)
|
|
var cooldownErr *modelCooldownError
|
|
if !errors.As(errPick, &cooldownErr) {
|
|
t.Fatalf("pickSingle() before sync error = %v, want modelCooldownError", errPick)
|
|
}
|
|
if got != nil {
|
|
t.Fatalf("pickSingle() before sync auth = %v, want nil", got)
|
|
}
|
|
|
|
got, executor, errPick := manager.pickNext(ctx, "gemini", "scheduler-cooldown-rebuild-model", cliproxyexecutor.Options{}, nil)
|
|
if errPick != nil {
|
|
t.Fatalf("pickNext() error = %v", errPick)
|
|
}
|
|
if executor == nil {
|
|
t.Fatal("pickNext() executor = nil")
|
|
}
|
|
if got == nil || got.ID != newAuth.ID {
|
|
t.Fatalf("pickNext() auth = %v, want %q", got, newAuth.ID)
|
|
}
|
|
}
|