package testserver import ( "bytes" "encoding/json" "fmt" "io" "net/http" "strings" ) type Client struct { server *Server lastResp *http.Response lastBody []byte } func NewClient(server *Server) *Client { return &Client{ server: server, } } func (c *Client) Request(method, path string, body interface{}) error { url := c.server.GetBaseURL() + path var reqBody io.Reader if body != nil { // Handle different body types switch b := body.(type) { case []byte: reqBody = bytes.NewReader(b) case string: reqBody = strings.NewReader(b) case map[string]string: jsonBody, err := json.Marshal(b) if err != nil { return fmt.Errorf("failed to marshal JSON body: %w", err) } reqBody = bytes.NewReader(jsonBody) default: return fmt.Errorf("unsupported body type: %T", body) } } req, err := http.NewRequest(method, url, reqBody) if err != nil { return fmt.Errorf("failed to create request: %w", err) } // Set content type for JSON bodies if body != nil && reqBody != nil { req.Header.Set("Content-Type", "application/json") } resp, err := http.DefaultClient.Do(req) if err != nil { return fmt.Errorf("request failed: %w", err) } defer resp.Body.Close() c.lastResp = resp c.lastBody, err = io.ReadAll(resp.Body) if err != nil { return fmt.Errorf("failed to read response body: %w", err) } return nil } func (c *Client) CustomRequest(method, path string, body interface{}) (*http.Response, error) { url := c.server.GetBaseURL() + path var reqBody io.Reader if body != nil { // Handle different body types switch b := body.(type) { case []byte: reqBody = bytes.NewReader(b) case string: reqBody = strings.NewReader(b) case map[string]string: jsonBody, err := json.Marshal(b) if err != nil { return nil, fmt.Errorf("failed to marshal JSON body: %w", err) } reqBody = bytes.NewReader(jsonBody) default: return nil, fmt.Errorf("unsupported body type: %T", body) } } req, err := http.NewRequest(method, url, reqBody) if err != nil { return nil, fmt.Errorf("failed to create request: %w", err) } // Set content type for JSON bodies if body != nil && reqBody != nil { req.Header.Set("Content-Type", "application/json") } resp, err := http.DefaultClient.Do(req) if err != nil { return nil, fmt.Errorf("request failed: %w", err) } // Don't close the body here - let the caller handle it c.lastResp = resp c.lastBody, err = io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("failed to read response body: %w", err) } return resp, nil } // RequestWithHeader allows setting custom headers for the request func (c *Client) RequestWithHeader(method, path string, body interface{}, headers map[string]string) error { url := c.server.GetBaseURL() + path var reqBody io.Reader if body != nil { // Handle different body types switch b := body.(type) { case []byte: reqBody = bytes.NewReader(b) case string: reqBody = strings.NewReader(b) case map[string]string: jsonBody, err := json.Marshal(b) if err != nil { return fmt.Errorf("failed to marshal JSON body: %w", err) } reqBody = bytes.NewReader(jsonBody) default: return fmt.Errorf("unsupported body type: %T", body) } } req, err := http.NewRequest(method, url, reqBody) if err != nil { return fmt.Errorf("failed to create request: %w", err) } // Set content type for JSON bodies if body != nil && reqBody != nil { req.Header.Set("Content-Type", "application/json") } // Set custom headers for key, value := range headers { req.Header.Set(key, value) } resp, err := http.DefaultClient.Do(req) if err != nil { return fmt.Errorf("request failed: %w", err) } defer resp.Body.Close() c.lastResp = resp c.lastBody, err = io.ReadAll(resp.Body) if err != nil { return fmt.Errorf("failed to read response body: %w", err) } return nil } func (c *Client) ExpectResponseBody(expected string) error { if c.lastResp == nil { return fmt.Errorf("no response received") } actual := string(c.lastBody) // Trim trailing newline if present (common in JSON responses) actual = strings.TrimSuffix(actual, "\n") if actual != expected { return fmt.Errorf("expected response body %q, got %q", expected, actual) } return nil } // Helper methods for debugging func (c *Client) GetLastResponse() *http.Response { return c.lastResp } func (c *Client) GetLastBody() []byte { return c.lastBody } func (c *Client) GetLastStatusCode() int { if c.lastResp == nil { return 0 } return c.lastResp.StatusCode }