internal/pluginhost/adapters_auth_body_slots_test.go
Rama main · réplica de lectura del repositorio original.
package pluginhost
import (
"bytes"
"context"
"net/http"
"net/http/httptest"
"testing"
"github.com/router-for-me/CLIProxyAPI/v8/internal/config"
)
// With every decode slot taken, a decoding request waits and gives up with its context.
func TestAccessAdapterDecodeWaitsForSlot(t *testing.T) {
saved := authDecodeSlots
authDecodeSlots = make(chan struct{}, 1)
authDecodeSlots <- struct{}{}
defer func() { authDecodeSlots = saved }()
ctx, cancel := context.WithCancel(context.Background())
cancel()
_, calls, _, authErr := authenticateWithBody(ctx, t, http.MethodPost, "/v1/responses", zstdCompress(t, []byte(`{"model":"gpt-5"}`)), "zstd", 0)
if authErr == nil || calls != 0 || len(authDecodeSlots) != 1 {
t.Fatalf("err %v, plugin calls %d, slots held %d", authErr, calls, len(authDecodeSlots))
}
}
// When a client cancels while a guarded RPC auth call is still running, the decode slot stays
// held until the underlying inner plugin call finishes.
func TestAccessAdapterCanceledRPCKeepsSlotUntilInnerCallFinishes(t *testing.T) {
saved := authDecodeSlots
authDecodeSlots = make(chan struct{}, 1)
defer func() { authDecodeSlots = saved }()
inner := &blockingGuardPluginClient{
started: make(chan struct{}),
release: make(chan struct{}),
}
guarded := newGuardedPluginClient(inner)
host := New()
host.runtimeConfig = &config.Config{}
adapter := newAccessAdapterForTest(host, "auth-plugin", rpcFrontendAuthProvider{
rpcPluginAdapter: &rpcPluginAdapter{
id: "auth-plugin",
host: host,
client: guarded,
},
})
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
compressed := zstdCompress(t, []byte(`{"model":"gpt-5"}`))
req := httptest.NewRequest(http.MethodPost, "/v1/responses", bytes.NewReader(compressed))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Content-Encoding", "zstd")
authDone := make(chan struct{})
go func() {
_, _ = adapter.Authenticate(ctx, req)
close(authDone)
}()
<-inner.started
if len(authDecodeSlots) != 1 {
t.Fatalf("slots held while inner call active = %d, want 1", len(authDecodeSlots))
}
cancel()
<-authDone
if len(authDecodeSlots) != 1 {
t.Fatalf("slots held after canceled Authenticate returned while inner call still blocked = %d, want 1", len(authDecodeSlots))
}
close(inner.release)
guarded.Shutdown()
if len(authDecodeSlots) != 0 {
t.Fatalf("slots held after inner call finished = %d, want 0", len(authDecodeSlots))
}
}