test_models.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. from django.test import TestCase
  2. from dcim.models import *
  3. class RackTestCase(TestCase):
  4. def setUp(self):
  5. self.site1 = Site.objects.create(
  6. name='TestSite1',
  7. slug='test-site-1'
  8. )
  9. self.site2 = Site.objects.create(
  10. name='TestSite2',
  11. slug='test-site-2'
  12. )
  13. self.group1 = RackGroup.objects.create(
  14. name='TestGroup1',
  15. slug='test-group-1',
  16. site=self.site1
  17. )
  18. self.group2 = RackGroup.objects.create(
  19. name='TestGroup2',
  20. slug='test-group-2',
  21. site=self.site2
  22. )
  23. self.rack = Rack.objects.create(
  24. name='TestRack1',
  25. facility_id='A101',
  26. site=self.site1,
  27. group=self.group1,
  28. u_height=42
  29. )
  30. self.manufacturer = Manufacturer.objects.create(
  31. name='Acme',
  32. slug='acme'
  33. )
  34. self.device_type = {
  35. 'ff2048': DeviceType.objects.create(
  36. manufacturer=self.manufacturer,
  37. model='FrameForwarder 2048',
  38. slug='ff2048'
  39. ),
  40. 'cc5000': DeviceType.objects.create(
  41. manufacturer=self.manufacturer,
  42. model='CurrentCatapult 5000',
  43. slug='cc5000',
  44. u_height=0
  45. ),
  46. }
  47. self.role = {
  48. 'Server': DeviceRole.objects.create(
  49. name='Server',
  50. slug='server',
  51. ),
  52. 'Switch': DeviceRole.objects.create(
  53. name='Switch',
  54. slug='switch',
  55. ),
  56. 'Console Server': DeviceRole.objects.create(
  57. name='Console Server',
  58. slug='console-server',
  59. ),
  60. 'PDU': DeviceRole.objects.create(
  61. name='PDU',
  62. slug='pdu',
  63. ),
  64. }
  65. def test_rack_device_outside_height(self):
  66. rack1 = Rack(
  67. name='TestRack2',
  68. facility_id='A102',
  69. site=self.site1,
  70. u_height=42
  71. )
  72. rack1.save()
  73. device1 = Device(
  74. name='TestSwitch1',
  75. device_type=DeviceType.objects.get(manufacturer__slug='acme', slug='ff2048'),
  76. device_role=DeviceRole.objects.get(slug='switch'),
  77. site=self.site1,
  78. rack=rack1,
  79. position=43,
  80. face=DeviceFaceChoices.FACE_FRONT,
  81. )
  82. device1.save()
  83. with self.assertRaises(ValidationError):
  84. rack1.clean()
  85. def test_rack_group_site(self):
  86. rack_invalid_group = Rack(
  87. name='TestRack2',
  88. facility_id='A102',
  89. site=self.site1,
  90. u_height=42,
  91. group=self.group2
  92. )
  93. rack_invalid_group.save()
  94. with self.assertRaises(ValidationError):
  95. rack_invalid_group.clean()
  96. def test_mount_single_device(self):
  97. device1 = Device(
  98. name='TestSwitch1',
  99. device_type=DeviceType.objects.get(manufacturer__slug='acme', slug='ff2048'),
  100. device_role=DeviceRole.objects.get(slug='switch'),
  101. site=self.site1,
  102. rack=self.rack,
  103. position=10,
  104. face=DeviceFaceChoices.FACE_REAR,
  105. )
  106. device1.save()
  107. # Validate rack height
  108. self.assertEqual(list(self.rack.units), list(reversed(range(1, 43))))
  109. # Validate inventory (front face)
  110. rack1_inventory_front = self.rack.get_front_elevation()
  111. self.assertEqual(rack1_inventory_front[-10]['device'], device1)
  112. del(rack1_inventory_front[-10])
  113. for u in rack1_inventory_front:
  114. self.assertIsNone(u['device'])
  115. # Validate inventory (rear face)
  116. rack1_inventory_rear = self.rack.get_rear_elevation()
  117. self.assertEqual(rack1_inventory_rear[-10]['device'], device1)
  118. del(rack1_inventory_rear[-10])
  119. for u in rack1_inventory_rear:
  120. self.assertIsNone(u['device'])
  121. def test_mount_zero_ru(self):
  122. pdu = Device.objects.create(
  123. name='TestPDU',
  124. device_role=self.role.get('PDU'),
  125. device_type=self.device_type.get('cc5000'),
  126. site=self.site1,
  127. rack=self.rack,
  128. position=None,
  129. face='',
  130. )
  131. self.assertTrue(pdu)
  132. class DeviceTestCase(TestCase):
  133. def setUp(self):
  134. self.site = Site.objects.create(name='Test Site 1', slug='test-site-1')
  135. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  136. self.device_type = DeviceType.objects.create(
  137. manufacturer=manufacturer, model='Test Device Type 1', slug='test-device-type-1'
  138. )
  139. self.device_role = DeviceRole.objects.create(
  140. name='Test Device Role 1', slug='test-device-role-1', color='ff0000'
  141. )
  142. # Create DeviceType components
  143. ConsolePortTemplate(
  144. device_type=self.device_type,
  145. name='Console Port 1'
  146. ).save()
  147. ConsoleServerPortTemplate(
  148. device_type=self.device_type,
  149. name='Console Server Port 1'
  150. ).save()
  151. ppt = PowerPortTemplate(
  152. device_type=self.device_type,
  153. name='Power Port 1',
  154. maximum_draw=1000,
  155. allocated_draw=500
  156. )
  157. ppt.save()
  158. PowerOutletTemplate(
  159. device_type=self.device_type,
  160. name='Power Outlet 1',
  161. power_port=ppt,
  162. feed_leg=POWERFEED_LEG_A
  163. ).save()
  164. InterfaceTemplate(
  165. device_type=self.device_type,
  166. name='Interface 1',
  167. type=InterfaceTypeChoices.TYPE_1GE_FIXED,
  168. mgmt_only=True
  169. ).save()
  170. rpt = RearPortTemplate(
  171. device_type=self.device_type,
  172. name='Rear Port 1',
  173. type=PORT_TYPE_8P8C,
  174. positions=8
  175. )
  176. rpt.save()
  177. FrontPortTemplate(
  178. device_type=self.device_type,
  179. name='Front Port 1',
  180. type=PORT_TYPE_8P8C,
  181. rear_port=rpt,
  182. rear_port_position=2
  183. ).save()
  184. DeviceBayTemplate(
  185. device_type=self.device_type,
  186. name='Device Bay 1'
  187. ).save()
  188. def test_device_creation(self):
  189. """
  190. Ensure that all Device components are copied automatically from the DeviceType.
  191. """
  192. d = Device(
  193. site=self.site,
  194. device_type=self.device_type,
  195. device_role=self.device_role,
  196. name='Test Device 1'
  197. )
  198. d.save()
  199. ConsolePort.objects.get(
  200. device=d,
  201. name='Console Port 1'
  202. )
  203. ConsoleServerPort.objects.get(
  204. device=d,
  205. name='Console Server Port 1'
  206. )
  207. pp = PowerPort.objects.get(
  208. device=d,
  209. name='Power Port 1',
  210. maximum_draw=1000,
  211. allocated_draw=500
  212. )
  213. PowerOutlet.objects.get(
  214. device=d,
  215. name='Power Outlet 1',
  216. power_port=pp,
  217. feed_leg=POWERFEED_LEG_A
  218. )
  219. Interface.objects.get(
  220. device=d,
  221. name='Interface 1',
  222. type=InterfaceTypeChoices.TYPE_1GE_FIXED,
  223. mgmt_only=True
  224. )
  225. rp = RearPort.objects.get(
  226. device=d,
  227. name='Rear Port 1',
  228. type=PORT_TYPE_8P8C,
  229. positions=8
  230. )
  231. FrontPort.objects.get(
  232. device=d,
  233. name='Front Port 1',
  234. type=PORT_TYPE_8P8C,
  235. rear_port=rp,
  236. rear_port_position=2
  237. )
  238. DeviceBay.objects.get(
  239. device=d,
  240. name='Device Bay 1'
  241. )
  242. class CableTestCase(TestCase):
  243. def setUp(self):
  244. site = Site.objects.create(name='Test Site 1', slug='test-site-1')
  245. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  246. devicetype = DeviceType.objects.create(
  247. manufacturer=manufacturer, model='Test Device Type 1', slug='test-device-type-1'
  248. )
  249. devicerole = DeviceRole.objects.create(
  250. name='Test Device Role 1', slug='test-device-role-1', color='ff0000'
  251. )
  252. self.device1 = Device.objects.create(
  253. device_type=devicetype, device_role=devicerole, name='TestDevice1', site=site
  254. )
  255. self.device2 = Device.objects.create(
  256. device_type=devicetype, device_role=devicerole, name='TestDevice2', site=site
  257. )
  258. self.interface1 = Interface.objects.create(device=self.device1, name='eth0')
  259. self.interface2 = Interface.objects.create(device=self.device2, name='eth0')
  260. self.cable = Cable(termination_a=self.interface1, termination_b=self.interface2)
  261. self.cable.save()
  262. self.power_port1 = PowerPort.objects.create(device=self.device2, name='psu1')
  263. self.patch_pannel = Device.objects.create(
  264. device_type=devicetype, device_role=devicerole, name='TestPatchPannel', site=site
  265. )
  266. self.rear_port = RearPort.objects.create(device=self.patch_pannel, name='R1', type=1000)
  267. self.front_port = FrontPort.objects.create(
  268. device=self.patch_pannel, name='F1', type=1000, rear_port=self.rear_port
  269. )
  270. def test_cable_creation(self):
  271. """
  272. When a new Cable is created, it must be cached on either termination point.
  273. """
  274. interface1 = Interface.objects.get(pk=self.interface1.pk)
  275. self.assertEqual(self.cable.termination_a, interface1)
  276. interface2 = Interface.objects.get(pk=self.interface2.pk)
  277. self.assertEqual(self.cable.termination_b, interface2)
  278. def test_cable_deletion(self):
  279. """
  280. When a Cable is deleted, the `cable` field on its termination points must be nullified.
  281. """
  282. self.cable.delete()
  283. interface1 = Interface.objects.get(pk=self.interface1.pk)
  284. self.assertIsNone(interface1.cable)
  285. interface2 = Interface.objects.get(pk=self.interface2.pk)
  286. self.assertIsNone(interface2.cable)
  287. def test_cabletermination_deletion(self):
  288. """
  289. When a CableTermination object is deleted, its attached Cable (if any) must also be deleted.
  290. """
  291. self.interface1.delete()
  292. cable = Cable.objects.filter(pk=self.cable.pk).first()
  293. self.assertIsNone(cable)
  294. def test_cable_validates_compatibale_types(self):
  295. """
  296. The clean method should have a check to ensure only compatible port types can be connected by a cable
  297. """
  298. # An interface cannot be connected to a power port
  299. cable = Cable(termination_a=self.interface1, termination_b=self.power_port1)
  300. with self.assertRaises(ValidationError):
  301. cable.clean()
  302. def test_cable_cannot_have_the_same_terminination_on_both_ends(self):
  303. """
  304. A cable cannot be made with the same A and B side terminations
  305. """
  306. cable = Cable(termination_a=self.interface1, termination_b=self.interface1)
  307. with self.assertRaises(ValidationError):
  308. cable.clean()
  309. def test_cable_front_port_cannot_connect_to_corresponding_rear_port(self):
  310. """
  311. A cable cannot connect a front port to its corresponding rear port
  312. """
  313. cable = Cable(termination_a=self.front_port, termination_b=self.rear_port)
  314. with self.assertRaises(ValidationError):
  315. cable.clean()
  316. def test_cable_cannot_terminate_to_an_existing_connection(self):
  317. """
  318. Either side of a cable cannot be terminated when that side already has a connection
  319. """
  320. # Try to create a cable with the same interface terminations
  321. cable = Cable(termination_a=self.interface2, termination_b=self.interface1)
  322. with self.assertRaises(ValidationError):
  323. cable.clean()
  324. def test_cable_cannot_terminate_to_a_virtual_inteface(self):
  325. """
  326. A cable cannot terminate to a virtual interface
  327. """
  328. virtual_interface = Interface(device=self.device1, name="V1", type=InterfaceTypeChoices.TYPE_VIRTUAL)
  329. cable = Cable(termination_a=self.interface2, termination_b=virtual_interface)
  330. with self.assertRaises(ValidationError):
  331. cable.clean()
  332. def test_cable_cannot_terminate_to_a_wireless_inteface(self):
  333. """
  334. A cable cannot terminate to a wireless interface
  335. """
  336. wireless_interface = Interface(device=self.device1, name="W1", type=InterfaceTypeChoices.TYPE_80211A)
  337. cable = Cable(termination_a=self.interface2, termination_b=wireless_interface)
  338. with self.assertRaises(ValidationError):
  339. cable.clean()
  340. class CablePathTestCase(TestCase):
  341. def setUp(self):
  342. site = Site.objects.create(name='Test Site 1', slug='test-site-1')
  343. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  344. devicetype = DeviceType.objects.create(
  345. manufacturer=manufacturer, model='Test Device Type 1', slug='test-device-type-1'
  346. )
  347. devicerole = DeviceRole.objects.create(
  348. name='Test Device Role 1', slug='test-device-role-1', color='ff0000'
  349. )
  350. self.device1 = Device.objects.create(
  351. device_type=devicetype, device_role=devicerole, name='Test Device 1', site=site
  352. )
  353. self.device2 = Device.objects.create(
  354. device_type=devicetype, device_role=devicerole, name='Test Device 2', site=site
  355. )
  356. self.interface1 = Interface.objects.create(device=self.device1, name='eth0')
  357. self.interface2 = Interface.objects.create(device=self.device2, name='eth0')
  358. self.panel1 = Device.objects.create(
  359. device_type=devicetype, device_role=devicerole, name='Test Panel 1', site=site
  360. )
  361. self.panel2 = Device.objects.create(
  362. device_type=devicetype, device_role=devicerole, name='Test Panel 2', site=site
  363. )
  364. self.rear_port1 = RearPort.objects.create(
  365. device=self.panel1, name='Rear Port 1', type=PORT_TYPE_8P8C
  366. )
  367. self.front_port1 = FrontPort.objects.create(
  368. device=self.panel1, name='Front Port 1', type=PORT_TYPE_8P8C, rear_port=self.rear_port1
  369. )
  370. self.rear_port2 = RearPort.objects.create(
  371. device=self.panel2, name='Rear Port 2', type=PORT_TYPE_8P8C
  372. )
  373. self.front_port2 = FrontPort.objects.create(
  374. device=self.panel2, name='Front Port 2', type=PORT_TYPE_8P8C, rear_port=self.rear_port2
  375. )
  376. def test_path_completion(self):
  377. # First segment
  378. cable1 = Cable(termination_a=self.interface1, termination_b=self.front_port1)
  379. cable1.save()
  380. interface1 = Interface.objects.get(pk=self.interface1.pk)
  381. self.assertIsNone(interface1.connected_endpoint)
  382. self.assertIsNone(interface1.connection_status)
  383. # Second segment
  384. cable2 = Cable(termination_a=self.rear_port1, termination_b=self.rear_port2)
  385. cable2.save()
  386. interface1 = Interface.objects.get(pk=self.interface1.pk)
  387. self.assertIsNone(interface1.connected_endpoint)
  388. self.assertIsNone(interface1.connection_status)
  389. # Third segment
  390. cable3 = Cable(termination_a=self.front_port2, termination_b=self.interface2, status=CONNECTION_STATUS_PLANNED)
  391. cable3.save()
  392. interface1 = Interface.objects.get(pk=self.interface1.pk)
  393. self.assertEqual(interface1.connected_endpoint, self.interface2)
  394. self.assertEqual(interface1.connection_status, CONNECTION_STATUS_PLANNED)
  395. # Switch third segment from planned to connected
  396. cable3.status = CONNECTION_STATUS_CONNECTED
  397. cable3.save()
  398. interface1 = Interface.objects.get(pk=self.interface1.pk)
  399. self.assertEqual(interface1.connected_endpoint, self.interface2)
  400. self.assertEqual(interface1.connection_status, CONNECTION_STATUS_CONNECTED)
  401. def test_path_teardown(self):
  402. # Build the path
  403. cable1 = Cable(termination_a=self.interface1, termination_b=self.front_port1)
  404. cable1.save()
  405. cable2 = Cable(termination_a=self.rear_port1, termination_b=self.rear_port2)
  406. cable2.save()
  407. cable3 = Cable(termination_a=self.front_port2, termination_b=self.interface2)
  408. cable3.save()
  409. interface1 = Interface.objects.get(pk=self.interface1.pk)
  410. self.assertEqual(interface1.connected_endpoint, self.interface2)
  411. self.assertEqual(interface1.connection_status, CONNECTION_STATUS_CONNECTED)
  412. # Remove a cable
  413. cable2.delete()
  414. interface1 = Interface.objects.get(pk=self.interface1.pk)
  415. self.assertIsNone(interface1.connected_endpoint)
  416. self.assertIsNone(interface1.connection_status)
  417. interface2 = Interface.objects.get(pk=self.interface2.pk)
  418. self.assertIsNone(interface2.connected_endpoint)
  419. self.assertIsNone(interface2.connection_status)