Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(222)

Side by Side Diff: appengine/ephelper/epfrontend/service_test.go

Issue 1750143003: Remove ephelper and other endpoints code. (Closed) Base URL: https://github.com/luci/luci-go@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package epfrontend
6
7 import (
8 "bytes"
9 "encoding/json"
10 "errors"
11 "fmt"
12 "net/http"
13 "net/http/httptest"
14 "net/url"
15 "testing"
16
17 "github.com/GoogleCloudPlatform/go-endpoints/endpoints"
18 . "github.com/smartystreets/goconvey/convey"
19 "golang.org/x/net/context"
20 )
21
22 type serviceBackendStub struct {
23 body bytes.Buffer
24 callback func(w http.ResponseWriter)
25 }
26
27 func (s *serviceBackendStub) ServeHTTP(w http.ResponseWriter, req *http.Request) {
28 defer req.Body.Close()
29 _, err := s.body.ReadFrom(req.Body)
30 if err != nil {
31 panic(err)
32 }
33
34 if s.callback != nil {
35 s.callback(w)
36 }
37 }
38
39 type requestNormalizer struct {
40 http.Handler
41 scheme string
42 host string
43 }
44
45 func (s *requestNormalizer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
46 u, err := url.ParseRequestURI(req.RequestURI)
47 if err != nil {
48 panic(err)
49 }
50
51 u.Scheme = s.scheme
52 u.Host = s.host
53 req.URL = u
54 req.RequestURI = u.Path
55 req.Host = u.Host
56 s.Handler.ServeHTTP(w, req)
57 }
58
59 type ServiceTestService struct {
60 }
61
62 type ServiceTestPathReq struct {
63 Name string `endpoints:"required"`
64 Count int64 `endpoints:"required"`
65 }
66
67 type ServiceTestResponse struct {
68 Count int64 `json:"count"`
69 }
70
71 func (s *ServiceTestService) PathReq(c context.Context, req *ServiceTestPathReq) (*ServiceTestResponse, error) {
72 return nil, endpoints.UnauthorizedError
73 }
74
75 type ServiceTestQueryReq struct {
76 Name string `endpoints:"required"`
77 Count int64 `json:"count,string"`
78
79 S string
80 F float32
81 B bool
82 B2 bool
83 I int32
84 }
85
86 func (s *ServiceTestService) QueryReq(c context.Context, req *ServiceTestQueryRe q) error {
87 return endpoints.UnauthorizedError
88 }
89
90 type ServiceTestPostReq struct {
91 S string
92 T string
93 }
94
95 func (s *ServiceTestService) Post(c context.Context, req *ServiceTestPostReq) er ror {
96 return endpoints.UnauthorizedError
97 }
98
99 func readErrorResponse(resp *http.Response) *outerError {
100 defer resp.Body.Close()
101
102 e := outerError{}
103 if err := json.NewDecoder(resp.Body).Decode(&e); err != nil {
104 return nil
105 }
106 return &e
107 }
108
109 func TestService(t *testing.T) {
110 Convey(`A testing service`, t, func() {
111 be := serviceBackendStub{}
112 fe := New("", &be)
113
114 ts := httptest.NewServer(&requestNormalizer{
115 Handler: fe,
116 scheme: "http",
117 host: "example.com",
118 })
119 defer ts.Close()
120
121 c := http.Client{}
122
123 Convey(`Requests to non-root URLs are rejected.`, func() {
124 resp, err := c.Get(fmt.Sprintf("%s%s", ts.URL, "/ohai"))
125 So(err, ShouldBeNil)
126 So(resp.StatusCode, ShouldEqual, http.StatusNotFound)
127 })
128
129 Convey(`With a registered test service (query parameters)`, func () {
130 // Create an endpoints backend because we need the API d escriptors that it
131 // creates from our services.
132 epbe := endpoints.NewServer("")
133 svc, err := epbe.RegisterService(&ServiceTestService{}, "test", "v1", "Test Service", true)
134 So(err, ShouldBeNil)
135 So(svc, ShouldNotBeNil)
136
137 m := svc.MethodByName("QueryReq")
138 m.Info().HTTPMethod = "GET"
139 m.Info().Path = "queryreq/{Name}"
140
141 So(fe.RegisterService(svc), ShouldBeNil)
142
143 Convey(`Will not register the service again.`, func() {
144 So(fe.RegisterService(svc), ShouldNotBeNil)
145 })
146
147 Convey(`Exposes a redirecting "explorer" API.`, func() {
148 redirected := false
149 c.CheckRedirect = func(req *http.Request, via [] *http.Request) error {
150 redirected = true
151 return errors.New("testing, no redirect" )
152 }
153
154 c.Get(fmt.Sprintf("%s%s", ts.URL, "/_ah/api/expl orer"))
155 So(redirected, ShouldBeTrue)
156 })
157
158 Convey(`POST requests to directory endpoint return http. StatusMethodNotAllowed.`, func() {
159 resp, err := c.Post(fmt.Sprintf("%s%s", ts.URL, "/_ah/api/discovery/v1/apis"), "", nil)
160 So(err, ShouldBeNil)
161 So(resp.StatusCode, ShouldEqual, http.StatusMeth odNotAllowed)
162 })
163
164 Convey(`Exposes a directory REST endpoint.`, func() {
165 exp := directoryList{}
166 loadJSONTestCase(&exp, "service", "test", "direc tory")
167
168 act := directoryList{}
169 resp, err := c.Get(fmt.Sprintf("%s%s", ts.URL, " /_ah/api/discovery/v1/apis"))
170 So(err, ShouldBeNil)
171 defer resp.Body.Close()
172 So(json.NewDecoder(resp.Body).Decode(&act), Shou ldBeNil)
173
174 So(act, ShouldResemble, exp)
175 })
176
177 Convey(`Exposes a service REST endpoint.`, func() {
178 exp := restDescription{}
179 loadJSONTestCase(&exp, "service", "test", "servi ce")
180
181 act := restDescription{}
182 resp, err := c.Get(fmt.Sprintf("%s%s", ts.URL, " /_ah/api/discovery/v1/apis/test/v1/rest"))
183 So(err, ShouldBeNil)
184 defer resp.Body.Close()
185 So(json.NewDecoder(resp.Body).Decode(&act), Shou ldBeNil)
186
187 So(act, ShouldResemble, exp)
188 })
189
190 Convey(`Can access the "pathreq" endpoint with path elem ents.`, func() {
191 _, err := c.Get(fmt.Sprintf("%s%s", ts.URL, "/_a h/api/test/v1/pathreq/testname/12345"))
192 So(err, ShouldBeNil)
193
194 So(be.body.String(), ShouldEqual, `{"Count":"123 45","Name":"testname"}`+"\n")
195 })
196
197 Convey(`Will return an error if an invalid "pathreq" pat h parameter is supplied.`, func() {
198 resp, err := c.Get(fmt.Sprintf("%s%s", ts.URL, " /_ah/api/test/v1/pathreq/testname/pi"))
199 So(err, ShouldBeNil)
200
201 e := readErrorResponse(resp)
202 So(e, ShouldNotBeNil)
203 So(e.Error, ShouldNotBeNil)
204 So(e.Error.Code, ShouldEqual, http.StatusBadRequ est)
205 So(e.Error.Message, ShouldEqual, "unspecified er ror")
206 })
207
208 Convey(`Can access the "queryreq" endpoint with query pa rameters.`, func() {
209 _, err := c.Get(fmt.Sprintf("%s%s", ts.URL,
210 "/_ah/api/test/v1/queryreq/testname?coun t=12345&S=foo&F=3.14&B=true&B2=false&I=1337"))
211 So(err, ShouldBeNil)
212
213 So(be.body.String(), ShouldEqual,
214 `{"B":true,"B2":false,"F":3.14,"I":1337, "Name":"testname","S":"foo","count":"12345"}`+"\n")
215 })
216
217 Convey(`Will return an error if an invalid "queryreq" qu ery parameter is supplied.`, func() {
218 resp, err := c.Get(fmt.Sprintf("%s%s", ts.URL, " /_ah/api/test/v1/queryreq/testname?count=pi"))
219 So(err, ShouldBeNil)
220
221 e := readErrorResponse(resp)
222 So(e, ShouldNotBeNil)
223 So(e.Error, ShouldNotBeNil)
224 So(e.Error.Code, ShouldEqual, http.StatusBadRequ est)
225 So(e.Error.Message, ShouldEqual, "unspecified er ror")
226 })
227
228 Convey(`Will augment POST data with query parameters.`, func() {
229 _, err := c.Post(fmt.Sprintf("%s%s", ts.URL, "/_ ah/api/test/v1/post?T=bar"),
230 "application/json", bytes.NewBufferStrin g(`{"S":"foo"}`))
231 So(err, ShouldBeNil)
232
233 So(be.body.String(), ShouldEqual, `{"S":"foo","T ":"bar"}`+"\n")
234 })
235
236 Convey(`Will return an error if an invalid endpoint is r equested.`, func() {
237 resp, err := c.Post(fmt.Sprintf("%s%s", ts.URL, "/_ah/api/test/v1/does.not.exist"), "", nil)
238 So(err, ShouldBeNil)
239
240 e := readErrorResponse(resp)
241 So(e, ShouldNotBeNil)
242 So(e.Error, ShouldNotBeNil)
243 So(e.Error.Code, ShouldEqual, http.StatusNotFoun d)
244 So(e.Error.Message, ShouldEqual, "unspecified er ror")
245 })
246
247 Convey(`Will catch backend panic() and wrap it with an e rror.`, func() {
248 didPanic := false
249 be.callback = func(http.ResponseWriter) {
250 didPanic = true
251 panic("test panic")
252 }
253
254 resp, err := c.Post(fmt.Sprintf("%s%s", ts.URL, "/_ah/api/test/v1/post"), "", nil)
255 So(err, ShouldBeNil)
256
257 So(didPanic, ShouldBeTrue)
258
259 e := readErrorResponse(resp)
260 So(e, ShouldNotBeNil)
261 So(e.Error, ShouldNotBeNil)
262 So(e.Error.Code, ShouldEqual, http.StatusService Unavailable)
263 })
264
265 Convey(`Will catch and forward backend JSON errors.`, fu nc() {
266 be.callback = func(w http.ResponseWriter) {
267 w.WriteHeader(http.StatusNotFound)
268 w.Write([]byte(`{"error_message": "test message"}`))
269 }
270
271 resp, err := c.Post(fmt.Sprintf("%s%s", ts.URL, "/_ah/api/test/v1/post"), "", nil)
272 So(err, ShouldBeNil)
273
274 e := readErrorResponse(resp)
275 So(e, ShouldNotBeNil)
276 So(e.Error, ShouldNotBeNil)
277 So(e.Error.Code, ShouldEqual, http.StatusNotFoun d)
278 So(e.Error.Message, ShouldEqual, "test message")
279 })
280
281 Convey(`Will catch non-JSON backend errors and wrap with generic error.`, func() {
282 be.callback = func(w http.ResponseWriter) {
283 w.WriteHeader(http.StatusNotFound)
284 w.Write([]byte("$$NOT JSON$$"))
285 }
286
287 resp, err := c.Post(fmt.Sprintf("%s%s", ts.URL, "/_ah/api/test/v1/post"), "", nil)
288 So(err, ShouldBeNil)
289
290 e := readErrorResponse(resp)
291 So(e, ShouldNotBeNil)
292 So(e.Error, ShouldNotBeNil)
293 So(e.Error.Code, ShouldEqual, http.StatusNotFoun d)
294 So(e.Error.Message, ShouldEqual, "unspecified er ror")
295 So(len(e.Error.Errors), ShouldEqual, 1)
296 So(e.Error.Errors[0].Message, ShouldContainSubst ring, "Failed to decode error JSON")
297 })
298 })
299 })
300 }
OLDNEW
« no previous file with comments | « appengine/ephelper/epfrontend/service.go ('k') | appengine/ephelper/epfrontend/service_testdata/test_directory.json » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698