Merge ~bjornt/maas:api-better-tests into maas:master
- Git
- lp:~bjornt/maas
- api-better-tests
- Merge into master
Proposed by
Björn Tillenius
Status: | Merged |
---|---|
Approved by: | Björn Tillenius |
Approved revision: | 6cea490cb6d91dedbdf2e984fa668589495d307f |
Merge reported by: | MAAS Lander |
Merged at revision: | not available |
Proposed branch: | ~bjornt/maas:api-better-tests |
Merge into: | maas:master |
Diff against target: |
854 lines (+486/-162) 4 files modified
src/maasserver/api/tests/test_interfaces.py (+210/-57) src/maasserver/api/tests/test_subnets.py (+146/-30) src/maasserver/api/tests/test_vlans.py (+128/-75) src/maasserver/testing/factory.py (+2/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Adam Collard (community) | Approve | ||
MAAS Lander | Needs Fixing | ||
Review via email: mp+419448@code.launchpad.net |
Commit message
Add some more tests for the API handlers.
This is in preparation for changing the way we generate the JSON
representation.
Description of the change
To post a comment you must log in.
Revision history for this message
Adam Collard (adam-collard) : | # |
review:
Approve
~bjornt/maas:api-better-tests
updated
- 6cea490... by Björn Tillenius
-
Fix test failures.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/src/maasserver/api/tests/test_interfaces.py b/src/maasserver/api/tests/test_interfaces.py |
2 | index 89c6171..5b17370 100644 |
3 | --- a/src/maasserver/api/tests/test_interfaces.py |
4 | +++ b/src/maasserver/api/tests/test_interfaces.py |
5 | @@ -26,6 +26,7 @@ from maasserver.enum import ( |
6 | NODE_TYPE, |
7 | ) |
8 | from maasserver.models import Interface |
9 | +from maasserver.models.vlan import DEFAULT_MTU |
10 | from maasserver.testing.api import APITestCase, APITransactionTestCase |
11 | from maasserver.testing.factory import factory |
12 | from maasserver.utils.converters import json_load_bytes |
13 | @@ -60,6 +61,44 @@ def get_interface_uri(interface, node=None): |
14 | return reverse("interface_handler", args=[node.system_id, interface]) |
15 | |
16 | |
17 | +def serialize_vlan(vlan): |
18 | + return { |
19 | + "id": vlan.id, |
20 | + "dhcp_on": vlan.dhcp_on, |
21 | + "external_dhcp": vlan.external_dhcp, |
22 | + "fabric": vlan.fabric.get_name(), |
23 | + "fabric_id": vlan.fabric_id, |
24 | + "mtu": vlan.mtu, |
25 | + "primary_rack": None, |
26 | + "secondary_rack": None, |
27 | + "space": "undefined" if not vlan.space else vlan.space.get_name(), |
28 | + "vid": vlan.vid, |
29 | + "name": vlan.get_name(), |
30 | + "relay_vlan": None, |
31 | + "resource_uri": f"/MAAS/api/2.0/vlans/{vlan.id}/", |
32 | + } |
33 | + |
34 | + |
35 | +def serialize_subnet(subnet): |
36 | + return { |
37 | + "name": subnet.name, |
38 | + "id": subnet.id, |
39 | + "vlan": serialize_vlan(subnet.vlan), |
40 | + "description": "", |
41 | + "cidr": subnet.cidr, |
42 | + "rdns_mode": subnet.rdns_mode, |
43 | + "gateway_ip": subnet.gateway_ip, |
44 | + "dns_servers": subnet.dns_servers, |
45 | + "allow_dns": subnet.allow_dns, |
46 | + "allow_proxy": subnet.allow_proxy, |
47 | + "active_discovery": subnet.active_discovery, |
48 | + "managed": subnet.managed, |
49 | + "disabled_boot_architectures": subnet.disabled_boot_architectures, |
50 | + "space": "undefined" if not subnet.space else subnet.space.get_name(), |
51 | + "resource_uri": f"/MAAS/api/2.0/subnets/{subnet.id}/", |
52 | + } |
53 | + |
54 | + |
55 | def make_complex_interface(node, name=None): |
56 | """Makes interface with parents and children.""" |
57 | fabric = factory.make_Fabric() |
58 | @@ -887,14 +926,113 @@ class TestNodeInterfaceAPI(APITransactionTestCase.ForUser): |
59 | get_interface_uri(interface, node=node), |
60 | ) |
61 | |
62 | + def test_read_basic(self): |
63 | + node = factory.make_Node() |
64 | + interface = factory.make_Interface( |
65 | + node=node, |
66 | + name="eno1", |
67 | + iftype=INTERFACE_TYPE.PHYSICAL, |
68 | + mac_address="11:11:11:11:11:11", |
69 | + enabled=False, |
70 | + vendor="my-vendor", |
71 | + product="my-product", |
72 | + firmware_version="1.2.3", |
73 | + link_connected=False, |
74 | + vlan=None, |
75 | + interface_speed=100, |
76 | + sriov_max_vf=0, |
77 | + tags=[], |
78 | + ) |
79 | + |
80 | + uri = get_interface_uri(interface) |
81 | + response = self.client.get(uri) |
82 | + self.assertEqual( |
83 | + http.client.OK, response.status_code, response.content |
84 | + ) |
85 | + parsed_interface = json_load_bytes(response.content) |
86 | + self.maxDiff = None |
87 | + self.assertEqual( |
88 | + { |
89 | + "system_id": node.system_id, |
90 | + "id": interface.id, |
91 | + "name": "eno1", |
92 | + "type": INTERFACE_TYPE.PHYSICAL, |
93 | + "vlan": None, |
94 | + "mac_address": "11:11:11:11:11:11", |
95 | + "parents": [], |
96 | + "children": [], |
97 | + "tags": [], |
98 | + "enabled": False, |
99 | + "links": [], |
100 | + "params": "", |
101 | + "discovered": None, |
102 | + "effective_mtu": DEFAULT_MTU, |
103 | + "vendor": "my-vendor", |
104 | + "product": "my-product", |
105 | + "firmware_version": "1.2.3", |
106 | + "link_connected": False, |
107 | + "interface_speed": 100, |
108 | + "link_speed": 0, |
109 | + "numa_node": 0, |
110 | + "sriov_max_vf": 0, |
111 | + "resource_uri": ( |
112 | + f"/MAAS/api/2.0/nodes/{node.system_id}/interfaces/{interface.id}/" |
113 | + ), |
114 | + }, |
115 | + parsed_interface, |
116 | + ) |
117 | + |
118 | + def test_read_connected(self): |
119 | + vlan = factory.make_VLAN(name="my-vlan", mtu=1234) |
120 | + interface = factory.make_Interface( |
121 | + enabled=True, |
122 | + link_connected=True, |
123 | + vlan=vlan, |
124 | + interface_speed=100, |
125 | + link_speed=10, |
126 | + tags=["foo", "bar"], |
127 | + ) |
128 | + |
129 | + uri = get_interface_uri(interface) |
130 | + response = self.client.get(uri) |
131 | + self.assertEqual( |
132 | + http.client.OK, response.status_code, response.content |
133 | + ) |
134 | + parsed_interface = json_load_bytes(response.content) |
135 | + expected_parts = { |
136 | + "id": interface.id, |
137 | + "tags": ["foo", "bar"], |
138 | + "enabled": True, |
139 | + "discovered": None, |
140 | + "effective_mtu": 1234, |
141 | + "link_connected": True, |
142 | + "interface_speed": 100, |
143 | + "link_speed": 10, |
144 | + "vlan": { |
145 | + "id": vlan.id, |
146 | + "dhcp_on": vlan.dhcp_on, |
147 | + "external_dhcp": vlan.external_dhcp, |
148 | + "fabric": vlan.fabric.get_name(), |
149 | + "fabric_id": vlan.fabric_id, |
150 | + "mtu": vlan.mtu, |
151 | + "primary_rack": None, |
152 | + "secondary_rack": None, |
153 | + "space": "undefined", |
154 | + "vid": vlan.vid, |
155 | + "name": vlan.get_name(), |
156 | + "relay_vlan": None, |
157 | + "resource_uri": f"/MAAS/api/2.0/vlans/{vlan.id}/", |
158 | + }, |
159 | + } |
160 | + for key, value in expected_parts.items(): |
161 | + self.assertEqual(parsed_interface[key], value) |
162 | + |
163 | def test_read(self): |
164 | node = factory.make_Node() |
165 | bond, parents, children = make_complex_interface(node) |
166 | - # Add some known links to the bond interface. |
167 | |
168 | - # First link is a DHCP link. |
169 | - links = [] |
170 | - dhcp_subnet = factory.make_Subnet() |
171 | + # Add some known links to the bond interface. |
172 | + dhcp_subnet = factory.make_Subnet(vlan=bond.vlan) |
173 | dhcp_ip = factory.make_StaticIPAddress( |
174 | alloc_type=IPADDRESS_TYPE.DHCP, |
175 | ip="", |
176 | @@ -908,19 +1046,9 @@ class TestNodeInterfaceAPI(APITransactionTestCase.ForUser): |
177 | subnet=dhcp_subnet, |
178 | interface=bond, |
179 | ) |
180 | - links.append( |
181 | - MatchesDict( |
182 | - { |
183 | - "id": Equals(dhcp_ip.id), |
184 | - "mode": Equals(INTERFACE_LINK_TYPE.DHCP), |
185 | - "subnet": ContainsDict({"id": Equals(dhcp_subnet.id)}), |
186 | - "ip_address": Equals(discovered_ip), |
187 | - } |
188 | - ) |
189 | - ) |
190 | |
191 | # Second link is a STATIC ip link. |
192 | - static_subnet = factory.make_Subnet() |
193 | + static_subnet = factory.make_Subnet(vlan=bond.vlan) |
194 | static_ip = factory.pick_ip_in_network(static_subnet.get_ipnetwork()) |
195 | sip = factory.make_StaticIPAddress( |
196 | alloc_type=IPADDRESS_TYPE.STICKY, |
197 | @@ -928,40 +1056,21 @@ class TestNodeInterfaceAPI(APITransactionTestCase.ForUser): |
198 | subnet=static_subnet, |
199 | interface=bond, |
200 | ) |
201 | - links.append( |
202 | - MatchesDict( |
203 | - { |
204 | - "id": Equals(sip.id), |
205 | - "mode": Equals(INTERFACE_LINK_TYPE.STATIC), |
206 | - "ip_address": Equals(static_ip), |
207 | - "subnet": ContainsDict({"id": Equals(static_subnet.id)}), |
208 | - } |
209 | - ) |
210 | - ) |
211 | |
212 | # Third link is just a LINK_UP. In reality this cannot exist while the |
213 | # other two links exist but for testing we allow it. If validation of |
214 | # the StaticIPAddress model ever included this check, which it |
215 | # probably should then this will fail and cause this test to break. |
216 | - link_subnet = factory.make_Subnet() |
217 | + link_subnet = factory.make_Subnet(vlan=bond.vlan) |
218 | link_ip = factory.make_StaticIPAddress( |
219 | alloc_type=IPADDRESS_TYPE.STICKY, |
220 | ip="", |
221 | subnet=link_subnet, |
222 | interface=bond, |
223 | ) |
224 | - links.append( |
225 | - MatchesDict( |
226 | - { |
227 | - "id": Equals(link_ip.id), |
228 | - "mode": Equals(INTERFACE_LINK_TYPE.LINK_UP), |
229 | - "subnet": ContainsDict({"id": Equals(link_subnet.id)}), |
230 | - } |
231 | - ) |
232 | - ) |
233 | |
234 | # Add MTU parameter. |
235 | - bond.params = {"mtu": random.randint(800, 2000)} |
236 | + bond.params = {"mtu": 1234} |
237 | bond.save() |
238 | |
239 | uri = get_interface_uri(bond) |
240 | @@ -970,33 +1079,77 @@ class TestNodeInterfaceAPI(APITransactionTestCase.ForUser): |
241 | http.client.OK, response.status_code, response.content |
242 | ) |
243 | parsed_interface = json_load_bytes(response.content) |
244 | - self.assertThat( |
245 | - parsed_interface, |
246 | - ContainsDict( |
247 | - { |
248 | - "id": Equals(bond.id), |
249 | - "name": Equals(bond.name), |
250 | - "type": Equals(bond.type), |
251 | - "vlan": ContainsDict({"id": Equals(bond.vlan.id)}), |
252 | - "mac_address": Equals("%s" % bond.mac_address), |
253 | - "tags": Equals(bond.tags), |
254 | - "resource_uri": Equals(get_interface_uri(bond)), |
255 | - "params": Equals(bond.params), |
256 | - "effective_mtu": Equals(bond.get_effective_mtu()), |
257 | - "system_id": Equals(node.system_id), |
258 | - } |
259 | - ), |
260 | - ) |
261 | + |
262 | + expected_parts = { |
263 | + "id": bond.id, |
264 | + "name": bond.name, |
265 | + "type": bond.type, |
266 | + "mac_address": str(bond.mac_address), |
267 | + "vlan": serialize_vlan(bond.vlan), |
268 | + "tags": bond.tags, |
269 | + "resource_uri": get_interface_uri(bond), |
270 | + "params": {"mtu": 1234}, |
271 | + "effective_mtu": 1500, |
272 | + "system_id": node.system_id, |
273 | + } |
274 | + for key, value in expected_parts.items(): |
275 | + self.assertEqual(parsed_interface[key], value) |
276 | self.assertEqual( |
277 | sorted(nic.name for nic in parents), parsed_interface["parents"] |
278 | ) |
279 | self.assertEqual( |
280 | sorted(nic.name for nic in children), parsed_interface["children"] |
281 | ) |
282 | - self.assertThat(parsed_interface["links"], MatchesSetwise(*links)) |
283 | - json_discovered = parsed_interface["discovered"][0] |
284 | - self.assertEqual(dhcp_subnet.id, json_discovered["subnet"]["id"]) |
285 | - self.assertEqual(discovered_ip, json_discovered["ip_address"]) |
286 | + |
287 | + self.assertEqual( |
288 | + [ |
289 | + { |
290 | + "id": dhcp_ip.id, |
291 | + "mode": "dhcp", |
292 | + "ip_address": discovered_ip, |
293 | + "subnet": serialize_subnet(dhcp_subnet), |
294 | + }, |
295 | + { |
296 | + "id": sip.id, |
297 | + "mode": "static", |
298 | + "ip_address": static_ip, |
299 | + "subnet": serialize_subnet(static_subnet), |
300 | + }, |
301 | + { |
302 | + "id": link_ip.id, |
303 | + "mode": "link_up", |
304 | + "subnet": serialize_subnet(link_subnet), |
305 | + }, |
306 | + ], |
307 | + parsed_interface["links"], |
308 | + ) |
309 | + self.assertEqual( |
310 | + [ |
311 | + { |
312 | + "ip_address": discovered_ip, |
313 | + "subnet": serialize_subnet(dhcp_subnet), |
314 | + }, |
315 | + ], |
316 | + parsed_interface["discovered"], |
317 | + ) |
318 | + |
319 | + def test_read_effective_mtu(self): |
320 | + node = factory.make_Node() |
321 | + bond, parents, children = make_complex_interface(node) |
322 | + bond.params = {"mtu": 1000} |
323 | + bond.save() |
324 | + children[0].params = {"mtu": 2000} |
325 | + children[0].save() |
326 | + |
327 | + uri = get_interface_uri(bond) |
328 | + response = self.client.get(uri) |
329 | + self.assertEqual( |
330 | + http.client.OK, response.status_code, response.content |
331 | + ) |
332 | + parsed_interface = json_load_bytes(response.content) |
333 | + |
334 | + self.assertEqual(bond.id, parsed_interface["id"]) |
335 | + self.assertEqual(2000, parsed_interface["effective_mtu"]) |
336 | |
337 | def test_read_by_specifier(self): |
338 | node = factory.make_Node(hostname="tasty-biscuits") |
339 | diff --git a/src/maasserver/api/tests/test_subnets.py b/src/maasserver/api/tests/test_subnets.py |
340 | index c85dede..2fc8cad 100644 |
341 | --- a/src/maasserver/api/tests/test_subnets.py |
342 | +++ b/src/maasserver/api/tests/test_subnets.py |
343 | @@ -8,12 +8,18 @@ import random |
344 | |
345 | from django.conf import settings |
346 | from django.urls import reverse |
347 | -from testtools.matchers import Contains, ContainsDict, Equals |
348 | - |
349 | -from maasserver.enum import IPADDRESS_TYPE, NODE_STATUS, RDNS_MODE_CHOICES |
350 | +from testtools.matchers import Contains, Equals |
351 | + |
352 | +from maasserver.enum import ( |
353 | + IPADDRESS_TYPE, |
354 | + NODE_STATUS, |
355 | + RDNS_MODE, |
356 | + RDNS_MODE_CHOICES, |
357 | +) |
358 | from maasserver.testing.api import APITestCase, explain_unexpected_response |
359 | -from maasserver.testing.factory import factory, RANDOM |
360 | +from maasserver.testing.factory import factory |
361 | from maasserver.utils.orm import reload_object |
362 | +from maastesting.djangotestcase import CountQueries |
363 | from provisioningserver.boot import BootMethodRegistry |
364 | from provisioningserver.utils.network import inet_ntop, IPRangeStatistics |
365 | |
366 | @@ -36,21 +42,58 @@ class TestSubnetsAPI(APITestCase.ForUser): |
367 | self.assertEqual("/MAAS/api/2.0/subnets/", get_subnets_uri()) |
368 | |
369 | def test_read(self): |
370 | - subnets = [factory.make_Subnet() for _ in range(3)] |
371 | + def make_subnet(): |
372 | + space = factory.make_Space() |
373 | + subnet = factory.make_Subnet(space=space) |
374 | + primary_rack = factory.make_RackController(subnet=subnet) |
375 | + secondary_rack = factory.make_RackController(subnet=subnet) |
376 | + relay_vlan = factory.make_VLAN() |
377 | + vlan = subnet.vlan |
378 | + vlan.dhcp_on = True |
379 | + vlan.primary_rack = primary_rack |
380 | + vlan.secondary_rack = secondary_rack |
381 | + vlan.relay_vlan = relay_vlan |
382 | + vlan.save() |
383 | + return subnet |
384 | + |
385 | + subnets = [make_subnet()] |
386 | uri = get_subnets_uri() |
387 | - response = self.client.get(uri) |
388 | + with CountQueries() as counter: |
389 | + response = self.client.get(uri) |
390 | + base_count = counter.count |
391 | |
392 | self.assertEqual( |
393 | http.client.OK, response.status_code, response.content |
394 | ) |
395 | - expected_ids = [subnet.id for subnet in subnets] |
396 | + |
397 | result_ids = [ |
398 | subnet["id"] |
399 | for subnet in json.loads( |
400 | response.content.decode(settings.DEFAULT_CHARSET) |
401 | ) |
402 | ] |
403 | - self.assertCountEqual(expected_ids, result_ids) |
404 | + self.assertCountEqual( |
405 | + [subnet.id for subnet in subnets], |
406 | + result_ids, |
407 | + json.loads(response.content.decode(settings.DEFAULT_CHARSET)), |
408 | + ) |
409 | + |
410 | + subnets.append(make_subnet()) |
411 | + with CountQueries() as counter: |
412 | + response = self.client.get(uri) |
413 | + # XXX: These should be the same. |
414 | + self.assertEqual(base_count + 7, counter.count) |
415 | + |
416 | + self.assertEqual( |
417 | + http.client.OK, response.status_code, response.content |
418 | + ) |
419 | + result_ids = [ |
420 | + subnet["id"] |
421 | + for subnet in json.loads( |
422 | + response.content.decode(settings.DEFAULT_CHARSET) |
423 | + ) |
424 | + ] |
425 | + self.assertCountEqual([subnet.id for subnet in subnets], result_ids) |
426 | |
427 | def test_create(self): |
428 | self.become_admin() |
429 | @@ -269,8 +312,15 @@ class TestSubnetAPI(APITestCase.ForUser): |
430 | "/MAAS/api/2.0/subnets/%s/" % subnet.id, get_subnet_uri(subnet) |
431 | ) |
432 | |
433 | - def test_read(self): |
434 | - subnet = factory.make_Subnet(space=RANDOM) |
435 | + def test_read_basic(self): |
436 | + subnet = factory.make_Subnet( |
437 | + name="my-subnet", |
438 | + cidr="10.10.10.0/24", |
439 | + gateway_ip=None, |
440 | + space=None, |
441 | + dns_servers=[], |
442 | + disabled_boot_architectures=[], |
443 | + ) |
444 | uri = get_subnet_uri(subnet) |
445 | response = self.client.get(uri) |
446 | |
447 | @@ -280,34 +330,100 @@ class TestSubnetAPI(APITestCase.ForUser): |
448 | parsed_subnet = json.loads( |
449 | response.content.decode(settings.DEFAULT_CHARSET) |
450 | ) |
451 | - self.assertThat( |
452 | + self.assertEqual( |
453 | parsed_subnet, |
454 | - ContainsDict( |
455 | - { |
456 | - "id": Equals(subnet.id), |
457 | - "name": Equals(subnet.name), |
458 | - "vlan": ContainsDict({"vid": Equals(subnet.vlan.vid)}), |
459 | - "space": Equals(subnet.space.get_name()), |
460 | - "cidr": Equals(subnet.cidr), |
461 | - "gateway_ip": Equals(subnet.gateway_ip), |
462 | - "dns_servers": Equals(subnet.dns_servers), |
463 | - "managed": Equals(subnet.managed), |
464 | - "disabled_boot_architectures": Equals( |
465 | - subnet.disabled_boot_architectures |
466 | - ), |
467 | - } |
468 | - ), |
469 | + { |
470 | + "id": subnet.id, |
471 | + "name": "my-subnet", |
472 | + "active_discovery": False, |
473 | + "allow_dns": True, |
474 | + "allow_proxy": True, |
475 | + "description": "", |
476 | + "space": "undefined", |
477 | + "cidr": "10.10.10.0/24", |
478 | + "gateway_ip": None, |
479 | + "dns_servers": [], |
480 | + "managed": True, |
481 | + "disabled_boot_architectures": [], |
482 | + "rdns_mode": RDNS_MODE.DEFAULT, |
483 | + "resource_uri": f"/MAAS/api/2.0/subnets/{subnet.id}/", |
484 | + "vlan": { |
485 | + "id": subnet.vlan_id, |
486 | + "dhcp_on": subnet.vlan.dhcp_on, |
487 | + "external_dhcp": subnet.vlan.external_dhcp, |
488 | + "fabric": subnet.vlan.fabric.get_name(), |
489 | + "fabric_id": subnet.vlan.fabric_id, |
490 | + "mtu": subnet.vlan.mtu, |
491 | + "primary_rack": None, |
492 | + "secondary_rack": None, |
493 | + "space": "undefined", |
494 | + "vid": subnet.vlan.vid, |
495 | + "name": subnet.vlan.get_name(), |
496 | + "relay_vlan": None, |
497 | + "resource_uri": f"/MAAS/api/2.0/vlans/{subnet.vlan_id}/", |
498 | + }, |
499 | + }, |
500 | ) |
501 | |
502 | - def test_read_includes_description(self): |
503 | - description = factory.make_string() |
504 | - subnet = factory.make_Subnet(space=RANDOM, description=description) |
505 | + def test_read_full(self): |
506 | + space = factory.make_Space(name="my-space") |
507 | + subnet = factory.make_Subnet( |
508 | + name="my-subnet", |
509 | + cidr="10.20.20.0/24", |
510 | + gateway_ip="10.20.20.1", |
511 | + space=space, |
512 | + dns_servers=["10.20.20.20"], |
513 | + disabled_boot_architectures=["pxe"], |
514 | + active_discovery=True, |
515 | + allow_proxy=False, |
516 | + allow_dns=False, |
517 | + description="My subnet", |
518 | + managed=False, |
519 | + rdns_mode=RDNS_MODE.DISABLED, |
520 | + ) |
521 | uri = get_subnet_uri(subnet) |
522 | response = self.client.get(uri) |
523 | + |
524 | + self.assertEqual( |
525 | + http.client.OK, response.status_code, response.content |
526 | + ) |
527 | parsed_subnet = json.loads( |
528 | response.content.decode(settings.DEFAULT_CHARSET) |
529 | ) |
530 | - self.assertEqual(description, parsed_subnet["description"]) |
531 | + self.assertEqual( |
532 | + parsed_subnet, |
533 | + { |
534 | + "id": subnet.id, |
535 | + "name": "my-subnet", |
536 | + "active_discovery": True, |
537 | + "allow_dns": False, |
538 | + "allow_proxy": False, |
539 | + "description": "My subnet", |
540 | + "space": "my-space", |
541 | + "cidr": "10.20.20.0/24", |
542 | + "gateway_ip": "10.20.20.1", |
543 | + "dns_servers": ["10.20.20.20"], |
544 | + "managed": False, |
545 | + "disabled_boot_architectures": ["pxe"], |
546 | + "rdns_mode": RDNS_MODE.DISABLED, |
547 | + "resource_uri": f"/MAAS/api/2.0/subnets/{subnet.id}/", |
548 | + "vlan": { |
549 | + "id": subnet.vlan_id, |
550 | + "dhcp_on": subnet.vlan.dhcp_on, |
551 | + "external_dhcp": subnet.vlan.external_dhcp, |
552 | + "fabric": subnet.vlan.fabric.get_name(), |
553 | + "fabric_id": subnet.vlan.fabric_id, |
554 | + "mtu": subnet.vlan.mtu, |
555 | + "primary_rack": None, |
556 | + "secondary_rack": None, |
557 | + "space": "my-space", |
558 | + "vid": subnet.vlan.vid, |
559 | + "name": subnet.vlan.get_name(), |
560 | + "relay_vlan": None, |
561 | + "resource_uri": f"/MAAS/api/2.0/vlans/{subnet.vlan_id}/", |
562 | + }, |
563 | + }, |
564 | + ) |
565 | |
566 | def test_read_404_when_bad_id(self): |
567 | uri = reverse("subnet_handler", args=[random.randint(100, 1000)]) |
568 | diff --git a/src/maasserver/api/tests/test_vlans.py b/src/maasserver/api/tests/test_vlans.py |
569 | index 2296787..38665d2 100644 |
570 | --- a/src/maasserver/api/tests/test_vlans.py |
571 | +++ b/src/maasserver/api/tests/test_vlans.py |
572 | @@ -10,12 +10,13 @@ import random |
573 | |
574 | from django.conf import settings |
575 | from django.urls import reverse |
576 | -from testtools.matchers import ContainsDict, Equals, Is, Not |
577 | +from testtools.matchers import Equals, Is, Not |
578 | |
579 | -from maasserver.models import Space |
580 | +from maasserver.models import Space, VLAN |
581 | from maasserver.testing.api import APITestCase |
582 | from maasserver.testing.factory import factory, RANDOM |
583 | from maasserver.utils.orm import reload_object |
584 | +from maastesting.djangotestcase import CountQueries |
585 | |
586 | |
587 | def get_vlans_uri(fabric): |
588 | @@ -41,23 +42,71 @@ class TestVlansAPI(APITestCase.ForUser): |
589 | ) |
590 | |
591 | def test_read(self): |
592 | + def make_vlan(): |
593 | + space = factory.make_Space() |
594 | + subnet = factory.make_Subnet(fabric=fabric, space=space) |
595 | + primary_rack = factory.make_RackController() |
596 | + factory.make_Interface(node=primary_rack, subnet=subnet) |
597 | + secondary_rack = factory.make_RackController() |
598 | + factory.make_Interface(node=secondary_rack, subnet=subnet) |
599 | + relay_vlan = factory.make_VLAN() |
600 | + vlan = subnet.vlan |
601 | + vlan.dhcp_on = True |
602 | + vlan.primary_rack = primary_rack |
603 | + vlan.secondary_rack = secondary_rack |
604 | + vlan.relay_vlan = relay_vlan |
605 | + vlan.save() |
606 | + |
607 | + def serialize_vlan(vlan): |
608 | + return { |
609 | + "id": vlan.id, |
610 | + "name": vlan.get_name(), |
611 | + "vid": vlan.vid, |
612 | + "fabric": vlan.fabric.name, |
613 | + "fabric_id": vlan.fabric_id, |
614 | + "mtu": vlan.mtu, |
615 | + "primary_rack": ( |
616 | + vlan.primary_rack.system_id if vlan.primary_rack else None |
617 | + ), |
618 | + "secondary_rack": ( |
619 | + vlan.secondary_rack.system_id |
620 | + if vlan.secondary_rack |
621 | + else None |
622 | + ), |
623 | + "dhcp_on": vlan.dhcp_on, |
624 | + "external_dhcp": None, |
625 | + "relay_vlan": serialize_vlan(vlan.relay_vlan) |
626 | + if vlan.relay_vlan |
627 | + else None, |
628 | + "space": vlan.space.name if vlan.space else "undefined", |
629 | + "resource_uri": f"/MAAS/api/2.0/vlans/{vlan.id}/", |
630 | + } |
631 | + |
632 | fabric = factory.make_Fabric() |
633 | - for vid in range(1, 4): |
634 | - factory.make_VLAN(vid=vid, fabric=fabric) |
635 | + make_vlan() |
636 | + |
637 | uri = get_vlans_uri(fabric) |
638 | - response = self.client.get(uri) |
639 | + with CountQueries() as counter: |
640 | + response = self.client.get(uri) |
641 | + base_count = counter.count |
642 | |
643 | self.assertEqual( |
644 | http.client.OK, response.status_code, response.content |
645 | ) |
646 | - expected_ids = [vlan.vid for vlan in fabric.vlan_set.all()] |
647 | - result_ids = [ |
648 | - vlan["vid"] |
649 | - for vlan in json.loads( |
650 | - response.content.decode(settings.DEFAULT_CHARSET) |
651 | - ) |
652 | - ] |
653 | - self.assertCountEqual(expected_ids, result_ids) |
654 | + result = json.loads(response.content.decode(settings.DEFAULT_CHARSET)) |
655 | + # It's three VLANs, since when creating a fabric, a default VLAN |
656 | + # is always created. |
657 | + vlans = {vlan.id: vlan for vlan in VLAN.objects.filter(fabric=fabric)} |
658 | + self.assertEqual(2, len(result)) |
659 | + for serialized_vlan in result: |
660 | + vlan = vlans[serialized_vlan["id"]] |
661 | + self.assertEqual(serialize_vlan(vlan), serialized_vlan) |
662 | + |
663 | + make_vlan() |
664 | + with CountQueries() as counter: |
665 | + response = self.client.get(uri) |
666 | + # XXX: These really should be equal. |
667 | + self.assertEqual(base_count + 5, counter.count) |
668 | |
669 | def test_create(self): |
670 | self.become_admin() |
671 | @@ -187,9 +236,11 @@ class TestVlanAPI(APITestCase.ForUser): |
672 | "/MAAS/api/2.0/vlans/%s/" % vlan.id, get_vlan_uri(vlan) |
673 | ) |
674 | |
675 | - def test_read(self): |
676 | - fabric = factory.make_Fabric() |
677 | - vlan = factory.make_VLAN(fabric=fabric) |
678 | + def test_read_basic(self): |
679 | + fabric = factory.make_Fabric(name="my-fabric") |
680 | + vlan = factory.make_VLAN( |
681 | + fabric=fabric, name="my-vlan", vid=123, mtu=1234 |
682 | + ) |
683 | uri = get_vlan_uri(vlan) |
684 | response = self.client.get(uri) |
685 | |
686 | @@ -199,24 +250,29 @@ class TestVlanAPI(APITestCase.ForUser): |
687 | parsed_vlan = json.loads( |
688 | response.content.decode(settings.DEFAULT_CHARSET) |
689 | ) |
690 | - self.assertThat( |
691 | + self.assertEqual( |
692 | parsed_vlan, |
693 | - ContainsDict( |
694 | - { |
695 | - "id": Equals(vlan.id), |
696 | - "name": Equals(vlan.get_name()), |
697 | - "vid": Equals(vlan.vid), |
698 | - "fabric": Equals(fabric.get_name()), |
699 | - "fabric_id": Equals(fabric.id), |
700 | - "resource_uri": Equals(get_vlan_uri(vlan)), |
701 | - } |
702 | - ), |
703 | - ) |
704 | - |
705 | - def test_read_with_fabric(self): |
706 | - fabric = factory.make_Fabric() |
707 | - vlan = factory.make_VLAN(fabric=fabric) |
708 | - uri = get_vlan_uri(vlan, fabric) |
709 | + { |
710 | + "id": vlan.id, |
711 | + "name": "my-vlan", |
712 | + "vid": 123, |
713 | + "fabric": "my-fabric", |
714 | + "fabric_id": fabric.id, |
715 | + "mtu": 1234, |
716 | + "primary_rack": None, |
717 | + "secondary_rack": None, |
718 | + "dhcp_on": False, |
719 | + "external_dhcp": None, |
720 | + "relay_vlan": None, |
721 | + "space": "undefined", |
722 | + "resource_uri": f"/MAAS/api/2.0/vlans/{vlan.id}/", |
723 | + }, |
724 | + ) |
725 | + |
726 | + def test_read_with_space(self): |
727 | + space = factory.make_Space(name="my-space") |
728 | + vlan = factory.make_VLAN(space=space) |
729 | + uri = get_vlan_uri(vlan, vlan.fabric) |
730 | response = self.client.get(uri) |
731 | |
732 | self.assertEqual( |
733 | @@ -225,22 +281,19 @@ class TestVlanAPI(APITestCase.ForUser): |
734 | parsed_vlan = json.loads( |
735 | response.content.decode(settings.DEFAULT_CHARSET) |
736 | ) |
737 | - self.assertThat( |
738 | - parsed_vlan, |
739 | - ContainsDict( |
740 | - { |
741 | - "id": Equals(vlan.id), |
742 | - "name": Equals(vlan.get_name()), |
743 | - "vid": Equals(vlan.vid), |
744 | - "fabric": Equals(fabric.get_name()), |
745 | - "resource_uri": Equals(get_vlan_uri(vlan)), |
746 | - } |
747 | - ), |
748 | - ) |
749 | - |
750 | - def test_read_with_space(self): |
751 | - space = factory.make_Space() |
752 | - vlan = factory.make_VLAN(space=space) |
753 | + self.assertEqual(parsed_vlan["space"], "my-space") |
754 | + |
755 | + def test_read_with_dhcp(self): |
756 | + subnet = factory.make_Subnet() |
757 | + primary_rack = factory.make_RackController() |
758 | + factory.make_Interface(node=primary_rack, subnet=subnet) |
759 | + secondary_rack = factory.make_RackController() |
760 | + factory.make_Interface(node=secondary_rack, subnet=subnet) |
761 | + vlan = subnet.vlan |
762 | + vlan.dhcp_on = True |
763 | + vlan.primary_rack = primary_rack |
764 | + vlan.secondary_rack = secondary_rack |
765 | + vlan.save() |
766 | uri = get_vlan_uri(vlan, vlan.fabric) |
767 | response = self.client.get(uri) |
768 | |
769 | @@ -250,21 +303,15 @@ class TestVlanAPI(APITestCase.ForUser): |
770 | parsed_vlan = json.loads( |
771 | response.content.decode(settings.DEFAULT_CHARSET) |
772 | ) |
773 | - self.assertThat( |
774 | - parsed_vlan, |
775 | - ContainsDict( |
776 | - { |
777 | - "id": Equals(vlan.id), |
778 | - "name": Equals(vlan.get_name()), |
779 | - "vid": Equals(vlan.vid), |
780 | - "space": Equals(space.get_name()), |
781 | - "resource_uri": Equals(get_vlan_uri(vlan)), |
782 | - } |
783 | - ), |
784 | - ) |
785 | - |
786 | - def test_read_without_space_returns_undefined_space(self): |
787 | - vlan = factory.make_VLAN(space=None) |
788 | + self.assertTrue(parsed_vlan["dhcp_on"]) |
789 | + self.assertEqual(primary_rack.system_id, parsed_vlan["primary_rack"]) |
790 | + self.assertEqual( |
791 | + secondary_rack.system_id, parsed_vlan["secondary_rack"] |
792 | + ) |
793 | + |
794 | + def test_read_with_relay_vlan(self): |
795 | + relay_vlan = factory.make_VLAN(name="my-relay") |
796 | + vlan = factory.make_VLAN(relay_vlan=relay_vlan) |
797 | uri = get_vlan_uri(vlan, vlan.fabric) |
798 | response = self.client.get(uri) |
799 | |
800 | @@ -274,17 +321,23 @@ class TestVlanAPI(APITestCase.ForUser): |
801 | parsed_vlan = json.loads( |
802 | response.content.decode(settings.DEFAULT_CHARSET) |
803 | ) |
804 | - self.assertThat( |
805 | - parsed_vlan, |
806 | - ContainsDict( |
807 | - { |
808 | - "id": Equals(vlan.id), |
809 | - "name": Equals(vlan.get_name()), |
810 | - "vid": Equals(vlan.vid), |
811 | - "space": Equals(Space.UNDEFINED), |
812 | - "resource_uri": Equals(get_vlan_uri(vlan)), |
813 | - } |
814 | - ), |
815 | + self.assertEqual( |
816 | + { |
817 | + "id": relay_vlan.id, |
818 | + "name": "my-relay", |
819 | + "vid": relay_vlan.vid, |
820 | + "fabric": relay_vlan.fabric.name, |
821 | + "fabric_id": relay_vlan.fabric_id, |
822 | + "mtu": relay_vlan.mtu, |
823 | + "primary_rack": None, |
824 | + "secondary_rack": None, |
825 | + "dhcp_on": False, |
826 | + "external_dhcp": None, |
827 | + "relay_vlan": None, |
828 | + "space": "undefined", |
829 | + "resource_uri": f"/MAAS/api/2.0/vlans/{relay_vlan.id}/", |
830 | + }, |
831 | + parsed_vlan["relay_vlan"], |
832 | ) |
833 | |
834 | def test_read_404_when_bad_id(self): |
835 | diff --git a/src/maasserver/testing/factory.py b/src/maasserver/testing/factory.py |
836 | index afaabfe..99e5258 100644 |
837 | --- a/src/maasserver/testing/factory.py |
838 | +++ b/src/maasserver/testing/factory.py |
839 | @@ -1617,6 +1617,7 @@ class Factory(maastesting.factory.Factory): |
840 | primary_rack=None, |
841 | secondary_rack=None, |
842 | relay_vlan=None, |
843 | + mtu=1500, |
844 | ): |
845 | assert vid != 0, "VID=0 VLANs are auto-created" |
846 | if name is RANDOM: |
847 | @@ -1636,6 +1637,7 @@ class Factory(maastesting.factory.Factory): |
848 | primary_rack=primary_rack, |
849 | secondary_rack=secondary_rack, |
850 | relay_vlan=relay_vlan, |
851 | + mtu=mtu, |
852 | ) |
853 | vlan.save() |
854 | for rack in [primary_rack, secondary_rack]: |
UNIT TESTS
-b api-better-tests lp:~bjornt/maas/+git/maas into -b master lp:~maas-committers/maas
STATUS: FAILED maas-ci. internal: 8080/job/ maas/job/ branch- tester/ 12366/console 5657fd1db21c323 73ea32b9d7
LOG: http://
COMMIT: e91fd87abc9b6a0