~juju-qa/ubuntu/xenial/juju/xenial-2.0-beta6

« back to all changes in this revision

Viewing changes to src/github.com/juju/gomaasapi/device_test.go

  • Committer: Nicholas Skaggs
  • Date: 2016-04-20 14:50:35 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20160420145035-m3aj05xazahybzxn
Merge beta5 upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2016 Canonical Ltd.
 
2
// Licensed under the LGPLv3, see LICENCE file for details.
 
3
 
 
4
package gomaasapi
 
5
 
 
6
import (
 
7
        "net/http"
 
8
 
 
9
        "github.com/juju/errors"
 
10
        "github.com/juju/testing"
 
11
        jc "github.com/juju/testing/checkers"
 
12
        "github.com/juju/version"
 
13
        gc "gopkg.in/check.v1"
 
14
)
 
15
 
 
16
type deviceSuite struct {
 
17
        testing.CleanupSuite
 
18
}
 
19
 
 
20
var _ = gc.Suite(&deviceSuite{})
 
21
 
 
22
func (*deviceSuite) TestReadDevicesBadSchema(c *gc.C) {
 
23
        _, err := readDevices(twoDotOh, "wat?")
 
24
        c.Check(err, jc.Satisfies, IsDeserializationError)
 
25
        c.Assert(err.Error(), gc.Equals, `device base schema check failed: expected list, got string("wat?")`)
 
26
}
 
27
 
 
28
func (*deviceSuite) TestReadDevices(c *gc.C) {
 
29
        devices, err := readDevices(twoDotOh, parseJSON(c, devicesResponse))
 
30
        c.Assert(err, jc.ErrorIsNil)
 
31
        c.Assert(devices, gc.HasLen, 1)
 
32
 
 
33
        device := devices[0]
 
34
        c.Check(device.SystemID(), gc.Equals, "4y3haf")
 
35
        c.Check(device.Hostname(), gc.Equals, "furnacelike-brittney")
 
36
        c.Check(device.FQDN(), gc.Equals, "furnacelike-brittney.maas")
 
37
        c.Check(device.IPAddresses(), jc.DeepEquals, []string{"192.168.100.11"})
 
38
        zone := device.Zone()
 
39
        c.Check(zone, gc.NotNil)
 
40
        c.Check(zone.Name(), gc.Equals, "default")
 
41
}
 
42
 
 
43
func (*deviceSuite) TestLowVersion(c *gc.C) {
 
44
        _, err := readDevices(version.MustParse("1.9.0"), parseJSON(c, devicesResponse))
 
45
        c.Assert(err, jc.Satisfies, IsUnsupportedVersionError)
 
46
}
 
47
 
 
48
func (*deviceSuite) TestHighVersion(c *gc.C) {
 
49
        devices, err := readDevices(version.MustParse("2.1.9"), parseJSON(c, devicesResponse))
 
50
        c.Assert(err, jc.ErrorIsNil)
 
51
        c.Assert(devices, gc.HasLen, 1)
 
52
}
 
53
 
 
54
func (s *deviceSuite) TestInterfaceSet(c *gc.C) {
 
55
        server, device := s.getServerAndDevice(c)
 
56
        server.AddGetResponse(device.interfacesURI(), http.StatusOK, interfacesResponse)
 
57
        ifaces := device.InterfaceSet()
 
58
        c.Assert(ifaces, gc.HasLen, 2)
 
59
}
 
60
 
 
61
type fakeVLAN struct {
 
62
        VLAN
 
63
        id int
 
64
}
 
65
 
 
66
func (f *fakeVLAN) ID() int {
 
67
        return f.id
 
68
}
 
69
 
 
70
func (s *controllerSuite) TestCreateInterfaceArgsValidate(c *gc.C) {
 
71
        for i, test := range []struct {
 
72
                args    CreateInterfaceArgs
 
73
                errText string
 
74
        }{{
 
75
                errText: "missing Name not valid",
 
76
        }, {
 
77
                args:    CreateInterfaceArgs{Name: "eth3"},
 
78
                errText: "missing MACAddress not valid",
 
79
        }, {
 
80
                args:    CreateInterfaceArgs{Name: "eth3", MACAddress: "a-mac-address"},
 
81
                errText: `missing VLAN not valid`,
 
82
        }, {
 
83
                args: CreateInterfaceArgs{Name: "eth3", MACAddress: "a-mac-address", VLAN: &fakeVLAN{}},
 
84
        }} {
 
85
                c.Logf("test %d", i)
 
86
                err := test.args.Validate()
 
87
                if test.errText == "" {
 
88
                        c.Check(err, jc.ErrorIsNil)
 
89
                } else {
 
90
                        c.Check(err, jc.Satisfies, errors.IsNotValid)
 
91
                        c.Check(err.Error(), gc.Equals, test.errText)
 
92
                }
 
93
        }
 
94
}
 
95
 
 
96
func (s *deviceSuite) TestCreateInterfaceValidates(c *gc.C) {
 
97
        _, device := s.getServerAndDevice(c)
 
98
        _, err := device.CreateInterface(CreateInterfaceArgs{})
 
99
        c.Assert(err, jc.Satisfies, errors.IsNotValid)
 
100
}
 
101
 
 
102
func (s *deviceSuite) TestCreateInterface(c *gc.C) {
 
103
        server, device := s.getServerAndDevice(c)
 
104
        server.AddPostResponse(device.interfacesURI()+"?op=create_physical", http.StatusOK, interfaceResponse)
 
105
 
 
106
        iface, err := device.CreateInterface(CreateInterfaceArgs{
 
107
                Name:       "eth43",
 
108
                MACAddress: "some-mac-address",
 
109
                VLAN:       &fakeVLAN{id: 33},
 
110
                Tags:       []string{"foo", "bar"},
 
111
        })
 
112
        c.Assert(err, jc.ErrorIsNil)
 
113
        c.Assert(iface, gc.NotNil)
 
114
 
 
115
        request := server.LastRequest()
 
116
        form := request.PostForm
 
117
        c.Assert(form.Get("name"), gc.Equals, "eth43")
 
118
        c.Assert(form.Get("mac_address"), gc.Equals, "some-mac-address")
 
119
        c.Assert(form.Get("vlan"), gc.Equals, "33")
 
120
        c.Assert(form.Get("tags"), gc.Equals, "foo,bar")
 
121
}
 
122
 
 
123
func minimalCreateInterfaceArgs() CreateInterfaceArgs {
 
124
        return CreateInterfaceArgs{
 
125
                Name:       "eth43",
 
126
                MACAddress: "some-mac-address",
 
127
                VLAN:       &fakeVLAN{id: 33},
 
128
        }
 
129
}
 
130
 
 
131
func (s *deviceSuite) TestCreateInterfaceNotFound(c *gc.C) {
 
132
        server, device := s.getServerAndDevice(c)
 
133
        server.AddPostResponse(device.interfacesURI()+"?op=create_physical", http.StatusNotFound, "can't find device")
 
134
        _, err := device.CreateInterface(minimalCreateInterfaceArgs())
 
135
        c.Assert(err, jc.Satisfies, IsBadRequestError)
 
136
        c.Assert(err.Error(), gc.Equals, "can't find device")
 
137
}
 
138
 
 
139
func (s *deviceSuite) TestCreateInterfaceConflict(c *gc.C) {
 
140
        server, device := s.getServerAndDevice(c)
 
141
        server.AddPostResponse(device.interfacesURI()+"?op=create_physical", http.StatusConflict, "device not allocated")
 
142
        _, err := device.CreateInterface(minimalCreateInterfaceArgs())
 
143
        c.Assert(err, jc.Satisfies, IsBadRequestError)
 
144
        c.Assert(err.Error(), gc.Equals, "device not allocated")
 
145
}
 
146
 
 
147
func (s *deviceSuite) TestCreateInterfaceForbidden(c *gc.C) {
 
148
        server, device := s.getServerAndDevice(c)
 
149
        server.AddPostResponse(device.interfacesURI()+"?op=create_physical", http.StatusForbidden, "device not yours")
 
150
        _, err := device.CreateInterface(minimalCreateInterfaceArgs())
 
151
        c.Assert(err, jc.Satisfies, IsPermissionError)
 
152
        c.Assert(err.Error(), gc.Equals, "device not yours")
 
153
}
 
154
 
 
155
func (s *deviceSuite) TestCreateInterfaceServiceUnavailable(c *gc.C) {
 
156
        server, device := s.getServerAndDevice(c)
 
157
        server.AddPostResponse(device.interfacesURI()+"?op=create_physical", http.StatusServiceUnavailable, "no ip addresses available")
 
158
        _, err := device.CreateInterface(minimalCreateInterfaceArgs())
 
159
        c.Assert(err, jc.Satisfies, IsCannotCompleteError)
 
160
        c.Assert(err.Error(), gc.Equals, "no ip addresses available")
 
161
}
 
162
 
 
163
func (s *deviceSuite) TestCreateInterfaceUnknown(c *gc.C) {
 
164
        server, device := s.getServerAndDevice(c)
 
165
        server.AddPostResponse(device.interfacesURI()+"?op=create_physical", http.StatusMethodNotAllowed, "wat?")
 
166
        _, err := device.CreateInterface(minimalCreateInterfaceArgs())
 
167
        c.Assert(err, jc.Satisfies, IsUnexpectedError)
 
168
        c.Assert(err.Error(), gc.Equals, "unexpected: ServerError: 405 Method Not Allowed (wat?)")
 
169
}
 
170
 
 
171
func (s *deviceSuite) getServerAndDevice(c *gc.C) (*SimpleTestServer, *device) {
 
172
        server, controller := createTestServerController(c, s)
 
173
        server.AddGetResponse("/api/2.0/devices/", http.StatusOK, devicesResponse)
 
174
 
 
175
        devices, err := controller.Devices(DevicesArgs{})
 
176
        c.Assert(err, jc.ErrorIsNil)
 
177
        c.Assert(devices, gc.HasLen, 1)
 
178
        return server, devices[0].(*device)
 
179
}
 
180
 
 
181
func (s *deviceSuite) TestDelete(c *gc.C) {
 
182
        server, device := s.getServerAndDevice(c)
 
183
        // Successful delete is 204 - StatusNoContent
 
184
        server.AddDeleteResponse(device.resourceURI, http.StatusNoContent, "")
 
185
        err := device.Delete()
 
186
        c.Assert(err, jc.ErrorIsNil)
 
187
}
 
188
 
 
189
func (s *deviceSuite) TestDelete404(c *gc.C) {
 
190
        _, device := s.getServerAndDevice(c)
 
191
        // No path, so 404
 
192
        err := device.Delete()
 
193
        c.Assert(err, jc.Satisfies, IsNoMatchError)
 
194
}
 
195
 
 
196
func (s *deviceSuite) TestDeleteForbidden(c *gc.C) {
 
197
        server, device := s.getServerAndDevice(c)
 
198
        server.AddDeleteResponse(device.resourceURI, http.StatusForbidden, "")
 
199
        err := device.Delete()
 
200
        c.Assert(err, jc.Satisfies, IsPermissionError)
 
201
}
 
202
 
 
203
func (s *deviceSuite) TestDeleteUnknown(c *gc.C) {
 
204
        server, device := s.getServerAndDevice(c)
 
205
        server.AddDeleteResponse(device.resourceURI, http.StatusConflict, "")
 
206
        err := device.Delete()
 
207
        c.Assert(err, jc.Satisfies, IsUnexpectedError)
 
208
}
 
209
 
 
210
const (
 
211
        deviceResponse = `
 
212
    {
 
213
        "zone": {
 
214
            "description": "",
 
215
            "resource_uri": "/MAAS/api/2.0/zones/default/",
 
216
            "name": "default"
 
217
        },
 
218
        "domain": {
 
219
            "resource_record_count": 0,
 
220
            "resource_uri": "/MAAS/api/2.0/domains/0/",
 
221
            "authoritative": true,
 
222
            "name": "maas",
 
223
            "ttl": null,
 
224
            "id": 0
 
225
        },
 
226
        "node_type_name": "Device",
 
227
        "address_ttl": null,
 
228
        "hostname": "furnacelike-brittney",
 
229
        "node_type": 1,
 
230
        "resource_uri": "/MAAS/api/2.0/devices/4y3haf/",
 
231
        "ip_addresses": ["192.168.100.11"],
 
232
        "owner": "thumper",
 
233
        "tag_names": [],
 
234
        "fqdn": "furnacelike-brittney.maas",
 
235
        "system_id": "4y3haf",
 
236
        "parent": "4y3ha3",
 
237
        "interface_set": [
 
238
            {
 
239
                "resource_uri": "/MAAS/api/2.0/nodes/4y3haf/interfaces/48/",
 
240
                "type": "physical",
 
241
                "mac_address": "78:f0:f1:16:a7:46",
 
242
                "params": "",
 
243
                "discovered": null,
 
244
                "effective_mtu": 1500,
 
245
                "id": 48,
 
246
                "children": [],
 
247
                "links": [],
 
248
                "name": "eth0",
 
249
                "vlan": {
 
250
                    "secondary_rack": null,
 
251
                    "dhcp_on": true,
 
252
                    "fabric": "fabric-0",
 
253
                    "mtu": 1500,
 
254
                    "primary_rack": "4y3h7n",
 
255
                    "resource_uri": "/MAAS/api/2.0/vlans/1/",
 
256
                    "external_dhcp": null,
 
257
                    "name": "untagged",
 
258
                    "id": 1,
 
259
                    "vid": 0
 
260
                },
 
261
                "tags": [],
 
262
                "parents": [],
 
263
                "enabled": true
 
264
            },
 
265
            {
 
266
                "resource_uri": "/MAAS/api/2.0/nodes/4y3haf/interfaces/49/",
 
267
                "type": "physical",
 
268
                "mac_address": "15:34:d3:2d:f7:a7",
 
269
                "params": {},
 
270
                "discovered": null,
 
271
                "effective_mtu": 1500,
 
272
                "id": 49,
 
273
                "children": [],
 
274
                "links": [
 
275
                    {
 
276
                        "mode": "link_up",
 
277
                        "id": 101
 
278
                    }
 
279
                ],
 
280
                "name": "eth1",
 
281
                "vlan": {
 
282
                    "secondary_rack": null,
 
283
                    "dhcp_on": true,
 
284
                    "fabric": "fabric-0",
 
285
                    "mtu": 1500,
 
286
                    "primary_rack": "4y3h7n",
 
287
                    "resource_uri": "/MAAS/api/2.0/vlans/1/",
 
288
                    "external_dhcp": null,
 
289
                    "name": "untagged",
 
290
                    "id": 1,
 
291
                    "vid": 0
 
292
                },
 
293
                "tags": [],
 
294
                "parents": [],
 
295
                "enabled": true
 
296
            }
 
297
        ]
 
298
    }
 
299
    `
 
300
        devicesResponse = "[" + deviceResponse + "]"
 
301
)