Ctrl K
ComunidadGuías…

internal/pluginhost/plugin_refresh_compat_executor_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package pluginhost

import (
	"context"
	"net/http"
	"strings"
	"testing"

	"github.com/router-for-me/CLIProxyAPI/v8/internal/config"
	runtimeexecutor "github.com/router-for-me/CLIProxyAPI/v8/internal/runtime/executor"
	coreauth "github.com/router-for-me/CLIProxyAPI/v8/sdk/cliproxy/auth"
	cliproxyexecutor "github.com/router-for-me/CLIProxyAPI/v8/sdk/cliproxy/executor"
	"github.com/router-for-me/CLIProxyAPI/v8/sdk/pluginapi"
)

type stubCompatExecutor struct {
	id           string
	executeCalls int
	refreshCalls int
}

func (e *stubCompatExecutor) Identifier() string { return e.id }

func (e *stubCompatExecutor) Execute(context.Context, *coreauth.Auth, cliproxyexecutor.Request, cliproxyexecutor.Options) (cliproxyexecutor.Response, error) {
	e.executeCalls++
	return cliproxyexecutor.Response{Payload: []byte(`{"ok":true}`)}, nil
}

func (e *stubCompatExecutor) ExecuteStream(context.Context, *coreauth.Auth, cliproxyexecutor.Request, cliproxyexecutor.Options) (*cliproxyexecutor.StreamResult, error) {
	return &cliproxyexecutor.StreamResult{}, nil
}

func (e *stubCompatExecutor) Refresh(_ context.Context, auth *coreauth.Auth) (*coreauth.Auth, error) {
	e.refreshCalls++
	return auth, nil
}

func (e *stubCompatExecutor) CountTokens(context.Context, *coreauth.Auth, cliproxyexecutor.Request, cliproxyexecutor.Options) (cliproxyexecutor.Response, error) {
	return cliproxyexecutor.Response{}, nil
}

func (e *stubCompatExecutor) HttpRequest(context.Context, *coreauth.Auth, *http.Request) (*http.Response, error) {
	return nil, nil
}

func (e *stubCompatExecutor) PrepareRequest(*http.Request, *coreauth.Auth) error {
	return nil
}

func TestPluginRefreshCompatExecutorDelegatesExecuteAndRefresh(t *testing.T) {
	refreshCalls := 0
	host := newHostWithRecords(capabilityRecord{
		id: "auth-plugin",
		plugin: pluginapi.Plugin{
			Capabilities: pluginapi.Capabilities{
				AuthProvider: fakeAuthProvider{
					identifier: "plugin-provider",
					refreshAuth: func(ctx context.Context, req pluginapi.AuthRefreshRequest) (pluginapi.AuthRefreshResponse, error) {
						refreshCalls++
						if req.AuthID != "auth-1" || req.AuthProvider != "plugin-provider" {
							t.Fatalf("RefreshAuth request = %#v", req)
						}
						return pluginapi.AuthRefreshResponse{
							Auth: pluginapi.AuthData{
								ID:       "auth-1",
								Provider: "plugin-provider",
								Metadata: map[string]any{
									"access_token":  "new-token",
									"refresh_token": "refresh-1",
								},
								Attributes: map[string]string{
									"base_url": "https://compat.example.com/v1",
								},
							},
						}, nil
					},
				},
			},
		},
	})

	inner := &stubCompatExecutor{id: "plugin-provider"}
	wrapped := NewPluginRefreshCompatExecutor(inner, host, &config.Config{})
	if wrapped == nil {
		t.Fatal("NewPluginRefreshCompatExecutor() = nil")
	}
	if !IsPluginRefreshCompatExecutor(wrapped) {
		t.Fatal("IsPluginRefreshCompatExecutor() = false, want true")
	}
	if got, ok := UnwrapPluginRefreshCompatExecutor(wrapped); !ok || got != inner {
		t.Fatalf("UnwrapPluginRefreshCompatExecutor() = (%T, %v), want inner", got, ok)
	}
	if wrapped.Identifier() != "plugin-provider" {
		t.Fatalf("Identifier() = %q, want plugin-provider", wrapped.Identifier())
	}

	auth := &coreauth.Auth{
		ID:       "auth-1",
		Provider: "plugin-provider",
		Metadata: map[string]any{
			"access_token":  "old-token",
			"refresh_token": "refresh-1",
		},
		Attributes: map[string]string{
			"base_url": "https://compat.example.com/v1",
		},
	}

	if _, errExecute := wrapped.Execute(context.Background(), auth, cliproxyexecutor.Request{}, cliproxyexecutor.Options{}); errExecute != nil {
		t.Fatalf("Execute() error = %v", errExecute)
	}
	if inner.executeCalls != 1 {
		t.Fatalf("inner Execute calls = %d, want 1", inner.executeCalls)
	}

	refreshed, errRefresh := wrapped.Refresh(context.Background(), auth)
	if errRefresh != nil {
		t.Fatalf("Refresh() error = %v", errRefresh)
	}
	if refreshCalls != 1 {
		t.Fatalf("plugin RefreshAuth calls = %d, want 1", refreshCalls)
	}
	if inner.refreshCalls != 0 {
		t.Fatalf("inner Refresh calls = %d, want 0", inner.refreshCalls)
	}
	if refreshed == nil || refreshed.Metadata["access_token"] != "new-token" {
		t.Fatalf("Refresh() auth = %#v, want updated access_token", refreshed)
	}
	if refreshed.Attributes["base_url"] != "https://compat.example.com/v1" {
		t.Fatalf("Refresh() base_url = %q, want preserved", refreshed.Attributes["base_url"])
	}
}

func TestPluginRefreshCompatExecutorErrorsWhenRefreshUnavailable(t *testing.T) {
	inner := &stubCompatExecutor{id: "plugin-provider"}
	wrapped := NewPluginRefreshCompatExecutor(inner, New(), &config.Config{})
	auth := &coreauth.Auth{
		ID:       "auth-1",
		Provider: "plugin-provider",
		Metadata: map[string]any{
			"access_token":  "old-token",
			"refresh_token": "refresh-1",
		},
	}

	_, errRefresh := wrapped.Refresh(context.Background(), auth)
	if errRefresh == nil {
		t.Fatal("Refresh() error = nil, want unavailable plugin refresh error")
	}
	if !strings.Contains(errRefresh.Error(), "plugin auth provider refresh is unavailable") {
		t.Fatalf("Refresh() error = %v, want unavailable message", errRefresh)
	}
	if inner.refreshCalls != 0 {
		t.Fatalf("inner Refresh calls = %d, want 0", inner.refreshCalls)
	}
}

func TestPluginRefreshCompatExecutorNoOpForAPIKeyAuth(t *testing.T) {
	inner := &stubCompatExecutor{id: "plugin-provider"}
	wrapped := NewPluginRefreshCompatExecutor(inner, New(), &config.Config{})
	auth := &coreauth.Auth{
		ID:       "auth-1",
		Provider: "plugin-provider",
		Attributes: map[string]string{
			"api_key":  "sk-test",
			"base_url": "https://compat.example.com/v1",
		},
	}

	refreshed, errRefresh := wrapped.Refresh(context.Background(), auth)
	if errRefresh != nil {
		t.Fatalf("Refresh() error = %v", errRefresh)
	}
	if refreshed == nil || refreshed.Attributes["api_key"] != "sk-test" {
		t.Fatalf("Refresh() auth = %#v, want unchanged api key auth", refreshed)
	}
}

type patchCompatExecutor struct {
	*stubCompatExecutor
	supported bool
}

func (e *patchCompatExecutor) SupportsApplyPatch() bool { return e.supported }

func TestPluginRefreshApplyPatchOptionalDelegation(t *testing.T) {
	for _, tc := range []struct {
		inner coreauth.ProviderExecutor
		want  bool
	}{
		{&stubCompatExecutor{id: "codex"}, false},
		{runtimeexecutor.NewOpenAICompatExecutor("arbitrary-plugin-name", &config.Config{}), true},
		{&patchCompatExecutor{&stubCompatExecutor{id: "custom"}, true}, true},
		{&patchCompatExecutor{&stubCompatExecutor{id: "custom"}, false}, false},
	} {
		wrapped := NewPluginRefreshCompatExecutor(tc.inner, nil, nil)
		support, okSupport := wrapped.(coreauth.ApplyPatchSupport)
		if !okSupport || support.SupportsApplyPatch() != tc.want {
			t.Errorf("%T: capability mismatch", tc.inner)
		}
		scoped := wrapped.(coreauth.APIKeyConfigExecutor).ForAPIKey()
		if scoped.(coreauth.ApplyPatchSupport).SupportsApplyPatch() != tc.want {
			t.Fatal("ForAPIKey lost inner capability")
		}
	}
	if (&pluginRefreshCompatExecutor{}).SupportsApplyPatch() {
		t.Fatal("empty wrapper advertised support")
	}
}