package cliproxy import ( "context" "testing" "github.com/router-for-me/CLIProxyAPI/v7/internal/pluginhost" "github.com/router-for-me/CLIProxyAPI/v7/internal/runtime/executor" "github.com/router-for-me/CLIProxyAPI/v7/internal/watcher" sdkAuth "github.com/router-for-me/CLIProxyAPI/v7/sdk/auth" coreauth "github.com/router-for-me/CLIProxyAPI/v7/sdk/cliproxy/auth" "github.com/router-for-me/CLIProxyAPI/v7/sdk/config" sdktranslator "github.com/router-for-me/CLIProxyAPI/v7/sdk/translator") func TestEnsureExecutorsForAuth_CodexDoesNotReplaceInNormalMode(t *testing.T) { service := &Service{ cfg: &config.Config{}, coreManager: coreauth.NewManager(nil, nil, nil), } auth := &coreauth.Auth{ ID: "codex-auth-1", Provider: "codex", Status: coreauth.StatusActive, } service.ensureExecutorsForAuth(auth) firstExecutor, okFirst := service.coreManager.Executor("codex") if !okFirst || firstExecutor == nil { t.Fatal("expected codex executor after first bind") } service.ensureExecutorsForAuth(auth) secondExecutor, okSecond := service.coreManager.Executor("codex") if !okSecond || secondExecutor == nil { t.Fatal("expected codex executor after second bind") } if firstExecutor != secondExecutor { t.Fatal("expected codex executor to stay unchanged in normal mode") }} func TestEnsureExecutorsForAuthWithMode_CodexForceReplace(t *testing.T) { service := &Service{ cfg: &config.Config{}, coreManager: coreauth.NewManager(nil, nil, nil), } auth := &coreauth.Auth{ ID: "codex-auth-2", Provider: "codex", Status: coreauth.StatusActive, } service.ensureExecutorsForAuth(auth) firstExecutor, okFirst := service.coreManager.Executor("codex") if !okFirst || firstExecutor == nil { t.Fatal("expected codex executor after first bind") } service.ensureExecutorsForAuthWithMode(auth, true) secondExecutor, okSecond := service.coreManager.Executor("codex") if !okSecond || secondExecutor == nil { t.Fatal("expected codex executor after forced rebind") } if firstExecutor == secondExecutor { t.Fatal("expected codex executor replacement in force mode") }} func TestSyncPluginModelRuntime_UnrelatedAuthDoesNotReplaceWebsocketExecutor(t *testing.T) { testCases := []struct { name string provider string homeEnabled bool }{ {name: "codex standard mode", provider: "codex"}, {name: "codex home mode", provider: "codex", homeEnabled: true}, {name: "xai standard mode", provider: "xai"}, {name: "xai home mode", provider: "xai", homeEnabled: true}, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { ctx := context.Background() cfg := &config.Config{} cfg.Home.Enabled = tt.homeEnabled service := &Service{ cfg: cfg, coreManager: coreauth.NewManager(nil, nil, nil), pluginHost: pluginhost.New(), } providerAuth := &coreauth.Auth{ ID: tt.provider + "-auth", Provider: tt.provider, Status: coreauth.StatusActive, } unrelatedAuth := &coreauth.Auth{ ID: "unrelated-auth", Provider: "claude", Status: coreauth.StatusActive, } t.Cleanup(func() { GlobalModelRegistry().UnregisterClient(providerAuth.ID) GlobalModelRegistry().UnregisterClient(unrelatedAuth.ID) sdkAuth.RegisterPluginAuthParser(nil) sdktranslator.SetPluginHooks(nil) }) if _, errRegister := service.coreManager.Register(ctx, providerAuth); errRegister != nil { t.Fatalf("register %s auth: %v", tt.provider, errRegister) } if _, errRegister := service.coreManager.Register(ctx, unrelatedAuth); errRegister != nil { t.Fatalf("register unrelated auth: %v", errRegister) } service.ensureExecutorsForAuth(providerAuth) firstExecutor, okFirst := service.coreManager.Executor(tt.provider) if !okFirst || firstExecutor == nil { t.Fatalf("expected %s executor before plugin model sync", tt.provider) } updatedAuth := unrelatedAuth.Clone() updatedAuth.Label = "updated unrelated auth" service.handleAuthUpdate(ctx, watcher.AuthUpdate{ Action: watcher.AuthUpdateActionModify, ID: updatedAuth.ID, Auth: updatedAuth, }) secondExecutor, okSecond := service.coreManager.Executor(tt.provider) if !okSecond || secondExecutor == nil { t.Fatalf("expected %s executor after plugin model sync", tt.provider) } if firstExecutor != secondExecutor { t.Fatalf("expected unrelated auth sync to preserve the %s executor", tt.provider) } }) }} func TestEnsureExecutorsForAuth_XAIDoesNotReplaceInNormalMode(t *testing.T) { service := &Service{ cfg: &config.Config{}, coreManager: coreauth.NewManager(nil, nil, nil), } auth := &coreauth.Auth{ ID: "xai-auth-1", Provider: "xai", Status: coreauth.StatusActive, } service.ensureExecutorsForAuth(auth) firstExecutor, okFirst := service.coreManager.Executor("xai") if !okFirst || firstExecutor == nil { t.Fatal("expected xai executor after first bind") } if _, isXAIAutoExecutor := firstExecutor.(*executor.XAIAutoExecutor); !isXAIAutoExecutor { t.Fatalf("xai executor type = %T, want *executor.XAIAutoExecutor", firstExecutor) } service.ensureExecutorsForAuth(auth) secondExecutor, okSecond := service.coreManager.Executor("xai") if !okSecond || secondExecutor == nil { t.Fatal("expected xai executor after second bind") } if firstExecutor != secondExecutor { t.Fatal("expected xai executor to stay unchanged in normal mode") }} func TestEnsureExecutorsForAuthWithMode_XAIForceReplace(t *testing.T) { service := &Service{ cfg: &config.Config{}, coreManager: coreauth.NewManager(nil, nil, nil), } auth := &coreauth.Auth{ ID: "xai-auth-2", Provider: "xai", Status: coreauth.StatusActive, } service.ensureExecutorsForAuth(auth) firstExecutor, okFirst := service.coreManager.Executor("xai") if !okFirst || firstExecutor == nil { t.Fatal("expected xai executor after first bind") } service.ensureExecutorsForAuthWithMode(auth, true) secondExecutor, okSecond := service.coreManager.Executor("xai") if !okSecond || secondExecutor == nil { t.Fatal("expected xai executor after forced rebind") } if firstExecutor == secondExecutor { t.Fatal("expected xai executor replacement in force mode") } if _, isXAIAutoExecutor := secondExecutor.(*executor.XAIAutoExecutor); !isXAIAutoExecutor { t.Fatalf("xai executor type = %T, want *executor.XAIAutoExecutor", secondExecutor) }} func TestEnsureExecutorsForAuth_XAIReplacesExecutorAfterConfigUpdate(t *testing.T) { service := &Service{ cfg: &config.Config{}, coreManager: coreauth.NewManager(nil, nil, nil), pluginHost: pluginhost.New(), } t.Cleanup(func() { sdkAuth.RegisterPluginAuthParser(nil) sdktranslator.SetPluginHooks(nil) }) auth := &coreauth.Auth{ ID: "xai-auth-config-update", Provider: "xai", Status: coreauth.StatusActive, } service.ensureExecutorsForAuth(auth) firstExecutor, okFirst := service.coreManager.Executor("xai") if !okFirst || firstExecutor == nil { t.Fatal("expected xai executor before config update") } service.applyWatcherConfigUpdate(&config.Config{}) service.ensureExecutorsForAuth(auth) secondExecutor, okSecond := service.coreManager.Executor("xai") if !okSecond || secondExecutor == nil { t.Fatal("expected xai executor after config update") } if firstExecutor == secondExecutor { t.Fatal("expected stale xai executor replacement after config update") } if _, isXAIAutoExecutor := secondExecutor.(*executor.XAIAutoExecutor); !isXAIAutoExecutor { t.Fatalf("xai executor type = %T, want *executor.XAIAutoExecutor", secondExecutor) }}
package cliproxy
import (
"context"
"testing"
"github.com/router-for-me/CLIProxyAPI/v7/internal/pluginhost"
"github.com/router-for-me/CLIProxyAPI/v7/internal/runtime/executor"
"github.com/router-for-me/CLIProxyAPI/v7/internal/watcher"
sdkAuth "github.com/router-for-me/CLIProxyAPI/v7/sdk/auth"
coreauth "github.com/router-for-me/CLIProxyAPI/v7/sdk/cliproxy/auth"
"github.com/router-for-me/CLIProxyAPI/v7/sdk/config"
sdktranslator "github.com/router-for-me/CLIProxyAPI/v7/sdk/translator"
)
func TestEnsureExecutorsForAuth_CodexDoesNotReplaceInNormalMode(t *testing.T) {
service := &Service{
cfg: &config.Config{},
coreManager: coreauth.NewManager(nil, nil, nil),
}
auth := &coreauth.Auth{
ID: "codex-auth-1",
Provider: "codex",
Status: coreauth.StatusActive,
}
service.ensureExecutorsForAuth(auth)
firstExecutor, okFirst := service.coreManager.Executor("codex")
if !okFirst || firstExecutor == nil {
t.Fatal("expected codex executor after first bind")
}
service.ensureExecutorsForAuth(auth)
secondExecutor, okSecond := service.coreManager.Executor("codex")
if !okSecond || secondExecutor == nil {
t.Fatal("expected codex executor after second bind")
}
if firstExecutor != secondExecutor {
t.Fatal("expected codex executor to stay unchanged in normal mode")
}
}
func TestEnsureExecutorsForAuthWithMode_CodexForceReplace(t *testing.T) {
service := &Service{
cfg: &config.Config{},
coreManager: coreauth.NewManager(nil, nil, nil),
}
auth := &coreauth.Auth{
ID: "codex-auth-2",
Provider: "codex",
Status: coreauth.StatusActive,
}
service.ensureExecutorsForAuth(auth)
firstExecutor, okFirst := service.coreManager.Executor("codex")
if !okFirst || firstExecutor == nil {
t.Fatal("expected codex executor after first bind")
}
service.ensureExecutorsForAuthWithMode(auth, true)
secondExecutor, okSecond := service.coreManager.Executor("codex")
if !okSecond || secondExecutor == nil {
t.Fatal("expected codex executor after forced rebind")
}
if firstExecutor == secondExecutor {
t.Fatal("expected codex executor replacement in force mode")
}
}
func TestSyncPluginModelRuntime_UnrelatedAuthDoesNotReplaceWebsocketExecutor(t *testing.T) {
testCases := []struct {
name string
provider string
homeEnabled bool
}{
{name: "codex standard mode", provider: "codex"},
{name: "codex home mode", provider: "codex", homeEnabled: true},
{name: "xai standard mode", provider: "xai"},
{name: "xai home mode", provider: "xai", homeEnabled: true},
}
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
cfg := &config.Config{}
cfg.Home.Enabled = tt.homeEnabled
service := &Service{
cfg: cfg,
coreManager: coreauth.NewManager(nil, nil, nil),
pluginHost: pluginhost.New(),
}
providerAuth := &coreauth.Auth{
ID: tt.provider + "-auth",
Provider: tt.provider,
Status: coreauth.StatusActive,
}
unrelatedAuth := &coreauth.Auth{
ID: "unrelated-auth",
Provider: "claude",
Status: coreauth.StatusActive,
}
t.Cleanup(func() {
GlobalModelRegistry().UnregisterClient(providerAuth.ID)
GlobalModelRegistry().UnregisterClient(unrelatedAuth.ID)
sdkAuth.RegisterPluginAuthParser(nil)
sdktranslator.SetPluginHooks(nil)
})
if _, errRegister := service.coreManager.Register(ctx, providerAuth); errRegister != nil {
t.Fatalf("register %s auth: %v", tt.provider, errRegister)
}
if _, errRegister := service.coreManager.Register(ctx, unrelatedAuth); errRegister != nil {
t.Fatalf("register unrelated auth: %v", errRegister)
}
service.ensureExecutorsForAuth(providerAuth)
firstExecutor, okFirst := service.coreManager.Executor(tt.provider)
if !okFirst || firstExecutor == nil {
t.Fatalf("expected %s executor before plugin model sync", tt.provider)
}
updatedAuth := unrelatedAuth.Clone()
updatedAuth.Label = "updated unrelated auth"
service.handleAuthUpdate(ctx, watcher.AuthUpdate{
Action: watcher.AuthUpdateActionModify,
ID: updatedAuth.ID,
Auth: updatedAuth,
})
secondExecutor, okSecond := service.coreManager.Executor(tt.provider)
if !okSecond || secondExecutor == nil {
t.Fatalf("expected %s executor after plugin model sync", tt.provider)
}
if firstExecutor != secondExecutor {
t.Fatalf("expected unrelated auth sync to preserve the %s executor", tt.provider)
}
})
}
}
func TestEnsureExecutorsForAuth_XAIDoesNotReplaceInNormalMode(t *testing.T) {
service := &Service{
cfg: &config.Config{},
coreManager: coreauth.NewManager(nil, nil, nil),
}
auth := &coreauth.Auth{
ID: "xai-auth-1",
Provider: "xai",
Status: coreauth.StatusActive,
}
service.ensureExecutorsForAuth(auth)
firstExecutor, okFirst := service.coreManager.Executor("xai")
if !okFirst || firstExecutor == nil {
t.Fatal("expected xai executor after first bind")
}
if _, isXAIAutoExecutor := firstExecutor.(*executor.XAIAutoExecutor); !isXAIAutoExecutor {
t.Fatalf("xai executor type = %T, want *executor.XAIAutoExecutor", firstExecutor)
}
service.ensureExecutorsForAuth(auth)
secondExecutor, okSecond := service.coreManager.Executor("xai")
if !okSecond || secondExecutor == nil {
t.Fatal("expected xai executor after second bind")
}
if firstExecutor != secondExecutor {
t.Fatal("expected xai executor to stay unchanged in normal mode")
}
}
func TestEnsureExecutorsForAuthWithMode_XAIForceReplace(t *testing.T) {
service := &Service{
cfg: &config.Config{},
coreManager: coreauth.NewManager(nil, nil, nil),
}
auth := &coreauth.Auth{
ID: "xai-auth-2",
Provider: "xai",
Status: coreauth.StatusActive,
}
service.ensureExecutorsForAuth(auth)
firstExecutor, okFirst := service.coreManager.Executor("xai")
if !okFirst || firstExecutor == nil {
t.Fatal("expected xai executor after first bind")
}
service.ensureExecutorsForAuthWithMode(auth, true)
secondExecutor, okSecond := service.coreManager.Executor("xai")
if !okSecond || secondExecutor == nil {
t.Fatal("expected xai executor after forced rebind")
}
if firstExecutor == secondExecutor {
t.Fatal("expected xai executor replacement in force mode")
}
if _, isXAIAutoExecutor := secondExecutor.(*executor.XAIAutoExecutor); !isXAIAutoExecutor {
t.Fatalf("xai executor type = %T, want *executor.XAIAutoExecutor", secondExecutor)
}
}
func TestEnsureExecutorsForAuth_XAIReplacesExecutorAfterConfigUpdate(t *testing.T) {
service := &Service{
cfg: &config.Config{},
coreManager: coreauth.NewManager(nil, nil, nil),
pluginHost: pluginhost.New(),
}
t.Cleanup(func() {
sdkAuth.RegisterPluginAuthParser(nil)
sdktranslator.SetPluginHooks(nil)
})
auth := &coreauth.Auth{
ID: "xai-auth-config-update",
Provider: "xai",
Status: coreauth.StatusActive,
}
service.ensureExecutorsForAuth(auth)
firstExecutor, okFirst := service.coreManager.Executor("xai")
if !okFirst || firstExecutor == nil {
t.Fatal("expected xai executor before config update")
}
service.applyWatcherConfigUpdate(&config.Config{})
service.ensureExecutorsForAuth(auth)
secondExecutor, okSecond := service.coreManager.Executor("xai")
if !okSecond || secondExecutor == nil {
t.Fatal("expected xai executor after config update")
}
if firstExecutor == secondExecutor {
t.Fatal("expected stale xai executor replacement after config update")
}
if _, isXAIAutoExecutor := secondExecutor.(*executor.XAIAutoExecutor); !isXAIAutoExecutor {
t.Fatalf("xai executor type = %T, want *executor.XAIAutoExecutor", secondExecutor)
}
}