Merge lp:~mfoord/gomaasapi/devices into lp:gomaasapi

Proposed by Michael Foord
Status: Merged
Approved by: Michael Foord
Approved revision: 95
Merged at revision: 63
Proposed branch: lp:~mfoord/gomaasapi/devices
Merge into: lp:gomaasapi
Diff against target: 559 lines (+478/-5)
2 files modified
testservice.go (+250/-5)
testservice_test.go (+228/-0)
To merge this branch: bzr merge lp:~mfoord/gomaasapi/devices
Reviewer Review Type Date Requested Status
Raphaël Badin (community) Approve
Dimiter Naydenov (community) Approve
Review via email: mp+263370@code.launchpad.net

Commit message

Adding devices support to gomaasapi test server.

Description of the change

Adding devices support to gomaasapi test server.

To post a comment you must log in.
Revision history for this message
Dimiter Naydenov (dimitern) wrote :

LGTM in general, apart from the one comment inline below, if I wish we had logging in places where StatusBadRequest is returned to explain the reason and make the test server a bit easier to use.

Also, as discussed on IRC we need support for op=claim_sticky_ip (or was it claim-sticky-ip?).

review: Approve
lp:~mfoord/gomaasapi/devices updated
95. By Michael Foord

Updated comments

Revision history for this message
Michael Foord (mfoord) wrote :

> LGTM in general, apart from the one comment inline below, if I wish we had
> logging in places where StatusBadRequest is returned to explain the reason and
> make the test server a bit easier to use.
>
> Also, as discussed on IRC we need support for op=claim_sticky_ip (or was it
> claim-sticky-ip?).

There's no logging in gomaasapi I'm afraid. The rest is now done.

Revision history for this message
Dimiter Naydenov (dimitern) wrote :

Looks good to land, thanks!

review: Approve
Revision history for this message
Raphaël Badin (rvb) wrote :

Looks good to me as well… lots of TODOs in there but I understand creating a test double is costly and you're only implementing what you need right now.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'testservice.go'
--- testservice.go 2015-06-02 02:28:04 +0000
+++ testservice.go 2015-07-02 16:26:32 +0000
@@ -5,6 +5,7 @@
55
6import (6import (
7 "bufio"7 "bufio"
8 "bytes"
8 "encoding/base64"9 "encoding/base64"
9 "encoding/json"10 "encoding/json"
10 "fmt"11 "fmt"
@@ -18,6 +19,7 @@
18 "sort"19 "sort"
19 "strconv"20 "strconv"
20 "strings"21 "strings"
22 "text/template"
21 "time"23 "time"
2224
23 "gopkg.in/mgo.v2/bson"25 "gopkg.in/mgo.v2/bson"
@@ -85,6 +87,24 @@
85 // nodegroupsInterfaces is a map of nodegroup UUIDs to interface87 // nodegroupsInterfaces is a map of nodegroup UUIDs to interface
86 // objects.88 // objects.
87 nodegroupsInterfaces map[string][]JSONObject89 nodegroupsInterfaces map[string][]JSONObject
90
91 // versionJSON is the response to the /version/ endpoint listing the
92 // capabilities of the MAAS server.
93 versionJSON string
94
95 // devices is a map of device UUIDs to devices.
96 devices map[string]*device
97}
98
99type device struct {
100 IPAddresses []string
101 SystemId string
102 MACAddress string
103 Parent string
104 Hostname string
105
106 // Not part of the device definition but used by the template.
107 APIVersion string
88}108}
89109
90func getNodesEndpoint(version string) string {110func getNodesEndpoint(version string) string {
@@ -100,6 +120,19 @@
100 return regexp.MustCompile(reString)120 return regexp.MustCompile(reString)
101}121}
102122
123func getDevicesEndpoint(version string) string {
124 return fmt.Sprintf("/api/%s/devices/", version)
125}
126
127func getDeviceURL(version, systemId string) string {
128 return fmt.Sprintf("/api/%s/devices/%s/", version, systemId)
129}
130
131func getDeviceURLRE(version string) *regexp.Regexp {
132 reString := fmt.Sprintf("^/api/%s/devices/([^/]*)/$", regexp.QuoteMeta(version))
133 return regexp.MustCompile(reString)
134}
135
103func getFilesEndpoint(version string) string {136func getFilesEndpoint(version string) string {
104 return fmt.Sprintf("/api/%s/files/", version)137 return fmt.Sprintf("/api/%s/files/", version)
105}138}
@@ -141,10 +174,6 @@
141 return fmt.Sprintf("/api/%s/version/", version)174 return fmt.Sprintf("/api/%s/version/", version)
142}175}
143176
144func getVersionJSON() string {
145 return `{"capabilities": ["networks-management","static-ipaddresses"]}`
146}
147
148func getNodegroupsEndpoint(version string) string {177func getNodegroupsEndpoint(version string) string {
149 return fmt.Sprintf("/api/%s/nodegroups/", version)178 return fmt.Sprintf("/api/%s/nodegroups/", version)
150}179}
@@ -185,6 +214,14 @@
185 server.bootImages = make(map[string][]JSONObject)214 server.bootImages = make(map[string][]JSONObject)
186 server.nodegroupsInterfaces = make(map[string][]JSONObject)215 server.nodegroupsInterfaces = make(map[string][]JSONObject)
187 server.zones = make(map[string]JSONObject)216 server.zones = make(map[string]JSONObject)
217 server.versionJSON = `{"capabilities": ["networks-management","static-ipaddresses"]}`
218 server.devices = make(map[string]*device)
219}
220
221// SetVersionJSON sets the JSON response (capabilities) returned from the
222// /version/ endpoint.
223func (server *TestServer) SetVersionJSON(json string) {
224 server.versionJSON = json
188}225}
189226
190// NodesOperations returns the list of operations performed at the /nodes/227// NodesOperations returns the list of operations performed at the /nodes/
@@ -466,6 +503,11 @@
466 server := &TestServer{version: version}503 server := &TestServer{version: version}
467504
468 serveMux := http.NewServeMux()505 serveMux := http.NewServeMux()
506 devicesURL := getDevicesEndpoint(server.version)
507 // Register handler for '/api/<version>/devices/*'.
508 serveMux.HandleFunc(devicesURL, func(w http.ResponseWriter, r *http.Request) {
509 devicesHandler(server, w, r)
510 })
469 nodesURL := getNodesEndpoint(server.version)511 nodesURL := getNodesEndpoint(server.version)
470 // Register handler for '/api/<version>/nodes/*'.512 // Register handler for '/api/<version>/nodes/*'.
471 serveMux.HandleFunc(nodesURL, func(w http.ResponseWriter, r *http.Request) {513 serveMux.HandleFunc(nodesURL, func(w http.ResponseWriter, r *http.Request) {
@@ -513,6 +555,209 @@
513 return server555 return server
514}556}
515557
558// devicesHandler handles requests for '/api/<version>/devices/*'.
559func devicesHandler(server *TestServer, w http.ResponseWriter, r *http.Request) {
560 values, err := url.ParseQuery(r.URL.RawQuery)
561 checkError(err)
562 op := values.Get("op")
563 deviceURLRE := getDeviceURLRE(server.version)
564 deviceURLMatch := deviceURLRE.FindStringSubmatch(r.URL.Path)
565 devicesURL := getDevicesEndpoint(server.version)
566 switch {
567 case r.URL.Path == devicesURL:
568 devicesTopLevelHandler(server, w, r, op)
569 case deviceURLMatch != nil:
570 // Request for a single device.
571 deviceHandler(server, w, r, deviceURLMatch[1], op)
572 default:
573 // Default handler: not found.
574 http.NotFoundHandler().ServeHTTP(w, r)
575 }
576}
577
578// devicesTopLevelHandler handles a request for /api/<version>/devices/
579// (with no device id following as part of the path).
580func devicesTopLevelHandler(server *TestServer, w http.ResponseWriter, r *http.Request, op string) {
581 switch {
582 case r.Method == "GET" && op == "list":
583 // Device listing operation.
584 deviceListingHandler(server, w, r)
585 case r.Method == "POST" && op == "new":
586 newDeviceHandler(server, w, r)
587 default:
588 w.WriteHeader(http.StatusBadRequest)
589 }
590}
591
592func macMatches(device *device, macs []string, hasMac bool) bool {
593 if !hasMac {
594 return true
595 }
596 return contains(macs, device.MACAddress)
597}
598
599// deviceListingHandler handles requests for '/devices/'.
600func deviceListingHandler(server *TestServer, w http.ResponseWriter, r *http.Request) {
601 values, err := url.ParseQuery(r.URL.RawQuery)
602 checkError(err)
603 // TODO(mfoord): support filtering by hostname and id
604 macs, hasMac := values["mac_address"]
605 var matchedDevices []string
606 for _, device := range server.devices {
607 if macMatches(device, macs, hasMac) {
608 matchedDevices = append(matchedDevices, renderDevice(device))
609 }
610 }
611 json := fmt.Sprintf("[%v]", strings.Join(matchedDevices, ", "))
612
613 w.WriteHeader(http.StatusOK)
614 fmt.Fprint(w, json)
615}
616
617var templateFuncs = template.FuncMap{
618 "quotedList": func(items []string) string {
619 var pieces []string
620 for _, item := range items {
621 pieces = append(pieces, fmt.Sprintf("%q", item))
622 }
623 return strings.Join(pieces, ", ")
624 },
625}
626
627const (
628 // The json template for generating new devices.
629 // TODO(mfoord): set resource_uri in MAC addresses
630 deviceTemplate = `{
631 "macaddress_set": [
632 {
633 "mac_address": "{{.MACAddress}}"
634 }
635 ],
636 "zone": {
637 "resource_uri": "/MAAS/api/{{.APIVersion}}/zones/default/",
638 "name": "default",
639 "description": ""
640 },
641 "parent": "{{.Parent}}",
642 "ip_addresses": [{{.IPAddresses | quotedList }}],
643 "hostname": "{{.Hostname}}",
644 "tag_names": [],
645 "owner": "maas-admin",
646 "system_id": "{{.SystemId}}",
647 "resource_uri": "/MAAS/api/{{.APIVersion}}/devices/{{.SystemId}}/"
648}`
649)
650
651func renderDevice(device *device) string {
652 t := template.New("Device template")
653 t = t.Funcs(templateFuncs)
654 t, err := t.Parse(deviceTemplate)
655 checkError(err)
656 var buf bytes.Buffer
657 err = t.Execute(&buf, device)
658 checkError(err)
659 return buf.String()
660}
661
662func getValue(values url.Values, value string) (string, bool) {
663 result, hasResult := values[value]
664 if !hasResult || len(result) != 1 || result[0] == "" {
665 return "", false
666 }
667 return result[0], true
668}
669
670// newDeviceHandler creates, stores and returns new devices.
671func newDeviceHandler(server *TestServer, w http.ResponseWriter, r *http.Request) {
672 err := r.ParseForm()
673 checkError(err)
674 values := r.PostForm
675
676 // TODO(mfood): generate a "proper" uuid for the system Id.
677 uuid, err := generateNonce()
678 checkError(err)
679 systemId := fmt.Sprintf("node-%v", uuid)
680 // At least one MAC address must be specified.
681 // TODO(mfoord) we only support a single MAC in the test server.
682 mac, hasMac := getValue(values, "mac_addresses")
683
684 // hostname and parent are optional.
685 // TODO(mfoord): we require both to be set in the test server.
686 hostname, hasHostname := getValue(values, "hostname")
687 parent, hasParent := getValue(values, "parent")
688 if !hasHostname || !hasMac || !hasParent {
689 w.WriteHeader(http.StatusBadRequest)
690 return
691 }
692
693 device := &device{
694 MACAddress: mac,
695 APIVersion: server.version,
696 Parent: parent,
697 Hostname: hostname,
698 SystemId: systemId,
699 }
700
701 deviceJSON := renderDevice(device)
702 server.devices[systemId] = device
703
704 w.WriteHeader(http.StatusOK)
705 fmt.Fprint(w, deviceJSON)
706 return
707}
708
709// deviceHandler handles requests for '/api/<version>/devices/<system_id>/'.
710func deviceHandler(server *TestServer, w http.ResponseWriter, r *http.Request, systemId string, operation string) {
711 device, ok := server.devices[systemId]
712 if !ok {
713 http.NotFoundHandler().ServeHTTP(w, r)
714 return
715 }
716 if r.Method == "GET" {
717 deviceJSON := renderDevice(device)
718 if operation == "" {
719 w.WriteHeader(http.StatusOK)
720 fmt.Fprint(w, deviceJSON)
721 return
722 } else {
723 w.WriteHeader(http.StatusBadRequest)
724 return
725 }
726 }
727 if r.Method == "POST" {
728 if operation == "claim_sticky_ip_address" {
729 err := r.ParseForm()
730 checkError(err)
731 values := r.PostForm
732 // TODO(mfoord): support optional mac_address parameter
733 // TODO(mfoord): requested_address should be optional
734 // and we should generate one if it isn't provided.
735 address, hasAddress := getValue(values, "requested_address")
736 if !hasAddress {
737 w.WriteHeader(http.StatusBadRequest)
738 return
739 }
740 checkError(err)
741 device.IPAddresses = append(device.IPAddresses, address)
742 deviceJSON := renderDevice(device)
743 w.WriteHeader(http.StatusOK)
744 fmt.Fprint(w, deviceJSON)
745 return
746 } else {
747 w.WriteHeader(http.StatusBadRequest)
748 return
749 }
750 } else if r.Method == "DELETE" {
751 delete(server.devices, systemId)
752 w.WriteHeader(http.StatusNoContent)
753 return
754
755 }
756
757 // TODO(mfoord): support PUT method for updating device
758 http.NotFoundHandler().ServeHTTP(w, r)
759}
760
516// nodesHandler handles requests for '/api/<version>/nodes/*'.761// nodesHandler handles requests for '/api/<version>/nodes/*'.
517func nodesHandler(server *TestServer, w http.ResponseWriter, r *http.Request) {762func nodesHandler(server *TestServer, w http.ResponseWriter, r *http.Request) {
518 values, err := url.ParseQuery(r.URL.RawQuery)763 values, err := url.ParseQuery(r.URL.RawQuery)
@@ -1188,7 +1433,7 @@
1188 }1433 }
1189 w.Header().Set("Content-Type", "application/json; charset=utf-8")1434 w.Header().Set("Content-Type", "application/json; charset=utf-8")
1190 w.WriteHeader(http.StatusOK)1435 w.WriteHeader(http.StatusOK)
1191 fmt.Fprint(w, getVersionJSON())1436 fmt.Fprint(w, server.versionJSON)
1192}1437}
11931438
1194// nodegroupsHandler handles requests for '/api/<version>/nodegroups/*'.1439// nodegroupsHandler handles requests for '/api/<version>/nodegroups/*'.
11951440
=== modified file 'testservice_test.go'
--- testservice_test.go 2015-01-13 03:11:30 +0000
+++ testservice_test.go 2015-07-02 16:26:32 +0000
@@ -49,6 +49,234 @@
49 c.Check(getNodeURL("0.1", "test"), Equals, "/api/0.1/nodes/test/")49 c.Check(getNodeURL("0.1", "test"), Equals, "/api/0.1/nodes/test/")
50}50}
5151
52func (suite *TestServerSuite) TestSetVersionJSON(c *C) {
53 capabilities := `{"capabilities": ["networks-management","static-ipaddresses", "devices-management"]}`
54 suite.server.SetVersionJSON(capabilities)
55
56 url := fmt.Sprintf("/api/%s/version/", suite.server.version)
57 resp, err := http.Get(suite.server.Server.URL + url)
58 c.Assert(err, IsNil)
59 c.Check(resp.StatusCode, Equals, http.StatusOK)
60 content, err := readAndClose(resp.Body)
61 c.Assert(err, IsNil)
62 c.Assert(string(content), Equals, capabilities)
63}
64
65func (suite *TestServerSuite) createDevice(c *C, mac, hostname, parent string) string {
66 devicesURL := fmt.Sprintf("/api/%s/devices/", suite.server.version) + "?op=new"
67 values := url.Values{}
68 values.Add("mac_addresses", mac)
69 values.Add("hostname", hostname)
70 values.Add("parent", parent)
71 result := suite.post(c, devicesURL, values)
72 resultMap, err := result.GetMap()
73 c.Assert(err, IsNil)
74 systemId, err := resultMap["system_id"].GetString()
75 c.Assert(err, IsNil)
76 return systemId
77}
78
79func getString(c *C, object map[string]JSONObject, key string) string {
80 value, err := object[key].GetString()
81 c.Assert(err, IsNil)
82 return value
83}
84
85func (suite *TestServerSuite) post(c *C, url string, values url.Values) JSONObject {
86 resp, err := http.Post(suite.server.Server.URL+url, "application/x-www-form-urlencoded", strings.NewReader(values.Encode()))
87 c.Assert(err, IsNil)
88 c.Check(resp.StatusCode, Equals, http.StatusOK)
89 content, err := readAndClose(resp.Body)
90 c.Assert(err, IsNil)
91 result, err := Parse(suite.server.client, content)
92 c.Assert(err, IsNil)
93 return result
94}
95
96func (suite *TestServerSuite) get(c *C, url string) JSONObject {
97 resp, err := http.Get(suite.server.Server.URL + url)
98 c.Assert(err, IsNil)
99 c.Assert(resp.StatusCode, Equals, http.StatusOK)
100
101 content, err := readAndClose(resp.Body)
102 c.Assert(err, IsNil)
103
104 result, err := Parse(suite.server.client, content)
105 c.Assert(err, IsNil)
106 return result
107}
108
109func checkDevice(c *C, device map[string]JSONObject, mac, hostname, parent string) {
110 macArray, err := device["macaddress_set"].GetArray()
111 c.Assert(err, IsNil)
112 c.Assert(macArray, HasLen, 1)
113 macMap, err := macArray[0].GetMap()
114 c.Assert(err, IsNil)
115
116 actualMac := getString(c, macMap, "mac_address")
117 c.Assert(actualMac, Equals, mac)
118
119 actualParent := getString(c, device, "parent")
120 c.Assert(actualParent, Equals, parent)
121 actualHostname := getString(c, device, "hostname")
122 c.Assert(actualHostname, Equals, hostname)
123}
124
125func (suite *TestServerSuite) TestNewDeviceRequiredParameters(c *C) {
126 devicesURL := fmt.Sprintf("/api/%s/devices/", suite.server.version) + "?op=new"
127 values := url.Values{}
128 values.Add("mac_addresses", "foo")
129 values.Add("hostname", "bar")
130 post := func(values url.Values) int {
131 resp, err := http.Post(suite.server.Server.URL+devicesURL, "application/x-www-form-urlencoded", strings.NewReader(values.Encode()))
132 c.Assert(err, IsNil)
133 return resp.StatusCode
134 }
135 c.Check(post(values), Equals, http.StatusBadRequest)
136 values.Del("hostname")
137 values.Add("parent", "baz")
138 c.Check(post(values), Equals, http.StatusBadRequest)
139 values.Del("mac_addresses")
140 values.Add("hostname", "bam")
141 c.Check(post(values), Equals, http.StatusBadRequest)
142}
143
144func (suite *TestServerSuite) TestNewDevice(c *C) {
145 devicesURL := fmt.Sprintf("/api/%s/devices/", suite.server.version) + "?op=new"
146
147 values := url.Values{}
148 values.Add("mac_addresses", "foo")
149 values.Add("hostname", "bar")
150 values.Add("parent", "baz")
151 result := suite.post(c, devicesURL, values)
152
153 resultMap, err := result.GetMap()
154 c.Assert(err, IsNil)
155
156 macArray, err := resultMap["macaddress_set"].GetArray()
157 c.Assert(err, IsNil)
158 c.Assert(macArray, HasLen, 1)
159 macMap, err := macArray[0].GetMap()
160 c.Assert(err, IsNil)
161
162 mac := getString(c, macMap, "mac_address")
163 c.Assert(mac, Equals, "foo")
164
165 parent := getString(c, resultMap, "parent")
166 c.Assert(parent, Equals, "baz")
167 hostname := getString(c, resultMap, "hostname")
168 c.Assert(hostname, Equals, "bar")
169
170 addresses, err := resultMap["ip_addresses"].GetArray()
171 c.Assert(err, IsNil)
172 c.Assert(addresses, HasLen, 0)
173
174 systemId := getString(c, resultMap, "system_id")
175 resourceURI := getString(c, resultMap, "resource_uri")
176 c.Assert(resourceURI, Equals, fmt.Sprintf("/MAAS/api/%v/devices/%v/", suite.server.version, systemId))
177}
178
179func (suite *TestServerSuite) TestGetDevice(c *C) {
180 systemId := suite.createDevice(c, "foo", "bar", "baz")
181 deviceURL := fmt.Sprintf("/api/%v/devices/%v/", suite.server.version, systemId)
182
183 result := suite.get(c, deviceURL)
184 resultMap, err := result.GetMap()
185 c.Assert(err, IsNil)
186 checkDevice(c, resultMap, "foo", "bar", "baz")
187 actualId, err := resultMap["system_id"].GetString()
188 c.Assert(actualId, Equals, systemId)
189}
190
191func (suite *TestServerSuite) TestDevicesList(c *C) {
192 firstId := suite.createDevice(c, "foo", "bar", "baz")
193 c.Assert(firstId, Not(Equals), "")
194 secondId := suite.createDevice(c, "bam", "bing", "bong")
195 c.Assert(secondId, Not(Equals), "")
196
197 devicesURL := fmt.Sprintf("/api/%s/devices/", suite.server.version) + "?op=list"
198 result := suite.get(c, devicesURL)
199
200 devicesArray, err := result.GetArray()
201 c.Assert(err, IsNil)
202 c.Assert(devicesArray, HasLen, 2)
203
204 for _, device := range devicesArray {
205 deviceMap, err := device.GetMap()
206 c.Assert(err, IsNil)
207 systemId, err := deviceMap["system_id"].GetString()
208 c.Assert(err, IsNil)
209 switch systemId {
210 case firstId:
211 checkDevice(c, deviceMap, "foo", "bar", "baz")
212 case secondId:
213 checkDevice(c, deviceMap, "bam", "bing", "bong")
214 default:
215 c.Fatalf("unknown system id %q", systemId)
216 }
217 }
218}
219
220func (suite *TestServerSuite) TestDevicesListMacFiltering(c *C) {
221 firstId := suite.createDevice(c, "foo", "bar", "baz")
222 c.Assert(firstId, Not(Equals), "")
223 secondId := suite.createDevice(c, "bam", "bing", "bong")
224 c.Assert(secondId, Not(Equals), "")
225
226 op := fmt.Sprintf("?op=list&mac_address=%v", "foo")
227 devicesURL := fmt.Sprintf("/api/%s/devices/", suite.server.version) + op
228 result := suite.get(c, devicesURL)
229
230 devicesArray, err := result.GetArray()
231 c.Assert(err, IsNil)
232 c.Assert(devicesArray, HasLen, 1)
233 deviceMap, err := devicesArray[0].GetMap()
234 c.Assert(err, IsNil)
235 checkDevice(c, deviceMap, "foo", "bar", "baz")
236}
237
238func (suite *TestServerSuite) TestDeviceClaimStickyIPRequiresAddress(c *C) {
239 systemId := suite.createDevice(c, "foo", "bar", "baz")
240 op := "?op=claim_sticky_ip_address"
241 deviceURL := fmt.Sprintf("/api/%s/devices/%s/%s", suite.server.version, systemId, op)
242 values := url.Values{}
243 resp, err := http.Post(suite.server.Server.URL+deviceURL, "application/x-www-form-urlencoded", strings.NewReader(values.Encode()))
244 c.Assert(err, IsNil)
245 c.Assert(resp.StatusCode, Equals, http.StatusBadRequest)
246}
247
248func (suite *TestServerSuite) TestDeviceClaimStickyIP(c *C) {
249 systemId := suite.createDevice(c, "foo", "bar", "baz")
250 op := "?op=claim_sticky_ip_address"
251 deviceURL := fmt.Sprintf("/api/%s/devices/%s/", suite.server.version, systemId)
252 values := url.Values{}
253 values.Add("requested_address", "127.0.0.1")
254 result := suite.post(c, deviceURL+op, values)
255 resultMap, err := result.GetMap()
256 c.Assert(err, IsNil)
257
258 addresses, err := resultMap["ip_addresses"].GetArray()
259 c.Assert(err, IsNil)
260 c.Assert(addresses, HasLen, 1)
261 address, err := addresses[0].GetString()
262 c.Assert(err, IsNil)
263 c.Assert(address, Equals, "127.0.0.1")
264}
265
266func (suite *TestServerSuite) TestDeleteDevice(c *C) {
267 systemId := suite.createDevice(c, "foo", "bar", "baz")
268 deviceURL := fmt.Sprintf("/api/%s/devices/%s/", suite.server.version, systemId)
269 req, err := http.NewRequest("DELETE", suite.server.Server.URL+deviceURL, nil)
270 c.Assert(err, IsNil)
271 resp, err := http.DefaultClient.Do(req)
272 c.Assert(err, IsNil)
273 c.Assert(resp.StatusCode, Equals, http.StatusNoContent)
274
275 resp, err = http.Get(suite.server.Server.URL + deviceURL)
276 c.Assert(err, IsNil)
277 c.Assert(resp.StatusCode, Equals, http.StatusNotFound)
278}
279
52func (suite *TestServerSuite) TestInvalidOperationOnNodesIsBadRequest(c *C) {280func (suite *TestServerSuite) TestInvalidOperationOnNodesIsBadRequest(c *C) {
53 badURL := getNodesEndpoint(suite.server.version) + "?op=procrastinate"281 badURL := getNodesEndpoint(suite.server.version) + "?op=procrastinate"
54282

Subscribers

People subscribed via source and target branches

to all changes: