| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- package service
- import (
- "context"
- "io"
- "net/http"
- "strings"
- "testing"
- "github.com/Wei-Shaw/sub2api/internal/pkg/tlsfingerprint"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- )
- type pluginRoutingHTTPUpstream struct {
- doCalls int
- doWithTLSCalls int
- }
- func (u *pluginRoutingHTTPUpstream) Do(*http.Request, string, int64, int) (*http.Response, error) {
- u.doCalls++
- return &http.Response{
- StatusCode: http.StatusOK,
- Header: make(http.Header),
- Body: io.NopCloser(strings.NewReader("legacy")),
- }, nil
- }
- func (u *pluginRoutingHTTPUpstream) DoWithTLS(
- request *http.Request,
- proxyURL string,
- accountID int64,
- accountConcurrency int,
- _ *tlsfingerprint.Profile,
- ) (*http.Response, error) {
- u.doWithTLSCalls++
- return u.Do(request, proxyURL, accountID, accountConcurrency)
- }
- func TestPluginManagerRoutingDoesNotTouchAPIKeyOrOtherProviders(t *testing.T) {
- manager := &PluginManager{}
- request, err := http.NewRequestWithContext(context.Background(), http.MethodPost, "https://example.com/v1/responses", nil)
- require.NoError(t, err)
- accounts := []*Account{
- {ID: 1, Platform: PlatformOpenAI, Type: AccountTypeAPIKey},
- {ID: 2, Platform: PlatformAnthropic, Type: AccountTypeOAuth},
- {ID: 3, Platform: PlatformGemini, Type: AccountTypeOAuth},
- }
- for _, account := range accounts {
- response, handled, routeErr := manager.RoundTripOpenAIOAuth(context.Background(), request, "", account)
- assert.Nil(t, response)
- assert.False(t, handled)
- assert.NoError(t, routeErr)
- }
- }
- func TestPluginManagerRoutingKeepsOAuthOnLegacyPathWithoutEnabledBinding(t *testing.T) {
- manager := &PluginManager{}
- request, err := http.NewRequestWithContext(context.Background(), http.MethodPost, "https://example.com/v1/responses", nil)
- require.NoError(t, err)
- account := &Account{ID: 10, Platform: PlatformOpenAI, Type: AccountTypeOAuth}
- response, handled, routeErr := manager.RoundTripOpenAIOAuth(context.Background(), request, "", account)
- assert.Nil(t, response)
- assert.False(t, handled)
- assert.NoError(t, routeErr)
- }
- func TestPluginManagerRoutingSelectsOnlyEligibleOpenAIOAuthAccounts(t *testing.T) {
- manager := &PluginManager{}
- manager.route.Store(&pluginRoute{pluginID: 1, rolloutPercent: 100, unavailable: "测试不可用"})
- assert.True(t, manager.ShouldRouteOpenAIOAuth(&Account{ID: 10, Platform: PlatformOpenAI, Type: AccountTypeOAuth}))
- assert.False(t, manager.ShouldRouteOpenAIOAuth(&Account{ID: 10, Platform: PlatformOpenAI, Type: AccountTypeAPIKey}))
- assert.False(t, manager.ShouldRouteOpenAIOAuth(&Account{ID: 10, Platform: PlatformGrok, Type: AccountTypeOAuth}))
- assert.False(t, manager.ShouldRouteOpenAIOAuth(nil))
- }
- func TestOpenAIGatewayPluginRoutingPreservesAPIKeyAndFailsClosedForOAuth(t *testing.T) {
- manager := &PluginManager{}
- manager.route.Store(&pluginRoute{pluginID: 1, rolloutPercent: 100, unavailable: "测试不可用"})
- upstream := &pluginRoutingHTTPUpstream{}
- service := &OpenAIGatewayService{pluginManager: manager, httpUpstream: upstream}
- apiKeyRequest, err := http.NewRequestWithContext(context.Background(), http.MethodPost, "https://example.com/v1/responses", nil)
- require.NoError(t, err)
- apiKeyResponse, err := service.doOpenAIUpstream(apiKeyRequest, "", &Account{
- ID: 1, Platform: PlatformOpenAI, Type: AccountTypeAPIKey, Concurrency: 1,
- })
- require.NoError(t, err)
- require.NotNil(t, apiKeyResponse)
- _ = apiKeyResponse.Body.Close()
- assert.Equal(t, 1, upstream.doCalls)
- oauthRequest, err := http.NewRequestWithContext(context.Background(), http.MethodPost, "https://example.com/v1/responses", nil)
- require.NoError(t, err)
- oauthResponse, err := service.doOpenAIUpstream(oauthRequest, "", &Account{
- ID: 2, Platform: PlatformOpenAI, Type: AccountTypeOAuth, Concurrency: 1,
- })
- require.Error(t, err)
- assert.Nil(t, oauthResponse)
- assert.Contains(t, err.Error(), "插件不可用")
- assert.Equal(t, 1, upstream.doCalls)
- }
- func TestStablePluginBucketIsDeterministicAndBounded(t *testing.T) {
- for id := int64(1); id <= 1000; id++ {
- first := stablePluginBucket(id)
- assert.Equal(t, first, stablePluginBucket(id))
- assert.Less(t, first, uint64(100))
- }
- }
|