-
Notifications
You must be signed in to change notification settings - Fork 107
/
response.go
196 lines (161 loc) · 5.16 KB
/
response.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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
package gock
import (
"bytes"
"encoding/json"
"encoding/xml"
"io"
"io/ioutil"
"net/http"
"time"
)
// MapResponseFunc represents the required function interface impletemed by response mappers.
type MapResponseFunc func(*http.Response) *http.Response
// FilterResponseFunc represents the required function interface impletemed by response filters.
type FilterResponseFunc func(*http.Response) bool
// Response represents high-level HTTP fields to configure
// and define HTTP responses intercepted by gock.
type Response struct {
// Mock stores the parent mock reference for the current response mock used for method delegation.
Mock Mock
// Error stores the latest response configuration or injected error.
Error error
// UseNetwork enables the use of real network for the current mock.
UseNetwork bool
// StatusCode stores the response status code.
StatusCode int
// Headers stores the response headers.
Header http.Header
// Cookies stores the response cookie fields.
Cookies []*http.Cookie
// BodyGen stores a io.ReadCloser generator to be returned.
BodyGen func() io.ReadCloser
// BodyBuffer stores the array of bytes to use as body.
BodyBuffer []byte
// ResponseDelay stores the simulated response delay.
ResponseDelay time.Duration
// Mappers stores the request functions mappers used for matching.
Mappers []MapResponseFunc
// Filters stores the request functions filters used for matching.
Filters []FilterResponseFunc
}
// NewResponse creates a new Response.
func NewResponse() *Response {
return &Response{Header: make(http.Header)}
}
// Status defines the desired HTTP status code to reply in the current response.
func (r *Response) Status(code int) *Response {
r.StatusCode = code
return r
}
// Type defines the response Content-Type MIME header field.
// Supports type alias. E.g: json, xml, form, text...
func (r *Response) Type(kind string) *Response {
mime := BodyTypeAliases[kind]
if mime != "" {
kind = mime
}
r.Header.Set("Content-Type", kind)
return r
}
// SetHeader sets a new header field in the mock response.
func (r *Response) SetHeader(key, value string) *Response {
r.Header.Set(key, value)
return r
}
// AddHeader adds a new header field in the mock response
// with out removing an existent one.
func (r *Response) AddHeader(key, value string) *Response {
r.Header.Add(key, value)
return r
}
// SetHeaders sets a map of header fields in the mock response.
func (r *Response) SetHeaders(headers map[string]string) *Response {
for key, value := range headers {
r.Header.Add(key, value)
}
return r
}
// Body sets the HTTP response body to be used.
func (r *Response) Body(body io.Reader) *Response {
r.BodyBuffer, r.Error = ioutil.ReadAll(body)
return r
}
// BodyGenerator accepts a io.ReadCloser generator, returning custom io.ReadCloser
// for every response. This will take priority than other Body methods used.
func (r *Response) BodyGenerator(generator func() io.ReadCloser) *Response {
r.BodyGen = generator
return r
}
// BodyString defines the response body as string.
func (r *Response) BodyString(body string) *Response {
r.BodyBuffer = []byte(body)
return r
}
// File defines the response body reading the data
// from disk based on the file path string.
func (r *Response) File(path string) *Response {
r.BodyBuffer, r.Error = ioutil.ReadFile(path)
return r
}
// JSON defines the response body based on a JSON based input.
func (r *Response) JSON(data interface{}) *Response {
r.Header.Set("Content-Type", "application/json")
r.BodyBuffer, r.Error = readAndDecode(data, "json")
return r
}
// XML defines the response body based on a XML based input.
func (r *Response) XML(data interface{}) *Response {
r.Header.Set("Content-Type", "application/xml")
r.BodyBuffer, r.Error = readAndDecode(data, "xml")
return r
}
// SetError defines the response simulated error.
func (r *Response) SetError(err error) *Response {
r.Error = err
return r
}
// Delay defines the response simulated delay.
// This feature is still experimental and will be improved in the future.
func (r *Response) Delay(delay time.Duration) *Response {
r.ResponseDelay = delay
return r
}
// Map adds a new response mapper function to map http.Response before the matching process.
func (r *Response) Map(fn MapResponseFunc) *Response {
r.Mappers = append(r.Mappers, fn)
return r
}
// Filter filters a new request filter function to filter http.Request before the matching process.
func (r *Response) Filter(fn FilterResponseFunc) *Response {
r.Filters = append(r.Filters, fn)
return r
}
// EnableNetworking enables the use real networking for the current mock.
func (r *Response) EnableNetworking() *Response {
r.UseNetwork = true
return r
}
// Done returns true if the mock was done and disabled.
func (r *Response) Done() bool {
return r.Mock.Done()
}
func readAndDecode(data interface{}, kind string) ([]byte, error) {
buf := &bytes.Buffer{}
switch data.(type) {
case string:
buf.WriteString(data.(string))
case []byte:
buf.Write(data.([]byte))
default:
var err error
if kind == "xml" {
err = xml.NewEncoder(buf).Encode(data)
} else {
err = json.NewEncoder(buf).Encode(data)
}
if err != nil {
return nil, err
}
}
return ioutil.ReadAll(buf)
}