test_views.py 105 KB

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