Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(954)

Side by Side Diff: testservices/novaservice/service_http_test.go

Issue 6924043: Second phase of nova testing service: HTTP API. (Closed)
Patch Set: Second phase of nova testing service: HTTP aPI. Created 11 years, 3 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Nova double testing service - HTTP API tests 1 // Nova double testing service - HTTP API tests
2 2
3 package novaservice 3 package novaservice
4 4
5 import ( 5 import (
6 "bytes"
7 "encoding/json"
8 "io/ioutil"
6 . "launchpad.net/gocheck" 9 . "launchpad.net/gocheck"
10 "launchpad.net/goose/nova"
7 "launchpad.net/goose/testing/httpsuite" 11 "launchpad.net/goose/testing/httpsuite"
12 "net/http"
13 "strconv"
14 "strings"
8 ) 15 )
9 16
10 type NovaHTTPSuite struct { 17 type NovaHTTPSuite struct {
11 httpsuite.HTTPSuite 18 httpsuite.HTTPSuite
12 service *Nova 19 service *Nova
13 } 20 }
14 21
15 var _ = Suite(&NovaHTTPSuite{}) 22 var _ = Suite(&NovaHTTPSuite{})
16 23
17 func (s *NovaHTTPSuite) SetUpSuite(c *C) { 24 func (s *NovaHTTPSuite) SetUpSuite(c *C) {
18 s.HTTPSuite.SetUpSuite(c) 25 s.HTTPSuite.SetUpSuite(c)
19 » s.service = New(s.Server.URL, baseURL, token) 26 » s.service = New(s.Server.URL, baseURL, token, tenantId)
20 } 27 }
21 28
22 func (s *NovaHTTPSuite) TearDownSuite(c *C) { 29 func (s *NovaHTTPSuite) TearDownSuite(c *C) {
23 s.HTTPSuite.TearDownSuite(c) 30 s.HTTPSuite.TearDownSuite(c)
24 } 31 }
25 32
26 func (s *NovaHTTPSuite) SetUpTest(c *C) { 33 func (s *NovaHTTPSuite) SetUpTest(c *C) {
27 s.HTTPSuite.SetUpTest(c) 34 s.HTTPSuite.SetUpTest(c)
28 » s.Mux.Handle(baseURL, s.service) 35 » s.service.setupHTTP(s.Mux)
29 } 36 }
30 37
31 func (s *NovaHTTPSuite) TearDownTest(c *C) { 38 func (s *NovaHTTPSuite) TearDownTest(c *C) {
32 s.HTTPSuite.TearDownTest(c) 39 s.HTTPSuite.TearDownTest(c)
33 } 40 }
41
42 // assertJSON asserts the passed http.Response's body can be
43 // unmarshalled into the passed expected object.
44 func (s *NovaHTTPSuite) assertJSON(c *C, resp *http.Response, expected interface {}) {
fwereade 2012/12/12 15:18:44 Doesn't need to be a method.
dimitern 2012/12/12 17:32:24 Done.
45 body, err := ioutil.ReadAll(resp.Body)
46 defer resp.Body.Close()
47 c.Assert(err, IsNil)
48 err = json.Unmarshal(body, &expected)
49 c.Assert(err, IsNil)
50 }
51
52 // assertBody asserts the passed http.Response's body matches the
53 // expected response, replacing any variables in the expected body.
54 func (s *NovaHTTPSuite) assertBody(c *C, resp *http.Response, expected response) {
fwereade 2012/12/12 15:18:44 ditto
dimitern 2012/12/12 17:32:24 Done.
55 body, err := ioutil.ReadAll(resp.Body)
56 defer resp.Body.Close()
57 c.Assert(err, IsNil)
58 expBody := expected.replaceVars(resp.Request)
59 // cast to string for easier asserts debugging
60 c.Assert(string(body), Equals, string(expBody))
61 }
62
63 // sendRequest constructs an HTTP request from the parameters and
64 // sends it, returning the response or an error.
65 func (s *NovaHTTPSuite) sendRequest(method, url string, body []byte, headers htt p.Header) (*http.Response, error) {
66 if !strings.HasPrefix(url, s.service.hostname) {
67 url = s.service.hostname + strings.TrimLeft(url, "/")
68 }
69 bodyReader := bytes.NewReader(body)
rog 2012/12/12 15:02:33 or inline
dimitern 2012/12/12 17:32:24 Done.
70 req, err := http.NewRequest(method, url, bodyReader)
71 if err != nil {
72 return nil, err
73 }
74 if headers != nil {
rog 2012/12/12 15:02:33 d
dimitern 2012/12/12 17:32:24 Done.
75 for header, values := range headers {
76 for _, value := range values {
77 req.Header.Add(header, value)
78 }
79 }
80 }
81 // workaround for https://code.google.com/p/go/issues/detail?id=4454
rog 2012/12/12 15:02:33 i thought that issue was triggered by the NoConten
dimitern 2012/12/12 17:32:24 Any time when len(body) == 0, hence the transfer-e
rog 2012/12/12 18:12:13 i'd be surprised if that was true. can you reprodu
82 req.Header.Set("Content-Length", strconv.Itoa(len(body)))
83 return http.DefaultClient.Do(req)
84 }
85
86 // authRequest is a shortcut for sending requests with pre-set token
87 // header and correct version prefix and tenant ID in the URL.
88 func (s *NovaHTTPSuite) authRequest(method, path string, body []byte, headers ht tp.Header) (*http.Response, error) {
89 if headers == nil {
90 headers = make(http.Header)
91 }
92 headers.Set(authToken, s.service.token)
93 url := s.service.endpoint(true, path)
94 return s.sendRequest(method, url, body, headers)
95 }
96
97 // jsonRequest serializes the passed body object to JSON and sends a
98 // the request with authRequest().
99 func (s *NovaHTTPSuite) jsonRequest(method, path string, body interface{}, heade rs http.Header) (*http.Response, error) {
100 jsonBody, err := json.Marshal(body)
101 if err != nil {
102 return nil, err
103 }
104 return s.authRequest(method, path, jsonBody, headers)
105 }
106
107 func (s *NovaHTTPSuite) TestUnauthorizedResponse(c *C) {
108 resp, err := s.sendRequest("GET", "/any", nil, nil)
109 c.Assert(err, IsNil)
110 c.Assert(resp.StatusCode, Equals, http.StatusUnauthorized)
111 headers := make(http.Header)
112 headers.Set(authToken, "phony")
113 resp, err = s.sendRequest("POST", "/any", nil, headers)
114 c.Assert(err, IsNil)
115 c.Assert(resp.StatusCode, Equals, http.StatusUnauthorized)
116 s.assertBody(c, resp, unauthorizedResponse)
117 }
118
119 func (s *NovaHTTPSuite) TestNoVersionResponse(c *C) {
120 headers := make(http.Header)
121 headers.Set(authToken, s.service.token)
122 resp, err := s.sendRequest("GET", "/", nil, headers)
123 c.Assert(err, IsNil)
124 c.Assert(resp.StatusCode, Equals, http.StatusOK)
125 s.assertBody(c, resp, noVersionResponse)
126 }
127
128 func (s *NovaHTTPSuite) TestMultipleChoicesResponse(c *C) {
129 headers := make(http.Header)
130 headers.Set(authToken, s.service.token)
131 resp, err := s.sendRequest("GET", "/any", nil, headers)
132 c.Assert(err, IsNil)
133 c.Assert(resp.StatusCode, Equals, http.StatusMultipleChoices)
134 s.assertBody(c, resp, multipleChoicesResponse)
135 resp, err = s.sendRequest("POST", "/any/other/one", nil, headers)
136 c.Assert(err, IsNil)
137 c.Assert(resp.StatusCode, Equals, http.StatusMultipleChoices)
138 s.assertBody(c, resp, multipleChoicesResponse)
139 }
140
141 func (s *NovaHTTPSuite) TestNotFoundResponse(c *C) {
142 resp, err := s.authRequest("GET", "/flavors/", nil, nil)
143 c.Assert(err, IsNil)
144 c.Assert(resp.StatusCode, Equals, http.StatusNotFound)
145 resp, err = s.authRequest("POST", "/any/unknown/one", nil, nil)
146 c.Assert(err, IsNil)
147 c.Assert(resp.StatusCode, Equals, http.StatusNotFound)
148 resp, err = s.authRequest("GET", "/flavors/id", nil, nil)
149 c.Assert(err, IsNil)
150 c.Assert(resp.StatusCode, Equals, http.StatusNotFound)
151 }
152
153 func (s *NovaHTTPSuite) TestBadRequestResponse(c *C) {
154 headers := make(http.Header)
155 headers.Set(authToken, token)
156 resp, err := s.sendRequest("GET", s.service.baseURL+"/phony_token", nil, headers)
157 c.Assert(err, IsNil)
158 c.Assert(resp.StatusCode, Equals, http.StatusBadRequest)
159 s.assertBody(c, resp, badRequestResponse)
rog 2012/12/12 15:02:33 it seems to me that all these bad-status tests cou
dimitern 2012/12/12 17:32:24 I was thinking of it, but was not sure whether it'
160 }
161
162 func (s *NovaHTTPSuite) TestGetFlavors(c *C) {
163 entities := s.service.allFlavorsAsEntities()
164 c.Assert(entities, HasLen, 0)
165 resp, err := s.authRequest("GET", "/flavors", nil, nil)
166 c.Assert(err, IsNil)
167 c.Assert(resp.StatusCode, Equals, http.StatusNoContent)
168 flavors := []nova.FlavorDetail{
169 nova.FlavorDetail{Id: "fl1", Name: "flavor 1"},
170 nova.FlavorDetail{Id: "fl2", Name: "flavor 2"},
171 }
172 for _, flavor := range flavors {
173 s.service.buildFlavorLinks(&flavor)
174 err = s.service.addFlavor(flavor)
175 defer s.service.removeFlavor(flavor.Id)
176 c.Assert(err, IsNil)
177 }
178 entities = s.service.allFlavorsAsEntities()
179 resp, err = s.authRequest("GET", "/flavors", nil, nil)
180 c.Assert(err, IsNil)
181 c.Assert(resp.StatusCode, Equals, http.StatusOK)
182 var expected struct {
183 Flavors []nova.Entity
184 }
185 s.assertJSON(c, resp, expected)
186 }
187
188 func (s *NovaHTTPSuite) TestGetInvalidFlavorsFails(c *C) {
189 flavor := nova.FlavorDetail{Id: "1"}
190 err := s.service.addFlavor(flavor)
191 c.Assert(err, IsNil)
192 defer s.service.removeFlavor("1")
193 resp, err := s.authRequest("GET", "/flavors/invalid", nil, nil)
194 c.Assert(err, IsNil)
195 c.Assert(resp.StatusCode, Equals, http.StatusNotFound)
196 s.assertBody(c, resp, notFoundResponse)
197 }
198
199 func (s *NovaHTTPSuite) TestPostInvalidFlavorsFails(c *C) {
200 resp, err := s.authRequest("POST", "/flavors/invalid", nil, nil)
201 c.Assert(err, IsNil)
202 c.Assert(resp.StatusCode, Equals, http.StatusNotFound)
203 s.assertBody(c, resp, notFoundResponse)
204 }
205
206 func (s *NovaHTTPSuite) TestPostEmptyFlavorsFails(c *C) {
207 resp, err := s.authRequest("POST", "/flavors", nil, nil)
208 c.Assert(err, IsNil)
209 c.Assert(resp.StatusCode, Equals, http.StatusBadRequest)
210 s.assertBody(c, resp, badRequest2Response)
211 }
212
213 func (s *NovaHTTPSuite) TestPostValidFlavorSucceeds(c *C) {
214 _, err := s.service.flavor("fl1")
215 c.Assert(err, NotNil)
216 var req struct {
217 Flavor nova.FlavorDetail `json:"flavor"`
218 }
219 req.Flavor = nova.FlavorDetail{Id: "fl1", Name: "flavor 1"}
220 resp, err := s.jsonRequest("POST", "/flavors", req, nil)
221 c.Assert(err, IsNil)
222 c.Assert(resp.StatusCode, Equals, http.StatusCreated)
223 s.assertBody(c, resp, createdResponse)
224 _, err = s.service.flavor("fl1")
225 c.Assert(err, IsNil)
226 s.service.removeFlavor("fl1")
227 }
228
229 func (s *NovaHTTPSuite) TestPutFlavorsFails(c *C) {
230 resp, err := s.authRequest("PUT", "/flavors", nil, nil)
231 c.Assert(err, IsNil)
232 c.Assert(resp.StatusCode, Equals, http.StatusNotFound)
233 s.assertBody(c, resp, notFoundResponse)
234 }
235
236 func (s *NovaHTTPSuite) TestDeleteFlavorsFails(c *C) {
237 resp, err := s.authRequest("DELETE", "/flavors", nil, nil)
238 c.Assert(err, IsNil)
239 c.Assert(resp.StatusCode, Equals, http.StatusNotFound)
240 s.assertBody(c, resp, notFoundResponse)
241 }
242
243 func (s *NovaHTTPSuite) TestGetFlavorsDetail(c *C) {
244 flavors := s.service.allFlavors()
245 c.Assert(flavors, HasLen, 0)
246 resp, err := s.authRequest("GET", "/flavors/detail", nil, nil)
247 c.Assert(err, IsNil)
248 c.Assert(resp.StatusCode, Equals, http.StatusNoContent)
249 flavors = []nova.FlavorDetail{
250 nova.FlavorDetail{Id: "fl1", Name: "flavor 1"},
251 nova.FlavorDetail{Id: "fl2", Name: "flavor 2"},
252 }
253 for _, flavor := range flavors {
254 s.service.buildFlavorLinks(&flavor)
255 err = s.service.addFlavor(flavor)
256 defer s.service.removeFlavor(flavor.Id)
257 c.Assert(err, IsNil)
258 }
259 resp, err = s.authRequest("GET", "/flavors/detail", nil, nil)
260 c.Assert(err, IsNil)
261 c.Assert(resp.StatusCode, Equals, http.StatusOK)
262 var expected struct {
263 Flavors []nova.FlavorDetail
264 }
265 s.assertJSON(c, resp, expected)
266 }
267
268 func (s *NovaHTTPSuite) TestPostFlavorsDetailFails(c *C) {
269 resp, err := s.authRequest("POST", "/flavors/detail", nil, nil)
270 c.Assert(err, IsNil)
271 c.Assert(resp.StatusCode, Equals, http.StatusNotFound)
272 s.assertBody(c, resp, notFoundResponse)
273 }
274
275 func (s *NovaHTTPSuite) TestPutFlavorsDetailFails(c *C) {
276 resp, err := s.authRequest("PUT", "/flavors/detail", nil, nil)
277 c.Assert(err, IsNil)
278 c.Assert(resp.StatusCode, Equals, http.StatusNotFound)
279 s.assertBody(c, resp, notFoundJSONResponse)
280 }
281
282 func (s *NovaHTTPSuite) TestDeleteFlavorsDetailFails(c *C) {
283 resp, err := s.authRequest("DELETE", "/flavors/detail", nil, nil)
284 c.Assert(err, IsNil)
285 c.Assert(resp.StatusCode, Equals, http.StatusForbidden)
286 s.assertBody(c, resp, forbiddenResponse)
287 }
fwereade 2012/12/12 15:18:44 These quick error tests would be great for a table
dimitern 2012/12/12 17:32:24 As discussed, I can implement table-based approach
OLDNEW

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b