Merge ~bjornt/maas:api-better-tests into maas: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)
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.

To post a comment you must log in.
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b api-better-tests lp:~bjornt/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas/job/branch-tester/12366/console
COMMIT: e91fd87abc9b6a05657fd1db21c32373ea32b9d7

review: Needs Fixing
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
diff --git a/src/maasserver/api/tests/test_interfaces.py b/src/maasserver/api/tests/test_interfaces.py
index 89c6171..5b17370 100644
--- a/src/maasserver/api/tests/test_interfaces.py
+++ b/src/maasserver/api/tests/test_interfaces.py
@@ -26,6 +26,7 @@ from maasserver.enum import (
26 NODE_TYPE,26 NODE_TYPE,
27)27)
28from maasserver.models import Interface28from maasserver.models import Interface
29from maasserver.models.vlan import DEFAULT_MTU
29from maasserver.testing.api import APITestCase, APITransactionTestCase30from maasserver.testing.api import APITestCase, APITransactionTestCase
30from maasserver.testing.factory import factory31from maasserver.testing.factory import factory
31from maasserver.utils.converters import json_load_bytes32from maasserver.utils.converters import json_load_bytes
@@ -60,6 +61,44 @@ def get_interface_uri(interface, node=None):
60 return reverse("interface_handler", args=[node.system_id, interface])61 return reverse("interface_handler", args=[node.system_id, interface])
6162
6263
64def serialize_vlan(vlan):
65 return {
66 "id": vlan.id,
67 "dhcp_on": vlan.dhcp_on,
68 "external_dhcp": vlan.external_dhcp,
69 "fabric": vlan.fabric.get_name(),
70 "fabric_id": vlan.fabric_id,
71 "mtu": vlan.mtu,
72 "primary_rack": None,
73 "secondary_rack": None,
74 "space": "undefined" if not vlan.space else vlan.space.get_name(),
75 "vid": vlan.vid,
76 "name": vlan.get_name(),
77 "relay_vlan": None,
78 "resource_uri": f"/MAAS/api/2.0/vlans/{vlan.id}/",
79 }
80
81
82def serialize_subnet(subnet):
83 return {
84 "name": subnet.name,
85 "id": subnet.id,
86 "vlan": serialize_vlan(subnet.vlan),
87 "description": "",
88 "cidr": subnet.cidr,
89 "rdns_mode": subnet.rdns_mode,
90 "gateway_ip": subnet.gateway_ip,
91 "dns_servers": subnet.dns_servers,
92 "allow_dns": subnet.allow_dns,
93 "allow_proxy": subnet.allow_proxy,
94 "active_discovery": subnet.active_discovery,
95 "managed": subnet.managed,
96 "disabled_boot_architectures": subnet.disabled_boot_architectures,
97 "space": "undefined" if not subnet.space else subnet.space.get_name(),
98 "resource_uri": f"/MAAS/api/2.0/subnets/{subnet.id}/",
99 }
100
101
63def make_complex_interface(node, name=None):102def make_complex_interface(node, name=None):
64 """Makes interface with parents and children."""103 """Makes interface with parents and children."""
65 fabric = factory.make_Fabric()104 fabric = factory.make_Fabric()
@@ -887,14 +926,113 @@ class TestNodeInterfaceAPI(APITransactionTestCase.ForUser):
887 get_interface_uri(interface, node=node),926 get_interface_uri(interface, node=node),
888 )927 )
889928
929 def test_read_basic(self):
930 node = factory.make_Node()
931 interface = factory.make_Interface(
932 node=node,
933 name="eno1",
934 iftype=INTERFACE_TYPE.PHYSICAL,
935 mac_address="11:11:11:11:11:11",
936 enabled=False,
937 vendor="my-vendor",
938 product="my-product",
939 firmware_version="1.2.3",
940 link_connected=False,
941 vlan=None,
942 interface_speed=100,
943 sriov_max_vf=0,
944 tags=[],
945 )
946
947 uri = get_interface_uri(interface)
948 response = self.client.get(uri)
949 self.assertEqual(
950 http.client.OK, response.status_code, response.content
951 )
952 parsed_interface = json_load_bytes(response.content)
953 self.maxDiff = None
954 self.assertEqual(
955 {
956 "system_id": node.system_id,
957 "id": interface.id,
958 "name": "eno1",
959 "type": INTERFACE_TYPE.PHYSICAL,
960 "vlan": None,
961 "mac_address": "11:11:11:11:11:11",
962 "parents": [],
963 "children": [],
964 "tags": [],
965 "enabled": False,
966 "links": [],
967 "params": "",
968 "discovered": None,
969 "effective_mtu": DEFAULT_MTU,
970 "vendor": "my-vendor",
971 "product": "my-product",
972 "firmware_version": "1.2.3",
973 "link_connected": False,
974 "interface_speed": 100,
975 "link_speed": 0,
976 "numa_node": 0,
977 "sriov_max_vf": 0,
978 "resource_uri": (
979 f"/MAAS/api/2.0/nodes/{node.system_id}/interfaces/{interface.id}/"
980 ),
981 },
982 parsed_interface,
983 )
984
985 def test_read_connected(self):
986 vlan = factory.make_VLAN(name="my-vlan", mtu=1234)
987 interface = factory.make_Interface(
988 enabled=True,
989 link_connected=True,
990 vlan=vlan,
991 interface_speed=100,
992 link_speed=10,
993 tags=["foo", "bar"],
994 )
995
996 uri = get_interface_uri(interface)
997 response = self.client.get(uri)
998 self.assertEqual(
999 http.client.OK, response.status_code, response.content
1000 )
1001 parsed_interface = json_load_bytes(response.content)
1002 expected_parts = {
1003 "id": interface.id,
1004 "tags": ["foo", "bar"],
1005 "enabled": True,
1006 "discovered": None,
1007 "effective_mtu": 1234,
1008 "link_connected": True,
1009 "interface_speed": 100,
1010 "link_speed": 10,
1011 "vlan": {
1012 "id": vlan.id,
1013 "dhcp_on": vlan.dhcp_on,
1014 "external_dhcp": vlan.external_dhcp,
1015 "fabric": vlan.fabric.get_name(),
1016 "fabric_id": vlan.fabric_id,
1017 "mtu": vlan.mtu,
1018 "primary_rack": None,
1019 "secondary_rack": None,
1020 "space": "undefined",
1021 "vid": vlan.vid,
1022 "name": vlan.get_name(),
1023 "relay_vlan": None,
1024 "resource_uri": f"/MAAS/api/2.0/vlans/{vlan.id}/",
1025 },
1026 }
1027 for key, value in expected_parts.items():
1028 self.assertEqual(parsed_interface[key], value)
1029
890 def test_read(self):1030 def test_read(self):
891 node = factory.make_Node()1031 node = factory.make_Node()
892 bond, parents, children = make_complex_interface(node)1032 bond, parents, children = make_complex_interface(node)
893 # Add some known links to the bond interface.
8941033
895 # First link is a DHCP link.1034 # Add some known links to the bond interface.
896 links = []1035 dhcp_subnet = factory.make_Subnet(vlan=bond.vlan)
897 dhcp_subnet = factory.make_Subnet()
898 dhcp_ip = factory.make_StaticIPAddress(1036 dhcp_ip = factory.make_StaticIPAddress(
899 alloc_type=IPADDRESS_TYPE.DHCP,1037 alloc_type=IPADDRESS_TYPE.DHCP,
900 ip="",1038 ip="",
@@ -908,19 +1046,9 @@ class TestNodeInterfaceAPI(APITransactionTestCase.ForUser):
908 subnet=dhcp_subnet,1046 subnet=dhcp_subnet,
909 interface=bond,1047 interface=bond,
910 )1048 )
911 links.append(
912 MatchesDict(
913 {
914 "id": Equals(dhcp_ip.id),
915 "mode": Equals(INTERFACE_LINK_TYPE.DHCP),
916 "subnet": ContainsDict({"id": Equals(dhcp_subnet.id)}),
917 "ip_address": Equals(discovered_ip),
918 }
919 )
920 )
9211049
922 # Second link is a STATIC ip link.1050 # Second link is a STATIC ip link.
923 static_subnet = factory.make_Subnet()1051 static_subnet = factory.make_Subnet(vlan=bond.vlan)
924 static_ip = factory.pick_ip_in_network(static_subnet.get_ipnetwork())1052 static_ip = factory.pick_ip_in_network(static_subnet.get_ipnetwork())
925 sip = factory.make_StaticIPAddress(1053 sip = factory.make_StaticIPAddress(
926 alloc_type=IPADDRESS_TYPE.STICKY,1054 alloc_type=IPADDRESS_TYPE.STICKY,
@@ -928,40 +1056,21 @@ class TestNodeInterfaceAPI(APITransactionTestCase.ForUser):
928 subnet=static_subnet,1056 subnet=static_subnet,
929 interface=bond,1057 interface=bond,
930 )1058 )
931 links.append(
932 MatchesDict(
933 {
934 "id": Equals(sip.id),
935 "mode": Equals(INTERFACE_LINK_TYPE.STATIC),
936 "ip_address": Equals(static_ip),
937 "subnet": ContainsDict({"id": Equals(static_subnet.id)}),
938 }
939 )
940 )
9411059
942 # Third link is just a LINK_UP. In reality this cannot exist while the1060 # Third link is just a LINK_UP. In reality this cannot exist while the
943 # other two links exist but for testing we allow it. If validation of1061 # other two links exist but for testing we allow it. If validation of
944 # the StaticIPAddress model ever included this check, which it1062 # the StaticIPAddress model ever included this check, which it
945 # probably should then this will fail and cause this test to break.1063 # probably should then this will fail and cause this test to break.
946 link_subnet = factory.make_Subnet()1064 link_subnet = factory.make_Subnet(vlan=bond.vlan)
947 link_ip = factory.make_StaticIPAddress(1065 link_ip = factory.make_StaticIPAddress(
948 alloc_type=IPADDRESS_TYPE.STICKY,1066 alloc_type=IPADDRESS_TYPE.STICKY,
949 ip="",1067 ip="",
950 subnet=link_subnet,1068 subnet=link_subnet,
951 interface=bond,1069 interface=bond,
952 )1070 )
953 links.append(
954 MatchesDict(
955 {
956 "id": Equals(link_ip.id),
957 "mode": Equals(INTERFACE_LINK_TYPE.LINK_UP),
958 "subnet": ContainsDict({"id": Equals(link_subnet.id)}),
959 }
960 )
961 )
9621071
963 # Add MTU parameter.1072 # Add MTU parameter.
964 bond.params = {"mtu": random.randint(800, 2000)}1073 bond.params = {"mtu": 1234}
965 bond.save()1074 bond.save()
9661075
967 uri = get_interface_uri(bond)1076 uri = get_interface_uri(bond)
@@ -970,33 +1079,77 @@ class TestNodeInterfaceAPI(APITransactionTestCase.ForUser):
970 http.client.OK, response.status_code, response.content1079 http.client.OK, response.status_code, response.content
971 )1080 )
972 parsed_interface = json_load_bytes(response.content)1081 parsed_interface = json_load_bytes(response.content)
973 self.assertThat(1082
974 parsed_interface,1083 expected_parts = {
975 ContainsDict(1084 "id": bond.id,
976 {1085 "name": bond.name,
977 "id": Equals(bond.id),1086 "type": bond.type,
978 "name": Equals(bond.name),1087 "mac_address": str(bond.mac_address),
979 "type": Equals(bond.type),1088 "vlan": serialize_vlan(bond.vlan),
980 "vlan": ContainsDict({"id": Equals(bond.vlan.id)}),1089 "tags": bond.tags,
981 "mac_address": Equals("%s" % bond.mac_address),1090 "resource_uri": get_interface_uri(bond),
982 "tags": Equals(bond.tags),1091 "params": {"mtu": 1234},
983 "resource_uri": Equals(get_interface_uri(bond)),1092 "effective_mtu": 1500,
984 "params": Equals(bond.params),1093 "system_id": node.system_id,
985 "effective_mtu": Equals(bond.get_effective_mtu()),1094 }
986 "system_id": Equals(node.system_id),1095 for key, value in expected_parts.items():
987 }1096 self.assertEqual(parsed_interface[key], value)
988 ),
989 )
990 self.assertEqual(1097 self.assertEqual(
991 sorted(nic.name for nic in parents), parsed_interface["parents"]1098 sorted(nic.name for nic in parents), parsed_interface["parents"]
992 )1099 )
993 self.assertEqual(1100 self.assertEqual(
994 sorted(nic.name for nic in children), parsed_interface["children"]1101 sorted(nic.name for nic in children), parsed_interface["children"]
995 )1102 )
996 self.assertThat(parsed_interface["links"], MatchesSetwise(*links))1103
997 json_discovered = parsed_interface["discovered"][0]1104 self.assertEqual(
998 self.assertEqual(dhcp_subnet.id, json_discovered["subnet"]["id"])1105 [
999 self.assertEqual(discovered_ip, json_discovered["ip_address"])1106 {
1107 "id": dhcp_ip.id,
1108 "mode": "dhcp",
1109 "ip_address": discovered_ip,
1110 "subnet": serialize_subnet(dhcp_subnet),
1111 },
1112 {
1113 "id": sip.id,
1114 "mode": "static",
1115 "ip_address": static_ip,
1116 "subnet": serialize_subnet(static_subnet),
1117 },
1118 {
1119 "id": link_ip.id,
1120 "mode": "link_up",
1121 "subnet": serialize_subnet(link_subnet),
1122 },
1123 ],
1124 parsed_interface["links"],
1125 )
1126 self.assertEqual(
1127 [
1128 {
1129 "ip_address": discovered_ip,
1130 "subnet": serialize_subnet(dhcp_subnet),
1131 },
1132 ],
1133 parsed_interface["discovered"],
1134 )
1135
1136 def test_read_effective_mtu(self):
1137 node = factory.make_Node()
1138 bond, parents, children = make_complex_interface(node)
1139 bond.params = {"mtu": 1000}
1140 bond.save()
1141 children[0].params = {"mtu": 2000}
1142 children[0].save()
1143
1144 uri = get_interface_uri(bond)
1145 response = self.client.get(uri)
1146 self.assertEqual(
1147 http.client.OK, response.status_code, response.content
1148 )
1149 parsed_interface = json_load_bytes(response.content)
1150
1151 self.assertEqual(bond.id, parsed_interface["id"])
1152 self.assertEqual(2000, parsed_interface["effective_mtu"])
10001153
1001 def test_read_by_specifier(self):1154 def test_read_by_specifier(self):
1002 node = factory.make_Node(hostname="tasty-biscuits")1155 node = factory.make_Node(hostname="tasty-biscuits")
diff --git a/src/maasserver/api/tests/test_subnets.py b/src/maasserver/api/tests/test_subnets.py
index c85dede..2fc8cad 100644
--- a/src/maasserver/api/tests/test_subnets.py
+++ b/src/maasserver/api/tests/test_subnets.py
@@ -8,12 +8,18 @@ import random
88
9from django.conf import settings9from django.conf import settings
10from django.urls import reverse10from django.urls import reverse
11from testtools.matchers import Contains, ContainsDict, Equals11from testtools.matchers import Contains, Equals
1212
13from maasserver.enum import IPADDRESS_TYPE, NODE_STATUS, RDNS_MODE_CHOICES13from maasserver.enum import (
14 IPADDRESS_TYPE,
15 NODE_STATUS,
16 RDNS_MODE,
17 RDNS_MODE_CHOICES,
18)
14from maasserver.testing.api import APITestCase, explain_unexpected_response19from maasserver.testing.api import APITestCase, explain_unexpected_response
15from maasserver.testing.factory import factory, RANDOM20from maasserver.testing.factory import factory
16from maasserver.utils.orm import reload_object21from maasserver.utils.orm import reload_object
22from maastesting.djangotestcase import CountQueries
17from provisioningserver.boot import BootMethodRegistry23from provisioningserver.boot import BootMethodRegistry
18from provisioningserver.utils.network import inet_ntop, IPRangeStatistics24from provisioningserver.utils.network import inet_ntop, IPRangeStatistics
1925
@@ -36,21 +42,58 @@ class TestSubnetsAPI(APITestCase.ForUser):
36 self.assertEqual("/MAAS/api/2.0/subnets/", get_subnets_uri())42 self.assertEqual("/MAAS/api/2.0/subnets/", get_subnets_uri())
3743
38 def test_read(self):44 def test_read(self):
39 subnets = [factory.make_Subnet() for _ in range(3)]45 def make_subnet():
46 space = factory.make_Space()
47 subnet = factory.make_Subnet(space=space)
48 primary_rack = factory.make_RackController(subnet=subnet)
49 secondary_rack = factory.make_RackController(subnet=subnet)
50 relay_vlan = factory.make_VLAN()
51 vlan = subnet.vlan
52 vlan.dhcp_on = True
53 vlan.primary_rack = primary_rack
54 vlan.secondary_rack = secondary_rack
55 vlan.relay_vlan = relay_vlan
56 vlan.save()
57 return subnet
58
59 subnets = [make_subnet()]
40 uri = get_subnets_uri()60 uri = get_subnets_uri()
41 response = self.client.get(uri)61 with CountQueries() as counter:
62 response = self.client.get(uri)
63 base_count = counter.count
4264
43 self.assertEqual(65 self.assertEqual(
44 http.client.OK, response.status_code, response.content66 http.client.OK, response.status_code, response.content
45 )67 )
46 expected_ids = [subnet.id for subnet in subnets]68
47 result_ids = [69 result_ids = [
48 subnet["id"]70 subnet["id"]
49 for subnet in json.loads(71 for subnet in json.loads(
50 response.content.decode(settings.DEFAULT_CHARSET)72 response.content.decode(settings.DEFAULT_CHARSET)
51 )73 )
52 ]74 ]
53 self.assertCountEqual(expected_ids, result_ids)75 self.assertCountEqual(
76 [subnet.id for subnet in subnets],
77 result_ids,
78 json.loads(response.content.decode(settings.DEFAULT_CHARSET)),
79 )
80
81 subnets.append(make_subnet())
82 with CountQueries() as counter:
83 response = self.client.get(uri)
84 # XXX: These should be the same.
85 self.assertEqual(base_count + 7, counter.count)
86
87 self.assertEqual(
88 http.client.OK, response.status_code, response.content
89 )
90 result_ids = [
91 subnet["id"]
92 for subnet in json.loads(
93 response.content.decode(settings.DEFAULT_CHARSET)
94 )
95 ]
96 self.assertCountEqual([subnet.id for subnet in subnets], result_ids)
5497
55 def test_create(self):98 def test_create(self):
56 self.become_admin()99 self.become_admin()
@@ -269,8 +312,15 @@ class TestSubnetAPI(APITestCase.ForUser):
269 "/MAAS/api/2.0/subnets/%s/" % subnet.id, get_subnet_uri(subnet)312 "/MAAS/api/2.0/subnets/%s/" % subnet.id, get_subnet_uri(subnet)
270 )313 )
271314
272 def test_read(self):315 def test_read_basic(self):
273 subnet = factory.make_Subnet(space=RANDOM)316 subnet = factory.make_Subnet(
317 name="my-subnet",
318 cidr="10.10.10.0/24",
319 gateway_ip=None,
320 space=None,
321 dns_servers=[],
322 disabled_boot_architectures=[],
323 )
274 uri = get_subnet_uri(subnet)324 uri = get_subnet_uri(subnet)
275 response = self.client.get(uri)325 response = self.client.get(uri)
276326
@@ -280,34 +330,100 @@ class TestSubnetAPI(APITestCase.ForUser):
280 parsed_subnet = json.loads(330 parsed_subnet = json.loads(
281 response.content.decode(settings.DEFAULT_CHARSET)331 response.content.decode(settings.DEFAULT_CHARSET)
282 )332 )
283 self.assertThat(333 self.assertEqual(
284 parsed_subnet,334 parsed_subnet,
285 ContainsDict(335 {
286 {336 "id": subnet.id,
287 "id": Equals(subnet.id),337 "name": "my-subnet",
288 "name": Equals(subnet.name),338 "active_discovery": False,
289 "vlan": ContainsDict({"vid": Equals(subnet.vlan.vid)}),339 "allow_dns": True,
290 "space": Equals(subnet.space.get_name()),340 "allow_proxy": True,
291 "cidr": Equals(subnet.cidr),341 "description": "",
292 "gateway_ip": Equals(subnet.gateway_ip),342 "space": "undefined",
293 "dns_servers": Equals(subnet.dns_servers),343 "cidr": "10.10.10.0/24",
294 "managed": Equals(subnet.managed),344 "gateway_ip": None,
295 "disabled_boot_architectures": Equals(345 "dns_servers": [],
296 subnet.disabled_boot_architectures346 "managed": True,
297 ),347 "disabled_boot_architectures": [],
298 }348 "rdns_mode": RDNS_MODE.DEFAULT,
299 ),349 "resource_uri": f"/MAAS/api/2.0/subnets/{subnet.id}/",
350 "vlan": {
351 "id": subnet.vlan_id,
352 "dhcp_on": subnet.vlan.dhcp_on,
353 "external_dhcp": subnet.vlan.external_dhcp,
354 "fabric": subnet.vlan.fabric.get_name(),
355 "fabric_id": subnet.vlan.fabric_id,
356 "mtu": subnet.vlan.mtu,
357 "primary_rack": None,
358 "secondary_rack": None,
359 "space": "undefined",
360 "vid": subnet.vlan.vid,
361 "name": subnet.vlan.get_name(),
362 "relay_vlan": None,
363 "resource_uri": f"/MAAS/api/2.0/vlans/{subnet.vlan_id}/",
364 },
365 },
300 )366 )
301367
302 def test_read_includes_description(self):368 def test_read_full(self):
303 description = factory.make_string()369 space = factory.make_Space(name="my-space")
304 subnet = factory.make_Subnet(space=RANDOM, description=description)370 subnet = factory.make_Subnet(
371 name="my-subnet",
372 cidr="10.20.20.0/24",
373 gateway_ip="10.20.20.1",
374 space=space,
375 dns_servers=["10.20.20.20"],
376 disabled_boot_architectures=["pxe"],
377 active_discovery=True,
378 allow_proxy=False,
379 allow_dns=False,
380 description="My subnet",
381 managed=False,
382 rdns_mode=RDNS_MODE.DISABLED,
383 )
305 uri = get_subnet_uri(subnet)384 uri = get_subnet_uri(subnet)
306 response = self.client.get(uri)385 response = self.client.get(uri)
386
387 self.assertEqual(
388 http.client.OK, response.status_code, response.content
389 )
307 parsed_subnet = json.loads(390 parsed_subnet = json.loads(
308 response.content.decode(settings.DEFAULT_CHARSET)391 response.content.decode(settings.DEFAULT_CHARSET)
309 )392 )
310 self.assertEqual(description, parsed_subnet["description"])393 self.assertEqual(
394 parsed_subnet,
395 {
396 "id": subnet.id,
397 "name": "my-subnet",
398 "active_discovery": True,
399 "allow_dns": False,
400 "allow_proxy": False,
401 "description": "My subnet",
402 "space": "my-space",
403 "cidr": "10.20.20.0/24",
404 "gateway_ip": "10.20.20.1",
405 "dns_servers": ["10.20.20.20"],
406 "managed": False,
407 "disabled_boot_architectures": ["pxe"],
408 "rdns_mode": RDNS_MODE.DISABLED,
409 "resource_uri": f"/MAAS/api/2.0/subnets/{subnet.id}/",
410 "vlan": {
411 "id": subnet.vlan_id,
412 "dhcp_on": subnet.vlan.dhcp_on,
413 "external_dhcp": subnet.vlan.external_dhcp,
414 "fabric": subnet.vlan.fabric.get_name(),
415 "fabric_id": subnet.vlan.fabric_id,
416 "mtu": subnet.vlan.mtu,
417 "primary_rack": None,
418 "secondary_rack": None,
419 "space": "my-space",
420 "vid": subnet.vlan.vid,
421 "name": subnet.vlan.get_name(),
422 "relay_vlan": None,
423 "resource_uri": f"/MAAS/api/2.0/vlans/{subnet.vlan_id}/",
424 },
425 },
426 )
311427
312 def test_read_404_when_bad_id(self):428 def test_read_404_when_bad_id(self):
313 uri = reverse("subnet_handler", args=[random.randint(100, 1000)])429 uri = reverse("subnet_handler", args=[random.randint(100, 1000)])
diff --git a/src/maasserver/api/tests/test_vlans.py b/src/maasserver/api/tests/test_vlans.py
index 2296787..38665d2 100644
--- a/src/maasserver/api/tests/test_vlans.py
+++ b/src/maasserver/api/tests/test_vlans.py
@@ -10,12 +10,13 @@ import random
1010
11from django.conf import settings11from django.conf import settings
12from django.urls import reverse12from django.urls import reverse
13from testtools.matchers import ContainsDict, Equals, Is, Not13from testtools.matchers import Equals, Is, Not
1414
15from maasserver.models import Space15from maasserver.models import Space, VLAN
16from maasserver.testing.api import APITestCase16from maasserver.testing.api import APITestCase
17from maasserver.testing.factory import factory, RANDOM17from maasserver.testing.factory import factory, RANDOM
18from maasserver.utils.orm import reload_object18from maasserver.utils.orm import reload_object
19from maastesting.djangotestcase import CountQueries
1920
2021
21def get_vlans_uri(fabric):22def get_vlans_uri(fabric):
@@ -41,23 +42,71 @@ class TestVlansAPI(APITestCase.ForUser):
41 )42 )
4243
43 def test_read(self):44 def test_read(self):
45 def make_vlan():
46 space = factory.make_Space()
47 subnet = factory.make_Subnet(fabric=fabric, space=space)
48 primary_rack = factory.make_RackController()
49 factory.make_Interface(node=primary_rack, subnet=subnet)
50 secondary_rack = factory.make_RackController()
51 factory.make_Interface(node=secondary_rack, subnet=subnet)
52 relay_vlan = factory.make_VLAN()
53 vlan = subnet.vlan
54 vlan.dhcp_on = True
55 vlan.primary_rack = primary_rack
56 vlan.secondary_rack = secondary_rack
57 vlan.relay_vlan = relay_vlan
58 vlan.save()
59
60 def serialize_vlan(vlan):
61 return {
62 "id": vlan.id,
63 "name": vlan.get_name(),
64 "vid": vlan.vid,
65 "fabric": vlan.fabric.name,
66 "fabric_id": vlan.fabric_id,
67 "mtu": vlan.mtu,
68 "primary_rack": (
69 vlan.primary_rack.system_id if vlan.primary_rack else None
70 ),
71 "secondary_rack": (
72 vlan.secondary_rack.system_id
73 if vlan.secondary_rack
74 else None
75 ),
76 "dhcp_on": vlan.dhcp_on,
77 "external_dhcp": None,
78 "relay_vlan": serialize_vlan(vlan.relay_vlan)
79 if vlan.relay_vlan
80 else None,
81 "space": vlan.space.name if vlan.space else "undefined",
82 "resource_uri": f"/MAAS/api/2.0/vlans/{vlan.id}/",
83 }
84
44 fabric = factory.make_Fabric()85 fabric = factory.make_Fabric()
45 for vid in range(1, 4):86 make_vlan()
46 factory.make_VLAN(vid=vid, fabric=fabric)87
47 uri = get_vlans_uri(fabric)88 uri = get_vlans_uri(fabric)
48 response = self.client.get(uri)89 with CountQueries() as counter:
90 response = self.client.get(uri)
91 base_count = counter.count
4992
50 self.assertEqual(93 self.assertEqual(
51 http.client.OK, response.status_code, response.content94 http.client.OK, response.status_code, response.content
52 )95 )
53 expected_ids = [vlan.vid for vlan in fabric.vlan_set.all()]96 result = json.loads(response.content.decode(settings.DEFAULT_CHARSET))
54 result_ids = [97 # It's three VLANs, since when creating a fabric, a default VLAN
55 vlan["vid"]98 # is always created.
56 for vlan in json.loads(99 vlans = {vlan.id: vlan for vlan in VLAN.objects.filter(fabric=fabric)}
57 response.content.decode(settings.DEFAULT_CHARSET)100 self.assertEqual(2, len(result))
58 )101 for serialized_vlan in result:
59 ]102 vlan = vlans[serialized_vlan["id"]]
60 self.assertCountEqual(expected_ids, result_ids)103 self.assertEqual(serialize_vlan(vlan), serialized_vlan)
104
105 make_vlan()
106 with CountQueries() as counter:
107 response = self.client.get(uri)
108 # XXX: These really should be equal.
109 self.assertEqual(base_count + 5, counter.count)
61110
62 def test_create(self):111 def test_create(self):
63 self.become_admin()112 self.become_admin()
@@ -187,9 +236,11 @@ class TestVlanAPI(APITestCase.ForUser):
187 "/MAAS/api/2.0/vlans/%s/" % vlan.id, get_vlan_uri(vlan)236 "/MAAS/api/2.0/vlans/%s/" % vlan.id, get_vlan_uri(vlan)
188 )237 )
189238
190 def test_read(self):239 def test_read_basic(self):
191 fabric = factory.make_Fabric()240 fabric = factory.make_Fabric(name="my-fabric")
192 vlan = factory.make_VLAN(fabric=fabric)241 vlan = factory.make_VLAN(
242 fabric=fabric, name="my-vlan", vid=123, mtu=1234
243 )
193 uri = get_vlan_uri(vlan)244 uri = get_vlan_uri(vlan)
194 response = self.client.get(uri)245 response = self.client.get(uri)
195246
@@ -199,24 +250,29 @@ class TestVlanAPI(APITestCase.ForUser):
199 parsed_vlan = json.loads(250 parsed_vlan = json.loads(
200 response.content.decode(settings.DEFAULT_CHARSET)251 response.content.decode(settings.DEFAULT_CHARSET)
201 )252 )
202 self.assertThat(253 self.assertEqual(
203 parsed_vlan,254 parsed_vlan,
204 ContainsDict(255 {
205 {256 "id": vlan.id,
206 "id": Equals(vlan.id),257 "name": "my-vlan",
207 "name": Equals(vlan.get_name()),258 "vid": 123,
208 "vid": Equals(vlan.vid),259 "fabric": "my-fabric",
209 "fabric": Equals(fabric.get_name()),260 "fabric_id": fabric.id,
210 "fabric_id": Equals(fabric.id),261 "mtu": 1234,
211 "resource_uri": Equals(get_vlan_uri(vlan)),262 "primary_rack": None,
212 }263 "secondary_rack": None,
213 ),264 "dhcp_on": False,
214 )265 "external_dhcp": None,
215266 "relay_vlan": None,
216 def test_read_with_fabric(self):267 "space": "undefined",
217 fabric = factory.make_Fabric()268 "resource_uri": f"/MAAS/api/2.0/vlans/{vlan.id}/",
218 vlan = factory.make_VLAN(fabric=fabric)269 },
219 uri = get_vlan_uri(vlan, fabric)270 )
271
272 def test_read_with_space(self):
273 space = factory.make_Space(name="my-space")
274 vlan = factory.make_VLAN(space=space)
275 uri = get_vlan_uri(vlan, vlan.fabric)
220 response = self.client.get(uri)276 response = self.client.get(uri)
221277
222 self.assertEqual(278 self.assertEqual(
@@ -225,22 +281,19 @@ class TestVlanAPI(APITestCase.ForUser):
225 parsed_vlan = json.loads(281 parsed_vlan = json.loads(
226 response.content.decode(settings.DEFAULT_CHARSET)282 response.content.decode(settings.DEFAULT_CHARSET)
227 )283 )
228 self.assertThat(284 self.assertEqual(parsed_vlan["space"], "my-space")
229 parsed_vlan,285
230 ContainsDict(286 def test_read_with_dhcp(self):
231 {287 subnet = factory.make_Subnet()
232 "id": Equals(vlan.id),288 primary_rack = factory.make_RackController()
233 "name": Equals(vlan.get_name()),289 factory.make_Interface(node=primary_rack, subnet=subnet)
234 "vid": Equals(vlan.vid),290 secondary_rack = factory.make_RackController()
235 "fabric": Equals(fabric.get_name()),291 factory.make_Interface(node=secondary_rack, subnet=subnet)
236 "resource_uri": Equals(get_vlan_uri(vlan)),292 vlan = subnet.vlan
237 }293 vlan.dhcp_on = True
238 ),294 vlan.primary_rack = primary_rack
239 )295 vlan.secondary_rack = secondary_rack
240296 vlan.save()
241 def test_read_with_space(self):
242 space = factory.make_Space()
243 vlan = factory.make_VLAN(space=space)
244 uri = get_vlan_uri(vlan, vlan.fabric)297 uri = get_vlan_uri(vlan, vlan.fabric)
245 response = self.client.get(uri)298 response = self.client.get(uri)
246299
@@ -250,21 +303,15 @@ class TestVlanAPI(APITestCase.ForUser):
250 parsed_vlan = json.loads(303 parsed_vlan = json.loads(
251 response.content.decode(settings.DEFAULT_CHARSET)304 response.content.decode(settings.DEFAULT_CHARSET)
252 )305 )
253 self.assertThat(306 self.assertTrue(parsed_vlan["dhcp_on"])
254 parsed_vlan,307 self.assertEqual(primary_rack.system_id, parsed_vlan["primary_rack"])
255 ContainsDict(308 self.assertEqual(
256 {309 secondary_rack.system_id, parsed_vlan["secondary_rack"]
257 "id": Equals(vlan.id),310 )
258 "name": Equals(vlan.get_name()),311
259 "vid": Equals(vlan.vid),312 def test_read_with_relay_vlan(self):
260 "space": Equals(space.get_name()),313 relay_vlan = factory.make_VLAN(name="my-relay")
261 "resource_uri": Equals(get_vlan_uri(vlan)),314 vlan = factory.make_VLAN(relay_vlan=relay_vlan)
262 }
263 ),
264 )
265
266 def test_read_without_space_returns_undefined_space(self):
267 vlan = factory.make_VLAN(space=None)
268 uri = get_vlan_uri(vlan, vlan.fabric)315 uri = get_vlan_uri(vlan, vlan.fabric)
269 response = self.client.get(uri)316 response = self.client.get(uri)
270317
@@ -274,17 +321,23 @@ class TestVlanAPI(APITestCase.ForUser):
274 parsed_vlan = json.loads(321 parsed_vlan = json.loads(
275 response.content.decode(settings.DEFAULT_CHARSET)322 response.content.decode(settings.DEFAULT_CHARSET)
276 )323 )
277 self.assertThat(324 self.assertEqual(
278 parsed_vlan,325 {
279 ContainsDict(326 "id": relay_vlan.id,
280 {327 "name": "my-relay",
281 "id": Equals(vlan.id),328 "vid": relay_vlan.vid,
282 "name": Equals(vlan.get_name()),329 "fabric": relay_vlan.fabric.name,
283 "vid": Equals(vlan.vid),330 "fabric_id": relay_vlan.fabric_id,
284 "space": Equals(Space.UNDEFINED),331 "mtu": relay_vlan.mtu,
285 "resource_uri": Equals(get_vlan_uri(vlan)),332 "primary_rack": None,
286 }333 "secondary_rack": None,
287 ),334 "dhcp_on": False,
335 "external_dhcp": None,
336 "relay_vlan": None,
337 "space": "undefined",
338 "resource_uri": f"/MAAS/api/2.0/vlans/{relay_vlan.id}/",
339 },
340 parsed_vlan["relay_vlan"],
288 )341 )
289342
290 def test_read_404_when_bad_id(self):343 def test_read_404_when_bad_id(self):
diff --git a/src/maasserver/testing/factory.py b/src/maasserver/testing/factory.py
index afaabfe..99e5258 100644
--- a/src/maasserver/testing/factory.py
+++ b/src/maasserver/testing/factory.py
@@ -1617,6 +1617,7 @@ class Factory(maastesting.factory.Factory):
1617 primary_rack=None,1617 primary_rack=None,
1618 secondary_rack=None,1618 secondary_rack=None,
1619 relay_vlan=None,1619 relay_vlan=None,
1620 mtu=1500,
1620 ):1621 ):
1621 assert vid != 0, "VID=0 VLANs are auto-created"1622 assert vid != 0, "VID=0 VLANs are auto-created"
1622 if name is RANDOM:1623 if name is RANDOM:
@@ -1636,6 +1637,7 @@ class Factory(maastesting.factory.Factory):
1636 primary_rack=primary_rack,1637 primary_rack=primary_rack,
1637 secondary_rack=secondary_rack,1638 secondary_rack=secondary_rack,
1638 relay_vlan=relay_vlan,1639 relay_vlan=relay_vlan,
1640 mtu=mtu,
1639 )1641 )
1640 vlan.save()1642 vlan.save()
1641 for rack in [primary_rack, secondary_rack]:1643 for rack in [primary_rack, secondary_rack]:

Subscribers

People subscribed via source and target branches