Browse code

client: tidy-up mock-utilities

- Add a `mockResponse` utility, and slightly enhance it to also include
the request Headers and Status message, to be more closely to actual
responses.
- Add a `mockJSONResponse` utility, implemented using `mockResponse`
- Remove `plainTextErrorMock` in favor of `mockResponse`

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Sebastiaan van Stijn authored on 2025/10/23 18:58:55
Showing 2 changed files
... ...
@@ -1,7 +1,6 @@
1 1
 package client
2 2
 
3 3
 import (
4
-	"bytes"
5 4
 	"encoding/json"
6 5
 	"fmt"
7 6
 	"io"
... ...
@@ -50,30 +49,41 @@ func WithMockClient(doer func(*http.Request) (*http.Response, error)) Opt {
50 50
 }
51 51
 
52 52
 func errorMock(statusCode int, message string) func(req *http.Request) (*http.Response, error) {
53
-	return func(req *http.Request) (*http.Response, error) {
54
-		header := http.Header{}
55
-		header.Set("Content-Type", "application/json")
56
-
57
-		body, err := json.Marshal(&common.ErrorResponse{
58
-			Message: message,
59
-		})
60
-		if err != nil {
61
-			return nil, err
62
-		}
53
+	return mockJSONResponse(statusCode, nil, common.ErrorResponse{
54
+		Message: message,
55
+	})
56
+}
63 57
 
64
-		return &http.Response{
65
-			StatusCode: statusCode,
66
-			Body:       io.NopCloser(bytes.NewReader(body)),
67
-			Header:     header,
68
-		}, nil
58
+func mockJSONResponse[T any](statusCode int, headers http.Header, resp T) func(req *http.Request) (*http.Response, error) {
59
+	respBody, err := json.Marshal(&resp)
60
+	if err != nil {
61
+		panic(err)
62
+	}
63
+	hdr := make(http.Header)
64
+	if headers != nil {
65
+		hdr = headers.Clone()
69 66
 	}
67
+	hdr.Set("Content-Type", "application/json")
68
+	return mockResponse(statusCode, hdr, string(respBody))
70 69
 }
71 70
 
72
-func plainTextErrorMock(statusCode int, message string) func(req *http.Request) (*http.Response, error) {
71
+func mockResponse(statusCode int, headers http.Header, respBody string) func(req *http.Request) (*http.Response, error) {
72
+	if headers == nil {
73
+		headers = make(http.Header)
74
+	}
75
+	var body io.ReadCloser
76
+	if respBody == "" {
77
+		body = http.NoBody
78
+	} else {
79
+		body = io.NopCloser(strings.NewReader(respBody))
80
+	}
73 81
 	return func(req *http.Request) (*http.Response, error) {
74 82
 		return &http.Response{
83
+			Status:     fmt.Sprintf("%d %s", statusCode, http.StatusText(statusCode)),
75 84
 			StatusCode: statusCode,
76
-			Body:       io.NopCloser(bytes.NewReader([]byte(message))),
85
+			Header:     headers,
86
+			Body:       body,
87
+			Request:    req,
77 88
 		}, nil
78 89
 	}
79 90
 }
... ...
@@ -78,7 +78,7 @@ func TestSetHostHeader(t *testing.T) {
78 78
 // API versions < 1.24 returned plain text errors, but we may encounter
79 79
 // other situations where a non-JSON error is returned.
80 80
 func TestPlainTextError(t *testing.T) {
81
-	client, err := NewClientWithOpts(WithMockClient(plainTextErrorMock(http.StatusInternalServerError, "Server error")))
81
+	client, err := NewClientWithOpts(WithMockClient(mockResponse(http.StatusInternalServerError, nil, "Server error")))
82 82
 	assert.NilError(t, err)
83 83
 	_, err = client.ContainerList(context.Background(), ContainerListOptions{})
84 84
 	assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))