package upstreamimpl import ( "context" "net/http" "net/http/httptest" "testing" "time" "github.com/gogf/gf/v2/frame/g" ) func TestGatewayTimeoutAllowsDelayedHeaders(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { time.Sleep(40 * time.Millisecond) _, _ = w.Write([]byte(`{"code":0,"data":[]}`)) })) defer server.Close() client := g.Client() other := g.Client() original := other.Transport.(*http.Transport) original.ResponseHeaderTimeout = time.Millisecond client.Transport.(*http.Transport).ResponseHeaderTimeout = time.Millisecond configureGatewayTimeout(context.Background(), client, "/sim/change/sim-apn", 1, time.Second) response, err := client.Post(context.Background(), server.URL, nil) if err != nil { t.Fatal(err) } defer response.Close() if original.ResponseHeaderTimeout != time.Millisecond { t.Fatal("修改了共享Transport") } } func TestNonAPNGatewayTimeoutPreservesHeaderBudget(t *testing.T) { client := g.Client() transport := client.Transport.(*http.Transport) transport.ResponseHeaderTimeout = 17 * time.Second configureGatewayTimeout(context.Background(), client, "/sim/query/test", 2, 3*time.Second) if client.Client.Timeout != 6*time.Second || transport.ResponseHeaderTimeout != 6*time.Second { t.Fatalf("非APN响应头预算必须与请求预算一致:request=%s header=%s", client.Client.Timeout, transport.ResponseHeaderTimeout) } } // TestNonAPNBatchExpandsHeaderBudget 覆盖批量停复机等非 APN 路径: // 50 张卡按单卡预算放大后,响应头等待不能继续停留在 gclient 的 30 秒默认值。 func TestNonAPNBatchExpandsHeaderBudget(t *testing.T) { client := g.Client() transport := client.Transport.(*http.Transport) transport.ResponseHeaderTimeout = 30 * time.Second applyGatewayTimeout(client, "/sim/change/sim-status", 50, 10*time.Second, defaultDataServiceTimeout, defaultGatewayBatchTimeout) if client.Client.Timeout != 500*time.Second { t.Fatalf("请求预算=%s,期望500s", client.Client.Timeout) } if transport.ResponseHeaderTimeout != client.Client.Timeout { t.Fatalf("响应头预算=%s与请求预算不一致", transport.ResponseHeaderTimeout) } } // TestNonAPNBatchRespectsBatchTimeoutCap 保证异常上游不会无限占用连接: // 超出批量上限时按上限截断,且响应头预算同步截断。 func TestNonAPNBatchRespectsBatchTimeoutCap(t *testing.T) { client := g.Client() transport := client.Transport.(*http.Transport) applyGatewayTimeout(client, "/sim/query/usage", 1000, 10*time.Second, defaultDataServiceTimeout, defaultGatewayBatchTimeout) if client.Client.Timeout != defaultGatewayBatchTimeout { t.Fatalf("请求预算=%s,期望批量上限%s", client.Client.Timeout, defaultGatewayBatchTimeout) } if transport.ResponseHeaderTimeout != defaultGatewayBatchTimeout { t.Fatalf("响应头预算=%s,期望批量上限%s", transport.ResponseHeaderTimeout, defaultGatewayBatchTimeout) } } // TestNonAPNSingleCardKeepsPerCardBudget 保证单卡请求不被放大成批量预算。 func TestNonAPNSingleCardKeepsPerCardBudget(t *testing.T) { for _, count := range []int{0, 1} { client := g.Client() transport := client.Transport.(*http.Transport) applyGatewayTimeout(client, "/sim/query/test", count, 10*time.Second, defaultDataServiceTimeout, defaultGatewayBatchTimeout) if client.Client.Timeout != 10*time.Second || transport.ResponseHeaderTimeout != 10*time.Second { t.Fatalf("count=%d request=%s header=%s", count, client.Client.Timeout, transport.ResponseHeaderTimeout) } } } func TestDataServiceTimeoutOverridesCardBudget(t *testing.T) { for _, count := range []int{0, 1, 100} { client := g.Client() configureGatewayTimeout(context.Background(), client, "/sim/change/sim-apn", count, time.Millisecond) if client.Client.Timeout != 210*time.Second { t.Fatalf("count=%d timeout=%s", count, client.Client.Timeout) } if client.Transport.(*http.Transport).ResponseHeaderTimeout != client.Client.Timeout { t.Fatal("响应头预算不一致") } } }