| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- package repository
- import (
- "context"
- "net/http"
- "net/http/httptest"
- "reflect"
- "strings"
- "sync"
- "testing"
- "time"
- "unsafe"
- "github.com/Wei-Shaw/sub2api/internal/pkg/servertiming"
- "github.com/imroc/req/v3"
- "github.com/stretchr/testify/require"
- )
- func forceHTTPVersion(t *testing.T, client *req.Client) string {
- t.Helper()
- transport := client.GetTransport()
- field := reflect.ValueOf(transport).Elem().FieldByName("forceHttpVersion")
- require.True(t, field.IsValid(), "forceHttpVersion field not found")
- require.True(t, field.CanAddr(), "forceHttpVersion field not addressable")
- return reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().String()
- }
- func TestGetSharedReqClient_ForceHTTP2SeparatesCache(t *testing.T) {
- sharedReqClients = sync.Map{}
- base := reqClientOptions{
- ProxyURL: "http://proxy.local:8080",
- Timeout: time.Second,
- }
- clientDefault, err := getSharedReqClient(base)
- require.NoError(t, err)
- force := base
- force.ForceHTTP2 = true
- clientForce, err := getSharedReqClient(force)
- require.NoError(t, err)
- require.NotSame(t, clientDefault, clientForce)
- require.NotEqual(t, buildReqClientKey(base), buildReqClientKey(force))
- }
- func TestGetSharedReqClient_ReuseCachedClient(t *testing.T) {
- sharedReqClients = sync.Map{}
- opts := reqClientOptions{
- ProxyURL: "http://proxy.local:8080",
- Timeout: 2 * time.Second,
- }
- first, err := getSharedReqClient(opts)
- require.NoError(t, err)
- second, err := getSharedReqClient(opts)
- require.NoError(t, err)
- require.Same(t, first, second)
- }
- func TestGetSharedReqClient_IgnoresNonClientCache(t *testing.T) {
- sharedReqClients = sync.Map{}
- opts := reqClientOptions{
- ProxyURL: " http://proxy.local:8080 ",
- Timeout: 3 * time.Second,
- }
- key := buildReqClientKey(opts)
- sharedReqClients.Store(key, "invalid")
- client, err := getSharedReqClient(opts)
- require.NoError(t, err)
- require.NotNil(t, client)
- loaded, ok := sharedReqClients.Load(key)
- require.True(t, ok)
- require.IsType(t, "invalid", loaded)
- }
- func TestGetSharedReqClient_ImpersonateAndProxy(t *testing.T) {
- sharedReqClients = sync.Map{}
- opts := reqClientOptions{
- ProxyURL: " http://proxy.local:8080 ",
- Timeout: 4 * time.Second,
- Impersonate: true,
- }
- client, err := getSharedReqClient(opts)
- require.NoError(t, err)
- require.NotNil(t, client)
- require.Equal(t, "http://proxy.local:8080|4s|true|false", buildReqClientKey(opts))
- }
- func TestGetSharedReqClient_InvalidProxyURL(t *testing.T) {
- sharedReqClients = sync.Map{}
- opts := reqClientOptions{
- ProxyURL: "://missing-scheme",
- Timeout: time.Second,
- }
- _, err := getSharedReqClient(opts)
- require.Error(t, err)
- require.Contains(t, err.Error(), "invalid proxy URL")
- }
- func TestGetSharedReqClient_ProxyURLMissingHost(t *testing.T) {
- sharedReqClients = sync.Map{}
- opts := reqClientOptions{
- ProxyURL: "http://",
- Timeout: time.Second,
- }
- _, err := getSharedReqClient(opts)
- require.Error(t, err)
- require.Contains(t, err.Error(), "proxy URL missing host")
- }
- func TestCreateOpenAIReqClient_Timeout120Seconds(t *testing.T) {
- sharedReqClients = sync.Map{}
- client, err := createOpenAIReqClient("http://proxy.local:8080")
- require.NoError(t, err)
- require.Equal(t, 120*time.Second, client.GetClient().Timeout)
- }
- func TestCreateGeminiReqClient_ForceHTTP2Disabled(t *testing.T) {
- sharedReqClients = sync.Map{}
- client, err := createGeminiReqClient("http://proxy.local:8080")
- require.NoError(t, err)
- require.Equal(t, "", forceHTTPVersion(t, client))
- }
- func TestInstrumentReqClientRecordsDependency(t *testing.T) {
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
- w.WriteHeader(http.StatusNoContent)
- }))
- defer server.Close()
- collector := servertiming.New(time.Now())
- ctx := servertiming.WithCollector(context.Background(), collector)
- client := instrumentReqClient(req.C())
- response, err := client.R().SetContext(ctx).Get(server.URL)
- require.NoError(t, err)
- require.Equal(t, http.StatusNoContent, response.StatusCode)
- header := collector.HeaderValue(time.Now(), "bypass")
- require.True(t, strings.Contains(header, "dep_http;dur="), header)
- }
|