-
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathresponse_test.go
More file actions
138 lines (121 loc) · 3.85 KB
/
response_test.go
File metadata and controls
138 lines (121 loc) · 3.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package httpsuite
import (
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
)
type testResponse struct {
Key string `json:"key"`
}
func TestSendResponse(t *testing.T) {
t.Parallel()
tests := []struct {
name string
code int
data any
problem *ProblemDetails
meta any
expectedCode int
contentType string
}{
{
name: "success response",
code: http.StatusOK,
data: &testResponse{Key: "value"},
expectedCode: http.StatusOK,
contentType: "application/json; charset=utf-8",
},
{
name: "problem response",
code: http.StatusNotFound,
problem: NewProblemDetails(http.StatusNotFound, "", "Not Found", "The requested resource was not found"),
expectedCode: http.StatusNotFound,
contentType: "application/problem+json; charset=utf-8",
},
{
name: "success response with page meta",
code: http.StatusOK,
data: []string{"a", "b"},
meta: NewPageMeta(2, 10, 25),
expectedCode: http.StatusOK,
contentType: "application/json; charset=utf-8",
},
{
name: "success response with cursor meta",
code: http.StatusOK,
data: []string{"a", "b"},
meta: NewCursorMeta("next-1", "prev-1", true, true),
expectedCode: http.StatusOK,
contentType: "application/json; charset=utf-8",
},
{
name: "problem response normalizes status",
code: http.StatusBadRequest,
problem: NewProblemDetails(http.StatusUnprocessableEntity, "", "Invalid Request", "invalid"),
expectedCode: http.StatusBadRequest,
contentType: "application/problem+json; charset=utf-8",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
w := httptest.NewRecorder()
SendResponse[any](w, tt.code, tt.data, tt.problem, tt.meta)
if w.Code != tt.expectedCode {
t.Fatalf("expected status %d, got %d", tt.expectedCode, w.Code)
}
if got := w.Header().Get("Content-Type"); got != tt.contentType {
t.Fatalf("expected content type %q, got %q", tt.contentType, got)
}
if !json.Valid(w.Body.Bytes()) {
t.Fatalf("expected valid json, got %q", w.Body.String())
}
if tt.problem != nil {
var problem ProblemDetails
if err := json.NewDecoder(w.Body).Decode(&problem); err != nil {
t.Fatalf("decode problem details: %v", err)
}
if problem.Status != tt.expectedCode {
t.Fatalf("expected problem status %d, got %d", tt.expectedCode, problem.Status)
}
}
})
}
}
func TestSendResponseDoesNotLeakEncodeErrors(t *testing.T) {
t.Parallel()
w := httptest.NewRecorder()
SendResponse[any](w, http.StatusOK, map[string]any{"bad": func() {}}, nil, nil)
if w.Code != http.StatusInternalServerError {
t.Fatalf("expected status %d, got %d", http.StatusInternalServerError, w.Code)
}
var problem ProblemDetails
if err := json.NewDecoder(w.Body).Decode(&problem); err != nil {
t.Fatalf("decode problem details: %v", err)
}
if problem.Detail != "The server could not serialize the response." {
t.Fatalf("unexpected detail %q", problem.Detail)
}
}
func TestProblemResponseFallsBackWhenProblemEncodingFails(t *testing.T) {
t.Parallel()
w := httptest.NewRecorder()
problem := NewBadRequestProblem("invalid")
problem.Extensions = map[string]interface{}{"bad": func() {}}
ProblemResponse(w, problem)
if w.Code != http.StatusInternalServerError {
t.Fatalf("expected status %d, got %d", http.StatusInternalServerError, w.Code)
}
var got ProblemDetails
if err := json.NewDecoder(w.Body).Decode(&got); err != nil {
t.Fatalf("decode fallback problem details: %v", err)
}
if got.Title != "Internal Server Error" {
t.Fatalf("expected fallback title, got %q", got.Title)
}
if got.Detail != "An internal server error occurred." {
t.Fatalf("expected fallback detail, got %q", got.Detail)
}
}