test_api.py 63 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713
  1. from django.contrib.auth.models import User
  2. from django.urls import reverse
  3. from rest_framework import status
  4. from dcim.choices import *
  5. from dcim.constants import *
  6. from dcim.models import *
  7. from ipam.models import VLAN
  8. from utilities.testing import APITestCase, APIViewTestCases
  9. from virtualization.models import Cluster, ClusterType
  10. class AppTest(APITestCase):
  11. def test_root(self):
  12. url = reverse('dcim-api:api-root')
  13. response = self.client.get('{}?format=api'.format(url), **self.header)
  14. self.assertEqual(response.status_code, 200)
  15. class Mixins:
  16. class ComponentTraceMixin(APITestCase):
  17. peer_termination_type = None
  18. def test_trace(self):
  19. """
  20. Test tracing a device component's attached cable.
  21. """
  22. obj = self.model.objects.first()
  23. peer_device = Device.objects.create(
  24. site=Site.objects.first(),
  25. device_type=DeviceType.objects.first(),
  26. device_role=DeviceRole.objects.first(),
  27. name='Peer Device'
  28. )
  29. if self.peer_termination_type is None:
  30. raise NotImplementedError("Test case must set peer_termination_type")
  31. peer_obj = self.peer_termination_type.objects.create(
  32. device=peer_device,
  33. name='Peer Termination'
  34. )
  35. cable = Cable(termination_a=obj, termination_b=peer_obj, label='Cable 1')
  36. cable.save()
  37. self.add_permissions(f'dcim.view_{self.model._meta.model_name}')
  38. url = reverse(f'dcim-api:{self.model._meta.model_name}-trace', kwargs={'pk': obj.pk})
  39. response = self.client.get(url, **self.header)
  40. self.assertHttpStatus(response, status.HTTP_200_OK)
  41. self.assertEqual(len(response.data), 1)
  42. segment1 = response.data[0]
  43. self.assertEqual(segment1[0]['name'], obj.name)
  44. self.assertEqual(segment1[1]['label'], cable.label)
  45. self.assertEqual(segment1[2]['name'], peer_obj.name)
  46. class RegionTest(APIViewTestCases.APIViewTestCase):
  47. model = Region
  48. brief_fields = ['_depth', 'display', 'id', 'name', 'site_count', 'slug', 'url']
  49. create_data = [
  50. {
  51. 'name': 'Region 4',
  52. 'slug': 'region-4',
  53. },
  54. {
  55. 'name': 'Region 5',
  56. 'slug': 'region-5',
  57. },
  58. {
  59. 'name': 'Region 6',
  60. 'slug': 'region-6',
  61. },
  62. ]
  63. bulk_update_data = {
  64. 'description': 'New description',
  65. }
  66. @classmethod
  67. def setUpTestData(cls):
  68. Region.objects.create(name='Region 1', slug='region-1')
  69. Region.objects.create(name='Region 2', slug='region-2')
  70. Region.objects.create(name='Region 3', slug='region-3')
  71. class SiteGroupTest(APIViewTestCases.APIViewTestCase):
  72. model = SiteGroup
  73. brief_fields = ['_depth', 'display', 'id', 'name', 'site_count', 'slug', 'url']
  74. create_data = [
  75. {
  76. 'name': 'Site Group 4',
  77. 'slug': 'site-group-4',
  78. },
  79. {
  80. 'name': 'Site Group 5',
  81. 'slug': 'site-group-5',
  82. },
  83. {
  84. 'name': 'Site Group 6',
  85. 'slug': 'site-group-6',
  86. },
  87. ]
  88. bulk_update_data = {
  89. 'description': 'New description',
  90. }
  91. @classmethod
  92. def setUpTestData(cls):
  93. SiteGroup.objects.create(name='Site Group 1', slug='site-group-1')
  94. SiteGroup.objects.create(name='Site Group 2', slug='site-group-2')
  95. SiteGroup.objects.create(name='Site Group 3', slug='site-group-3')
  96. class SiteTest(APIViewTestCases.APIViewTestCase):
  97. model = Site
  98. brief_fields = ['display', 'id', 'name', 'slug', 'url']
  99. bulk_update_data = {
  100. 'status': 'planned',
  101. }
  102. @classmethod
  103. def setUpTestData(cls):
  104. regions = (
  105. Region.objects.create(name='Region 1', slug='region-1'),
  106. Region.objects.create(name='Region 2', slug='region-2'),
  107. )
  108. groups = (
  109. SiteGroup.objects.create(name='Site Group 1', slug='site-group-1'),
  110. SiteGroup.objects.create(name='Site Group 2', slug='site-group-2'),
  111. )
  112. sites = (
  113. Site(region=regions[0], group=groups[0], name='Site 1', slug='site-1'),
  114. Site(region=regions[0], group=groups[0], name='Site 2', slug='site-2'),
  115. Site(region=regions[0], group=groups[0], name='Site 3', slug='site-3'),
  116. )
  117. Site.objects.bulk_create(sites)
  118. cls.create_data = [
  119. {
  120. 'name': 'Site 4',
  121. 'slug': 'site-4',
  122. 'region': regions[1].pk,
  123. 'group': groups[1].pk,
  124. 'status': SiteStatusChoices.STATUS_ACTIVE,
  125. },
  126. {
  127. 'name': 'Site 5',
  128. 'slug': 'site-5',
  129. 'region': regions[1].pk,
  130. 'group': groups[1].pk,
  131. 'status': SiteStatusChoices.STATUS_ACTIVE,
  132. },
  133. {
  134. 'name': 'Site 6',
  135. 'slug': 'site-6',
  136. 'region': regions[1].pk,
  137. 'group': groups[1].pk,
  138. 'status': SiteStatusChoices.STATUS_ACTIVE,
  139. },
  140. ]
  141. class LocationTest(APIViewTestCases.APIViewTestCase):
  142. model = Location
  143. brief_fields = ['_depth', 'display', 'id', 'name', 'rack_count', 'slug', 'url']
  144. bulk_update_data = {
  145. 'description': 'New description',
  146. }
  147. @classmethod
  148. def setUpTestData(cls):
  149. sites = (
  150. Site(name='Site 1', slug='site-1'),
  151. Site(name='Site 2', slug='site-2'),
  152. )
  153. Site.objects.bulk_create(sites)
  154. parent_locations = (
  155. Location.objects.create(site=sites[0], name='Parent Location 1', slug='parent-location-1'),
  156. Location.objects.create(site=sites[1], name='Parent Location 2', slug='parent-location-2'),
  157. )
  158. Location.objects.create(site=sites[0], name='Location 1', slug='location-1', parent=parent_locations[0])
  159. Location.objects.create(site=sites[0], name='Location 2', slug='location-2', parent=parent_locations[0])
  160. Location.objects.create(site=sites[0], name='Location 3', slug='location-3', parent=parent_locations[0])
  161. cls.create_data = [
  162. {
  163. 'name': 'Test Location 4',
  164. 'slug': 'test-location-4',
  165. 'site': sites[1].pk,
  166. 'parent': parent_locations[1].pk,
  167. },
  168. {
  169. 'name': 'Test Location 5',
  170. 'slug': 'test-location-5',
  171. 'site': sites[1].pk,
  172. 'parent': parent_locations[1].pk,
  173. },
  174. {
  175. 'name': 'Test Location 6',
  176. 'slug': 'test-location-6',
  177. 'site': sites[1].pk,
  178. 'parent': parent_locations[1].pk,
  179. },
  180. ]
  181. class RackRoleTest(APIViewTestCases.APIViewTestCase):
  182. model = RackRole
  183. brief_fields = ['display', 'id', 'name', 'rack_count', 'slug', 'url']
  184. create_data = [
  185. {
  186. 'name': 'Rack Role 4',
  187. 'slug': 'rack-role-4',
  188. 'color': 'ffff00',
  189. },
  190. {
  191. 'name': 'Rack Role 5',
  192. 'slug': 'rack-role-5',
  193. 'color': 'ffff00',
  194. },
  195. {
  196. 'name': 'Rack Role 6',
  197. 'slug': 'rack-role-6',
  198. 'color': 'ffff00',
  199. },
  200. ]
  201. bulk_update_data = {
  202. 'description': 'New description',
  203. }
  204. @classmethod
  205. def setUpTestData(cls):
  206. rack_roles = (
  207. RackRole(name='Rack Role 1', slug='rack-role-1', color='ff0000'),
  208. RackRole(name='Rack Role 2', slug='rack-role-2', color='00ff00'),
  209. RackRole(name='Rack Role 3', slug='rack-role-3', color='0000ff'),
  210. )
  211. RackRole.objects.bulk_create(rack_roles)
  212. class RackTest(APIViewTestCases.APIViewTestCase):
  213. model = Rack
  214. brief_fields = ['device_count', 'display', 'id', 'name', 'url']
  215. bulk_update_data = {
  216. 'status': 'planned',
  217. }
  218. @classmethod
  219. def setUpTestData(cls):
  220. sites = (
  221. Site(name='Site 1', slug='site-1'),
  222. Site(name='Site 2', slug='site-2'),
  223. )
  224. Site.objects.bulk_create(sites)
  225. locations = (
  226. Location.objects.create(site=sites[0], name='Location 1', slug='location-1'),
  227. Location.objects.create(site=sites[1], name='Location 2', slug='location-2'),
  228. )
  229. rack_roles = (
  230. RackRole(name='Rack Role 1', slug='rack-role-1', color='ff0000'),
  231. RackRole(name='Rack Role 2', slug='rack-role-2', color='00ff00'),
  232. )
  233. RackRole.objects.bulk_create(rack_roles)
  234. racks = (
  235. Rack(site=sites[0], location=locations[0], role=rack_roles[0], name='Rack 1'),
  236. Rack(site=sites[0], location=locations[0], role=rack_roles[0], name='Rack 2'),
  237. Rack(site=sites[0], location=locations[0], role=rack_roles[0], name='Rack 3'),
  238. )
  239. Rack.objects.bulk_create(racks)
  240. cls.create_data = [
  241. {
  242. 'name': 'Test Rack 4',
  243. 'site': sites[1].pk,
  244. 'location': locations[1].pk,
  245. 'role': rack_roles[1].pk,
  246. },
  247. {
  248. 'name': 'Test Rack 5',
  249. 'site': sites[1].pk,
  250. 'location': locations[1].pk,
  251. 'role': rack_roles[1].pk,
  252. },
  253. {
  254. 'name': 'Test Rack 6',
  255. 'site': sites[1].pk,
  256. 'location': locations[1].pk,
  257. 'role': rack_roles[1].pk,
  258. },
  259. ]
  260. def test_get_rack_elevation(self):
  261. """
  262. GET a single rack elevation.
  263. """
  264. rack = Rack.objects.first()
  265. self.add_permissions('dcim.view_rack')
  266. url = reverse('dcim-api:rack-elevation', kwargs={'pk': rack.pk})
  267. # Retrieve all units
  268. response = self.client.get(url, **self.header)
  269. self.assertEqual(response.data['count'], 42)
  270. # Search for specific units
  271. response = self.client.get(f'{url}?q=3', **self.header)
  272. self.assertEqual(response.data['count'], 13)
  273. response = self.client.get(f'{url}?q=U3', **self.header)
  274. self.assertEqual(response.data['count'], 11)
  275. response = self.client.get(f'{url}?q=U10', **self.header)
  276. self.assertEqual(response.data['count'], 1)
  277. def test_get_rack_elevation_svg(self):
  278. """
  279. GET a single rack elevation in SVG format.
  280. """
  281. rack = Rack.objects.first()
  282. self.add_permissions('dcim.view_rack')
  283. url = '{}?render=svg'.format(reverse('dcim-api:rack-elevation', kwargs={'pk': rack.pk}))
  284. response = self.client.get(url, **self.header)
  285. self.assertHttpStatus(response, status.HTTP_200_OK)
  286. self.assertEqual(response.get('Content-Type'), 'image/svg+xml')
  287. class RackReservationTest(APIViewTestCases.APIViewTestCase):
  288. model = RackReservation
  289. brief_fields = ['display', 'id', 'units', 'url', 'user']
  290. bulk_update_data = {
  291. 'description': 'New description',
  292. }
  293. @classmethod
  294. def setUpTestData(cls):
  295. user = User.objects.create(username='user1', is_active=True)
  296. site = Site.objects.create(name='Test Site 1', slug='test-site-1')
  297. cls.racks = (
  298. Rack(site=site, name='Rack 1'),
  299. Rack(site=site, name='Rack 2'),
  300. )
  301. Rack.objects.bulk_create(cls.racks)
  302. rack_reservations = (
  303. RackReservation(rack=cls.racks[0], units=[1, 2, 3], user=user, description='Reservation #1'),
  304. RackReservation(rack=cls.racks[0], units=[4, 5, 6], user=user, description='Reservation #2'),
  305. RackReservation(rack=cls.racks[0], units=[7, 8, 9], user=user, description='Reservation #3'),
  306. )
  307. RackReservation.objects.bulk_create(rack_reservations)
  308. def setUp(self):
  309. super().setUp()
  310. # We have to set creation data under setUp() because we need access to the test user.
  311. self.create_data = [
  312. {
  313. 'rack': self.racks[1].pk,
  314. 'units': [10, 11, 12],
  315. 'user': self.user.pk,
  316. 'description': 'Reservation #4',
  317. },
  318. {
  319. 'rack': self.racks[1].pk,
  320. 'units': [13, 14, 15],
  321. 'user': self.user.pk,
  322. 'description': 'Reservation #5',
  323. },
  324. {
  325. 'rack': self.racks[1].pk,
  326. 'units': [16, 17, 18],
  327. 'user': self.user.pk,
  328. 'description': 'Reservation #6',
  329. },
  330. ]
  331. class ManufacturerTest(APIViewTestCases.APIViewTestCase):
  332. model = Manufacturer
  333. brief_fields = ['devicetype_count', 'display', 'id', 'name', 'slug', 'url']
  334. create_data = [
  335. {
  336. 'name': 'Manufacturer 4',
  337. 'slug': 'manufacturer-4',
  338. },
  339. {
  340. 'name': 'Manufacturer 5',
  341. 'slug': 'manufacturer-5',
  342. },
  343. {
  344. 'name': 'Manufacturer 6',
  345. 'slug': 'manufacturer-6',
  346. },
  347. ]
  348. bulk_update_data = {
  349. 'description': 'New description',
  350. }
  351. @classmethod
  352. def setUpTestData(cls):
  353. manufacturers = (
  354. Manufacturer(name='Manufacturer 1', slug='manufacturer-1'),
  355. Manufacturer(name='Manufacturer 2', slug='manufacturer-2'),
  356. Manufacturer(name='Manufacturer 3', slug='manufacturer-3'),
  357. )
  358. Manufacturer.objects.bulk_create(manufacturers)
  359. class DeviceTypeTest(APIViewTestCases.APIViewTestCase):
  360. model = DeviceType
  361. brief_fields = ['device_count', 'display', 'id', 'manufacturer', 'model', 'slug', 'url']
  362. bulk_update_data = {
  363. 'part_number': 'ABC123',
  364. }
  365. @classmethod
  366. def setUpTestData(cls):
  367. manufacturers = (
  368. Manufacturer(name='Manufacturer 1', slug='manufacturer-1'),
  369. Manufacturer(name='Manufacturer 2', slug='manufacturer-2'),
  370. )
  371. Manufacturer.objects.bulk_create(manufacturers)
  372. device_types = (
  373. DeviceType(manufacturer=manufacturers[0], model='Device Type 1', slug='device-type-1'),
  374. DeviceType(manufacturer=manufacturers[0], model='Device Type 2', slug='device-type-2'),
  375. DeviceType(manufacturer=manufacturers[0], model='Device Type 3', slug='device-type-3'),
  376. )
  377. DeviceType.objects.bulk_create(device_types)
  378. cls.create_data = [
  379. {
  380. 'manufacturer': manufacturers[1].pk,
  381. 'model': 'Device Type 4',
  382. 'slug': 'device-type-4',
  383. },
  384. {
  385. 'manufacturer': manufacturers[1].pk,
  386. 'model': 'Device Type 5',
  387. 'slug': 'device-type-5',
  388. },
  389. {
  390. 'manufacturer': manufacturers[1].pk,
  391. 'model': 'Device Type 6',
  392. 'slug': 'device-type-6',
  393. },
  394. ]
  395. class ConsolePortTemplateTest(APIViewTestCases.APIViewTestCase):
  396. model = ConsolePortTemplate
  397. brief_fields = ['display', 'id', 'name', 'url']
  398. bulk_update_data = {
  399. 'description': 'New description',
  400. }
  401. @classmethod
  402. def setUpTestData(cls):
  403. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  404. devicetype = DeviceType.objects.create(
  405. manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'
  406. )
  407. console_port_templates = (
  408. ConsolePortTemplate(device_type=devicetype, name='Console Port Template 1'),
  409. ConsolePortTemplate(device_type=devicetype, name='Console Port Template 2'),
  410. ConsolePortTemplate(device_type=devicetype, name='Console Port Template 3'),
  411. )
  412. ConsolePortTemplate.objects.bulk_create(console_port_templates)
  413. cls.create_data = [
  414. {
  415. 'device_type': devicetype.pk,
  416. 'name': 'Console Port Template 4',
  417. },
  418. {
  419. 'device_type': devicetype.pk,
  420. 'name': 'Console Port Template 5',
  421. },
  422. {
  423. 'device_type': devicetype.pk,
  424. 'name': 'Console Port Template 6',
  425. },
  426. ]
  427. class ConsoleServerPortTemplateTest(APIViewTestCases.APIViewTestCase):
  428. model = ConsoleServerPortTemplate
  429. brief_fields = ['display', 'id', 'name', 'url']
  430. bulk_update_data = {
  431. 'description': 'New description',
  432. }
  433. @classmethod
  434. def setUpTestData(cls):
  435. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  436. devicetype = DeviceType.objects.create(
  437. manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'
  438. )
  439. console_server_port_templates = (
  440. ConsoleServerPortTemplate(device_type=devicetype, name='Console Server Port Template 1'),
  441. ConsoleServerPortTemplate(device_type=devicetype, name='Console Server Port Template 2'),
  442. ConsoleServerPortTemplate(device_type=devicetype, name='Console Server Port Template 3'),
  443. )
  444. ConsoleServerPortTemplate.objects.bulk_create(console_server_port_templates)
  445. cls.create_data = [
  446. {
  447. 'device_type': devicetype.pk,
  448. 'name': 'Console Server Port Template 4',
  449. },
  450. {
  451. 'device_type': devicetype.pk,
  452. 'name': 'Console Server Port Template 5',
  453. },
  454. {
  455. 'device_type': devicetype.pk,
  456. 'name': 'Console Server Port Template 6',
  457. },
  458. ]
  459. class PowerPortTemplateTest(APIViewTestCases.APIViewTestCase):
  460. model = PowerPortTemplate
  461. brief_fields = ['display', 'id', 'name', 'url']
  462. bulk_update_data = {
  463. 'description': 'New description',
  464. }
  465. @classmethod
  466. def setUpTestData(cls):
  467. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  468. devicetype = DeviceType.objects.create(
  469. manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'
  470. )
  471. power_port_templates = (
  472. PowerPortTemplate(device_type=devicetype, name='Power Port Template 1'),
  473. PowerPortTemplate(device_type=devicetype, name='Power Port Template 2'),
  474. PowerPortTemplate(device_type=devicetype, name='Power Port Template 3'),
  475. )
  476. PowerPortTemplate.objects.bulk_create(power_port_templates)
  477. cls.create_data = [
  478. {
  479. 'device_type': devicetype.pk,
  480. 'name': 'Power Port Template 4',
  481. },
  482. {
  483. 'device_type': devicetype.pk,
  484. 'name': 'Power Port Template 5',
  485. },
  486. {
  487. 'device_type': devicetype.pk,
  488. 'name': 'Power Port Template 6',
  489. },
  490. ]
  491. class PowerOutletTemplateTest(APIViewTestCases.APIViewTestCase):
  492. model = PowerOutletTemplate
  493. brief_fields = ['display', 'id', 'name', 'url']
  494. bulk_update_data = {
  495. 'description': 'New description',
  496. }
  497. @classmethod
  498. def setUpTestData(cls):
  499. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  500. devicetype = DeviceType.objects.create(
  501. manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'
  502. )
  503. power_outlet_templates = (
  504. PowerOutletTemplate(device_type=devicetype, name='Power Outlet Template 1'),
  505. PowerOutletTemplate(device_type=devicetype, name='Power Outlet Template 2'),
  506. PowerOutletTemplate(device_type=devicetype, name='Power Outlet Template 3'),
  507. )
  508. PowerOutletTemplate.objects.bulk_create(power_outlet_templates)
  509. cls.create_data = [
  510. {
  511. 'device_type': devicetype.pk,
  512. 'name': 'Power Outlet Template 4',
  513. },
  514. {
  515. 'device_type': devicetype.pk,
  516. 'name': 'Power Outlet Template 5',
  517. },
  518. {
  519. 'device_type': devicetype.pk,
  520. 'name': 'Power Outlet Template 6',
  521. },
  522. ]
  523. class InterfaceTemplateTest(APIViewTestCases.APIViewTestCase):
  524. model = InterfaceTemplate
  525. brief_fields = ['display', 'id', 'name', 'url']
  526. bulk_update_data = {
  527. 'description': 'New description',
  528. }
  529. @classmethod
  530. def setUpTestData(cls):
  531. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  532. devicetype = DeviceType.objects.create(
  533. manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'
  534. )
  535. interface_templates = (
  536. InterfaceTemplate(device_type=devicetype, name='Interface Template 1', type='1000base-t'),
  537. InterfaceTemplate(device_type=devicetype, name='Interface Template 2', type='1000base-t'),
  538. InterfaceTemplate(device_type=devicetype, name='Interface Template 3', type='1000base-t'),
  539. )
  540. InterfaceTemplate.objects.bulk_create(interface_templates)
  541. cls.create_data = [
  542. {
  543. 'device_type': devicetype.pk,
  544. 'name': 'Interface Template 4',
  545. 'type': '1000base-t',
  546. },
  547. {
  548. 'device_type': devicetype.pk,
  549. 'name': 'Interface Template 5',
  550. 'type': '1000base-t',
  551. },
  552. {
  553. 'device_type': devicetype.pk,
  554. 'name': 'Interface Template 6',
  555. 'type': '1000base-t',
  556. },
  557. ]
  558. class FrontPortTemplateTest(APIViewTestCases.APIViewTestCase):
  559. model = FrontPortTemplate
  560. brief_fields = ['display', 'id', 'name', 'url']
  561. bulk_update_data = {
  562. 'description': 'New description',
  563. }
  564. @classmethod
  565. def setUpTestData(cls):
  566. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  567. devicetype = DeviceType.objects.create(
  568. manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'
  569. )
  570. rear_port_templates = (
  571. RearPortTemplate(device_type=devicetype, name='Rear Port Template 1', type=PortTypeChoices.TYPE_8P8C),
  572. RearPortTemplate(device_type=devicetype, name='Rear Port Template 2', type=PortTypeChoices.TYPE_8P8C),
  573. RearPortTemplate(device_type=devicetype, name='Rear Port Template 3', type=PortTypeChoices.TYPE_8P8C),
  574. RearPortTemplate(device_type=devicetype, name='Rear Port Template 4', type=PortTypeChoices.TYPE_8P8C),
  575. RearPortTemplate(device_type=devicetype, name='Rear Port Template 5', type=PortTypeChoices.TYPE_8P8C),
  576. RearPortTemplate(device_type=devicetype, name='Rear Port Template 6', type=PortTypeChoices.TYPE_8P8C),
  577. )
  578. RearPortTemplate.objects.bulk_create(rear_port_templates)
  579. front_port_templates = (
  580. FrontPortTemplate(
  581. device_type=devicetype,
  582. name='Front Port Template 1',
  583. type=PortTypeChoices.TYPE_8P8C,
  584. rear_port=rear_port_templates[0]
  585. ),
  586. FrontPortTemplate(
  587. device_type=devicetype,
  588. name='Front Port Template 2',
  589. type=PortTypeChoices.TYPE_8P8C,
  590. rear_port=rear_port_templates[1]
  591. ),
  592. FrontPortTemplate(
  593. device_type=devicetype,
  594. name='Front Port Template 3',
  595. type=PortTypeChoices.TYPE_8P8C,
  596. rear_port=rear_port_templates[2]
  597. ),
  598. )
  599. FrontPortTemplate.objects.bulk_create(front_port_templates)
  600. cls.create_data = [
  601. {
  602. 'device_type': devicetype.pk,
  603. 'name': 'Front Port Template 4',
  604. 'type': PortTypeChoices.TYPE_8P8C,
  605. 'rear_port': rear_port_templates[3].pk,
  606. 'rear_port_position': 1,
  607. },
  608. {
  609. 'device_type': devicetype.pk,
  610. 'name': 'Front Port Template 5',
  611. 'type': PortTypeChoices.TYPE_8P8C,
  612. 'rear_port': rear_port_templates[4].pk,
  613. 'rear_port_position': 1,
  614. },
  615. {
  616. 'device_type': devicetype.pk,
  617. 'name': 'Front Port Template 6',
  618. 'type': PortTypeChoices.TYPE_8P8C,
  619. 'rear_port': rear_port_templates[5].pk,
  620. 'rear_port_position': 1,
  621. },
  622. ]
  623. class RearPortTemplateTest(APIViewTestCases.APIViewTestCase):
  624. model = RearPortTemplate
  625. brief_fields = ['display', 'id', 'name', 'url']
  626. bulk_update_data = {
  627. 'description': 'New description',
  628. }
  629. @classmethod
  630. def setUpTestData(cls):
  631. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  632. devicetype = DeviceType.objects.create(
  633. manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'
  634. )
  635. rear_port_templates = (
  636. RearPortTemplate(device_type=devicetype, name='Rear Port Template 1', type=PortTypeChoices.TYPE_8P8C),
  637. RearPortTemplate(device_type=devicetype, name='Rear Port Template 2', type=PortTypeChoices.TYPE_8P8C),
  638. RearPortTemplate(device_type=devicetype, name='Rear Port Template 3', type=PortTypeChoices.TYPE_8P8C),
  639. )
  640. RearPortTemplate.objects.bulk_create(rear_port_templates)
  641. cls.create_data = [
  642. {
  643. 'device_type': devicetype.pk,
  644. 'name': 'Rear Port Template 4',
  645. 'type': PortTypeChoices.TYPE_8P8C,
  646. },
  647. {
  648. 'device_type': devicetype.pk,
  649. 'name': 'Rear Port Template 5',
  650. 'type': PortTypeChoices.TYPE_8P8C,
  651. },
  652. {
  653. 'device_type': devicetype.pk,
  654. 'name': 'Rear Port Template 6',
  655. 'type': PortTypeChoices.TYPE_8P8C,
  656. },
  657. ]
  658. class DeviceBayTemplateTest(APIViewTestCases.APIViewTestCase):
  659. model = DeviceBayTemplate
  660. brief_fields = ['display', 'id', 'name', 'url']
  661. bulk_update_data = {
  662. 'description': 'New description',
  663. }
  664. @classmethod
  665. def setUpTestData(cls):
  666. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  667. devicetype = DeviceType.objects.create(
  668. manufacturer=manufacturer,
  669. model='Device Type 1',
  670. slug='device-type-1',
  671. subdevice_role=SubdeviceRoleChoices.ROLE_PARENT
  672. )
  673. device_bay_templates = (
  674. DeviceBayTemplate(device_type=devicetype, name='Device Bay Template 1'),
  675. DeviceBayTemplate(device_type=devicetype, name='Device Bay Template 2'),
  676. DeviceBayTemplate(device_type=devicetype, name='Device Bay Template 3'),
  677. )
  678. DeviceBayTemplate.objects.bulk_create(device_bay_templates)
  679. cls.create_data = [
  680. {
  681. 'device_type': devicetype.pk,
  682. 'name': 'Device Bay Template 4',
  683. },
  684. {
  685. 'device_type': devicetype.pk,
  686. 'name': 'Device Bay Template 5',
  687. },
  688. {
  689. 'device_type': devicetype.pk,
  690. 'name': 'Device Bay Template 6',
  691. },
  692. ]
  693. class DeviceRoleTest(APIViewTestCases.APIViewTestCase):
  694. model = DeviceRole
  695. brief_fields = ['device_count', 'display', 'id', 'name', 'slug', 'url', 'virtualmachine_count']
  696. create_data = [
  697. {
  698. 'name': 'Device Role 4',
  699. 'slug': 'device-role-4',
  700. 'color': 'ffff00',
  701. },
  702. {
  703. 'name': 'Device Role 5',
  704. 'slug': 'device-role-5',
  705. 'color': 'ffff00',
  706. },
  707. {
  708. 'name': 'Device Role 6',
  709. 'slug': 'device-role-6',
  710. 'color': 'ffff00',
  711. },
  712. ]
  713. bulk_update_data = {
  714. 'description': 'New description',
  715. }
  716. @classmethod
  717. def setUpTestData(cls):
  718. device_roles = (
  719. DeviceRole(name='Device Role 1', slug='device-role-1', color='ff0000'),
  720. DeviceRole(name='Device Role 2', slug='device-role-2', color='00ff00'),
  721. DeviceRole(name='Device Role 3', slug='device-role-3', color='0000ff'),
  722. )
  723. DeviceRole.objects.bulk_create(device_roles)
  724. class PlatformTest(APIViewTestCases.APIViewTestCase):
  725. model = Platform
  726. brief_fields = ['device_count', 'display', 'id', 'name', 'slug', 'url', 'virtualmachine_count']
  727. create_data = [
  728. {
  729. 'name': 'Platform 4',
  730. 'slug': 'platform-4',
  731. },
  732. {
  733. 'name': 'Platform 5',
  734. 'slug': 'platform-5',
  735. },
  736. {
  737. 'name': 'Platform 6',
  738. 'slug': 'platform-6',
  739. },
  740. ]
  741. bulk_update_data = {
  742. 'description': 'New description',
  743. }
  744. @classmethod
  745. def setUpTestData(cls):
  746. platforms = (
  747. Platform(name='Platform 1', slug='platform-1'),
  748. Platform(name='Platform 2', slug='platform-2'),
  749. Platform(name='Platform 3', slug='platform-3'),
  750. )
  751. Platform.objects.bulk_create(platforms)
  752. class DeviceTest(APIViewTestCases.APIViewTestCase):
  753. model = Device
  754. brief_fields = ['display', 'id', 'name', 'url']
  755. bulk_update_data = {
  756. 'status': 'failed',
  757. }
  758. @classmethod
  759. def setUpTestData(cls):
  760. sites = (
  761. Site(name='Site 1', slug='site-1'),
  762. Site(name='Site 2', slug='site-2'),
  763. )
  764. Site.objects.bulk_create(sites)
  765. racks = (
  766. Rack(name='Rack 1', site=sites[0]),
  767. Rack(name='Rack 2', site=sites[1]),
  768. )
  769. Rack.objects.bulk_create(racks)
  770. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  771. device_types = (
  772. DeviceType(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'),
  773. DeviceType(manufacturer=manufacturer, model='Device Type 2', slug='device-type-2'),
  774. )
  775. DeviceType.objects.bulk_create(device_types)
  776. device_roles = (
  777. DeviceRole(name='Device Role 1', slug='device-role-1', color='ff0000'),
  778. DeviceRole(name='Device Role 2', slug='device-role-2', color='00ff00'),
  779. )
  780. DeviceRole.objects.bulk_create(device_roles)
  781. cluster_type = ClusterType.objects.create(name='Cluster Type 1', slug='cluster-type-1')
  782. clusters = (
  783. Cluster(name='Cluster 1', type=cluster_type),
  784. Cluster(name='Cluster 2', type=cluster_type),
  785. )
  786. Cluster.objects.bulk_create(clusters)
  787. devices = (
  788. Device(
  789. device_type=device_types[0],
  790. device_role=device_roles[0],
  791. name='Device 1',
  792. site=sites[0],
  793. rack=racks[0],
  794. cluster=clusters[0],
  795. local_context_data={'A': 1}
  796. ),
  797. Device(
  798. device_type=device_types[0],
  799. device_role=device_roles[0],
  800. name='Device 2',
  801. site=sites[0],
  802. rack=racks[0],
  803. cluster=clusters[0],
  804. local_context_data={'B': 2}
  805. ),
  806. Device(
  807. device_type=device_types[0],
  808. device_role=device_roles[0],
  809. name='Device 3',
  810. site=sites[0],
  811. rack=racks[0],
  812. cluster=clusters[0],
  813. local_context_data={'C': 3}
  814. ),
  815. )
  816. Device.objects.bulk_create(devices)
  817. cls.create_data = [
  818. {
  819. 'device_type': device_types[1].pk,
  820. 'device_role': device_roles[1].pk,
  821. 'name': 'Test Device 4',
  822. 'site': sites[1].pk,
  823. 'rack': racks[1].pk,
  824. 'cluster': clusters[1].pk,
  825. },
  826. {
  827. 'device_type': device_types[1].pk,
  828. 'device_role': device_roles[1].pk,
  829. 'name': 'Test Device 5',
  830. 'site': sites[1].pk,
  831. 'rack': racks[1].pk,
  832. 'cluster': clusters[1].pk,
  833. },
  834. {
  835. 'device_type': device_types[1].pk,
  836. 'device_role': device_roles[1].pk,
  837. 'name': 'Test Device 6',
  838. 'site': sites[1].pk,
  839. 'rack': racks[1].pk,
  840. 'cluster': clusters[1].pk,
  841. },
  842. ]
  843. def test_config_context_included_by_default_in_list_view(self):
  844. """
  845. Check that config context data is included by default in the devices list.
  846. """
  847. self.add_permissions('dcim.view_device')
  848. url = reverse('dcim-api:device-list') + '?slug=device-with-context-data'
  849. response = self.client.get(url, **self.header)
  850. self.assertEqual(response.data['results'][0].get('config_context', {}).get('A'), 1)
  851. def test_config_context_excluded(self):
  852. """
  853. Check that config context data can be excluded by passing ?exclude=config_context.
  854. """
  855. self.add_permissions('dcim.view_device')
  856. url = reverse('dcim-api:device-list') + '?exclude=config_context'
  857. response = self.client.get(url, **self.header)
  858. self.assertFalse('config_context' in response.data['results'][0])
  859. def test_unique_name_per_site_constraint(self):
  860. """
  861. Check that creating a device with a duplicate name within a site fails.
  862. """
  863. device = Device.objects.first()
  864. data = {
  865. 'device_type': device.device_type.pk,
  866. 'device_role': device.device_role.pk,
  867. 'site': device.site.pk,
  868. 'name': device.name,
  869. }
  870. self.add_permissions('dcim.add_device')
  871. url = reverse('dcim-api:device-list')
  872. response = self.client.post(url, data, format='json', **self.header)
  873. self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
  874. class ConsolePortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase):
  875. model = ConsolePort
  876. brief_fields = ['_occupied', 'cable', 'device', 'display', 'id', 'name', 'url']
  877. bulk_update_data = {
  878. 'description': 'New description',
  879. }
  880. peer_termination_type = ConsoleServerPort
  881. @classmethod
  882. def setUpTestData(cls):
  883. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  884. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  885. site = Site.objects.create(name='Site 1', slug='site-1')
  886. devicerole = DeviceRole.objects.create(name='Test Device Role 1', slug='test-device-role-1', color='ff0000')
  887. device = Device.objects.create(device_type=devicetype, device_role=devicerole, name='Device 1', site=site)
  888. console_ports = (
  889. ConsolePort(device=device, name='Console Port 1'),
  890. ConsolePort(device=device, name='Console Port 2'),
  891. ConsolePort(device=device, name='Console Port 3'),
  892. )
  893. ConsolePort.objects.bulk_create(console_ports)
  894. cls.create_data = [
  895. {
  896. 'device': device.pk,
  897. 'name': 'Console Port 4',
  898. },
  899. {
  900. 'device': device.pk,
  901. 'name': 'Console Port 5',
  902. },
  903. {
  904. 'device': device.pk,
  905. 'name': 'Console Port 6',
  906. },
  907. ]
  908. class ConsoleServerPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase):
  909. model = ConsoleServerPort
  910. brief_fields = ['_occupied', 'cable', 'device', 'display', 'id', 'name', 'url']
  911. bulk_update_data = {
  912. 'description': 'New description',
  913. }
  914. peer_termination_type = ConsolePort
  915. @classmethod
  916. def setUpTestData(cls):
  917. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  918. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  919. site = Site.objects.create(name='Site 1', slug='site-1')
  920. devicerole = DeviceRole.objects.create(name='Test Device Role 1', slug='test-device-role-1', color='ff0000')
  921. device = Device.objects.create(device_type=devicetype, device_role=devicerole, name='Device 1', site=site)
  922. console_server_ports = (
  923. ConsoleServerPort(device=device, name='Console Server Port 1'),
  924. ConsoleServerPort(device=device, name='Console Server Port 2'),
  925. ConsoleServerPort(device=device, name='Console Server Port 3'),
  926. )
  927. ConsoleServerPort.objects.bulk_create(console_server_ports)
  928. cls.create_data = [
  929. {
  930. 'device': device.pk,
  931. 'name': 'Console Server Port 4',
  932. },
  933. {
  934. 'device': device.pk,
  935. 'name': 'Console Server Port 5',
  936. },
  937. {
  938. 'device': device.pk,
  939. 'name': 'Console Server Port 6',
  940. },
  941. ]
  942. class PowerPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase):
  943. model = PowerPort
  944. brief_fields = ['_occupied', 'cable', 'device', 'display', 'id', 'name', 'url']
  945. bulk_update_data = {
  946. 'description': 'New description',
  947. }
  948. peer_termination_type = PowerOutlet
  949. @classmethod
  950. def setUpTestData(cls):
  951. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  952. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  953. site = Site.objects.create(name='Site 1', slug='site-1')
  954. devicerole = DeviceRole.objects.create(name='Test Device Role 1', slug='test-device-role-1', color='ff0000')
  955. device = Device.objects.create(device_type=devicetype, device_role=devicerole, name='Device 1', site=site)
  956. power_ports = (
  957. PowerPort(device=device, name='Power Port 1'),
  958. PowerPort(device=device, name='Power Port 2'),
  959. PowerPort(device=device, name='Power Port 3'),
  960. )
  961. PowerPort.objects.bulk_create(power_ports)
  962. cls.create_data = [
  963. {
  964. 'device': device.pk,
  965. 'name': 'Power Port 4',
  966. },
  967. {
  968. 'device': device.pk,
  969. 'name': 'Power Port 5',
  970. },
  971. {
  972. 'device': device.pk,
  973. 'name': 'Power Port 6',
  974. },
  975. ]
  976. class PowerOutletTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase):
  977. model = PowerOutlet
  978. brief_fields = ['_occupied', 'cable', 'device', 'display', 'id', 'name', 'url']
  979. bulk_update_data = {
  980. 'description': 'New description',
  981. }
  982. peer_termination_type = PowerPort
  983. @classmethod
  984. def setUpTestData(cls):
  985. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  986. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  987. site = Site.objects.create(name='Site 1', slug='site-1')
  988. devicerole = DeviceRole.objects.create(name='Test Device Role 1', slug='test-device-role-1', color='ff0000')
  989. device = Device.objects.create(device_type=devicetype, device_role=devicerole, name='Device 1', site=site)
  990. power_outlets = (
  991. PowerOutlet(device=device, name='Power Outlet 1'),
  992. PowerOutlet(device=device, name='Power Outlet 2'),
  993. PowerOutlet(device=device, name='Power Outlet 3'),
  994. )
  995. PowerOutlet.objects.bulk_create(power_outlets)
  996. cls.create_data = [
  997. {
  998. 'device': device.pk,
  999. 'name': 'Power Outlet 4',
  1000. },
  1001. {
  1002. 'device': device.pk,
  1003. 'name': 'Power Outlet 5',
  1004. },
  1005. {
  1006. 'device': device.pk,
  1007. 'name': 'Power Outlet 6',
  1008. },
  1009. ]
  1010. class InterfaceTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase):
  1011. model = Interface
  1012. brief_fields = ['_occupied', 'cable', 'device', 'display', 'id', 'name', 'url']
  1013. bulk_update_data = {
  1014. 'description': 'New description',
  1015. }
  1016. peer_termination_type = Interface
  1017. @classmethod
  1018. def setUpTestData(cls):
  1019. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  1020. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  1021. site = Site.objects.create(name='Site 1', slug='site-1')
  1022. devicerole = DeviceRole.objects.create(name='Test Device Role 1', slug='test-device-role-1', color='ff0000')
  1023. device = Device.objects.create(device_type=devicetype, device_role=devicerole, name='Device 1', site=site)
  1024. interfaces = (
  1025. Interface(device=device, name='Interface 1', type='1000base-t'),
  1026. Interface(device=device, name='Interface 2', type='1000base-t'),
  1027. Interface(device=device, name='Interface 3', type='1000base-t'),
  1028. )
  1029. Interface.objects.bulk_create(interfaces)
  1030. vlans = (
  1031. VLAN(name='VLAN 1', vid=1),
  1032. VLAN(name='VLAN 2', vid=2),
  1033. VLAN(name='VLAN 3', vid=3),
  1034. )
  1035. VLAN.objects.bulk_create(vlans)
  1036. cls.create_data = [
  1037. {
  1038. 'device': device.pk,
  1039. 'name': 'Interface 4',
  1040. 'type': '1000base-t',
  1041. 'mode': InterfaceModeChoices.MODE_TAGGED,
  1042. 'tagged_vlans': [vlans[0].pk, vlans[1].pk],
  1043. 'untagged_vlan': vlans[2].pk,
  1044. },
  1045. {
  1046. 'device': device.pk,
  1047. 'name': 'Interface 5',
  1048. 'type': '1000base-t',
  1049. 'mode': InterfaceModeChoices.MODE_TAGGED,
  1050. 'tagged_vlans': [vlans[0].pk, vlans[1].pk],
  1051. 'untagged_vlan': vlans[2].pk,
  1052. },
  1053. {
  1054. 'device': device.pk,
  1055. 'name': 'Interface 6',
  1056. 'type': '1000base-t',
  1057. 'mode': InterfaceModeChoices.MODE_TAGGED,
  1058. 'tagged_vlans': [vlans[0].pk, vlans[1].pk],
  1059. 'untagged_vlan': vlans[2].pk,
  1060. },
  1061. ]
  1062. class FrontPortTest(APIViewTestCases.APIViewTestCase):
  1063. model = FrontPort
  1064. brief_fields = ['_occupied', 'cable', 'device', 'display', 'id', 'name', 'url']
  1065. bulk_update_data = {
  1066. 'description': 'New description',
  1067. }
  1068. peer_termination_type = Interface
  1069. @classmethod
  1070. def setUpTestData(cls):
  1071. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  1072. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  1073. site = Site.objects.create(name='Site 1', slug='site-1')
  1074. devicerole = DeviceRole.objects.create(name='Test Device Role 1', slug='test-device-role-1', color='ff0000')
  1075. device = Device.objects.create(device_type=devicetype, device_role=devicerole, name='Device 1', site=site)
  1076. rear_ports = (
  1077. RearPort(device=device, name='Rear Port 1', type=PortTypeChoices.TYPE_8P8C),
  1078. RearPort(device=device, name='Rear Port 2', type=PortTypeChoices.TYPE_8P8C),
  1079. RearPort(device=device, name='Rear Port 3', type=PortTypeChoices.TYPE_8P8C),
  1080. RearPort(device=device, name='Rear Port 4', type=PortTypeChoices.TYPE_8P8C),
  1081. RearPort(device=device, name='Rear Port 5', type=PortTypeChoices.TYPE_8P8C),
  1082. RearPort(device=device, name='Rear Port 6', type=PortTypeChoices.TYPE_8P8C),
  1083. )
  1084. RearPort.objects.bulk_create(rear_ports)
  1085. front_ports = (
  1086. FrontPort(device=device, name='Front Port 1', type=PortTypeChoices.TYPE_8P8C, rear_port=rear_ports[0]),
  1087. FrontPort(device=device, name='Front Port 2', type=PortTypeChoices.TYPE_8P8C, rear_port=rear_ports[1]),
  1088. FrontPort(device=device, name='Front Port 3', type=PortTypeChoices.TYPE_8P8C, rear_port=rear_ports[2]),
  1089. )
  1090. FrontPort.objects.bulk_create(front_ports)
  1091. cls.create_data = [
  1092. {
  1093. 'device': device.pk,
  1094. 'name': 'Front Port 4',
  1095. 'type': PortTypeChoices.TYPE_8P8C,
  1096. 'rear_port': rear_ports[3].pk,
  1097. 'rear_port_position': 1,
  1098. },
  1099. {
  1100. 'device': device.pk,
  1101. 'name': 'Front Port 5',
  1102. 'type': PortTypeChoices.TYPE_8P8C,
  1103. 'rear_port': rear_ports[4].pk,
  1104. 'rear_port_position': 1,
  1105. },
  1106. {
  1107. 'device': device.pk,
  1108. 'name': 'Front Port 6',
  1109. 'type': PortTypeChoices.TYPE_8P8C,
  1110. 'rear_port': rear_ports[5].pk,
  1111. 'rear_port_position': 1,
  1112. },
  1113. ]
  1114. class RearPortTest(APIViewTestCases.APIViewTestCase):
  1115. model = RearPort
  1116. brief_fields = ['_occupied', 'cable', 'device', 'display', 'id', 'name', 'url']
  1117. bulk_update_data = {
  1118. 'description': 'New description',
  1119. }
  1120. peer_termination_type = Interface
  1121. @classmethod
  1122. def setUpTestData(cls):
  1123. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  1124. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  1125. site = Site.objects.create(name='Site 1', slug='site-1')
  1126. devicerole = DeviceRole.objects.create(name='Test Device Role 1', slug='test-device-role-1', color='ff0000')
  1127. device = Device.objects.create(device_type=devicetype, device_role=devicerole, name='Device 1', site=site)
  1128. rear_ports = (
  1129. RearPort(device=device, name='Rear Port 1', type=PortTypeChoices.TYPE_8P8C),
  1130. RearPort(device=device, name='Rear Port 2', type=PortTypeChoices.TYPE_8P8C),
  1131. RearPort(device=device, name='Rear Port 3', type=PortTypeChoices.TYPE_8P8C),
  1132. )
  1133. RearPort.objects.bulk_create(rear_ports)
  1134. cls.create_data = [
  1135. {
  1136. 'device': device.pk,
  1137. 'name': 'Rear Port 4',
  1138. 'type': PortTypeChoices.TYPE_8P8C,
  1139. },
  1140. {
  1141. 'device': device.pk,
  1142. 'name': 'Rear Port 5',
  1143. 'type': PortTypeChoices.TYPE_8P8C,
  1144. },
  1145. {
  1146. 'device': device.pk,
  1147. 'name': 'Rear Port 6',
  1148. 'type': PortTypeChoices.TYPE_8P8C,
  1149. },
  1150. ]
  1151. class DeviceBayTest(APIViewTestCases.APIViewTestCase):
  1152. model = DeviceBay
  1153. brief_fields = ['device', 'display', 'id', 'name', 'url']
  1154. bulk_update_data = {
  1155. 'description': 'New description',
  1156. }
  1157. @classmethod
  1158. def setUpTestData(cls):
  1159. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  1160. site = Site.objects.create(name='Site 1', slug='site-1')
  1161. devicerole = DeviceRole.objects.create(name='Test Device Role 1', slug='test-device-role-1', color='ff0000')
  1162. device_types = (
  1163. DeviceType(
  1164. manufacturer=manufacturer,
  1165. model='Device Type 1',
  1166. slug='device-type-1',
  1167. subdevice_role=SubdeviceRoleChoices.ROLE_PARENT
  1168. ),
  1169. DeviceType(
  1170. manufacturer=manufacturer,
  1171. model='Device Type 2',
  1172. slug='device-type-2',
  1173. subdevice_role=SubdeviceRoleChoices.ROLE_CHILD
  1174. ),
  1175. )
  1176. DeviceType.objects.bulk_create(device_types)
  1177. devices = (
  1178. Device(device_type=device_types[0], device_role=devicerole, name='Device 1', site=site),
  1179. Device(device_type=device_types[1], device_role=devicerole, name='Device 2', site=site),
  1180. Device(device_type=device_types[1], device_role=devicerole, name='Device 3', site=site),
  1181. Device(device_type=device_types[1], device_role=devicerole, name='Device 4', site=site),
  1182. )
  1183. Device.objects.bulk_create(devices)
  1184. device_bays = (
  1185. DeviceBay(device=devices[0], name='Device Bay 1'),
  1186. DeviceBay(device=devices[0], name='Device Bay 2'),
  1187. DeviceBay(device=devices[0], name='Device Bay 3'),
  1188. )
  1189. DeviceBay.objects.bulk_create(device_bays)
  1190. cls.create_data = [
  1191. {
  1192. 'device': devices[0].pk,
  1193. 'name': 'Device Bay 4',
  1194. 'installed_device': devices[1].pk,
  1195. },
  1196. {
  1197. 'device': devices[0].pk,
  1198. 'name': 'Device Bay 5',
  1199. 'installed_device': devices[2].pk,
  1200. },
  1201. {
  1202. 'device': devices[0].pk,
  1203. 'name': 'Device Bay 6',
  1204. 'installed_device': devices[3].pk,
  1205. },
  1206. ]
  1207. class InventoryItemTest(APIViewTestCases.APIViewTestCase):
  1208. model = InventoryItem
  1209. brief_fields = ['_depth', 'device', 'display', 'id', 'name', 'url']
  1210. bulk_update_data = {
  1211. 'description': 'New description',
  1212. }
  1213. @classmethod
  1214. def setUpTestData(cls):
  1215. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  1216. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  1217. site = Site.objects.create(name='Site 1', slug='site-1')
  1218. devicerole = DeviceRole.objects.create(name='Test Device Role 1', slug='test-device-role-1', color='ff0000')
  1219. device = Device.objects.create(device_type=devicetype, device_role=devicerole, name='Device 1', site=site)
  1220. InventoryItem.objects.create(device=device, name='Inventory Item 1', manufacturer=manufacturer)
  1221. InventoryItem.objects.create(device=device, name='Inventory Item 2', manufacturer=manufacturer)
  1222. InventoryItem.objects.create(device=device, name='Inventory Item 3', manufacturer=manufacturer)
  1223. cls.create_data = [
  1224. {
  1225. 'device': device.pk,
  1226. 'name': 'Inventory Item 4',
  1227. 'manufacturer': manufacturer.pk,
  1228. },
  1229. {
  1230. 'device': device.pk,
  1231. 'name': 'Inventory Item 5',
  1232. 'manufacturer': manufacturer.pk,
  1233. },
  1234. {
  1235. 'device': device.pk,
  1236. 'name': 'Inventory Item 6',
  1237. 'manufacturer': manufacturer.pk,
  1238. },
  1239. ]
  1240. class CableTest(APIViewTestCases.APIViewTestCase):
  1241. model = Cable
  1242. brief_fields = ['display', 'id', 'label', 'url']
  1243. bulk_update_data = {
  1244. 'length': 100,
  1245. 'length_unit': 'm',
  1246. }
  1247. # TODO: Allow updating cable terminations
  1248. test_update_object = None
  1249. @classmethod
  1250. def setUpTestData(cls):
  1251. site = Site.objects.create(name='Site 1', slug='site-1')
  1252. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  1253. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  1254. devicerole = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1', color='ff0000')
  1255. devices = (
  1256. Device(device_type=devicetype, device_role=devicerole, name='Device 1', site=site),
  1257. Device(device_type=devicetype, device_role=devicerole, name='Device 2', site=site),
  1258. )
  1259. Device.objects.bulk_create(devices)
  1260. interfaces = []
  1261. for device in devices:
  1262. for i in range(0, 10):
  1263. interfaces.append(Interface(device=device, type=InterfaceTypeChoices.TYPE_1GE_FIXED, name=f'eth{i}'))
  1264. Interface.objects.bulk_create(interfaces)
  1265. cables = (
  1266. Cable(termination_a=interfaces[0], termination_b=interfaces[10], label='Cable 1'),
  1267. Cable(termination_a=interfaces[1], termination_b=interfaces[11], label='Cable 2'),
  1268. Cable(termination_a=interfaces[2], termination_b=interfaces[12], label='Cable 3'),
  1269. )
  1270. for cable in cables:
  1271. cable.save()
  1272. cls.create_data = [
  1273. {
  1274. 'termination_a_type': 'dcim.interface',
  1275. 'termination_a_id': interfaces[4].pk,
  1276. 'termination_b_type': 'dcim.interface',
  1277. 'termination_b_id': interfaces[14].pk,
  1278. 'label': 'Cable 4',
  1279. },
  1280. {
  1281. 'termination_a_type': 'dcim.interface',
  1282. 'termination_a_id': interfaces[5].pk,
  1283. 'termination_b_type': 'dcim.interface',
  1284. 'termination_b_id': interfaces[15].pk,
  1285. 'label': 'Cable 5',
  1286. },
  1287. {
  1288. 'termination_a_type': 'dcim.interface',
  1289. 'termination_a_id': interfaces[6].pk,
  1290. 'termination_b_type': 'dcim.interface',
  1291. 'termination_b_id': interfaces[16].pk,
  1292. 'label': 'Cable 6',
  1293. },
  1294. ]
  1295. class ConnectedDeviceTest(APITestCase):
  1296. def setUp(self):
  1297. super().setUp()
  1298. self.site1 = Site.objects.create(name='Test Site 1', slug='test-site-1')
  1299. self.site2 = Site.objects.create(name='Test Site 2', slug='test-site-2')
  1300. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  1301. self.devicetype1 = DeviceType.objects.create(
  1302. manufacturer=manufacturer, model='Test Device Type 1', slug='test-device-type-1'
  1303. )
  1304. self.devicetype2 = DeviceType.objects.create(
  1305. manufacturer=manufacturer, model='Test Device Type 2', slug='test-device-type-2'
  1306. )
  1307. self.devicerole1 = DeviceRole.objects.create(
  1308. name='Test Device Role 1', slug='test-device-role-1', color='ff0000'
  1309. )
  1310. self.devicerole2 = DeviceRole.objects.create(
  1311. name='Test Device Role 2', slug='test-device-role-2', color='00ff00'
  1312. )
  1313. self.device1 = Device.objects.create(
  1314. device_type=self.devicetype1, device_role=self.devicerole1, name='TestDevice1', site=self.site1
  1315. )
  1316. self.device2 = Device.objects.create(
  1317. device_type=self.devicetype1, device_role=self.devicerole1, name='TestDevice2', site=self.site1
  1318. )
  1319. self.interface1 = Interface.objects.create(device=self.device1, name='eth0')
  1320. self.interface2 = Interface.objects.create(device=self.device2, name='eth0')
  1321. cable = Cable(termination_a=self.interface1, termination_b=self.interface2)
  1322. cable.save()
  1323. def test_get_connected_device(self):
  1324. url = reverse('dcim-api:connected-device-list')
  1325. response = self.client.get(url + '?peer_device=TestDevice2&peer_interface=eth0', **self.header)
  1326. self.assertHttpStatus(response, status.HTTP_200_OK)
  1327. self.assertEqual(response.data['name'], self.device1.name)
  1328. class VirtualChassisTest(APIViewTestCases.APIViewTestCase):
  1329. model = VirtualChassis
  1330. brief_fields = ['id', 'master', 'member_count', 'name', 'url']
  1331. @classmethod
  1332. def setUpTestData(cls):
  1333. site = Site.objects.create(name='Test Site', slug='test-site')
  1334. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  1335. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type', slug='device-type')
  1336. devicerole = DeviceRole.objects.create(name='Device Role', slug='device-role', color='ff0000')
  1337. devices = (
  1338. Device(name='Device 1', device_type=devicetype, device_role=devicerole, site=site),
  1339. Device(name='Device 2', device_type=devicetype, device_role=devicerole, site=site),
  1340. Device(name='Device 3', device_type=devicetype, device_role=devicerole, site=site),
  1341. Device(name='Device 4', device_type=devicetype, device_role=devicerole, site=site),
  1342. Device(name='Device 5', device_type=devicetype, device_role=devicerole, site=site),
  1343. Device(name='Device 6', device_type=devicetype, device_role=devicerole, site=site),
  1344. Device(name='Device 7', device_type=devicetype, device_role=devicerole, site=site),
  1345. Device(name='Device 8', device_type=devicetype, device_role=devicerole, site=site),
  1346. Device(name='Device 9', device_type=devicetype, device_role=devicerole, site=site),
  1347. Device(name='Device 10', device_type=devicetype, device_role=devicerole, site=site),
  1348. Device(name='Device 11', device_type=devicetype, device_role=devicerole, site=site),
  1349. Device(name='Device 12', device_type=devicetype, device_role=devicerole, site=site),
  1350. )
  1351. Device.objects.bulk_create(devices)
  1352. # Create 12 interfaces per device
  1353. interfaces = []
  1354. for i, device in enumerate(devices):
  1355. for j in range(0, 13):
  1356. interfaces.append(
  1357. # Interface name starts with parent device's position in VC; e.g. 1/1, 1/2, 1/3...
  1358. Interface(device=device, name=f'{i%3+1}/{j}', type=InterfaceTypeChoices.TYPE_1GE_FIXED)
  1359. )
  1360. Interface.objects.bulk_create(interfaces)
  1361. # Create three VirtualChassis with three members each
  1362. virtual_chassis = (
  1363. VirtualChassis(name='Virtual Chassis 1', master=devices[0], domain='domain-1'),
  1364. VirtualChassis(name='Virtual Chassis 2', master=devices[3], domain='domain-2'),
  1365. VirtualChassis(name='Virtual Chassis 3', master=devices[6], domain='domain-3'),
  1366. )
  1367. VirtualChassis.objects.bulk_create(virtual_chassis)
  1368. Device.objects.filter(pk=devices[0].pk).update(virtual_chassis=virtual_chassis[0], vc_position=1)
  1369. Device.objects.filter(pk=devices[1].pk).update(virtual_chassis=virtual_chassis[0], vc_position=2)
  1370. Device.objects.filter(pk=devices[2].pk).update(virtual_chassis=virtual_chassis[0], vc_position=3)
  1371. Device.objects.filter(pk=devices[3].pk).update(virtual_chassis=virtual_chassis[1], vc_position=1)
  1372. Device.objects.filter(pk=devices[4].pk).update(virtual_chassis=virtual_chassis[1], vc_position=2)
  1373. Device.objects.filter(pk=devices[5].pk).update(virtual_chassis=virtual_chassis[1], vc_position=3)
  1374. Device.objects.filter(pk=devices[6].pk).update(virtual_chassis=virtual_chassis[2], vc_position=1)
  1375. Device.objects.filter(pk=devices[7].pk).update(virtual_chassis=virtual_chassis[2], vc_position=2)
  1376. Device.objects.filter(pk=devices[8].pk).update(virtual_chassis=virtual_chassis[2], vc_position=3)
  1377. cls.update_data = {
  1378. 'name': 'Virtual Chassis X',
  1379. 'domain': 'domain-x',
  1380. 'master': devices[1].pk,
  1381. }
  1382. cls.create_data = [
  1383. {
  1384. 'name': 'Virtual Chassis 4',
  1385. 'domain': 'domain-4',
  1386. },
  1387. {
  1388. 'name': 'Virtual Chassis 5',
  1389. 'domain': 'domain-5',
  1390. },
  1391. {
  1392. 'name': 'Virtual Chassis 6',
  1393. 'domain': 'domain-6',
  1394. },
  1395. ]
  1396. cls.bulk_update_data = {
  1397. 'domain': 'newdomain',
  1398. }
  1399. class PowerPanelTest(APIViewTestCases.APIViewTestCase):
  1400. model = PowerPanel
  1401. brief_fields = ['display', 'id', 'name', 'powerfeed_count', 'url']
  1402. @classmethod
  1403. def setUpTestData(cls):
  1404. sites = (
  1405. Site.objects.create(name='Site 1', slug='site-1'),
  1406. Site.objects.create(name='Site 2', slug='site-2'),
  1407. )
  1408. locations = (
  1409. Location.objects.create(name='Location 1', slug='location-1', site=sites[0]),
  1410. Location.objects.create(name='Location 2', slug='location-2', site=sites[0]),
  1411. Location.objects.create(name='Location 3', slug='location-3', site=sites[0]),
  1412. Location.objects.create(name='Location 4', slug='location-3', site=sites[1]),
  1413. )
  1414. power_panels = (
  1415. PowerPanel(site=sites[0], location=locations[0], name='Power Panel 1'),
  1416. PowerPanel(site=sites[0], location=locations[1], name='Power Panel 2'),
  1417. PowerPanel(site=sites[0], location=locations[2], name='Power Panel 3'),
  1418. )
  1419. PowerPanel.objects.bulk_create(power_panels)
  1420. cls.create_data = [
  1421. {
  1422. 'name': 'Power Panel 4',
  1423. 'site': sites[0].pk,
  1424. 'location': locations[0].pk,
  1425. },
  1426. {
  1427. 'name': 'Power Panel 5',
  1428. 'site': sites[0].pk,
  1429. 'location': locations[1].pk,
  1430. },
  1431. {
  1432. 'name': 'Power Panel 6',
  1433. 'site': sites[0].pk,
  1434. 'location': locations[2].pk,
  1435. },
  1436. ]
  1437. cls.bulk_update_data = {
  1438. 'site': sites[1].pk,
  1439. 'location': locations[3].pk
  1440. }
  1441. class PowerFeedTest(APIViewTestCases.APIViewTestCase):
  1442. model = PowerFeed
  1443. brief_fields = ['_occupied', 'cable', 'display', 'id', 'name', 'url']
  1444. bulk_update_data = {
  1445. 'status': 'planned',
  1446. }
  1447. @classmethod
  1448. def setUpTestData(cls):
  1449. site = Site.objects.create(name='Site 1', slug='site-1')
  1450. location = Location.objects.create(site=site, name='Location 1', slug='location-1')
  1451. rackrole = RackRole.objects.create(name='Rack Role 1', slug='rack-role-1', color='ff0000')
  1452. racks = (
  1453. Rack(site=site, location=location, role=rackrole, name='Rack 1'),
  1454. Rack(site=site, location=location, role=rackrole, name='Rack 2'),
  1455. Rack(site=site, location=location, role=rackrole, name='Rack 3'),
  1456. Rack(site=site, location=location, role=rackrole, name='Rack 4'),
  1457. )
  1458. Rack.objects.bulk_create(racks)
  1459. power_panels = (
  1460. PowerPanel(site=site, location=location, name='Power Panel 1'),
  1461. PowerPanel(site=site, location=location, name='Power Panel 2'),
  1462. )
  1463. PowerPanel.objects.bulk_create(power_panels)
  1464. PRIMARY = PowerFeedTypeChoices.TYPE_PRIMARY
  1465. REDUNDANT = PowerFeedTypeChoices.TYPE_REDUNDANT
  1466. power_feeds = (
  1467. PowerFeed(power_panel=power_panels[0], rack=racks[0], name='Power Feed 1A', type=PRIMARY),
  1468. PowerFeed(power_panel=power_panels[1], rack=racks[0], name='Power Feed 1B', type=REDUNDANT),
  1469. PowerFeed(power_panel=power_panels[0], rack=racks[1], name='Power Feed 2A', type=PRIMARY),
  1470. PowerFeed(power_panel=power_panels[1], rack=racks[1], name='Power Feed 2B', type=REDUNDANT),
  1471. PowerFeed(power_panel=power_panels[0], rack=racks[2], name='Power Feed 3A', type=PRIMARY),
  1472. PowerFeed(power_panel=power_panels[1], rack=racks[2], name='Power Feed 3B', type=REDUNDANT),
  1473. )
  1474. PowerFeed.objects.bulk_create(power_feeds)
  1475. cls.create_data = [
  1476. {
  1477. 'name': 'Power Feed 4A',
  1478. 'power_panel': power_panels[0].pk,
  1479. 'rack': racks[3].pk,
  1480. 'type': PRIMARY,
  1481. },
  1482. {
  1483. 'name': 'Power Feed 4B',
  1484. 'power_panel': power_panels[1].pk,
  1485. 'rack': racks[3].pk,
  1486. 'type': REDUNDANT,
  1487. },
  1488. ]