test_views.py 128 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523
  1. from decimal import Decimal
  2. from zoneinfo import ZoneInfo
  3. import yaml
  4. from django.test import override_settings
  5. from django.urls import reverse
  6. from netaddr import EUI
  7. from dcim.choices import *
  8. from dcim.constants import *
  9. from dcim.models import *
  10. from ipam.models import ASN, RIR, VLAN, VRF
  11. from netbox.choices import CSVDelimiterChoices, ImportFormatChoices, WeightUnitChoices
  12. from tenancy.models import Tenant
  13. from users.models import User
  14. from utilities.testing import ViewTestCases, create_tags, create_test_device, post_data
  15. from wireless.models import WirelessLAN
  16. class RegionTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
  17. model = Region
  18. @classmethod
  19. def setUpTestData(cls):
  20. # Create three Regions
  21. regions = (
  22. Region(name='Region 1', slug='region-1'),
  23. Region(name='Region 2', slug='region-2'),
  24. Region(name='Region 3', slug='region-3'),
  25. )
  26. for region in regions:
  27. region.save()
  28. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  29. cls.form_data = {
  30. 'name': 'Region X',
  31. 'slug': 'region-x',
  32. 'parent': regions[2].pk,
  33. 'description': 'A new region',
  34. 'tags': [t.pk for t in tags],
  35. }
  36. cls.csv_data = (
  37. "name,slug,description",
  38. "Region 4,region-4,Fourth region",
  39. "Region 5,region-5,Fifth region",
  40. "Region 6,region-6,Sixth region",
  41. )
  42. cls.csv_update_data = (
  43. "id,name,description",
  44. f"{regions[0].pk},Region 7,Fourth region7",
  45. f"{regions[1].pk},Region 8,Fifth region8",
  46. f"{regions[2].pk},Region 0,Sixth region9",
  47. )
  48. cls.bulk_edit_data = {
  49. 'description': 'New description',
  50. }
  51. class SiteGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
  52. model = SiteGroup
  53. @classmethod
  54. def setUpTestData(cls):
  55. # Create three SiteGroups
  56. sitegroups = (
  57. SiteGroup(name='Site Group 1', slug='site-group-1'),
  58. SiteGroup(name='Site Group 2', slug='site-group-2'),
  59. SiteGroup(name='Site Group 3', slug='site-group-3'),
  60. )
  61. for sitegroup in sitegroups:
  62. sitegroup.save()
  63. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  64. cls.form_data = {
  65. 'name': 'Site Group X',
  66. 'slug': 'site-group-x',
  67. 'parent': sitegroups[2].pk,
  68. 'description': 'A new site group',
  69. 'tags': [t.pk for t in tags],
  70. }
  71. cls.csv_data = (
  72. "name,slug,description",
  73. "Site Group 4,site-group-4,Fourth site group",
  74. "Site Group 5,site-group-5,Fifth site group",
  75. "Site Group 6,site-group-6,Sixth site group",
  76. )
  77. cls.csv_update_data = (
  78. "id,name,description",
  79. f"{sitegroups[0].pk},Site Group 7,Fourth site group7",
  80. f"{sitegroups[1].pk},Site Group 8,Fifth site group8",
  81. f"{sitegroups[2].pk},Site Group 0,Sixth site group9",
  82. )
  83. cls.bulk_edit_data = {
  84. 'description': 'New description',
  85. }
  86. class SiteTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  87. model = Site
  88. @classmethod
  89. def setUpTestData(cls):
  90. regions = (
  91. Region(name='Region 1', slug='region-1'),
  92. Region(name='Region 2', slug='region-2'),
  93. )
  94. for region in regions:
  95. region.save()
  96. groups = (
  97. SiteGroup(name='Site Group 1', slug='site-group-1'),
  98. SiteGroup(name='Site Group 2', slug='site-group-2'),
  99. )
  100. for group in groups:
  101. group.save()
  102. rir = RIR.objects.create(name='RFC 6996', is_private=True)
  103. asns = [
  104. ASN(asn=65000 + i, rir=rir) for i in range(8)
  105. ]
  106. ASN.objects.bulk_create(asns)
  107. sites = Site.objects.bulk_create([
  108. Site(name='Site 1', slug='site-1', region=regions[0], group=groups[1]),
  109. Site(name='Site 2', slug='site-2', region=regions[0], group=groups[1]),
  110. Site(name='Site 3', slug='site-3', region=regions[0], group=groups[1]),
  111. ])
  112. sites[0].asns.set([asns[0], asns[1]])
  113. sites[1].asns.set([asns[2], asns[3]])
  114. sites[2].asns.set([asns[4], asns[5]])
  115. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  116. cls.form_data = {
  117. 'name': 'Site X',
  118. 'slug': 'site-x',
  119. 'status': SiteStatusChoices.STATUS_PLANNED,
  120. 'region': regions[1].pk,
  121. 'group': groups[1].pk,
  122. 'tenant': None,
  123. 'facility': 'Facility X',
  124. 'asns': [asns[6].pk, asns[7].pk],
  125. 'time_zone': ZoneInfo('UTC'),
  126. 'description': 'Site description',
  127. 'physical_address': '742 Evergreen Terrace, Springfield, USA',
  128. 'shipping_address': '742 Evergreen Terrace, Springfield, USA',
  129. 'latitude': Decimal('35.780000'),
  130. 'longitude': Decimal('-78.642000'),
  131. 'comments': 'Test site',
  132. 'tags': [t.pk for t in tags],
  133. }
  134. cls.csv_data = (
  135. "name,slug,status",
  136. "Site 4,site-4,planned",
  137. "Site 5,site-5,active",
  138. "Site 6,site-6,staging",
  139. )
  140. cls.csv_update_data = (
  141. "id,name,status",
  142. f"{sites[0].pk},Site 7,staging",
  143. f"{sites[1].pk},Site 8,planned",
  144. f"{sites[2].pk},Site 9,active",
  145. )
  146. cls.bulk_edit_data = {
  147. 'status': SiteStatusChoices.STATUS_PLANNED,
  148. 'region': regions[1].pk,
  149. 'group': groups[1].pk,
  150. 'tenant': None,
  151. 'time_zone': ZoneInfo('US/Eastern'),
  152. 'description': 'New description',
  153. }
  154. class LocationTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
  155. model = Location
  156. @classmethod
  157. def setUpTestData(cls):
  158. site = Site.objects.create(name='Site 1', slug='site-1')
  159. tenant = Tenant.objects.create(name='Tenant 1', slug='tenant-1')
  160. locations = (
  161. Location(
  162. name='Location 1',
  163. slug='location-1',
  164. site=site,
  165. status=LocationStatusChoices.STATUS_ACTIVE,
  166. tenant=tenant,
  167. ),
  168. Location(
  169. name='Location 2',
  170. slug='location-2',
  171. site=site,
  172. status=LocationStatusChoices.STATUS_ACTIVE,
  173. tenant=tenant,
  174. ),
  175. Location(
  176. name='Location 3',
  177. slug='location-3',
  178. site=site,
  179. status=LocationStatusChoices.STATUS_ACTIVE,
  180. tenant=tenant,
  181. ),
  182. )
  183. for location in locations:
  184. location.save()
  185. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  186. cls.form_data = {
  187. 'name': 'Location X',
  188. 'slug': 'location-x',
  189. 'site': site.pk,
  190. 'status': LocationStatusChoices.STATUS_PLANNED,
  191. 'facility': 'Facility X',
  192. 'tenant': tenant.pk,
  193. 'description': 'A new location',
  194. 'tags': [t.pk for t in tags],
  195. }
  196. cls.csv_data = (
  197. "site,tenant,name,slug,status,description",
  198. "Site 1,Tenant 1,Location 4,location-4,planned,Fourth location",
  199. "Site 1,Tenant 1,Location 5,location-5,planned,Fifth location",
  200. "Site 1,Tenant 1,Location 6,location-6,planned,Sixth location",
  201. )
  202. cls.csv_update_data = (
  203. "id,name,description",
  204. f"{locations[0].pk},Location 7,Fourth location7",
  205. f"{locations[1].pk},Location 8,Fifth location8",
  206. f"{locations[2].pk},Location 0,Sixth location9",
  207. )
  208. cls.bulk_edit_data = {
  209. 'description': 'New description',
  210. }
  211. class RackRoleTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
  212. model = RackRole
  213. @classmethod
  214. def setUpTestData(cls):
  215. rack_roles = (
  216. RackRole(name='Rack Role 1', slug='rack-role-1'),
  217. RackRole(name='Rack Role 2', slug='rack-role-2'),
  218. RackRole(name='Rack Role 3', slug='rack-role-3'),
  219. )
  220. RackRole.objects.bulk_create(rack_roles)
  221. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  222. cls.form_data = {
  223. 'name': 'Rack Role X',
  224. 'slug': 'rack-role-x',
  225. 'color': 'c0c0c0',
  226. 'description': 'New role',
  227. 'tags': [t.pk for t in tags],
  228. }
  229. cls.csv_data = (
  230. "name,slug,color",
  231. "Rack Role 4,rack-role-4,ff0000",
  232. "Rack Role 5,rack-role-5,00ff00",
  233. "Rack Role 6,rack-role-6,0000ff",
  234. )
  235. cls.csv_update_data = (
  236. "id,name,description",
  237. f"{rack_roles[0].pk},Rack Role 7,New description7",
  238. f"{rack_roles[1].pk},Rack Role 8,New description8",
  239. f"{rack_roles[2].pk},Rack Role 9,New description9",
  240. )
  241. cls.bulk_edit_data = {
  242. 'color': '00ff00',
  243. 'description': 'New description',
  244. }
  245. class RackReservationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  246. model = RackReservation
  247. @classmethod
  248. def setUpTestData(cls):
  249. user2 = User.objects.create_user(username='testuser2')
  250. user3 = User.objects.create_user(username='testuser3')
  251. site = Site.objects.create(name='Site 1', slug='site-1')
  252. location = Location(name='Location 1', slug='location-1', site=site)
  253. location.save()
  254. rack = Rack(name='Rack 1', site=site, location=location)
  255. rack.save()
  256. rack_reservations = (
  257. RackReservation(rack=rack, user=user2, units=[1, 2, 3], description='Reservation 1'),
  258. RackReservation(rack=rack, user=user2, units=[4, 5, 6], description='Reservation 2'),
  259. RackReservation(rack=rack, user=user2, units=[7, 8, 9], description='Reservation 3'),
  260. )
  261. RackReservation.objects.bulk_create(rack_reservations)
  262. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  263. cls.form_data = {
  264. 'rack': rack.pk,
  265. 'units': "10,11,12",
  266. 'user': user3.pk,
  267. 'tenant': None,
  268. 'description': 'Rack reservation',
  269. 'tags': [t.pk for t in tags],
  270. }
  271. cls.csv_data = (
  272. 'site,location,rack,units,description',
  273. 'Site 1,Location 1,Rack 1,"10,11,12",Reservation 1',
  274. 'Site 1,Location 1,Rack 1,"13,14,15",Reservation 2',
  275. 'Site 1,Location 1,Rack 1,"16,17,18",Reservation 3',
  276. )
  277. cls.csv_update_data = (
  278. 'id,description',
  279. f'{rack_reservations[0].pk},New description1',
  280. f'{rack_reservations[1].pk},New description2',
  281. f'{rack_reservations[2].pk},New description3',
  282. )
  283. cls.bulk_edit_data = {
  284. 'user': user3.pk,
  285. 'tenant': None,
  286. 'description': 'New description',
  287. }
  288. class RackTypeTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  289. model = RackType
  290. @classmethod
  291. def setUpTestData(cls):
  292. manufacturers = (
  293. Manufacturer(name='Manufacturer 1', slug='manufacturer-1'),
  294. Manufacturer(name='Manufacturer 2', slug='manufacturer-2'),
  295. )
  296. Manufacturer.objects.bulk_create(manufacturers)
  297. rack_types = (
  298. RackType(
  299. manufacturer=manufacturers[0],
  300. model='RackType 1',
  301. slug='rack-type-1',
  302. form_factor=RackFormFactorChoices.TYPE_CABINET,
  303. ),
  304. RackType(
  305. manufacturer=manufacturers[0],
  306. model='RackType 2',
  307. slug='rack-type-2',
  308. form_factor=RackFormFactorChoices.TYPE_CABINET,
  309. ),
  310. RackType(
  311. manufacturer=manufacturers[0],
  312. model='RackType 3',
  313. slug='rack-type-3',
  314. form_factor=RackFormFactorChoices.TYPE_CABINET,
  315. ),
  316. )
  317. RackType.objects.bulk_create(rack_types)
  318. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  319. cls.form_data = {
  320. 'manufacturer': manufacturers[1].pk,
  321. 'model': 'RackType X',
  322. 'slug': 'rack-type-x',
  323. 'type': RackFormFactorChoices.TYPE_CABINET,
  324. 'width': RackWidthChoices.WIDTH_19IN,
  325. 'u_height': 48,
  326. 'desc_units': False,
  327. 'outer_width': 500,
  328. 'outer_depth': 500,
  329. 'outer_unit': RackDimensionUnitChoices.UNIT_MILLIMETER,
  330. 'starting_unit': 1,
  331. 'weight': 100,
  332. 'max_weight': 2000,
  333. 'weight_unit': WeightUnitChoices.UNIT_POUND,
  334. 'form_factor': RackFormFactorChoices.TYPE_CABINET,
  335. 'comments': 'Some comments',
  336. 'tags': [t.pk for t in tags],
  337. }
  338. cls.csv_data = (
  339. "manufacturer,model,slug,width,u_height,weight,max_weight,weight_unit",
  340. "Manufacturer 1,RackType 4,rack-type-4,19,42,100,2000,kg",
  341. "Manufacturer 1,RackType 5,rack-type-5,19,42,100,2000,kg",
  342. "Manufacturer 1,RackType 6,rack-type-6,19,42,100,2000,kg",
  343. )
  344. cls.csv_update_data = (
  345. "id,model",
  346. f"{rack_types[0].pk},RackType 7",
  347. f"{rack_types[1].pk},RackType 8",
  348. f"{rack_types[2].pk},RackType 9",
  349. )
  350. cls.bulk_edit_data = {
  351. 'manufacturer': manufacturers[1].pk,
  352. 'type': RackFormFactorChoices.TYPE_4POST,
  353. 'width': RackWidthChoices.WIDTH_23IN,
  354. 'u_height': 49,
  355. 'desc_units': True,
  356. 'outer_width': 30,
  357. 'outer_depth': 30,
  358. 'outer_unit': RackDimensionUnitChoices.UNIT_INCH,
  359. 'weight': 200,
  360. 'max_weight': 4000,
  361. 'weight_unit': WeightUnitChoices.UNIT_POUND,
  362. 'comments': 'New comments',
  363. }
  364. class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  365. model = Rack
  366. @classmethod
  367. def setUpTestData(cls):
  368. sites = (
  369. Site(name='Site 1', slug='site-1'),
  370. Site(name='Site 2', slug='site-2'),
  371. )
  372. Site.objects.bulk_create(sites)
  373. locations = (
  374. Location(name='Location 1', slug='location-1', site=sites[0]),
  375. Location(name='Location 2', slug='location-2', site=sites[1])
  376. )
  377. for location in locations:
  378. location.save()
  379. rackroles = (
  380. RackRole(name='Rack Role 1', slug='rack-role-1'),
  381. RackRole(name='Rack Role 2', slug='rack-role-2'),
  382. )
  383. RackRole.objects.bulk_create(rackroles)
  384. racks = (
  385. Rack(name='Rack 1', site=sites[0]),
  386. Rack(name='Rack 2', site=sites[0]),
  387. Rack(name='Rack 3', site=sites[0]),
  388. )
  389. Rack.objects.bulk_create(racks)
  390. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  391. cls.form_data = {
  392. 'name': 'Rack X',
  393. 'facility_id': 'Facility X',
  394. 'site': sites[1].pk,
  395. 'location': locations[1].pk,
  396. 'tenant': None,
  397. 'status': RackStatusChoices.STATUS_PLANNED,
  398. 'role': rackroles[1].pk,
  399. 'serial': '123456',
  400. 'asset_tag': 'ABCDEF',
  401. 'form_factor': RackFormFactorChoices.TYPE_CABINET,
  402. 'width': RackWidthChoices.WIDTH_19IN,
  403. 'u_height': 48,
  404. 'desc_units': False,
  405. 'outer_width': 500,
  406. 'outer_depth': 500,
  407. 'outer_unit': RackDimensionUnitChoices.UNIT_MILLIMETER,
  408. 'starting_unit': 1,
  409. 'weight': 100,
  410. 'max_weight': 2000,
  411. 'weight_unit': WeightUnitChoices.UNIT_POUND,
  412. 'comments': 'Some comments',
  413. 'tags': [t.pk for t in tags],
  414. }
  415. cls.csv_data = (
  416. "site,location,name,status,width,u_height,weight,max_weight,weight_unit",
  417. "Site 1,,Rack 4,active,19,42,100,2000,kg",
  418. "Site 1,Location 1,Rack 5,active,19,42,100,2000,kg",
  419. "Site 2,Location 2,Rack 6,active,19,42,100,2000,kg",
  420. )
  421. cls.csv_update_data = (
  422. "id,name,status",
  423. f"{racks[0].pk},Rack 7,{RackStatusChoices.STATUS_DEPRECATED}",
  424. f"{racks[1].pk},Rack 8,{RackStatusChoices.STATUS_DEPRECATED}",
  425. f"{racks[2].pk},Rack 9,{RackStatusChoices.STATUS_DEPRECATED}",
  426. )
  427. cls.bulk_edit_data = {
  428. 'site': sites[1].pk,
  429. 'location': locations[1].pk,
  430. 'tenant': None,
  431. 'status': RackStatusChoices.STATUS_DEPRECATED,
  432. 'role': rackroles[1].pk,
  433. 'serial': '654321',
  434. 'form_factor': RackFormFactorChoices.TYPE_4POST,
  435. 'width': RackWidthChoices.WIDTH_23IN,
  436. 'u_height': 49,
  437. 'desc_units': True,
  438. 'outer_width': 30,
  439. 'outer_depth': 30,
  440. 'outer_unit': RackDimensionUnitChoices.UNIT_INCH,
  441. 'weight': 200,
  442. 'max_weight': 4000,
  443. 'weight_unit': WeightUnitChoices.UNIT_POUND,
  444. 'comments': 'New comments',
  445. }
  446. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  447. def test_list_rack_elevations(self):
  448. """
  449. Test viewing the list of rack elevations.
  450. """
  451. response = self.client.get(reverse('dcim:rack_elevation_list'))
  452. self.assertHttpStatus(response, 200)
  453. class ManufacturerTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
  454. model = Manufacturer
  455. @classmethod
  456. def setUpTestData(cls):
  457. manufacturers = (
  458. Manufacturer(name='Manufacturer 1', slug='manufacturer-1'),
  459. Manufacturer(name='Manufacturer 2', slug='manufacturer-2'),
  460. Manufacturer(name='Manufacturer 3', slug='manufacturer-3'),
  461. )
  462. Manufacturer.objects.bulk_create(manufacturers)
  463. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  464. cls.form_data = {
  465. 'name': 'Manufacturer X',
  466. 'slug': 'manufacturer-x',
  467. 'description': 'A new manufacturer',
  468. 'tags': [t.pk for t in tags],
  469. }
  470. cls.csv_data = (
  471. "name,slug,description",
  472. "Manufacturer 4,manufacturer-4,Fourth manufacturer",
  473. "Manufacturer 5,manufacturer-5,Fifth manufacturer",
  474. "Manufacturer 6,manufacturer-6,Sixth manufacturer",
  475. )
  476. cls.csv_update_data = (
  477. "id,name,description",
  478. f"{manufacturers[0].pk},Manufacturer 7,Fourth manufacturer7",
  479. f"{manufacturers[1].pk},Manufacturer 8,Fifth manufacturer8",
  480. f"{manufacturers[2].pk},Manufacturer 9,Sixth manufacturer9",
  481. )
  482. cls.bulk_edit_data = {
  483. 'description': 'New description',
  484. }
  485. # TODO: Change base class to PrimaryObjectViewTestCase
  486. # Blocked by absence of bulk import view for DeviceTypes
  487. class DeviceTypeTestCase(
  488. ViewTestCases.GetObjectViewTestCase,
  489. ViewTestCases.GetObjectChangelogViewTestCase,
  490. ViewTestCases.CreateObjectViewTestCase,
  491. ViewTestCases.EditObjectViewTestCase,
  492. ViewTestCases.DeleteObjectViewTestCase,
  493. ViewTestCases.ListObjectsViewTestCase,
  494. ViewTestCases.BulkEditObjectsViewTestCase,
  495. ViewTestCases.BulkDeleteObjectsViewTestCase
  496. ):
  497. model = DeviceType
  498. @classmethod
  499. def setUpTestData(cls):
  500. manufacturers = (
  501. Manufacturer(name='Manufacturer 1', slug='manufacturer-1'),
  502. Manufacturer(name='Manufacturer 2', slug='manufacturer-2')
  503. )
  504. Manufacturer.objects.bulk_create(manufacturers)
  505. platforms = (
  506. Platform(name='Platform 1', slug='platform-1', manufacturer=manufacturers[0]),
  507. Platform(name='Platform 2', slug='platform-3', manufacturer=manufacturers[1]),
  508. )
  509. Platform.objects.bulk_create(platforms)
  510. DeviceType.objects.bulk_create([
  511. DeviceType(model='Device Type 1', slug='device-type-1', manufacturer=manufacturers[0]),
  512. DeviceType(model='Device Type 2', slug='device-type-2', manufacturer=manufacturers[0]),
  513. DeviceType(model='Device Type 3', slug='device-type-3', manufacturer=manufacturers[0]),
  514. ])
  515. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  516. cls.form_data = {
  517. 'manufacturer': manufacturers[1].pk,
  518. 'default_platform': platforms[0].pk,
  519. 'model': 'Device Type X',
  520. 'slug': 'device-type-x',
  521. 'part_number': '123ABC',
  522. 'u_height': 2,
  523. 'is_full_depth': True,
  524. 'subdevice_role': None,
  525. 'comments': 'Some comments',
  526. 'tags': [t.pk for t in tags],
  527. }
  528. cls.bulk_edit_data = {
  529. 'manufacturer': manufacturers[1].pk,
  530. 'default_platform': platforms[1].pk,
  531. 'u_height': 3,
  532. 'is_full_depth': False,
  533. }
  534. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  535. def test_devicetype_consoleports(self):
  536. devicetype = DeviceType.objects.first()
  537. console_ports = (
  538. ConsolePortTemplate(device_type=devicetype, name='Console Port 1'),
  539. ConsolePortTemplate(device_type=devicetype, name='Console Port 2'),
  540. ConsolePortTemplate(device_type=devicetype, name='Console Port 3'),
  541. )
  542. ConsolePortTemplate.objects.bulk_create(console_ports)
  543. url = reverse('dcim:devicetype_consoleports', kwargs={'pk': devicetype.pk})
  544. self.assertHttpStatus(self.client.get(url), 200)
  545. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  546. def test_devicetype_consoleserverports(self):
  547. devicetype = DeviceType.objects.first()
  548. console_server_ports = (
  549. ConsoleServerPortTemplate(device_type=devicetype, name='Console Server Port 1'),
  550. ConsoleServerPortTemplate(device_type=devicetype, name='Console Server Port 2'),
  551. ConsoleServerPortTemplate(device_type=devicetype, name='Console Server Port 3'),
  552. )
  553. ConsoleServerPortTemplate.objects.bulk_create(console_server_ports)
  554. url = reverse('dcim:devicetype_consoleserverports', kwargs={'pk': devicetype.pk})
  555. self.assertHttpStatus(self.client.get(url), 200)
  556. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  557. def test_devicetype_powerports(self):
  558. devicetype = DeviceType.objects.first()
  559. power_ports = (
  560. PowerPortTemplate(device_type=devicetype, name='Power Port 1'),
  561. PowerPortTemplate(device_type=devicetype, name='Power Port 2'),
  562. PowerPortTemplate(device_type=devicetype, name='Power Port 3'),
  563. )
  564. PowerPortTemplate.objects.bulk_create(power_ports)
  565. url = reverse('dcim:devicetype_powerports', kwargs={'pk': devicetype.pk})
  566. self.assertHttpStatus(self.client.get(url), 200)
  567. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  568. def test_devicetype_poweroutlets(self):
  569. devicetype = DeviceType.objects.first()
  570. power_outlets = (
  571. PowerOutletTemplate(device_type=devicetype, name='Power Outlet 1'),
  572. PowerOutletTemplate(device_type=devicetype, name='Power Outlet 2'),
  573. PowerOutletTemplate(device_type=devicetype, name='Power Outlet 3'),
  574. )
  575. PowerOutletTemplate.objects.bulk_create(power_outlets)
  576. url = reverse('dcim:devicetype_poweroutlets', kwargs={'pk': devicetype.pk})
  577. self.assertHttpStatus(self.client.get(url), 200)
  578. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  579. def test_devicetype_interfaces(self):
  580. devicetype = DeviceType.objects.first()
  581. interfaces = (
  582. InterfaceTemplate(device_type=devicetype, name='Interface 1'),
  583. InterfaceTemplate(device_type=devicetype, name='Interface 2'),
  584. InterfaceTemplate(device_type=devicetype, name='Interface 3'),
  585. )
  586. InterfaceTemplate.objects.bulk_create(interfaces)
  587. url = reverse('dcim:devicetype_interfaces', kwargs={'pk': devicetype.pk})
  588. self.assertHttpStatus(self.client.get(url), 200)
  589. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  590. def test_devicetype_rearports(self):
  591. devicetype = DeviceType.objects.first()
  592. rear_ports = (
  593. RearPortTemplate(device_type=devicetype, name='Rear Port 1'),
  594. RearPortTemplate(device_type=devicetype, name='Rear Port 2'),
  595. RearPortTemplate(device_type=devicetype, name='Rear Port 3'),
  596. )
  597. RearPortTemplate.objects.bulk_create(rear_ports)
  598. url = reverse('dcim:devicetype_rearports', kwargs={'pk': devicetype.pk})
  599. self.assertHttpStatus(self.client.get(url), 200)
  600. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  601. def test_devicetype_frontports(self):
  602. devicetype = DeviceType.objects.first()
  603. rear_ports = (
  604. RearPortTemplate(device_type=devicetype, name='Rear Port 1'),
  605. RearPortTemplate(device_type=devicetype, name='Rear Port 2'),
  606. RearPortTemplate(device_type=devicetype, name='Rear Port 3'),
  607. )
  608. RearPortTemplate.objects.bulk_create(rear_ports)
  609. front_ports = (
  610. FrontPortTemplate(
  611. device_type=devicetype, name='Front Port 1', rear_port=rear_ports[0], rear_port_position=1
  612. ),
  613. FrontPortTemplate(
  614. device_type=devicetype, name='Front Port 2', rear_port=rear_ports[1], rear_port_position=1
  615. ),
  616. FrontPortTemplate(
  617. device_type=devicetype, name='Front Port 3', rear_port=rear_ports[2], rear_port_position=1
  618. ),
  619. )
  620. FrontPortTemplate.objects.bulk_create(front_ports)
  621. url = reverse('dcim:devicetype_frontports', kwargs={'pk': devicetype.pk})
  622. self.assertHttpStatus(self.client.get(url), 200)
  623. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  624. def test_devicetype_modulebays(self):
  625. devicetype = DeviceType.objects.first()
  626. module_bays = (
  627. ModuleBayTemplate(device_type=devicetype, name='Module Bay 1'),
  628. ModuleBayTemplate(device_type=devicetype, name='Module Bay 2'),
  629. ModuleBayTemplate(device_type=devicetype, name='Module Bay 3'),
  630. )
  631. ModuleBayTemplate.objects.bulk_create(module_bays)
  632. url = reverse('dcim:devicetype_modulebays', kwargs={'pk': devicetype.pk})
  633. self.assertHttpStatus(self.client.get(url), 200)
  634. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  635. def test_devicetype_devicebays(self):
  636. devicetype = DeviceType.objects.first()
  637. device_bays = (
  638. DeviceBayTemplate(device_type=devicetype, name='Device Bay 1'),
  639. DeviceBayTemplate(device_type=devicetype, name='Device Bay 2'),
  640. DeviceBayTemplate(device_type=devicetype, name='Device Bay 3'),
  641. )
  642. DeviceBayTemplate.objects.bulk_create(device_bays)
  643. url = reverse('dcim:devicetype_devicebays', kwargs={'pk': devicetype.pk})
  644. self.assertHttpStatus(self.client.get(url), 200)
  645. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  646. def test_devicetype_inventoryitems(self):
  647. devicetype = DeviceType.objects.first()
  648. inventory_items = (
  649. DeviceBayTemplate(device_type=devicetype, name='Device Bay 1'),
  650. DeviceBayTemplate(device_type=devicetype, name='Device Bay 2'),
  651. DeviceBayTemplate(device_type=devicetype, name='Device Bay 3'),
  652. )
  653. for inventory_item in inventory_items:
  654. inventory_item.save()
  655. url = reverse('dcim:devicetype_inventoryitems', kwargs={'pk': devicetype.pk})
  656. self.assertHttpStatus(self.client.get(url), 200)
  657. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  658. def test_import_objects(self):
  659. """
  660. Custom import test for YAML-based imports (versus CSV)
  661. """
  662. IMPORT_DATA = """
  663. manufacturer: Generic
  664. model: TEST-1000
  665. slug: test-1000
  666. default_platform: Platform
  667. u_height: 2
  668. is_full_depth: false
  669. airflow: front-to-rear
  670. subdevice_role: parent
  671. weight: 10
  672. weight_unit: kg
  673. comments: Test comment
  674. console-ports:
  675. - name: Console Port 1
  676. type: de-9
  677. - name: Console Port 2
  678. type: de-9
  679. - name: Console Port 3
  680. type: de-9
  681. console-server-ports:
  682. - name: Console Server Port 1
  683. type: rj-45
  684. - name: Console Server Port 2
  685. type: rj-45
  686. - name: Console Server Port 3
  687. type: rj-45
  688. power-ports:
  689. - name: Power Port 1
  690. type: iec-60320-c14
  691. - name: Power Port 2
  692. type: iec-60320-c14
  693. - name: Power Port 3
  694. type: iec-60320-c14
  695. power-outlets:
  696. - name: Power Outlet 1
  697. type: iec-60320-c13
  698. power_port: Power Port 1
  699. feed_leg: A
  700. - name: Power Outlet 2
  701. type: iec-60320-c13
  702. power_port: Power Port 1
  703. feed_leg: A
  704. - name: Power Outlet 3
  705. type: iec-60320-c13
  706. power_port: Power Port 1
  707. feed_leg: A
  708. interfaces:
  709. - name: Interface 1
  710. type: 1000base-t
  711. mgmt_only: true
  712. - name: Interface 2
  713. type: 1000base-t
  714. enabled: false
  715. - name: Interface 3
  716. type: 1000base-t
  717. rear-ports:
  718. - name: Rear Port 1
  719. type: 8p8c
  720. - name: Rear Port 2
  721. type: 8p8c
  722. - name: Rear Port 3
  723. type: 8p8c
  724. front-ports:
  725. - name: Front Port 1
  726. type: 8p8c
  727. rear_port: Rear Port 1
  728. - name: Front Port 2
  729. type: 8p8c
  730. rear_port: Rear Port 2
  731. - name: Front Port 3
  732. type: 8p8c
  733. rear_port: Rear Port 3
  734. module-bays:
  735. - name: Module Bay 1
  736. - name: Module Bay 2
  737. - name: Module Bay 3
  738. device-bays:
  739. - name: Device Bay 1
  740. - name: Device Bay 2
  741. - name: Device Bay 3
  742. inventory-items:
  743. - name: Inventory Item 1
  744. manufacturer: Generic
  745. - name: Inventory Item 2
  746. manufacturer: Generic
  747. - name: Inventory Item 3
  748. manufacturer: Generic
  749. """
  750. # Create the manufacturer and platform
  751. manufacturer = Manufacturer(name='Generic', slug='generic')
  752. manufacturer.save()
  753. platform = Platform(name='Platform', slug='test-platform', manufacturer=manufacturer)
  754. platform.save()
  755. # Add all required permissions to the test user
  756. self.add_permissions(
  757. 'dcim.view_devicetype',
  758. 'dcim.add_devicetype',
  759. 'dcim.add_consoleporttemplate',
  760. 'dcim.add_consoleserverporttemplate',
  761. 'dcim.add_powerporttemplate',
  762. 'dcim.add_poweroutlettemplate',
  763. 'dcim.add_interfacetemplate',
  764. 'dcim.add_frontporttemplate',
  765. 'dcim.add_rearporttemplate',
  766. 'dcim.add_modulebaytemplate',
  767. 'dcim.add_devicebaytemplate',
  768. 'dcim.add_inventoryitemtemplate',
  769. )
  770. form_data = {
  771. 'data': IMPORT_DATA,
  772. 'format': 'yaml'
  773. }
  774. response = self.client.post(reverse('dcim:devicetype_bulk_import'), data=form_data, follow=True)
  775. self.assertHttpStatus(response, 200)
  776. device_type = DeviceType.objects.get(model='TEST-1000')
  777. self.assertEqual(device_type.manufacturer.pk, manufacturer.pk)
  778. self.assertEqual(device_type.default_platform.pk, platform.pk)
  779. self.assertEqual(device_type.slug, 'test-1000')
  780. self.assertEqual(device_type.u_height, 2)
  781. self.assertFalse(device_type.is_full_depth)
  782. self.assertEqual(device_type.airflow, DeviceAirflowChoices.AIRFLOW_FRONT_TO_REAR)
  783. self.assertEqual(device_type.subdevice_role, SubdeviceRoleChoices.ROLE_PARENT)
  784. self.assertEqual(device_type.weight, 10)
  785. self.assertEqual(device_type.weight_unit, WeightUnitChoices.UNIT_KILOGRAM)
  786. self.assertEqual(device_type.comments, 'Test comment')
  787. # Verify all of the components were created
  788. self.assertEqual(device_type.consoleporttemplates.count(), 3)
  789. cp1 = ConsolePortTemplate.objects.first()
  790. self.assertEqual(cp1.name, 'Console Port 1')
  791. self.assertEqual(cp1.type, ConsolePortTypeChoices.TYPE_DE9)
  792. self.assertEqual(device_type.consoleserverporttemplates.count(), 3)
  793. csp1 = ConsoleServerPortTemplate.objects.first()
  794. self.assertEqual(csp1.name, 'Console Server Port 1')
  795. self.assertEqual(csp1.type, ConsolePortTypeChoices.TYPE_RJ45)
  796. self.assertEqual(device_type.powerporttemplates.count(), 3)
  797. pp1 = PowerPortTemplate.objects.first()
  798. self.assertEqual(pp1.name, 'Power Port 1')
  799. self.assertEqual(pp1.type, PowerPortTypeChoices.TYPE_IEC_C14)
  800. self.assertEqual(device_type.poweroutlettemplates.count(), 3)
  801. po1 = PowerOutletTemplate.objects.first()
  802. self.assertEqual(po1.name, 'Power Outlet 1')
  803. self.assertEqual(po1.type, PowerOutletTypeChoices.TYPE_IEC_C13)
  804. self.assertEqual(po1.power_port, pp1)
  805. self.assertEqual(po1.feed_leg, PowerOutletFeedLegChoices.FEED_LEG_A)
  806. self.assertEqual(device_type.interfacetemplates.count(), 3)
  807. iface1 = InterfaceTemplate.objects.first()
  808. self.assertEqual(iface1.name, 'Interface 1')
  809. self.assertEqual(iface1.type, InterfaceTypeChoices.TYPE_1GE_FIXED)
  810. self.assertTrue(iface1.mgmt_only)
  811. self.assertTrue(iface1.enabled)
  812. iface2 = InterfaceTemplate.objects.filter(name="Interface 2").first()
  813. self.assertFalse(iface2.enabled)
  814. self.assertEqual(device_type.rearporttemplates.count(), 3)
  815. rp1 = RearPortTemplate.objects.first()
  816. self.assertEqual(rp1.name, 'Rear Port 1')
  817. self.assertEqual(device_type.frontporttemplates.count(), 3)
  818. fp1 = FrontPortTemplate.objects.first()
  819. self.assertEqual(fp1.name, 'Front Port 1')
  820. self.assertEqual(fp1.rear_port, rp1)
  821. self.assertEqual(fp1.rear_port_position, 1)
  822. self.assertEqual(device_type.modulebaytemplates.count(), 3)
  823. mb1 = ModuleBayTemplate.objects.first()
  824. self.assertEqual(mb1.name, 'Module Bay 1')
  825. self.assertEqual(device_type.devicebaytemplates.count(), 3)
  826. db1 = DeviceBayTemplate.objects.first()
  827. self.assertEqual(db1.name, 'Device Bay 1')
  828. self.assertEqual(device_type.inventoryitemtemplates.count(), 3)
  829. ii1 = InventoryItemTemplate.objects.first()
  830. self.assertEqual(ii1.name, 'Inventory Item 1')
  831. def test_export_objects(self):
  832. url = reverse('dcim:devicetype_list')
  833. self.add_permissions('dcim.view_devicetype')
  834. # Test default YAML export
  835. response = self.client.get(f'{url}?export')
  836. self.assertEqual(response.status_code, 200)
  837. data = list(yaml.load_all(response.content, Loader=yaml.SafeLoader))
  838. self.assertEqual(len(data), 3)
  839. self.assertEqual(data[0]['manufacturer'], 'Manufacturer 1')
  840. self.assertEqual(data[0]['model'], 'Device Type 1')
  841. # Test table-based export
  842. response = self.client.get(f'{url}?export=table')
  843. self.assertHttpStatus(response, 200)
  844. self.assertEqual(response.get('Content-Type'), 'text/csv; charset=utf-8')
  845. # TODO: Change base class to PrimaryObjectViewTestCase
  846. # Blocked by absence of bulk import view for ModuleTypes
  847. class ModuleTypeTestCase(
  848. ViewTestCases.GetObjectViewTestCase,
  849. ViewTestCases.GetObjectChangelogViewTestCase,
  850. ViewTestCases.CreateObjectViewTestCase,
  851. ViewTestCases.EditObjectViewTestCase,
  852. ViewTestCases.DeleteObjectViewTestCase,
  853. ViewTestCases.ListObjectsViewTestCase,
  854. ViewTestCases.BulkEditObjectsViewTestCase,
  855. ViewTestCases.BulkDeleteObjectsViewTestCase
  856. ):
  857. model = ModuleType
  858. @classmethod
  859. def setUpTestData(cls):
  860. manufacturers = (
  861. Manufacturer(name='Manufacturer 1', slug='manufacturer-1'),
  862. Manufacturer(name='Manufacturer 2', slug='manufacturer-2')
  863. )
  864. Manufacturer.objects.bulk_create(manufacturers)
  865. ModuleType.objects.bulk_create([
  866. ModuleType(model='Module Type 1', manufacturer=manufacturers[0]),
  867. ModuleType(model='Module Type 2', manufacturer=manufacturers[0]),
  868. ModuleType(model='Module Type 3', manufacturer=manufacturers[0]),
  869. ])
  870. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  871. cls.form_data = {
  872. 'manufacturer': manufacturers[1].pk,
  873. 'model': 'Device Type X',
  874. 'part_number': '123ABC',
  875. 'comments': 'Some comments',
  876. 'tags': [t.pk for t in tags],
  877. }
  878. cls.bulk_edit_data = {
  879. 'manufacturer': manufacturers[1].pk,
  880. 'part_number': '456DEF',
  881. }
  882. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  883. def test_moduletype_consoleports(self):
  884. moduletype = ModuleType.objects.first()
  885. console_ports = (
  886. ConsolePortTemplate(module_type=moduletype, name='Console Port 1'),
  887. ConsolePortTemplate(module_type=moduletype, name='Console Port 2'),
  888. ConsolePortTemplate(module_type=moduletype, name='Console Port 3'),
  889. )
  890. ConsolePortTemplate.objects.bulk_create(console_ports)
  891. url = reverse('dcim:moduletype_consoleports', kwargs={'pk': moduletype.pk})
  892. self.assertHttpStatus(self.client.get(url), 200)
  893. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  894. def test_moduletype_consoleserverports(self):
  895. moduletype = ModuleType.objects.first()
  896. console_server_ports = (
  897. ConsoleServerPortTemplate(module_type=moduletype, name='Console Server Port 1'),
  898. ConsoleServerPortTemplate(module_type=moduletype, name='Console Server Port 2'),
  899. ConsoleServerPortTemplate(module_type=moduletype, name='Console Server Port 3'),
  900. )
  901. ConsoleServerPortTemplate.objects.bulk_create(console_server_ports)
  902. url = reverse('dcim:moduletype_consoleserverports', kwargs={'pk': moduletype.pk})
  903. self.assertHttpStatus(self.client.get(url), 200)
  904. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  905. def test_moduletype_powerports(self):
  906. moduletype = ModuleType.objects.first()
  907. power_ports = (
  908. PowerPortTemplate(module_type=moduletype, name='Power Port 1'),
  909. PowerPortTemplate(module_type=moduletype, name='Power Port 2'),
  910. PowerPortTemplate(module_type=moduletype, name='Power Port 3'),
  911. )
  912. PowerPortTemplate.objects.bulk_create(power_ports)
  913. url = reverse('dcim:moduletype_powerports', kwargs={'pk': moduletype.pk})
  914. self.assertHttpStatus(self.client.get(url), 200)
  915. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  916. def test_moduletype_poweroutlets(self):
  917. moduletype = ModuleType.objects.first()
  918. power_outlets = (
  919. PowerOutletTemplate(module_type=moduletype, name='Power Outlet 1'),
  920. PowerOutletTemplate(module_type=moduletype, name='Power Outlet 2'),
  921. PowerOutletTemplate(module_type=moduletype, name='Power Outlet 3'),
  922. )
  923. PowerOutletTemplate.objects.bulk_create(power_outlets)
  924. url = reverse('dcim:moduletype_poweroutlets', kwargs={'pk': moduletype.pk})
  925. self.assertHttpStatus(self.client.get(url), 200)
  926. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  927. def test_moduletype_interfaces(self):
  928. moduletype = ModuleType.objects.first()
  929. interfaces = (
  930. InterfaceTemplate(module_type=moduletype, name='Interface 1'),
  931. InterfaceTemplate(module_type=moduletype, name='Interface 2'),
  932. InterfaceTemplate(module_type=moduletype, name='Interface 3'),
  933. )
  934. InterfaceTemplate.objects.bulk_create(interfaces)
  935. url = reverse('dcim:moduletype_interfaces', kwargs={'pk': moduletype.pk})
  936. self.assertHttpStatus(self.client.get(url), 200)
  937. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  938. def test_moduletype_rearports(self):
  939. moduletype = ModuleType.objects.first()
  940. rear_ports = (
  941. RearPortTemplate(module_type=moduletype, name='Rear Port 1'),
  942. RearPortTemplate(module_type=moduletype, name='Rear Port 2'),
  943. RearPortTemplate(module_type=moduletype, name='Rear Port 3'),
  944. )
  945. RearPortTemplate.objects.bulk_create(rear_ports)
  946. url = reverse('dcim:moduletype_rearports', kwargs={'pk': moduletype.pk})
  947. self.assertHttpStatus(self.client.get(url), 200)
  948. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  949. def test_moduletype_frontports(self):
  950. moduletype = ModuleType.objects.first()
  951. rear_ports = (
  952. RearPortTemplate(module_type=moduletype, name='Rear Port 1'),
  953. RearPortTemplate(module_type=moduletype, name='Rear Port 2'),
  954. RearPortTemplate(module_type=moduletype, name='Rear Port 3'),
  955. )
  956. RearPortTemplate.objects.bulk_create(rear_ports)
  957. front_ports = (
  958. FrontPortTemplate(
  959. module_type=moduletype, name='Front Port 1', rear_port=rear_ports[0], rear_port_position=1
  960. ),
  961. FrontPortTemplate(
  962. module_type=moduletype, name='Front Port 2', rear_port=rear_ports[1], rear_port_position=1
  963. ),
  964. FrontPortTemplate(
  965. module_type=moduletype, name='Front Port 3', rear_port=rear_ports[2], rear_port_position=1
  966. ),
  967. )
  968. FrontPortTemplate.objects.bulk_create(front_ports)
  969. url = reverse('dcim:moduletype_frontports', kwargs={'pk': moduletype.pk})
  970. self.assertHttpStatus(self.client.get(url), 200)
  971. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  972. def test_import_objects(self):
  973. """
  974. Custom import test for YAML-based imports (versus CSV)
  975. """
  976. IMPORT_DATA = """
  977. manufacturer: Generic
  978. model: TEST-1000
  979. weight: 10
  980. weight_unit: lb
  981. comments: Test comment
  982. console-ports:
  983. - name: Console Port 1
  984. type: de-9
  985. - name: Console Port 2
  986. type: de-9
  987. - name: Console Port 3
  988. type: de-9
  989. console-server-ports:
  990. - name: Console Server Port 1
  991. type: rj-45
  992. - name: Console Server Port 2
  993. type: rj-45
  994. - name: Console Server Port 3
  995. type: rj-45
  996. power-ports:
  997. - name: Power Port 1
  998. type: iec-60320-c14
  999. - name: Power Port 2
  1000. type: iec-60320-c14
  1001. - name: Power Port 3
  1002. type: iec-60320-c14
  1003. power-outlets:
  1004. - name: Power Outlet 1
  1005. type: iec-60320-c13
  1006. power_port: Power Port 1
  1007. feed_leg: A
  1008. - name: Power Outlet 2
  1009. type: iec-60320-c13
  1010. power_port: Power Port 1
  1011. feed_leg: A
  1012. - name: Power Outlet 3
  1013. type: iec-60320-c13
  1014. power_port: Power Port 1
  1015. feed_leg: A
  1016. interfaces:
  1017. - name: Interface 1
  1018. type: 1000base-t
  1019. mgmt_only: true
  1020. - name: Interface 2
  1021. type: 1000base-t
  1022. - name: Interface 3
  1023. type: 1000base-t
  1024. rear-ports:
  1025. - name: Rear Port 1
  1026. type: 8p8c
  1027. - name: Rear Port 2
  1028. type: 8p8c
  1029. - name: Rear Port 3
  1030. type: 8p8c
  1031. front-ports:
  1032. - name: Front Port 1
  1033. type: 8p8c
  1034. rear_port: Rear Port 1
  1035. - name: Front Port 2
  1036. type: 8p8c
  1037. rear_port: Rear Port 2
  1038. - name: Front Port 3
  1039. type: 8p8c
  1040. rear_port: Rear Port 3
  1041. """
  1042. # Create the manufacturer
  1043. manufacturer = Manufacturer(name='Generic', slug='generic')
  1044. manufacturer.save()
  1045. # Add all required permissions to the test user
  1046. self.add_permissions(
  1047. 'dcim.view_moduletype',
  1048. 'dcim.add_moduletype',
  1049. 'dcim.add_consoleporttemplate',
  1050. 'dcim.add_consoleserverporttemplate',
  1051. 'dcim.add_powerporttemplate',
  1052. 'dcim.add_poweroutlettemplate',
  1053. 'dcim.add_interfacetemplate',
  1054. 'dcim.add_frontporttemplate',
  1055. 'dcim.add_rearporttemplate',
  1056. )
  1057. form_data = {
  1058. 'data': IMPORT_DATA,
  1059. 'format': 'yaml'
  1060. }
  1061. response = self.client.post(reverse('dcim:moduletype_bulk_import'), data=form_data, follow=True)
  1062. self.assertHttpStatus(response, 200)
  1063. module_type = ModuleType.objects.get(model='TEST-1000')
  1064. self.assertEqual(module_type.manufacturer.pk, manufacturer.pk)
  1065. self.assertEqual(module_type.weight, 10)
  1066. self.assertEqual(module_type.weight_unit, WeightUnitChoices.UNIT_POUND)
  1067. self.assertEqual(module_type.comments, 'Test comment')
  1068. # Verify all the components were created
  1069. self.assertEqual(module_type.consoleporttemplates.count(), 3)
  1070. cp1 = ConsolePortTemplate.objects.first()
  1071. self.assertEqual(cp1.name, 'Console Port 1')
  1072. self.assertEqual(cp1.type, ConsolePortTypeChoices.TYPE_DE9)
  1073. self.assertEqual(module_type.consoleserverporttemplates.count(), 3)
  1074. csp1 = ConsoleServerPortTemplate.objects.first()
  1075. self.assertEqual(csp1.name, 'Console Server Port 1')
  1076. self.assertEqual(csp1.type, ConsolePortTypeChoices.TYPE_RJ45)
  1077. self.assertEqual(module_type.powerporttemplates.count(), 3)
  1078. pp1 = PowerPortTemplate.objects.first()
  1079. self.assertEqual(pp1.name, 'Power Port 1')
  1080. self.assertEqual(pp1.type, PowerPortTypeChoices.TYPE_IEC_C14)
  1081. self.assertEqual(module_type.poweroutlettemplates.count(), 3)
  1082. po1 = PowerOutletTemplate.objects.first()
  1083. self.assertEqual(po1.name, 'Power Outlet 1')
  1084. self.assertEqual(po1.type, PowerOutletTypeChoices.TYPE_IEC_C13)
  1085. self.assertEqual(po1.power_port, pp1)
  1086. self.assertEqual(po1.feed_leg, PowerOutletFeedLegChoices.FEED_LEG_A)
  1087. self.assertEqual(module_type.interfacetemplates.count(), 3)
  1088. iface1 = InterfaceTemplate.objects.first()
  1089. self.assertEqual(iface1.name, 'Interface 1')
  1090. self.assertEqual(iface1.type, InterfaceTypeChoices.TYPE_1GE_FIXED)
  1091. self.assertTrue(iface1.mgmt_only)
  1092. self.assertEqual(module_type.rearporttemplates.count(), 3)
  1093. rp1 = RearPortTemplate.objects.first()
  1094. self.assertEqual(rp1.name, 'Rear Port 1')
  1095. self.assertEqual(module_type.frontporttemplates.count(), 3)
  1096. fp1 = FrontPortTemplate.objects.first()
  1097. self.assertEqual(fp1.name, 'Front Port 1')
  1098. self.assertEqual(fp1.rear_port, rp1)
  1099. self.assertEqual(fp1.rear_port_position, 1)
  1100. def test_export_objects(self):
  1101. url = reverse('dcim:moduletype_list')
  1102. self.add_permissions('dcim.view_moduletype')
  1103. # Test default YAML export
  1104. response = self.client.get(f'{url}?export')
  1105. self.assertEqual(response.status_code, 200)
  1106. data = list(yaml.load_all(response.content, Loader=yaml.SafeLoader))
  1107. self.assertEqual(len(data), 3)
  1108. self.assertEqual(data[0]['manufacturer'], 'Manufacturer 1')
  1109. self.assertEqual(data[0]['model'], 'Module Type 1')
  1110. # Test table-based export
  1111. response = self.client.get(f'{url}?export=table')
  1112. self.assertHttpStatus(response, 200)
  1113. self.assertEqual(response.get('Content-Type'), 'text/csv; charset=utf-8')
  1114. #
  1115. # DeviceType components
  1116. #
  1117. class ConsolePortTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
  1118. model = ConsolePortTemplate
  1119. validation_excluded_fields = ('name', 'label')
  1120. @classmethod
  1121. def setUpTestData(cls):
  1122. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  1123. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  1124. ConsolePortTemplate.objects.bulk_create((
  1125. ConsolePortTemplate(device_type=devicetype, name='Console Port Template 1'),
  1126. ConsolePortTemplate(device_type=devicetype, name='Console Port Template 2'),
  1127. ConsolePortTemplate(device_type=devicetype, name='Console Port Template 3'),
  1128. ))
  1129. cls.form_data = {
  1130. 'device_type': devicetype.pk,
  1131. 'name': 'Console Port Template X',
  1132. 'type': ConsolePortTypeChoices.TYPE_RJ45,
  1133. }
  1134. cls.bulk_create_data = {
  1135. 'device_type': devicetype.pk,
  1136. 'name': 'Console Port Template [4-6]',
  1137. 'type': ConsolePortTypeChoices.TYPE_RJ45,
  1138. }
  1139. cls.bulk_edit_data = {
  1140. 'type': ConsolePortTypeChoices.TYPE_RJ45,
  1141. }
  1142. class ConsoleServerPortTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
  1143. model = ConsoleServerPortTemplate
  1144. validation_excluded_fields = ('name', 'label')
  1145. @classmethod
  1146. def setUpTestData(cls):
  1147. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  1148. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  1149. ConsoleServerPortTemplate.objects.bulk_create((
  1150. ConsoleServerPortTemplate(device_type=devicetype, name='Console Server Port Template 1'),
  1151. ConsoleServerPortTemplate(device_type=devicetype, name='Console Server Port Template 2'),
  1152. ConsoleServerPortTemplate(device_type=devicetype, name='Console Server Port Template 3'),
  1153. ))
  1154. cls.form_data = {
  1155. 'device_type': devicetype.pk,
  1156. 'name': 'Console Server Port Template X',
  1157. 'type': ConsolePortTypeChoices.TYPE_RJ45,
  1158. }
  1159. cls.bulk_create_data = {
  1160. 'device_type': devicetype.pk,
  1161. 'name': 'Console Server Port Template [4-6]',
  1162. 'type': ConsolePortTypeChoices.TYPE_RJ45,
  1163. }
  1164. cls.bulk_edit_data = {
  1165. 'type': ConsolePortTypeChoices.TYPE_RJ45,
  1166. }
  1167. class PowerPortTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
  1168. model = PowerPortTemplate
  1169. validation_excluded_fields = ('name', 'label')
  1170. @classmethod
  1171. def setUpTestData(cls):
  1172. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  1173. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  1174. PowerPortTemplate.objects.bulk_create((
  1175. PowerPortTemplate(device_type=devicetype, name='Power Port Template 1'),
  1176. PowerPortTemplate(device_type=devicetype, name='Power Port Template 2'),
  1177. PowerPortTemplate(device_type=devicetype, name='Power Port Template 3'),
  1178. ))
  1179. cls.form_data = {
  1180. 'device_type': devicetype.pk,
  1181. 'name': 'Power Port Template X',
  1182. 'type': PowerPortTypeChoices.TYPE_IEC_C14,
  1183. 'maximum_draw': 100,
  1184. 'allocated_draw': 50,
  1185. }
  1186. cls.bulk_create_data = {
  1187. 'device_type': devicetype.pk,
  1188. 'name': 'Power Port Template [4-6]',
  1189. 'type': PowerPortTypeChoices.TYPE_IEC_C14,
  1190. 'maximum_draw': 100,
  1191. 'allocated_draw': 50,
  1192. }
  1193. cls.bulk_edit_data = {
  1194. 'type': PowerPortTypeChoices.TYPE_IEC_C14,
  1195. 'maximum_draw': 100,
  1196. 'allocated_draw': 50,
  1197. }
  1198. class PowerOutletTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
  1199. model = PowerOutletTemplate
  1200. validation_excluded_fields = ('name', 'label')
  1201. @classmethod
  1202. def setUpTestData(cls):
  1203. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  1204. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  1205. PowerOutletTemplate.objects.bulk_create((
  1206. PowerOutletTemplate(device_type=devicetype, name='Power Outlet Template 1'),
  1207. PowerOutletTemplate(device_type=devicetype, name='Power Outlet Template 2'),
  1208. PowerOutletTemplate(device_type=devicetype, name='Power Outlet Template 3'),
  1209. ))
  1210. powerports = (
  1211. PowerPortTemplate(device_type=devicetype, name='Power Port Template 1'),
  1212. )
  1213. PowerPortTemplate.objects.bulk_create(powerports)
  1214. cls.form_data = {
  1215. 'device_type': devicetype.pk,
  1216. 'name': 'Power Outlet Template X',
  1217. 'type': PowerOutletTypeChoices.TYPE_IEC_C13,
  1218. 'power_port': powerports[0].pk,
  1219. 'feed_leg': PowerOutletFeedLegChoices.FEED_LEG_B,
  1220. }
  1221. cls.bulk_create_data = {
  1222. 'device_type': devicetype.pk,
  1223. 'name': 'Power Outlet Template [4-6]',
  1224. 'type': PowerOutletTypeChoices.TYPE_IEC_C13,
  1225. 'power_port': powerports[0].pk,
  1226. 'feed_leg': PowerOutletFeedLegChoices.FEED_LEG_B,
  1227. }
  1228. cls.bulk_edit_data = {
  1229. 'type': PowerOutletTypeChoices.TYPE_IEC_C13,
  1230. 'feed_leg': PowerOutletFeedLegChoices.FEED_LEG_B,
  1231. }
  1232. class InterfaceTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
  1233. model = InterfaceTemplate
  1234. validation_excluded_fields = ('name', 'label')
  1235. @classmethod
  1236. def setUpTestData(cls):
  1237. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  1238. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  1239. InterfaceTemplate.objects.bulk_create((
  1240. InterfaceTemplate(device_type=devicetype, name='Interface Template 1'),
  1241. InterfaceTemplate(device_type=devicetype, name='Interface Template 2'),
  1242. InterfaceTemplate(device_type=devicetype, name='Interface Template 3'),
  1243. ))
  1244. cls.form_data = {
  1245. 'device_type': devicetype.pk,
  1246. 'name': 'Interface Template X',
  1247. 'type': InterfaceTypeChoices.TYPE_1GE_GBIC,
  1248. 'mgmt_only': True,
  1249. }
  1250. cls.bulk_create_data = {
  1251. 'device_type': devicetype.pk,
  1252. 'name': 'Interface Template [4-6]',
  1253. # Test that a label can be applied to each generated interface templates
  1254. 'label': 'Interface Template Label [3-5]',
  1255. 'type': InterfaceTypeChoices.TYPE_1GE_GBIC,
  1256. 'mgmt_only': True,
  1257. }
  1258. cls.bulk_edit_data = {
  1259. 'type': InterfaceTypeChoices.TYPE_1GE_GBIC,
  1260. 'mgmt_only': True,
  1261. }
  1262. class FrontPortTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
  1263. model = FrontPortTemplate
  1264. validation_excluded_fields = ('name', 'label', 'rear_port')
  1265. @classmethod
  1266. def setUpTestData(cls):
  1267. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  1268. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  1269. rearports = (
  1270. RearPortTemplate(device_type=devicetype, name='Rear Port Template 1'),
  1271. RearPortTemplate(device_type=devicetype, name='Rear Port Template 2'),
  1272. RearPortTemplate(device_type=devicetype, name='Rear Port Template 3'),
  1273. RearPortTemplate(device_type=devicetype, name='Rear Port Template 4'),
  1274. RearPortTemplate(device_type=devicetype, name='Rear Port Template 5'),
  1275. RearPortTemplate(device_type=devicetype, name='Rear Port Template 6'),
  1276. )
  1277. RearPortTemplate.objects.bulk_create(rearports)
  1278. FrontPortTemplate.objects.bulk_create(
  1279. (
  1280. FrontPortTemplate(
  1281. device_type=devicetype, name='Front Port Template 1', rear_port=rearports[0], rear_port_position=1
  1282. ),
  1283. FrontPortTemplate(
  1284. device_type=devicetype, name='Front Port Template 2', rear_port=rearports[1], rear_port_position=1
  1285. ),
  1286. FrontPortTemplate(
  1287. device_type=devicetype, name='Front Port Template 3', rear_port=rearports[2], rear_port_position=1
  1288. ),
  1289. )
  1290. )
  1291. cls.form_data = {
  1292. 'device_type': devicetype.pk,
  1293. 'name': 'Front Port X',
  1294. 'type': PortTypeChoices.TYPE_8P8C,
  1295. 'rear_port': rearports[3].pk,
  1296. 'rear_port_position': 1,
  1297. }
  1298. cls.bulk_create_data = {
  1299. 'device_type': devicetype.pk,
  1300. 'name': 'Front Port [4-6]',
  1301. 'type': PortTypeChoices.TYPE_8P8C,
  1302. 'rear_port': [f'{rp.pk}:1' for rp in rearports[3:6]],
  1303. }
  1304. cls.bulk_edit_data = {
  1305. 'type': PortTypeChoices.TYPE_8P8C,
  1306. }
  1307. class RearPortTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
  1308. model = RearPortTemplate
  1309. validation_excluded_fields = ('name', 'label')
  1310. @classmethod
  1311. def setUpTestData(cls):
  1312. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  1313. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  1314. RearPortTemplate.objects.bulk_create((
  1315. RearPortTemplate(device_type=devicetype, name='Rear Port Template 1'),
  1316. RearPortTemplate(device_type=devicetype, name='Rear Port Template 2'),
  1317. RearPortTemplate(device_type=devicetype, name='Rear Port Template 3'),
  1318. ))
  1319. cls.form_data = {
  1320. 'device_type': devicetype.pk,
  1321. 'name': 'Rear Port Template X',
  1322. 'type': PortTypeChoices.TYPE_8P8C,
  1323. 'positions': 2,
  1324. }
  1325. cls.bulk_create_data = {
  1326. 'device_type': devicetype.pk,
  1327. 'name': 'Rear Port Template [4-6]',
  1328. 'type': PortTypeChoices.TYPE_8P8C,
  1329. 'positions': 2,
  1330. }
  1331. cls.bulk_edit_data = {
  1332. 'type': PortTypeChoices.TYPE_8P8C,
  1333. }
  1334. class ModuleBayTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
  1335. model = ModuleBayTemplate
  1336. validation_excluded_fields = ('name', 'label')
  1337. @classmethod
  1338. def setUpTestData(cls):
  1339. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  1340. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  1341. ModuleBayTemplate.objects.bulk_create((
  1342. ModuleBayTemplate(device_type=devicetype, name='Module Bay Template 1'),
  1343. ModuleBayTemplate(device_type=devicetype, name='Module Bay Template 2'),
  1344. ModuleBayTemplate(device_type=devicetype, name='Module Bay Template 3'),
  1345. ))
  1346. cls.form_data = {
  1347. 'device_type': devicetype.pk,
  1348. 'name': 'Module Bay Template X',
  1349. }
  1350. cls.bulk_create_data = {
  1351. 'device_type': devicetype.pk,
  1352. 'name': 'Module Bay Template [4-6]',
  1353. }
  1354. cls.bulk_edit_data = {
  1355. 'description': 'Foo bar',
  1356. }
  1357. class DeviceBayTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
  1358. model = DeviceBayTemplate
  1359. validation_excluded_fields = ('name', 'label')
  1360. @classmethod
  1361. def setUpTestData(cls):
  1362. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  1363. devicetype = DeviceType.objects.create(
  1364. manufacturer=manufacturer,
  1365. model='Device Type 1',
  1366. slug='device-type-1',
  1367. subdevice_role=SubdeviceRoleChoices.ROLE_PARENT
  1368. )
  1369. DeviceBayTemplate.objects.bulk_create((
  1370. DeviceBayTemplate(device_type=devicetype, name='Device Bay Template 1'),
  1371. DeviceBayTemplate(device_type=devicetype, name='Device Bay Template 2'),
  1372. DeviceBayTemplate(device_type=devicetype, name='Device Bay Template 3'),
  1373. ))
  1374. cls.form_data = {
  1375. 'device_type': devicetype.pk,
  1376. 'name': 'Device Bay Template X',
  1377. }
  1378. cls.bulk_create_data = {
  1379. 'device_type': devicetype.pk,
  1380. 'name': 'Device Bay Template [4-6]',
  1381. }
  1382. cls.bulk_edit_data = {
  1383. 'description': 'Foo bar',
  1384. }
  1385. class InventoryItemTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
  1386. model = InventoryItemTemplate
  1387. validation_excluded_fields = ('name', 'label')
  1388. @classmethod
  1389. def setUpTestData(cls):
  1390. manufacturers = (
  1391. Manufacturer(name='Manufacturer 1', slug='manufacturer-1'),
  1392. Manufacturer(name='Manufacturer 2', slug='manufacturer-2'),
  1393. )
  1394. Manufacturer.objects.bulk_create(manufacturers)
  1395. devicetype = DeviceType.objects.create(
  1396. manufacturer=manufacturers[0], model='Device Type 1', slug='device-type-1'
  1397. )
  1398. inventory_item_templates = (
  1399. InventoryItemTemplate(
  1400. device_type=devicetype, name='Inventory Item Template 1', manufacturer=manufacturers[0]
  1401. ),
  1402. InventoryItemTemplate(
  1403. device_type=devicetype, name='Inventory Item Template 2', manufacturer=manufacturers[0]
  1404. ),
  1405. InventoryItemTemplate(
  1406. device_type=devicetype, name='Inventory Item Template 3', manufacturer=manufacturers[0]
  1407. ),
  1408. )
  1409. for item in inventory_item_templates:
  1410. item.save()
  1411. cls.form_data = {
  1412. 'device_type': devicetype.pk,
  1413. 'name': 'Inventory Item Template X',
  1414. 'manufacturer': manufacturers[1].pk,
  1415. }
  1416. cls.bulk_create_data = {
  1417. 'device_type': devicetype.pk,
  1418. 'name': 'Inventory Item Template [4-6]',
  1419. 'manufacturer': manufacturers[1].pk,
  1420. }
  1421. cls.bulk_edit_data = {
  1422. 'description': 'Foo bar',
  1423. }
  1424. class DeviceRoleTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
  1425. model = DeviceRole
  1426. @classmethod
  1427. def setUpTestData(cls):
  1428. roles = (
  1429. DeviceRole(name='Device Role 1', slug='device-role-1'),
  1430. DeviceRole(name='Device Role 2', slug='device-role-2'),
  1431. DeviceRole(name='Device Role 3', slug='device-role-3'),
  1432. )
  1433. DeviceRole.objects.bulk_create(roles)
  1434. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  1435. cls.form_data = {
  1436. 'name': 'Device Role X',
  1437. 'slug': 'device-role-x',
  1438. 'color': 'c0c0c0',
  1439. 'vm_role': False,
  1440. 'description': 'New device role',
  1441. 'tags': [t.pk for t in tags],
  1442. }
  1443. cls.csv_data = (
  1444. "name,slug,color",
  1445. "Device Role 4,device-role-4,ff0000",
  1446. "Device Role 5,device-role-5,00ff00",
  1447. "Device Role 6,device-role-6,0000ff",
  1448. )
  1449. cls.csv_update_data = (
  1450. "id,name,description",
  1451. f"{roles[0].pk},Device Role 7,New description7",
  1452. f"{roles[1].pk},Device Role 8,New description8",
  1453. f"{roles[2].pk},Device Role 9,New description9",
  1454. )
  1455. cls.bulk_edit_data = {
  1456. 'color': '00ff00',
  1457. 'description': 'New description',
  1458. }
  1459. class PlatformTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
  1460. model = Platform
  1461. @classmethod
  1462. def setUpTestData(cls):
  1463. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  1464. platforms = (
  1465. Platform(name='Platform 1', slug='platform-1', manufacturer=manufacturer),
  1466. Platform(name='Platform 2', slug='platform-2', manufacturer=manufacturer),
  1467. Platform(name='Platform 3', slug='platform-3', manufacturer=manufacturer),
  1468. )
  1469. Platform.objects.bulk_create(platforms)
  1470. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  1471. cls.form_data = {
  1472. 'name': 'Platform X',
  1473. 'slug': 'platform-x',
  1474. 'manufacturer': manufacturer.pk,
  1475. 'description': 'A new platform',
  1476. 'tags': [t.pk for t in tags],
  1477. }
  1478. cls.csv_data = (
  1479. "name,slug,description",
  1480. "Platform 4,platform-4,Fourth platform",
  1481. "Platform 5,platform-5,Fifth platform",
  1482. "Platform 6,platform-6,Sixth platform",
  1483. )
  1484. cls.csv_update_data = (
  1485. "id,name,description",
  1486. f"{platforms[0].pk},Platform 7,Fourth platform7",
  1487. f"{platforms[1].pk},Platform 8,Fifth platform8",
  1488. f"{platforms[2].pk},Platform 9,Sixth platform9",
  1489. )
  1490. cls.bulk_edit_data = {
  1491. 'description': 'New description',
  1492. }
  1493. class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  1494. model = Device
  1495. @classmethod
  1496. def setUpTestData(cls):
  1497. sites = (
  1498. Site(name='Site 1', slug='site-1'),
  1499. Site(name='Site 2', slug='site-2'),
  1500. )
  1501. Site.objects.bulk_create(sites)
  1502. location = Location(site=sites[0], name='Location 1', slug='location-1')
  1503. location.save()
  1504. racks = (
  1505. Rack(name='Rack 1', site=sites[0], location=location),
  1506. Rack(name='Rack 2', site=sites[1]),
  1507. )
  1508. Rack.objects.bulk_create(racks)
  1509. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  1510. devicetypes = (
  1511. DeviceType(model='Device Type 1', slug='device-type-1', manufacturer=manufacturer),
  1512. DeviceType(model='Device Type 2', slug='device-type-2', manufacturer=manufacturer),
  1513. )
  1514. DeviceType.objects.bulk_create(devicetypes)
  1515. roles = (
  1516. DeviceRole(name='Device Role 1', slug='device-role-1'),
  1517. DeviceRole(name='Device Role 2', slug='device-role-2'),
  1518. )
  1519. DeviceRole.objects.bulk_create(roles)
  1520. platforms = (
  1521. Platform(name='Platform 1', slug='platform-1'),
  1522. Platform(name='Platform 2', slug='platform-2'),
  1523. )
  1524. Platform.objects.bulk_create(platforms)
  1525. devices = (
  1526. Device(
  1527. name='Device 1',
  1528. site=sites[0],
  1529. rack=racks[0],
  1530. device_type=devicetypes[0],
  1531. role=roles[0],
  1532. platform=platforms[0],
  1533. ),
  1534. Device(
  1535. name='Device 2',
  1536. site=sites[0],
  1537. rack=racks[0],
  1538. device_type=devicetypes[0],
  1539. role=roles[0],
  1540. platform=platforms[0],
  1541. ),
  1542. Device(
  1543. name='Device 3',
  1544. site=sites[0],
  1545. rack=racks[0],
  1546. device_type=devicetypes[0],
  1547. role=roles[0],
  1548. platform=platforms[0],
  1549. ),
  1550. )
  1551. Device.objects.bulk_create(devices)
  1552. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  1553. VirtualChassis.objects.create(name='Virtual Chassis 1')
  1554. cls.form_data = {
  1555. 'device_type': devicetypes[1].pk,
  1556. 'role': roles[1].pk,
  1557. 'tenant': None,
  1558. 'platform': platforms[1].pk,
  1559. 'name': 'Device X',
  1560. 'serial': '123456',
  1561. 'asset_tag': 'ABCDEF',
  1562. 'site': sites[1].pk,
  1563. 'rack': racks[1].pk,
  1564. 'position': 1,
  1565. 'face': DeviceFaceChoices.FACE_FRONT,
  1566. 'latitude': Decimal('35.780000'),
  1567. 'longitude': Decimal('-78.642000'),
  1568. 'status': DeviceStatusChoices.STATUS_PLANNED,
  1569. 'primary_ip4': None,
  1570. 'primary_ip6': None,
  1571. 'cluster': None,
  1572. 'virtual_chassis': None,
  1573. 'vc_position': None,
  1574. 'vc_priority': None,
  1575. 'comments': 'A new device',
  1576. 'tags': [t.pk for t in tags],
  1577. 'local_context_data': None,
  1578. }
  1579. cls.csv_data = (
  1580. (
  1581. "role,manufacturer,device_type,status,name,site,location,rack,position,face,virtual_chassis,"
  1582. "vc_position,vc_priority"
  1583. ),
  1584. (
  1585. "Device Role 1,Manufacturer 1,Device Type 1,active,Device 4,Site 1,Location 1,Rack 1,10,front,"
  1586. "Virtual Chassis 1,1,10"
  1587. ),
  1588. (
  1589. "Device Role 1,Manufacturer 1,Device Type 1,active,Device 5,Site 1,Location 1,Rack 1,20,front,"
  1590. "Virtual Chassis 1,2,20"
  1591. ),
  1592. (
  1593. "Device Role 1,Manufacturer 1,Device Type 1,active,Device 6,Site 1,Location 1,Rack 1,30,front,"
  1594. "Virtual Chassis 1,3,30"
  1595. ),
  1596. )
  1597. cls.csv_update_data = (
  1598. "id,status",
  1599. f"{devices[0].pk},{DeviceStatusChoices.STATUS_DECOMMISSIONING}",
  1600. f"{devices[1].pk},{DeviceStatusChoices.STATUS_DECOMMISSIONING}",
  1601. f"{devices[2].pk},{DeviceStatusChoices.STATUS_DECOMMISSIONING}",
  1602. )
  1603. cls.bulk_edit_data = {
  1604. 'device_type': devicetypes[1].pk,
  1605. 'role': roles[1].pk,
  1606. 'tenant': None,
  1607. 'platform': platforms[1].pk,
  1608. 'serial': '123456',
  1609. 'status': DeviceStatusChoices.STATUS_DECOMMISSIONING,
  1610. }
  1611. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1612. def test_device_consoleports(self):
  1613. device = Device.objects.first()
  1614. console_ports = (
  1615. ConsolePort(device=device, name='Console Port 1'),
  1616. ConsolePort(device=device, name='Console Port 2'),
  1617. ConsolePort(device=device, name='Console Port 3'),
  1618. )
  1619. ConsolePort.objects.bulk_create(console_ports)
  1620. url = reverse('dcim:device_consoleports', kwargs={'pk': device.pk})
  1621. self.assertHttpStatus(self.client.get(url), 200)
  1622. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1623. def test_device_consoleserverports(self):
  1624. device = Device.objects.first()
  1625. console_server_ports = (
  1626. ConsoleServerPort(device=device, name='Console Server Port 1'),
  1627. ConsoleServerPort(device=device, name='Console Server Port 2'),
  1628. ConsoleServerPort(device=device, name='Console Server Port 3'),
  1629. )
  1630. ConsoleServerPort.objects.bulk_create(console_server_ports)
  1631. url = reverse('dcim:device_consoleserverports', kwargs={'pk': device.pk})
  1632. self.assertHttpStatus(self.client.get(url), 200)
  1633. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1634. def test_device_powerports(self):
  1635. device = Device.objects.first()
  1636. power_ports = (
  1637. PowerPort(device=device, name='Power Port 1'),
  1638. PowerPort(device=device, name='Power Port 2'),
  1639. PowerPort(device=device, name='Power Port 3'),
  1640. )
  1641. PowerPort.objects.bulk_create(power_ports)
  1642. url = reverse('dcim:device_powerports', kwargs={'pk': device.pk})
  1643. self.assertHttpStatus(self.client.get(url), 200)
  1644. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1645. def test_device_poweroutlets(self):
  1646. device = Device.objects.first()
  1647. power_outlets = (
  1648. PowerOutlet(device=device, name='Power Outlet 1'),
  1649. PowerOutlet(device=device, name='Power Outlet 2'),
  1650. PowerOutlet(device=device, name='Power Outlet 3'),
  1651. )
  1652. PowerOutlet.objects.bulk_create(power_outlets)
  1653. url = reverse('dcim:device_poweroutlets', kwargs={'pk': device.pk})
  1654. self.assertHttpStatus(self.client.get(url), 200)
  1655. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1656. def test_device_interfaces(self):
  1657. device = Device.objects.first()
  1658. interfaces = (
  1659. Interface(device=device, name='Interface 1'),
  1660. Interface(device=device, name='Interface 2'),
  1661. Interface(device=device, name='Interface 3'),
  1662. )
  1663. Interface.objects.bulk_create(interfaces)
  1664. url = reverse('dcim:device_interfaces', kwargs={'pk': device.pk})
  1665. self.assertHttpStatus(self.client.get(url), 200)
  1666. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1667. def test_device_rearports(self):
  1668. device = Device.objects.first()
  1669. rear_ports = (
  1670. RearPort(device=device, name='Rear Port 1'),
  1671. RearPort(device=device, name='Rear Port 2'),
  1672. RearPort(device=device, name='Rear Port 3'),
  1673. )
  1674. RearPort.objects.bulk_create(rear_ports)
  1675. url = reverse('dcim:device_rearports', kwargs={'pk': device.pk})
  1676. self.assertHttpStatus(self.client.get(url), 200)
  1677. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1678. def test_device_frontports(self):
  1679. device = Device.objects.first()
  1680. rear_ports = (
  1681. RearPort(device=device, name='Rear Port 1'),
  1682. RearPort(device=device, name='Rear Port 2'),
  1683. RearPort(device=device, name='Rear Port 3'),
  1684. )
  1685. RearPort.objects.bulk_create(rear_ports)
  1686. front_ports = (
  1687. FrontPort(device=device, name='Front Port 1', rear_port=rear_ports[0], rear_port_position=1),
  1688. FrontPort(device=device, name='Front Port 2', rear_port=rear_ports[1], rear_port_position=1),
  1689. FrontPort(device=device, name='Front Port 3', rear_port=rear_ports[2], rear_port_position=1),
  1690. )
  1691. FrontPort.objects.bulk_create(front_ports)
  1692. url = reverse('dcim:device_frontports', kwargs={'pk': device.pk})
  1693. self.assertHttpStatus(self.client.get(url), 200)
  1694. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1695. def test_device_modulebays(self):
  1696. device = Device.objects.first()
  1697. ModuleBay.objects.create(device=device, name='Module Bay 1')
  1698. ModuleBay.objects.create(device=device, name='Module Bay 2')
  1699. ModuleBay.objects.create(device=device, name='Module Bay 3')
  1700. url = reverse('dcim:device_modulebays', kwargs={'pk': device.pk})
  1701. self.assertHttpStatus(self.client.get(url), 200)
  1702. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1703. def test_device_devicebays(self):
  1704. device = Device.objects.first()
  1705. device_bays = (
  1706. DeviceBay(device=device, name='Device Bay 1'),
  1707. DeviceBay(device=device, name='Device Bay 2'),
  1708. DeviceBay(device=device, name='Device Bay 3'),
  1709. )
  1710. DeviceBay.objects.bulk_create(device_bays)
  1711. url = reverse('dcim:device_devicebays', kwargs={'pk': device.pk})
  1712. self.assertHttpStatus(self.client.get(url), 200)
  1713. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1714. def test_device_inventory(self):
  1715. device = Device.objects.first()
  1716. inventory_items = (
  1717. InventoryItem(device=device, name='Inventory Item 1'),
  1718. InventoryItem(device=device, name='Inventory Item 2'),
  1719. InventoryItem(device=device, name='Inventory Item 3'),
  1720. )
  1721. for item in inventory_items:
  1722. item.save()
  1723. url = reverse('dcim:device_inventory', kwargs={'pk': device.pk})
  1724. self.assertHttpStatus(self.client.get(url), 200)
  1725. class ModuleTestCase(
  1726. # Module does not support bulk renaming (no name field) or
  1727. # bulk creation (need to specify module bays)
  1728. ViewTestCases.GetObjectViewTestCase,
  1729. ViewTestCases.GetObjectChangelogViewTestCase,
  1730. ViewTestCases.CreateObjectViewTestCase,
  1731. ViewTestCases.EditObjectViewTestCase,
  1732. ViewTestCases.DeleteObjectViewTestCase,
  1733. ViewTestCases.ListObjectsViewTestCase,
  1734. ViewTestCases.BulkImportObjectsViewTestCase,
  1735. ViewTestCases.BulkEditObjectsViewTestCase,
  1736. ViewTestCases.BulkDeleteObjectsViewTestCase,
  1737. ):
  1738. model = Module
  1739. @classmethod
  1740. def setUpTestData(cls):
  1741. manufacturer = Manufacturer.objects.create(name='Generic', slug='generic')
  1742. devices = (
  1743. create_test_device('Device 1'),
  1744. create_test_device('Device 2'),
  1745. )
  1746. module_types = (
  1747. ModuleType(manufacturer=manufacturer, model='Module Type 1'),
  1748. ModuleType(manufacturer=manufacturer, model='Module Type 2'),
  1749. ModuleType(manufacturer=manufacturer, model='Module Type 3'),
  1750. ModuleType(manufacturer=manufacturer, model='Module Type 4'),
  1751. )
  1752. ModuleType.objects.bulk_create(module_types)
  1753. module_bays = (
  1754. ModuleBay(device=devices[0], name='Module Bay 1'),
  1755. ModuleBay(device=devices[0], name='Module Bay 2'),
  1756. ModuleBay(device=devices[0], name='Module Bay 3'),
  1757. ModuleBay(device=devices[0], name='Module Bay 4'),
  1758. ModuleBay(device=devices[0], name='Module Bay 5'),
  1759. ModuleBay(device=devices[1], name='Module Bay 1'),
  1760. ModuleBay(device=devices[1], name='Module Bay 2'),
  1761. ModuleBay(device=devices[1], name='Module Bay 3'),
  1762. ModuleBay(device=devices[1], name='Module Bay 4'),
  1763. ModuleBay(device=devices[1], name='Module Bay 5'),
  1764. )
  1765. for module_bay in module_bays:
  1766. module_bay.save()
  1767. modules = (
  1768. Module(device=devices[0], module_bay=module_bays[0], module_type=module_types[0]),
  1769. Module(device=devices[0], module_bay=module_bays[1], module_type=module_types[1]),
  1770. Module(device=devices[0], module_bay=module_bays[2], module_type=module_types[2]),
  1771. )
  1772. Module.objects.bulk_create(modules)
  1773. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  1774. cls.form_data = {
  1775. 'device': devices[0].pk,
  1776. 'module_bay': module_bays[3].pk,
  1777. 'module_type': module_types[0].pk,
  1778. 'status': ModuleStatusChoices.STATUS_ACTIVE,
  1779. 'serial': 'A',
  1780. 'tags': [t.pk for t in tags],
  1781. }
  1782. cls.bulk_edit_data = {
  1783. 'module_type': module_types[3].pk,
  1784. 'status': ModuleStatusChoices.STATUS_PLANNED,
  1785. }
  1786. cls.csv_data = (
  1787. "device,module_bay,module_type,status,serial,asset_tag",
  1788. "Device 2,Module Bay 1,Module Type 1,active,A,A",
  1789. "Device 2,Module Bay 2,Module Type 2,planned,B,B",
  1790. "Device 2,Module Bay 3,Module Type 3,failed,C,C",
  1791. )
  1792. cls.csv_update_data = (
  1793. "id,status,serial",
  1794. f"{modules[0].pk},offline,Serial 2",
  1795. f"{modules[1].pk},offline,Serial 3",
  1796. f"{modules[2].pk},offline,Serial 1",
  1797. )
  1798. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1799. def test_module_component_replication(self):
  1800. self.add_permissions('dcim.add_module')
  1801. # Add 5 InterfaceTemplates to a ModuleType
  1802. module_type = ModuleType.objects.first()
  1803. interface_templates = [
  1804. InterfaceTemplate(module_type=module_type, name=f'Interface {i}') for i in range(1, 6)
  1805. ]
  1806. InterfaceTemplate.objects.bulk_create(interface_templates)
  1807. form_data = self.form_data.copy()
  1808. device = Device.objects.get(pk=form_data['device'])
  1809. # Create a module *without* replicating components
  1810. form_data['replicate_components'] = False
  1811. request = {
  1812. 'path': self._get_url('add'),
  1813. 'data': post_data(form_data),
  1814. }
  1815. self.assertHttpStatus(self.client.post(**request), 302)
  1816. self.assertEqual(Interface.objects.filter(device=device).count(), 0)
  1817. # Create a second module (in the next bay) with replicated components
  1818. form_data['module_bay'] += 1
  1819. form_data['replicate_components'] = True
  1820. request = {
  1821. 'path': self._get_url('add'),
  1822. 'data': post_data(form_data),
  1823. }
  1824. self.assertHttpStatus(self.client.post(**request), 302)
  1825. self.assertEqual(Interface.objects.filter(device=device).count(), 5)
  1826. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1827. def test_module_bulk_replication(self):
  1828. self.add_permissions('dcim.add_module')
  1829. # Add 5 InterfaceTemplates to a ModuleType
  1830. module_type = ModuleType.objects.first()
  1831. interface_templates = [
  1832. InterfaceTemplate(module_type=module_type, name=f'Interface {i}')
  1833. for i in range(1, 6)
  1834. ]
  1835. InterfaceTemplate.objects.bulk_create(interface_templates)
  1836. # Create a module *without* replicating components
  1837. device = Device.objects.get(name='Device 2')
  1838. module_bay = ModuleBay.objects.get(device=device, name='Module Bay 4')
  1839. csv_data = [
  1840. "device,module_bay,module_type,status,replicate_components",
  1841. f"{device.name},{module_bay.name},{module_type.model},active,false"
  1842. ]
  1843. request = {
  1844. 'path': self._get_url('bulk_import'),
  1845. 'data': {
  1846. 'data': '\n'.join(csv_data),
  1847. 'format': ImportFormatChoices.CSV,
  1848. 'csv_delimiter': CSVDelimiterChoices.AUTO,
  1849. }
  1850. }
  1851. initial_count = Module.objects.count()
  1852. self.assertHttpStatus(self.client.post(**request), 302)
  1853. self.assertEqual(Module.objects.count(), initial_count + len(csv_data) - 1)
  1854. self.assertEqual(Interface.objects.filter(device=device).count(), 0)
  1855. # Create a second module (in the next bay) with replicated components
  1856. module_bay = ModuleBay.objects.get(device=device, name='Module Bay 5')
  1857. csv_data[1] = f"{device.name},{module_bay.name},{module_type.model},active,true"
  1858. request = {
  1859. 'path': self._get_url('bulk_import'),
  1860. 'data': {
  1861. 'data': '\n'.join(csv_data),
  1862. 'format': ImportFormatChoices.CSV,
  1863. 'csv_delimiter': CSVDelimiterChoices.AUTO,
  1864. }
  1865. }
  1866. initial_count = Module.objects.count()
  1867. self.assertHttpStatus(self.client.post(**request), 302)
  1868. self.assertEqual(Module.objects.count(), initial_count + len(csv_data) - 1)
  1869. self.assertEqual(Interface.objects.filter(device=device).count(), 5)
  1870. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1871. def test_module_component_adoption(self):
  1872. self.add_permissions('dcim.add_module')
  1873. interface_name = "Interface-1"
  1874. # Add an interface to the ModuleType
  1875. module_type = ModuleType.objects.first()
  1876. InterfaceTemplate(module_type=module_type, name=interface_name).save()
  1877. form_data = self.form_data.copy()
  1878. device = Device.objects.get(pk=form_data['device'])
  1879. # Create an interface to be adopted
  1880. interface = Interface(device=device, name=interface_name, type=InterfaceTypeChoices.TYPE_10GE_FIXED)
  1881. interface.save()
  1882. # Ensure that interface is created with no module
  1883. self.assertIsNone(interface.module)
  1884. # Create a module with adopted components
  1885. form_data['module_type'] = module_type
  1886. form_data['replicate_components'] = False
  1887. form_data['adopt_components'] = True
  1888. request = {
  1889. 'path': self._get_url('add'),
  1890. 'data': post_data(form_data),
  1891. }
  1892. self.assertHttpStatus(self.client.post(**request), 302)
  1893. # Re-retrieve interface to get new module id
  1894. interface.refresh_from_db()
  1895. # Check that the Interface now has a module
  1896. self.assertIsNotNone(interface.module)
  1897. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1898. def test_module_bulk_adoption(self):
  1899. self.add_permissions('dcim.add_module')
  1900. interface_name = "Interface-1"
  1901. # Add an interface to the ModuleType
  1902. module_type = ModuleType.objects.first()
  1903. InterfaceTemplate(module_type=module_type, name=interface_name).save()
  1904. form_data = self.form_data.copy()
  1905. device = Device.objects.get(pk=form_data['device'])
  1906. # Create an interface to be adopted
  1907. interface = Interface(device=device, name=interface_name, type=InterfaceTypeChoices.TYPE_10GE_FIXED)
  1908. interface.save()
  1909. # Ensure that interface is created with no module
  1910. self.assertIsNone(interface.module)
  1911. # Create a module with adopted components
  1912. module_bay = ModuleBay.objects.get(device=device, name='Module Bay 4')
  1913. csv_data = [
  1914. "device,module_bay,module_type,status,replicate_components,adopt_components",
  1915. f"{device.name},{module_bay.name},{module_type.model},active,false,true"
  1916. ]
  1917. request = {
  1918. 'path': self._get_url('bulk_import'),
  1919. 'data': {
  1920. 'data': '\n'.join(csv_data),
  1921. 'format': ImportFormatChoices.CSV,
  1922. 'csv_delimiter': CSVDelimiterChoices.AUTO,
  1923. }
  1924. }
  1925. initial_count = self._get_queryset().count()
  1926. self.assertHttpStatus(self.client.post(**request), 302)
  1927. self.assertEqual(self._get_queryset().count(), initial_count + len(csv_data) - 1)
  1928. # Re-retrieve interface to get new module id
  1929. interface.refresh_from_db()
  1930. # Check that the Interface now has a module
  1931. self.assertIsNotNone(interface.module)
  1932. class ConsolePortTestCase(ViewTestCases.DeviceComponentViewTestCase):
  1933. model = ConsolePort
  1934. validation_excluded_fields = ('name', 'label')
  1935. @classmethod
  1936. def setUpTestData(cls):
  1937. device = create_test_device('Device 1')
  1938. console_ports = (
  1939. ConsolePort(device=device, name='Console Port 1'),
  1940. ConsolePort(device=device, name='Console Port 2'),
  1941. ConsolePort(device=device, name='Console Port 3'),
  1942. )
  1943. ConsolePort.objects.bulk_create(console_ports)
  1944. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  1945. cls.form_data = {
  1946. 'device': device.pk,
  1947. 'name': 'Console Port X',
  1948. 'type': ConsolePortTypeChoices.TYPE_RJ45,
  1949. 'description': 'A console port',
  1950. 'tags': sorted([t.pk for t in tags]),
  1951. }
  1952. cls.bulk_create_data = {
  1953. 'device': device.pk,
  1954. 'name': 'Console Port [4-6]',
  1955. # Test that a label can be applied to each generated console ports
  1956. 'label': 'Serial[3-5]',
  1957. 'type': ConsolePortTypeChoices.TYPE_RJ45,
  1958. 'description': 'A console port',
  1959. 'tags': sorted([t.pk for t in tags]),
  1960. }
  1961. cls.bulk_edit_data = {
  1962. 'type': ConsolePortTypeChoices.TYPE_RJ45,
  1963. 'description': 'New description',
  1964. }
  1965. cls.csv_data = (
  1966. "device,name",
  1967. "Device 1,Console Port 4",
  1968. "Device 1,Console Port 5",
  1969. "Device 1,Console Port 6",
  1970. )
  1971. cls.csv_update_data = (
  1972. "id,name,description",
  1973. f"{console_ports[0].pk},Console Port 7,New description7",
  1974. f"{console_ports[1].pk},Console Port 8,New description8",
  1975. f"{console_ports[2].pk},Console Port 9,New description9",
  1976. )
  1977. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1978. def test_trace(self):
  1979. consoleport = ConsolePort.objects.first()
  1980. consoleserverport = ConsoleServerPort.objects.create(
  1981. device=consoleport.device,
  1982. name='Console Server Port 1'
  1983. )
  1984. Cable(a_terminations=[consoleport], b_terminations=[consoleserverport]).save()
  1985. response = self.client.get(reverse('dcim:consoleport_trace', kwargs={'pk': consoleport.pk}))
  1986. self.assertHttpStatus(response, 200)
  1987. class ConsoleServerPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
  1988. model = ConsoleServerPort
  1989. validation_excluded_fields = ('name', 'label')
  1990. @classmethod
  1991. def setUpTestData(cls):
  1992. device = create_test_device('Device 1')
  1993. console_server_ports = (
  1994. ConsoleServerPort(device=device, name='Console Server Port 1'),
  1995. ConsoleServerPort(device=device, name='Console Server Port 2'),
  1996. ConsoleServerPort(device=device, name='Console Server Port 3'),
  1997. )
  1998. ConsoleServerPort.objects.bulk_create(console_server_ports)
  1999. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  2000. cls.form_data = {
  2001. 'device': device.pk,
  2002. 'name': 'Console Server Port X',
  2003. 'type': ConsolePortTypeChoices.TYPE_RJ45,
  2004. 'description': 'A console server port',
  2005. 'tags': [t.pk for t in tags],
  2006. }
  2007. cls.bulk_create_data = {
  2008. 'device': device.pk,
  2009. 'name': 'Console Server Port [4-6]',
  2010. 'type': ConsolePortTypeChoices.TYPE_RJ45,
  2011. 'description': 'A console server port',
  2012. 'tags': [t.pk for t in tags],
  2013. }
  2014. cls.bulk_edit_data = {
  2015. 'type': ConsolePortTypeChoices.TYPE_RJ11,
  2016. 'description': 'New description',
  2017. }
  2018. cls.csv_data = (
  2019. "device,name",
  2020. "Device 1,Console Server Port 4",
  2021. "Device 1,Console Server Port 5",
  2022. "Device 1,Console Server Port 6",
  2023. )
  2024. cls.csv_update_data = (
  2025. "id,name,description",
  2026. f"{console_server_ports[0].pk},Console Server Port 7,New description 7",
  2027. f"{console_server_ports[1].pk},Console Server Port 8,New description 8",
  2028. f"{console_server_ports[2].pk},Console Server Port 9,New description 9",
  2029. )
  2030. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  2031. def test_trace(self):
  2032. consoleserverport = ConsoleServerPort.objects.first()
  2033. consoleport = ConsolePort.objects.create(
  2034. device=consoleserverport.device,
  2035. name='Console Port 1'
  2036. )
  2037. Cable(a_terminations=[consoleserverport], b_terminations=[consoleport]).save()
  2038. response = self.client.get(reverse('dcim:consoleserverport_trace', kwargs={'pk': consoleserverport.pk}))
  2039. self.assertHttpStatus(response, 200)
  2040. class PowerPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
  2041. model = PowerPort
  2042. validation_excluded_fields = ('name', 'label')
  2043. @classmethod
  2044. def setUpTestData(cls):
  2045. device = create_test_device('Device 1')
  2046. power_ports = (
  2047. PowerPort(device=device, name='Power Port 1'),
  2048. PowerPort(device=device, name='Power Port 2'),
  2049. PowerPort(device=device, name='Power Port 3'),
  2050. )
  2051. PowerPort.objects.bulk_create(power_ports)
  2052. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  2053. cls.form_data = {
  2054. 'device': device.pk,
  2055. 'name': 'Power Port X',
  2056. 'type': PowerPortTypeChoices.TYPE_IEC_C14,
  2057. 'maximum_draw': 100,
  2058. 'allocated_draw': 50,
  2059. 'description': 'A power port',
  2060. 'tags': [t.pk for t in tags],
  2061. }
  2062. cls.bulk_create_data = {
  2063. 'device': device.pk,
  2064. 'name': 'Power Port [4-6]]',
  2065. 'type': PowerPortTypeChoices.TYPE_IEC_C14,
  2066. 'maximum_draw': 100,
  2067. 'allocated_draw': 50,
  2068. 'description': 'A power port',
  2069. 'tags': [t.pk for t in tags],
  2070. }
  2071. cls.bulk_edit_data = {
  2072. 'type': PowerPortTypeChoices.TYPE_IEC_C14,
  2073. 'maximum_draw': 100,
  2074. 'allocated_draw': 50,
  2075. 'description': 'New description',
  2076. }
  2077. cls.csv_data = (
  2078. "device,name",
  2079. "Device 1,Power Port 4",
  2080. "Device 1,Power Port 5",
  2081. "Device 1,Power Port 6",
  2082. )
  2083. cls.csv_update_data = (
  2084. "id,name,description",
  2085. f"{power_ports[0].pk},Power Port 7,New description7",
  2086. f"{power_ports[1].pk},Power Port 8,New description8",
  2087. f"{power_ports[2].pk},Power Port 9,New description9",
  2088. )
  2089. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  2090. def test_trace(self):
  2091. powerport = PowerPort.objects.first()
  2092. poweroutlet = PowerOutlet.objects.create(
  2093. device=powerport.device,
  2094. name='Power Outlet 1'
  2095. )
  2096. Cable(a_terminations=[powerport], b_terminations=[poweroutlet]).save()
  2097. response = self.client.get(reverse('dcim:powerport_trace', kwargs={'pk': powerport.pk}))
  2098. self.assertHttpStatus(response, 200)
  2099. class PowerOutletTestCase(ViewTestCases.DeviceComponentViewTestCase):
  2100. model = PowerOutlet
  2101. validation_excluded_fields = ('name', 'label')
  2102. @classmethod
  2103. def setUpTestData(cls):
  2104. device = create_test_device('Device 1')
  2105. powerports = (
  2106. PowerPort(device=device, name='Power Port 1'),
  2107. PowerPort(device=device, name='Power Port 2'),
  2108. )
  2109. PowerPort.objects.bulk_create(powerports)
  2110. power_outlets = (
  2111. PowerOutlet(device=device, name='Power Outlet 1', power_port=powerports[0]),
  2112. PowerOutlet(device=device, name='Power Outlet 2', power_port=powerports[0]),
  2113. PowerOutlet(device=device, name='Power Outlet 3', power_port=powerports[0]),
  2114. )
  2115. PowerOutlet.objects.bulk_create(power_outlets)
  2116. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  2117. cls.form_data = {
  2118. 'device': device.pk,
  2119. 'name': 'Power Outlet X',
  2120. 'type': PowerOutletTypeChoices.TYPE_IEC_C13,
  2121. 'power_port': powerports[1].pk,
  2122. 'feed_leg': PowerOutletFeedLegChoices.FEED_LEG_B,
  2123. 'description': 'A power outlet',
  2124. 'tags': [t.pk for t in tags],
  2125. }
  2126. cls.bulk_create_data = {
  2127. 'device': device.pk,
  2128. 'name': 'Power Outlet [4-6]',
  2129. 'type': PowerOutletTypeChoices.TYPE_IEC_C13,
  2130. 'power_port': powerports[1].pk,
  2131. 'feed_leg': PowerOutletFeedLegChoices.FEED_LEG_B,
  2132. 'description': 'A power outlet',
  2133. 'tags': [t.pk for t in tags],
  2134. }
  2135. cls.bulk_edit_data = {
  2136. 'type': PowerOutletTypeChoices.TYPE_IEC_C15,
  2137. 'power_port': powerports[1].pk,
  2138. 'feed_leg': PowerOutletFeedLegChoices.FEED_LEG_B,
  2139. 'description': 'New description',
  2140. }
  2141. cls.csv_data = (
  2142. "device,name",
  2143. "Device 1,Power Outlet 4",
  2144. "Device 1,Power Outlet 5",
  2145. "Device 1,Power Outlet 6",
  2146. )
  2147. cls.csv_update_data = (
  2148. "id,name,description",
  2149. f"{power_outlets[0].pk},Power Outlet 7,New description7",
  2150. f"{power_outlets[1].pk},Power Outlet 8,New description8",
  2151. f"{power_outlets[2].pk},Power Outlet 9,New description9",
  2152. )
  2153. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  2154. def test_trace(self):
  2155. poweroutlet = PowerOutlet.objects.first()
  2156. powerport = PowerPort.objects.first()
  2157. Cable(a_terminations=[poweroutlet], b_terminations=[powerport]).save()
  2158. response = self.client.get(reverse('dcim:poweroutlet_trace', kwargs={'pk': poweroutlet.pk}))
  2159. self.assertHttpStatus(response, 200)
  2160. class InterfaceTestCase(ViewTestCases.DeviceComponentViewTestCase):
  2161. model = Interface
  2162. validation_excluded_fields = ('name', 'label')
  2163. @classmethod
  2164. def setUpTestData(cls):
  2165. device = create_test_device('Device 1')
  2166. interfaces = (
  2167. Interface(device=device, name='Interface 1'),
  2168. Interface(device=device, name='Interface 2'),
  2169. Interface(device=device, name='Interface 3'),
  2170. Interface(device=device, name='LAG', type=InterfaceTypeChoices.TYPE_LAG),
  2171. Interface(device=device, name='_BRIDGE', type=InterfaceTypeChoices.TYPE_VIRTUAL), # Must be ordered last
  2172. )
  2173. Interface.objects.bulk_create(interfaces)
  2174. vlans = (
  2175. VLAN(vid=1, name='VLAN1', site=device.site),
  2176. VLAN(vid=101, name='VLAN101', site=device.site),
  2177. VLAN(vid=102, name='VLAN102', site=device.site),
  2178. VLAN(vid=103, name='VLAN103', site=device.site),
  2179. )
  2180. VLAN.objects.bulk_create(vlans)
  2181. wireless_lans = (
  2182. WirelessLAN(ssid='WLAN1'),
  2183. WirelessLAN(ssid='WLAN2'),
  2184. )
  2185. WirelessLAN.objects.bulk_create(wireless_lans)
  2186. vrfs = (
  2187. VRF(name='VRF 1'),
  2188. VRF(name='VRF 2'),
  2189. VRF(name='VRF 3'),
  2190. )
  2191. VRF.objects.bulk_create(vrfs)
  2192. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  2193. cls.form_data = {
  2194. 'device': device.pk,
  2195. 'name': 'Interface X',
  2196. 'type': InterfaceTypeChoices.TYPE_1GE_GBIC,
  2197. 'enabled': False,
  2198. 'bridge': interfaces[4].pk,
  2199. 'lag': interfaces[3].pk,
  2200. 'wwn': EUI('01:02:03:04:05:06:07:08', version=64),
  2201. 'mtu': 65000,
  2202. 'speed': 1000000,
  2203. 'duplex': 'full',
  2204. 'mgmt_only': True,
  2205. 'description': 'A front port',
  2206. 'mode': InterfaceModeChoices.MODE_TAGGED,
  2207. 'tx_power': 10,
  2208. 'poe_mode': InterfacePoEModeChoices.MODE_PSE,
  2209. 'poe_type': InterfacePoETypeChoices.TYPE_1_8023AF,
  2210. 'untagged_vlan': vlans[0].pk,
  2211. 'tagged_vlans': [v.pk for v in vlans[1:4]],
  2212. 'wireless_lans': [wireless_lans[0].pk, wireless_lans[1].pk],
  2213. 'vrf': vrfs[0].pk,
  2214. 'tags': [t.pk for t in tags],
  2215. }
  2216. cls.bulk_create_data = {
  2217. 'device': device.pk,
  2218. 'name': 'Interface [4-6]',
  2219. 'type': InterfaceTypeChoices.TYPE_1GE_GBIC,
  2220. 'enabled': False,
  2221. 'bridge': interfaces[4].pk,
  2222. 'lag': interfaces[3].pk,
  2223. 'wwn': EUI('01:02:03:04:05:06:07:08', version=64),
  2224. 'mtu': 2000,
  2225. 'speed': 100000,
  2226. 'duplex': 'half',
  2227. 'mgmt_only': True,
  2228. 'description': 'A front port',
  2229. 'poe_mode': InterfacePoEModeChoices.MODE_PSE,
  2230. 'poe_type': InterfacePoETypeChoices.TYPE_1_8023AF,
  2231. 'mode': InterfaceModeChoices.MODE_TAGGED,
  2232. 'untagged_vlan': vlans[0].pk,
  2233. 'tagged_vlans': [v.pk for v in vlans[1:4]],
  2234. 'wireless_lans': [wireless_lans[0].pk, wireless_lans[1].pk],
  2235. 'vrf': vrfs[0].pk,
  2236. 'tags': [t.pk for t in tags],
  2237. }
  2238. cls.bulk_edit_data = {
  2239. 'type': InterfaceTypeChoices.TYPE_1GE_FIXED,
  2240. 'enabled': True,
  2241. 'lag': interfaces[3].pk,
  2242. 'wwn': EUI('01:02:03:04:05:06:07:08', version=64),
  2243. 'mtu': 2000,
  2244. 'speed': 1000000,
  2245. 'duplex': 'full',
  2246. 'mgmt_only': True,
  2247. 'description': 'New description',
  2248. 'poe_mode': InterfacePoEModeChoices.MODE_PD,
  2249. 'poe_type': InterfacePoETypeChoices.TYPE_2_8023AT,
  2250. 'mode': InterfaceModeChoices.MODE_TAGGED,
  2251. 'tx_power': 10,
  2252. 'untagged_vlan': vlans[0].pk,
  2253. 'tagged_vlans': [v.pk for v in vlans[1:4]],
  2254. 'vrf': vrfs[1].pk,
  2255. }
  2256. cls.csv_data = (
  2257. "device,name,type,vrf.pk,poe_mode,poe_type",
  2258. f"Device 1,Interface 4,1000base-t,{vrfs[0].pk},pse,type1-ieee802.3af",
  2259. f"Device 1,Interface 5,1000base-t,{vrfs[0].pk},pse,type1-ieee802.3af",
  2260. f"Device 1,Interface 6,1000base-t,{vrfs[0].pk},pse,type1-ieee802.3af",
  2261. )
  2262. cls.csv_update_data = (
  2263. "id,name,description",
  2264. f"{interfaces[0].pk},Interface 7,New description7",
  2265. f"{interfaces[1].pk},Interface 8,New description8",
  2266. f"{interfaces[2].pk},Interface 9,New description9",
  2267. )
  2268. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  2269. def test_trace(self):
  2270. interface1, interface2 = Interface.objects.all()[:2]
  2271. Cable(a_terminations=[interface1], b_terminations=[interface2]).save()
  2272. response = self.client.get(reverse('dcim:interface_trace', kwargs={'pk': interface1.pk}))
  2273. self.assertHttpStatus(response, 200)
  2274. def test_bulk_delete_child_interfaces(self):
  2275. interface1 = Interface.objects.get(name='Interface 1')
  2276. device = interface1.device
  2277. self.add_permissions('dcim.delete_interface')
  2278. # Create a child interface
  2279. child = Interface.objects.create(
  2280. device=device,
  2281. name='Interface 1A',
  2282. type=InterfaceTypeChoices.TYPE_VIRTUAL,
  2283. parent=interface1
  2284. )
  2285. self.assertEqual(device.interfaces.count(), 6)
  2286. # Attempt to delete only the parent interface
  2287. data = {
  2288. 'confirm': True,
  2289. }
  2290. self.client.post(self._get_url('delete', interface1), data)
  2291. self.assertEqual(device.interfaces.count(), 6) # Parent was not deleted
  2292. # Attempt to bulk delete parent & child together
  2293. data = {
  2294. 'pk': [interface1.pk, child.pk],
  2295. 'confirm': True,
  2296. '_confirm': True, # Form button
  2297. }
  2298. self.client.post(self._get_url('bulk_delete'), data)
  2299. self.assertEqual(device.interfaces.count(), 4) # Child & parent were both deleted
  2300. class FrontPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
  2301. model = FrontPort
  2302. validation_excluded_fields = ('name', 'label', 'rear_port')
  2303. @classmethod
  2304. def setUpTestData(cls):
  2305. device = create_test_device('Device 1')
  2306. rearports = (
  2307. RearPort(device=device, name='Rear Port 1'),
  2308. RearPort(device=device, name='Rear Port 2'),
  2309. RearPort(device=device, name='Rear Port 3'),
  2310. RearPort(device=device, name='Rear Port 4'),
  2311. RearPort(device=device, name='Rear Port 5'),
  2312. RearPort(device=device, name='Rear Port 6'),
  2313. )
  2314. RearPort.objects.bulk_create(rearports)
  2315. front_ports = (
  2316. FrontPort(device=device, name='Front Port 1', rear_port=rearports[0]),
  2317. FrontPort(device=device, name='Front Port 2', rear_port=rearports[1]),
  2318. FrontPort(device=device, name='Front Port 3', rear_port=rearports[2]),
  2319. )
  2320. FrontPort.objects.bulk_create(front_ports)
  2321. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  2322. cls.form_data = {
  2323. 'device': device.pk,
  2324. 'name': 'Front Port X',
  2325. 'type': PortTypeChoices.TYPE_8P8C,
  2326. 'rear_port': rearports[3].pk,
  2327. 'rear_port_position': 1,
  2328. 'description': 'New description',
  2329. 'tags': [t.pk for t in tags],
  2330. }
  2331. cls.bulk_create_data = {
  2332. 'device': device.pk,
  2333. 'name': 'Front Port [4-6]',
  2334. 'type': PortTypeChoices.TYPE_8P8C,
  2335. 'rear_port': [f'{rp.pk}:1' for rp in rearports[3:6]],
  2336. 'description': 'New description',
  2337. 'tags': [t.pk for t in tags],
  2338. }
  2339. cls.bulk_edit_data = {
  2340. 'type': PortTypeChoices.TYPE_8P8C,
  2341. 'description': 'New description',
  2342. }
  2343. cls.csv_data = (
  2344. "device,name,type,rear_port,rear_port_position",
  2345. "Device 1,Front Port 4,8p8c,Rear Port 4,1",
  2346. "Device 1,Front Port 5,8p8c,Rear Port 5,1",
  2347. "Device 1,Front Port 6,8p8c,Rear Port 6,1",
  2348. )
  2349. cls.csv_update_data = (
  2350. "id,name,description",
  2351. f"{front_ports[0].pk},Front Port 7,New description7",
  2352. f"{front_ports[1].pk},Front Port 8,New description8",
  2353. f"{front_ports[2].pk},Front Port 9,New description9",
  2354. )
  2355. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  2356. def test_trace(self):
  2357. frontport = FrontPort.objects.first()
  2358. interface = Interface.objects.create(
  2359. device=frontport.device,
  2360. name='Interface 1'
  2361. )
  2362. Cable(a_terminations=[frontport], b_terminations=[interface]).save()
  2363. response = self.client.get(reverse('dcim:frontport_trace', kwargs={'pk': frontport.pk}))
  2364. self.assertHttpStatus(response, 200)
  2365. class RearPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
  2366. model = RearPort
  2367. validation_excluded_fields = ('name', 'label')
  2368. @classmethod
  2369. def setUpTestData(cls):
  2370. device = create_test_device('Device 1')
  2371. rear_ports = (
  2372. RearPort(device=device, name='Rear Port 1'),
  2373. RearPort(device=device, name='Rear Port 2'),
  2374. RearPort(device=device, name='Rear Port 3'),
  2375. )
  2376. RearPort.objects.bulk_create(rear_ports)
  2377. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  2378. cls.form_data = {
  2379. 'device': device.pk,
  2380. 'name': 'Rear Port X',
  2381. 'type': PortTypeChoices.TYPE_8P8C,
  2382. 'positions': 3,
  2383. 'description': 'A rear port',
  2384. 'tags': [t.pk for t in tags],
  2385. }
  2386. cls.bulk_create_data = {
  2387. 'device': device.pk,
  2388. 'name': 'Rear Port [4-6]',
  2389. 'type': PortTypeChoices.TYPE_8P8C,
  2390. 'positions': 3,
  2391. 'description': 'A rear port',
  2392. 'tags': [t.pk for t in tags],
  2393. }
  2394. cls.bulk_edit_data = {
  2395. 'type': PortTypeChoices.TYPE_8P8C,
  2396. 'description': 'New description',
  2397. }
  2398. cls.csv_data = (
  2399. "device,name,type,positions",
  2400. "Device 1,Rear Port 4,8p8c,1",
  2401. "Device 1,Rear Port 5,8p8c,1",
  2402. "Device 1,Rear Port 6,8p8c,1",
  2403. )
  2404. cls.csv_update_data = (
  2405. "id,name,description",
  2406. f"{rear_ports[0].pk},Rear Port 7,New description7",
  2407. f"{rear_ports[1].pk},Rear Port 8,New description8",
  2408. f"{rear_ports[2].pk},Rear Port 9,New description9",
  2409. )
  2410. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  2411. def test_trace(self):
  2412. rearport = RearPort.objects.first()
  2413. interface = Interface.objects.create(
  2414. device=rearport.device,
  2415. name='Interface 1'
  2416. )
  2417. Cable(a_terminations=[rearport], b_terminations=[interface]).save()
  2418. response = self.client.get(reverse('dcim:rearport_trace', kwargs={'pk': rearport.pk}))
  2419. self.assertHttpStatus(response, 200)
  2420. class ModuleBayTestCase(ViewTestCases.DeviceComponentViewTestCase):
  2421. model = ModuleBay
  2422. validation_excluded_fields = ('name', 'label')
  2423. @classmethod
  2424. def setUpTestData(cls):
  2425. device = create_test_device('Device 1')
  2426. module_bays = (
  2427. ModuleBay(device=device, name='Module Bay 1'),
  2428. ModuleBay(device=device, name='Module Bay 2'),
  2429. ModuleBay(device=device, name='Module Bay 3'),
  2430. )
  2431. for module_bay in module_bays:
  2432. module_bay.save()
  2433. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  2434. cls.form_data = {
  2435. 'device': device.pk,
  2436. 'name': 'Module Bay X',
  2437. 'description': 'A device bay',
  2438. 'tags': [t.pk for t in tags],
  2439. }
  2440. cls.bulk_create_data = {
  2441. 'device': device.pk,
  2442. 'name': 'Module Bay [4-6]',
  2443. 'description': 'A module bay',
  2444. 'tags': [t.pk for t in tags],
  2445. }
  2446. cls.bulk_edit_data = {
  2447. 'description': 'New description',
  2448. }
  2449. cls.csv_data = (
  2450. "device,name",
  2451. "Device 1,Module Bay 4",
  2452. "Device 1,Module Bay 5",
  2453. "Device 1,Module Bay 6",
  2454. )
  2455. cls.csv_update_data = (
  2456. "id,name,description",
  2457. f"{module_bays[0].pk},Module Bay 7,New description7",
  2458. f"{module_bays[1].pk},Module Bay 8,New description8",
  2459. f"{module_bays[2].pk},Module Bay 9,New description9",
  2460. )
  2461. class DeviceBayTestCase(ViewTestCases.DeviceComponentViewTestCase):
  2462. model = DeviceBay
  2463. validation_excluded_fields = ('name', 'label')
  2464. @classmethod
  2465. def setUpTestData(cls):
  2466. device = create_test_device('Device 1')
  2467. # Update the DeviceType subdevice role to allow adding DeviceBays
  2468. DeviceType.objects.update(subdevice_role=SubdeviceRoleChoices.ROLE_PARENT)
  2469. device_bays = (
  2470. DeviceBay(device=device, name='Device Bay 1'),
  2471. DeviceBay(device=device, name='Device Bay 2'),
  2472. DeviceBay(device=device, name='Device Bay 3'),
  2473. )
  2474. DeviceBay.objects.bulk_create(device_bays)
  2475. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  2476. cls.form_data = {
  2477. 'device': device.pk,
  2478. 'name': 'Device Bay X',
  2479. 'description': 'A device bay',
  2480. 'tags': [t.pk for t in tags],
  2481. }
  2482. cls.bulk_create_data = {
  2483. 'device': device.pk,
  2484. 'name': 'Device Bay [4-6]',
  2485. 'description': 'A device bay',
  2486. 'tags': [t.pk for t in tags],
  2487. }
  2488. cls.bulk_edit_data = {
  2489. 'description': 'New description',
  2490. }
  2491. cls.csv_data = (
  2492. "device,name",
  2493. "Device 1,Device Bay 4",
  2494. "Device 1,Device Bay 5",
  2495. "Device 1,Device Bay 6",
  2496. )
  2497. cls.csv_update_data = (
  2498. "id,name,description",
  2499. f"{device_bays[0].pk},Device Bay 7,New description7",
  2500. f"{device_bays[1].pk},Device Bay 8,New description8",
  2501. f"{device_bays[2].pk},Device Bay 9,New description9",
  2502. )
  2503. class InventoryItemTestCase(ViewTestCases.DeviceComponentViewTestCase):
  2504. model = InventoryItem
  2505. validation_excluded_fields = ('name', 'label')
  2506. @classmethod
  2507. def setUpTestData(cls):
  2508. device = create_test_device('Device 1')
  2509. manufacturer, _ = Manufacturer.objects.get_or_create(name='Manufacturer 1', slug='manufacturer-1')
  2510. roles = (
  2511. InventoryItemRole(name='Inventory Item Role 1', slug='inventory-item-role-1'),
  2512. InventoryItemRole(name='Inventory Item Role 2', slug='inventory-item-role-2'),
  2513. )
  2514. InventoryItemRole.objects.bulk_create(roles)
  2515. inventory_item1 = InventoryItem.objects.create(
  2516. device=device, name='Inventory Item 1', role=roles[0], manufacturer=manufacturer
  2517. )
  2518. inventory_item2 = InventoryItem.objects.create(
  2519. device=device, name='Inventory Item 2', role=roles[0], manufacturer=manufacturer
  2520. )
  2521. inventory_item3 = InventoryItem.objects.create(
  2522. device=device, name='Inventory Item 3', role=roles[0], manufacturer=manufacturer
  2523. )
  2524. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  2525. cls.form_data = {
  2526. 'device': device.pk,
  2527. 'role': roles[1].pk,
  2528. 'manufacturer': manufacturer.pk,
  2529. 'name': 'Inventory Item X',
  2530. 'parent': None,
  2531. 'discovered': False,
  2532. 'part_id': '123456',
  2533. 'serial': '123ABC',
  2534. 'asset_tag': 'ABC123',
  2535. 'status': InventoryItemStatusChoices.STATUS_ACTIVE,
  2536. 'description': 'An inventory item',
  2537. 'tags': [t.pk for t in tags],
  2538. }
  2539. cls.bulk_create_data = {
  2540. 'device': device.pk,
  2541. 'name': 'Inventory Item [4-6]',
  2542. 'role': roles[1].pk,
  2543. 'manufacturer': manufacturer.pk,
  2544. 'parent': None,
  2545. 'discovered': False,
  2546. 'part_id': '123456',
  2547. 'serial': '123ABC',
  2548. 'status': InventoryItemStatusChoices.STATUS_ACTIVE,
  2549. 'description': 'An inventory item',
  2550. 'tags': [t.pk for t in tags],
  2551. }
  2552. cls.bulk_edit_data = {
  2553. 'role': roles[1].pk,
  2554. 'part_id': '123456',
  2555. 'description': 'New description',
  2556. }
  2557. cls.csv_data = (
  2558. "device,name,parent,status",
  2559. "Device 1,Inventory Item 4,Inventory Item 1,active",
  2560. "Device 1,Inventory Item 5,Inventory Item 2,planned",
  2561. "Device 1,Inventory Item 6,Inventory Item 3,failed",
  2562. )
  2563. cls.csv_update_data = (
  2564. "id,name,description",
  2565. f"{inventory_item1.pk},Inventory Item 7,New description7",
  2566. f"{inventory_item2.pk},Inventory Item 8,New description8",
  2567. f"{inventory_item3.pk},Inventory Item 9,New description9",
  2568. )
  2569. class InventoryItemRoleTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
  2570. model = InventoryItemRole
  2571. @classmethod
  2572. def setUpTestData(cls):
  2573. inventory_item_roles = (
  2574. InventoryItemRole(name='Inventory Item Role 1', slug='inventory-item-role-1'),
  2575. InventoryItemRole(name='Inventory Item Role 2', slug='inventory-item-role-2'),
  2576. InventoryItemRole(name='Inventory Item Role 3', slug='inventory-item-role-3'),
  2577. )
  2578. InventoryItemRole.objects.bulk_create(inventory_item_roles)
  2579. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  2580. cls.form_data = {
  2581. 'name': 'Inventory Item Role X',
  2582. 'slug': 'inventory-item-role-x',
  2583. 'color': 'c0c0c0',
  2584. 'description': 'New inventory item role',
  2585. 'tags': [t.pk for t in tags],
  2586. }
  2587. cls.csv_data = (
  2588. "name,slug,color",
  2589. "Inventory Item Role 4,inventory-item-role-4,ff0000",
  2590. "Inventory Item Role 5,inventory-item-role-5,00ff00",
  2591. "Inventory Item Role 6,inventory-item-role-6,0000ff",
  2592. )
  2593. cls.csv_update_data = (
  2594. "id,name,description",
  2595. f"{inventory_item_roles[0].pk},Inventory Item Role 7,New description7",
  2596. f"{inventory_item_roles[1].pk},Inventory Item Role 8,New description8",
  2597. f"{inventory_item_roles[2].pk},Inventory Item Role 9,New description9",
  2598. )
  2599. cls.bulk_edit_data = {
  2600. 'color': '00ff00',
  2601. 'description': 'New description',
  2602. }
  2603. # TODO: Change base class to PrimaryObjectViewTestCase
  2604. # Blocked by lack of common creation view for cables (termination A must be initialized)
  2605. class CableTestCase(
  2606. ViewTestCases.GetObjectViewTestCase,
  2607. ViewTestCases.GetObjectChangelogViewTestCase,
  2608. ViewTestCases.EditObjectViewTestCase,
  2609. ViewTestCases.DeleteObjectViewTestCase,
  2610. ViewTestCases.ListObjectsViewTestCase,
  2611. ViewTestCases.BulkImportObjectsViewTestCase,
  2612. ViewTestCases.BulkEditObjectsViewTestCase,
  2613. ViewTestCases.BulkDeleteObjectsViewTestCase
  2614. ):
  2615. model = Cable
  2616. @classmethod
  2617. def setUpTestData(cls):
  2618. site = Site.objects.create(name='Site 1', slug='site-1')
  2619. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  2620. devicetype = DeviceType.objects.create(model='Device Type 1', manufacturer=manufacturer)
  2621. role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1')
  2622. vc = VirtualChassis.objects.create(name='Virtual Chassis')
  2623. devices = (
  2624. Device(name='Device 1', site=site, device_type=devicetype, role=role),
  2625. Device(name='Device 2', site=site, device_type=devicetype, role=role),
  2626. Device(name='Device 3', site=site, device_type=devicetype, role=role),
  2627. Device(name='Device 4', site=site, device_type=devicetype, role=role),
  2628. )
  2629. Device.objects.bulk_create(devices)
  2630. vc.members.set((devices[0], devices[1], devices[2]))
  2631. vc.master = devices[0]
  2632. vc.save()
  2633. interfaces = (
  2634. Interface(device=devices[0], name='Interface 1', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  2635. Interface(device=devices[0], name='Interface 2', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  2636. Interface(device=devices[0], name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  2637. Interface(device=devices[1], name='Interface 1', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  2638. Interface(device=devices[1], name='Interface 2', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  2639. Interface(device=devices[1], name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  2640. Interface(device=devices[2], name='Interface 1', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  2641. Interface(device=devices[2], name='Interface 2', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  2642. Interface(device=devices[2], name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  2643. Interface(device=devices[3], name='Interface 1', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  2644. Interface(device=devices[3], name='Interface 2', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  2645. Interface(device=devices[3], name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  2646. Interface(device=devices[1], name='Device 2 Interface', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  2647. Interface(device=devices[2], name='Device 3 Interface', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  2648. Interface(device=devices[3], name='Interface 4', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  2649. Interface(device=devices[3], name='Interface 5', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  2650. )
  2651. Interface.objects.bulk_create(interfaces)
  2652. cable1 = Cable(a_terminations=[interfaces[0]], b_terminations=[interfaces[3]], type=CableTypeChoices.TYPE_CAT6)
  2653. cable1.save()
  2654. cable2 = Cable(a_terminations=[interfaces[1]], b_terminations=[interfaces[4]], type=CableTypeChoices.TYPE_CAT6)
  2655. cable2.save()
  2656. cable3 = Cable(a_terminations=[interfaces[2]], b_terminations=[interfaces[5]], type=CableTypeChoices.TYPE_CAT6)
  2657. cable3.save()
  2658. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  2659. cls.form_data = {
  2660. # TODO: Revisit this limitation
  2661. # Changing terminations not supported when editing an existing Cable
  2662. 'a_terminations': [interfaces[0].pk],
  2663. 'b_terminations': [interfaces[3].pk],
  2664. 'type': CableTypeChoices.TYPE_CAT6,
  2665. 'status': LinkStatusChoices.STATUS_PLANNED,
  2666. 'label': 'Label',
  2667. 'color': 'c0c0c0',
  2668. 'length': 100,
  2669. 'length_unit': CableLengthUnitChoices.UNIT_FOOT,
  2670. 'tags': [t.pk for t in tags],
  2671. }
  2672. cls.csv_data = (
  2673. "side_a_device,side_a_type,side_a_name,side_b_device,side_b_type,side_b_name",
  2674. "Device 3,dcim.interface,Interface 1,Device 4,dcim.interface,Interface 1",
  2675. "Device 3,dcim.interface,Interface 2,Device 4,dcim.interface,Interface 2",
  2676. "Device 3,dcim.interface,Interface 3,Device 4,dcim.interface,Interface 3",
  2677. "Device 1,dcim.interface,Device 2 Interface,Device 4,dcim.interface,Interface 4",
  2678. "Device 1,dcim.interface,Device 3 Interface,Device 4,dcim.interface,Interface 5",
  2679. )
  2680. cls.csv_update_data = (
  2681. "id,label,color",
  2682. f"{cable1.pk},New label7,00ff00",
  2683. f"{cable2.pk},New label8,00ff00",
  2684. f"{cable3.pk},New label9,00ff00",
  2685. )
  2686. cls.bulk_edit_data = {
  2687. 'type': CableTypeChoices.TYPE_CAT5E,
  2688. 'status': LinkStatusChoices.STATUS_CONNECTED,
  2689. 'label': 'New label',
  2690. 'color': '00ff00',
  2691. 'length': 50,
  2692. 'length_unit': CableLengthUnitChoices.UNIT_METER,
  2693. }
  2694. def model_to_dict(self, *args, **kwargs):
  2695. data = super().model_to_dict(*args, **kwargs)
  2696. # Serialize termination objects
  2697. if 'a_terminations' in data:
  2698. data['a_terminations'] = [obj.pk for obj in data['a_terminations']]
  2699. if 'b_terminations' in data:
  2700. data['b_terminations'] = [obj.pk for obj in data['b_terminations']]
  2701. return data
  2702. class VirtualChassisTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  2703. model = VirtualChassis
  2704. @classmethod
  2705. def setUpTestData(cls):
  2706. site = Site.objects.create(name='Site 1', slug='site-1')
  2707. manufacturer = Manufacturer.objects.create(name='Manufacturer', slug='manufacturer-1')
  2708. device_type = DeviceType.objects.create(
  2709. manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'
  2710. )
  2711. role = DeviceRole.objects.create(
  2712. name='Device Role', slug='device-role-1'
  2713. )
  2714. devices = (
  2715. Device(device_type=device_type, role=role, name='Device 1', site=site),
  2716. Device(device_type=device_type, role=role, name='Device 2', site=site),
  2717. Device(device_type=device_type, role=role, name='Device 3', site=site),
  2718. Device(device_type=device_type, role=role, name='Device 4', site=site),
  2719. Device(device_type=device_type, role=role, name='Device 5', site=site),
  2720. Device(device_type=device_type, role=role, name='Device 6', site=site),
  2721. Device(device_type=device_type, role=role, name='Device 7', site=site),
  2722. Device(device_type=device_type, role=role, name='Device 8', site=site),
  2723. Device(device_type=device_type, role=role, name='Device 9', site=site),
  2724. Device(device_type=device_type, role=role, name='Device 10', site=site),
  2725. Device(device_type=device_type, role=role, name='Device 11', site=site),
  2726. Device(device_type=device_type, role=role, name='Device 12', site=site),
  2727. )
  2728. Device.objects.bulk_create(devices)
  2729. # Create three VirtualChassis with three members each
  2730. vc1 = VirtualChassis.objects.create(name='VC1', master=devices[0], domain='domain-1')
  2731. Device.objects.filter(pk=devices[0].pk).update(virtual_chassis=vc1, vc_position=1)
  2732. Device.objects.filter(pk=devices[1].pk).update(virtual_chassis=vc1, vc_position=2)
  2733. Device.objects.filter(pk=devices[2].pk).update(virtual_chassis=vc1, vc_position=3)
  2734. vc2 = VirtualChassis.objects.create(name='VC2', master=devices[3], domain='domain-2')
  2735. Device.objects.filter(pk=devices[3].pk).update(virtual_chassis=vc2, vc_position=1)
  2736. Device.objects.filter(pk=devices[4].pk).update(virtual_chassis=vc2, vc_position=2)
  2737. Device.objects.filter(pk=devices[5].pk).update(virtual_chassis=vc2, vc_position=3)
  2738. vc3 = VirtualChassis.objects.create(name='VC3', master=devices[6], domain='domain-3')
  2739. Device.objects.filter(pk=devices[6].pk).update(virtual_chassis=vc3, vc_position=1)
  2740. Device.objects.filter(pk=devices[7].pk).update(virtual_chassis=vc3, vc_position=2)
  2741. Device.objects.filter(pk=devices[8].pk).update(virtual_chassis=vc3, vc_position=3)
  2742. cls.form_data = {
  2743. 'name': 'VC4',
  2744. 'domain': 'domain-4',
  2745. # Management form data for VC members
  2746. 'form-TOTAL_FORMS': 0,
  2747. 'form-INITIAL_FORMS': 3,
  2748. 'form-MIN_NUM_FORMS': 0,
  2749. 'form-MAX_NUM_FORMS': 1000,
  2750. }
  2751. cls.csv_data = (
  2752. "name,domain,master",
  2753. "VC4,Domain 4,Device 10",
  2754. "VC5,Domain 5,Device 11",
  2755. "VC6,Domain 6,Device 12",
  2756. )
  2757. cls.csv_update_data = (
  2758. "id,name,domain",
  2759. f"{vc1.pk},VC7,Domain 7",
  2760. f"{vc2.pk},VC8,Domain 8",
  2761. f"{vc3.pk},VC9,Domain 9",
  2762. )
  2763. cls.bulk_edit_data = {
  2764. 'domain': 'domain-x',
  2765. }
  2766. class PowerPanelTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  2767. model = PowerPanel
  2768. @classmethod
  2769. def setUpTestData(cls):
  2770. sites = (
  2771. Site(name='Site 1', slug='site-1'),
  2772. Site(name='Site 2', slug='site-2'),
  2773. )
  2774. Site.objects.bulk_create(sites)
  2775. locations = (
  2776. Location(name='Location 1', slug='location-1', site=sites[0]),
  2777. Location(name='Location 2', slug='location-2', site=sites[1]),
  2778. )
  2779. for location in locations:
  2780. location.save()
  2781. power_panels = (
  2782. PowerPanel(site=sites[0], location=locations[0], name='Power Panel 1'),
  2783. PowerPanel(site=sites[0], location=locations[0], name='Power Panel 2'),
  2784. PowerPanel(site=sites[0], location=locations[0], name='Power Panel 3'),
  2785. )
  2786. PowerPanel.objects.bulk_create(power_panels)
  2787. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  2788. cls.form_data = {
  2789. 'site': sites[1].pk,
  2790. 'location': locations[1].pk,
  2791. 'name': 'Power Panel X',
  2792. 'tags': [t.pk for t in tags],
  2793. }
  2794. cls.csv_data = (
  2795. "site,location,name",
  2796. "Site 1,Location 1,Power Panel 4",
  2797. "Site 1,Location 1,Power Panel 5",
  2798. "Site 1,Location 1,Power Panel 6",
  2799. )
  2800. cls.csv_update_data = (
  2801. "id,name",
  2802. f"{power_panels[0].pk},Power Panel 7",
  2803. f"{power_panels[1].pk},Power Panel 8",
  2804. f"{power_panels[2].pk},Power Panel 9",
  2805. )
  2806. cls.bulk_edit_data = {
  2807. 'site': sites[1].pk,
  2808. 'location': locations[1].pk,
  2809. }
  2810. class PowerFeedTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  2811. model = PowerFeed
  2812. @classmethod
  2813. def setUpTestData(cls):
  2814. site = Site.objects.create(name='Site 1', slug='site-1')
  2815. powerpanels = (
  2816. PowerPanel(site=site, name='Power Panel 1'),
  2817. PowerPanel(site=site, name='Power Panel 2'),
  2818. )
  2819. PowerPanel.objects.bulk_create(powerpanels)
  2820. racks = (
  2821. Rack(site=site, name='Rack 1'),
  2822. Rack(site=site, name='Rack 2'),
  2823. )
  2824. Rack.objects.bulk_create(racks)
  2825. power_feeds = (
  2826. PowerFeed(name='Power Feed 1', power_panel=powerpanels[0], rack=racks[0]),
  2827. PowerFeed(name='Power Feed 2', power_panel=powerpanels[0], rack=racks[0]),
  2828. PowerFeed(name='Power Feed 3', power_panel=powerpanels[0], rack=racks[0]),
  2829. )
  2830. PowerFeed.objects.bulk_create(power_feeds)
  2831. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  2832. cls.form_data = {
  2833. 'name': 'Power Feed X',
  2834. 'power_panel': powerpanels[1].pk,
  2835. 'rack': racks[1].pk,
  2836. 'status': PowerFeedStatusChoices.STATUS_PLANNED,
  2837. 'type': PowerFeedTypeChoices.TYPE_REDUNDANT,
  2838. 'supply': PowerFeedSupplyChoices.SUPPLY_DC,
  2839. 'phase': PowerFeedPhaseChoices.PHASE_3PHASE,
  2840. 'voltage': 100,
  2841. 'amperage': 100,
  2842. 'max_utilization': 50,
  2843. 'comments': 'New comments',
  2844. 'tags': [t.pk for t in tags],
  2845. }
  2846. cls.csv_data = (
  2847. "site,power_panel,name,status,type,supply,phase,voltage,amperage,max_utilization",
  2848. "Site 1,Power Panel 1,Power Feed 4,active,primary,ac,single-phase,120,20,80",
  2849. "Site 1,Power Panel 1,Power Feed 5,active,primary,ac,single-phase,120,20,80",
  2850. "Site 1,Power Panel 1,Power Feed 6,active,primary,ac,single-phase,120,20,80",
  2851. )
  2852. cls.csv_update_data = (
  2853. "id,name,status",
  2854. f"{power_feeds[0].pk},Power Feed 7,{PowerFeedStatusChoices.STATUS_PLANNED}",
  2855. f"{power_feeds[1].pk},Power Feed 8,{PowerFeedStatusChoices.STATUS_PLANNED}",
  2856. f"{power_feeds[2].pk},Power Feed 9,{PowerFeedStatusChoices.STATUS_PLANNED}",
  2857. )
  2858. cls.bulk_edit_data = {
  2859. 'power_panel': powerpanels[1].pk,
  2860. 'rack': racks[1].pk,
  2861. 'status': PowerFeedStatusChoices.STATUS_PLANNED,
  2862. 'type': PowerFeedTypeChoices.TYPE_REDUNDANT,
  2863. 'supply': PowerFeedSupplyChoices.SUPPLY_DC,
  2864. 'phase': PowerFeedPhaseChoices.PHASE_3PHASE,
  2865. 'voltage': 100,
  2866. 'amperage': 100,
  2867. 'max_utilization': 50,
  2868. 'comments': 'New comments',
  2869. }
  2870. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  2871. def test_trace(self):
  2872. manufacturer = Manufacturer.objects.create(name='Manufacturer', slug='manufacturer-1')
  2873. device_type = DeviceType.objects.create(
  2874. manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'
  2875. )
  2876. role = DeviceRole.objects.create(
  2877. name='Device Role', slug='device-role-1'
  2878. )
  2879. device = Device.objects.create(
  2880. site=Site.objects.first(), device_type=device_type, role=role
  2881. )
  2882. powerfeed = PowerFeed.objects.first()
  2883. powerport = PowerPort.objects.create(
  2884. device=device,
  2885. name='Power Port 1'
  2886. )
  2887. Cable(a_terminations=[powerfeed], b_terminations=[powerport]).save()
  2888. response = self.client.get(reverse('dcim:powerfeed_trace', kwargs={'pk': powerfeed.pk}))
  2889. self.assertHttpStatus(response, 200)
  2890. class VirtualDeviceContextTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  2891. model = VirtualDeviceContext
  2892. @classmethod
  2893. def setUpTestData(cls):
  2894. devices = [create_test_device(name='Device 1')]
  2895. vdcs = (
  2896. VirtualDeviceContext(name='VDC 1', identifier=1, device=devices[0], status='active'),
  2897. VirtualDeviceContext(name='VDC 2', identifier=2, device=devices[0], status='active'),
  2898. VirtualDeviceContext(name='VDC 3', identifier=3, device=devices[0], status='active'),
  2899. )
  2900. VirtualDeviceContext.objects.bulk_create(vdcs)
  2901. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  2902. cls.form_data = {
  2903. 'device': devices[0].pk,
  2904. 'status': 'active',
  2905. 'name': 'VDC 4',
  2906. 'identifier': 4,
  2907. 'primary_ip4': None,
  2908. 'primary_ip6': None,
  2909. 'tags': [t.pk for t in tags],
  2910. }
  2911. cls.csv_data = (
  2912. "device,status,name,identifier",
  2913. "Device 1,active,VDC 5,5",
  2914. "Device 1,active,VDC 6,6",
  2915. "Device 1,active,VDC 7,7",
  2916. )
  2917. cls.csv_update_data = (
  2918. "id,status",
  2919. f"{vdcs[0].pk},{VirtualDeviceContextStatusChoices.STATUS_PLANNED}",
  2920. f"{vdcs[1].pk},{VirtualDeviceContextStatusChoices.STATUS_PLANNED}",
  2921. f"{vdcs[2].pk},{VirtualDeviceContextStatusChoices.STATUS_PLANNED}",
  2922. )
  2923. cls.bulk_edit_data = {
  2924. 'status': VirtualDeviceContextStatusChoices.STATUS_OFFLINE,
  2925. }
  2926. class MACAddressTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  2927. model = MACAddress
  2928. @classmethod
  2929. def setUpTestData(cls):
  2930. device = create_test_device(name='Device 1')
  2931. interfaces = (
  2932. Interface(device=device, name='Interface 1', type='1000base-t'),
  2933. Interface(device=device, name='Interface 2', type='1000base-t'),
  2934. Interface(device=device, name='Interface 3', type='1000base-t'),
  2935. Interface(device=device, name='Interface 4', type='1000base-t'),
  2936. Interface(device=device, name='Interface 5', type='1000base-t'),
  2937. Interface(device=device, name='Interface 6', type='1000base-t'),
  2938. )
  2939. Interface.objects.bulk_create(interfaces)
  2940. mac_addresses = (
  2941. MACAddress(mac_address='00:00:00:00:00:01', assigned_object=interfaces[0]),
  2942. MACAddress(mac_address='00:00:00:00:00:02', assigned_object=interfaces[1]),
  2943. MACAddress(mac_address='00:00:00:00:00:03', assigned_object=interfaces[2]),
  2944. )
  2945. MACAddress.objects.bulk_create(mac_addresses)
  2946. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  2947. cls.form_data = {
  2948. 'mac_address': EUI('00:00:00:00:00:04'),
  2949. 'description': 'New MAC address',
  2950. 'interface_id': interfaces[3].pk,
  2951. 'tags': [t.pk for t in tags],
  2952. }
  2953. cls.csv_data = (
  2954. "mac_address,device,interface",
  2955. "00:00:00:00:00:04,Device 1,Interface 4",
  2956. "00:00:00:00:00:05,Device 1,Interface 5",
  2957. "00:00:00:00:00:06,Device 1,Interface 6",
  2958. )
  2959. cls.csv_update_data = (
  2960. "id,mac_address",
  2961. f"{mac_addresses[0].pk},00:00:00:00:00:0a",
  2962. f"{mac_addresses[1].pk},00:00:00:00:00:0b",
  2963. f"{mac_addresses[2].pk},00:00:00:00:00:0c",
  2964. )
  2965. cls.bulk_edit_data = {
  2966. 'description': 'New description',
  2967. }