//go:build test // +build test package httptest import ( "bytes" "encoding/json" "io" "net/http" "net/http/httptest" "strings" "time" ) type TestClient struct { client *http.Client authToken string baseURL string } func NewTestClient(handler http.Handler) *TestClient { server := httptest.NewServer(handler) return &TestClient{ client: server.Client(), baseURL: server.URL, } } func (c *TestClient) Server() *httptest.Server { return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { c.client.Transport.RoundTrip(r) })) } func (c *TestClient) SetAuthToken(token string) { c.authToken = token } func (c *TestClient) ClearAuthToken() { c.authToken = "" } func (c *TestClient) getAuthHeader() string { if c.authToken == "" { return "" } return "Bearer " + c.authToken } func (c *TestClient) Get(path string) (*http.Response, error) { req, err := http.NewRequest("GET", c.baseURL+path, nil) if err != nil { return nil, err } if auth := c.getAuthHeader(); auth != "" { req.Header.Set("Authorization", auth) } return c.client.Do(req) } func (c *TestClient) Post(path string, body interface{}) (*http.Response, error) { var bodyReader io.Reader if body != nil { jsonBytes, err := json.Marshal(body) if err != nil { return nil, err } bodyReader = bytes.NewReader(jsonBytes) } req, err := http.NewRequest("POST", c.baseURL+path, bodyReader) if err != nil { return nil, err } if auth := c.getAuthHeader(); auth != "" { req.Header.Set("Authorization", auth) } req.Header.Set("Content-Type", "application/json") return c.client.Do(req) } func (c *TestClient) Put(path string, body interface{}) (*http.Response, error) { var bodyReader io.Reader if body != nil { jsonBytes, err := json.Marshal(body) if err != nil { return nil, err } bodyReader = bytes.NewReader(jsonBytes) } req, err := http.NewRequest("PUT", c.baseURL+path, bodyReader) if err != nil { return nil, err } if auth := c.getAuthHeader(); auth != "" { req.Header.Set("Authorization", auth) } req.Header.Set("Content-Type", "application/json") return c.client.Do(req) } func (c *TestClient) Delete(path string) (*http.Response, error) { req, err := http.NewRequest("DELETE", c.baseURL+path, nil) if err != nil { return nil, err } if auth := c.getAuthHeader(); auth != "" { req.Header.Set("Authorization", auth) } return c.client.Do(req) } func (c *TestClient) Patch(path string, body interface{}) (*http.Response, error) { var bodyReader io.Reader if body != nil { jsonBytes, err := json.Marshal(body) if err != nil { return nil, err } bodyReader = bytes.NewReader(jsonBytes) } req, err := http.NewRequest("PATCH", c.baseURL+path, bodyReader) if err != nil { return nil, err } if auth := c.getAuthHeader(); auth != "" { req.Header.Set("Authorization", auth) } req.Header.Set("Content-Type", "application/json") return c.client.Do(req) } func (c *TestClient) ReadResponse(resp *http.Response, dest interface{}) error { defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return err } return json.Unmarshal(body, dest) } func (c *TestClient) GetBody(resp *http.Response) (string, error) { defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return "", err } return string(body), nil } func (c *TestClient) Close() { c.client.CloseIdleConnections() } type Response struct { StatusCode int Body []byte Header http.Header } func (c *TestClient) Do(req *http.Request) (*Response, error) { resp, err := c.client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return nil, err } return &Response{ StatusCode: resp.StatusCode, Body: body, Header: resp.Header, }, nil } func (c *TestClient) NewRequest(method, path string, body interface{}) (*http.Request, error) { var bodyReader io.Reader if body != nil { jsonBytes, err := json.Marshal(body) if err != nil { return nil, err } bodyReader = bytes.NewReader(jsonBytes) } req, err := http.NewRequest(method, c.baseURL+path, bodyReader) if err != nil { return nil, err } if auth := c.getAuthHeader(); auth != "" { req.Header.Set("Authorization", auth) } if body != nil { req.Header.Set("Content-Type", "application/json") } return req, nil } func MustParseJSON(body []byte, v interface{}) { if err := json.Unmarshal(body, v); err != nil { panic("failed to parse JSON: " + err.Error() + "\nBody: " + string(body)) } } func JSONBody(v interface{}) io.Reader { jsonBytes, err := json.Marshal(v) if err != nil { panic("failed to marshal JSON: " + err.Error()) } return bytes.NewReader(jsonBytes) } func SetDefaultTimeout(client *http.Client) { client.Timeout = 10 * time.Second } func Contains(s, substr string) bool { return strings.Contains(s, substr) }