test_models.py 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188
  1. from django.core.exceptions import ValidationError
  2. from django.test import TestCase
  3. from circuits.models import *
  4. from dcim.choices import *
  5. from dcim.models import *
  6. from tenancy.models import Tenant
  7. class RackTestCase(TestCase):
  8. def setUp(self):
  9. self.site1 = Site.objects.create(
  10. name='TestSite1',
  11. slug='test-site-1'
  12. )
  13. self.site2 = Site.objects.create(
  14. name='TestSite2',
  15. slug='test-site-2'
  16. )
  17. self.group1 = RackGroup.objects.create(
  18. name='TestGroup1',
  19. slug='test-group-1',
  20. site=self.site1
  21. )
  22. self.group2 = RackGroup.objects.create(
  23. name='TestGroup2',
  24. slug='test-group-2',
  25. site=self.site2
  26. )
  27. self.rack = Rack.objects.create(
  28. name='TestRack1',
  29. facility_id='A101',
  30. site=self.site1,
  31. group=self.group1,
  32. u_height=42
  33. )
  34. self.manufacturer = Manufacturer.objects.create(
  35. name='Acme',
  36. slug='acme'
  37. )
  38. self.device_type = {
  39. 'ff2048': DeviceType.objects.create(
  40. manufacturer=self.manufacturer,
  41. model='FrameForwarder 2048',
  42. slug='ff2048'
  43. ),
  44. 'cc5000': DeviceType.objects.create(
  45. manufacturer=self.manufacturer,
  46. model='CurrentCatapult 5000',
  47. slug='cc5000',
  48. u_height=0
  49. ),
  50. }
  51. self.role = {
  52. 'Server': DeviceRole.objects.create(
  53. name='Server',
  54. slug='server',
  55. ),
  56. 'Switch': DeviceRole.objects.create(
  57. name='Switch',
  58. slug='switch',
  59. ),
  60. 'Console Server': DeviceRole.objects.create(
  61. name='Console Server',
  62. slug='console-server',
  63. ),
  64. 'PDU': DeviceRole.objects.create(
  65. name='PDU',
  66. slug='pdu',
  67. ),
  68. }
  69. def test_rack_device_outside_height(self):
  70. rack1 = Rack(
  71. name='TestRack2',
  72. facility_id='A102',
  73. site=self.site1,
  74. u_height=42
  75. )
  76. rack1.save()
  77. device1 = Device(
  78. name='TestSwitch1',
  79. device_type=DeviceType.objects.get(manufacturer__slug='acme', slug='ff2048'),
  80. device_role=DeviceRole.objects.get(slug='switch'),
  81. site=self.site1,
  82. rack=rack1,
  83. position=43,
  84. face=DeviceFaceChoices.FACE_FRONT,
  85. )
  86. device1.save()
  87. with self.assertRaises(ValidationError):
  88. rack1.clean()
  89. def test_rack_group_site(self):
  90. rack_invalid_group = Rack(
  91. name='TestRack2',
  92. facility_id='A102',
  93. site=self.site1,
  94. u_height=42,
  95. group=self.group2
  96. )
  97. rack_invalid_group.save()
  98. with self.assertRaises(ValidationError):
  99. rack_invalid_group.clean()
  100. def test_mount_single_device(self):
  101. device1 = Device(
  102. name='TestSwitch1',
  103. device_type=DeviceType.objects.get(manufacturer__slug='acme', slug='ff2048'),
  104. device_role=DeviceRole.objects.get(slug='switch'),
  105. site=self.site1,
  106. rack=self.rack,
  107. position=10,
  108. face=DeviceFaceChoices.FACE_REAR,
  109. )
  110. device1.save()
  111. # Validate rack height
  112. self.assertEqual(list(self.rack.units), list(reversed(range(1, 43))))
  113. # Validate inventory (front face)
  114. rack1_inventory_front = self.rack.get_rack_units(face=DeviceFaceChoices.FACE_FRONT)
  115. self.assertEqual(rack1_inventory_front[-10]['device'], device1)
  116. del(rack1_inventory_front[-10])
  117. for u in rack1_inventory_front:
  118. self.assertIsNone(u['device'])
  119. # Validate inventory (rear face)
  120. rack1_inventory_rear = self.rack.get_rack_units(face=DeviceFaceChoices.FACE_REAR)
  121. self.assertEqual(rack1_inventory_rear[-10]['device'], device1)
  122. del(rack1_inventory_rear[-10])
  123. for u in rack1_inventory_rear:
  124. self.assertIsNone(u['device'])
  125. def test_mount_zero_ru(self):
  126. pdu = Device.objects.create(
  127. name='TestPDU',
  128. device_role=self.role.get('PDU'),
  129. device_type=self.device_type.get('cc5000'),
  130. site=self.site1,
  131. rack=self.rack,
  132. position=None,
  133. face='',
  134. )
  135. self.assertTrue(pdu)
  136. class DeviceTestCase(TestCase):
  137. def setUp(self):
  138. self.site = Site.objects.create(name='Test Site 1', slug='test-site-1')
  139. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  140. self.device_type = DeviceType.objects.create(
  141. manufacturer=manufacturer, model='Test Device Type 1', slug='test-device-type-1'
  142. )
  143. self.device_role = DeviceRole.objects.create(
  144. name='Test Device Role 1', slug='test-device-role-1', color='ff0000'
  145. )
  146. # Create DeviceType components
  147. ConsolePortTemplate(
  148. device_type=self.device_type,
  149. name='Console Port 1'
  150. ).save()
  151. ConsoleServerPortTemplate(
  152. device_type=self.device_type,
  153. name='Console Server Port 1'
  154. ).save()
  155. ppt = PowerPortTemplate(
  156. device_type=self.device_type,
  157. name='Power Port 1',
  158. maximum_draw=1000,
  159. allocated_draw=500
  160. )
  161. ppt.save()
  162. PowerOutletTemplate(
  163. device_type=self.device_type,
  164. name='Power Outlet 1',
  165. power_port=ppt,
  166. feed_leg=PowerOutletFeedLegChoices.FEED_LEG_A
  167. ).save()
  168. InterfaceTemplate(
  169. device_type=self.device_type,
  170. name='Interface 1',
  171. type=InterfaceTypeChoices.TYPE_1GE_FIXED,
  172. mgmt_only=True
  173. ).save()
  174. rpt = RearPortTemplate(
  175. device_type=self.device_type,
  176. name='Rear Port 1',
  177. type=PortTypeChoices.TYPE_8P8C,
  178. positions=8
  179. )
  180. rpt.save()
  181. FrontPortTemplate(
  182. device_type=self.device_type,
  183. name='Front Port 1',
  184. type=PortTypeChoices.TYPE_8P8C,
  185. rear_port=rpt,
  186. rear_port_position=2
  187. ).save()
  188. DeviceBayTemplate(
  189. device_type=self.device_type,
  190. name='Device Bay 1'
  191. ).save()
  192. def test_device_creation(self):
  193. """
  194. Ensure that all Device components are copied automatically from the DeviceType.
  195. """
  196. d = Device(
  197. site=self.site,
  198. device_type=self.device_type,
  199. device_role=self.device_role,
  200. name='Test Device 1'
  201. )
  202. d.save()
  203. ConsolePort.objects.get(
  204. device=d,
  205. name='Console Port 1'
  206. )
  207. ConsoleServerPort.objects.get(
  208. device=d,
  209. name='Console Server Port 1'
  210. )
  211. pp = PowerPort.objects.get(
  212. device=d,
  213. name='Power Port 1',
  214. maximum_draw=1000,
  215. allocated_draw=500
  216. )
  217. PowerOutlet.objects.get(
  218. device=d,
  219. name='Power Outlet 1',
  220. power_port=pp,
  221. feed_leg=PowerOutletFeedLegChoices.FEED_LEG_A
  222. )
  223. Interface.objects.get(
  224. device=d,
  225. name='Interface 1',
  226. type=InterfaceTypeChoices.TYPE_1GE_FIXED,
  227. mgmt_only=True
  228. )
  229. rp = RearPort.objects.get(
  230. device=d,
  231. name='Rear Port 1',
  232. type=PortTypeChoices.TYPE_8P8C,
  233. positions=8
  234. )
  235. FrontPort.objects.get(
  236. device=d,
  237. name='Front Port 1',
  238. type=PortTypeChoices.TYPE_8P8C,
  239. rear_port=rp,
  240. rear_port_position=2
  241. )
  242. DeviceBay.objects.get(
  243. device=d,
  244. name='Device Bay 1'
  245. )
  246. def test_multiple_unnamed_devices(self):
  247. device1 = Device(
  248. site=self.site,
  249. device_type=self.device_type,
  250. device_role=self.device_role,
  251. name=''
  252. )
  253. device1.save()
  254. device2 = Device(
  255. site=device1.site,
  256. device_type=device1.device_type,
  257. device_role=device1.device_role,
  258. name=''
  259. )
  260. device2.full_clean()
  261. device2.save()
  262. self.assertEqual(Device.objects.filter(name='').count(), 2)
  263. def test_device_duplicate_names(self):
  264. device1 = Device(
  265. site=self.site,
  266. device_type=self.device_type,
  267. device_role=self.device_role,
  268. name='Test Device 1'
  269. )
  270. device1.save()
  271. device2 = Device(
  272. site=device1.site,
  273. device_type=device1.device_type,
  274. device_role=device1.device_role,
  275. name=device1.name
  276. )
  277. # Two devices assigned to the same Site and no Tenant should fail validation
  278. with self.assertRaises(ValidationError):
  279. device2.full_clean()
  280. tenant = Tenant.objects.create(name='Test Tenant 1', slug='test-tenant-1')
  281. device1.tenant = tenant
  282. device1.save()
  283. device2.tenant = tenant
  284. # Two devices assigned to the same Site and the same Tenant should fail validation
  285. with self.assertRaises(ValidationError):
  286. device2.full_clean()
  287. device2.tenant = None
  288. # Two devices assigned to the same Site and different Tenants should pass validation
  289. device2.full_clean()
  290. device2.save()
  291. class CableTestCase(TestCase):
  292. def setUp(self):
  293. site = Site.objects.create(name='Test Site 1', slug='test-site-1')
  294. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  295. devicetype = DeviceType.objects.create(
  296. manufacturer=manufacturer, model='Test Device Type 1', slug='test-device-type-1'
  297. )
  298. devicerole = DeviceRole.objects.create(
  299. name='Test Device Role 1', slug='test-device-role-1', color='ff0000'
  300. )
  301. self.device1 = Device.objects.create(
  302. device_type=devicetype, device_role=devicerole, name='TestDevice1', site=site
  303. )
  304. self.device2 = Device.objects.create(
  305. device_type=devicetype, device_role=devicerole, name='TestDevice2', site=site
  306. )
  307. self.interface1 = Interface.objects.create(device=self.device1, name='eth0')
  308. self.interface2 = Interface.objects.create(device=self.device2, name='eth0')
  309. self.interface3 = Interface.objects.create(device=self.device2, name='eth1')
  310. self.cable = Cable(termination_a=self.interface1, termination_b=self.interface2)
  311. self.cable.save()
  312. self.power_port1 = PowerPort.objects.create(device=self.device2, name='psu1')
  313. self.patch_pannel = Device.objects.create(
  314. device_type=devicetype, device_role=devicerole, name='TestPatchPannel', site=site
  315. )
  316. self.rear_port1 = RearPort.objects.create(device=self.patch_pannel, name='RP1', type='8p8c')
  317. self.front_port1 = FrontPort.objects.create(
  318. device=self.patch_pannel, name='FP1', type='8p8c', rear_port=self.rear_port1, rear_port_position=1
  319. )
  320. self.rear_port2 = RearPort.objects.create(device=self.patch_pannel, name='RP2', type='8p8c', positions=2)
  321. self.front_port2 = FrontPort.objects.create(
  322. device=self.patch_pannel, name='FP2', type='8p8c', rear_port=self.rear_port2, rear_port_position=1
  323. )
  324. self.rear_port3 = RearPort.objects.create(device=self.patch_pannel, name='RP3', type='8p8c', positions=3)
  325. self.front_port3 = FrontPort.objects.create(
  326. device=self.patch_pannel, name='FP3', type='8p8c', rear_port=self.rear_port3, rear_port_position=1
  327. )
  328. self.rear_port4 = RearPort.objects.create(device=self.patch_pannel, name='RP4', type='8p8c', positions=3)
  329. self.front_port4 = FrontPort.objects.create(
  330. device=self.patch_pannel, name='FP4', type='8p8c', rear_port=self.rear_port4, rear_port_position=1
  331. )
  332. self.provider = Provider.objects.create(name='Provider 1', slug='provider-1')
  333. self.circuittype = CircuitType.objects.create(name='Circuit Type 1', slug='circuit-type-1')
  334. self.circuit = Circuit.objects.create(provider=self.provider, type=self.circuittype, cid='1')
  335. self.circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, site=site, term_side='A', port_speed=1000)
  336. self.circuittermination2 = CircuitTermination.objects.create(circuit=self.circuit, site=site, term_side='Z', port_speed=1000)
  337. def test_cable_creation(self):
  338. """
  339. When a new Cable is created, it must be cached on either termination point.
  340. """
  341. interface1 = Interface.objects.get(pk=self.interface1.pk)
  342. self.assertEqual(self.cable.termination_a, interface1)
  343. interface2 = Interface.objects.get(pk=self.interface2.pk)
  344. self.assertEqual(self.cable.termination_b, interface2)
  345. def test_cable_deletion(self):
  346. """
  347. When a Cable is deleted, the `cable` field on its termination points must be nullified. The str() method
  348. should still return the PK of the string even after being nullified.
  349. """
  350. self.cable.delete()
  351. self.assertIsNone(self.cable.pk)
  352. self.assertNotEqual(str(self.cable), '#None')
  353. interface1 = Interface.objects.get(pk=self.interface1.pk)
  354. self.assertIsNone(interface1.cable)
  355. interface2 = Interface.objects.get(pk=self.interface2.pk)
  356. self.assertIsNone(interface2.cable)
  357. def test_cabletermination_deletion(self):
  358. """
  359. When a CableTermination object is deleted, its attached Cable (if any) must also be deleted.
  360. """
  361. self.interface1.delete()
  362. cable = Cable.objects.filter(pk=self.cable.pk).first()
  363. self.assertIsNone(cable)
  364. def test_cable_validates_compatible_types(self):
  365. """
  366. The clean method should have a check to ensure only compatible port types can be connected by a cable
  367. """
  368. # An interface cannot be connected to a power port
  369. cable = Cable(termination_a=self.interface1, termination_b=self.power_port1)
  370. with self.assertRaises(ValidationError):
  371. cable.clean()
  372. def test_cable_cannot_have_the_same_terminination_on_both_ends(self):
  373. """
  374. A cable cannot be made with the same A and B side terminations
  375. """
  376. cable = Cable(termination_a=self.interface1, termination_b=self.interface1)
  377. with self.assertRaises(ValidationError):
  378. cable.clean()
  379. def test_cable_front_port_cannot_connect_to_corresponding_rear_port(self):
  380. """
  381. A cable cannot connect a front port to its corresponding rear port
  382. """
  383. cable = Cable(termination_a=self.front_port1, termination_b=self.rear_port1)
  384. with self.assertRaises(ValidationError):
  385. cable.clean()
  386. def test_cable_cannot_terminate_to_an_existing_connection(self):
  387. """
  388. Either side of a cable cannot be terminated when that side already has a connection
  389. """
  390. # Try to create a cable with the same interface terminations
  391. cable = Cable(termination_a=self.interface2, termination_b=self.interface1)
  392. with self.assertRaises(ValidationError):
  393. cable.clean()
  394. def test_connection_via_single_position_rearport(self):
  395. """
  396. A RearPort with one position can be connected to anything.
  397. [CableTermination X]---[RP(pos=1) FP]---[CableTermination Y]
  398. is allowed anywhere
  399. [CableTermination X]---[CableTermination Y]
  400. is allowed.
  401. A RearPort with multiple positions may not be directly connected to a path endpoint or another RearPort
  402. with a different number of positions. RearPorts with a single position on the other hand may be connected
  403. to such CableTerminations. Check that this is indeed allowed.
  404. """
  405. # Connecting a single-position RearPort to a multi-position RearPort is ok
  406. Cable(termination_a=self.rear_port1, termination_b=self.rear_port2).full_clean()
  407. # Connecting a single-position RearPort to an Interface is ok
  408. Cable(termination_a=self.rear_port1, termination_b=self.interface3).full_clean()
  409. # Connecting a single-position RearPort to a CircuitTermination is ok
  410. Cable(termination_a=self.rear_port1, termination_b=self.circuittermination1).full_clean()
  411. def test_connection_via_multi_position_rearport(self):
  412. """
  413. A RearPort with multiple positions may not be directly connected to a path endpoint or another RearPort
  414. with a different number of positions.
  415. The following scenario's are allowed (with x>1):
  416. ~----------+ +---------~
  417. | |
  418. RP2(pos=x)|---|RP(pos=x)
  419. | |
  420. ~----------+ +---------~
  421. ~----------+ +---------~
  422. | |
  423. RP2(pos=x)|---|RP(pos=1)
  424. | |
  425. ~----------+ +---------~
  426. ~----------+ +------------------~
  427. | |
  428. RP2(pos=x)|---|CircuitTermination
  429. | |
  430. ~----------+ +------------------~
  431. These scenarios are NOT allowed (with x>1):
  432. ~----------+ +----------~
  433. | |
  434. RP2(pos=x)|---|RP(pos!=x)
  435. | |
  436. ~----------+ +----------~
  437. ~----------+ +----------~
  438. | |
  439. RP2(pos=x)|---|Interface
  440. | |
  441. ~----------+ +----------~
  442. These scenarios are tested in this order below.
  443. """
  444. # Connecting a multi-position RearPort to another RearPort with the same number of positions is ok
  445. Cable(termination_a=self.rear_port3, termination_b=self.rear_port4).full_clean()
  446. # Connecting a multi-position RearPort to a single-position RearPort is ok
  447. Cable(termination_a=self.rear_port2, termination_b=self.rear_port1).full_clean()
  448. # Connecting a multi-position RearPort to a CircuitTermination is ok
  449. Cable(termination_a=self.rear_port2, termination_b=self.circuittermination1).full_clean()
  450. with self.assertRaises(
  451. ValidationError,
  452. msg='Connecting a 2-position RearPort to a 3-position RearPort should fail'
  453. ):
  454. Cable(termination_a=self.rear_port2, termination_b=self.rear_port3).full_clean()
  455. with self.assertRaises(
  456. ValidationError,
  457. msg='Connecting a multi-position RearPort to an Interface should fail'
  458. ):
  459. Cable(termination_a=self.rear_port2, termination_b=self.interface3).full_clean()
  460. def test_cable_cannot_terminate_to_a_virtual_interface(self):
  461. """
  462. A cable cannot terminate to a virtual interface
  463. """
  464. virtual_interface = Interface(device=self.device1, name="V1", type=InterfaceTypeChoices.TYPE_VIRTUAL)
  465. cable = Cable(termination_a=self.interface2, termination_b=virtual_interface)
  466. with self.assertRaises(ValidationError):
  467. cable.clean()
  468. def test_cable_cannot_terminate_to_a_wireless_interface(self):
  469. """
  470. A cable cannot terminate to a wireless interface
  471. """
  472. wireless_interface = Interface(device=self.device1, name="W1", type=InterfaceTypeChoices.TYPE_80211A)
  473. cable = Cable(termination_a=self.interface2, termination_b=wireless_interface)
  474. with self.assertRaises(ValidationError):
  475. cable.clean()
  476. class CablePathTestCase(TestCase):
  477. @classmethod
  478. def setUpTestData(cls):
  479. site = Site.objects.create(name='Site 1', slug='site-1')
  480. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  481. devicetype = DeviceType.objects.create(
  482. manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'
  483. )
  484. devicerole = DeviceRole.objects.create(
  485. name='Device Role 1', slug='device-role-1', color='ff0000'
  486. )
  487. provider = Provider.objects.create(name='Provider 1', slug='provider-1')
  488. circuittype = CircuitType.objects.create(name='Circuit Type 1', slug='circuit-type-1')
  489. circuit = Circuit.objects.create(provider=provider, type=circuittype, cid='1')
  490. CircuitTermination.objects.bulk_create((
  491. CircuitTermination(circuit=circuit, site=site, term_side='A', port_speed=1000),
  492. CircuitTermination(circuit=circuit, site=site, term_side='Z', port_speed=1000),
  493. ))
  494. # Create four network devices with four interfaces each
  495. devices = (
  496. Device(device_type=devicetype, device_role=devicerole, name='Device 1', site=site),
  497. Device(device_type=devicetype, device_role=devicerole, name='Device 2', site=site),
  498. Device(device_type=devicetype, device_role=devicerole, name='Device 3', site=site),
  499. Device(device_type=devicetype, device_role=devicerole, name='Device 4', site=site),
  500. )
  501. Device.objects.bulk_create(devices)
  502. for device in devices:
  503. Interface.objects.bulk_create((
  504. Interface(device=device, name='Interface 1', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  505. Interface(device=device, name='Interface 2', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  506. Interface(device=device, name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  507. Interface(device=device, name='Interface 4', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  508. ))
  509. # Create four patch panels, each with one rear port and four front ports
  510. patch_panels = (
  511. Device(device_type=devicetype, device_role=devicerole, name='Panel 1', site=site),
  512. Device(device_type=devicetype, device_role=devicerole, name='Panel 2', site=site),
  513. Device(device_type=devicetype, device_role=devicerole, name='Panel 3', site=site),
  514. Device(device_type=devicetype, device_role=devicerole, name='Panel 4', site=site),
  515. Device(device_type=devicetype, device_role=devicerole, name='Panel 5', site=site),
  516. Device(device_type=devicetype, device_role=devicerole, name='Panel 6', site=site),
  517. )
  518. Device.objects.bulk_create(patch_panels)
  519. # Create patch panels with 4 positions
  520. for patch_panel in patch_panels[:4]:
  521. rearport = RearPort.objects.create(device=patch_panel, name='Rear Port 1', positions=4, type=PortTypeChoices.TYPE_8P8C)
  522. FrontPort.objects.bulk_create((
  523. FrontPort(device=patch_panel, name='Front Port 1', rear_port=rearport, rear_port_position=1, type=PortTypeChoices.TYPE_8P8C),
  524. FrontPort(device=patch_panel, name='Front Port 2', rear_port=rearport, rear_port_position=2, type=PortTypeChoices.TYPE_8P8C),
  525. FrontPort(device=patch_panel, name='Front Port 3', rear_port=rearport, rear_port_position=3, type=PortTypeChoices.TYPE_8P8C),
  526. FrontPort(device=patch_panel, name='Front Port 4', rear_port=rearport, rear_port_position=4, type=PortTypeChoices.TYPE_8P8C),
  527. ))
  528. # Create 1-on-1 patch panels
  529. for patch_panel in patch_panels[4:]:
  530. rearport = RearPort.objects.create(device=patch_panel, name='Rear Port 1', positions=1, type=PortTypeChoices.TYPE_8P8C)
  531. FrontPort.objects.create(device=patch_panel, name='Front Port 1', rear_port=rearport, rear_port_position=1, type=PortTypeChoices.TYPE_8P8C)
  532. def test_direct_connection(self):
  533. """
  534. Test a direct connection between two interfaces.
  535. [Device 1] ----- [Device 2]
  536. Iface1 Iface1
  537. """
  538. # Create cable
  539. cable = Cable(
  540. termination_a=Interface.objects.get(device__name='Device 1', name='Interface 1'),
  541. termination_b=Interface.objects.get(device__name='Device 2', name='Interface 1')
  542. )
  543. cable.full_clean()
  544. cable.save()
  545. # Retrieve endpoints
  546. endpoint_a = Interface.objects.get(device__name='Device 1', name='Interface 1')
  547. endpoint_b = Interface.objects.get(device__name='Device 2', name='Interface 1')
  548. # Validate connections
  549. self.assertEqual(endpoint_a.connected_endpoint, endpoint_b)
  550. self.assertEqual(endpoint_b.connected_endpoint, endpoint_a)
  551. self.assertTrue(endpoint_a.connection_status)
  552. self.assertTrue(endpoint_b.connection_status)
  553. # Delete cable
  554. cable.delete()
  555. # Refresh endpoints
  556. endpoint_a.refresh_from_db()
  557. endpoint_b.refresh_from_db()
  558. # Check that connections have been nullified
  559. self.assertIsNone(endpoint_a.connected_endpoint)
  560. self.assertIsNone(endpoint_b.connected_endpoint)
  561. self.assertIsNone(endpoint_a.connection_status)
  562. self.assertIsNone(endpoint_b.connection_status)
  563. def test_connection_via_single_rear_port(self):
  564. """
  565. Test a connection which passes through a rear port with exactly one front port.
  566. 1 2
  567. [Device 1] ----- [Panel 5] ----- [Device 2]
  568. Iface1 FP1 RP1 Iface1
  569. """
  570. # Create cables (FP first, RP second)
  571. cable1 = Cable(
  572. termination_a=Interface.objects.get(device__name='Device 1', name='Interface 1'),
  573. termination_b=FrontPort.objects.get(device__name='Panel 5', name='Front Port 1')
  574. )
  575. cable1.full_clean()
  576. cable1.save()
  577. cable2 = Cable(
  578. termination_a=RearPort.objects.get(device__name='Panel 5', name='Rear Port 1'),
  579. termination_b=Interface.objects.get(device__name='Device 2', name='Interface 1')
  580. )
  581. self.assertEqual(cable2.termination_a.positions, 1) # Sanity check
  582. cable2.full_clean()
  583. cable2.save()
  584. # Retrieve endpoints
  585. endpoint_a = Interface.objects.get(device__name='Device 1', name='Interface 1')
  586. endpoint_b = Interface.objects.get(device__name='Device 2', name='Interface 1')
  587. # Validate connections
  588. self.assertEqual(endpoint_a.connected_endpoint, endpoint_b)
  589. self.assertEqual(endpoint_b.connected_endpoint, endpoint_a)
  590. self.assertTrue(endpoint_a.connection_status)
  591. self.assertTrue(endpoint_b.connection_status)
  592. # Delete cable 1
  593. cable1.delete()
  594. # Refresh endpoints
  595. endpoint_a.refresh_from_db()
  596. endpoint_b.refresh_from_db()
  597. # Check that connections have been nullified
  598. self.assertIsNone(endpoint_a.connected_endpoint)
  599. self.assertIsNone(endpoint_b.connected_endpoint)
  600. self.assertIsNone(endpoint_a.connection_status)
  601. self.assertIsNone(endpoint_b.connection_status)
  602. def test_connections_via_nested_single_position_rearport(self):
  603. """
  604. Test a connection which passes through a single front/rear port pair between two multi-position rear ports.
  605. Test two connections via patched rear ports:
  606. Device 1 <---> Device 2
  607. Device 3 <---> Device 4
  608. 1 2
  609. [Device 1] -----------+ +----------- [Device 2]
  610. Iface1 | | Iface1
  611. FP1 | 3 4 | FP1
  612. [Panel 1] ----- [Panel 5] ----- [Panel 2]
  613. FP2 | RP1 RP1 FP1 RP1 | FP2
  614. Iface1 | | Iface1
  615. [Device 3] -----------+ +----------- [Device 4]
  616. 5 6
  617. """
  618. # Create cables (Panel 5 RP first, FP second)
  619. cable1 = Cable(
  620. termination_a=Interface.objects.get(device__name='Device 1', name='Interface 1'),
  621. termination_b=FrontPort.objects.get(device__name='Panel 1', name='Front Port 1')
  622. )
  623. cable1.full_clean()
  624. cable1.save()
  625. cable2 = Cable(
  626. termination_b=FrontPort.objects.get(device__name='Panel 2', name='Front Port 1'),
  627. termination_a=Interface.objects.get(device__name='Device 2', name='Interface 1')
  628. )
  629. cable2.full_clean()
  630. cable2.save()
  631. cable3 = Cable(
  632. termination_b=RearPort.objects.get(device__name='Panel 1', name='Rear Port 1'),
  633. termination_a=RearPort.objects.get(device__name='Panel 5', name='Rear Port 1')
  634. )
  635. cable3.full_clean()
  636. cable3.save()
  637. cable4 = Cable(
  638. termination_b=FrontPort.objects.get(device__name='Panel 5', name='Front Port 1'),
  639. termination_a=RearPort.objects.get(device__name='Panel 2', name='Rear Port 1')
  640. )
  641. cable4.full_clean()
  642. cable4.save()
  643. cable5 = Cable(
  644. termination_b=FrontPort.objects.get(device__name='Panel 1', name='Front Port 2'),
  645. termination_a=Interface.objects.get(device__name='Device 3', name='Interface 1')
  646. )
  647. cable5.full_clean()
  648. cable5.save()
  649. cable6 = Cable(
  650. termination_b=FrontPort.objects.get(device__name='Panel 2', name='Front Port 2'),
  651. termination_a=Interface.objects.get(device__name='Device 4', name='Interface 1')
  652. )
  653. cable6.full_clean()
  654. cable6.save()
  655. # Retrieve endpoints
  656. endpoint_a = Interface.objects.get(device__name='Device 1', name='Interface 1')
  657. endpoint_b = Interface.objects.get(device__name='Device 2', name='Interface 1')
  658. endpoint_c = Interface.objects.get(device__name='Device 3', name='Interface 1')
  659. endpoint_d = Interface.objects.get(device__name='Device 4', name='Interface 1')
  660. # Validate connections
  661. self.assertEqual(endpoint_a.connected_endpoint, endpoint_b)
  662. self.assertEqual(endpoint_b.connected_endpoint, endpoint_a)
  663. self.assertEqual(endpoint_c.connected_endpoint, endpoint_d)
  664. self.assertEqual(endpoint_d.connected_endpoint, endpoint_c)
  665. self.assertTrue(endpoint_a.connection_status)
  666. self.assertTrue(endpoint_b.connection_status)
  667. self.assertTrue(endpoint_c.connection_status)
  668. self.assertTrue(endpoint_d.connection_status)
  669. # Delete cable 3
  670. cable3.delete()
  671. # Refresh endpoints
  672. endpoint_a.refresh_from_db()
  673. endpoint_b.refresh_from_db()
  674. endpoint_c.refresh_from_db()
  675. endpoint_d.refresh_from_db()
  676. # Check that connections have been nullified
  677. self.assertIsNone(endpoint_a.connected_endpoint)
  678. self.assertIsNone(endpoint_b.connected_endpoint)
  679. self.assertIsNone(endpoint_c.connected_endpoint)
  680. self.assertIsNone(endpoint_d.connected_endpoint)
  681. self.assertIsNone(endpoint_a.connection_status)
  682. self.assertIsNone(endpoint_b.connection_status)
  683. self.assertIsNone(endpoint_c.connection_status)
  684. self.assertIsNone(endpoint_d.connection_status)
  685. def test_connections_via_patch(self):
  686. """
  687. Test two connections via patched rear ports:
  688. Device 1 <---> Device 2
  689. Device 3 <---> Device 4
  690. 1 2
  691. [Device 1] -----------+ +----------- [Device 2]
  692. Iface1 | | Iface1
  693. FP1 | 3 | FP1
  694. [Panel 1] ----- [Panel 2]
  695. FP2 | RP1 RP1 | FP2
  696. Iface1 | | Iface1
  697. [Device 3] -----------+ +----------- [Device 4]
  698. 4 5
  699. """
  700. # Create cables
  701. cable1 = Cable(
  702. termination_a=Interface.objects.get(device__name='Device 1', name='Interface 1'),
  703. termination_b=FrontPort.objects.get(device__name='Panel 1', name='Front Port 1')
  704. )
  705. cable1.full_clean()
  706. cable1.save()
  707. cable2 = Cable(
  708. termination_a=Interface.objects.get(device__name='Device 2', name='Interface 1'),
  709. termination_b=FrontPort.objects.get(device__name='Panel 2', name='Front Port 1')
  710. )
  711. cable2.full_clean()
  712. cable2.save()
  713. cable3 = Cable(
  714. termination_a=RearPort.objects.get(device__name='Panel 1', name='Rear Port 1'),
  715. termination_b=RearPort.objects.get(device__name='Panel 2', name='Rear Port 1')
  716. )
  717. cable3.full_clean()
  718. cable3.save()
  719. cable4 = Cable(
  720. termination_a=Interface.objects.get(device__name='Device 3', name='Interface 1'),
  721. termination_b=FrontPort.objects.get(device__name='Panel 1', name='Front Port 2')
  722. )
  723. cable4.full_clean()
  724. cable4.save()
  725. cable5 = Cable(
  726. termination_a=Interface.objects.get(device__name='Device 4', name='Interface 1'),
  727. termination_b=FrontPort.objects.get(device__name='Panel 2', name='Front Port 2')
  728. )
  729. cable5.full_clean()
  730. cable5.save()
  731. # Retrieve endpoints
  732. endpoint_a = Interface.objects.get(device__name='Device 1', name='Interface 1')
  733. endpoint_b = Interface.objects.get(device__name='Device 2', name='Interface 1')
  734. endpoint_c = Interface.objects.get(device__name='Device 3', name='Interface 1')
  735. endpoint_d = Interface.objects.get(device__name='Device 4', name='Interface 1')
  736. # Validate connections
  737. self.assertEqual(endpoint_a.connected_endpoint, endpoint_b)
  738. self.assertEqual(endpoint_b.connected_endpoint, endpoint_a)
  739. self.assertEqual(endpoint_c.connected_endpoint, endpoint_d)
  740. self.assertEqual(endpoint_d.connected_endpoint, endpoint_c)
  741. self.assertTrue(endpoint_a.connection_status)
  742. self.assertTrue(endpoint_b.connection_status)
  743. self.assertTrue(endpoint_c.connection_status)
  744. self.assertTrue(endpoint_d.connection_status)
  745. # Delete cable 3
  746. cable3.delete()
  747. # Refresh endpoints
  748. endpoint_a.refresh_from_db()
  749. endpoint_b.refresh_from_db()
  750. endpoint_c.refresh_from_db()
  751. endpoint_d.refresh_from_db()
  752. # Check that connections have been nullified
  753. self.assertIsNone(endpoint_a.connected_endpoint)
  754. self.assertIsNone(endpoint_b.connected_endpoint)
  755. self.assertIsNone(endpoint_c.connected_endpoint)
  756. self.assertIsNone(endpoint_d.connected_endpoint)
  757. self.assertIsNone(endpoint_a.connection_status)
  758. self.assertIsNone(endpoint_b.connection_status)
  759. self.assertIsNone(endpoint_c.connection_status)
  760. self.assertIsNone(endpoint_d.connection_status)
  761. def test_connections_via_multiple_patches(self):
  762. """
  763. Test two connections via patched rear ports:
  764. Device 1 <---> Device 2
  765. Device 3 <---> Device 4
  766. 1 2 3
  767. [Device 1] -----------+ +---------------+ +----------- [Device 2]
  768. Iface1 | | | | Iface1
  769. FP1 | 4 | FP1 FP1 | 5 | FP1
  770. [Panel 1] ----- [Panel 2] [Panel 3] ----- [Panel 4]
  771. FP2 | RP1 RP1 | FP2 FP2 | RP1 RP1 | FP2
  772. Iface1 | | | | Iface1
  773. [Device 3] -----------+ +---------------+ +----------- [Device 4]
  774. 6 7 8
  775. """
  776. # Create cables
  777. cable1 = Cable(
  778. termination_a=Interface.objects.get(device__name='Device 1', name='Interface 1'),
  779. termination_b=FrontPort.objects.get(device__name='Panel 1', name='Front Port 1')
  780. )
  781. cable1.full_clean()
  782. cable1.save()
  783. cable2 = Cable(
  784. termination_a=FrontPort.objects.get(device__name='Panel 2', name='Front Port 1'),
  785. termination_b=FrontPort.objects.get(device__name='Panel 3', name='Front Port 1')
  786. )
  787. cable2.full_clean()
  788. cable2.save()
  789. cable3 = Cable(
  790. termination_a=FrontPort.objects.get(device__name='Panel 4', name='Front Port 1'),
  791. termination_b=Interface.objects.get(device__name='Device 2', name='Interface 1')
  792. )
  793. cable3.full_clean()
  794. cable3.save()
  795. cable4 = Cable(
  796. termination_a=RearPort.objects.get(device__name='Panel 1', name='Rear Port 1'),
  797. termination_b=RearPort.objects.get(device__name='Panel 2', name='Rear Port 1')
  798. )
  799. cable4.full_clean()
  800. cable4.save()
  801. cable5 = Cable(
  802. termination_a=RearPort.objects.get(device__name='Panel 3', name='Rear Port 1'),
  803. termination_b=RearPort.objects.get(device__name='Panel 4', name='Rear Port 1')
  804. )
  805. cable5.full_clean()
  806. cable5.save()
  807. cable6 = Cable(
  808. termination_a=Interface.objects.get(device__name='Device 3', name='Interface 1'),
  809. termination_b=FrontPort.objects.get(device__name='Panel 1', name='Front Port 2')
  810. )
  811. cable6.full_clean()
  812. cable6.save()
  813. cable7 = Cable(
  814. termination_a=FrontPort.objects.get(device__name='Panel 2', name='Front Port 2'),
  815. termination_b=FrontPort.objects.get(device__name='Panel 3', name='Front Port 2')
  816. )
  817. cable7.full_clean()
  818. cable7.save()
  819. cable8 = Cable(
  820. termination_a=FrontPort.objects.get(device__name='Panel 4', name='Front Port 2'),
  821. termination_b=Interface.objects.get(device__name='Device 4', name='Interface 1')
  822. )
  823. cable8.full_clean()
  824. cable8.save()
  825. # Retrieve endpoints
  826. endpoint_a = Interface.objects.get(device__name='Device 1', name='Interface 1')
  827. endpoint_b = Interface.objects.get(device__name='Device 2', name='Interface 1')
  828. endpoint_c = Interface.objects.get(device__name='Device 3', name='Interface 1')
  829. endpoint_d = Interface.objects.get(device__name='Device 4', name='Interface 1')
  830. # Validate connections
  831. self.assertEqual(endpoint_a.connected_endpoint, endpoint_b)
  832. self.assertEqual(endpoint_b.connected_endpoint, endpoint_a)
  833. self.assertEqual(endpoint_c.connected_endpoint, endpoint_d)
  834. self.assertEqual(endpoint_d.connected_endpoint, endpoint_c)
  835. self.assertTrue(endpoint_a.connection_status)
  836. self.assertTrue(endpoint_b.connection_status)
  837. self.assertTrue(endpoint_c.connection_status)
  838. self.assertTrue(endpoint_d.connection_status)
  839. # Delete cables 4 and 5
  840. cable4.delete()
  841. cable5.delete()
  842. # Refresh endpoints
  843. endpoint_a.refresh_from_db()
  844. endpoint_b.refresh_from_db()
  845. endpoint_c.refresh_from_db()
  846. endpoint_d.refresh_from_db()
  847. # Check that connections have been nullified
  848. self.assertIsNone(endpoint_a.connected_endpoint)
  849. self.assertIsNone(endpoint_b.connected_endpoint)
  850. self.assertIsNone(endpoint_c.connected_endpoint)
  851. self.assertIsNone(endpoint_d.connected_endpoint)
  852. self.assertIsNone(endpoint_a.connection_status)
  853. self.assertIsNone(endpoint_b.connection_status)
  854. self.assertIsNone(endpoint_c.connection_status)
  855. self.assertIsNone(endpoint_d.connection_status)
  856. def test_connections_via_nested_rear_ports(self):
  857. """
  858. Test two connections via nested rear ports:
  859. Device 1 <---> Device 2
  860. Device 3 <---> Device 4
  861. 1 2
  862. [Device 1] -----------+ +----------- [Device 2]
  863. Iface1 | | Iface1
  864. FP1 | 3 4 5 | FP1
  865. [Panel 1] ----- [Panel 2] ----- [Panel 3] ----- [Panel 4]
  866. FP2 | RP1 FP1 RP1 RP1 FP1 RP1 | FP2
  867. Iface1 | | Iface1
  868. [Device 3] -----------+ +----------- [Device 4]
  869. 6 7
  870. """
  871. # Create cables
  872. cable1 = Cable(
  873. termination_a=Interface.objects.get(device__name='Device 1', name='Interface 1'),
  874. termination_b=FrontPort.objects.get(device__name='Panel 1', name='Front Port 1')
  875. )
  876. cable1.full_clean()
  877. cable1.save()
  878. cable2 = Cable(
  879. termination_a=FrontPort.objects.get(device__name='Panel 4', name='Front Port 1'),
  880. termination_b=Interface.objects.get(device__name='Device 2', name='Interface 1')
  881. )
  882. cable2.full_clean()
  883. cable2.save()
  884. cable3 = Cable(
  885. termination_a=RearPort.objects.get(device__name='Panel 1', name='Rear Port 1'),
  886. termination_b=FrontPort.objects.get(device__name='Panel 2', name='Front Port 1')
  887. )
  888. cable3.full_clean()
  889. cable3.save()
  890. cable4 = Cable(
  891. termination_a=RearPort.objects.get(device__name='Panel 2', name='Rear Port 1'),
  892. termination_b=RearPort.objects.get(device__name='Panel 3', name='Rear Port 1')
  893. )
  894. cable4.full_clean()
  895. cable4.save()
  896. cable5 = Cable(
  897. termination_a=FrontPort.objects.get(device__name='Panel 3', name='Front Port 1'),
  898. termination_b=RearPort.objects.get(device__name='Panel 4', name='Rear Port 1')
  899. )
  900. cable5.full_clean()
  901. cable5.save()
  902. cable6 = Cable(
  903. termination_a=Interface.objects.get(device__name='Device 3', name='Interface 1'),
  904. termination_b=FrontPort.objects.get(device__name='Panel 1', name='Front Port 2')
  905. )
  906. cable6.full_clean()
  907. cable6.save()
  908. cable7 = Cable(
  909. termination_a=FrontPort.objects.get(device__name='Panel 4', name='Front Port 2'),
  910. termination_b=Interface.objects.get(device__name='Device 4', name='Interface 1')
  911. )
  912. cable7.full_clean()
  913. cable7.save()
  914. # Retrieve endpoints
  915. endpoint_a = Interface.objects.get(device__name='Device 1', name='Interface 1')
  916. endpoint_b = Interface.objects.get(device__name='Device 2', name='Interface 1')
  917. endpoint_c = Interface.objects.get(device__name='Device 3', name='Interface 1')
  918. endpoint_d = Interface.objects.get(device__name='Device 4', name='Interface 1')
  919. # Validate connections
  920. self.assertEqual(endpoint_a.connected_endpoint, endpoint_b)
  921. self.assertEqual(endpoint_b.connected_endpoint, endpoint_a)
  922. self.assertEqual(endpoint_c.connected_endpoint, endpoint_d)
  923. self.assertEqual(endpoint_d.connected_endpoint, endpoint_c)
  924. self.assertTrue(endpoint_a.connection_status)
  925. self.assertTrue(endpoint_b.connection_status)
  926. self.assertTrue(endpoint_c.connection_status)
  927. self.assertTrue(endpoint_d.connection_status)
  928. # Delete cable 4
  929. cable4.delete()
  930. # Refresh endpoints
  931. endpoint_a.refresh_from_db()
  932. endpoint_b.refresh_from_db()
  933. endpoint_c.refresh_from_db()
  934. endpoint_d.refresh_from_db()
  935. # Check that connections have been nullified
  936. self.assertIsNone(endpoint_a.connected_endpoint)
  937. self.assertIsNone(endpoint_b.connected_endpoint)
  938. self.assertIsNone(endpoint_c.connected_endpoint)
  939. self.assertIsNone(endpoint_d.connected_endpoint)
  940. self.assertIsNone(endpoint_a.connection_status)
  941. self.assertIsNone(endpoint_b.connection_status)
  942. self.assertIsNone(endpoint_c.connection_status)
  943. self.assertIsNone(endpoint_d.connection_status)
  944. def test_connection_via_circuit(self):
  945. """
  946. 1 2
  947. [Device 1] ----- [Circuit] ----- [Device 2]
  948. Iface1 A Z Iface1
  949. """
  950. # Create cables
  951. cable1 = Cable(
  952. termination_a=Interface.objects.get(device__name='Device 1', name='Interface 1'),
  953. termination_b=CircuitTermination.objects.get(term_side='A')
  954. )
  955. cable1.full_clean()
  956. cable1.save()
  957. cable2 = Cable(
  958. termination_a=CircuitTermination.objects.get(term_side='Z'),
  959. termination_b=Interface.objects.get(device__name='Device 2', name='Interface 1')
  960. )
  961. cable2.full_clean()
  962. cable2.save()
  963. # Retrieve endpoints
  964. endpoint_a = Interface.objects.get(device__name='Device 1', name='Interface 1')
  965. endpoint_b = Interface.objects.get(device__name='Device 2', name='Interface 1')
  966. # Validate connections
  967. self.assertEqual(endpoint_a.connected_endpoint, endpoint_b)
  968. self.assertEqual(endpoint_b.connected_endpoint, endpoint_a)
  969. self.assertTrue(endpoint_a.connection_status)
  970. self.assertTrue(endpoint_b.connection_status)
  971. # Delete circuit
  972. circuit = Circuit.objects.first().delete()
  973. # Refresh endpoints
  974. endpoint_a.refresh_from_db()
  975. endpoint_b.refresh_from_db()
  976. # Check that connections have been nullified
  977. self.assertIsNone(endpoint_a.connected_endpoint)
  978. self.assertIsNone(endpoint_b.connected_endpoint)
  979. self.assertIsNone(endpoint_a.connection_status)
  980. self.assertIsNone(endpoint_b.connection_status)
  981. def test_connection_via_patched_circuit(self):
  982. """
  983. 1 2 3 4
  984. [Device 1] ----- [Panel 5] ----- [Circuit] ----- [Panel 6] ----- [Device 2]
  985. Iface1 FP1 RP1 A Z RP1 FP1 Iface1
  986. """
  987. # Create cables
  988. cable1 = Cable(
  989. termination_a=Interface.objects.get(device__name='Device 1', name='Interface 1'),
  990. termination_b=FrontPort.objects.get(device__name='Panel 5', name='Front Port 1')
  991. )
  992. cable1.full_clean()
  993. cable1.save()
  994. cable2 = Cable(
  995. termination_a=RearPort.objects.get(device__name='Panel 5', name='Rear Port 1'),
  996. termination_b=CircuitTermination.objects.get(term_side='A')
  997. )
  998. cable2.full_clean()
  999. cable2.save()
  1000. cable3 = Cable(
  1001. termination_a=CircuitTermination.objects.get(term_side='Z'),
  1002. termination_b=RearPort.objects.get(device__name='Panel 6', name='Rear Port 1')
  1003. )
  1004. cable3.full_clean()
  1005. cable3.save()
  1006. cable4 = Cable(
  1007. termination_a=FrontPort.objects.get(device__name='Panel 6', name='Front Port 1'),
  1008. termination_b=Interface.objects.get(device__name='Device 2', name='Interface 1')
  1009. )
  1010. cable4.full_clean()
  1011. cable4.save()
  1012. # Retrieve endpoints
  1013. endpoint_a = Interface.objects.get(device__name='Device 1', name='Interface 1')
  1014. endpoint_b = Interface.objects.get(device__name='Device 2', name='Interface 1')
  1015. # Validate connections
  1016. self.assertEqual(endpoint_a.connected_endpoint, endpoint_b)
  1017. self.assertEqual(endpoint_b.connected_endpoint, endpoint_a)
  1018. self.assertTrue(endpoint_a.connection_status)
  1019. self.assertTrue(endpoint_b.connection_status)
  1020. # Delete circuit
  1021. circuit = Circuit.objects.first().delete()
  1022. # Refresh endpoints
  1023. endpoint_a.refresh_from_db()
  1024. endpoint_b.refresh_from_db()
  1025. # Check that connections have been nullified
  1026. self.assertIsNone(endpoint_a.connected_endpoint)
  1027. self.assertIsNone(endpoint_b.connected_endpoint)
  1028. self.assertIsNone(endpoint_a.connection_status)
  1029. self.assertIsNone(endpoint_b.connection_status)