test_views.py 125 KB

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