Skip to content

Commit f9879fd

Browse files
authored
feat(exp): add mock requests after mock server creation (#558)
This allows to extend the list of requests the server expects to respond to. This also REPLACES the `mockutil.Server` function with a struct. You can create a new Server using the `mockutil.NewServer` function.
1 parent 8515c25 commit f9879fd

File tree

2 files changed

+90
-52
lines changed

2 files changed

+90
-52
lines changed

hcloud/exp/mockutil/http.go

+78-51
Original file line numberDiff line numberDiff line change
@@ -27,70 +27,97 @@ type Request struct {
2727
JSONRaw string
2828
}
2929

30-
// Handler is used with a [httptest.Server] to mock http requests provided by the user.
31-
//
32-
// Request matching is based on the request count, and the user provided request will be
33-
// iterated over.
30+
// Handler is using a [Server] to mock http requests provided by the user.
3431
func Handler(t *testing.T, requests []Request) http.HandlerFunc {
3532
t.Helper()
3633

37-
index := 0
34+
server := NewServer(t, requests)
35+
t.Cleanup(server.close)
3836

39-
t.Cleanup(func() {
40-
assert.EqualValues(t, len(requests), index, "expected more calls")
41-
})
37+
return server.handler
38+
}
4239

43-
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
44-
if testing.Verbose() {
45-
t.Logf("call %d: %s %s\n", index, r.Method, r.RequestURI)
46-
}
40+
// NewServer returns a new mock server that closes itself at the end of the test.
41+
func NewServer(t *testing.T, requests []Request) *Server {
42+
t.Helper()
4743

48-
if index >= len(requests) {
49-
t.Fatalf("received unknown call %d", index)
50-
}
44+
o := &Server{t: t}
45+
o.Server = httptest.NewServer(http.HandlerFunc(o.handler))
46+
t.Cleanup(o.close)
5147

52-
expected := requests[index]
48+
o.Expect(requests)
5349

54-
expectedCall := expected.Method
55-
foundCall := r.Method
56-
if expected.Path != "" {
57-
expectedCall += " " + expected.Path
58-
foundCall += " " + r.RequestURI
59-
}
60-
require.Equal(t, expectedCall, foundCall)
50+
return o
51+
}
6152

62-
if expected.Want != nil {
63-
expected.Want(t, r)
64-
}
53+
// Server embeds a [httptest.Server] that answers HTTP calls with a list of expected [Request].
54+
//
55+
// Request matching is based on the request count, and the user provided request will be
56+
// iterated over.
57+
//
58+
// A Server must be created using the [NewServer] function.
59+
type Server struct {
60+
*httptest.Server
6561

66-
switch {
67-
case expected.JSON != nil:
68-
w.Header().Set("Content-Type", "application/json")
69-
w.WriteHeader(expected.Status)
70-
if err := json.NewEncoder(w).Encode(expected.JSON); err != nil {
71-
t.Fatal(err)
72-
}
73-
case expected.JSONRaw != "":
74-
w.Header().Set("Content-Type", "application/json")
75-
w.WriteHeader(expected.Status)
76-
_, err := w.Write([]byte(expected.JSONRaw))
77-
if err != nil {
78-
t.Fatal(err)
79-
}
80-
default:
81-
w.WriteHeader(expected.Status)
82-
}
62+
t *testing.T
8363

84-
index++
85-
})
64+
requests []Request
65+
index int
8666
}
8767

88-
// Server is a [httptest.Server] wrapping a [Handler] that closes itself at the end of the test.
89-
func Server(t *testing.T, requests []Request) *httptest.Server {
90-
t.Helper()
68+
// Expect adds requests to the list of requests expected by the [Server].
69+
func (m *Server) Expect(requests []Request) {
70+
m.requests = append(m.requests, requests...)
71+
}
72+
73+
func (m *Server) close() {
74+
m.t.Helper()
9175

92-
server := httptest.NewServer(Handler(t, requests))
93-
t.Cleanup(server.Close)
76+
m.Server.Close()
77+
78+
assert.EqualValues(m.t, len(m.requests), m.index, "expected more calls")
79+
}
80+
81+
func (m *Server) handler(w http.ResponseWriter, r *http.Request) {
82+
if testing.Verbose() {
83+
m.t.Logf("call %d: %s %s\n", m.index, r.Method, r.RequestURI)
84+
}
85+
86+
if m.index >= len(m.requests) {
87+
m.t.Fatalf("received unknown call %d", m.index)
88+
}
89+
90+
expected := m.requests[m.index]
91+
92+
expectedCall := expected.Method
93+
foundCall := r.Method
94+
if expected.Path != "" {
95+
expectedCall += " " + expected.Path
96+
foundCall += " " + r.RequestURI
97+
}
98+
require.Equal(m.t, expectedCall, foundCall)
99+
100+
if expected.Want != nil {
101+
expected.Want(m.t, r)
102+
}
103+
104+
switch {
105+
case expected.JSON != nil:
106+
w.Header().Set("Content-Type", "application/json")
107+
w.WriteHeader(expected.Status)
108+
if err := json.NewEncoder(w).Encode(expected.JSON); err != nil {
109+
m.t.Fatal(err)
110+
}
111+
case expected.JSONRaw != "":
112+
w.Header().Set("Content-Type", "application/json")
113+
w.WriteHeader(expected.Status)
114+
_, err := w.Write([]byte(expected.JSONRaw))
115+
if err != nil {
116+
m.t.Fatal(err)
117+
}
118+
default:
119+
w.WriteHeader(expected.Status)
120+
}
94121

95-
return server
122+
m.index++
96123
}

hcloud/exp/mockutil/http_test.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
)
1414

1515
func TestHandler(t *testing.T) {
16-
server := Server(t, []Request{
16+
server := NewServer(t, []Request{
1717
{
1818
Method: "GET", Path: "/",
1919
Status: 200,
@@ -68,6 +68,17 @@ func TestHandler(t *testing.T) {
6868
assert.Equal(t, 200, resp.StatusCode)
6969
assert.Equal(t, "", resp.Header.Get("Content-Type"))
7070
assert.Equal(t, "", readBody(t, resp))
71+
72+
// Extra request 5
73+
server.Expect([]Request{
74+
{Method: "GET", Path: "/", Status: 200},
75+
})
76+
77+
resp, err = http.Get(server.URL)
78+
require.NoError(t, err)
79+
assert.Equal(t, 200, resp.StatusCode)
80+
assert.Equal(t, "", resp.Header.Get("Content-Type"))
81+
assert.Equal(t, "", readBody(t, resp))
7182
}
7283

7384
func readBody(t *testing.T, resp *http.Response) string {

0 commit comments

Comments
 (0)