mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-06-22 23:36:11 +08:00
- Added a Go scheduler plugin demonstrating CLIProxyAPI capabilities, such as `plugin.register`, `plugin.reconfigure`, and `scheduler.pick`. - Implemented methods for plugin configuration, built-in scheduler delegation (`fill-first`, `round-robin`), dynamic candidate selection, and error handling. - Extended `pluginhost` with scheduler handling, candidate normalization, and fallback mechanisms. - Included examples, tests, and detailed documentation for scheduler usage and implementation.
88 lines
2.4 KiB
Go
88 lines
2.4 KiB
Go
package cliproxy
|
|
|
|
import (
|
|
"context"
|
|
"reflect"
|
|
"testing"
|
|
"unsafe"
|
|
|
|
"github.com/router-for-me/CLIProxyAPI/v7/internal/pluginhost"
|
|
coreauth "github.com/router-for-me/CLIProxyAPI/v7/sdk/cliproxy/auth"
|
|
"github.com/router-for-me/CLIProxyAPI/v7/sdk/config"
|
|
)
|
|
|
|
func TestBuilderBuildInjectsPluginHostScheduler(t *testing.T) {
|
|
host := pluginhost.New()
|
|
service, errBuild := NewBuilder().
|
|
WithConfig(&config.Config{AuthDir: t.TempDir()}).
|
|
WithConfigPath(t.TempDir() + "/config.yaml").
|
|
WithPluginHost(host).
|
|
Build()
|
|
if errBuild != nil {
|
|
t.Fatalf("Build() error = %v", errBuild)
|
|
}
|
|
|
|
got := pluginSchedulerFromManager(t, service.coreManager)
|
|
if got != host {
|
|
t.Fatalf("plugin scheduler = %p, want host %p", got, host)
|
|
}
|
|
}
|
|
|
|
func TestServiceSyncPluginRuntimeConfigInjectsPluginHostScheduler(t *testing.T) {
|
|
host := pluginhost.New()
|
|
service := &Service{
|
|
cfg: &config.Config{},
|
|
coreManager: coreauth.NewManager(nil, nil, nil),
|
|
pluginHost: host,
|
|
}
|
|
|
|
if ok := service.syncPluginRuntimeConfig(context.Background()); !ok {
|
|
t.Fatal("syncPluginRuntimeConfig() = false, want true")
|
|
}
|
|
|
|
got := pluginSchedulerFromManager(t, service.coreManager)
|
|
if got != host {
|
|
t.Fatalf("plugin scheduler = %p, want host %p", got, host)
|
|
}
|
|
}
|
|
|
|
func TestServiceSyncPluginRuntimeConfigClearsPluginSchedulerWithoutHost(t *testing.T) {
|
|
host := pluginhost.New()
|
|
service := &Service{
|
|
cfg: &config.Config{},
|
|
coreManager: coreauth.NewManager(nil, nil, nil),
|
|
pluginHost: host,
|
|
}
|
|
service.coreManager.SetPluginScheduler(host)
|
|
service.pluginHost = nil
|
|
|
|
if ok := service.syncPluginRuntimeConfig(context.Background()); ok {
|
|
t.Fatal("syncPluginRuntimeConfig() = true, want false")
|
|
}
|
|
|
|
got := pluginSchedulerFromManager(t, service.coreManager)
|
|
if got != nil {
|
|
t.Fatalf("plugin scheduler = %p, want nil", got)
|
|
}
|
|
}
|
|
|
|
func pluginSchedulerFromManager(t *testing.T, manager *coreauth.Manager) *pluginhost.Host {
|
|
t.Helper()
|
|
if manager == nil {
|
|
t.Fatal("manager = nil")
|
|
}
|
|
value := reflect.ValueOf(manager).Elem().FieldByName("pluginScheduler")
|
|
if !value.IsValid() {
|
|
t.Fatal("pluginScheduler field not found")
|
|
}
|
|
scheduler := reflect.NewAt(value.Type(), unsafe.Pointer(value.UnsafeAddr())).Elem().Interface()
|
|
if scheduler == nil {
|
|
return nil
|
|
}
|
|
host, ok := scheduler.(*pluginhost.Host)
|
|
if !ok {
|
|
t.Fatalf("pluginScheduler type = %T, want *pluginhost.Host", scheduler)
|
|
}
|
|
return host
|
|
}
|