-
Notifications
You must be signed in to change notification settings - Fork 0
/
registry.go
169 lines (140 loc) · 5 KB
/
registry.go
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package httpregistry
import (
"errors"
"net/http"
"net/http/httptest"
"net/http/httputil"
"testing"
)
// A Registry contains all the Match that were registered and it is designed to allow easy access and manipulation to them
type Registry struct {
matches []match
misses []miss
}
// NewRegistry creates a new Registry
func NewRegistry() *Registry {
reg := Registry{}
return ®
}
// AddSimpleRequest is a helper function for the most common case of wanting to return a 200 response when URL is called with a method
func (reg *Registry) AddSimpleRequest(URL string, method string) {
request := NewRequest(URL, method)
reg.matches = append(reg.matches, newFixedResponseMatch(request, OkResponse))
}
// AddSimpleRequest is a helper function for the common case of wanting to return a statusCode response when URL is called with a method
func (reg *Registry) AddSimpleRequestWithStatusCode(URL string, method string, statusCode int) {
request := NewRequest(URL, method)
response := NewResponse(statusCode, nil)
reg.matches = append(reg.matches, newFixedResponseMatch(request, response))
}
// AddRequest adds request to the mock server and it returns a 200 response each time that request happens
func (reg *Registry) AddRequest(request Request) {
reg.matches = append(reg.matches, newFixedResponseMatch(request, OkResponse))
}
// AddRequest adds request to the mock server and it returns response each time that request happens
func (reg *Registry) AddRequestWithResponse(request Request, response Response) {
reg.matches = append(reg.matches, newFixedResponseMatch(request, response))
}
func (reg *Registry) AddRequestWithResponses(request Request, responses ...Response) {
reg.matches = append(reg.matches, newMultipleResponsesMatch(request, responses))
}
func (reg *Registry) GetMatchesPerRequest(r Request) []*http.Request {
for _, match := range reg.matches {
if match.Request().Equal(r) {
return match.Matches()
}
}
return []*http.Request{}
}
func (reg *Registry) GetMatchesUrl(url string) []*http.Request {
for _, match := range reg.matches {
r := match.Request()
if r.urlAsRegex.MatchString(url) {
return match.Matches()
}
}
return []*http.Request{}
}
func (reg *Registry) GetMatchesUrlAndMethod(url string, method string) []*http.Request {
for _, match := range reg.matches {
r := match.Request()
if r.urlAsRegex.MatchString(url) && r.Method == method {
return match.Matches()
}
}
return []*http.Request{}
}
// GetServer returns a httptest.Server designed to match all the requests registered with the Registry
func (reg *Registry) GetServer(t *testing.T) *httptest.Server {
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// We reset the misses since if a previous request matched it is pointless to record that some of the mocks did not match it.
// If said request did not match then the test would have crashed in any case so the information in misses is useless.
reg.misses = []miss{}
for _, possibleMatch := range reg.matches {
requestToMatch := possibleMatch.Request()
if !requestToMatch.urlAsRegex.MatchString(r.URL.String()) {
miss := miss{
MissedMatch: requestToMatch,
Why: pathDoesNotMatch,
}
reg.misses = append(reg.misses, miss)
continue
}
if requestToMatch.Method != r.Method {
miss := miss{
MissedMatch: requestToMatch,
Why: methodDoesNotMatch,
}
reg.misses = append(reg.misses, miss)
continue
}
headersToMatch := requestToMatch.Headers
headersMatch := true
for headerToMatch, valueToMatch := range headersToMatch {
value := r.Header.Get(headerToMatch)
if value == "" || value != valueToMatch {
headersMatch = false
miss := miss{
MissedMatch: requestToMatch,
Why: headersDoNotMatch,
}
reg.misses = append(reg.misses, miss)
break
}
}
if !headersMatch {
continue
}
response, err := possibleMatch.NextResponse(r)
if err != nil {
if errors.Is(errNoNextResponseFound, err) {
t.Errorf("run out of responses when calling: %v %v", requestToMatch.Method, requestToMatch.Url)
}
}
for k, v := range response.headers {
w.Header().Add(k, v)
}
w.WriteHeader(response.status)
_, err = w.Write(response.body)
if err != nil {
panic("cannot write body of request")
}
return
}
res, err := httputil.DumpRequest(r, true)
if err != nil {
t.Errorf("impossible to dump http request with error %v", err)
}
t.Errorf("no registered request matched %v\n you can use .Why() to get an explanation of why", string(res))
}))
}
// Why returns a string that contains all the reasons why the request submitted to the registry failed to match with the registered requests.
// The envision use of this function is just as a helper when debugging the tests,
// most of the time it might not be obvious if there is a typo or a small error.
func (reg *Registry) Why() string {
output := ""
for _, miss := range reg.misses {
output += miss.String() + "\n"
}
return output
}