295 lines · 9.9 KB · Go
RawDownload
package pluginapi import (	"context"	"encoding/json"	"strings"	"testing") type compileTimePlugin struct{} var _ ModelRegistrar = (*compileTimePlugin)(nil)var _ ModelProvider = (*compileTimePlugin)(nil)var _ AuthProvider = (*compileTimePlugin)(nil)var _ FrontendAuthProvider = (*compileTimePlugin)(nil)var _ Scheduler = (*compileTimePlugin)(nil)var _ ProviderExecutor = (*compileTimePlugin)(nil)var _ HostHTTPClient = (*compileTimePlugin)(nil)var _ RequestTranslator = (*compileTimePlugin)(nil)var _ RequestNormalizer = (*compileTimePlugin)(nil)var _ ResponseTranslator = (*compileTimePlugin)(nil)var _ ResponseNormalizer = (*compileTimePlugin)(nil)var _ RequestInterceptor = (*compileTimePlugin)(nil)var _ ResponseInterceptor = (*compileTimePlugin)(nil)var _ StreamChunkInterceptor = (*compileTimePlugin)(nil)var _ ThinkingApplier = (*compileTimePlugin)(nil)var _ UsagePlugin = (*compileTimePlugin)(nil)var _ CommandLinePlugin = (*compileTimePlugin)(nil)var _ ManagementAPI = (*compileTimePlugin)(nil)var _ ManagementHandler = (*compileTimePlugin)(nil) func TestMetadataConfigFieldsExposePluginSchema(t *testing.T) {	meta := Metadata{		Name:             "example",		Version:          "1.0.0",		Author:           "test",		GitHubRepository: "https://github.com/router-for-me/CLIProxyAPI",		Logo:             "https://example.com/logo.svg",		ConfigFields: []ConfigField{{			Name:        "mode",			Type:        ConfigFieldTypeEnum,			EnumValues:  []string{"safe", "fast"},			Description: "Execution mode.",		}},	}	if meta.Logo == "" || len(meta.ConfigFields) != 1 {		t.Fatalf("metadata missing logo or config fields: %#v", meta)	}} func TestResourceRouteMenuFieldsExposeManagementUIHints(t *testing.T) {	route := ResourceRoute{		Path:        "/status",		Menu:        "Example Status",		Description: "Shows example plugin status.",		Handler:     compileTimePlugin{},	}	if route.Menu == "" || route.Description == "" {		t.Fatalf("resource route missing menu fields: %#v", route)	}} func TestHostInjectedHTTPClientIsNotEncodedInPluginJSON(t *testing.T) {	requests := []struct {		name string		req  any		dst  any	}{		{			name: "auth login start",			req:  AuthLoginStartRequest{Provider: "plugin-example", HTTPClient: compileTimePlugin{}},			dst:  &AuthLoginStartRequest{},		},		{			name: "auth login poll",			req:  AuthLoginPollRequest{Provider: "plugin-example", HTTPClient: compileTimePlugin{}},			dst:  &AuthLoginPollRequest{},		},		{			name: "auth refresh",			req:  AuthRefreshRequest{AuthID: "auth-1", HTTPClient: compileTimePlugin{}},			dst:  &AuthRefreshRequest{},		},		{			name: "auth model",			req:  AuthModelRequest{AuthID: "auth-1", HTTPClient: compileTimePlugin{}},			dst:  &AuthModelRequest{},		},		{			name: "executor request",			req:  ExecutorRequest{Model: "model-1", HTTPClient: compileTimePlugin{}},			dst:  &ExecutorRequest{},		},		{			name: "executor http request",			req:  ExecutorHTTPRequest{AuthID: "auth-1", HTTPClient: compileTimePlugin{}},			dst:  &ExecutorHTTPRequest{},		},	} 	for _, tt := range requests {		raw, errMarshal := json.Marshal(tt.req)		if errMarshal != nil {			t.Fatalf("%s marshal error = %v", tt.name, errMarshal)		}		if strings.Contains(string(raw), "HTTPClient") {			t.Fatalf("%s JSON contains host HTTPClient: %s", tt.name, raw)		}		withLegacyHTTPClient := append(raw[:len(raw)-1], []byte(`,"HTTPClient":{}}`)...)		if errUnmarshal := json.Unmarshal(withLegacyHTTPClient, tt.dst); errUnmarshal != nil {			t.Fatalf("%s unmarshal with legacy HTTPClient object error = %v", tt.name, errUnmarshal)		}	}} func TestSchedulerTypesExposeRoutingFields(t *testing.T) {	request := SchedulerPickRequest{		Plugin:    Metadata{Name: "scheduler-plugin"},		Provider:  "openai",		Providers: []string{"openai", "gemini"},		Model:     "gpt-test",		Stream:    true,		Options: SchedulerOptions{			Headers:  map[string][]string{"X-Test": []string{"1"}},			Metadata: map[string]any{"tenant": "demo"},		},		Candidates: []SchedulerAuthCandidate{{			ID:         "auth-1",			Provider:   "openai",			Priority:   10,			Status:     "ready",			Attributes: map[string]string{"region": "us"},			Metadata:   map[string]any{"load": float64(0.5)},		}},	}	response := SchedulerPickResponse{		AuthID:          request.Candidates[0].ID,		DelegateBuiltin: SchedulerBuiltinRoundRobin,		Handled:         true,	} 	if request.Plugin.Name != "scheduler-plugin" {		t.Fatalf("Plugin.Name = %q", request.Plugin.Name)	}	if request.Provider != "openai" {		t.Fatalf("Provider = %q", request.Provider)	}	if len(request.Providers) != 2 || request.Providers[1] != "gemini" {		t.Fatalf("Providers = %#v", request.Providers)	}	if request.Model != "gpt-test" {		t.Fatalf("Model = %q", request.Model)	}	if !request.Stream {		t.Fatalf("Stream = %v", request.Stream)	}	if got := request.Options.Headers["X-Test"]; len(got) != 1 || got[0] != "1" {		t.Fatalf("Options.Headers = %#v", request.Options.Headers)	}	if request.Options.Metadata["tenant"] != "demo" {		t.Fatalf("Options.Metadata = %#v", request.Options.Metadata)	}	if len(request.Candidates) != 1 {		t.Fatalf("Candidates = %#v", request.Candidates)	}	candidate := request.Candidates[0]	if candidate.ID != "auth-1" || candidate.Provider != "openai" || candidate.Priority != 10 || candidate.Status != "ready" {		t.Fatalf("Candidate = %#v", candidate)	}	if candidate.Attributes["region"] != "us" {		t.Fatalf("Candidate.Attributes = %#v", candidate.Attributes)	}	if candidate.Metadata["load"] != float64(0.5) {		t.Fatalf("Candidate.Metadata = %#v", candidate.Metadata)	}	if response.AuthID != "auth-1" || response.DelegateBuiltin != SchedulerBuiltinRoundRobin || !response.Handled {		t.Fatalf("SchedulerPickResponse = %#v", response)	}} func (compileTimePlugin) RegisterModels(context.Context, ModelRegistrationRequest) (ModelRegistrationResponse, error) {	return ModelRegistrationResponse{}, nil} func (compileTimePlugin) StaticModels(context.Context, StaticModelRequest) (ModelResponse, error) {	return ModelResponse{}, nil} func (compileTimePlugin) ModelsForAuth(context.Context, AuthModelRequest) (ModelResponse, error) {	return ModelResponse{}, nil} func (compileTimePlugin) Identifier() string { return "compile-time" } func (compileTimePlugin) ParseAuth(context.Context, AuthParseRequest) (AuthParseResponse, error) {	return AuthParseResponse{}, nil} func (compileTimePlugin) StartLogin(context.Context, AuthLoginStartRequest) (AuthLoginStartResponse, error) {	return AuthLoginStartResponse{}, nil} func (compileTimePlugin) PollLogin(context.Context, AuthLoginPollRequest) (AuthLoginPollResponse, error) {	return AuthLoginPollResponse{}, nil} func (compileTimePlugin) RefreshAuth(context.Context, AuthRefreshRequest) (AuthRefreshResponse, error) {	return AuthRefreshResponse{}, nil} func (compileTimePlugin) Authenticate(context.Context, FrontendAuthRequest) (FrontendAuthResponse, error) {	return FrontendAuthResponse{}, nil} func (compileTimePlugin) Pick(context.Context, SchedulerPickRequest) (SchedulerPickResponse, error) {	return SchedulerPickResponse{}, nil} func (compileTimePlugin) Execute(context.Context, ExecutorRequest) (ExecutorResponse, error) {	return ExecutorResponse{}, nil} func (compileTimePlugin) ExecuteStream(context.Context, ExecutorRequest) (ExecutorStreamResponse, error) {	return ExecutorStreamResponse{}, nil} func (compileTimePlugin) CountTokens(context.Context, ExecutorRequest) (ExecutorResponse, error) {	return ExecutorResponse{}, nil} func (compileTimePlugin) HttpRequest(context.Context, ExecutorHTTPRequest) (ExecutorHTTPResponse, error) {	return ExecutorHTTPResponse{}, nil} func (compileTimePlugin) Do(context.Context, HTTPRequest) (HTTPResponse, error) {	return HTTPResponse{}, nil} func (compileTimePlugin) DoStream(context.Context, HTTPRequest) (HTTPStreamResponse, error) {	return HTTPStreamResponse{}, nil} func (compileTimePlugin) TranslateRequest(context.Context, RequestTransformRequest) (PayloadResponse, error) {	return PayloadResponse{}, nil} func (compileTimePlugin) NormalizeRequest(context.Context, RequestTransformRequest) (PayloadResponse, error) {	return PayloadResponse{}, nil} func (compileTimePlugin) TranslateResponse(context.Context, ResponseTransformRequest) (PayloadResponse, error) {	return PayloadResponse{}, nil} func (compileTimePlugin) NormalizeResponse(context.Context, ResponseTransformRequest) (PayloadResponse, error) {	return PayloadResponse{}, nil} func (compileTimePlugin) InterceptRequestBeforeAuth(context.Context, RequestInterceptRequest) (RequestInterceptResponse, error) {	return RequestInterceptResponse{}, nil} func (compileTimePlugin) InterceptRequestAfterAuth(context.Context, RequestInterceptRequest) (RequestInterceptResponse, error) {	return RequestInterceptResponse{}, nil} func (compileTimePlugin) InterceptResponse(context.Context, ResponseInterceptRequest) (ResponseInterceptResponse, error) {	return ResponseInterceptResponse{}, nil} func (compileTimePlugin) InterceptStreamChunk(context.Context, StreamChunkInterceptRequest) (StreamChunkInterceptResponse, error) {	return StreamChunkInterceptResponse{}, nil} func (compileTimePlugin) ApplyThinking(context.Context, ThinkingApplyRequest) (PayloadResponse, error) {	return PayloadResponse{}, nil} func (compileTimePlugin) HandleUsage(context.Context, UsageRecord) {} func (compileTimePlugin) RegisterCommandLine(context.Context, CommandLineRegistrationRequest) (CommandLineRegistrationResponse, error) {	return CommandLineRegistrationResponse{}, nil} func (compileTimePlugin) ExecuteCommandLine(context.Context, CommandLineExecutionRequest) (CommandLineExecutionResponse, error) {	return CommandLineExecutionResponse{}, nil} func (compileTimePlugin) RegisterManagement(context.Context, ManagementRegistrationRequest) (ManagementRegistrationResponse, error) {	return ManagementRegistrationResponse{}, nil} func (compileTimePlugin) HandleManagement(context.Context, ManagementRequest) (ManagementResponse, error) {	return ManagementResponse{}, nil}