Files
CLIProxyAPI/sdk/cliproxy/service_plugin_scheduler_test.go
Luis Pater 693ce1c55a feat(pluginhost, scheduler): introduce Go-based plugin with scheduler capabilities
- 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.
2026-06-09 13:57:36 +08:00

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
}