account_traffic_http_test.go 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
  1. package repository
  2. import (
  3. "errors"
  4. "io"
  5. "net/http"
  6. "net/http/httptest"
  7. "strings"
  8. "sync/atomic"
  9. "testing"
  10. "github.com/Wei-Shaw/sub2api/internal/service"
  11. "github.com/stretchr/testify/require"
  12. )
  13. func TestAccountTrafficHTTPEnforcesBudgetBeforeNetwork(t *testing.T) {
  14. _, cache, plan := trafficFixture(t)
  15. plan.Policy.RPM = 1
  16. plan.Policy.Burst = 1
  17. control := service.NewAccountTrafficService(cache)
  18. upstream := NewControlledHTTPUpstream(nil, control)
  19. a := &service.Account{ID: 42, Concurrency: 8, Extra: map[string]any{service.AccountTrafficPolicyKey: plan.Policy}}
  20. var calls atomic.Int32
  21. server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  22. calls.Add(1)
  23. w.Header().Set("Content-Type", "text/event-stream")
  24. io.WriteString(w, "data: hello\n\n")
  25. }))
  26. defer server.Close()
  27. req, _ := http.NewRequest("POST", server.URL, strings.NewReader("{}"))
  28. resp, err := upstream.Do(service.WithAccountTrafficRequest(req, a), "", 42, 8)
  29. require.NoError(t, err)
  30. _, err = io.ReadAll(resp.Body)
  31. require.NoError(t, err)
  32. require.NoError(t, resp.Body.Close())
  33. req, _ = http.NewRequest("POST", server.URL, strings.NewReader("{}"))
  34. _, err = upstream.Do(service.WithAccountTrafficRequest(req, a), "", 42, 8)
  35. var limited *service.AccountTrafficLimitError
  36. require.True(t, errors.As(err, &limited))
  37. require.EqualValues(t, 1, calls.Load())
  38. // Turning both switches off immediately restores the normal transport.
  39. a.Extra = nil
  40. req, _ = http.NewRequest("POST", server.URL, strings.NewReader("{}"))
  41. resp, err = upstream.Do(service.WithAccountTrafficRequest(req, a), "", 42, 8)
  42. require.NoError(t, err)
  43. resp.Body.Close()
  44. require.EqualValues(t, 2, calls.Load())
  45. }