Files
httpx/response_test.go
Aleksey Shakhmatov f9a05f5c57 Add Client with response wrapper, request helpers, and full middleware assembly
Implements the top-level httpx.Client that composes the full chain:
  Logging → User Middlewares → Retry → Circuit Breaker → Balancer → Transport

- Response wrapper with JSON/XML/Bytes decoding and body caching
- NewJSONRequest helper with Content-Type and GetBody support
- Functional options: WithBaseURL, WithTimeout, WithRetry, WithEndpoints, etc.
- Integration tests covering retry, balancing, error mapping, and JSON round-trips
2026-03-20 14:22:22 +03:00

97 lines
2.3 KiB
Go

package httpx
import (
"io"
"net/http"
"strings"
"testing"
)
func makeTestResponse(statusCode int, body string) *Response {
return newResponse(&http.Response{
StatusCode: statusCode,
Body: io.NopCloser(strings.NewReader(body)),
Header: make(http.Header),
})
}
func TestResponse(t *testing.T) {
t.Run("Bytes returns body", func(t *testing.T) {
r := makeTestResponse(200, "hello world")
b, err := r.Bytes()
if err != nil {
t.Fatalf("Bytes() error: %v", err)
}
if string(b) != "hello world" {
t.Errorf("Bytes() = %q, want %q", string(b), "hello world")
}
})
t.Run("body caching returns same data", func(t *testing.T) {
r := makeTestResponse(200, "cached body")
b1, err := r.Bytes()
if err != nil {
t.Fatalf("first Bytes() error: %v", err)
}
b2, err := r.Bytes()
if err != nil {
t.Fatalf("second Bytes() error: %v", err)
}
if string(b1) != string(b2) {
t.Errorf("Bytes() returned different data: %q vs %q", b1, b2)
}
})
t.Run("String returns body as string", func(t *testing.T) {
r := makeTestResponse(200, "string body")
s, err := r.String()
if err != nil {
t.Fatalf("String() error: %v", err)
}
if s != "string body" {
t.Errorf("String() = %q, want %q", s, "string body")
}
})
t.Run("JSON decodes body", func(t *testing.T) {
r := makeTestResponse(200, `{"name":"test","value":42}`)
var result struct {
Name string `json:"name"`
Value int `json:"value"`
}
if err := r.JSON(&result); err != nil {
t.Fatalf("JSON() error: %v", err)
}
if result.Name != "test" {
t.Errorf("Name = %q, want %q", result.Name, "test")
}
if result.Value != 42 {
t.Errorf("Value = %d, want %d", result.Value, 42)
}
})
t.Run("IsSuccess for 2xx", func(t *testing.T) {
for _, code := range []int{200, 201, 204, 299} {
r := makeTestResponse(code, "")
if !r.IsSuccess() {
t.Errorf("IsSuccess() = false for status %d", code)
}
if r.IsError() {
t.Errorf("IsError() = true for status %d", code)
}
}
})
t.Run("IsError for 4xx and 5xx", func(t *testing.T) {
for _, code := range []int{400, 404, 500, 503} {
r := makeTestResponse(code, "")
if !r.IsError() {
t.Errorf("IsError() = false for status %d", code)
}
if r.IsSuccess() {
t.Errorf("IsSuccess() = true for status %d", code)
}
}
})
}