~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/gopkg.in/goose.v1/testservices/novaservice/service_http_test.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Nova double testing service - HTTP API tests
 
2
 
 
3
package novaservice
 
4
 
 
5
import (
 
6
        "bytes"
 
7
        "encoding/json"
 
8
        "fmt"
 
9
        "io/ioutil"
 
10
        "net/http"
 
11
        "sort"
 
12
        "strconv"
 
13
        "strings"
 
14
 
 
15
        gc "gopkg.in/check.v1"
 
16
 
 
17
        "gopkg.in/goose.v1/nova"
 
18
        "gopkg.in/goose.v1/testing/httpsuite"
 
19
        "gopkg.in/goose.v1/testservices/hook"
 
20
        "gopkg.in/goose.v1/testservices/identityservice"
 
21
)
 
22
 
 
23
type NovaHTTPSuite struct {
 
24
        httpsuite.HTTPSuite
 
25
        service *Nova
 
26
        token   string
 
27
}
 
28
 
 
29
var _ = gc.Suite(&NovaHTTPSuite{})
 
30
 
 
31
type NovaHTTPSSuite struct {
 
32
        httpsuite.HTTPSuite
 
33
        service *Nova
 
34
        token   string
 
35
}
 
36
 
 
37
var _ = gc.Suite(&NovaHTTPSSuite{HTTPSuite: httpsuite.HTTPSuite{UseTLS: true}})
 
38
 
 
39
func (s *NovaHTTPSuite) SetUpSuite(c *gc.C) {
 
40
        s.HTTPSuite.SetUpSuite(c)
 
41
        identityDouble := identityservice.NewUserPass()
 
42
        userInfo := identityDouble.AddUser("fred", "secret", "tenant")
 
43
        s.token = userInfo.Token
 
44
        s.service = New(s.Server.URL, versionPath, userInfo.TenantId, region, identityDouble, nil)
 
45
}
 
46
 
 
47
func (s *NovaHTTPSuite) TearDownSuite(c *gc.C) {
 
48
        s.HTTPSuite.TearDownSuite(c)
 
49
}
 
50
 
 
51
func (s *NovaHTTPSuite) SetUpTest(c *gc.C) {
 
52
        s.HTTPSuite.SetUpTest(c)
 
53
        s.service.SetupHTTP(s.Mux)
 
54
        // this is otherwise handled not directly by nova test service
 
55
        // but by openstack that tries for / before.
 
56
        s.Mux.Handle("/", s.service.handler((*Nova).handleRoot))
 
57
}
 
58
 
 
59
func (s *NovaHTTPSuite) TearDownTest(c *gc.C) {
 
60
        s.HTTPSuite.TearDownTest(c)
 
61
}
 
62
 
 
63
// assertJSON asserts the passed http.Response's body can be
 
64
// unmarshalled into the given expected object, populating it with the
 
65
// successfully parsed data.
 
66
func assertJSON(c *gc.C, resp *http.Response, expected interface{}) {
 
67
        body, err := ioutil.ReadAll(resp.Body)
 
68
        defer resp.Body.Close()
 
69
        c.Assert(err, gc.IsNil)
 
70
        err = json.Unmarshal(body, &expected)
 
71
        c.Assert(err, gc.IsNil)
 
72
}
 
73
 
 
74
// assertBody asserts the passed http.Response's body matches the
 
75
// expected response, replacing any variables in the expected body.
 
76
func assertBody(c *gc.C, resp *http.Response, expected *errorResponse) {
 
77
        body, err := ioutil.ReadAll(resp.Body)
 
78
        defer resp.Body.Close()
 
79
        c.Assert(err, gc.IsNil)
 
80
        expBody := expected.requestBody(resp.Request)
 
81
        // cast to string for easier asserts debugging
 
82
        c.Assert(string(body), gc.Equals, string(expBody))
 
83
}
 
84
 
 
85
// sendRequest constructs an HTTP request from the parameters and
 
86
// sends it, returning the response or an error.
 
87
func (s *NovaHTTPSuite) sendRequest(method, url string, body []byte, headers http.Header) (*http.Response, error) {
 
88
        if !strings.HasPrefix(url, "http") {
 
89
                url = "http://" + s.service.Hostname + strings.TrimLeft(url, "/")
 
90
        }
 
91
        req, err := http.NewRequest(method, url, bytes.NewReader(body))
 
92
        if err != nil {
 
93
                return nil, err
 
94
        }
 
95
        for header, values := range headers {
 
96
                for _, value := range values {
 
97
                        req.Header.Add(header, value)
 
98
                }
 
99
        }
 
100
        // workaround for https://code.google.com/p/go/issues/detail?id=4454
 
101
        req.Header.Set("Content-Length", strconv.Itoa(len(body)))
 
102
        return http.DefaultClient.Do(req)
 
103
}
 
104
 
 
105
// authRequest is a shortcut for sending requests with pre-set token
 
106
// header and correct version prefix and tenant ID in the URL.
 
107
func (s *NovaHTTPSuite) authRequest(method, path string, body []byte, headers http.Header) (*http.Response, error) {
 
108
        if headers == nil {
 
109
                headers = make(http.Header)
 
110
        }
 
111
        headers.Set(authToken, s.token)
 
112
        url := s.service.endpointURL(true, path)
 
113
        return s.sendRequest(method, url, body, headers)
 
114
}
 
115
 
 
116
// jsonRequest serializes the passed body object to JSON and sends a
 
117
// the request with authRequest().
 
118
func (s *NovaHTTPSuite) jsonRequest(method, path string, body interface{}, headers http.Header) (*http.Response, error) {
 
119
        jsonBody, err := json.Marshal(body)
 
120
        if err != nil {
 
121
                return nil, err
 
122
        }
 
123
        return s.authRequest(method, path, jsonBody, headers)
 
124
}
 
125
 
 
126
// setHeader creates http.Header map, sets the given header, and
 
127
// returns the map.
 
128
func setHeader(header, value string) http.Header {
 
129
        h := make(http.Header)
 
130
        h.Set(header, value)
 
131
        return h
 
132
}
 
133
 
 
134
// SimpleTest defines a simple request without a body and expected response.
 
135
type SimpleTest struct {
 
136
        unauth  bool
 
137
        method  string
 
138
        url     string
 
139
        headers http.Header
 
140
        expect  *errorResponse
 
141
}
 
142
 
 
143
func (s *NovaHTTPSuite) simpleTests() []SimpleTest {
 
144
        var simpleTests = []SimpleTest{
 
145
                {
 
146
                        unauth:  true,
 
147
                        method:  "GET",
 
148
                        url:     "/any",
 
149
                        headers: make(http.Header),
 
150
                        expect:  errUnauthorized,
 
151
                },
 
152
                {
 
153
                        unauth:  true,
 
154
                        method:  "POST",
 
155
                        url:     "/any",
 
156
                        headers: setHeader(authToken, "phony"),
 
157
                        expect:  errUnauthorized,
 
158
                },
 
159
                {
 
160
                        unauth:  true,
 
161
                        method:  "GET",
 
162
                        url:     "/any",
 
163
                        headers: setHeader(authToken, s.token),
 
164
                        expect:  errMultipleChoices,
 
165
                },
 
166
                {
 
167
                        unauth:  true,
 
168
                        method:  "POST",
 
169
                        url:     "/any/unknown/one",
 
170
                        headers: setHeader(authToken, s.token),
 
171
                        expect:  errMultipleChoices,
 
172
                },
 
173
                {
 
174
                        method: "POST",
 
175
                        url:    "/any/unknown/one",
 
176
                        expect: errNotFound,
 
177
                },
 
178
                {
 
179
                        unauth:  true,
 
180
                        method:  "GET",
 
181
                        url:     versionPath + "/phony_token",
 
182
                        headers: setHeader(authToken, s.token),
 
183
                        expect:  errBadRequest,
 
184
                },
 
185
                {
 
186
                        method: "GET",
 
187
                        url:    "/flavors/",
 
188
                        expect: errNotFound,
 
189
                },
 
190
                {
 
191
                        method: "GET",
 
192
                        url:    "/flavors/invalid",
 
193
                        expect: errNotFound,
 
194
                },
 
195
                {
 
196
                        method: "POST",
 
197
                        url:    "/flavors",
 
198
                        expect: errBadRequest2,
 
199
                },
 
200
                {
 
201
                        method: "POST",
 
202
                        url:    "/flavors/invalid",
 
203
                        expect: errNotFound,
 
204
                },
 
205
                {
 
206
                        method: "PUT",
 
207
                        url:    "/flavors",
 
208
                        expect: errNotFound,
 
209
                },
 
210
                {
 
211
                        method: "PUT",
 
212
                        url:    "/flavors/invalid",
 
213
                        expect: errNotFoundJSON,
 
214
                },
 
215
                {
 
216
                        method: "DELETE",
 
217
                        url:    "/flavors",
 
218
                        expect: errNotFound,
 
219
                },
 
220
                {
 
221
                        method: "DELETE",
 
222
                        url:    "/flavors/invalid",
 
223
                        expect: errForbidden,
 
224
                },
 
225
                {
 
226
                        method: "GET",
 
227
                        url:    "/flavors/detail/invalid",
 
228
                        expect: errNotFound,
 
229
                },
 
230
                {
 
231
                        method: "POST",
 
232
                        url:    "/flavors/detail",
 
233
                        expect: errNotFound,
 
234
                },
 
235
                {
 
236
                        method: "POST",
 
237
                        url:    "/flavors/detail/invalid",
 
238
                        expect: errNotFound,
 
239
                },
 
240
                {
 
241
                        method: "PUT",
 
242
                        url:    "/flavors/detail",
 
243
                        expect: errNotFoundJSON,
 
244
                },
 
245
                {
 
246
                        method: "PUT",
 
247
                        url:    "/flavors/detail/invalid",
 
248
                        expect: errNotFound,
 
249
                },
 
250
                {
 
251
                        method: "DELETE",
 
252
                        url:    "/flavors/detail",
 
253
                        expect: errForbidden,
 
254
                },
 
255
                {
 
256
                        method: "DELETE",
 
257
                        url:    "/flavors/detail/invalid",
 
258
                        expect: errNotFound,
 
259
                },
 
260
                {
 
261
                        method: "GET",
 
262
                        url:    "/servers/invalid",
 
263
                        expect: &errorResponse{code: 404, body: "{\"itemNotFound\":{\"message\":\"No such server \\\"invalid\\\"\", \"code\":404}}"},
 
264
                },
 
265
                {
 
266
                        method: "POST",
 
267
                        url:    "/servers",
 
268
                        expect: errBadRequest2,
 
269
                },
 
270
                {
 
271
                        method: "POST",
 
272
                        url:    "/servers/invalid",
 
273
                        expect: errNotFound,
 
274
                },
 
275
                {
 
276
                        method: "PUT",
 
277
                        url:    "/servers",
 
278
                        expect: errNotFound,
 
279
                },
 
280
                {
 
281
                        method: "PUT",
 
282
                        url:    "/servers/invalid",
 
283
                        expect: errBadRequest2,
 
284
                },
 
285
                {
 
286
                        method: "DELETE",
 
287
                        url:    "/servers",
 
288
                        expect: errNotFound,
 
289
                },
 
290
                {
 
291
                        method: "DELETE",
 
292
                        url:    "/servers/invalid",
 
293
                        expect: errNotFoundJSON,
 
294
                },
 
295
                {
 
296
                        method: "GET",
 
297
                        url:    "/servers/detail/invalid",
 
298
                        expect: errNotFound,
 
299
                },
 
300
                {
 
301
                        method: "POST",
 
302
                        url:    "/servers/detail",
 
303
                        expect: errNotFound,
 
304
                },
 
305
                {
 
306
                        method: "POST",
 
307
                        url:    "/servers/detail/invalid",
 
308
                        expect: errNotFound,
 
309
                },
 
310
                {
 
311
                        method: "PUT",
 
312
                        url:    "/servers/detail",
 
313
                        expect: errBadRequest2,
 
314
                },
 
315
                {
 
316
                        method: "PUT",
 
317
                        url:    "/servers/detail/invalid",
 
318
                        expect: errNotFound,
 
319
                },
 
320
                {
 
321
                        method: "DELETE",
 
322
                        url:    "/servers/detail",
 
323
                        expect: errNotFoundJSON,
 
324
                },
 
325
                {
 
326
                        method: "DELETE",
 
327
                        url:    "/servers/detail/invalid",
 
328
                        expect: errNotFound,
 
329
                },
 
330
                {
 
331
                        method: "GET",
 
332
                        url:    "/os-security-groups/42",
 
333
                        expect: errNotFoundJSONSG,
 
334
                },
 
335
                {
 
336
                        method: "POST",
 
337
                        url:    "/os-security-groups",
 
338
                        expect: errBadRequest2,
 
339
                },
 
340
                {
 
341
                        method: "POST",
 
342
                        url:    "/os-security-groups/invalid",
 
343
                        expect: errNotFound,
 
344
                },
 
345
                {
 
346
                        method: "PUT",
 
347
                        url:    "/os-security-groups",
 
348
                        expect: errNotFound,
 
349
                },
 
350
                {
 
351
                        method: "PUT",
 
352
                        url:    "/os-security-groups/invalid",
 
353
                        expect: errNotFoundJSONSG,
 
354
                },
 
355
                {
 
356
                        method: "DELETE",
 
357
                        url:    "/os-security-groups",
 
358
                        expect: errNotFound,
 
359
                },
 
360
                {
 
361
                        method: "DELETE",
 
362
                        url:    "/os-security-groups/42",
 
363
                        expect: errNotFoundJSONSG,
 
364
                },
 
365
                {
 
366
                        method: "GET",
 
367
                        url:    "/os-security-group-rules",
 
368
                        expect: errNotFoundJSON,
 
369
                },
 
370
                {
 
371
                        method: "GET",
 
372
                        url:    "/os-security-group-rules/invalid",
 
373
                        expect: errNotFoundJSON,
 
374
                },
 
375
                {
 
376
                        method: "GET",
 
377
                        url:    "/os-security-group-rules/42",
 
378
                        expect: errNotFoundJSON,
 
379
                },
 
380
                {
 
381
                        method: "POST",
 
382
                        url:    "/os-security-group-rules",
 
383
                        expect: errBadRequest2,
 
384
                },
 
385
                {
 
386
                        method: "POST",
 
387
                        url:    "/os-security-group-rules/invalid",
 
388
                        expect: errNotFound,
 
389
                },
 
390
                {
 
391
                        method: "PUT",
 
392
                        url:    "/os-security-group-rules",
 
393
                        expect: errNotFound,
 
394
                },
 
395
                {
 
396
                        method: "PUT",
 
397
                        url:    "/os-security-group-rules/invalid",
 
398
                        expect: errNotFoundJSON,
 
399
                },
 
400
                {
 
401
                        method: "DELETE",
 
402
                        url:    "/os-security-group-rules",
 
403
                        expect: errNotFound,
 
404
                },
 
405
                {
 
406
                        method: "DELETE",
 
407
                        url:    "/os-security-group-rules/42",
 
408
                        expect: errNotFoundJSONSGR,
 
409
                },
 
410
                {
 
411
                        method: "GET",
 
412
                        url:    "/os-floating-ips/42",
 
413
                        expect: errNotFoundJSON,
 
414
                },
 
415
                {
 
416
                        method: "POST",
 
417
                        url:    "/os-floating-ips/invalid",
 
418
                        expect: errNotFound,
 
419
                },
 
420
                {
 
421
                        method: "PUT",
 
422
                        url:    "/os-floating-ips",
 
423
                        expect: errNotFound,
 
424
                },
 
425
                {
 
426
                        method: "PUT",
 
427
                        url:    "/os-floating-ips/invalid",
 
428
                        expect: errNotFoundJSON,
 
429
                },
 
430
                {
 
431
                        method: "DELETE",
 
432
                        url:    "/os-floating-ips",
 
433
                        expect: errNotFound,
 
434
                },
 
435
                {
 
436
                        method: "DELETE",
 
437
                        url:    "/os-floating-ips/invalid",
 
438
                        expect: errNotFoundJSON,
 
439
                },
 
440
        }
 
441
        return simpleTests
 
442
}
 
443
 
 
444
func (s *NovaHTTPSuite) TestSimpleRequestTests(c *gc.C) {
 
445
        simpleTests := s.simpleTests()
 
446
        for i, t := range simpleTests {
 
447
                c.Logf("#%d. %s %s -> %d", i, t.method, t.url, t.expect.code)
 
448
                if t.headers == nil {
 
449
                        t.headers = make(http.Header)
 
450
                        t.headers.Set(authToken, s.token)
 
451
                }
 
452
                var (
 
453
                        resp *http.Response
 
454
                        err  error
 
455
                )
 
456
                if t.unauth {
 
457
                        resp, err = s.sendRequest(t.method, t.url, nil, t.headers)
 
458
                } else {
 
459
                        resp, err = s.authRequest(t.method, t.url, nil, t.headers)
 
460
                }
 
461
                c.Assert(err, gc.IsNil)
 
462
                c.Assert(resp.StatusCode, gc.Equals, t.expect.code)
 
463
                assertBody(c, resp, t.expect)
 
464
        }
 
465
        fmt.Printf("total: %d\n", len(simpleTests))
 
466
}
 
467
 
 
468
func (s *NovaHTTPSuite) TestGetFlavors(c *gc.C) {
 
469
        // The test service has 3 default flavours.
 
470
        var expected struct {
 
471
                Flavors []nova.Entity
 
472
        }
 
473
        resp, err := s.authRequest("GET", "/flavors", nil, nil)
 
474
        c.Assert(err, gc.IsNil)
 
475
        c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
 
476
        assertJSON(c, resp, &expected)
 
477
        c.Assert(expected.Flavors, gc.HasLen, 3)
 
478
        entities := s.service.allFlavorsAsEntities()
 
479
        c.Assert(entities, gc.HasLen, 3)
 
480
        sort.Sort(nova.EntitySortBy{Attr: "Id", Entities: expected.Flavors})
 
481
        sort.Sort(nova.EntitySortBy{Attr: "Id", Entities: entities})
 
482
        c.Assert(expected.Flavors, gc.DeepEquals, entities)
 
483
        var expectedFlavor struct {
 
484
                Flavor nova.FlavorDetail
 
485
        }
 
486
        resp, err = s.authRequest("GET", "/flavors/1", nil, nil)
 
487
        c.Assert(err, gc.IsNil)
 
488
        c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
 
489
        assertJSON(c, resp, &expectedFlavor)
 
490
        c.Assert(expectedFlavor.Flavor.Name, gc.Equals, "m1.tiny")
 
491
}
 
492
 
 
493
func (s *NovaHTTPSuite) TestGetFlavorsDetail(c *gc.C) {
 
494
        // The test service has 3 default flavours.
 
495
        flavors := s.service.allFlavors()
 
496
        c.Assert(flavors, gc.HasLen, 3)
 
497
        var expected struct {
 
498
                Flavors []nova.FlavorDetail
 
499
        }
 
500
        resp, err := s.authRequest("GET", "/flavors/detail", nil, nil)
 
501
        c.Assert(err, gc.IsNil)
 
502
        c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
 
503
        assertJSON(c, resp, &expected)
 
504
        c.Assert(expected.Flavors, gc.HasLen, 3)
 
505
        sort.Sort(nova.FlavorDetailSortBy{Attr: "Id", FlavorDetails: expected.Flavors})
 
506
        sort.Sort(nova.FlavorDetailSortBy{Attr: "Id", FlavorDetails: flavors})
 
507
        c.Assert(expected.Flavors, gc.DeepEquals, flavors)
 
508
        resp, err = s.authRequest("GET", "/flavors/detail/1", nil, nil)
 
509
        c.Assert(err, gc.IsNil)
 
510
        assertBody(c, resp, errNotFound)
 
511
}
 
512
 
 
513
func (s *NovaHTTPSuite) TestGetServers(c *gc.C) {
 
514
        entities, err := s.service.allServersAsEntities(nil)
 
515
        c.Assert(err, gc.IsNil)
 
516
        c.Assert(entities, gc.HasLen, 0)
 
517
        var expected struct {
 
518
                Servers []nova.Entity
 
519
        }
 
520
        resp, err := s.authRequest("GET", "/servers", nil, nil)
 
521
        c.Assert(err, gc.IsNil)
 
522
        c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
 
523
        assertJSON(c, resp, &expected)
 
524
        c.Assert(expected.Servers, gc.HasLen, 0)
 
525
        servers := []nova.ServerDetail{
 
526
                {Id: "sr1", Name: "server 1"},
 
527
                {Id: "sr2", Name: "server 2"},
 
528
        }
 
529
        for i, server := range servers {
 
530
                s.service.buildServerLinks(&server)
 
531
                servers[i] = server
 
532
                err := s.service.addServer(server)
 
533
                c.Assert(err, gc.IsNil)
 
534
                defer s.service.removeServer(server.Id)
 
535
        }
 
536
        entities, err = s.service.allServersAsEntities(nil)
 
537
        c.Assert(err, gc.IsNil)
 
538
        resp, err = s.authRequest("GET", "/servers", nil, nil)
 
539
        c.Assert(err, gc.IsNil)
 
540
        c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
 
541
        assertJSON(c, resp, &expected)
 
542
        c.Assert(expected.Servers, gc.HasLen, 2)
 
543
        if expected.Servers[0].Id != entities[0].Id {
 
544
                expected.Servers[0], expected.Servers[1] = expected.Servers[1], expected.Servers[0]
 
545
        }
 
546
        c.Assert(expected.Servers, gc.DeepEquals, entities)
 
547
        var expectedServer struct {
 
548
                Server nova.ServerDetail
 
549
        }
 
550
        resp, err = s.authRequest("GET", "/servers/sr1", nil, nil)
 
551
        c.Assert(err, gc.IsNil)
 
552
        c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
 
553
        assertJSON(c, resp, &expectedServer)
 
554
        c.Assert(expectedServer.Server, gc.DeepEquals, servers[0])
 
555
}
 
556
 
 
557
func (s *NovaHTTPSuite) TestGetServersWithFilters(c *gc.C) {
 
558
        entities, err := s.service.allServersAsEntities(nil)
 
559
        c.Assert(err, gc.IsNil)
 
560
        c.Assert(entities, gc.HasLen, 0)
 
561
        var expected struct {
 
562
                Servers []nova.Entity
 
563
        }
 
564
        url := "/servers?status=RESCUE&status=BUILD&name=srv2&name=srv1"
 
565
        resp, err := s.authRequest("GET", url, nil, nil)
 
566
        c.Assert(err, gc.IsNil)
 
567
        c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
 
568
        assertJSON(c, resp, &expected)
 
569
        c.Assert(expected.Servers, gc.HasLen, 0)
 
570
        servers := []nova.ServerDetail{
 
571
                {Id: "sr1", Name: "srv1", Status: nova.StatusBuild},
 
572
                {Id: "sr2", Name: "srv2", Status: nova.StatusRescue},
 
573
                {Id: "sr3", Name: "srv3", Status: nova.StatusActive},
 
574
        }
 
575
        for i, server := range servers {
 
576
                s.service.buildServerLinks(&server)
 
577
                servers[i] = server
 
578
                err := s.service.addServer(server)
 
579
                c.Assert(err, gc.IsNil)
 
580
                defer s.service.removeServer(server.Id)
 
581
        }
 
582
        resp, err = s.authRequest("GET", url, nil, nil)
 
583
        c.Assert(err, gc.IsNil)
 
584
        c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
 
585
        assertJSON(c, resp, &expected)
 
586
        c.Assert(expected.Servers, gc.HasLen, 1)
 
587
        c.Assert(expected.Servers[0].Id, gc.Equals, servers[0].Id)
 
588
        c.Assert(expected.Servers[0].Name, gc.Equals, servers[0].Name)
 
589
}
 
590
 
 
591
func (s *NovaHTTPSuite) TestGetServersWithBadFilter(c *gc.C) {
 
592
        url := "/servers?name=(server"
 
593
        resp, err := s.authRequest("GET", url, nil, nil)
 
594
        c.Assert(err, gc.IsNil)
 
595
        c.Assert(resp.StatusCode, gc.Equals, http.StatusInternalServerError)
 
596
        type novaError struct {
 
597
                Code    int
 
598
                Message string
 
599
        }
 
600
        var expected struct {
 
601
                novaError `json:"computeFault"`
 
602
        }
 
603
        assertJSON(c, resp, &expected)
 
604
        c.Check(expected.Code, gc.Equals, 500)
 
605
        c.Check(expected.Message, gc.Matches, `error parsing.*\(server.*`)
 
606
}
 
607
 
 
608
func (s *NovaHTTPSuite) TestGetServersPatchMatch(c *gc.C) {
 
609
        cleanup := s.service.RegisterControlPoint(
 
610
                "matchServers",
 
611
                func(sc hook.ServiceControl, args ...interface{}) error {
 
612
                        return fmt.Errorf("Unexpected error")
 
613
                },
 
614
        )
 
615
        defer cleanup()
 
616
        resp, err := s.authRequest("GET", "/servers", nil, nil)
 
617
        c.Assert(err, gc.IsNil)
 
618
        c.Assert(resp.StatusCode, gc.Equals, http.StatusInternalServerError)
 
619
        type novaError struct {
 
620
                Code    int
 
621
                Message string
 
622
        }
 
623
        var expected struct {
 
624
                novaError `json:"computeFault"`
 
625
        }
 
626
        assertJSON(c, resp, &expected)
 
627
        c.Check(expected.Code, gc.Equals, 500)
 
628
        c.Check(expected.Message, gc.Equals, "Unexpected error")
 
629
}
 
630
 
 
631
func (s *NovaHTTPSuite) TestNewUUID(c *gc.C) {
 
632
        uuid, err := newUUID()
 
633
        c.Assert(err, gc.IsNil)
 
634
        var p1, p2, p3, p4, p5 string
 
635
        num, err := fmt.Sscanf(uuid, "%8x-%4x-%4x-%4x-%12x", &p1, &p2, &p3, &p4, &p5)
 
636
        c.Assert(err, gc.IsNil)
 
637
        c.Assert(num, gc.Equals, 5)
 
638
        uuid2, err := newUUID()
 
639
        c.Assert(err, gc.IsNil)
 
640
        c.Assert(uuid2, gc.Not(gc.Equals), uuid)
 
641
}
 
642
 
 
643
func (s *NovaHTTPSuite) assertAddresses(c *gc.C, serverId string) {
 
644
        server, err := s.service.server(serverId)
 
645
        c.Assert(err, gc.IsNil)
 
646
        c.Assert(server.Addresses, gc.HasLen, 2)
 
647
        c.Assert(server.Addresses["public"], gc.HasLen, 2)
 
648
        c.Assert(server.Addresses["private"], gc.HasLen, 2)
 
649
        for network, addresses := range server.Addresses {
 
650
                for _, addr := range addresses {
 
651
                        if addr.Version == 4 && network == "public" {
 
652
                                c.Assert(addr.Address, gc.Matches, `127\.10\.0\.\d{1,3}`)
 
653
                        } else if addr.Version == 4 && network == "private" {
 
654
                                c.Assert(addr.Address, gc.Matches, `127\.0\.0\.\d{1,3}`)
 
655
                        }
 
656
                }
 
657
 
 
658
        }
 
659
}
 
660
 
 
661
func (s *NovaHTTPSuite) TestRunServer(c *gc.C) {
 
662
        entities, err := s.service.allServersAsEntities(nil)
 
663
        c.Assert(err, gc.IsNil)
 
664
        c.Assert(entities, gc.HasLen, 0)
 
665
        var req struct {
 
666
                Server struct {
 
667
                        FlavorRef      string              `json:"flavorRef"`
 
668
                        ImageRef       string              `json:"imageRef"`
 
669
                        Name           string              `json:"name"`
 
670
                        SecurityGroups []map[string]string `json:"security_groups"`
 
671
                } `json:"server"`
 
672
        }
 
673
        resp, err := s.jsonRequest("POST", "/servers", req, nil)
 
674
        c.Assert(err, gc.IsNil)
 
675
        c.Assert(resp.StatusCode, gc.Equals, http.StatusBadRequest)
 
676
        assertBody(c, resp, errBadRequestSrvName)
 
677
        req.Server.Name = "srv1"
 
678
        resp, err = s.jsonRequest("POST", "/servers", req, nil)
 
679
        c.Assert(err, gc.IsNil)
 
680
        c.Assert(resp.StatusCode, gc.Equals, http.StatusBadRequest)
 
681
        assertBody(c, resp, errBadRequestSrvImage)
 
682
        req.Server.ImageRef = "image"
 
683
        resp, err = s.jsonRequest("POST", "/servers", req, nil)
 
684
        c.Assert(err, gc.IsNil)
 
685
        c.Assert(resp.StatusCode, gc.Equals, http.StatusBadRequest)
 
686
        assertBody(c, resp, errBadRequestSrvFlavor)
 
687
        req.Server.FlavorRef = "flavor"
 
688
        var expected struct {
 
689
                Server struct {
 
690
                        SecurityGroups []map[string]string `json:"security_groups"`
 
691
                        Id             string
 
692
                        Links          []nova.Link
 
693
                        AdminPass      string
 
694
                }
 
695
        }
 
696
        resp, err = s.jsonRequest("POST", "/servers", req, nil)
 
697
        c.Assert(err, gc.IsNil)
 
698
        c.Assert(resp.StatusCode, gc.Equals, http.StatusAccepted)
 
699
        assertJSON(c, resp, &expected)
 
700
        c.Assert(expected.Server.SecurityGroups, gc.HasLen, 1)
 
701
        c.Assert(expected.Server.SecurityGroups[0]["name"], gc.Equals, "default")
 
702
        c.Assert(expected.Server.Id, gc.Not(gc.Equals), "")
 
703
        c.Assert(expected.Server.Links, gc.HasLen, 2)
 
704
        c.Assert(expected.Server.AdminPass, gc.Not(gc.Equals), "")
 
705
        s.assertAddresses(c, expected.Server.Id)
 
706
        srv, err := s.service.server(expected.Server.Id)
 
707
        c.Assert(err, gc.IsNil)
 
708
        c.Assert(srv.Links, gc.DeepEquals, expected.Server.Links)
 
709
        s.service.removeServer(srv.Id)
 
710
        req.Server.Name = "test2"
 
711
        req.Server.SecurityGroups = []map[string]string{
 
712
                {"name": "default"},
 
713
                {"name": "group1"},
 
714
                {"name": "group2"},
 
715
        }
 
716
        err = s.service.addSecurityGroup(nova.SecurityGroup{Id: "1", Name: "group1"})
 
717
        c.Assert(err, gc.IsNil)
 
718
        defer s.service.removeSecurityGroup("1")
 
719
        err = s.service.addSecurityGroup(nova.SecurityGroup{Id: "2", Name: "group2"})
 
720
        c.Assert(err, gc.IsNil)
 
721
        defer s.service.removeSecurityGroup("2")
 
722
        resp, err = s.jsonRequest("POST", "/servers", req, nil)
 
723
        c.Assert(err, gc.IsNil)
 
724
        c.Assert(resp.StatusCode, gc.Equals, http.StatusAccepted)
 
725
        assertJSON(c, resp, &expected)
 
726
        c.Assert(expected.Server.SecurityGroups, gc.DeepEquals, req.Server.SecurityGroups)
 
727
        srv, err = s.service.server(expected.Server.Id)
 
728
        c.Assert(err, gc.IsNil)
 
729
        ok := s.service.hasServerSecurityGroup(srv.Id, "1")
 
730
        c.Assert(ok, gc.Equals, true)
 
731
        ok = s.service.hasServerSecurityGroup(srv.Id, "2")
 
732
        c.Assert(ok, gc.Equals, true)
 
733
        ok = s.service.hasServerSecurityGroup(srv.Id, "999")
 
734
        c.Assert(ok, gc.Equals, true)
 
735
        s.service.removeServerSecurityGroup(srv.Id, "1")
 
736
        s.service.removeServerSecurityGroup(srv.Id, "2")
 
737
        s.service.removeServerSecurityGroup(srv.Id, "999")
 
738
        s.service.removeServer(srv.Id)
 
739
}
 
740
 
 
741
func (s *NovaHTTPSuite) TestDeleteServer(c *gc.C) {
 
742
        server := nova.ServerDetail{Id: "sr1"}
 
743
        _, err := s.service.server(server.Id)
 
744
        c.Assert(err, gc.NotNil)
 
745
        err = s.service.addServer(server)
 
746
        c.Assert(err, gc.IsNil)
 
747
        defer s.service.removeServer(server.Id)
 
748
        resp, err := s.authRequest("DELETE", "/servers/sr1", nil, nil)
 
749
        c.Assert(err, gc.IsNil)
 
750
        c.Assert(resp.StatusCode, gc.Equals, http.StatusNoContent)
 
751
        _, err = s.service.server(server.Id)
 
752
        c.Assert(err, gc.NotNil)
 
753
}
 
754
 
 
755
func (s *NovaHTTPSuite) TestGetServersDetail(c *gc.C) {
 
756
        servers, err := s.service.allServers(nil)
 
757
        c.Assert(err, gc.IsNil)
 
758
        c.Assert(servers, gc.HasLen, 0)
 
759
        var expected struct {
 
760
                Servers []nova.ServerDetail `json:"servers"`
 
761
        }
 
762
        resp, err := s.authRequest("GET", "/servers/detail", nil, nil)
 
763
        c.Assert(err, gc.IsNil)
 
764
        c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
 
765
        assertJSON(c, resp, &expected)
 
766
        c.Assert(expected.Servers, gc.HasLen, 0)
 
767
        servers = []nova.ServerDetail{
 
768
                {Id: "sr1", Name: "server 1"},
 
769
                {Id: "sr2", Name: "server 2"},
 
770
        }
 
771
        for i, server := range servers {
 
772
                s.service.buildServerLinks(&server)
 
773
                servers[i] = server
 
774
                err := s.service.addServer(server)
 
775
                c.Assert(err, gc.IsNil)
 
776
                defer s.service.removeServer(server.Id)
 
777
        }
 
778
        resp, err = s.authRequest("GET", "/servers/detail", nil, nil)
 
779
        c.Assert(err, gc.IsNil)
 
780
        c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
 
781
        assertJSON(c, resp, &expected)
 
782
        c.Assert(expected.Servers, gc.HasLen, 2)
 
783
        if expected.Servers[0].Id != servers[0].Id {
 
784
                expected.Servers[0], expected.Servers[1] = expected.Servers[1], expected.Servers[0]
 
785
        }
 
786
        c.Assert(expected.Servers, gc.DeepEquals, servers)
 
787
        resp, err = s.authRequest("GET", "/servers/detail/sr1", nil, nil)
 
788
        c.Assert(err, gc.IsNil)
 
789
        assertBody(c, resp, errNotFound)
 
790
}
 
791
 
 
792
func (s *NovaHTTPSuite) TestGetServersDetailWithFilters(c *gc.C) {
 
793
        servers, err := s.service.allServers(nil)
 
794
        c.Assert(err, gc.IsNil)
 
795
        c.Assert(servers, gc.HasLen, 0)
 
796
        var expected struct {
 
797
                Servers []nova.ServerDetail `json:"servers"`
 
798
        }
 
799
        url := "/servers/detail?status=RESCUE&status=BUILD&name=srv2&name=srv1"
 
800
        resp, err := s.authRequest("GET", url, nil, nil)
 
801
        c.Assert(err, gc.IsNil)
 
802
        c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
 
803
        assertJSON(c, resp, &expected)
 
804
        c.Assert(expected.Servers, gc.HasLen, 0)
 
805
        servers = []nova.ServerDetail{
 
806
                {Id: "sr1", Name: "srv1", Status: nova.StatusBuild},
 
807
                {Id: "sr2", Name: "srv2", Status: nova.StatusRescue},
 
808
                {Id: "sr3", Name: "srv3", Status: nova.StatusActive},
 
809
        }
 
810
        for i, server := range servers {
 
811
                s.service.buildServerLinks(&server)
 
812
                servers[i] = server
 
813
                err := s.service.addServer(server)
 
814
                c.Assert(err, gc.IsNil)
 
815
                defer s.service.removeServer(server.Id)
 
816
        }
 
817
        resp, err = s.authRequest("GET", url, nil, nil)
 
818
        c.Assert(err, gc.IsNil)
 
819
        c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
 
820
        assertJSON(c, resp, &expected)
 
821
        c.Assert(expected.Servers, gc.HasLen, 1)
 
822
        c.Assert(expected.Servers[0], gc.DeepEquals, servers[0])
 
823
}
 
824
 
 
825
func (s *NovaHTTPSuite) TestGetSecurityGroups(c *gc.C) {
 
826
        // There is always a default security group.
 
827
        groups := s.service.allSecurityGroups()
 
828
        c.Assert(groups, gc.HasLen, 1)
 
829
        var expected struct {
 
830
                Groups []nova.SecurityGroup `json:"security_groups"`
 
831
        }
 
832
        resp, err := s.authRequest("GET", "/os-security-groups", nil, nil)
 
833
        c.Assert(err, gc.IsNil)
 
834
        c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
 
835
        assertJSON(c, resp, &expected)
 
836
        c.Assert(expected.Groups, gc.HasLen, 1)
 
837
        groups = []nova.SecurityGroup{
 
838
                {
 
839
                        Id:       "1",
 
840
                        Name:     "group 1",
 
841
                        TenantId: s.service.TenantId,
 
842
                        Rules:    []nova.SecurityGroupRule{},
 
843
                },
 
844
                {
 
845
                        Id:       "2",
 
846
                        Name:     "group 2",
 
847
                        TenantId: s.service.TenantId,
 
848
                        Rules:    []nova.SecurityGroupRule{},
 
849
                },
 
850
        }
 
851
        for _, group := range groups {
 
852
                err := s.service.addSecurityGroup(group)
 
853
                c.Assert(err, gc.IsNil)
 
854
                defer s.service.removeSecurityGroup(group.Id)
 
855
        }
 
856
        resp, err = s.authRequest("GET", "/os-security-groups", nil, nil)
 
857
        c.Assert(err, gc.IsNil)
 
858
        c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
 
859
        assertJSON(c, resp, &expected)
 
860
        c.Assert(expected.Groups, gc.HasLen, len(groups)+1)
 
861
        checkGroupsInList(c, groups, expected.Groups)
 
862
        var expectedGroup struct {
 
863
                Group nova.SecurityGroup `json:"security_group"`
 
864
        }
 
865
        resp, err = s.authRequest("GET", "/os-security-groups/1", nil, nil)
 
866
        c.Assert(err, gc.IsNil)
 
867
        c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
 
868
        assertJSON(c, resp, &expectedGroup)
 
869
        c.Assert(expectedGroup.Group, gc.DeepEquals, groups[0])
 
870
}
 
871
 
 
872
func (s *NovaHTTPSuite) TestAddSecurityGroup(c *gc.C) {
 
873
        group := nova.SecurityGroup{
 
874
                Id:          "1",
 
875
                Name:        "group 1",
 
876
                Description: "desc",
 
877
                TenantId:    s.service.TenantId,
 
878
                Rules:       []nova.SecurityGroupRule{},
 
879
        }
 
880
        _, err := s.service.securityGroup(group.Id)
 
881
        c.Assert(err, gc.NotNil)
 
882
        var req struct {
 
883
                Group struct {
 
884
                        Name        string `json:"name"`
 
885
                        Description string `json:"description"`
 
886
                } `json:"security_group"`
 
887
        }
 
888
        req.Group.Name = group.Name
 
889
        req.Group.Description = group.Description
 
890
        var expected struct {
 
891
                Group nova.SecurityGroup `json:"security_group"`
 
892
        }
 
893
        resp, err := s.jsonRequest("POST", "/os-security-groups", req, nil)
 
894
        c.Assert(err, gc.IsNil)
 
895
        c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
 
896
        assertJSON(c, resp, &expected)
 
897
        c.Assert(expected.Group, gc.DeepEquals, group)
 
898
        err = s.service.removeSecurityGroup(group.Id)
 
899
        c.Assert(err, gc.IsNil)
 
900
}
 
901
 
 
902
func (s *NovaHTTPSuite) TestDeleteSecurityGroup(c *gc.C) {
 
903
        group := nova.SecurityGroup{Id: "1", Name: "group 1"}
 
904
        _, err := s.service.securityGroup(group.Id)
 
905
        c.Assert(err, gc.NotNil)
 
906
        err = s.service.addSecurityGroup(group)
 
907
        c.Assert(err, gc.IsNil)
 
908
        defer s.service.removeSecurityGroup(group.Id)
 
909
        resp, err := s.authRequest("DELETE", "/os-security-groups/1", nil, nil)
 
910
        c.Assert(err, gc.IsNil)
 
911
        c.Assert(resp.StatusCode, gc.Equals, http.StatusAccepted)
 
912
        _, err = s.service.securityGroup(group.Id)
 
913
        c.Assert(err, gc.NotNil)
 
914
}
 
915
 
 
916
func (s *NovaHTTPSuite) TestAddSecurityGroupRule(c *gc.C) {
 
917
        group1 := nova.SecurityGroup{Id: "1", Name: "src"}
 
918
        group2 := nova.SecurityGroup{Id: "2", Name: "tgt"}
 
919
        err := s.service.addSecurityGroup(group1)
 
920
        c.Assert(err, gc.IsNil)
 
921
        defer s.service.removeSecurityGroup(group1.Id)
 
922
        err = s.service.addSecurityGroup(group2)
 
923
        c.Assert(err, gc.IsNil)
 
924
        defer s.service.removeSecurityGroup(group2.Id)
 
925
        riIngress := nova.RuleInfo{
 
926
                ParentGroupId: "1",
 
927
                FromPort:      1234,
 
928
                ToPort:        4321,
 
929
                IPProtocol:    "tcp",
 
930
                Cidr:          "1.2.3.4/5",
 
931
        }
 
932
        riGroup := nova.RuleInfo{
 
933
                ParentGroupId: group2.Id,
 
934
                GroupId:       &group1.Id,
 
935
        }
 
936
        iprange := make(map[string]string)
 
937
        iprange["cidr"] = riIngress.Cidr
 
938
        rule1 := nova.SecurityGroupRule{
 
939
                Id:            "1",
 
940
                ParentGroupId: group1.Id,
 
941
                FromPort:      &riIngress.FromPort,
 
942
                ToPort:        &riIngress.ToPort,
 
943
                IPProtocol:    &riIngress.IPProtocol,
 
944
                IPRange:       iprange,
 
945
        }
 
946
        rule2 := nova.SecurityGroupRule{
 
947
                Id:            "2",
 
948
                ParentGroupId: group2.Id,
 
949
                Group: nova.SecurityGroupRef{
 
950
                        Name:     group1.Name,
 
951
                        TenantId: s.service.TenantId,
 
952
                },
 
953
        }
 
954
        ok := s.service.hasSecurityGroupRule(group1.Id, rule1.Id)
 
955
        c.Assert(ok, gc.Equals, false)
 
956
        ok = s.service.hasSecurityGroupRule(group2.Id, rule2.Id)
 
957
        c.Assert(ok, gc.Equals, false)
 
958
        var req struct {
 
959
                Rule nova.RuleInfo `json:"security_group_rule"`
 
960
        }
 
961
        req.Rule = riIngress
 
962
        var expected struct {
 
963
                Rule nova.SecurityGroupRule `json:"security_group_rule"`
 
964
        }
 
965
        resp, err := s.jsonRequest("POST", "/os-security-group-rules", req, nil)
 
966
        c.Assert(err, gc.IsNil)
 
967
        c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
 
968
        assertJSON(c, resp, &expected)
 
969
        c.Assert(expected.Rule.Id, gc.Equals, rule1.Id)
 
970
        c.Assert(expected.Rule.ParentGroupId, gc.Equals, rule1.ParentGroupId)
 
971
        c.Assert(expected.Rule.Group, gc.Equals, nova.SecurityGroupRef{})
 
972
        c.Assert(*expected.Rule.FromPort, gc.Equals, *rule1.FromPort)
 
973
        c.Assert(*expected.Rule.ToPort, gc.Equals, *rule1.ToPort)
 
974
        c.Assert(*expected.Rule.IPProtocol, gc.Equals, *rule1.IPProtocol)
 
975
        c.Assert(expected.Rule.IPRange, gc.DeepEquals, rule1.IPRange)
 
976
        defer s.service.removeSecurityGroupRule(rule1.Id)
 
977
        req.Rule = riGroup
 
978
        resp, err = s.jsonRequest("POST", "/os-security-group-rules", req, nil)
 
979
        c.Assert(err, gc.IsNil)
 
980
        c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
 
981
        assertJSON(c, resp, &expected)
 
982
        c.Assert(expected.Rule.Id, gc.Equals, rule2.Id)
 
983
        c.Assert(expected.Rule.ParentGroupId, gc.Equals, rule2.ParentGroupId)
 
984
        c.Assert(expected.Rule.Group, gc.DeepEquals, rule2.Group)
 
985
        err = s.service.removeSecurityGroupRule(rule2.Id)
 
986
        c.Assert(err, gc.IsNil)
 
987
}
 
988
 
 
989
func (s *NovaHTTPSuite) TestDeleteSecurityGroupRule(c *gc.C) {
 
990
        group1 := nova.SecurityGroup{Id: "1", Name: "src"}
 
991
        group2 := nova.SecurityGroup{Id: "2", Name: "tgt"}
 
992
        err := s.service.addSecurityGroup(group1)
 
993
        c.Assert(err, gc.IsNil)
 
994
        defer s.service.removeSecurityGroup(group1.Id)
 
995
        err = s.service.addSecurityGroup(group2)
 
996
        c.Assert(err, gc.IsNil)
 
997
        defer s.service.removeSecurityGroup(group2.Id)
 
998
        riGroup := nova.RuleInfo{
 
999
                ParentGroupId: group2.Id,
 
1000
                GroupId:       &group1.Id,
 
1001
        }
 
1002
        rule := nova.SecurityGroupRule{
 
1003
                Id:            "1",
 
1004
                ParentGroupId: group2.Id,
 
1005
                Group: nova.SecurityGroupRef{
 
1006
                        Name:     group1.Name,
 
1007
                        TenantId: group1.TenantId,
 
1008
                },
 
1009
        }
 
1010
        err = s.service.addSecurityGroupRule(rule.Id, riGroup)
 
1011
        c.Assert(err, gc.IsNil)
 
1012
        resp, err := s.authRequest("DELETE", "/os-security-group-rules/1", nil, nil)
 
1013
        c.Assert(err, gc.IsNil)
 
1014
        c.Assert(resp.StatusCode, gc.Equals, http.StatusAccepted)
 
1015
        ok := s.service.hasSecurityGroupRule(group2.Id, rule.Id)
 
1016
        c.Assert(ok, gc.Equals, false)
 
1017
}
 
1018
 
 
1019
func (s *NovaHTTPSuite) TestAddServerSecurityGroup(c *gc.C) {
 
1020
        group := nova.SecurityGroup{Id: "1", Name: "group"}
 
1021
        err := s.service.addSecurityGroup(group)
 
1022
        c.Assert(err, gc.IsNil)
 
1023
        defer s.service.removeSecurityGroup(group.Id)
 
1024
        server := nova.ServerDetail{Id: "sr1"}
 
1025
        err = s.service.addServer(server)
 
1026
        c.Assert(err, gc.IsNil)
 
1027
        defer s.service.removeServer(server.Id)
 
1028
        ok := s.service.hasServerSecurityGroup(server.Id, group.Id)
 
1029
        c.Assert(ok, gc.Equals, false)
 
1030
        var req struct {
 
1031
                Group struct {
 
1032
                        Name string `json:"name"`
 
1033
                } `json:"addSecurityGroup"`
 
1034
        }
 
1035
        req.Group.Name = group.Name
 
1036
        resp, err := s.jsonRequest("POST", "/servers/"+server.Id+"/action", req, nil)
 
1037
        c.Assert(err, gc.IsNil)
 
1038
        c.Assert(resp.StatusCode, gc.Equals, http.StatusAccepted)
 
1039
        ok = s.service.hasServerSecurityGroup(server.Id, group.Id)
 
1040
        c.Assert(ok, gc.Equals, true)
 
1041
        err = s.service.removeServerSecurityGroup(server.Id, group.Id)
 
1042
        c.Assert(err, gc.IsNil)
 
1043
}
 
1044
 
 
1045
func (s *NovaHTTPSuite) TestGetServerSecurityGroups(c *gc.C) {
 
1046
        server := nova.ServerDetail{Id: "sr1"}
 
1047
        groups := []nova.SecurityGroup{
 
1048
                {
 
1049
                        Id:       "1",
 
1050
                        Name:     "group1",
 
1051
                        TenantId: s.service.TenantId,
 
1052
                        Rules:    []nova.SecurityGroupRule{},
 
1053
                },
 
1054
                {
 
1055
                        Id:       "2",
 
1056
                        Name:     "group2",
 
1057
                        TenantId: s.service.TenantId,
 
1058
                        Rules:    []nova.SecurityGroupRule{},
 
1059
                },
 
1060
        }
 
1061
        srvGroups := s.service.allServerSecurityGroups(server.Id)
 
1062
        c.Assert(srvGroups, gc.HasLen, 0)
 
1063
        err := s.service.addServer(server)
 
1064
        c.Assert(err, gc.IsNil)
 
1065
        defer s.service.removeServer(server.Id)
 
1066
        for _, group := range groups {
 
1067
                err = s.service.addSecurityGroup(group)
 
1068
                c.Assert(err, gc.IsNil)
 
1069
                defer s.service.removeSecurityGroup(group.Id)
 
1070
                err = s.service.addServerSecurityGroup(server.Id, group.Id)
 
1071
                c.Assert(err, gc.IsNil)
 
1072
                defer s.service.removeServerSecurityGroup(server.Id, group.Id)
 
1073
        }
 
1074
        srvGroups = s.service.allServerSecurityGroups(server.Id)
 
1075
        var expected struct {
 
1076
                Groups []nova.SecurityGroup `json:"security_groups"`
 
1077
        }
 
1078
        resp, err := s.authRequest("GET", "/servers/"+server.Id+"/os-security-groups", nil, nil)
 
1079
        c.Assert(err, gc.IsNil)
 
1080
        assertJSON(c, resp, &expected)
 
1081
        c.Assert(expected.Groups, gc.DeepEquals, groups)
 
1082
}
 
1083
 
 
1084
func (s *NovaHTTPSuite) TestDeleteServerSecurityGroup(c *gc.C) {
 
1085
        group := nova.SecurityGroup{Id: "1", Name: "group"}
 
1086
        err := s.service.addSecurityGroup(group)
 
1087
        c.Assert(err, gc.IsNil)
 
1088
        defer s.service.removeSecurityGroup(group.Id)
 
1089
        server := nova.ServerDetail{Id: "sr1"}
 
1090
        err = s.service.addServer(server)
 
1091
        c.Assert(err, gc.IsNil)
 
1092
        defer s.service.removeServer(server.Id)
 
1093
        ok := s.service.hasServerSecurityGroup(server.Id, group.Id)
 
1094
        c.Assert(ok, gc.Equals, false)
 
1095
        err = s.service.addServerSecurityGroup(server.Id, group.Id)
 
1096
        c.Assert(err, gc.IsNil)
 
1097
        var req struct {
 
1098
                Group struct {
 
1099
                        Name string `json:"name"`
 
1100
                } `json:"removeSecurityGroup"`
 
1101
        }
 
1102
        req.Group.Name = group.Name
 
1103
        resp, err := s.jsonRequest("POST", "/servers/"+server.Id+"/action", req, nil)
 
1104
        c.Assert(err, gc.IsNil)
 
1105
        c.Assert(resp.StatusCode, gc.Equals, http.StatusAccepted)
 
1106
        ok = s.service.hasServerSecurityGroup(server.Id, group.Id)
 
1107
        c.Assert(ok, gc.Equals, false)
 
1108
}
 
1109
 
 
1110
func (s *NovaHTTPSuite) TestPostFloatingIP(c *gc.C) {
 
1111
        fip := nova.FloatingIP{Id: "1", IP: "10.0.0.1", Pool: "nova"}
 
1112
        c.Assert(s.service.allFloatingIPs(), gc.HasLen, 0)
 
1113
        var expected struct {
 
1114
                IP nova.FloatingIP `json:"floating_ip"`
 
1115
        }
 
1116
        resp, err := s.authRequest("POST", "/os-floating-ips", nil, nil)
 
1117
        c.Assert(err, gc.IsNil)
 
1118
        c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
 
1119
        assertJSON(c, resp, &expected)
 
1120
        c.Assert(expected.IP, gc.DeepEquals, fip)
 
1121
        err = s.service.removeFloatingIP(fip.Id)
 
1122
        c.Assert(err, gc.IsNil)
 
1123
}
 
1124
 
 
1125
func (s *NovaHTTPSuite) TestGetFloatingIPs(c *gc.C) {
 
1126
        c.Assert(s.service.allFloatingIPs(), gc.HasLen, 0)
 
1127
        var expected struct {
 
1128
                IPs []nova.FloatingIP `json:"floating_ips"`
 
1129
        }
 
1130
        resp, err := s.authRequest("GET", "/os-floating-ips", nil, nil)
 
1131
        c.Assert(err, gc.IsNil)
 
1132
        c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
 
1133
        assertJSON(c, resp, &expected)
 
1134
        c.Assert(expected.IPs, gc.HasLen, 0)
 
1135
        fips := []nova.FloatingIP{
 
1136
                {Id: "1", IP: "1.2.3.4", Pool: "nova"},
 
1137
                {Id: "2", IP: "4.3.2.1", Pool: "nova"},
 
1138
        }
 
1139
        for _, fip := range fips {
 
1140
                err := s.service.addFloatingIP(fip)
 
1141
                defer s.service.removeFloatingIP(fip.Id)
 
1142
                c.Assert(err, gc.IsNil)
 
1143
        }
 
1144
        resp, err = s.authRequest("GET", "/os-floating-ips", nil, nil)
 
1145
        c.Assert(err, gc.IsNil)
 
1146
        c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
 
1147
        assertJSON(c, resp, &expected)
 
1148
        if expected.IPs[0].Id != fips[0].Id {
 
1149
                expected.IPs[0], expected.IPs[1] = expected.IPs[1], expected.IPs[0]
 
1150
        }
 
1151
        c.Assert(expected.IPs, gc.DeepEquals, fips)
 
1152
        var expectedIP struct {
 
1153
                IP nova.FloatingIP `json:"floating_ip"`
 
1154
        }
 
1155
        resp, err = s.authRequest("GET", "/os-floating-ips/1", nil, nil)
 
1156
        c.Assert(err, gc.IsNil)
 
1157
        c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
 
1158
        assertJSON(c, resp, &expectedIP)
 
1159
        c.Assert(expectedIP.IP, gc.DeepEquals, fips[0])
 
1160
}
 
1161
 
 
1162
func (s *NovaHTTPSuite) TestDeleteFloatingIP(c *gc.C) {
 
1163
        fip := nova.FloatingIP{Id: "1", IP: "10.0.0.1", Pool: "nova"}
 
1164
        err := s.service.addFloatingIP(fip)
 
1165
        c.Assert(err, gc.IsNil)
 
1166
        defer s.service.removeFloatingIP(fip.Id)
 
1167
        resp, err := s.authRequest("DELETE", "/os-floating-ips/1", nil, nil)
 
1168
        c.Assert(err, gc.IsNil)
 
1169
        c.Assert(resp.StatusCode, gc.Equals, http.StatusAccepted)
 
1170
        _, err = s.service.floatingIP(fip.Id)
 
1171
        c.Assert(err, gc.NotNil)
 
1172
}
 
1173
 
 
1174
func (s *NovaHTTPSuite) TestAddServerFloatingIP(c *gc.C) {
 
1175
        fip := nova.FloatingIP{Id: "1", IP: "1.2.3.4"}
 
1176
        server := nova.ServerDetail{Id: "sr1"}
 
1177
        err := s.service.addFloatingIP(fip)
 
1178
        c.Assert(err, gc.IsNil)
 
1179
        defer s.service.removeFloatingIP(fip.Id)
 
1180
        err = s.service.addServer(server)
 
1181
        c.Assert(err, gc.IsNil)
 
1182
        defer s.service.removeServer(server.Id)
 
1183
        c.Assert(s.service.hasServerFloatingIP(server.Id, fip.IP), gc.Equals, false)
 
1184
        var req struct {
 
1185
                AddFloatingIP struct {
 
1186
                        Address string `json:"address"`
 
1187
                } `json:"addFloatingIp"`
 
1188
        }
 
1189
        req.AddFloatingIP.Address = fip.IP
 
1190
        resp, err := s.jsonRequest("POST", "/servers/"+server.Id+"/action", req, nil)
 
1191
        c.Assert(err, gc.IsNil)
 
1192
        c.Assert(resp.StatusCode, gc.Equals, http.StatusAccepted)
 
1193
        c.Assert(s.service.hasServerFloatingIP(server.Id, fip.IP), gc.Equals, true)
 
1194
        err = s.service.removeServerFloatingIP(server.Id, fip.Id)
 
1195
        c.Assert(err, gc.IsNil)
 
1196
}
 
1197
 
 
1198
func (s *NovaHTTPSuite) TestRemoveServerFloatingIP(c *gc.C) {
 
1199
        fip := nova.FloatingIP{Id: "1", IP: "1.2.3.4"}
 
1200
        server := nova.ServerDetail{Id: "sr1"}
 
1201
        err := s.service.addFloatingIP(fip)
 
1202
        c.Assert(err, gc.IsNil)
 
1203
        defer s.service.removeFloatingIP(fip.Id)
 
1204
        err = s.service.addServer(server)
 
1205
        c.Assert(err, gc.IsNil)
 
1206
        defer s.service.removeServer(server.Id)
 
1207
        err = s.service.addServerFloatingIP(server.Id, fip.Id)
 
1208
        c.Assert(err, gc.IsNil)
 
1209
        defer s.service.removeServerFloatingIP(server.Id, fip.Id)
 
1210
        c.Assert(s.service.hasServerFloatingIP(server.Id, fip.IP), gc.Equals, true)
 
1211
        var req struct {
 
1212
                RemoveFloatingIP struct {
 
1213
                        Address string `json:"address"`
 
1214
                } `json:"removeFloatingIp"`
 
1215
        }
 
1216
        req.RemoveFloatingIP.Address = fip.IP
 
1217
        resp, err := s.jsonRequest("POST", "/servers/"+server.Id+"/action", req, nil)
 
1218
        c.Assert(err, gc.IsNil)
 
1219
        c.Assert(resp.StatusCode, gc.Equals, http.StatusAccepted)
 
1220
        c.Assert(s.service.hasServerFloatingIP(server.Id, fip.IP), gc.Equals, false)
 
1221
}
 
1222
 
 
1223
func (s *NovaHTTPSuite) TestListAvailabilityZones(c *gc.C) {
 
1224
        resp, err := s.jsonRequest("GET", "/os-availability-zone", nil, nil)
 
1225
        c.Assert(err, gc.IsNil)
 
1226
        assertBody(c, resp, errNotFoundJSON)
 
1227
 
 
1228
        zones := []nova.AvailabilityZone{
 
1229
                {Name: "az1"},
 
1230
                {
 
1231
                        Name: "az2", State: nova.AvailabilityZoneState{Available: true},
 
1232
                },
 
1233
        }
 
1234
        s.service.SetAvailabilityZones(zones...)
 
1235
        resp, err = s.jsonRequest("GET", "/os-availability-zone", nil, nil)
 
1236
        c.Assert(err, gc.IsNil)
 
1237
        var expected struct {
 
1238
                Zones []nova.AvailabilityZone `json:"availabilityZoneInfo"`
 
1239
        }
 
1240
        assertJSON(c, resp, &expected)
 
1241
        c.Assert(expected.Zones, gc.DeepEquals, zones)
 
1242
}
 
1243
 
 
1244
func (s *NovaHTTPSSuite) SetUpSuite(c *gc.C) {
 
1245
        s.HTTPSuite.SetUpSuite(c)
 
1246
        identityDouble := identityservice.NewUserPass()
 
1247
        userInfo := identityDouble.AddUser("fred", "secret", "tenant")
 
1248
        s.token = userInfo.Token
 
1249
        c.Assert(s.Server.URL[:8], gc.Equals, "https://")
 
1250
        s.service = New(s.Server.URL, versionPath, userInfo.TenantId, region, identityDouble, nil)
 
1251
}
 
1252
 
 
1253
func (s *NovaHTTPSSuite) TearDownSuite(c *gc.C) {
 
1254
        s.HTTPSuite.TearDownSuite(c)
 
1255
}
 
1256
 
 
1257
func (s *NovaHTTPSSuite) SetUpTest(c *gc.C) {
 
1258
        s.HTTPSuite.SetUpTest(c)
 
1259
        s.service.SetupHTTP(s.Mux)
 
1260
}
 
1261
 
 
1262
func (s *NovaHTTPSSuite) TearDownTest(c *gc.C) {
 
1263
        s.HTTPSuite.TearDownTest(c)
 
1264
}
 
1265
 
 
1266
func (s *NovaHTTPSSuite) TestHasHTTPSServiceURL(c *gc.C) {
 
1267
        endpoints := s.service.Endpoints()
 
1268
        c.Assert(endpoints[0].PublicURL[:8], gc.Equals, "https://")
 
1269
}
 
1270
 
 
1271
func (s *NovaHTTPSuite) TestSetServerMetadata(c *gc.C) {
 
1272
        const serverId = "sr1"
 
1273
 
 
1274
        err := s.service.addServer(nova.ServerDetail{Id: serverId})
 
1275
        c.Assert(err, gc.IsNil)
 
1276
        defer s.service.removeServer(serverId)
 
1277
        var req struct {
 
1278
                Metadata map[string]string `json:"metadata"`
 
1279
        }
 
1280
        req.Metadata = map[string]string{
 
1281
                "k1": "v1",
 
1282
                "k2": "v2",
 
1283
        }
 
1284
        resp, err := s.jsonRequest("POST", "/servers/"+serverId+"/metadata", req, nil)
 
1285
        c.Assert(err, gc.IsNil)
 
1286
        c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
 
1287
 
 
1288
        server, err := s.service.server(serverId)
 
1289
        c.Assert(err, gc.IsNil)
 
1290
        c.Assert(server.Metadata, gc.DeepEquals, req.Metadata)
 
1291
}