test_api.py 109 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965
  1. import json
  2. from django.test import override_settings, tag
  3. from django.urls import reverse
  4. from django.utils.translation import gettext as _
  5. from rest_framework import status
  6. from dcim.choices import *
  7. from dcim.constants import *
  8. from dcim.models import *
  9. from extras.models import ConfigTemplate
  10. from ipam.choices import VLANQinQRoleChoices
  11. from ipam.models import ASN, RIR, VLAN, VRF
  12. from netbox.api.serializers import GenericObjectSerializer
  13. from tenancy.models import Tenant
  14. from users.constants import TOKEN_PREFIX
  15. from users.models import Token, User
  16. from utilities.testing import APITestCase, APIViewTestCases, create_test_device, disable_logging
  17. from virtualization.models import Cluster, ClusterType
  18. from wireless.choices import WirelessChannelChoices
  19. from wireless.models import WirelessLAN
  20. class AppTest(APITestCase):
  21. def test_root(self):
  22. url = reverse('dcim-api:api-root')
  23. response = self.client.get('{}?format=api'.format(url), **self.header)
  24. self.assertEqual(response.status_code, 200)
  25. class Mixins:
  26. class ComponentTraceMixin(APITestCase):
  27. peer_termination_type = None
  28. def test_trace(self):
  29. """
  30. Test tracing a device component's attached cable.
  31. """
  32. obj = self.model.objects.first()
  33. peer_device = Device.objects.create(
  34. site=Site.objects.first(),
  35. device_type=DeviceType.objects.first(),
  36. role=DeviceRole.objects.first(),
  37. name='Peer Device'
  38. )
  39. if self.peer_termination_type is None:
  40. raise NotImplementedError(_("Test case must set peer_termination_type"))
  41. peer_obj = self.peer_termination_type.objects.create(
  42. device=peer_device,
  43. name='Peer Termination'
  44. )
  45. cable = Cable(a_terminations=[obj], b_terminations=[peer_obj], label='Cable 1')
  46. cable.save()
  47. self.add_permissions(f'dcim.view_{self.model._meta.model_name}')
  48. url = reverse(f'dcim-api:{self.model._meta.model_name}-trace', kwargs={'pk': obj.pk})
  49. response = self.client.get(url, **self.header)
  50. self.assertHttpStatus(response, status.HTTP_200_OK)
  51. self.assertEqual(len(response.data), 1)
  52. segment1 = response.data[0]
  53. self.assertEqual(segment1[0][0]['name'], obj.name)
  54. self.assertEqual(segment1[1]['label'], cable.label)
  55. self.assertEqual(segment1[2][0]['name'], peer_obj.name)
  56. class RegionTest(APIViewTestCases.APIViewTestCase):
  57. model = Region
  58. brief_fields = ['_depth', 'description', 'display', 'id', 'name', 'site_count', 'slug', 'url']
  59. create_data = [
  60. {
  61. 'name': 'Region 4',
  62. 'slug': 'region-4',
  63. 'comments': 'this is region 4, not region 5',
  64. },
  65. {
  66. 'name': 'Region 5',
  67. 'slug': 'region-5',
  68. },
  69. {
  70. 'name': 'Region 6',
  71. 'slug': 'region-6',
  72. },
  73. ]
  74. bulk_update_data = {
  75. 'description': 'New description',
  76. 'comments': 'New comments',
  77. }
  78. @classmethod
  79. def setUpTestData(cls):
  80. Region.objects.create(name='Region 1', slug='region-1')
  81. Region.objects.create(name='Region 2', slug='region-2', comments='what in the world is happening?')
  82. Region.objects.create(name='Region 3', slug='region-3')
  83. class SiteGroupTest(APIViewTestCases.APIViewTestCase):
  84. model = SiteGroup
  85. brief_fields = ['_depth', 'description', 'display', 'id', 'name', 'site_count', 'slug', 'url']
  86. create_data = [
  87. {
  88. 'name': 'Site Group 4',
  89. 'slug': 'site-group-4',
  90. 'comments': '',
  91. },
  92. {
  93. 'name': 'Site Group 5',
  94. 'slug': 'site-group-5',
  95. 'comments': 'not actually empty',
  96. },
  97. {
  98. 'name': 'Site Group 6',
  99. 'slug': 'site-group-6',
  100. 'comments': 'Do I really exist?',
  101. },
  102. ]
  103. bulk_update_data = {
  104. 'description': 'New description',
  105. 'comments': 'I do exist!',
  106. }
  107. @classmethod
  108. def setUpTestData(cls):
  109. SiteGroup.objects.create(name='Site Group 1', slug='site-group-1')
  110. SiteGroup.objects.create(name='Site Group 2', slug='site-group-2', comments='')
  111. SiteGroup.objects.create(name='Site Group 3', slug='site-group-3', comments='Hi!')
  112. class SiteTest(APIViewTestCases.APIViewTestCase):
  113. model = Site
  114. brief_fields = ['description', 'display', 'id', 'name', 'slug', 'url']
  115. bulk_update_data = {
  116. 'status': 'planned',
  117. }
  118. @classmethod
  119. def setUpTestData(cls):
  120. regions = (
  121. Region.objects.create(name='Region 1', slug='region-1'),
  122. Region.objects.create(name='Region 2', slug='region-2'),
  123. )
  124. groups = (
  125. SiteGroup.objects.create(name='Site Group 1', slug='site-group-1'),
  126. SiteGroup.objects.create(name='Site Group 2', slug='site-group-2'),
  127. )
  128. sites = (
  129. Site(region=regions[0], group=groups[0], name='Site 1', slug='site-1'),
  130. Site(region=regions[0], group=groups[0], name='Site 2', slug='site-2'),
  131. Site(region=regions[0], group=groups[0], name='Site 3', slug='site-3'),
  132. )
  133. Site.objects.bulk_create(sites)
  134. rir = RIR.objects.create(name='RFC 6996', is_private=True)
  135. tenant = Tenant.objects.create(name='Tenant 1', slug='tenant-1')
  136. asns = [
  137. ASN(asn=65000 + i, rir=rir) for i in range(8)
  138. ]
  139. ASN.objects.bulk_create(asns)
  140. cls.create_data = [
  141. {
  142. 'name': 'Site 4',
  143. 'slug': 'site-4',
  144. 'region': regions[1].pk,
  145. 'group': groups[1].pk,
  146. 'status': SiteStatusChoices.STATUS_ACTIVE,
  147. 'asns': [asns[0].pk, asns[1].pk],
  148. 'tenant': tenant.pk,
  149. },
  150. {
  151. 'name': 'Site 5',
  152. 'slug': 'site-5',
  153. 'region': regions[1].pk,
  154. 'group': groups[1].pk,
  155. 'status': SiteStatusChoices.STATUS_ACTIVE,
  156. 'asns': [asns[2].pk, asns[3].pk],
  157. },
  158. {
  159. 'name': 'Site 6',
  160. 'slug': 'site-6',
  161. 'region': regions[1].pk,
  162. 'group': groups[1].pk,
  163. 'status': SiteStatusChoices.STATUS_ACTIVE,
  164. 'asns': [asns[4].pk, asns[5].pk],
  165. },
  166. ]
  167. class LocationTest(APIViewTestCases.APIViewTestCase):
  168. model = Location
  169. brief_fields = ['_depth', 'description', 'display', 'id', 'name', 'rack_count', 'slug', 'url']
  170. bulk_update_data = {
  171. 'description': 'New description',
  172. }
  173. user_permissions = ('dcim.view_site',)
  174. @classmethod
  175. def setUpTestData(cls):
  176. sites = (
  177. Site(name='Site 1', slug='site-1'),
  178. Site(name='Site 2', slug='site-2'),
  179. )
  180. Site.objects.bulk_create(sites)
  181. parent_locations = (
  182. Location.objects.create(
  183. site=sites[0],
  184. name='Parent Location 1',
  185. slug='parent-location-1',
  186. status=LocationStatusChoices.STATUS_ACTIVE,
  187. comments='First!'
  188. ),
  189. Location.objects.create(
  190. site=sites[1],
  191. name='Parent Location 2',
  192. slug='parent-location-2',
  193. status=LocationStatusChoices.STATUS_ACTIVE,
  194. comments='Second!'
  195. ),
  196. )
  197. Location.objects.create(
  198. site=sites[0],
  199. name='Location 1',
  200. slug='location-1',
  201. parent=parent_locations[0],
  202. status=LocationStatusChoices.STATUS_ACTIVE,
  203. comments='Third!'
  204. )
  205. Location.objects.create(
  206. site=sites[0],
  207. name='Location 2',
  208. slug='location-2',
  209. parent=parent_locations[0],
  210. status=LocationStatusChoices.STATUS_ACTIVE,
  211. )
  212. Location.objects.create(
  213. site=sites[0],
  214. name='Location 3',
  215. slug='location-3',
  216. parent=parent_locations[0],
  217. status=LocationStatusChoices.STATUS_ACTIVE,
  218. )
  219. cls.create_data = [
  220. {
  221. 'name': 'Test Location 4',
  222. 'slug': 'test-location-4',
  223. 'site': sites[1].pk,
  224. 'parent': parent_locations[1].pk,
  225. 'status': LocationStatusChoices.STATUS_PLANNED,
  226. 'comments': '',
  227. },
  228. {
  229. 'name': 'Test Location 5',
  230. 'slug': 'test-location-5',
  231. 'site': sites[1].pk,
  232. 'parent': parent_locations[1].pk,
  233. 'status': LocationStatusChoices.STATUS_PLANNED,
  234. 'comments': 'Somebody should check on this location',
  235. },
  236. {
  237. 'name': 'Test Location 6',
  238. 'slug': 'test-location-6',
  239. 'site': sites[1].pk,
  240. # Omit parent to test uniqueness constraint
  241. 'status': LocationStatusChoices.STATUS_PLANNED,
  242. },
  243. ]
  244. class RackRoleTest(APIViewTestCases.APIViewTestCase):
  245. model = RackRole
  246. brief_fields = ['description', 'display', 'id', 'name', 'rack_count', 'slug', 'url']
  247. create_data = [
  248. {
  249. 'name': 'Rack Role 4',
  250. 'slug': 'rack-role-4',
  251. 'color': 'ffff00',
  252. },
  253. {
  254. 'name': 'Rack Role 5',
  255. 'slug': 'rack-role-5',
  256. 'color': 'ffff00',
  257. },
  258. {
  259. 'name': 'Rack Role 6',
  260. 'slug': 'rack-role-6',
  261. 'color': 'ffff00',
  262. },
  263. ]
  264. bulk_update_data = {
  265. 'description': 'New description',
  266. }
  267. @classmethod
  268. def setUpTestData(cls):
  269. rack_roles = (
  270. RackRole(name='Rack Role 1', slug='rack-role-1', color='ff0000'),
  271. RackRole(name='Rack Role 2', slug='rack-role-2', color='00ff00'),
  272. RackRole(name='Rack Role 3', slug='rack-role-3', color='0000ff'),
  273. )
  274. RackRole.objects.bulk_create(rack_roles)
  275. class RackTypeTest(APIViewTestCases.APIViewTestCase):
  276. model = RackType
  277. brief_fields = ['description', 'display', 'id', 'manufacturer', 'model', 'rack_count', 'slug', 'url']
  278. bulk_update_data = {
  279. 'description': 'new description',
  280. }
  281. user_permissions = ('dcim.view_manufacturer',)
  282. @classmethod
  283. def setUpTestData(cls):
  284. manufacturers = (
  285. Manufacturer(name='Manufacturer 1', slug='manufacturer-1'),
  286. Manufacturer(name='Manufacturer 2', slug='manufacturer-2'),
  287. )
  288. Manufacturer.objects.bulk_create(manufacturers)
  289. rack_types = (
  290. RackType(
  291. manufacturer=manufacturers[0],
  292. model='Rack Type 1',
  293. slug='rack-type-1',
  294. form_factor=RackFormFactorChoices.TYPE_CABINET,
  295. ),
  296. RackType(
  297. manufacturer=manufacturers[0],
  298. model='Rack Type 2',
  299. slug='rack-type-2',
  300. form_factor=RackFormFactorChoices.TYPE_CABINET,
  301. ),
  302. RackType(
  303. manufacturer=manufacturers[0],
  304. model='Rack Type 3',
  305. slug='rack-type-3',
  306. form_factor=RackFormFactorChoices.TYPE_CABINET,
  307. ),
  308. )
  309. RackType.objects.bulk_create(rack_types)
  310. cls.create_data = [
  311. {
  312. 'manufacturer': manufacturers[1].pk,
  313. 'model': 'Rack Type 4',
  314. 'slug': 'rack-type-4',
  315. 'form_factor': RackFormFactorChoices.TYPE_CABINET,
  316. },
  317. {
  318. 'manufacturer': manufacturers[1].pk,
  319. 'model': 'Rack Type 5',
  320. 'slug': 'rack-type-5',
  321. 'form_factor': RackFormFactorChoices.TYPE_CABINET,
  322. },
  323. {
  324. 'manufacturer': manufacturers[1].pk,
  325. 'model': 'Rack Type 6',
  326. 'slug': 'rack-type-6',
  327. 'form_factor': RackFormFactorChoices.TYPE_CABINET,
  328. },
  329. ]
  330. class RackTest(APIViewTestCases.APIViewTestCase):
  331. model = Rack
  332. brief_fields = ['description', 'device_count', 'display', 'id', 'name', 'url']
  333. bulk_update_data = {
  334. 'status': 'planned',
  335. }
  336. user_permissions = ('dcim.view_site', )
  337. @classmethod
  338. def setUpTestData(cls):
  339. sites = (
  340. Site(name='Site 1', slug='site-1'),
  341. Site(name='Site 2', slug='site-2'),
  342. )
  343. Site.objects.bulk_create(sites)
  344. locations = (
  345. Location.objects.create(site=sites[0], name='Location 1', slug='location-1'),
  346. Location.objects.create(site=sites[1], name='Location 2', slug='location-2'),
  347. )
  348. rack_roles = (
  349. RackRole(name='Rack Role 1', slug='rack-role-1', color='ff0000'),
  350. RackRole(name='Rack Role 2', slug='rack-role-2', color='00ff00'),
  351. )
  352. RackRole.objects.bulk_create(rack_roles)
  353. racks = (
  354. Rack(site=sites[0], location=locations[0], role=rack_roles[0], name='Rack 1'),
  355. Rack(site=sites[0], location=locations[0], role=rack_roles[0], name='Rack 2'),
  356. Rack(site=sites[0], location=locations[0], role=rack_roles[0], name='Rack 3'),
  357. )
  358. Rack.objects.bulk_create(racks)
  359. cls.create_data = [
  360. {
  361. 'name': 'Test Rack 4',
  362. 'site': sites[1].pk,
  363. 'location': locations[1].pk,
  364. 'role': rack_roles[1].pk,
  365. },
  366. {
  367. 'name': 'Test Rack 5',
  368. 'site': sites[1].pk,
  369. 'location': locations[1].pk,
  370. 'role': rack_roles[1].pk,
  371. },
  372. {
  373. 'name': 'Test Rack 6',
  374. 'site': sites[1].pk,
  375. 'location': locations[1].pk,
  376. 'role': rack_roles[1].pk,
  377. },
  378. ]
  379. def test_get_rack_elevation(self):
  380. """
  381. GET a single rack elevation.
  382. """
  383. rack = Rack.objects.first()
  384. self.add_permissions('dcim.view_rack')
  385. url = reverse('dcim-api:rack-elevation', kwargs={'pk': rack.pk})
  386. # Retrieve all units
  387. response = self.client.get(url, **self.header)
  388. self.assertEqual(response.data['count'], 84)
  389. # Search for specific units
  390. response = self.client.get(f'{url}?q=3', **self.header)
  391. self.assertEqual(response.data['count'], 26)
  392. response = self.client.get(f'{url}?q=U3', **self.header)
  393. self.assertEqual(response.data['count'], 22)
  394. response = self.client.get(f'{url}?q=U10', **self.header)
  395. self.assertEqual(response.data['count'], 2)
  396. def test_get_rack_elevation_svg(self):
  397. """
  398. GET a single rack elevation in SVG format.
  399. """
  400. rack = Rack.objects.first()
  401. self.add_permissions('dcim.view_rack')
  402. url = '{}?render=svg'.format(reverse('dcim-api:rack-elevation', kwargs={'pk': rack.pk}))
  403. response = self.client.get(url, **self.header)
  404. self.assertHttpStatus(response, status.HTTP_200_OK)
  405. self.assertEqual(response.get('Content-Type'), 'image/svg+xml')
  406. class RackReservationTest(APIViewTestCases.APIViewTestCase):
  407. model = RackReservation
  408. brief_fields = ['description', 'display', 'id', 'status', 'units', 'url', 'user']
  409. bulk_update_data = {
  410. 'description': 'New description',
  411. }
  412. user_permissions = ('dcim.view_rack', 'users.view_user')
  413. @classmethod
  414. def setUpTestData(cls):
  415. user = User.objects.create(username='user1', is_active=True)
  416. site = Site.objects.create(name='Test Site 1', slug='test-site-1')
  417. racks = (
  418. Rack(site=site, name='Rack 1'),
  419. Rack(site=site, name='Rack 2'),
  420. )
  421. Rack.objects.bulk_create(racks)
  422. rack_reservations = (
  423. RackReservation(
  424. rack=racks[0],
  425. units=[1, 2, 3],
  426. user=user,
  427. description='Reservation #1',
  428. ),
  429. RackReservation(
  430. rack=racks[0],
  431. units=[4, 5, 6],
  432. user=user,
  433. description='Reservation #2'
  434. ),
  435. RackReservation(
  436. rack=racks[0],
  437. units=[7, 8, 9],
  438. user=user,
  439. description='Reservation #3',
  440. ),
  441. )
  442. RackReservation.objects.bulk_create(rack_reservations)
  443. cls.create_data = [
  444. {
  445. 'rack': racks[1].pk,
  446. 'units': [10, 11, 12],
  447. 'status': RackReservationStatusChoices.STATUS_ACTIVE,
  448. 'user': user.pk,
  449. 'description': 'Reservation #4',
  450. },
  451. {
  452. 'rack': racks[1].pk,
  453. 'units': [13, 14, 15],
  454. 'status': RackReservationStatusChoices.STATUS_PENDING,
  455. 'user': user.pk,
  456. 'description': 'Reservation #5',
  457. },
  458. {
  459. 'rack': racks[1].pk,
  460. 'units': [16, 17, 18],
  461. 'status': RackReservationStatusChoices.STATUS_STALE,
  462. 'user': user.pk,
  463. 'description': 'Reservation #6',
  464. },
  465. ]
  466. class ManufacturerTest(APIViewTestCases.APIViewTestCase):
  467. model = Manufacturer
  468. brief_fields = ['description', 'devicetype_count', 'display', 'id', 'name', 'slug', 'url']
  469. create_data = [
  470. {
  471. 'name': 'Manufacturer 4',
  472. 'slug': 'manufacturer-4',
  473. },
  474. {
  475. 'name': 'Manufacturer 5',
  476. 'slug': 'manufacturer-5',
  477. },
  478. {
  479. 'name': 'Manufacturer 6',
  480. 'slug': 'manufacturer-6',
  481. },
  482. ]
  483. bulk_update_data = {
  484. 'description': 'New description',
  485. }
  486. @classmethod
  487. def setUpTestData(cls):
  488. manufacturers = (
  489. Manufacturer(name='Manufacturer 1', slug='manufacturer-1'),
  490. Manufacturer(name='Manufacturer 2', slug='manufacturer-2'),
  491. Manufacturer(name='Manufacturer 3', slug='manufacturer-3'),
  492. )
  493. Manufacturer.objects.bulk_create(manufacturers)
  494. class DeviceTypeTest(APIViewTestCases.APIViewTestCase):
  495. model = DeviceType
  496. brief_fields = ['description', 'device_count', 'display', 'id', 'manufacturer', 'model', 'slug', 'url']
  497. bulk_update_data = {
  498. 'part_number': 'ABC123',
  499. }
  500. user_permissions = ('dcim.view_manufacturer', )
  501. @classmethod
  502. def setUpTestData(cls):
  503. manufacturers = (
  504. Manufacturer(name='Manufacturer 1', slug='manufacturer-1'),
  505. Manufacturer(name='Manufacturer 2', slug='manufacturer-2'),
  506. )
  507. Manufacturer.objects.bulk_create(manufacturers)
  508. device_types = (
  509. DeviceType(manufacturer=manufacturers[0], model='Device Type 1', slug='device-type-1'),
  510. DeviceType(manufacturer=manufacturers[0], model='Device Type 2', slug='device-type-2'),
  511. DeviceType(manufacturer=manufacturers[0], model='Device Type 3', slug='device-type-3'),
  512. )
  513. DeviceType.objects.bulk_create(device_types)
  514. cls.create_data = [
  515. {
  516. 'manufacturer': manufacturers[1].pk,
  517. 'model': 'Device Type 4',
  518. 'slug': 'device-type-4',
  519. 'u_height': 0,
  520. },
  521. {
  522. 'manufacturer': manufacturers[1].pk,
  523. 'model': 'Device Type 5',
  524. 'slug': 'device-type-5',
  525. 'u_height': 0.5,
  526. },
  527. {
  528. 'manufacturer': manufacturers[1].pk,
  529. 'model': 'Device Type 6',
  530. 'slug': 'device-type-6',
  531. 'u_height': 1,
  532. },
  533. ]
  534. class ModuleTypeTest(APIViewTestCases.APIViewTestCase):
  535. model = ModuleType
  536. brief_fields = ['description', 'display', 'id', 'manufacturer', 'model', 'module_count', 'profile', 'url']
  537. bulk_update_data = {
  538. 'part_number': 'ABC123',
  539. }
  540. user_permissions = ('dcim.view_manufacturer', )
  541. @classmethod
  542. def setUpTestData(cls):
  543. manufacturers = (
  544. Manufacturer(name='Manufacturer 1', slug='manufacturer-1'),
  545. Manufacturer(name='Manufacturer 2', slug='manufacturer-2'),
  546. )
  547. Manufacturer.objects.bulk_create(manufacturers)
  548. module_types = (
  549. ModuleType(manufacturer=manufacturers[0], model='Module Type 1'),
  550. ModuleType(manufacturer=manufacturers[0], model='Module Type 2'),
  551. ModuleType(manufacturer=manufacturers[0], model='Module Type 3'),
  552. )
  553. ModuleType.objects.bulk_create(module_types)
  554. cls.create_data = [
  555. {
  556. 'manufacturer': manufacturers[1].pk,
  557. 'model': 'Module Type 4',
  558. },
  559. {
  560. 'manufacturer': manufacturers[1].pk,
  561. 'model': 'Module Type 5',
  562. },
  563. {
  564. 'manufacturer': manufacturers[1].pk,
  565. 'model': 'Module Type 6',
  566. },
  567. ]
  568. class ModuleTypeProfileTest(APIViewTestCases.APIViewTestCase):
  569. model = ModuleTypeProfile
  570. brief_fields = ['description', 'display', 'id', 'name', 'url']
  571. SCHEMAS = [
  572. {
  573. "properties": {
  574. "foo": {
  575. "type": "string"
  576. }
  577. }
  578. },
  579. {
  580. "properties": {
  581. "foo": {
  582. "type": "integer"
  583. }
  584. }
  585. },
  586. {
  587. "properties": {
  588. "foo": {
  589. "type": "boolean"
  590. }
  591. }
  592. },
  593. ]
  594. create_data = [
  595. {
  596. 'name': 'Module Type Profile 4',
  597. 'schema': SCHEMAS[0],
  598. },
  599. {
  600. 'name': 'Module Type Profile 5',
  601. 'schema': SCHEMAS[1],
  602. },
  603. {
  604. 'name': 'Module Type Profile 6',
  605. 'schema': SCHEMAS[2],
  606. },
  607. ]
  608. bulk_update_data = {
  609. 'description': 'New description',
  610. 'comments': 'New comments',
  611. }
  612. @classmethod
  613. def setUpTestData(cls):
  614. module_type_profiles = (
  615. ModuleTypeProfile(
  616. name='Module Type Profile 1',
  617. schema=cls.SCHEMAS[0]
  618. ),
  619. ModuleTypeProfile(
  620. name='Module Type Profile 2',
  621. schema=cls.SCHEMAS[1]
  622. ),
  623. ModuleTypeProfile(
  624. name='Module Type Profile 3',
  625. schema=cls.SCHEMAS[2]
  626. ),
  627. )
  628. ModuleTypeProfile.objects.bulk_create(module_type_profiles)
  629. class ConsolePortTemplateTest(APIViewTestCases.APIViewTestCase):
  630. model = ConsolePortTemplate
  631. brief_fields = ['description', 'display', 'id', 'name', 'url']
  632. bulk_update_data = {
  633. 'description': 'New description',
  634. }
  635. @classmethod
  636. def setUpTestData(cls):
  637. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  638. devicetype = DeviceType.objects.create(
  639. manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'
  640. )
  641. moduletype = ModuleType.objects.create(
  642. manufacturer=manufacturer, model='Module Type 1'
  643. )
  644. console_port_templates = (
  645. ConsolePortTemplate(device_type=devicetype, name='Console Port Template 1'),
  646. ConsolePortTemplate(device_type=devicetype, name='Console Port Template 2'),
  647. ConsolePortTemplate(device_type=devicetype, name='Console Port Template 3'),
  648. )
  649. ConsolePortTemplate.objects.bulk_create(console_port_templates)
  650. cls.create_data = [
  651. {
  652. 'device_type': devicetype.pk,
  653. 'name': 'Console Port Template 4',
  654. },
  655. {
  656. 'device_type': devicetype.pk,
  657. 'name': 'Console Port Template 5',
  658. },
  659. {
  660. 'module_type': moduletype.pk,
  661. 'name': 'Console Port Template 6',
  662. },
  663. {
  664. 'module_type': moduletype.pk,
  665. 'name': 'Console Port Template 7',
  666. },
  667. ]
  668. class ConsoleServerPortTemplateTest(APIViewTestCases.APIViewTestCase):
  669. model = ConsoleServerPortTemplate
  670. brief_fields = ['description', 'display', 'id', 'name', 'url']
  671. bulk_update_data = {
  672. 'description': 'New description',
  673. }
  674. @classmethod
  675. def setUpTestData(cls):
  676. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  677. devicetype = DeviceType.objects.create(
  678. manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'
  679. )
  680. moduletype = ModuleType.objects.create(
  681. manufacturer=manufacturer, model='Module Type 1'
  682. )
  683. console_server_port_templates = (
  684. ConsoleServerPortTemplate(device_type=devicetype, name='Console Server Port Template 1'),
  685. ConsoleServerPortTemplate(device_type=devicetype, name='Console Server Port Template 2'),
  686. ConsoleServerPortTemplate(device_type=devicetype, name='Console Server Port Template 3'),
  687. )
  688. ConsoleServerPortTemplate.objects.bulk_create(console_server_port_templates)
  689. cls.create_data = [
  690. {
  691. 'device_type': devicetype.pk,
  692. 'name': 'Console Server Port Template 4',
  693. },
  694. {
  695. 'device_type': devicetype.pk,
  696. 'name': 'Console Server Port Template 5',
  697. },
  698. {
  699. 'module_type': moduletype.pk,
  700. 'name': 'Console Server Port Template 6',
  701. },
  702. {
  703. 'module_type': moduletype.pk,
  704. 'name': 'Console Server Port Template 7',
  705. },
  706. ]
  707. class PowerPortTemplateTest(APIViewTestCases.APIViewTestCase):
  708. model = PowerPortTemplate
  709. brief_fields = ['description', 'display', 'id', 'name', 'url']
  710. bulk_update_data = {
  711. 'description': 'New description',
  712. }
  713. @classmethod
  714. def setUpTestData(cls):
  715. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  716. devicetype = DeviceType.objects.create(
  717. manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'
  718. )
  719. moduletype = ModuleType.objects.create(
  720. manufacturer=manufacturer, model='Module Type 1'
  721. )
  722. power_port_templates = (
  723. PowerPortTemplate(device_type=devicetype, name='Power Port Template 1'),
  724. PowerPortTemplate(device_type=devicetype, name='Power Port Template 2'),
  725. PowerPortTemplate(device_type=devicetype, name='Power Port Template 3'),
  726. )
  727. PowerPortTemplate.objects.bulk_create(power_port_templates)
  728. cls.create_data = [
  729. {
  730. 'device_type': devicetype.pk,
  731. 'name': 'Power Port Template 4',
  732. },
  733. {
  734. 'device_type': devicetype.pk,
  735. 'name': 'Power Port Template 5',
  736. },
  737. {
  738. 'module_type': moduletype.pk,
  739. 'name': 'Power Port Template 6',
  740. },
  741. {
  742. 'module_type': moduletype.pk,
  743. 'name': 'Power Port Template 7',
  744. },
  745. ]
  746. class PowerOutletTemplateTest(APIViewTestCases.APIViewTestCase):
  747. model = PowerOutletTemplate
  748. brief_fields = ['description', 'display', 'id', 'name', 'url']
  749. bulk_update_data = {
  750. 'description': 'New description',
  751. }
  752. user_permissions = ('dcim.view_devicetype', )
  753. @classmethod
  754. def setUpTestData(cls):
  755. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  756. devicetype = DeviceType.objects.create(
  757. manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'
  758. )
  759. moduletype = ModuleType.objects.create(
  760. manufacturer=manufacturer, model='Module Type 1'
  761. )
  762. power_port_templates = (
  763. PowerPortTemplate(device_type=devicetype, name='Power Port Template 1'),
  764. PowerPortTemplate(device_type=devicetype, name='Power Port Template 2'),
  765. )
  766. PowerPortTemplate.objects.bulk_create(power_port_templates)
  767. power_outlet_templates = (
  768. PowerOutletTemplate(device_type=devicetype, name='Power Outlet Template 1'),
  769. PowerOutletTemplate(device_type=devicetype, name='Power Outlet Template 2'),
  770. PowerOutletTemplate(device_type=devicetype, name='Power Outlet Template 3'),
  771. )
  772. PowerOutletTemplate.objects.bulk_create(power_outlet_templates)
  773. cls.create_data = [
  774. {
  775. 'device_type': devicetype.pk,
  776. 'name': 'Power Outlet Template 4',
  777. 'power_port': power_port_templates[0].pk,
  778. },
  779. {
  780. 'device_type': devicetype.pk,
  781. 'name': 'Power Outlet Template 5',
  782. 'power_port': power_port_templates[1].pk,
  783. },
  784. {
  785. 'device_type': devicetype.pk,
  786. 'name': 'Power Outlet Template 6',
  787. 'power_port': None,
  788. },
  789. {
  790. 'module_type': moduletype.pk,
  791. 'name': 'Power Outlet Template 7',
  792. },
  793. {
  794. 'module_type': moduletype.pk,
  795. 'name': 'Power Outlet Template 8',
  796. },
  797. ]
  798. class InterfaceTemplateTest(APIViewTestCases.APIViewTestCase):
  799. model = InterfaceTemplate
  800. brief_fields = ['description', 'display', 'id', 'name', 'url']
  801. bulk_update_data = {
  802. 'description': 'New description',
  803. }
  804. @classmethod
  805. def setUpTestData(cls):
  806. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  807. devicetype = DeviceType.objects.create(
  808. manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'
  809. )
  810. moduletype = ModuleType.objects.create(
  811. manufacturer=manufacturer, model='Module Type 1'
  812. )
  813. interface_templates = (
  814. InterfaceTemplate(device_type=devicetype, name='Interface Template 1', type='1000base-t'),
  815. InterfaceTemplate(device_type=devicetype, name='Interface Template 2', type='1000base-t'),
  816. InterfaceTemplate(device_type=devicetype, name='Interface Template 3', type='1000base-t'),
  817. )
  818. InterfaceTemplate.objects.bulk_create(interface_templates)
  819. cls.create_data = [
  820. {
  821. 'device_type': devicetype.pk,
  822. 'name': 'Interface Template 4',
  823. 'type': '1000base-t',
  824. },
  825. {
  826. 'device_type': devicetype.pk,
  827. 'name': 'Interface Template 5',
  828. 'type': '1000base-t',
  829. },
  830. {
  831. 'module_type': moduletype.pk,
  832. 'name': 'Interface Template 6',
  833. 'type': '1000base-t',
  834. },
  835. {
  836. 'module_type': moduletype.pk,
  837. 'name': 'Interface Template 7',
  838. 'type': '1000base-t',
  839. },
  840. ]
  841. class FrontPortTemplateTest(APIViewTestCases.APIViewTestCase):
  842. model = FrontPortTemplate
  843. brief_fields = ['description', 'display', 'id', 'name', 'url']
  844. bulk_update_data = {
  845. 'description': 'New description',
  846. }
  847. user_permissions = ('dcim.view_rearporttemplate', )
  848. @classmethod
  849. def setUpTestData(cls):
  850. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  851. devicetype = DeviceType.objects.create(
  852. manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'
  853. )
  854. moduletype = ModuleType.objects.create(
  855. manufacturer=manufacturer, model='Module Type 1'
  856. )
  857. rear_port_templates = (
  858. RearPortTemplate(device_type=devicetype, name='Rear Port Template 1', type=PortTypeChoices.TYPE_8P8C),
  859. RearPortTemplate(device_type=devicetype, name='Rear Port Template 2', type=PortTypeChoices.TYPE_8P8C),
  860. RearPortTemplate(device_type=devicetype, name='Rear Port Template 3', type=PortTypeChoices.TYPE_8P8C),
  861. RearPortTemplate(device_type=devicetype, name='Rear Port Template 4', type=PortTypeChoices.TYPE_8P8C),
  862. RearPortTemplate(device_type=devicetype, name='Rear Port Template 5', type=PortTypeChoices.TYPE_8P8C),
  863. RearPortTemplate(device_type=devicetype, name='Rear Port Template 6', type=PortTypeChoices.TYPE_8P8C),
  864. )
  865. RearPortTemplate.objects.bulk_create(rear_port_templates)
  866. front_port_templates = (
  867. FrontPortTemplate(device_type=devicetype, name='Front Port Template 1', type=PortTypeChoices.TYPE_8P8C),
  868. FrontPortTemplate(device_type=devicetype, name='Front Port Template 2', type=PortTypeChoices.TYPE_8P8C),
  869. FrontPortTemplate(module_type=moduletype, name='Front Port Template 3', type=PortTypeChoices.TYPE_8P8C),
  870. )
  871. FrontPortTemplate.objects.bulk_create(front_port_templates)
  872. PortTemplateMapping.objects.bulk_create([
  873. PortTemplateMapping(
  874. device_type=devicetype,
  875. front_port=front_port_templates[0],
  876. rear_port=rear_port_templates[0],
  877. ),
  878. PortTemplateMapping(
  879. device_type=devicetype,
  880. front_port=front_port_templates[1],
  881. rear_port=rear_port_templates[1],
  882. ),
  883. PortTemplateMapping(
  884. module_type=moduletype,
  885. front_port=front_port_templates[2],
  886. rear_port=rear_port_templates[2],
  887. ),
  888. ])
  889. cls.create_data = [
  890. {
  891. 'device_type': devicetype.pk,
  892. 'name': 'Front Port Template 3',
  893. 'type': PortTypeChoices.TYPE_8P8C,
  894. 'rear_ports': [
  895. {
  896. 'position': 1,
  897. 'rear_port': rear_port_templates[3].pk,
  898. 'rear_port_position': 1,
  899. },
  900. ],
  901. },
  902. {
  903. 'device_type': devicetype.pk,
  904. 'name': 'Front Port Template 4',
  905. 'type': PortTypeChoices.TYPE_8P8C,
  906. 'rear_ports': [
  907. {
  908. 'position': 1,
  909. 'rear_port': rear_port_templates[4].pk,
  910. 'rear_port_position': 1,
  911. },
  912. ],
  913. },
  914. {
  915. 'module_type': moduletype.pk,
  916. 'name': 'Front Port Template 7',
  917. 'type': PortTypeChoices.TYPE_8P8C,
  918. 'rear_ports': [
  919. {
  920. 'position': 1,
  921. 'rear_port': rear_port_templates[5].pk,
  922. 'rear_port_position': 1,
  923. },
  924. ],
  925. },
  926. ]
  927. cls.update_data = {
  928. 'type': PortTypeChoices.TYPE_LC,
  929. 'rear_ports': [
  930. {
  931. 'position': 1,
  932. 'rear_port': rear_port_templates[3].pk,
  933. 'rear_port_position': 1,
  934. },
  935. ],
  936. }
  937. def test_update_object(self):
  938. super().test_update_object()
  939. # Check that the port mapping was updated after modifying the front port template
  940. front_port_template = FrontPortTemplate.objects.get(name='Front Port Template 1')
  941. rear_port_template = RearPortTemplate.objects.get(name='Rear Port Template 4')
  942. self.assertTrue(
  943. PortTemplateMapping.objects.filter(
  944. front_port=front_port_template,
  945. front_port_position=1,
  946. rear_port=rear_port_template,
  947. rear_port_position=1,
  948. ).exists()
  949. )
  950. class RearPortTemplateTest(APIViewTestCases.APIViewTestCase):
  951. model = RearPortTemplate
  952. brief_fields = ['description', 'display', 'id', 'name', 'url']
  953. bulk_update_data = {
  954. 'description': 'New description',
  955. }
  956. @classmethod
  957. def setUpTestData(cls):
  958. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  959. devicetype = DeviceType.objects.create(
  960. manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'
  961. )
  962. moduletype = ModuleType.objects.create(
  963. manufacturer=manufacturer, model='Module Type 1'
  964. )
  965. front_port_templates = (
  966. FrontPortTemplate(device_type=devicetype, name='Front Port Template 1', type=PortTypeChoices.TYPE_8P8C),
  967. FrontPortTemplate(device_type=devicetype, name='Front Port Template 2', type=PortTypeChoices.TYPE_8P8C),
  968. FrontPortTemplate(module_type=moduletype, name='Front Port Template 3', type=PortTypeChoices.TYPE_8P8C),
  969. FrontPortTemplate(module_type=moduletype, name='Front Port Template 4', type=PortTypeChoices.TYPE_8P8C),
  970. FrontPortTemplate(module_type=moduletype, name='Front Port Template 5', type=PortTypeChoices.TYPE_8P8C),
  971. FrontPortTemplate(module_type=moduletype, name='Front Port Template 6', type=PortTypeChoices.TYPE_8P8C),
  972. )
  973. FrontPortTemplate.objects.bulk_create(front_port_templates)
  974. rear_port_templates = (
  975. RearPortTemplate(device_type=devicetype, name='Rear Port Template 1', type=PortTypeChoices.TYPE_8P8C),
  976. RearPortTemplate(device_type=devicetype, name='Rear Port Template 2', type=PortTypeChoices.TYPE_8P8C),
  977. RearPortTemplate(device_type=devicetype, name='Rear Port Template 3', type=PortTypeChoices.TYPE_8P8C),
  978. )
  979. RearPortTemplate.objects.bulk_create(rear_port_templates)
  980. PortTemplateMapping.objects.bulk_create([
  981. PortTemplateMapping(
  982. device_type=devicetype,
  983. front_port=front_port_templates[0],
  984. rear_port=rear_port_templates[0],
  985. ),
  986. PortTemplateMapping(
  987. device_type=devicetype,
  988. front_port=front_port_templates[1],
  989. rear_port=rear_port_templates[1],
  990. ),
  991. PortTemplateMapping(
  992. module_type=moduletype,
  993. front_port=front_port_templates[2],
  994. rear_port=rear_port_templates[2],
  995. ),
  996. ])
  997. cls.create_data = [
  998. {
  999. 'device_type': devicetype.pk,
  1000. 'name': 'Rear Port Template 4',
  1001. 'type': PortTypeChoices.TYPE_8P8C,
  1002. 'front_ports': [
  1003. {
  1004. 'position': 1,
  1005. 'front_port': front_port_templates[3].pk,
  1006. 'front_port_position': 1,
  1007. },
  1008. ],
  1009. },
  1010. {
  1011. 'device_type': devicetype.pk,
  1012. 'name': 'Rear Port Template 5',
  1013. 'type': PortTypeChoices.TYPE_8P8C,
  1014. 'front_ports': [
  1015. {
  1016. 'position': 1,
  1017. 'front_port': front_port_templates[4].pk,
  1018. 'front_port_position': 1,
  1019. },
  1020. ],
  1021. },
  1022. {
  1023. 'module_type': moduletype.pk,
  1024. 'name': 'Rear Port Template 6',
  1025. 'type': PortTypeChoices.TYPE_8P8C,
  1026. 'front_ports': [
  1027. {
  1028. 'position': 1,
  1029. 'front_port': front_port_templates[5].pk,
  1030. 'front_port_position': 1,
  1031. },
  1032. ],
  1033. },
  1034. ]
  1035. cls.update_data = {
  1036. 'type': PortTypeChoices.TYPE_LC,
  1037. 'front_ports': [
  1038. {
  1039. 'position': 1,
  1040. 'front_port': front_port_templates[3].pk,
  1041. 'front_port_position': 1,
  1042. },
  1043. ],
  1044. }
  1045. def test_update_object(self):
  1046. super().test_update_object()
  1047. # Check that the port mapping was updated after modifying the rear port template
  1048. front_port_template = FrontPortTemplate.objects.get(name='Front Port Template 4')
  1049. rear_port_template = RearPortTemplate.objects.get(name='Rear Port Template 1')
  1050. self.assertTrue(
  1051. PortTemplateMapping.objects.filter(
  1052. front_port=front_port_template,
  1053. front_port_position=1,
  1054. rear_port=rear_port_template,
  1055. rear_port_position=1,
  1056. ).exists()
  1057. )
  1058. class ModuleBayTemplateTest(APIViewTestCases.APIViewTestCase):
  1059. model = ModuleBayTemplate
  1060. brief_fields = ['description', 'display', 'id', 'name', 'url']
  1061. bulk_update_data = {
  1062. 'description': 'New description',
  1063. }
  1064. user_permissions = ('dcim.view_devicetype', )
  1065. @classmethod
  1066. def setUpTestData(cls):
  1067. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  1068. devicetype = DeviceType.objects.create(
  1069. manufacturer=manufacturer,
  1070. model='Device Type 1',
  1071. slug='device-type-1',
  1072. subdevice_role=SubdeviceRoleChoices.ROLE_PARENT
  1073. )
  1074. module_bay_templates = (
  1075. ModuleBayTemplate(device_type=devicetype, name='Module Bay Template 1'),
  1076. ModuleBayTemplate(device_type=devicetype, name='Module Bay Template 2'),
  1077. ModuleBayTemplate(device_type=devicetype, name='Module Bay Template 3'),
  1078. )
  1079. ModuleBayTemplate.objects.bulk_create(module_bay_templates)
  1080. cls.create_data = [
  1081. {
  1082. 'device_type': devicetype.pk,
  1083. 'name': 'Module Bay Template 4',
  1084. },
  1085. {
  1086. 'device_type': devicetype.pk,
  1087. 'name': 'Module Bay Template 5',
  1088. },
  1089. {
  1090. 'device_type': devicetype.pk,
  1091. 'name': 'Module Bay Template 6',
  1092. },
  1093. ]
  1094. class DeviceBayTemplateTest(APIViewTestCases.APIViewTestCase):
  1095. model = DeviceBayTemplate
  1096. brief_fields = ['description', 'display', 'id', 'name', 'url']
  1097. bulk_update_data = {
  1098. 'description': 'New description',
  1099. }
  1100. user_permissions = ('dcim.view_devicetype', )
  1101. @classmethod
  1102. def setUpTestData(cls):
  1103. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  1104. devicetype = DeviceType.objects.create(
  1105. manufacturer=manufacturer,
  1106. model='Device Type 1',
  1107. slug='device-type-1',
  1108. subdevice_role=SubdeviceRoleChoices.ROLE_PARENT
  1109. )
  1110. device_bay_templates = (
  1111. DeviceBayTemplate(device_type=devicetype, name='Device Bay Template 1'),
  1112. DeviceBayTemplate(device_type=devicetype, name='Device Bay Template 2'),
  1113. DeviceBayTemplate(device_type=devicetype, name='Device Bay Template 3'),
  1114. )
  1115. DeviceBayTemplate.objects.bulk_create(device_bay_templates)
  1116. cls.create_data = [
  1117. {
  1118. 'device_type': devicetype.pk,
  1119. 'name': 'Device Bay Template 4',
  1120. },
  1121. {
  1122. 'device_type': devicetype.pk,
  1123. 'name': 'Device Bay Template 5',
  1124. },
  1125. {
  1126. 'device_type': devicetype.pk,
  1127. 'name': 'Device Bay Template 6',
  1128. },
  1129. ]
  1130. class InventoryItemTemplateTest(APIViewTestCases.APIViewTestCase):
  1131. model = InventoryItemTemplate
  1132. brief_fields = ['_depth', 'description', 'display', 'id', 'name', 'url']
  1133. bulk_update_data = {
  1134. 'description': 'New description',
  1135. }
  1136. user_permissions = ('dcim.view_devicetype', 'dcim.view_manufacturer',)
  1137. @classmethod
  1138. def setUpTestData(cls):
  1139. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  1140. devicetype = DeviceType.objects.create(
  1141. manufacturer=manufacturer,
  1142. model='Device Type 1',
  1143. slug='device-type-1'
  1144. )
  1145. role = InventoryItemRole.objects.create(name='Inventory Item Role 1', slug='inventory-item-role-1')
  1146. inventory_item_templates = (
  1147. InventoryItemTemplate(
  1148. device_type=devicetype, name='Inventory Item Template 1', manufacturer=manufacturer, role=role
  1149. ),
  1150. InventoryItemTemplate(
  1151. device_type=devicetype, name='Inventory Item Template 2', manufacturer=manufacturer, role=role
  1152. ),
  1153. InventoryItemTemplate(
  1154. device_type=devicetype, name='Inventory Item Template 3', manufacturer=manufacturer, role=role
  1155. ),
  1156. InventoryItemTemplate(
  1157. device_type=devicetype, name='Inventory Item Template 4', manufacturer=manufacturer, role=role
  1158. ),
  1159. )
  1160. for item in inventory_item_templates:
  1161. item.save()
  1162. cls.create_data = [
  1163. {
  1164. 'device_type': devicetype.pk,
  1165. 'name': 'Inventory Item Template 5',
  1166. 'manufacturer': manufacturer.pk,
  1167. 'role': role.pk,
  1168. 'parent': inventory_item_templates[3].pk,
  1169. },
  1170. {
  1171. 'device_type': devicetype.pk,
  1172. 'name': 'Inventory Item Template 6',
  1173. 'manufacturer': manufacturer.pk,
  1174. 'role': role.pk,
  1175. 'parent': inventory_item_templates[3].pk,
  1176. },
  1177. {
  1178. 'device_type': devicetype.pk,
  1179. 'name': 'Inventory Item Template 7',
  1180. 'manufacturer': manufacturer.pk,
  1181. 'role': role.pk,
  1182. 'parent': inventory_item_templates[3].pk,
  1183. },
  1184. ]
  1185. class DeviceRoleTest(APIViewTestCases.APIViewTestCase):
  1186. model = DeviceRole
  1187. brief_fields = [
  1188. '_depth', 'description', 'device_count', 'display', 'id', 'name', 'slug', 'url', 'virtualmachine_count'
  1189. ]
  1190. create_data = [
  1191. {
  1192. 'name': 'Device Role 4',
  1193. 'slug': 'device-role-4',
  1194. 'color': 'ffff00',
  1195. },
  1196. {
  1197. 'name': 'Device Role 5',
  1198. 'slug': 'device-role-5',
  1199. 'color': 'ffff00',
  1200. },
  1201. {
  1202. 'name': 'Device Role 6',
  1203. 'slug': 'device-role-6',
  1204. 'color': 'ffff00',
  1205. },
  1206. ]
  1207. bulk_update_data = {
  1208. 'description': 'New description',
  1209. }
  1210. @classmethod
  1211. def setUpTestData(cls):
  1212. DeviceRole.objects.create(name='Device Role 1', slug='device-role-1', color='ff0000')
  1213. DeviceRole.objects.create(name='Device Role 2', slug='device-role-2', color='00ff00')
  1214. DeviceRole.objects.create(name='Device Role 3', slug='device-role-3', color='0000ff')
  1215. class PlatformTest(APIViewTestCases.APIViewTestCase):
  1216. model = Platform
  1217. brief_fields = [
  1218. '_depth', 'description', 'device_count', 'display', 'id', 'name', 'slug', 'url', 'virtualmachine_count',
  1219. ]
  1220. create_data = [
  1221. {
  1222. 'name': 'Platform 4',
  1223. 'slug': 'platform-4',
  1224. },
  1225. {
  1226. 'name': 'Platform 5',
  1227. 'slug': 'platform-5',
  1228. },
  1229. {
  1230. 'name': 'Platform 6',
  1231. 'slug': 'platform-6',
  1232. },
  1233. ]
  1234. bulk_update_data = {
  1235. 'description': 'New description',
  1236. }
  1237. @classmethod
  1238. def setUpTestData(cls):
  1239. platforms = (
  1240. Platform(name='Platform 1', slug='platform-1'),
  1241. Platform(name='Platform 2', slug='platform-2'),
  1242. Platform(name='Platform 3', slug='platform-3'),
  1243. )
  1244. for platform in platforms:
  1245. platform.save()
  1246. class DeviceTest(APIViewTestCases.APIViewTestCase):
  1247. model = Device
  1248. brief_fields = ['description', 'display', 'id', 'name', 'url']
  1249. bulk_update_data = {
  1250. 'status': 'failed',
  1251. }
  1252. user_permissions = (
  1253. 'dcim.view_site', 'dcim.view_rack', 'dcim.view_location', 'dcim.view_devicerole', 'dcim.view_devicetype',
  1254. )
  1255. @classmethod
  1256. def setUpTestData(cls):
  1257. sites = (
  1258. Site(name='Site 1', slug='site-1'),
  1259. Site(name='Site 2', slug='site-2'),
  1260. )
  1261. Site.objects.bulk_create(sites)
  1262. racks = (
  1263. Rack(name='Rack 1', site=sites[0]),
  1264. Rack(name='Rack 2', site=sites[1]),
  1265. )
  1266. Rack.objects.bulk_create(racks)
  1267. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  1268. device_types = (
  1269. DeviceType(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'),
  1270. DeviceType(manufacturer=manufacturer, model='Device Type 2', slug='device-type-2', u_height=2),
  1271. )
  1272. DeviceType.objects.bulk_create(device_types)
  1273. roles = (
  1274. DeviceRole(name='Device Role 1', slug='device-role-1', color='ff0000'),
  1275. DeviceRole(name='Device Role 2', slug='device-role-2', color='00ff00'),
  1276. )
  1277. for role in roles:
  1278. role.save()
  1279. cluster_type = ClusterType.objects.create(name='Cluster Type 1', slug='cluster-type-1')
  1280. clusters = (
  1281. Cluster(name='Cluster 1', type=cluster_type),
  1282. Cluster(name='Cluster 2', type=cluster_type),
  1283. )
  1284. Cluster.objects.bulk_create(clusters)
  1285. devices = (
  1286. Device(
  1287. device_type=device_types[0],
  1288. role=roles[0],
  1289. name='Device 1',
  1290. site=sites[0],
  1291. rack=racks[0],
  1292. cluster=clusters[0],
  1293. local_context_data={'A': 1}
  1294. ),
  1295. Device(
  1296. device_type=device_types[0],
  1297. role=roles[0],
  1298. name='Device 2',
  1299. site=sites[0],
  1300. rack=racks[0],
  1301. cluster=clusters[0],
  1302. local_context_data={'B': 2}
  1303. ),
  1304. Device(
  1305. device_type=device_types[0],
  1306. role=roles[0],
  1307. name='Device 3',
  1308. site=sites[0],
  1309. rack=racks[0],
  1310. cluster=clusters[0],
  1311. local_context_data={'C': 3}
  1312. ),
  1313. )
  1314. Device.objects.bulk_create(devices)
  1315. cls.create_data = [
  1316. {
  1317. 'device_type': device_types[1].pk,
  1318. 'role': roles[1].pk,
  1319. 'name': 'Test Device 4',
  1320. 'site': sites[1].pk,
  1321. 'rack': racks[1].pk,
  1322. 'cluster': clusters[1].pk,
  1323. },
  1324. {
  1325. 'device_type': device_types[1].pk,
  1326. 'role': roles[1].pk,
  1327. 'name': 'Test Device 5',
  1328. 'site': sites[1].pk,
  1329. 'rack': racks[1].pk,
  1330. 'cluster': clusters[1].pk,
  1331. },
  1332. {
  1333. 'device_type': device_types[1].pk,
  1334. 'role': roles[1].pk,
  1335. 'name': 'Test Device 6',
  1336. 'site': sites[1].pk,
  1337. 'rack': racks[1].pk,
  1338. 'cluster': clusters[1].pk,
  1339. },
  1340. ]
  1341. def test_config_context_included_by_default_in_list_view(self):
  1342. """
  1343. Check that config context data is included by default in the devices list.
  1344. """
  1345. self.add_permissions('dcim.view_device')
  1346. url = reverse('dcim-api:device-list') + '?slug=device-with-context-data'
  1347. response = self.client.get(url, **self.header)
  1348. self.assertEqual(response.data['results'][0].get('config_context', {}).get('A'), 1)
  1349. def test_config_context_excluded(self):
  1350. """
  1351. Check that config context data can be excluded by passing ?exclude=config_context.
  1352. """
  1353. self.add_permissions('dcim.view_device')
  1354. url = reverse('dcim-api:device-list') + '?exclude=config_context'
  1355. response = self.client.get(url, **self.header)
  1356. self.assertFalse('config_context' in response.data['results'][0])
  1357. def test_unique_name_per_site_constraint(self):
  1358. """
  1359. Check that creating a device with a duplicate name within a site fails.
  1360. """
  1361. device = Device.objects.first()
  1362. data = {
  1363. 'device_type': device.device_type.pk,
  1364. 'role': device.role.pk,
  1365. 'site': device.site.pk,
  1366. 'name': device.name,
  1367. }
  1368. self.add_permissions('dcim.add_device')
  1369. url = reverse('dcim-api:device-list')
  1370. response = self.client.post(url, data, format='json', **self.header)
  1371. self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
  1372. def test_rack_fit(self):
  1373. """
  1374. Check that creating multiple devices with overlapping position fails.
  1375. """
  1376. device = Device.objects.first()
  1377. device_type = DeviceType.objects.all()[1]
  1378. data = [
  1379. {
  1380. 'device_type': device_type.pk,
  1381. 'role': device.role.pk,
  1382. 'site': device.site.pk,
  1383. 'name': 'Test Device 7',
  1384. 'rack': device.rack.pk,
  1385. 'face': 'front',
  1386. 'position': 1
  1387. },
  1388. {
  1389. 'device_type': device_type.pk,
  1390. 'role': device.role.pk,
  1391. 'site': device.site.pk,
  1392. 'name': 'Test Device 8',
  1393. 'rack': device.rack.pk,
  1394. 'face': 'front',
  1395. 'position': 2
  1396. }
  1397. ]
  1398. self.add_permissions('dcim.add_device')
  1399. url = reverse('dcim-api:device-list')
  1400. response = self.client.post(url, data, format='json', **self.header)
  1401. self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
  1402. def test_render_config(self):
  1403. configtemplate = ConfigTemplate.objects.create(
  1404. name='Config Template 1',
  1405. template_code='Config for device {{ device.name }}'
  1406. )
  1407. device = Device.objects.first()
  1408. device.config_template = configtemplate
  1409. device.save()
  1410. self.add_permissions('dcim.render_config_device', 'dcim.view_device')
  1411. url = reverse('dcim-api:device-render-config', kwargs={'pk': device.pk})
  1412. response = self.client.post(url, {}, format='json', **self.header)
  1413. self.assertHttpStatus(response, status.HTTP_200_OK)
  1414. self.assertEqual(response.data['content'], f'Config for device {device.name}')
  1415. def test_render_config_without_permission(self):
  1416. configtemplate = ConfigTemplate.objects.create(
  1417. name='Config Template 1',
  1418. template_code='Config for device {{ device.name }}'
  1419. )
  1420. device = Device.objects.first()
  1421. device.config_template = configtemplate
  1422. device.save()
  1423. # No permissions added - user has no render_config permission
  1424. url = reverse('dcim-api:device-render-config', kwargs={'pk': device.pk})
  1425. response = self.client.post(url, {}, format='json', **self.header)
  1426. self.assertHttpStatus(response, status.HTTP_404_NOT_FOUND)
  1427. def test_render_config_token_write_enabled(self):
  1428. configtemplate = ConfigTemplate.objects.create(
  1429. name='Config Template 1',
  1430. template_code='Config for device {{ device.name }}'
  1431. )
  1432. device = Device.objects.first()
  1433. device.config_template = configtemplate
  1434. device.save()
  1435. self.add_permissions('dcim.render_config_device', 'dcim.view_device')
  1436. url = reverse('dcim-api:device-render-config', kwargs={'pk': device.pk})
  1437. # Request without token auth should fail with PermissionDenied
  1438. response = self.client.post(url, {}, format='json')
  1439. self.assertHttpStatus(response, status.HTTP_403_FORBIDDEN)
  1440. # Create token with write_enabled=False
  1441. token = Token.objects.create(version=2, user=self.user, write_enabled=False)
  1442. token_header = f'Bearer {TOKEN_PREFIX}{token.key}.{token.token}'
  1443. # Request with write-disabled token should fail
  1444. response = self.client.post(url, {}, format='json', HTTP_AUTHORIZATION=token_header)
  1445. self.assertHttpStatus(response, status.HTTP_403_FORBIDDEN)
  1446. # Enable write and retry
  1447. token.write_enabled = True
  1448. token.save()
  1449. response = self.client.post(url, {}, format='json', HTTP_AUTHORIZATION=token_header)
  1450. self.assertHttpStatus(response, status.HTTP_200_OK)
  1451. class ModuleTest(APIViewTestCases.APIViewTestCase):
  1452. model = Module
  1453. brief_fields = ['description', 'device', 'display', 'id', 'module_bay', 'module_type', 'url']
  1454. bulk_update_data = {
  1455. 'serial': '1234ABCD',
  1456. }
  1457. user_permissions = ('dcim.view_modulebay', 'dcim.view_moduletype', 'dcim.view_device')
  1458. @classmethod
  1459. def setUpTestData(cls):
  1460. manufacturer = Manufacturer.objects.create(name='Generic', slug='generic')
  1461. device = create_test_device('Test Device 1')
  1462. module_types = (
  1463. ModuleType(manufacturer=manufacturer, model='Module Type 1'),
  1464. ModuleType(manufacturer=manufacturer, model='Module Type 2'),
  1465. ModuleType(manufacturer=manufacturer, model='Module Type 3'),
  1466. )
  1467. ModuleType.objects.bulk_create(module_types)
  1468. module_bays = (
  1469. ModuleBay(device=device, name='Module Bay 1'),
  1470. ModuleBay(device=device, name='Module Bay 2'),
  1471. ModuleBay(device=device, name='Module Bay 3'),
  1472. ModuleBay(device=device, name='Module Bay 4'),
  1473. ModuleBay(device=device, name='Module Bay 5'),
  1474. ModuleBay(device=device, name='Module Bay 6'),
  1475. )
  1476. for module_bay in module_bays:
  1477. module_bay.save()
  1478. modules = (
  1479. Module(device=device, module_bay=module_bays[0], module_type=module_types[0]),
  1480. Module(device=device, module_bay=module_bays[1], module_type=module_types[1]),
  1481. Module(device=device, module_bay=module_bays[2], module_type=module_types[2]),
  1482. )
  1483. Module.objects.bulk_create(modules)
  1484. cls.create_data = [
  1485. {
  1486. 'device': device.pk,
  1487. 'module_bay': module_bays[3].pk,
  1488. 'module_type': module_types[0].pk,
  1489. 'status': ModuleStatusChoices.STATUS_ACTIVE,
  1490. 'serial': 'ABC123',
  1491. 'asset_tag': 'Foo1',
  1492. },
  1493. {
  1494. 'device': device.pk,
  1495. 'module_bay': module_bays[4].pk,
  1496. 'module_type': module_types[1].pk,
  1497. 'status': ModuleStatusChoices.STATUS_ACTIVE,
  1498. 'serial': 'DEF456',
  1499. 'asset_tag': 'Foo2',
  1500. },
  1501. {
  1502. 'device': device.pk,
  1503. 'module_bay': module_bays[5].pk,
  1504. 'module_type': module_types[2].pk,
  1505. 'status': ModuleStatusChoices.STATUS_ACTIVE,
  1506. 'serial': 'GHI789',
  1507. 'asset_tag': 'Foo3',
  1508. },
  1509. ]
  1510. class ConsolePortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase):
  1511. model = ConsolePort
  1512. brief_fields = ['_occupied', 'cable', 'description', 'device', 'display', 'id', 'name', 'url']
  1513. bulk_update_data = {
  1514. 'description': 'New description',
  1515. }
  1516. peer_termination_type = ConsoleServerPort
  1517. user_permissions = ('dcim.view_device', )
  1518. @classmethod
  1519. def setUpTestData(cls):
  1520. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  1521. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  1522. site = Site.objects.create(name='Site 1', slug='site-1')
  1523. role = DeviceRole.objects.create(name='Test Device Role 1', slug='test-device-role-1', color='ff0000')
  1524. device = Device.objects.create(device_type=devicetype, role=role, name='Device 1', site=site)
  1525. console_ports = (
  1526. ConsolePort(device=device, name='Console Port 1'),
  1527. ConsolePort(device=device, name='Console Port 2'),
  1528. ConsolePort(device=device, name='Console Port 3'),
  1529. )
  1530. ConsolePort.objects.bulk_create(console_ports)
  1531. cls.create_data = [
  1532. {
  1533. 'device': device.pk,
  1534. 'name': 'Console Port 4',
  1535. 'speed': 9600,
  1536. },
  1537. {
  1538. 'device': device.pk,
  1539. 'name': 'Console Port 5',
  1540. 'speed': 115200,
  1541. },
  1542. {
  1543. 'device': device.pk,
  1544. 'name': 'Console Port 6',
  1545. 'speed': None,
  1546. },
  1547. ]
  1548. class ConsoleServerPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase):
  1549. model = ConsoleServerPort
  1550. brief_fields = ['_occupied', 'cable', 'description', 'device', 'display', 'id', 'name', 'url']
  1551. bulk_update_data = {
  1552. 'description': 'New description',
  1553. }
  1554. peer_termination_type = ConsolePort
  1555. user_permissions = ('dcim.view_device', )
  1556. @classmethod
  1557. def setUpTestData(cls):
  1558. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  1559. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  1560. site = Site.objects.create(name='Site 1', slug='site-1')
  1561. role = DeviceRole.objects.create(name='Test Device Role 1', slug='test-device-role-1', color='ff0000')
  1562. device = Device.objects.create(device_type=devicetype, role=role, name='Device 1', site=site)
  1563. console_server_ports = (
  1564. ConsoleServerPort(device=device, name='Console Server Port 1'),
  1565. ConsoleServerPort(device=device, name='Console Server Port 2'),
  1566. ConsoleServerPort(device=device, name='Console Server Port 3'),
  1567. )
  1568. ConsoleServerPort.objects.bulk_create(console_server_ports)
  1569. cls.create_data = [
  1570. {
  1571. 'device': device.pk,
  1572. 'name': 'Console Server Port 4',
  1573. 'speed': 9600,
  1574. },
  1575. {
  1576. 'device': device.pk,
  1577. 'name': 'Console Server Port 5',
  1578. 'speed': 115200,
  1579. },
  1580. {
  1581. 'device': device.pk,
  1582. 'name': 'Console Server Port 6',
  1583. 'speed': None,
  1584. },
  1585. ]
  1586. class PowerPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase):
  1587. model = PowerPort
  1588. brief_fields = ['_occupied', 'cable', 'description', 'device', 'display', 'id', 'name', 'url']
  1589. bulk_update_data = {
  1590. 'description': 'New description',
  1591. }
  1592. peer_termination_type = PowerOutlet
  1593. user_permissions = ('dcim.view_device', )
  1594. @classmethod
  1595. def setUpTestData(cls):
  1596. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  1597. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  1598. site = Site.objects.create(name='Site 1', slug='site-1')
  1599. role = DeviceRole.objects.create(name='Test Device Role 1', slug='test-device-role-1', color='ff0000')
  1600. device = Device.objects.create(device_type=devicetype, role=role, name='Device 1', site=site)
  1601. power_ports = (
  1602. PowerPort(device=device, name='Power Port 1'),
  1603. PowerPort(device=device, name='Power Port 2'),
  1604. PowerPort(device=device, name='Power Port 3'),
  1605. )
  1606. PowerPort.objects.bulk_create(power_ports)
  1607. cls.create_data = [
  1608. {
  1609. 'device': device.pk,
  1610. 'name': 'Power Port 4',
  1611. },
  1612. {
  1613. 'device': device.pk,
  1614. 'name': 'Power Port 5',
  1615. },
  1616. {
  1617. 'device': device.pk,
  1618. 'name': 'Power Port 6',
  1619. },
  1620. ]
  1621. class PowerOutletTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase):
  1622. model = PowerOutlet
  1623. brief_fields = ['_occupied', 'cable', 'description', 'device', 'display', 'id', 'name', 'url']
  1624. bulk_update_data = {
  1625. 'description': 'New description',
  1626. }
  1627. peer_termination_type = PowerPort
  1628. user_permissions = ('dcim.view_device', )
  1629. @classmethod
  1630. def setUpTestData(cls):
  1631. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  1632. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  1633. site = Site.objects.create(name='Site 1', slug='site-1')
  1634. role = DeviceRole.objects.create(name='Test Device Role 1', slug='test-device-role-1', color='ff0000')
  1635. device = Device.objects.create(device_type=devicetype, role=role, name='Device 1', site=site)
  1636. power_ports = (
  1637. PowerPort(device=device, name='Power Port 1'),
  1638. PowerPort(device=device, name='Power Port 2'),
  1639. )
  1640. PowerPort.objects.bulk_create(power_ports)
  1641. power_outlets = (
  1642. PowerOutlet(device=device, name='Power Outlet 1'),
  1643. PowerOutlet(device=device, name='Power Outlet 2'),
  1644. PowerOutlet(device=device, name='Power Outlet 3'),
  1645. )
  1646. PowerOutlet.objects.bulk_create(power_outlets)
  1647. cls.create_data = [
  1648. {
  1649. 'device': device.pk,
  1650. 'name': 'Power Outlet 4',
  1651. 'power_port': power_ports[0].pk,
  1652. },
  1653. {
  1654. 'device': device.pk,
  1655. 'name': 'Power Outlet 5',
  1656. 'power_port': power_ports[1].pk,
  1657. },
  1658. {
  1659. 'device': device.pk,
  1660. 'name': 'Power Outlet 6',
  1661. 'power_port': None,
  1662. },
  1663. ]
  1664. class InterfaceTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase):
  1665. model = Interface
  1666. brief_fields = ['_occupied', 'cable', 'description', 'device', 'display', 'id', 'name', 'url']
  1667. bulk_update_data = {
  1668. 'description': 'New description',
  1669. }
  1670. peer_termination_type = Interface
  1671. user_permissions = ('dcim.view_device', )
  1672. @classmethod
  1673. def setUpTestData(cls):
  1674. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  1675. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  1676. site = Site.objects.create(name='Site 1', slug='site-1')
  1677. role = DeviceRole.objects.create(name='Test Device Role 1', slug='test-device-role-1', color='ff0000')
  1678. device = Device.objects.create(device_type=devicetype, role=role, name='Device 1', site=site)
  1679. interfaces = (
  1680. Interface(device=device, name='Interface 1', type='1000base-t'),
  1681. Interface(device=device, name='Interface 2', type='1000base-t'),
  1682. Interface(device=device, name='Interface 3', type='1000base-t'),
  1683. )
  1684. Interface.objects.bulk_create(interfaces)
  1685. vdcs = (
  1686. VirtualDeviceContext(name='VDC 1', identifier=1, device=device),
  1687. VirtualDeviceContext(name='VDC 2', identifier=2, device=device)
  1688. )
  1689. VirtualDeviceContext.objects.bulk_create(vdcs)
  1690. vlans = (
  1691. VLAN(name='VLAN 1', vid=1),
  1692. VLAN(name='VLAN 2', vid=2),
  1693. VLAN(name='VLAN 3', vid=3),
  1694. VLAN(name='SVLAN 1', vid=1001, qinq_role=VLANQinQRoleChoices.ROLE_SERVICE),
  1695. )
  1696. VLAN.objects.bulk_create(vlans)
  1697. wireless_lans = (
  1698. WirelessLAN(ssid='WLAN1'),
  1699. WirelessLAN(ssid='WLAN2'),
  1700. )
  1701. WirelessLAN.objects.bulk_create(wireless_lans)
  1702. vrfs = (
  1703. VRF(name='VRF 1'),
  1704. VRF(name='VRF 2'),
  1705. VRF(name='VRF 3'),
  1706. )
  1707. VRF.objects.bulk_create(vrfs)
  1708. cls.create_data = [
  1709. {
  1710. 'device': device.pk,
  1711. 'name': 'Interface 4',
  1712. 'type': '1000base-t',
  1713. 'mode': InterfaceModeChoices.MODE_TAGGED,
  1714. 'speed': 1000000,
  1715. 'duplex': 'full',
  1716. 'vrf': vrfs[0].pk,
  1717. 'poe_mode': InterfacePoEModeChoices.MODE_PD,
  1718. 'poe_type': InterfacePoETypeChoices.TYPE_1_8023AF,
  1719. 'tagged_vlans': [vlans[0].pk, vlans[1].pk],
  1720. 'untagged_vlan': vlans[2].pk,
  1721. },
  1722. {
  1723. 'device': device.pk,
  1724. 'name': 'Interface 5',
  1725. 'type': '1000base-t',
  1726. 'mode': InterfaceModeChoices.MODE_TAGGED,
  1727. 'bridge': interfaces[0].pk,
  1728. 'speed': 100000,
  1729. 'duplex': 'half',
  1730. 'vrf': vrfs[1].pk,
  1731. 'tagged_vlans': [vlans[0].pk, vlans[1].pk],
  1732. 'untagged_vlan': vlans[2].pk,
  1733. },
  1734. {
  1735. 'device': device.pk,
  1736. 'vdcs': [vdcs[0].pk],
  1737. 'name': 'Interface 6',
  1738. 'type': 'virtual',
  1739. 'mode': InterfaceModeChoices.MODE_TAGGED,
  1740. 'parent': interfaces[1].pk,
  1741. 'vrf': vrfs[2].pk,
  1742. 'tagged_vlans': [vlans[0].pk, vlans[1].pk],
  1743. 'untagged_vlan': vlans[2].pk,
  1744. },
  1745. {
  1746. 'device': device.pk,
  1747. 'vdcs': [vdcs[1].pk],
  1748. 'name': 'Interface 7',
  1749. 'type': InterfaceTypeChoices.TYPE_80211A,
  1750. 'mode': InterfaceModeChoices.MODE_Q_IN_Q,
  1751. 'tx_power': 10,
  1752. 'wireless_lans': [wireless_lans[0].pk, wireless_lans[1].pk],
  1753. 'rf_channel': WirelessChannelChoices.CHANNEL_5G_32,
  1754. 'qinq_svlan': vlans[3].pk,
  1755. },
  1756. {
  1757. 'device': device.pk,
  1758. 'vdcs': [vdcs[1].pk],
  1759. 'name': 'Interface 8',
  1760. 'type': InterfaceTypeChoices.TYPE_80211A,
  1761. 'mode': InterfaceModeChoices.MODE_Q_IN_Q,
  1762. 'tx_power': 10,
  1763. 'wireless_lans': [wireless_lans[0].pk, wireless_lans[1].pk],
  1764. 'rf_channel': "",
  1765. 'qinq_svlan': vlans[3].pk,
  1766. },
  1767. ]
  1768. def _perform_interface_test_with_invalid_data(self, mode: str = None, invalid_data: dict = {}):
  1769. device = Device.objects.first()
  1770. data = {
  1771. 'device': device.pk,
  1772. 'name': 'Interface 1',
  1773. 'type': InterfaceTypeChoices.TYPE_1GE_FIXED,
  1774. }
  1775. data.update({'mode': mode})
  1776. data.update(invalid_data)
  1777. response = self.client.post(self._get_list_url(), data, format='json', **self.header)
  1778. self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
  1779. content = json.loads(response.content)
  1780. for key in invalid_data.keys():
  1781. self.assertIn(key, content)
  1782. self.assertIsNone(content.get('data'))
  1783. def test_bulk_delete_child_interfaces(self):
  1784. interface1 = Interface.objects.get(name='Interface 1')
  1785. device = interface1.device
  1786. self.add_permissions('dcim.delete_interface')
  1787. # Create a child interface
  1788. child = Interface.objects.create(
  1789. device=device,
  1790. name='Interface 1A',
  1791. type=InterfaceTypeChoices.TYPE_VIRTUAL,
  1792. parent=interface1
  1793. )
  1794. self.assertEqual(device.interfaces.count(), 4)
  1795. # Attempt to delete only the parent interface
  1796. url = self._get_detail_url(interface1)
  1797. with disable_logging():
  1798. self.client.delete(url, **self.header)
  1799. self.assertEqual(device.interfaces.count(), 4) # Parent was not deleted
  1800. # Attempt to bulk delete parent & child together
  1801. data = [
  1802. {"id": interface1.pk},
  1803. {"id": child.pk},
  1804. ]
  1805. self.client.delete(self._get_list_url(), data, format='json', **self.header)
  1806. self.assertEqual(device.interfaces.count(), 2) # Child & parent were both deleted
  1807. def test_create_child_interfaces_mode_invalid_data(self):
  1808. """
  1809. POST data to test interface mode check and invalid tagged/untagged VLANS.
  1810. """
  1811. self.add_permissions('dcim.add_interface')
  1812. vlans = VLAN.objects.all()[0:3]
  1813. # Routed mode, untagged, tagged and qinq service vlan
  1814. invalid_data = {
  1815. 'untagged_vlan': vlans[0].pk,
  1816. 'tagged_vlans': [vlans[1].pk, vlans[2].pk],
  1817. 'qinq_svlan': vlans[2].pk
  1818. }
  1819. self._perform_interface_test_with_invalid_data(None, invalid_data)
  1820. # Routed mode, untagged and tagged vlan
  1821. invalid_data = {
  1822. 'untagged_vlan': vlans[0].pk,
  1823. 'tagged_vlans': [vlans[1].pk, vlans[2].pk],
  1824. }
  1825. self._perform_interface_test_with_invalid_data(None, invalid_data)
  1826. # Routed mode, untagged vlan
  1827. invalid_data = {
  1828. 'untagged_vlan': vlans[0].pk,
  1829. }
  1830. self._perform_interface_test_with_invalid_data(None, invalid_data)
  1831. invalid_data = {
  1832. 'tagged_vlans': [vlans[1].pk, vlans[2].pk],
  1833. }
  1834. # Routed mode, qinq service vlan
  1835. self._perform_interface_test_with_invalid_data(None, invalid_data)
  1836. # Access mode, tagged vlans
  1837. self._perform_interface_test_with_invalid_data(InterfaceModeChoices.MODE_ACCESS, invalid_data)
  1838. # All tagged mode, tagged vlans
  1839. self._perform_interface_test_with_invalid_data(InterfaceModeChoices.MODE_TAGGED_ALL, invalid_data)
  1840. invalid_data = {
  1841. 'qinq_svlan': vlans[0].pk,
  1842. }
  1843. # Routed mode, qinq service vlan
  1844. self._perform_interface_test_with_invalid_data(None, invalid_data)
  1845. # Access mode, qinq service vlan
  1846. self._perform_interface_test_with_invalid_data(InterfaceModeChoices.MODE_ACCESS, invalid_data)
  1847. # Tagged mode, qinq service vlan
  1848. self._perform_interface_test_with_invalid_data(InterfaceModeChoices.MODE_TAGGED, invalid_data)
  1849. # Tagged-all mode, qinq service vlan
  1850. self._perform_interface_test_with_invalid_data(InterfaceModeChoices.MODE_TAGGED_ALL, invalid_data)
  1851. class FrontPortTest(APIViewTestCases.APIViewTestCase):
  1852. model = FrontPort
  1853. brief_fields = ['_occupied', 'cable', 'description', 'device', 'display', 'id', 'name', 'url']
  1854. bulk_update_data = {
  1855. 'description': 'New description',
  1856. }
  1857. peer_termination_type = Interface
  1858. user_permissions = ('dcim.view_device', 'dcim.view_rearport')
  1859. @classmethod
  1860. def setUpTestData(cls):
  1861. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  1862. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  1863. site = Site.objects.create(name='Site 1', slug='site-1')
  1864. role = DeviceRole.objects.create(name='Test Device Role 1', slug='test-device-role-1', color='ff0000')
  1865. device = Device.objects.create(device_type=devicetype, role=role, name='Device 1', site=site)
  1866. rear_ports = (
  1867. RearPort(device=device, name='Rear Port 1', type=PortTypeChoices.TYPE_8P8C),
  1868. RearPort(device=device, name='Rear Port 2', type=PortTypeChoices.TYPE_8P8C),
  1869. RearPort(device=device, name='Rear Port 3', type=PortTypeChoices.TYPE_8P8C),
  1870. RearPort(device=device, name='Rear Port 4', type=PortTypeChoices.TYPE_8P8C),
  1871. RearPort(device=device, name='Rear Port 5', type=PortTypeChoices.TYPE_8P8C),
  1872. RearPort(device=device, name='Rear Port 6', type=PortTypeChoices.TYPE_8P8C),
  1873. )
  1874. RearPort.objects.bulk_create(rear_ports)
  1875. front_ports = (
  1876. FrontPort(device=device, name='Front Port 1', type=PortTypeChoices.TYPE_8P8C),
  1877. FrontPort(device=device, name='Front Port 2', type=PortTypeChoices.TYPE_8P8C),
  1878. FrontPort(device=device, name='Front Port 3', type=PortTypeChoices.TYPE_8P8C),
  1879. )
  1880. FrontPort.objects.bulk_create(front_ports)
  1881. PortMapping.objects.bulk_create([
  1882. PortMapping(device=device, front_port=front_ports[0], rear_port=rear_ports[0]),
  1883. PortMapping(device=device, front_port=front_ports[1], rear_port=rear_ports[1]),
  1884. PortMapping(device=device, front_port=front_ports[2], rear_port=rear_ports[2]),
  1885. ])
  1886. cls.create_data = [
  1887. {
  1888. 'device': device.pk,
  1889. 'name': 'Front Port 4',
  1890. 'type': PortTypeChoices.TYPE_8P8C,
  1891. 'rear_ports': [
  1892. {
  1893. 'position': 1,
  1894. 'rear_port': rear_ports[3].pk,
  1895. 'rear_port_position': 1,
  1896. },
  1897. ],
  1898. },
  1899. {
  1900. 'device': device.pk,
  1901. 'name': 'Front Port 5',
  1902. 'type': PortTypeChoices.TYPE_8P8C,
  1903. 'rear_ports': [
  1904. {
  1905. 'position': 1,
  1906. 'rear_port': rear_ports[4].pk,
  1907. 'rear_port_position': 1,
  1908. },
  1909. ],
  1910. },
  1911. {
  1912. 'device': device.pk,
  1913. 'name': 'Front Port 6',
  1914. 'type': PortTypeChoices.TYPE_8P8C,
  1915. 'rear_ports': [
  1916. {
  1917. 'position': 1,
  1918. 'rear_port': rear_ports[5].pk,
  1919. 'rear_port_position': 1,
  1920. },
  1921. ],
  1922. },
  1923. ]
  1924. cls.update_data = {
  1925. 'type': PortTypeChoices.TYPE_LC,
  1926. 'rear_ports': [
  1927. {
  1928. 'position': 1,
  1929. 'rear_port': rear_ports[3].pk,
  1930. 'rear_port_position': 1,
  1931. },
  1932. ],
  1933. }
  1934. def test_update_object(self):
  1935. super().test_update_object()
  1936. # Check that the port mapping was updated after modifying the front port
  1937. front_port = FrontPort.objects.get(name='Front Port 1')
  1938. rear_port = RearPort.objects.get(name='Rear Port 4')
  1939. self.assertTrue(
  1940. PortMapping.objects.filter(
  1941. front_port=front_port,
  1942. front_port_position=1,
  1943. rear_port=rear_port,
  1944. rear_port_position=1,
  1945. ).exists()
  1946. )
  1947. @tag('regression') # Issue #18991
  1948. def test_front_port_paths(self):
  1949. device = Device.objects.first()
  1950. interface1 = Interface.objects.create(device=device, name='Interface 1')
  1951. rear_port = RearPort.objects.create(device=device, name='Rear Port 10', type=PortTypeChoices.TYPE_8P8C)
  1952. front_port = FrontPort.objects.create(device=device, name='Front Port 10', type=PortTypeChoices.TYPE_8P8C)
  1953. PortMapping.objects.create(device=device, front_port=front_port, rear_port=rear_port)
  1954. Cable.objects.create(a_terminations=[interface1], b_terminations=[front_port])
  1955. self.add_permissions(f'dcim.view_{self.model._meta.model_name}')
  1956. url = reverse(f'dcim-api:{self.model._meta.model_name}-paths', kwargs={'pk': front_port.pk})
  1957. response = self.client.get(url, **self.header)
  1958. self.assertHttpStatus(response, status.HTTP_200_OK)
  1959. class RearPortTest(APIViewTestCases.APIViewTestCase):
  1960. model = RearPort
  1961. brief_fields = ['_occupied', 'cable', 'description', 'device', 'display', 'id', 'name', 'url']
  1962. bulk_update_data = {
  1963. 'description': 'New description',
  1964. }
  1965. peer_termination_type = Interface
  1966. user_permissions = ('dcim.view_device', )
  1967. @classmethod
  1968. def setUpTestData(cls):
  1969. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  1970. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  1971. site = Site.objects.create(name='Site 1', slug='site-1')
  1972. role = DeviceRole.objects.create(name='Test Device Role 1', slug='test-device-role-1', color='ff0000')
  1973. device = Device.objects.create(device_type=devicetype, role=role, name='Device 1', site=site)
  1974. front_ports = (
  1975. FrontPort(device=device, name='Front Port 1', type=PortTypeChoices.TYPE_8P8C),
  1976. FrontPort(device=device, name='Front Port 2', type=PortTypeChoices.TYPE_8P8C),
  1977. FrontPort(device=device, name='Front Port 3', type=PortTypeChoices.TYPE_8P8C),
  1978. FrontPort(device=device, name='Front Port 4', type=PortTypeChoices.TYPE_8P8C),
  1979. FrontPort(device=device, name='Front Port 5', type=PortTypeChoices.TYPE_8P8C),
  1980. FrontPort(device=device, name='Front Port 6', type=PortTypeChoices.TYPE_8P8C),
  1981. )
  1982. FrontPort.objects.bulk_create(front_ports)
  1983. rear_ports = (
  1984. RearPort(device=device, name='Rear Port 1', type=PortTypeChoices.TYPE_8P8C),
  1985. RearPort(device=device, name='Rear Port 2', type=PortTypeChoices.TYPE_8P8C),
  1986. RearPort(device=device, name='Rear Port 3', type=PortTypeChoices.TYPE_8P8C),
  1987. )
  1988. RearPort.objects.bulk_create(rear_ports)
  1989. cls.create_data = [
  1990. {
  1991. 'device': device.pk,
  1992. 'name': 'Rear Port 4',
  1993. 'type': PortTypeChoices.TYPE_8P8C,
  1994. 'front_ports': [
  1995. {
  1996. 'position': 1,
  1997. 'front_port': front_ports[3].pk,
  1998. 'front_port_position': 1,
  1999. },
  2000. ],
  2001. },
  2002. {
  2003. 'device': device.pk,
  2004. 'name': 'Rear Port 5',
  2005. 'type': PortTypeChoices.TYPE_8P8C,
  2006. 'front_ports': [
  2007. {
  2008. 'position': 1,
  2009. 'front_port': front_ports[4].pk,
  2010. 'front_port_position': 1,
  2011. },
  2012. ],
  2013. },
  2014. {
  2015. 'device': device.pk,
  2016. 'name': 'Rear Port 6',
  2017. 'type': PortTypeChoices.TYPE_8P8C,
  2018. 'front_ports': [
  2019. {
  2020. 'position': 1,
  2021. 'front_port': front_ports[5].pk,
  2022. 'front_port_position': 1,
  2023. },
  2024. ],
  2025. },
  2026. ]
  2027. cls.update_data = {
  2028. 'type': PortTypeChoices.TYPE_LC,
  2029. 'front_ports': [
  2030. {
  2031. 'position': 1,
  2032. 'front_port': front_ports[3].pk,
  2033. 'front_port_position': 1,
  2034. },
  2035. ],
  2036. }
  2037. def test_update_object(self):
  2038. super().test_update_object()
  2039. # Check that the port mapping was updated after modifying the rear port
  2040. front_port = FrontPort.objects.get(name='Front Port 4')
  2041. rear_port = RearPort.objects.get(name='Rear Port 1')
  2042. self.assertTrue(
  2043. PortMapping.objects.filter(
  2044. front_port=front_port,
  2045. front_port_position=1,
  2046. rear_port=rear_port,
  2047. rear_port_position=1,
  2048. ).exists()
  2049. )
  2050. @tag('regression') # Issue #18991
  2051. def test_rear_port_paths(self):
  2052. device = Device.objects.first()
  2053. interface1 = Interface.objects.create(device=device, name='Interface 1')
  2054. rear_port = RearPort.objects.create(
  2055. device=device,
  2056. name='Rear Port 10',
  2057. type=PortTypeChoices.TYPE_8P8C,
  2058. )
  2059. Cable.objects.create(a_terminations=[interface1], b_terminations=[rear_port])
  2060. self.add_permissions(f'dcim.view_{self.model._meta.model_name}')
  2061. url = reverse(f'dcim-api:{self.model._meta.model_name}-paths', kwargs={'pk': rear_port.pk})
  2062. response = self.client.get(url, **self.header)
  2063. self.assertHttpStatus(response, status.HTTP_200_OK)
  2064. class ModuleBayTest(APIViewTestCases.APIViewTestCase):
  2065. model = ModuleBay
  2066. brief_fields = ['description', 'display', 'id', 'installed_module', 'name', 'url']
  2067. bulk_update_data = {
  2068. 'description': 'New description',
  2069. }
  2070. user_permissions = ('dcim.view_device', )
  2071. @classmethod
  2072. def setUpTestData(cls):
  2073. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  2074. site = Site.objects.create(name='Site 1', slug='site-1')
  2075. role = DeviceRole.objects.create(name='Test Device Role 1', slug='test-device-role-1', color='ff0000')
  2076. device_type = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  2077. device = Device.objects.create(device_type=device_type, role=role, name='Device 1', site=site)
  2078. module_bays = (
  2079. ModuleBay(device=device, name='Device Bay 1'),
  2080. ModuleBay(device=device, name='Device Bay 2'),
  2081. ModuleBay(device=device, name='Device Bay 3'),
  2082. )
  2083. for module_bay in module_bays:
  2084. module_bay.save()
  2085. cls.create_data = [
  2086. {
  2087. 'device': device.pk,
  2088. 'name': 'Device Bay 4',
  2089. },
  2090. {
  2091. 'device': device.pk,
  2092. 'name': 'Device Bay 5',
  2093. },
  2094. {
  2095. 'device': device.pk,
  2096. 'name': 'Device Bay 6',
  2097. },
  2098. ]
  2099. class DeviceBayTest(APIViewTestCases.APIViewTestCase):
  2100. model = DeviceBay
  2101. brief_fields = ['description', 'device', 'display', 'id', 'name', 'url']
  2102. bulk_update_data = {
  2103. 'description': 'New description',
  2104. }
  2105. user_permissions = ('dcim.view_device', )
  2106. @classmethod
  2107. def setUpTestData(cls):
  2108. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  2109. site = Site.objects.create(name='Site 1', slug='site-1')
  2110. role = DeviceRole.objects.create(name='Test Device Role 1', slug='test-device-role-1', color='ff0000')
  2111. device_types = (
  2112. DeviceType(
  2113. manufacturer=manufacturer,
  2114. model='Device Type 1',
  2115. slug='device-type-1',
  2116. subdevice_role=SubdeviceRoleChoices.ROLE_PARENT
  2117. ),
  2118. DeviceType(
  2119. manufacturer=manufacturer,
  2120. model='Device Type 2',
  2121. slug='device-type-2',
  2122. subdevice_role=SubdeviceRoleChoices.ROLE_CHILD
  2123. ),
  2124. )
  2125. DeviceType.objects.bulk_create(device_types)
  2126. devices = (
  2127. Device(device_type=device_types[0], role=role, name='Device 1', site=site),
  2128. Device(device_type=device_types[1], role=role, name='Device 2', site=site),
  2129. Device(device_type=device_types[1], role=role, name='Device 3', site=site),
  2130. Device(device_type=device_types[1], role=role, name='Device 4', site=site),
  2131. )
  2132. Device.objects.bulk_create(devices)
  2133. device_bays = (
  2134. DeviceBay(device=devices[0], name='Device Bay 1'),
  2135. DeviceBay(device=devices[0], name='Device Bay 2'),
  2136. DeviceBay(device=devices[0], name='Device Bay 3'),
  2137. )
  2138. DeviceBay.objects.bulk_create(device_bays)
  2139. cls.create_data = [
  2140. {
  2141. 'device': devices[0].pk,
  2142. 'name': 'Device Bay 4',
  2143. 'installed_device': devices[1].pk,
  2144. },
  2145. {
  2146. 'device': devices[0].pk,
  2147. 'name': 'Device Bay 5',
  2148. 'installed_device': devices[2].pk,
  2149. },
  2150. {
  2151. 'device': devices[0].pk,
  2152. 'name': 'Device Bay 6',
  2153. 'installed_device': devices[3].pk,
  2154. },
  2155. ]
  2156. class InventoryItemTest(APIViewTestCases.APIViewTestCase):
  2157. model = InventoryItem
  2158. brief_fields = ['_depth', 'description', 'device', 'display', 'id', 'name', 'url']
  2159. bulk_update_data = {
  2160. 'description': 'New description',
  2161. }
  2162. user_permissions = ('dcim.view_device', 'dcim.view_manufacturer')
  2163. @classmethod
  2164. def setUpTestData(cls):
  2165. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  2166. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  2167. site = Site.objects.create(name='Site 1', slug='site-1')
  2168. role = DeviceRole.objects.create(name='Test Device Role 1', slug='test-device-role-1', color='ff0000')
  2169. device = Device.objects.create(device_type=devicetype, role=role, name='Device 1', site=site)
  2170. roles = (
  2171. InventoryItemRole(name='Inventory Item Role 1', slug='inventory-item-role-1'),
  2172. InventoryItemRole(name='Inventory Item Role 2', slug='inventory-item-role-2'),
  2173. )
  2174. InventoryItemRole.objects.bulk_create(roles)
  2175. interfaces = (
  2176. Interface(device=device, name='Interface 1'),
  2177. Interface(device=device, name='Interface 2'),
  2178. Interface(device=device, name='Interface 3'),
  2179. )
  2180. Interface.objects.bulk_create(interfaces)
  2181. InventoryItem.objects.create(
  2182. device=device, name='Inventory Item 1', role=roles[0], manufacturer=manufacturer, component=interfaces[0]
  2183. )
  2184. InventoryItem.objects.create(
  2185. device=device, name='Inventory Item 2', role=roles[0], manufacturer=manufacturer, component=interfaces[1]
  2186. )
  2187. InventoryItem.objects.create(
  2188. device=device, name='Inventory Item 3', role=roles[0], manufacturer=manufacturer, component=interfaces[2]
  2189. )
  2190. cls.create_data = [
  2191. {
  2192. 'device': device.pk,
  2193. 'name': 'Inventory Item 4',
  2194. 'role': roles[1].pk,
  2195. 'manufacturer': manufacturer.pk,
  2196. 'component_type': 'dcim.interface',
  2197. 'component_id': interfaces[0].pk,
  2198. },
  2199. {
  2200. 'device': device.pk,
  2201. 'name': 'Inventory Item 5',
  2202. 'role': roles[1].pk,
  2203. 'manufacturer': manufacturer.pk,
  2204. 'component_type': 'dcim.interface',
  2205. 'component_id': interfaces[1].pk,
  2206. },
  2207. {
  2208. 'device': device.pk,
  2209. 'name': 'Inventory Item 6',
  2210. 'role': roles[1].pk,
  2211. 'manufacturer': manufacturer.pk,
  2212. 'component_type': 'dcim.interface',
  2213. 'component_id': interfaces[2].pk,
  2214. },
  2215. ]
  2216. class InventoryItemRoleTest(APIViewTestCases.APIViewTestCase):
  2217. model = InventoryItemRole
  2218. brief_fields = ['description', 'display', 'id', 'inventoryitem_count', 'name', 'slug', 'url']
  2219. create_data = [
  2220. {
  2221. 'name': 'Inventory Item Role 4',
  2222. 'slug': 'inventory-item-role-4',
  2223. 'color': 'ffff00',
  2224. },
  2225. {
  2226. 'name': 'Inventory Item Role 5',
  2227. 'slug': 'inventory-item-role-5',
  2228. 'color': 'ffff00',
  2229. },
  2230. {
  2231. 'name': 'Inventory Item Role 6',
  2232. 'slug': 'inventory-item-role-6',
  2233. 'color': 'ffff00',
  2234. },
  2235. ]
  2236. bulk_update_data = {
  2237. 'description': 'New description',
  2238. }
  2239. @classmethod
  2240. def setUpTestData(cls):
  2241. roles = (
  2242. InventoryItemRole(name='Inventory Item Role 1', slug='inventory-item-role-1', color='ff0000'),
  2243. InventoryItemRole(name='Inventory Item Role 2', slug='inventory-item-role-2', color='00ff00'),
  2244. InventoryItemRole(name='Inventory Item Role 3', slug='inventory-item-role-3', color='0000ff'),
  2245. )
  2246. InventoryItemRole.objects.bulk_create(roles)
  2247. class CableTest(APIViewTestCases.APIViewTestCase):
  2248. model = Cable
  2249. brief_fields = ['description', 'display', 'id', 'label', 'url']
  2250. bulk_update_data = {
  2251. 'length': 100,
  2252. 'length_unit': 'm',
  2253. }
  2254. # TODO: Allow updating cable terminations
  2255. test_update_object = None
  2256. def model_to_dict(self, *args, **kwargs):
  2257. data = super().model_to_dict(*args, **kwargs)
  2258. # Serialize termination objects
  2259. if 'a_terminations' in data:
  2260. data['a_terminations'] = GenericObjectSerializer(data['a_terminations'], many=True).data
  2261. if 'b_terminations' in data:
  2262. data['b_terminations'] = GenericObjectSerializer(data['b_terminations'], many=True).data
  2263. return data
  2264. @classmethod
  2265. def setUpTestData(cls):
  2266. site = Site.objects.create(name='Site 1', slug='site-1')
  2267. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  2268. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  2269. role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1', color='ff0000')
  2270. devices = (
  2271. Device(device_type=devicetype, role=role, name='Device 1', site=site),
  2272. Device(device_type=devicetype, role=role, name='Device 2', site=site),
  2273. )
  2274. Device.objects.bulk_create(devices)
  2275. interfaces = []
  2276. for device in devices:
  2277. for i in range(0, 10):
  2278. interfaces.append(Interface(device=device, type=InterfaceTypeChoices.TYPE_1GE_FIXED, name=f'eth{i}'))
  2279. Interface.objects.bulk_create(interfaces)
  2280. cables = (
  2281. Cable(a_terminations=[interfaces[0]], b_terminations=[interfaces[10]], label='Cable 1'),
  2282. Cable(a_terminations=[interfaces[1]], b_terminations=[interfaces[11]], label='Cable 2'),
  2283. Cable(a_terminations=[interfaces[2]], b_terminations=[interfaces[12]], label='Cable 3'),
  2284. )
  2285. for cable in cables:
  2286. cable.save()
  2287. cls.create_data = [
  2288. {
  2289. 'a_terminations': [{
  2290. 'object_type': 'dcim.interface',
  2291. 'object_id': interfaces[4].pk,
  2292. }],
  2293. 'b_terminations': [{
  2294. 'object_type': 'dcim.interface',
  2295. 'object_id': interfaces[14].pk,
  2296. }],
  2297. 'label': 'Cable 4',
  2298. 'profile': CableProfileChoices.SINGLE_1C1P,
  2299. },
  2300. {
  2301. 'a_terminations': [{
  2302. 'object_type': 'dcim.interface',
  2303. 'object_id': interfaces[5].pk,
  2304. }],
  2305. 'b_terminations': [{
  2306. 'object_type': 'dcim.interface',
  2307. 'object_id': interfaces[15].pk,
  2308. }],
  2309. 'label': 'Cable 5',
  2310. 'profile': CableProfileChoices.SINGLE_1C1P,
  2311. },
  2312. {
  2313. 'a_terminations': [{
  2314. 'object_type': 'dcim.interface',
  2315. 'object_id': interfaces[6].pk,
  2316. }],
  2317. 'b_terminations': [{
  2318. 'object_type': 'dcim.interface',
  2319. 'object_id': interfaces[16].pk,
  2320. }],
  2321. 'label': 'Cable 6',
  2322. # No profile (legacy behavior)
  2323. },
  2324. ]
  2325. class CableTerminationTest(
  2326. APIViewTestCases.GetObjectViewTestCase,
  2327. APIViewTestCases.ListObjectsViewTestCase,
  2328. ):
  2329. model = CableTermination
  2330. brief_fields = [
  2331. 'cable', 'cable_end', 'connector', 'display', 'id', 'positions', 'termination_id', 'termination_type', 'url',
  2332. ]
  2333. @classmethod
  2334. def setUpTestData(cls):
  2335. device1 = create_test_device('Device 1')
  2336. device2 = create_test_device('Device 2')
  2337. interfaces = []
  2338. for device in (device1, device2):
  2339. for i in range(0, 10):
  2340. interfaces.append(Interface(device=device, type=InterfaceTypeChoices.TYPE_1GE_FIXED, name=f'eth{i}'))
  2341. Interface.objects.bulk_create(interfaces)
  2342. cables = (
  2343. Cable(a_terminations=[interfaces[0]], b_terminations=[interfaces[10]], label='Cable 1'),
  2344. Cable(a_terminations=[interfaces[1]], b_terminations=[interfaces[11]], label='Cable 2'),
  2345. Cable(a_terminations=[interfaces[2]], b_terminations=[interfaces[12]], label='Cable 3'),
  2346. )
  2347. for cable in cables:
  2348. cable.save()
  2349. class ConnectedDeviceTest(APITestCase):
  2350. @classmethod
  2351. def setUpTestData(cls):
  2352. site = Site.objects.create(name='Site 1', slug='site-1')
  2353. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  2354. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  2355. role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1', color='ff0000')
  2356. devices = (
  2357. Device(device_type=devicetype, role=role, name='TestDevice1', site=site),
  2358. Device(device_type=devicetype, role=role, name='TestDevice2', site=site),
  2359. )
  2360. Device.objects.bulk_create(devices)
  2361. interfaces = (
  2362. Interface(device=devices[0], name='eth0'),
  2363. Interface(device=devices[1], name='eth0'),
  2364. Interface(device=devices[0], name='eth1'), # Not connected
  2365. )
  2366. Interface.objects.bulk_create(interfaces)
  2367. cable = Cable(a_terminations=[interfaces[0]], b_terminations=[interfaces[1]])
  2368. cable.save()
  2369. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  2370. def test_get_connected_device(self):
  2371. url = reverse('dcim-api:connected-device-list')
  2372. url_params = '?peer_device=TestDevice1&peer_interface=eth0'
  2373. response = self.client.get(url + url_params, **self.header)
  2374. self.assertHttpStatus(response, status.HTTP_200_OK)
  2375. self.assertEqual(response.data['name'], 'TestDevice2')
  2376. url_params = '?peer_device=TestDevice1&peer_interface=eth1'
  2377. response = self.client.get(url + url_params, **self.header)
  2378. self.assertHttpStatus(response, status.HTTP_404_NOT_FOUND)
  2379. class VirtualChassisTest(APIViewTestCases.APIViewTestCase):
  2380. model = VirtualChassis
  2381. brief_fields = ['description', 'display', 'id', 'master', 'member_count', 'name', 'url']
  2382. @classmethod
  2383. def setUpTestData(cls):
  2384. site = Site.objects.create(name='Test Site', slug='test-site')
  2385. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  2386. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type', slug='device-type')
  2387. role = DeviceRole.objects.create(name='Device Role', slug='device-role', color='ff0000')
  2388. devices = (
  2389. Device(name='Device 1', device_type=devicetype, role=role, site=site),
  2390. Device(name='Device 2', device_type=devicetype, role=role, site=site),
  2391. Device(name='Device 3', device_type=devicetype, role=role, site=site),
  2392. Device(name='Device 4', device_type=devicetype, role=role, site=site),
  2393. Device(name='Device 5', device_type=devicetype, role=role, site=site),
  2394. Device(name='Device 6', device_type=devicetype, role=role, site=site),
  2395. Device(name='Device 7', device_type=devicetype, role=role, site=site),
  2396. Device(name='Device 8', device_type=devicetype, role=role, site=site),
  2397. Device(name='Device 9', device_type=devicetype, role=role, site=site),
  2398. Device(name='Device 10', device_type=devicetype, role=role, site=site),
  2399. Device(name='Device 11', device_type=devicetype, role=role, site=site),
  2400. Device(name='Device 12', device_type=devicetype, role=role, site=site),
  2401. )
  2402. Device.objects.bulk_create(devices)
  2403. # Create 12 interfaces per device
  2404. interfaces = []
  2405. for i, device in enumerate(devices):
  2406. for j in range(0, 13):
  2407. interfaces.append(
  2408. # Interface name starts with parent device's position in VC; e.g. 1/1, 1/2, 1/3...
  2409. Interface(device=device, name=f'{i % 3 + 1}/{j}', type=InterfaceTypeChoices.TYPE_1GE_FIXED)
  2410. )
  2411. Interface.objects.bulk_create(interfaces)
  2412. # Create three VirtualChassis with three members each
  2413. virtual_chassis = (
  2414. VirtualChassis(name='Virtual Chassis 1', master=devices[0], domain='domain-1'),
  2415. VirtualChassis(name='Virtual Chassis 2', master=devices[3], domain='domain-2'),
  2416. VirtualChassis(name='Virtual Chassis 3', master=devices[6], domain='domain-3'),
  2417. )
  2418. VirtualChassis.objects.bulk_create(virtual_chassis)
  2419. Device.objects.filter(pk=devices[0].pk).update(virtual_chassis=virtual_chassis[0], vc_position=1)
  2420. Device.objects.filter(pk=devices[1].pk).update(virtual_chassis=virtual_chassis[0], vc_position=2)
  2421. Device.objects.filter(pk=devices[2].pk).update(virtual_chassis=virtual_chassis[0], vc_position=3)
  2422. Device.objects.filter(pk=devices[3].pk).update(virtual_chassis=virtual_chassis[1], vc_position=1)
  2423. Device.objects.filter(pk=devices[4].pk).update(virtual_chassis=virtual_chassis[1], vc_position=2)
  2424. Device.objects.filter(pk=devices[5].pk).update(virtual_chassis=virtual_chassis[1], vc_position=3)
  2425. Device.objects.filter(pk=devices[6].pk).update(virtual_chassis=virtual_chassis[2], vc_position=1)
  2426. Device.objects.filter(pk=devices[7].pk).update(virtual_chassis=virtual_chassis[2], vc_position=2)
  2427. Device.objects.filter(pk=devices[8].pk).update(virtual_chassis=virtual_chassis[2], vc_position=3)
  2428. cls.update_data = {
  2429. 'name': 'Virtual Chassis X',
  2430. 'domain': 'domain-x',
  2431. 'master': devices[1].pk,
  2432. }
  2433. cls.create_data = [
  2434. {
  2435. 'name': 'Virtual Chassis 4',
  2436. 'domain': 'domain-4',
  2437. },
  2438. {
  2439. 'name': 'Virtual Chassis 5',
  2440. 'domain': 'domain-5',
  2441. },
  2442. {
  2443. 'name': 'Virtual Chassis 6',
  2444. 'domain': 'domain-6',
  2445. },
  2446. ]
  2447. cls.bulk_update_data = {
  2448. 'domain': 'newdomain',
  2449. 'master': None
  2450. }
  2451. class PowerPanelTest(APIViewTestCases.APIViewTestCase):
  2452. model = PowerPanel
  2453. brief_fields = ['description', 'display', 'id', 'name', 'powerfeed_count', 'url']
  2454. user_permissions = ('dcim.view_site', )
  2455. @classmethod
  2456. def setUpTestData(cls):
  2457. sites = (
  2458. Site.objects.create(name='Site 1', slug='site-1'),
  2459. Site.objects.create(name='Site 2', slug='site-2'),
  2460. )
  2461. locations = (
  2462. Location.objects.create(name='Location 1', slug='location-1', site=sites[0]),
  2463. Location.objects.create(name='Location 2', slug='location-2', site=sites[0]),
  2464. Location.objects.create(name='Location 3', slug='location-3', site=sites[0]),
  2465. Location.objects.create(name='Location 4', slug='location-3', site=sites[1]),
  2466. )
  2467. power_panels = (
  2468. PowerPanel(site=sites[0], location=locations[0], name='Power Panel 1'),
  2469. PowerPanel(site=sites[0], location=locations[1], name='Power Panel 2'),
  2470. PowerPanel(site=sites[0], location=locations[2], name='Power Panel 3'),
  2471. )
  2472. PowerPanel.objects.bulk_create(power_panels)
  2473. cls.create_data = [
  2474. {
  2475. 'name': 'Power Panel 4',
  2476. 'site': sites[0].pk,
  2477. 'location': locations[0].pk,
  2478. },
  2479. {
  2480. 'name': 'Power Panel 5',
  2481. 'site': sites[0].pk,
  2482. 'location': locations[1].pk,
  2483. },
  2484. {
  2485. 'name': 'Power Panel 6',
  2486. 'site': sites[0].pk,
  2487. 'location': locations[2].pk,
  2488. },
  2489. ]
  2490. cls.bulk_update_data = {
  2491. 'site': sites[1].pk,
  2492. 'location': locations[3].pk
  2493. }
  2494. class PowerFeedTest(APIViewTestCases.APIViewTestCase):
  2495. model = PowerFeed
  2496. brief_fields = ['_occupied', 'cable', 'description', 'display', 'id', 'name', 'url']
  2497. bulk_update_data = {
  2498. 'status': 'planned',
  2499. }
  2500. user_permissions = ('dcim.view_powerpanel', )
  2501. @classmethod
  2502. def setUpTestData(cls):
  2503. site = Site.objects.create(name='Site 1', slug='site-1')
  2504. location = Location.objects.create(site=site, name='Location 1', slug='location-1')
  2505. rackrole = RackRole.objects.create(name='Rack Role 1', slug='rack-role-1', color='ff0000')
  2506. racks = (
  2507. Rack(site=site, location=location, role=rackrole, name='Rack 1'),
  2508. Rack(site=site, location=location, role=rackrole, name='Rack 2'),
  2509. Rack(site=site, location=location, role=rackrole, name='Rack 3'),
  2510. Rack(site=site, location=location, role=rackrole, name='Rack 4'),
  2511. )
  2512. Rack.objects.bulk_create(racks)
  2513. power_panels = (
  2514. PowerPanel(site=site, location=location, name='Power Panel 1'),
  2515. PowerPanel(site=site, location=location, name='Power Panel 2'),
  2516. )
  2517. PowerPanel.objects.bulk_create(power_panels)
  2518. PRIMARY = PowerFeedTypeChoices.TYPE_PRIMARY
  2519. REDUNDANT = PowerFeedTypeChoices.TYPE_REDUNDANT
  2520. power_feeds = (
  2521. PowerFeed(power_panel=power_panels[0], rack=racks[0], name='Power Feed 1A', type=PRIMARY),
  2522. PowerFeed(power_panel=power_panels[1], rack=racks[0], name='Power Feed 1B', type=REDUNDANT),
  2523. PowerFeed(power_panel=power_panels[0], rack=racks[1], name='Power Feed 2A', type=PRIMARY),
  2524. PowerFeed(power_panel=power_panels[1], rack=racks[1], name='Power Feed 2B', type=REDUNDANT),
  2525. PowerFeed(power_panel=power_panels[0], rack=racks[2], name='Power Feed 3A', type=PRIMARY),
  2526. PowerFeed(power_panel=power_panels[1], rack=racks[2], name='Power Feed 3B', type=REDUNDANT),
  2527. )
  2528. PowerFeed.objects.bulk_create(power_feeds)
  2529. cls.create_data = [
  2530. {
  2531. 'name': 'Power Feed 4A',
  2532. 'power_panel': power_panels[0].pk,
  2533. 'rack': racks[3].pk,
  2534. 'type': PRIMARY,
  2535. },
  2536. {
  2537. 'name': 'Power Feed 4B',
  2538. 'power_panel': power_panels[1].pk,
  2539. 'rack': racks[3].pk,
  2540. 'type': REDUNDANT,
  2541. },
  2542. ]
  2543. class VirtualDeviceContextTest(APIViewTestCases.APIViewTestCase):
  2544. model = VirtualDeviceContext
  2545. brief_fields = ['description', 'device', 'display', 'id', 'identifier', 'name', 'url']
  2546. bulk_update_data = {
  2547. 'status': 'planned',
  2548. }
  2549. @classmethod
  2550. def setUpTestData(cls):
  2551. site = Site.objects.create(name='Test Site', slug='test-site')
  2552. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  2553. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type', slug='device-type')
  2554. role = DeviceRole.objects.create(name='Device Role', slug='device-role', color='ff0000')
  2555. devices = (
  2556. Device(name='Device 1', device_type=devicetype, role=role, site=site),
  2557. Device(name='Device 2', device_type=devicetype, role=role, site=site),
  2558. Device(name='Device 3', device_type=devicetype, role=role, site=site),
  2559. )
  2560. Device.objects.bulk_create(devices)
  2561. vdcs = (
  2562. VirtualDeviceContext(device=devices[1], name='VDC 1', identifier=1, status='active'),
  2563. VirtualDeviceContext(device=devices[1], name='VDC 2', identifier=2, status='active'),
  2564. VirtualDeviceContext(device=devices[2], name='VDC 1', identifier=1, status='active'),
  2565. VirtualDeviceContext(device=devices[2], name='VDC 2', identifier=2, status='active'),
  2566. VirtualDeviceContext(device=devices[2], name='VDC 3', identifier=3, status='active'),
  2567. VirtualDeviceContext(device=devices[2], name='VDC 4', identifier=4, status='active'),
  2568. VirtualDeviceContext(device=devices[2], name='VDC 5', identifier=5, status='active'),
  2569. )
  2570. VirtualDeviceContext.objects.bulk_create(vdcs)
  2571. cls.create_data = [
  2572. {
  2573. 'device': devices[0].pk,
  2574. 'status': 'active',
  2575. 'name': 'VDC 1',
  2576. 'identifier': 1,
  2577. },
  2578. {
  2579. 'device': devices[0].pk,
  2580. 'status': 'active',
  2581. 'name': 'VDC 2',
  2582. 'identifier': 2,
  2583. },
  2584. {
  2585. 'device': devices[1].pk,
  2586. 'status': 'active',
  2587. 'name': 'VDC 3',
  2588. # Omit identifier to test uniqueness constraint
  2589. },
  2590. ]
  2591. class MACAddressTest(APIViewTestCases.APIViewTestCase):
  2592. model = MACAddress
  2593. brief_fields = ['description', 'display', 'id', 'mac_address', 'url']
  2594. bulk_update_data = {
  2595. 'description': 'New description',
  2596. }
  2597. @classmethod
  2598. def setUpTestData(cls):
  2599. device = create_test_device(name='Device 1')
  2600. interfaces = (
  2601. Interface(device=device, name='Interface 1', type='1000base-t'),
  2602. Interface(device=device, name='Interface 2', type='1000base-t'),
  2603. Interface(device=device, name='Interface 3', type='1000base-t'),
  2604. Interface(device=device, name='Interface 4', type='1000base-t'),
  2605. Interface(device=device, name='Interface 5', type='1000base-t'),
  2606. )
  2607. Interface.objects.bulk_create(interfaces)
  2608. mac_addresses = (
  2609. MACAddress(mac_address='00:00:00:00:00:01', assigned_object=interfaces[0]),
  2610. MACAddress(mac_address='00:00:00:00:00:02', assigned_object=interfaces[1]),
  2611. MACAddress(mac_address='00:00:00:00:00:03', assigned_object=interfaces[2]),
  2612. )
  2613. MACAddress.objects.bulk_create(mac_addresses)
  2614. cls.create_data = [
  2615. {
  2616. 'mac_address': '00:00:00:00:00:04',
  2617. 'assigned_object_type': 'dcim.interface',
  2618. 'assigned_object_id': interfaces[3].pk,
  2619. },
  2620. {
  2621. 'mac_address': '00:00:00:00:00:05',
  2622. 'assigned_object_type': 'dcim.interface',
  2623. 'assigned_object_id': interfaces[4].pk,
  2624. },
  2625. {
  2626. 'mac_address': '00:00:00:00:00:06',
  2627. },
  2628. ]