-
Notifications
You must be signed in to change notification settings - Fork 3
/
tester.go
206 lines (165 loc) · 4.45 KB
/
tester.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
197
198
199
200
201
202
203
204
205
206
package fire
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"strings"
"github.com/256dpi/jsonapi"
"go.mongodb.org/mongo-driver/bson"
"github.com/256dpi/fire/coal"
)
// A Tester provides facilities to the test a fire API.
type Tester struct {
*coal.Tester
// The handler to be tested.
Handler http.Handler
// A path prefix e.g. 'api'.
Prefix string
// The header to be set on all requests and contexts.
Header map[string]string
// Context to be set on fake requests.
Context context.Context
}
// NewTester returns a new tester.
func NewTester(store *coal.Store, models ...coal.Model) *Tester {
return &Tester{
Tester: coal.NewTester(store, models...),
Header: make(map[string]string),
Context: context.Background(),
}
}
// Assign will create a controller group with the specified controllers and
// assign in to the Handler attribute of the tester. It will return the created
// group.
func (t *Tester) Assign(prefix string, controllers ...*Controller) *Group {
group := NewGroup()
group.Add(controllers...)
group.Reporter = func(err error) {
panic(err)
}
t.Handler = Compose(RootTracer(), group.Endpoint(prefix))
return group
}
// Clean will remove the collections of models that have been registered and
// reset the header map.
func (t *Tester) Clean() {
// clean models
t.Tester.Clean()
// reset header
t.Header = make(map[string]string)
// reset context
t.Context = context.Background()
}
// Path returns a root prefixed path for the supplied path.
func (t *Tester) Path(path string) string {
// add root slash
path = "/" + strings.Trim(path, "/")
// add prefix if available
if t.Prefix != "" {
path = "/" + t.Prefix + path
}
return path
}
// RunCallback is a helper to test callbacks.
func (t *Tester) RunCallback(ctx *Context, cb *Callback) error {
return t.RunHandler(ctx, cb.Handler)
}
// WithContext runs the given function with a prepared context.
func (t *Tester) WithContext(ctx *Context, fn func(*Context)) {
_ = t.RunHandler(ctx, func(ctx *Context) error {
fn(ctx)
return nil
})
}
// RunHandler builds a context and runs the passed handler with it.
func (t *Tester) RunHandler(ctx *Context, h Handler) error {
// set context if missing
if ctx == nil {
ctx = &Context{}
}
// set data if missing
if ctx.Data == nil {
ctx.Data = Map{}
}
// set operation if missing
if ctx.Operation == 0 {
ctx.Operation = List
}
// set store if unset
if ctx.Store == nil {
ctx.Store = t.Store
}
// init model if present
if ctx.Model != nil {
coal.Init(ctx.Model)
}
// init queries
if ctx.Selector == nil {
ctx.Selector = bson.M{}
}
if ctx.Filters == nil {
ctx.Filters = []bson.M{}
}
// set request
if ctx.HTTPRequest == nil {
// create request
req, err := http.NewRequest("GET", "", nil)
if err != nil {
panic(err)
}
// set headers
for key, value := range t.Header {
req.Header.Set(key, value)
}
// set context
ctx.HTTPRequest = req.WithContext(t.Context)
}
// set response writer
if ctx.ResponseWriter == nil {
ctx.ResponseWriter = httptest.NewRecorder()
}
// set json api request
if ctx.JSONAPIRequest == nil {
ctx.JSONAPIRequest = &jsonapi.Request{}
}
// set tracers
ctx.Tracer = NewTracerWithRoot("fire/Tester.RunHandler")
defer ctx.Tracer.Finish(true)
// call handler
return h(ctx)
}
// Request will run the specified request against the registered handler. This
// function can be used to create custom testing facilities.
func (t *Tester) Request(method, path string, payload string, callback func(*httptest.ResponseRecorder, *http.Request)) {
// create request
request, err := http.NewRequest(method, t.Path(path), strings.NewReader(payload))
if err != nil {
panic(err)
}
// prepare recorder
recorder := httptest.NewRecorder()
// preset jsonapi accept header
request.Header.Set("Accept", jsonapi.MediaType)
// add content type if required
if method == "POST" || method == "PATCH" || method == "DELETE" {
request.Header.Set("Content-Type", jsonapi.MediaType)
}
// set custom headers
for k, v := range t.Header {
request.Header.Set(k, v)
}
// server request
t.Handler.ServeHTTP(recorder, request)
// run callback
callback(recorder, request)
}
// DebugRequest returns a string of information to debug requests.
func (t *Tester) DebugRequest(r *http.Request, rr *httptest.ResponseRecorder) string {
return fmt.Sprintf(`
URL: %s
Header: %s
Status: %d
Header: %v
Body: %v`, r.URL.String(), r.Header, rr.Code, rr.HeaderMap, rr.Body.String())
}