test_models.py 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  1. from django.core.exceptions import ValidationError
  2. from django.test import tag, TestCase
  3. from circuits.models import *
  4. from core.models import ObjectType
  5. from dcim.choices import *
  6. from dcim.models import *
  7. from extras.models import CustomField
  8. from netbox.choices import WeightUnitChoices
  9. from tenancy.models import Tenant
  10. from utilities.data import drange
  11. from virtualization.models import Cluster, ClusterType
  12. class MACAddressTestCase(TestCase):
  13. @classmethod
  14. def setUpTestData(cls):
  15. site = Site.objects.create(name='Test Site 1', slug='test-site-1')
  16. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  17. device_type = DeviceType.objects.create(
  18. manufacturer=manufacturer, model='Test Device Type 1', slug='test-device-type-1'
  19. )
  20. device_role = DeviceRole.objects.create(name='Test Role 1', slug='test-role-1')
  21. device = Device.objects.create(
  22. name='Device 1', device_type=device_type, role=device_role, site=site,
  23. )
  24. cls.interface = Interface.objects.create(
  25. device=device,
  26. name='Interface 1',
  27. type=InterfaceTypeChoices.TYPE_1GE_FIXED,
  28. mgmt_only=True
  29. )
  30. cls.mac_a = MACAddress.objects.create(mac_address='1234567890ab', assigned_object=cls.interface)
  31. cls.mac_b = MACAddress.objects.create(mac_address='1234567890ba', assigned_object=cls.interface)
  32. cls.interface.primary_mac_address = cls.mac_a
  33. cls.interface.save()
  34. @tag('regression')
  35. def test_clean_will_not_allow_removal_of_assigned_object_if_primary(self):
  36. self.mac_a.assigned_object = None
  37. with self.assertRaisesMessage(ValidationError, 'Cannot unassign MAC Address while'):
  38. self.mac_a.clean()
  39. @tag('regression')
  40. def test_clean_will_allow_removal_of_assigned_object_if_not_primary(self):
  41. self.mac_b.assigned_object = None
  42. self.mac_b.clean()
  43. class LocationTestCase(TestCase):
  44. def test_change_location_site(self):
  45. """
  46. Check that all child Locations and Racks get updated when a Location is moved to a new Site. Topology:
  47. Site A
  48. - Location A1
  49. - Location A2
  50. - Rack 2
  51. - Device 2
  52. - Rack 1
  53. - Device 1
  54. """
  55. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  56. device_type = DeviceType.objects.create(
  57. manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'
  58. )
  59. role = DeviceRole.objects.create(
  60. name='Device Role 1', slug='device-role-1', color='ff0000'
  61. )
  62. site_a = Site.objects.create(name='Site A', slug='site-a')
  63. site_b = Site.objects.create(name='Site B', slug='site-b')
  64. location_a1 = Location(site=site_a, name='Location A1', slug='location-a1')
  65. location_a1.save()
  66. location_a2 = Location(site=site_a, parent=location_a1, name='Location A2', slug='location-a2')
  67. location_a2.save()
  68. rack1 = Rack.objects.create(site=site_a, location=location_a1, name='Rack 1')
  69. rack2 = Rack.objects.create(site=site_a, location=location_a2, name='Rack 2')
  70. device1 = Device.objects.create(
  71. site=site_a,
  72. location=location_a1,
  73. name='Device 1',
  74. device_type=device_type,
  75. role=role
  76. )
  77. device2 = Device.objects.create(
  78. site=site_a,
  79. location=location_a2,
  80. name='Device 2',
  81. device_type=device_type,
  82. role=role
  83. )
  84. powerpanel1 = PowerPanel.objects.create(site=site_a, location=location_a1, name='Power Panel 1')
  85. # Move Location A1 to Site B
  86. location_a1.site = site_b
  87. location_a1.save()
  88. # Check that all objects within Location A1 now belong to Site B
  89. self.assertEqual(Location.objects.get(pk=location_a1.pk).site, site_b)
  90. self.assertEqual(Location.objects.get(pk=location_a2.pk).site, site_b)
  91. self.assertEqual(Rack.objects.get(pk=rack1.pk).site, site_b)
  92. self.assertEqual(Rack.objects.get(pk=rack2.pk).site, site_b)
  93. self.assertEqual(Device.objects.get(pk=device1.pk).site, site_b)
  94. self.assertEqual(Device.objects.get(pk=device2.pk).site, site_b)
  95. self.assertEqual(PowerPanel.objects.get(pk=powerpanel1.pk).site, site_b)
  96. class RackTypeTestCase(TestCase):
  97. @classmethod
  98. def setUpTestData(cls):
  99. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  100. RackType.objects.create(
  101. manufacturer=manufacturer,
  102. model='RackType 1',
  103. slug='rack-type-1',
  104. width=11,
  105. u_height=22,
  106. starting_unit=3,
  107. desc_units=True,
  108. outer_width=444,
  109. outer_depth=5,
  110. outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER,
  111. weight=66,
  112. weight_unit=WeightUnitChoices.UNIT_POUND,
  113. max_weight=7777,
  114. mounting_depth=8,
  115. )
  116. def test_rack_creation(self):
  117. rack_type = RackType.objects.first()
  118. sites = (
  119. Site(name='Site 1', slug='site-1'),
  120. )
  121. Site.objects.bulk_create(sites)
  122. locations = (
  123. Location(name='Location 1', slug='location-1', site=sites[0]),
  124. )
  125. for location in locations:
  126. location.save()
  127. rack = Rack.objects.create(
  128. name='Rack 1',
  129. facility_id='A101',
  130. site=sites[0],
  131. location=locations[0],
  132. rack_type=rack_type
  133. )
  134. self.assertEqual(rack.width, rack_type.width)
  135. self.assertEqual(rack.u_height, rack_type.u_height)
  136. self.assertEqual(rack.starting_unit, rack_type.starting_unit)
  137. self.assertEqual(rack.desc_units, rack_type.desc_units)
  138. self.assertEqual(rack.outer_width, rack_type.outer_width)
  139. self.assertEqual(rack.outer_depth, rack_type.outer_depth)
  140. self.assertEqual(rack.outer_unit, rack_type.outer_unit)
  141. self.assertEqual(rack.weight, rack_type.weight)
  142. self.assertEqual(rack.weight_unit, rack_type.weight_unit)
  143. self.assertEqual(rack.max_weight, rack_type.max_weight)
  144. self.assertEqual(rack.mounting_depth, rack_type.mounting_depth)
  145. class RackTestCase(TestCase):
  146. @classmethod
  147. def setUpTestData(cls):
  148. sites = (
  149. Site(name='Site 1', slug='site-1'),
  150. Site(name='Site 2', slug='site-2'),
  151. )
  152. Site.objects.bulk_create(sites)
  153. locations = (
  154. Location(name='Location 1', slug='location-1', site=sites[0]),
  155. Location(name='Location 2', slug='location-2', site=sites[1]),
  156. )
  157. for location in locations:
  158. location.save()
  159. Rack.objects.create(
  160. name='Rack 1',
  161. facility_id='A101',
  162. site=sites[0],
  163. location=locations[0],
  164. u_height=42
  165. )
  166. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  167. device_types = (
  168. DeviceType(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1', u_height=1),
  169. DeviceType(manufacturer=manufacturer, model='Device Type 2', slug='device-type-2', u_height=0),
  170. DeviceType(manufacturer=manufacturer, model='Device Type 3', slug='device-type-3', u_height=0.5),
  171. )
  172. DeviceType.objects.bulk_create(device_types)
  173. DeviceRole.objects.create(name='Device Role 1', slug='device-role-1')
  174. def test_rack_device_outside_height(self):
  175. site = Site.objects.first()
  176. rack = Rack.objects.first()
  177. device1 = Device(
  178. name='Device 1',
  179. device_type=DeviceType.objects.first(),
  180. role=DeviceRole.objects.first(),
  181. site=site,
  182. rack=rack,
  183. position=43,
  184. face=DeviceFaceChoices.FACE_FRONT,
  185. )
  186. device1.save()
  187. with self.assertRaises(ValidationError):
  188. rack.clean()
  189. def test_location_site(self):
  190. site1 = Site.objects.get(name='Site 1')
  191. location2 = Location.objects.get(name='Location 2')
  192. rack2 = Rack(
  193. name='Rack 2',
  194. site=site1,
  195. location=location2,
  196. u_height=42
  197. )
  198. rack2.save()
  199. with self.assertRaises(ValidationError):
  200. rack2.clean()
  201. def test_mount_single_device(self):
  202. site = Site.objects.first()
  203. rack = Rack.objects.first()
  204. device1 = Device(
  205. name='TestSwitch1',
  206. device_type=DeviceType.objects.first(),
  207. role=DeviceRole.objects.first(),
  208. site=site,
  209. rack=rack,
  210. position=10.0,
  211. face=DeviceFaceChoices.FACE_REAR,
  212. )
  213. device1.save()
  214. # Validate rack height
  215. self.assertEqual(list(rack.units), list(drange(42.5, 0.5, -0.5)))
  216. # Validate inventory (front face)
  217. rack1_inventory_front = {
  218. u['id']: u for u in rack.get_rack_units(face=DeviceFaceChoices.FACE_FRONT)
  219. }
  220. self.assertEqual(rack1_inventory_front[10.0]['device'], device1)
  221. self.assertEqual(rack1_inventory_front[10.5]['device'], device1)
  222. del rack1_inventory_front[10.0]
  223. del rack1_inventory_front[10.5]
  224. for u in rack1_inventory_front.values():
  225. self.assertIsNone(u['device'])
  226. # Validate inventory (rear face)
  227. rack1_inventory_rear = {
  228. u['id']: u for u in rack.get_rack_units(face=DeviceFaceChoices.FACE_REAR)
  229. }
  230. self.assertEqual(rack1_inventory_rear[10.0]['device'], device1)
  231. self.assertEqual(rack1_inventory_rear[10.5]['device'], device1)
  232. del rack1_inventory_rear[10.0]
  233. del rack1_inventory_rear[10.5]
  234. for u in rack1_inventory_rear.values():
  235. self.assertIsNone(u['device'])
  236. def test_mount_zero_ru(self):
  237. """
  238. Check that a 0RU device can be mounted in a rack with no face/position.
  239. """
  240. site = Site.objects.first()
  241. rack = Rack.objects.first()
  242. Device(
  243. name='Device 1',
  244. role=DeviceRole.objects.first(),
  245. device_type=DeviceType.objects.first(),
  246. site=site,
  247. rack=rack
  248. ).save()
  249. def test_mount_half_u_devices(self):
  250. """
  251. Check that two 0.5U devices can be mounted in the same rack unit.
  252. """
  253. rack = Rack.objects.first()
  254. attrs = {
  255. 'device_type': DeviceType.objects.get(u_height=0.5),
  256. 'role': DeviceRole.objects.first(),
  257. 'site': Site.objects.first(),
  258. 'rack': rack,
  259. 'face': DeviceFaceChoices.FACE_FRONT,
  260. }
  261. Device(name='Device 1', position=1, **attrs).save()
  262. Device(name='Device 2', position=1.5, **attrs).save()
  263. self.assertEqual(len(rack.get_available_units()), rack.u_height * 2 - 3)
  264. def test_change_rack_site(self):
  265. """
  266. Check that child Devices get updated when a Rack is moved to a new Site.
  267. """
  268. site_a = Site.objects.create(name='Site A', slug='site-a')
  269. site_b = Site.objects.create(name='Site B', slug='site-b')
  270. # Create Rack1 in Site A
  271. rack1 = Rack.objects.create(site=site_a, name='Rack 1')
  272. # Create Device1 in Rack1
  273. device1 = Device.objects.create(
  274. site=site_a,
  275. rack=rack1,
  276. device_type=DeviceType.objects.first(),
  277. role=DeviceRole.objects.first()
  278. )
  279. # Move Rack1 to Site B
  280. rack1.site = site_b
  281. rack1.save()
  282. # Check that Device1 is now assigned to Site B
  283. self.assertEqual(Device.objects.get(pk=device1.pk).site, site_b)
  284. def test_utilization(self):
  285. site = Site.objects.first()
  286. rack = Rack.objects.first()
  287. Device(
  288. name='Device 1',
  289. role=DeviceRole.objects.first(),
  290. device_type=DeviceType.objects.first(),
  291. site=site,
  292. rack=rack,
  293. position=1
  294. ).save()
  295. rack.refresh_from_db()
  296. self.assertEqual(rack.get_utilization(), 1 / 42 * 100)
  297. # create device excluded from utilization calculations
  298. dt = DeviceType.objects.create(
  299. manufacturer=Manufacturer.objects.first(),
  300. model='Device Type 4',
  301. slug='device-type-4',
  302. u_height=1,
  303. exclude_from_utilization=True
  304. )
  305. Device(
  306. name='Device 2',
  307. role=DeviceRole.objects.first(),
  308. device_type=dt,
  309. site=site,
  310. rack=rack,
  311. position=5
  312. ).save()
  313. rack.refresh_from_db()
  314. self.assertEqual(rack.get_utilization(), 1 / 42 * 100)
  315. class DeviceTestCase(TestCase):
  316. @classmethod
  317. def setUpTestData(cls):
  318. Site.objects.create(name='Test Site 1', slug='test-site-1')
  319. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  320. device_type = DeviceType.objects.create(
  321. manufacturer=manufacturer, model='Test Device Type 1', slug='test-device-type-1'
  322. )
  323. roles = (
  324. DeviceRole(name='Test Role 1', slug='test-role-1'),
  325. DeviceRole(name='Test Role 2', slug='test-role-2'),
  326. )
  327. for role in roles:
  328. role.save()
  329. # Create a CustomField with a default value & assign it to all component models
  330. cf1 = CustomField.objects.create(name='cf1', default='foo')
  331. cf1.object_types.set(
  332. ObjectType.objects.filter(app_label='dcim', model__in=[
  333. 'consoleport',
  334. 'consoleserverport',
  335. 'powerport',
  336. 'poweroutlet',
  337. 'interface',
  338. 'rearport',
  339. 'frontport',
  340. 'modulebay',
  341. 'devicebay',
  342. 'inventoryitem',
  343. ])
  344. )
  345. # Create DeviceType components
  346. ConsolePortTemplate(
  347. device_type=device_type,
  348. name='Console Port 1'
  349. ).save()
  350. ConsoleServerPortTemplate(
  351. device_type=device_type,
  352. name='Console Server Port 1'
  353. ).save()
  354. powerport = PowerPortTemplate(
  355. device_type=device_type,
  356. name='Power Port 1',
  357. maximum_draw=1000,
  358. allocated_draw=500
  359. )
  360. powerport.save()
  361. PowerOutletTemplate(
  362. device_type=device_type,
  363. name='Power Outlet 1',
  364. power_port=powerport,
  365. feed_leg=PowerOutletFeedLegChoices.FEED_LEG_A
  366. ).save()
  367. InterfaceTemplate(
  368. device_type=device_type,
  369. name='Interface 1',
  370. type=InterfaceTypeChoices.TYPE_1GE_FIXED,
  371. mgmt_only=True
  372. ).save()
  373. rearport = RearPortTemplate(
  374. device_type=device_type,
  375. name='Rear Port 1',
  376. type=PortTypeChoices.TYPE_8P8C,
  377. positions=8
  378. )
  379. rearport.save()
  380. FrontPortTemplate(
  381. device_type=device_type,
  382. name='Front Port 1',
  383. type=PortTypeChoices.TYPE_8P8C,
  384. rear_port=rearport,
  385. rear_port_position=2
  386. ).save()
  387. ModuleBayTemplate(
  388. device_type=device_type,
  389. name='Module Bay 1'
  390. ).save()
  391. DeviceBayTemplate(
  392. device_type=device_type,
  393. name='Device Bay 1'
  394. ).save()
  395. InventoryItemTemplate(
  396. device_type=device_type,
  397. name='Inventory Item 1'
  398. ).save()
  399. def test_device_creation(self):
  400. """
  401. Ensure that all Device components are copied automatically from the DeviceType.
  402. """
  403. device = Device(
  404. site=Site.objects.first(),
  405. device_type=DeviceType.objects.first(),
  406. role=DeviceRole.objects.first(),
  407. name='Test Device 1'
  408. )
  409. device.save()
  410. consoleport = ConsolePort.objects.get(
  411. device=device,
  412. name='Console Port 1'
  413. )
  414. self.assertEqual(consoleport.cf['cf1'], 'foo')
  415. consoleserverport = ConsoleServerPort.objects.get(
  416. device=device,
  417. name='Console Server Port 1'
  418. )
  419. self.assertEqual(consoleserverport.cf['cf1'], 'foo')
  420. powerport = PowerPort.objects.get(
  421. device=device,
  422. name='Power Port 1',
  423. maximum_draw=1000,
  424. allocated_draw=500
  425. )
  426. self.assertEqual(powerport.cf['cf1'], 'foo')
  427. poweroutlet = PowerOutlet.objects.get(
  428. device=device,
  429. name='Power Outlet 1',
  430. power_port=powerport,
  431. feed_leg=PowerOutletFeedLegChoices.FEED_LEG_A,
  432. status=PowerOutletStatusChoices.STATUS_ENABLED,
  433. )
  434. self.assertEqual(poweroutlet.cf['cf1'], 'foo')
  435. interface = Interface.objects.get(
  436. device=device,
  437. name='Interface 1',
  438. type=InterfaceTypeChoices.TYPE_1GE_FIXED,
  439. mgmt_only=True
  440. )
  441. self.assertEqual(interface.cf['cf1'], 'foo')
  442. rearport = RearPort.objects.get(
  443. device=device,
  444. name='Rear Port 1',
  445. type=PortTypeChoices.TYPE_8P8C,
  446. positions=8
  447. )
  448. self.assertEqual(rearport.cf['cf1'], 'foo')
  449. frontport = FrontPort.objects.get(
  450. device=device,
  451. name='Front Port 1',
  452. type=PortTypeChoices.TYPE_8P8C,
  453. rear_port=rearport,
  454. rear_port_position=2
  455. )
  456. self.assertEqual(frontport.cf['cf1'], 'foo')
  457. modulebay = ModuleBay.objects.get(
  458. device=device,
  459. name='Module Bay 1'
  460. )
  461. self.assertEqual(modulebay.cf['cf1'], 'foo')
  462. devicebay = DeviceBay.objects.get(
  463. device=device,
  464. name='Device Bay 1'
  465. )
  466. self.assertEqual(devicebay.cf['cf1'], 'foo')
  467. inventoryitem = InventoryItem.objects.get(
  468. device=device,
  469. name='Inventory Item 1'
  470. )
  471. self.assertEqual(inventoryitem.cf['cf1'], 'foo')
  472. def test_multiple_unnamed_devices(self):
  473. device1 = Device(
  474. site=Site.objects.first(),
  475. device_type=DeviceType.objects.first(),
  476. role=DeviceRole.objects.first(),
  477. name=None
  478. )
  479. device1.save()
  480. device2 = Device(
  481. site=device1.site,
  482. device_type=device1.device_type,
  483. role=device1.role,
  484. name=None
  485. )
  486. device2.full_clean()
  487. device2.save()
  488. self.assertEqual(Device.objects.filter(name__isnull=True).count(), 2)
  489. def test_device_name_case_sensitivity(self):
  490. device1 = Device(
  491. site=Site.objects.first(),
  492. device_type=DeviceType.objects.first(),
  493. role=DeviceRole.objects.first(),
  494. name='device 1'
  495. )
  496. device1.save()
  497. device2 = Device(
  498. site=device1.site,
  499. device_type=device1.device_type,
  500. role=device1.role,
  501. name='DEVICE 1'
  502. )
  503. # Uniqueness validation for name should ignore case
  504. with self.assertRaises(ValidationError):
  505. device2.full_clean()
  506. def test_device_duplicate_names(self):
  507. device1 = Device(
  508. site=Site.objects.first(),
  509. device_type=DeviceType.objects.first(),
  510. role=DeviceRole.objects.first(),
  511. name='Test Device 1'
  512. )
  513. device1.save()
  514. device2 = Device(
  515. site=device1.site,
  516. device_type=device1.device_type,
  517. role=device1.role,
  518. name=device1.name
  519. )
  520. # Two devices assigned to the same Site and no Tenant should fail validation
  521. with self.assertRaises(ValidationError):
  522. device2.full_clean()
  523. tenant = Tenant.objects.create(name='Test Tenant 1', slug='test-tenant-1')
  524. device1.tenant = tenant
  525. device1.save()
  526. device2.tenant = tenant
  527. # Two devices assigned to the same Site and the same Tenant should fail validation
  528. with self.assertRaises(ValidationError):
  529. device2.full_clean()
  530. device2.tenant = None
  531. # Two devices assigned to the same Site and different Tenants should pass validation
  532. device2.full_clean()
  533. device2.save()
  534. def test_device_label(self):
  535. device1 = Device(
  536. site=Site.objects.first(),
  537. device_type=DeviceType.objects.first(),
  538. role=DeviceRole.objects.first(),
  539. name=None,
  540. )
  541. self.assertEqual(device1.label, None)
  542. device1.name = 'Test Device 1'
  543. self.assertEqual(device1.label, 'Test Device 1')
  544. virtual_chassis = VirtualChassis.objects.create(name='VC 1')
  545. device2 = Device(
  546. site=Site.objects.first(),
  547. device_type=DeviceType.objects.first(),
  548. role=DeviceRole.objects.first(),
  549. name=None,
  550. virtual_chassis=virtual_chassis,
  551. vc_position=2,
  552. )
  553. self.assertEqual(device2.label, 'VC 1:2')
  554. device2.name = 'Test Device 2'
  555. self.assertEqual(device2.label, 'Test Device 2')
  556. def test_device_mismatched_site_cluster(self):
  557. cluster_type = ClusterType.objects.create(name='Cluster Type 1', slug='cluster-type-1')
  558. Cluster.objects.create(name='Cluster 1', type=cluster_type)
  559. sites = (
  560. Site(name='Site 1', slug='site-1'),
  561. Site(name='Site 2', slug='site-2'),
  562. )
  563. Site.objects.bulk_create(sites)
  564. clusters = (
  565. Cluster(name='Cluster 1', type=cluster_type, scope=sites[0]),
  566. Cluster(name='Cluster 2', type=cluster_type, scope=sites[1]),
  567. Cluster(name='Cluster 3', type=cluster_type, scope=None),
  568. )
  569. for cluster in clusters:
  570. cluster.save()
  571. device_type = DeviceType.objects.first()
  572. device_role = DeviceRole.objects.first()
  573. # Device with site only should pass
  574. Device(
  575. name='device1',
  576. site=sites[0],
  577. device_type=device_type,
  578. role=device_role
  579. ).full_clean()
  580. # Device with site, cluster non-site should pass
  581. Device(
  582. name='device1',
  583. site=sites[0],
  584. device_type=device_type,
  585. role=device_role,
  586. cluster=clusters[2]
  587. ).full_clean()
  588. # Device with mismatched site & cluster should fail
  589. with self.assertRaises(ValidationError):
  590. Device(
  591. name='device1',
  592. site=sites[0],
  593. device_type=device_type,
  594. role=device_role,
  595. cluster=clusters[1]
  596. ).full_clean()
  597. class ModuleBayTestCase(TestCase):
  598. @classmethod
  599. def setUpTestData(cls):
  600. site = Site.objects.create(name='Test Site 1', slug='test-site-1')
  601. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  602. device_type = DeviceType.objects.create(
  603. manufacturer=manufacturer, model='Test Device Type 1', slug='test-device-type-1'
  604. )
  605. device_role = DeviceRole.objects.create(name='Test Role 1', slug='test-role-1')
  606. # Create a CustomField with a default value & assign it to all component models
  607. location = Location.objects.create(name='Location 1', slug='location-1', site=site)
  608. rack = Rack.objects.create(name='Rack 1', site=site)
  609. device = Device.objects.create(
  610. name='Device 1', device_type=device_type, role=device_role, site=site, location=location, rack=rack
  611. )
  612. module_bays = (
  613. ModuleBay(device=device, name='Module Bay 1', label='A', description='First'),
  614. ModuleBay(device=device, name='Module Bay 2', label='B', description='Second'),
  615. ModuleBay(device=device, name='Module Bay 3', label='C', description='Third'),
  616. )
  617. for module_bay in module_bays:
  618. module_bay.save()
  619. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  620. module_type = ModuleType.objects.create(manufacturer=manufacturer, model='Module Type 1')
  621. modules = (
  622. Module(device=device, module_bay=module_bays[0], module_type=module_type),
  623. Module(device=device, module_bay=module_bays[1], module_type=module_type),
  624. Module(device=device, module_bay=module_bays[2], module_type=module_type),
  625. )
  626. # M3 -> MB3 -> M2 -> MB2 -> M1 -> MB1
  627. Module.objects.bulk_create(modules)
  628. module_bays[1].module = modules[0]
  629. module_bays[1].clean()
  630. module_bays[1].save()
  631. module_bays[2].module = modules[1]
  632. module_bays[2].clean()
  633. module_bays[2].save()
  634. def test_module_bay_recursion(self):
  635. module_bay_1 = ModuleBay.objects.get(name='Module Bay 1')
  636. module_bay_3 = ModuleBay.objects.get(name='Module Bay 3')
  637. module_1 = Module.objects.get(module_bay=module_bay_1)
  638. module_3 = Module.objects.get(module_bay=module_bay_3)
  639. # Confirm error if ModuleBay recurses
  640. with self.assertRaises(ValidationError):
  641. module_bay_1.module = module_3
  642. module_bay_1.clean()
  643. module_bay_1.save()
  644. # Confirm error if Module recurses
  645. with self.assertRaises(ValidationError):
  646. module_1.module_bay = module_bay_3
  647. module_1.clean()
  648. module_1.save()
  649. def test_single_module_token(self):
  650. device_type = DeviceType.objects.first()
  651. device_role = DeviceRole.objects.first()
  652. site = Site.objects.first()
  653. location = Location.objects.first()
  654. rack = Rack.objects.first()
  655. # Create DeviceType components
  656. ConsolePortTemplate.objects.create(
  657. device_type=device_type,
  658. name='{module}',
  659. label='{module}',
  660. )
  661. ModuleBayTemplate.objects.create(
  662. device_type=device_type,
  663. name='Module Bay 1'
  664. )
  665. device = Device.objects.create(
  666. name='Device 2',
  667. device_type=device_type,
  668. role=device_role,
  669. site=site,
  670. location=location,
  671. rack=rack
  672. )
  673. device.consoleports.first()
  674. def test_nested_module_token(self):
  675. pass
  676. class CableTestCase(TestCase):
  677. @classmethod
  678. def setUpTestData(cls):
  679. site = Site.objects.create(name='Test Site 1', slug='test-site-1')
  680. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  681. devicetype = DeviceType.objects.create(
  682. manufacturer=manufacturer, model='Test Device Type 1', slug='test-device-type-1'
  683. )
  684. role = DeviceRole.objects.create(
  685. name='Test Device Role 1', slug='test-device-role-1', color='ff0000'
  686. )
  687. device1 = Device.objects.create(
  688. device_type=devicetype, role=role, name='TestDevice1', site=site
  689. )
  690. device2 = Device.objects.create(
  691. device_type=devicetype, role=role, name='TestDevice2', site=site
  692. )
  693. interfaces = (
  694. Interface(device=device1, name='eth0'),
  695. Interface(device=device2, name='eth0'),
  696. Interface(device=device2, name='eth1'),
  697. )
  698. Interface.objects.bulk_create(interfaces)
  699. Cable(a_terminations=[interfaces[0]], b_terminations=[interfaces[1]]).save()
  700. PowerPort.objects.create(device=device2, name='psu1')
  701. patch_panel = Device.objects.create(
  702. device_type=devicetype, role=role, name='TestPatchPanel', site=site
  703. )
  704. rear_ports = (
  705. RearPort(device=patch_panel, name='RP1', type='8p8c'),
  706. RearPort(device=patch_panel, name='RP2', type='8p8c', positions=2),
  707. RearPort(device=patch_panel, name='RP3', type='8p8c', positions=3),
  708. RearPort(device=patch_panel, name='RP4', type='8p8c', positions=3),
  709. )
  710. RearPort.objects.bulk_create(rear_ports)
  711. front_ports = (
  712. FrontPort(device=patch_panel, name='FP1', type='8p8c', rear_port=rear_ports[0], rear_port_position=1),
  713. FrontPort(device=patch_panel, name='FP2', type='8p8c', rear_port=rear_ports[1], rear_port_position=1),
  714. FrontPort(device=patch_panel, name='FP3', type='8p8c', rear_port=rear_ports[2], rear_port_position=1),
  715. FrontPort(device=patch_panel, name='FP4', type='8p8c', rear_port=rear_ports[3], rear_port_position=1),
  716. )
  717. FrontPort.objects.bulk_create(front_ports)
  718. provider = Provider.objects.create(name='Provider 1', slug='provider-1')
  719. provider_network = ProviderNetwork.objects.create(name='Provider Network 1', provider=provider)
  720. circuittype = CircuitType.objects.create(name='Circuit Type 1', slug='circuit-type-1')
  721. circuit1 = Circuit.objects.create(provider=provider, type=circuittype, cid='1')
  722. circuit2 = Circuit.objects.create(provider=provider, type=circuittype, cid='2')
  723. CircuitTermination.objects.create(circuit=circuit1, termination=site, term_side='A')
  724. CircuitTermination.objects.create(circuit=circuit1, termination=site, term_side='Z')
  725. CircuitTermination.objects.create(circuit=circuit2, termination=provider_network, term_side='A')
  726. def test_cable_creation(self):
  727. """
  728. When a new Cable is created, it must be cached on either termination point.
  729. """
  730. interface1 = Interface.objects.get(device__name='TestDevice1', name='eth0')
  731. interface2 = Interface.objects.get(device__name='TestDevice2', name='eth0')
  732. cable = Cable.objects.first()
  733. self.assertEqual(interface1.cable, cable)
  734. self.assertEqual(interface2.cable, cable)
  735. self.assertEqual(interface1.cable_end, 'A')
  736. self.assertEqual(interface2.cable_end, 'B')
  737. self.assertEqual(interface1.link_peers, [interface2])
  738. self.assertEqual(interface2.link_peers, [interface1])
  739. def test_cable_deletion(self):
  740. """
  741. When a Cable is deleted, the `cable` field on its termination points must be nullified. The str() method
  742. should still return the PK of the string even after being nullified.
  743. """
  744. interface1 = Interface.objects.get(device__name='TestDevice1', name='eth0')
  745. interface2 = Interface.objects.get(device__name='TestDevice2', name='eth0')
  746. cable = Cable.objects.first()
  747. cable.delete()
  748. self.assertIsNone(cable.pk)
  749. self.assertNotEqual(str(cable), '#None')
  750. interface1 = Interface.objects.get(pk=interface1.pk)
  751. self.assertIsNone(interface1.cable)
  752. self.assertListEqual(interface1.link_peers, [])
  753. interface2 = Interface.objects.get(pk=interface2.pk)
  754. self.assertIsNone(interface2.cable)
  755. self.assertListEqual(interface2.link_peers, [])
  756. def test_cable_validates_same_parent_object(self):
  757. """
  758. The clean method should ensure that all terminations at either end of a Cable belong to the same parent object.
  759. """
  760. interface1 = Interface.objects.get(device__name='TestDevice1', name='eth0')
  761. powerport1 = PowerPort.objects.get(device__name='TestDevice2', name='psu1')
  762. cable = Cable(a_terminations=[interface1], b_terminations=[powerport1])
  763. with self.assertRaises(ValidationError):
  764. cable.clean()
  765. def test_cable_validates_same_type(self):
  766. """
  767. The clean method should ensure that all terminations at either end of a Cable are of the same type.
  768. """
  769. interface1 = Interface.objects.get(device__name='TestDevice1', name='eth0')
  770. frontport1 = FrontPort.objects.get(device__name='TestPatchPanel', name='FP1')
  771. rearport1 = RearPort.objects.get(device__name='TestPatchPanel', name='RP1')
  772. cable = Cable(a_terminations=[frontport1, rearport1], b_terminations=[interface1])
  773. with self.assertRaises(ValidationError):
  774. cable.clean()
  775. def test_cable_validates_compatible_types(self):
  776. """
  777. The clean method should have a check to ensure only compatible port types can be connected by a cable
  778. """
  779. interface1 = Interface.objects.get(device__name='TestDevice1', name='eth0')
  780. powerport1 = PowerPort.objects.get(device__name='TestDevice2', name='psu1')
  781. # An interface cannot be connected to a power port, for example
  782. cable = Cable(a_terminations=[interface1], b_terminations=[powerport1])
  783. with self.assertRaises(ValidationError):
  784. cable.clean()
  785. def test_cable_cannot_terminate_to_a_provider_network_circuittermination(self):
  786. """
  787. Neither side of a cable can be terminated to a CircuitTermination which is attached to a ProviderNetwork
  788. """
  789. interface3 = Interface.objects.get(device__name='TestDevice2', name='eth1')
  790. circuittermination3 = CircuitTermination.objects.get(circuit__cid='2', term_side='A')
  791. cable = Cable(a_terminations=[interface3], b_terminations=[circuittermination3])
  792. with self.assertRaises(ValidationError):
  793. cable.clean()
  794. def test_cable_cannot_terminate_to_a_virtual_interface(self):
  795. """
  796. A cable cannot terminate to a virtual interface
  797. """
  798. device1 = Device.objects.get(name='TestDevice1')
  799. interface2 = Interface.objects.get(device__name='TestDevice2', name='eth0')
  800. virtual_interface = Interface(device=device1, name="V1", type=InterfaceTypeChoices.TYPE_VIRTUAL)
  801. cable = Cable(a_terminations=[interface2], b_terminations=[virtual_interface])
  802. with self.assertRaises(ValidationError):
  803. cable.clean()
  804. def test_cable_cannot_terminate_to_a_wireless_interface(self):
  805. """
  806. A cable cannot terminate to a wireless interface
  807. """
  808. device1 = Device.objects.get(name='TestDevice1')
  809. interface2 = Interface.objects.get(device__name='TestDevice2', name='eth0')
  810. wireless_interface = Interface(device=device1, name="W1", type=InterfaceTypeChoices.TYPE_80211A)
  811. cable = Cable(a_terminations=[interface2], b_terminations=[wireless_interface])
  812. with self.assertRaises(ValidationError):
  813. cable.clean()
  814. @tag('regression')
  815. def test_cable_cannot_terminate_to_a_cellular_interface(self):
  816. """
  817. A cable cannot terminate to a cellular interface
  818. """
  819. device1 = Device.objects.get(name='TestDevice1')
  820. interface2 = Interface.objects.get(device__name='TestDevice2', name='eth0')
  821. cellular_interface = Interface(device=device1, name="W1", type=InterfaceTypeChoices.TYPE_LTE)
  822. cable = Cable(a_terminations=[interface2], b_terminations=[cellular_interface])
  823. with self.assertRaises(ValidationError):
  824. cable.clean()
  825. class VirtualDeviceContextTestCase(TestCase):
  826. @classmethod
  827. def setUpTestData(cls):
  828. site = Site.objects.create(name='Test Site 1', slug='test-site-1')
  829. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  830. devicetype = DeviceType.objects.create(
  831. manufacturer=manufacturer, model='Test Device Type 1', slug='test-device-type-1'
  832. )
  833. role = DeviceRole.objects.create(
  834. name='Test Device Role 1', slug='test-device-role-1', color='ff0000'
  835. )
  836. Device.objects.create(
  837. device_type=devicetype, role=role, name='TestDevice1', site=site
  838. )
  839. def test_vdc_and_interface_creation(self):
  840. device = Device.objects.first()
  841. vdc = VirtualDeviceContext(device=device, name="VDC 1", identifier=1, status='active')
  842. vdc.full_clean()
  843. vdc.save()
  844. interface = Interface(device=device, name='Eth1/1', type='10gbase-t')
  845. interface.full_clean()
  846. interface.save()
  847. interface.vdcs.set([vdc])
  848. def test_vdc_duplicate_name(self):
  849. device = Device.objects.first()
  850. vdc1 = VirtualDeviceContext(device=device, name="VDC 1", identifier=1, status='active')
  851. vdc1.full_clean()
  852. vdc1.save()
  853. vdc2 = VirtualDeviceContext(device=device, name="VDC 1", identifier=2, status='active')
  854. with self.assertRaises(ValidationError):
  855. vdc2.full_clean()
  856. def test_vdc_duplicate_identifier(self):
  857. device = Device.objects.first()
  858. vdc1 = VirtualDeviceContext(device=device, name="VDC 1", identifier=1, status='active')
  859. vdc1.full_clean()
  860. vdc1.save()
  861. vdc2 = VirtualDeviceContext(device=device, name="VDC 2", identifier=1, status='active')
  862. with self.assertRaises(ValidationError):
  863. vdc2.full_clean()