client_test.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. package api
  2. import (
  3. "context"
  4. "errors"
  5. "net/http"
  6. "net/http/httptest"
  7. "os"
  8. "path/filepath"
  9. "testing"
  10. "time"
  11. )
  12. func TestFetchSubscriptionDetail_Success(t *testing.T) {
  13. body, err := os.ReadFile(filepath.Join("testdata", "sample.json"))
  14. if err != nil {
  15. t.Fatalf("read sample: %v", err)
  16. }
  17. srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  18. if got := r.Header.Get("Authorization"); got != "Bearer test-key" {
  19. t.Errorf("Authorization = %q", got)
  20. }
  21. if r.URL.Path != "/api/v1/management/subscription/detail" {
  22. t.Errorf("path = %q", r.URL.Path)
  23. }
  24. w.Header().Set("Content-Type", "application/json")
  25. _, _ = w.Write(body)
  26. }))
  27. defer srv.Close()
  28. c := &Client{BaseURL: srv.URL, HTTPClient: srv.Client()}
  29. resp, raw, err := c.FetchSubscriptionDetail(context.Background(), "test-key")
  30. if err != nil {
  31. t.Fatalf("unexpected error: %v", err)
  32. }
  33. if !resp.Success {
  34. t.Error("resp.Success = false")
  35. }
  36. if resp.Data.Plan.Tier != "ultra" {
  37. t.Errorf("plan.tier = %q", resp.Data.Plan.Tier)
  38. }
  39. if resp.Data.Quota7Day.UsedValueUSD != 13.66 {
  40. t.Errorf("quota_7_day.used_value_usd = %v", resp.Data.Quota7Day.UsedValueUSD)
  41. }
  42. if resp.Data.QuotaMonthly.MaxValueUSD != 1134.33 {
  43. t.Errorf("quota_monthly.max_value_usd = %v", resp.Data.QuotaMonthly.MaxValueUSD)
  44. }
  45. if len(raw) != len(body) {
  46. t.Errorf("raw body length mismatch: got %d want %d", len(raw), len(body))
  47. }
  48. }
  49. func TestFetchSubscriptionDetail_StatusMapping(t *testing.T) {
  50. cases := []struct {
  51. name string
  52. status int
  53. target error
  54. }{
  55. {"401", http.StatusUnauthorized, ErrUnauthorized},
  56. {"403", http.StatusForbidden, ErrUnauthorized},
  57. {"422", http.StatusUnprocessableEntity, ErrRateLimited},
  58. {"429", http.StatusTooManyRequests, ErrRateLimited},
  59. {"500", http.StatusInternalServerError, ErrServer},
  60. {"502", http.StatusBadGateway, ErrServer},
  61. }
  62. for _, tc := range cases {
  63. t.Run(tc.name, func(t *testing.T) {
  64. srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  65. w.WriteHeader(tc.status)
  66. _, _ = w.Write([]byte(`{"success":false,"error":"x"}`))
  67. }))
  68. defer srv.Close()
  69. c := &Client{BaseURL: srv.URL, HTTPClient: srv.Client()}
  70. _, _, err := c.FetchSubscriptionDetail(context.Background(), "k")
  71. if !errors.Is(err, tc.target) {
  72. t.Fatalf("want %v, got %v", tc.target, err)
  73. }
  74. })
  75. }
  76. }
  77. func TestFetchSubscriptionDetail_MalformedJSON(t *testing.T) {
  78. srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  79. _, _ = w.Write([]byte(`{"success": not-json`))
  80. }))
  81. defer srv.Close()
  82. c := &Client{BaseURL: srv.URL, HTTPClient: srv.Client()}
  83. _, _, err := c.FetchSubscriptionDetail(context.Background(), "k")
  84. if !errors.Is(err, ErrBadResponse) {
  85. t.Fatalf("want ErrBadResponse, got %v", err)
  86. }
  87. }
  88. func TestFetchSubscriptionDetail_SuccessFalse(t *testing.T) {
  89. srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  90. _, _ = w.Write([]byte(`{"success":false,"error":"explicit failure"}`))
  91. }))
  92. defer srv.Close()
  93. c := &Client{BaseURL: srv.URL, HTTPClient: srv.Client()}
  94. _, _, err := c.FetchSubscriptionDetail(context.Background(), "k")
  95. if !errors.Is(err, ErrBadResponse) {
  96. t.Fatalf("want ErrBadResponse, got %v", err)
  97. }
  98. }
  99. func TestFetchSubscriptionDetail_Timeout(t *testing.T) {
  100. srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  101. time.Sleep(100 * time.Millisecond)
  102. w.WriteHeader(http.StatusOK)
  103. }))
  104. defer srv.Close()
  105. c := &Client{BaseURL: srv.URL, HTTPClient: &http.Client{Timeout: 5 * time.Millisecond}}
  106. _, _, err := c.FetchSubscriptionDetail(context.Background(), "k")
  107. if !errors.Is(err, ErrTimeout) {
  108. t.Fatalf("want ErrTimeout, got %v", err)
  109. }
  110. }