test_views.py 80 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199
  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, VLAN, RIR
  13. from tenancy.models import Tenant
  14. from utilities.testing import ViewTestCases, create_tags, create_test_device
  15. class RegionTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
  16. model = Region
  17. @classmethod
  18. def setUpTestData(cls):
  19. # Create three Regions
  20. regions = (
  21. Region(name='Region 1', slug='region-1'),
  22. Region(name='Region 2', slug='region-2'),
  23. Region(name='Region 3', slug='region-3'),
  24. )
  25. for region in regions:
  26. region.save()
  27. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  28. cls.form_data = {
  29. 'name': 'Region X',
  30. 'slug': 'region-x',
  31. 'parent': regions[2].pk,
  32. 'description': 'A new region',
  33. 'tags': [t.pk for t in tags],
  34. }
  35. cls.csv_data = (
  36. "name,slug,description",
  37. "Region 4,region-4,Fourth region",
  38. "Region 5,region-5,Fifth region",
  39. "Region 6,region-6,Sixth region",
  40. )
  41. cls.bulk_edit_data = {
  42. 'description': 'New description',
  43. }
  44. class SiteGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
  45. model = SiteGroup
  46. @classmethod
  47. def setUpTestData(cls):
  48. # Create three SiteGroups
  49. sitegroups = (
  50. SiteGroup(name='Site Group 1', slug='site-group-1'),
  51. SiteGroup(name='Site Group 2', slug='site-group-2'),
  52. SiteGroup(name='Site Group 3', slug='site-group-3'),
  53. )
  54. for sitegroup in sitegroups:
  55. sitegroup.save()
  56. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  57. cls.form_data = {
  58. 'name': 'Site Group X',
  59. 'slug': 'site-group-x',
  60. 'parent': sitegroups[2].pk,
  61. 'description': 'A new site group',
  62. 'tags': [t.pk for t in tags],
  63. }
  64. cls.csv_data = (
  65. "name,slug,description",
  66. "Site Group 4,site-group-4,Fourth site group",
  67. "Site Group 5,site-group-5,Fifth site group",
  68. "Site Group 6,site-group-6,Sixth site group",
  69. )
  70. cls.bulk_edit_data = {
  71. 'description': 'New description',
  72. }
  73. class SiteTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  74. model = Site
  75. @classmethod
  76. def setUpTestData(cls):
  77. regions = (
  78. Region(name='Region 1', slug='region-1'),
  79. Region(name='Region 2', slug='region-2'),
  80. )
  81. for region in regions:
  82. region.save()
  83. groups = (
  84. SiteGroup(name='Site Group 1', slug='site-group-1'),
  85. SiteGroup(name='Site Group 2', slug='site-group-2'),
  86. )
  87. for group in groups:
  88. group.save()
  89. sites = Site.objects.bulk_create([
  90. Site(name='Site 1', slug='site-1', region=regions[0], group=groups[1]),
  91. Site(name='Site 2', slug='site-2', region=regions[0], group=groups[1]),
  92. Site(name='Site 3', slug='site-3', region=regions[0], group=groups[1]),
  93. ])
  94. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  95. rir = RIR.objects.create(name='RFC 6996', is_private=True)
  96. asns = [
  97. ASN(asn=65000, rir=rir),
  98. ASN(asn=65001, rir=rir),
  99. ASN(asn=65002, rir=rir),
  100. ASN(asn=65003, rir=rir),
  101. ASN(asn=65004, rir=rir),
  102. ASN(asn=65005, rir=rir),
  103. ASN(asn=65006, rir=rir),
  104. ASN(asn=65007, rir=rir),
  105. ASN(asn=65008, rir=rir),
  106. ASN(asn=65009, rir=rir),
  107. ASN(asn=65010, rir=rir),
  108. ]
  109. ASN.objects.bulk_create(asns)
  110. asns[0].sites.set([sites[0]])
  111. asns[2].sites.set([sites[0]])
  112. asns[3].sites.set([sites[1]])
  113. asns[4].sites.set([sites[2]])
  114. asns[5].sites.set([sites[1]])
  115. asns[6].sites.set([sites[2]])
  116. asns[7].sites.set([sites[2]])
  117. asns[8].sites.set([sites[2]])
  118. asns[10].sites.set([sites[0]])
  119. cls.form_data = {
  120. 'name': 'Site X',
  121. 'slug': 'site-x',
  122. 'status': SiteStatusChoices.STATUS_PLANNED,
  123. 'region': regions[1].pk,
  124. 'group': groups[1].pk,
  125. 'tenant': None,
  126. 'facility': 'Facility X',
  127. 'time_zone': pytz.UTC,
  128. 'description': 'Site description',
  129. 'physical_address': '742 Evergreen Terrace, Springfield, USA',
  130. 'shipping_address': '742 Evergreen Terrace, Springfield, USA',
  131. 'latitude': Decimal('35.780000'),
  132. 'longitude': Decimal('-78.642000'),
  133. 'contact_name': 'Hank Hill',
  134. 'contact_phone': '123-555-9999',
  135. 'contact_email': 'hank@stricklandpropane.com',
  136. 'comments': 'Test site',
  137. 'tags': [t.pk for t in tags],
  138. }
  139. cls.csv_data = (
  140. "name,slug,status",
  141. "Site 4,site-4,planned",
  142. "Site 5,site-5,active",
  143. "Site 6,site-6,staging",
  144. )
  145. cls.bulk_edit_data = {
  146. 'status': SiteStatusChoices.STATUS_PLANNED,
  147. 'region': regions[1].pk,
  148. 'group': groups[1].pk,
  149. 'tenant': None,
  150. 'time_zone': pytz.timezone('US/Eastern'),
  151. 'description': 'New description',
  152. }
  153. class LocationTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
  154. model = Location
  155. @classmethod
  156. def setUpTestData(cls):
  157. site = Site.objects.create(name='Site 1', slug='site-1')
  158. tenant = Tenant.objects.create(name='Tenant 1', slug='tenant-1')
  159. locations = (
  160. Location(name='Location 1', slug='location-1', site=site, tenant=tenant),
  161. Location(name='Location 2', slug='location-2', site=site, tenant=tenant),
  162. Location(name='Location 3', slug='location-3', site=site, tenant=tenant),
  163. )
  164. for location in locations:
  165. location.save()
  166. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  167. cls.form_data = {
  168. 'name': 'Location X',
  169. 'slug': 'location-x',
  170. 'site': site.pk,
  171. 'tenant': tenant.pk,
  172. 'description': 'A new location',
  173. 'tags': [t.pk for t in tags],
  174. }
  175. cls.csv_data = (
  176. "site,tenant,name,slug,description",
  177. "Site 1,Tenant 1,Location 4,location-4,Fourth location",
  178. "Site 1,Tenant 1,Location 5,location-5,Fifth location",
  179. "Site 1,Tenant 1,Location 6,location-6,Sixth location",
  180. )
  181. cls.bulk_edit_data = {
  182. 'description': 'New description',
  183. }
  184. class RackRoleTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
  185. model = RackRole
  186. @classmethod
  187. def setUpTestData(cls):
  188. RackRole.objects.bulk_create([
  189. RackRole(name='Rack Role 1', slug='rack-role-1'),
  190. RackRole(name='Rack Role 2', slug='rack-role-2'),
  191. RackRole(name='Rack Role 3', slug='rack-role-3'),
  192. ])
  193. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  194. cls.form_data = {
  195. 'name': 'Rack Role X',
  196. 'slug': 'rack-role-x',
  197. 'color': 'c0c0c0',
  198. 'description': 'New role',
  199. 'tags': [t.pk for t in tags],
  200. }
  201. cls.csv_data = (
  202. "name,slug,color",
  203. "Rack Role 4,rack-role-4,ff0000",
  204. "Rack Role 5,rack-role-5,00ff00",
  205. "Rack Role 6,rack-role-6,0000ff",
  206. )
  207. cls.bulk_edit_data = {
  208. 'color': '00ff00',
  209. 'description': 'New description',
  210. }
  211. class RackReservationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  212. model = RackReservation
  213. @classmethod
  214. def setUpTestData(cls):
  215. user2 = User.objects.create_user(username='testuser2')
  216. user3 = User.objects.create_user(username='testuser3')
  217. site = Site.objects.create(name='Site 1', slug='site-1')
  218. location = Location(name='Location 1', slug='location-1', site=site)
  219. location.save()
  220. rack = Rack(name='Rack 1', site=site, location=location)
  221. rack.save()
  222. RackReservation.objects.bulk_create([
  223. RackReservation(rack=rack, user=user2, units=[1, 2, 3], description='Reservation 1'),
  224. RackReservation(rack=rack, user=user2, units=[4, 5, 6], description='Reservation 2'),
  225. RackReservation(rack=rack, user=user2, units=[7, 8, 9], description='Reservation 3'),
  226. ])
  227. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  228. cls.form_data = {
  229. 'rack': rack.pk,
  230. 'units': "10,11,12",
  231. 'user': user3.pk,
  232. 'tenant': None,
  233. 'description': 'Rack reservation',
  234. 'tags': [t.pk for t in tags],
  235. }
  236. cls.csv_data = (
  237. 'site,location,rack,units,description',
  238. 'Site 1,Location 1,Rack 1,"10,11,12",Reservation 1',
  239. 'Site 1,Location 1,Rack 1,"13,14,15",Reservation 2',
  240. 'Site 1,Location 1,Rack 1,"16,17,18",Reservation 3',
  241. )
  242. cls.bulk_edit_data = {
  243. 'user': user3.pk,
  244. 'tenant': None,
  245. 'description': 'New description',
  246. }
  247. class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  248. model = Rack
  249. @classmethod
  250. def setUpTestData(cls):
  251. sites = (
  252. Site(name='Site 1', slug='site-1'),
  253. Site(name='Site 2', slug='site-2'),
  254. )
  255. Site.objects.bulk_create(sites)
  256. locations = (
  257. Location(name='Location 1', slug='location-1', site=sites[0]),
  258. Location(name='Location 2', slug='location-2', site=sites[1])
  259. )
  260. for location in locations:
  261. location.save()
  262. rackroles = (
  263. RackRole(name='Rack Role 1', slug='rack-role-1'),
  264. RackRole(name='Rack Role 2', slug='rack-role-2'),
  265. )
  266. RackRole.objects.bulk_create(rackroles)
  267. Rack.objects.bulk_create((
  268. Rack(name='Rack 1', site=sites[0]),
  269. Rack(name='Rack 2', site=sites[0]),
  270. Rack(name='Rack 3', site=sites[0]),
  271. ))
  272. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  273. cls.form_data = {
  274. 'name': 'Rack X',
  275. 'facility_id': 'Facility X',
  276. 'site': sites[1].pk,
  277. 'location': locations[1].pk,
  278. 'tenant': None,
  279. 'status': RackStatusChoices.STATUS_PLANNED,
  280. 'role': rackroles[1].pk,
  281. 'serial': '123456',
  282. 'asset_tag': 'ABCDEF',
  283. 'type': RackTypeChoices.TYPE_CABINET,
  284. 'width': RackWidthChoices.WIDTH_19IN,
  285. 'u_height': 48,
  286. 'desc_units': False,
  287. 'outer_width': 500,
  288. 'outer_depth': 500,
  289. 'outer_unit': RackDimensionUnitChoices.UNIT_MILLIMETER,
  290. 'comments': 'Some comments',
  291. 'tags': [t.pk for t in tags],
  292. }
  293. cls.csv_data = (
  294. "site,location,name,status,width,u_height",
  295. "Site 1,,Rack 4,active,19,42",
  296. "Site 1,Location 1,Rack 5,active,19,42",
  297. "Site 2,Location 2,Rack 6,active,19,42",
  298. )
  299. cls.bulk_edit_data = {
  300. 'site': sites[1].pk,
  301. 'location': locations[1].pk,
  302. 'tenant': None,
  303. 'status': RackStatusChoices.STATUS_DEPRECATED,
  304. 'role': rackroles[1].pk,
  305. 'serial': '654321',
  306. 'type': RackTypeChoices.TYPE_4POST,
  307. 'width': RackWidthChoices.WIDTH_23IN,
  308. 'u_height': 49,
  309. 'desc_units': True,
  310. 'outer_width': 30,
  311. 'outer_depth': 30,
  312. 'outer_unit': RackDimensionUnitChoices.UNIT_INCH,
  313. 'comments': 'New comments',
  314. }
  315. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  316. def test_list_rack_elevations(self):
  317. """
  318. Test viewing the list of rack elevations.
  319. """
  320. response = self.client.get(reverse('dcim:rack_elevation_list'))
  321. self.assertHttpStatus(response, 200)
  322. class ManufacturerTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
  323. model = Manufacturer
  324. @classmethod
  325. def setUpTestData(cls):
  326. Manufacturer.objects.bulk_create([
  327. Manufacturer(name='Manufacturer 1', slug='manufacturer-1'),
  328. Manufacturer(name='Manufacturer 2', slug='manufacturer-2'),
  329. Manufacturer(name='Manufacturer 3', slug='manufacturer-3'),
  330. ])
  331. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  332. cls.form_data = {
  333. 'name': 'Manufacturer X',
  334. 'slug': 'manufacturer-x',
  335. 'description': 'A new manufacturer',
  336. 'tags': [t.pk for t in tags],
  337. }
  338. cls.csv_data = (
  339. "name,slug,description",
  340. "Manufacturer 4,manufacturer-4,Fourth manufacturer",
  341. "Manufacturer 5,manufacturer-5,Fifth manufacturer",
  342. "Manufacturer 6,manufacturer-6,Sixth manufacturer",
  343. )
  344. cls.bulk_edit_data = {
  345. 'description': 'New description',
  346. }
  347. # TODO: Change base class to PrimaryObjectViewTestCase
  348. # Blocked by absence of bulk import view for DeviceTypes
  349. class DeviceTypeTestCase(
  350. ViewTestCases.GetObjectViewTestCase,
  351. ViewTestCases.GetObjectChangelogViewTestCase,
  352. ViewTestCases.CreateObjectViewTestCase,
  353. ViewTestCases.EditObjectViewTestCase,
  354. ViewTestCases.DeleteObjectViewTestCase,
  355. ViewTestCases.ListObjectsViewTestCase,
  356. ViewTestCases.BulkEditObjectsViewTestCase,
  357. ViewTestCases.BulkDeleteObjectsViewTestCase
  358. ):
  359. model = DeviceType
  360. @classmethod
  361. def setUpTestData(cls):
  362. manufacturers = (
  363. Manufacturer(name='Manufacturer 1', slug='manufacturer-1'),
  364. Manufacturer(name='Manufacturer 2', slug='manufacturer-2')
  365. )
  366. Manufacturer.objects.bulk_create(manufacturers)
  367. DeviceType.objects.bulk_create([
  368. DeviceType(model='Device Type 1', slug='device-type-1', manufacturer=manufacturers[0]),
  369. DeviceType(model='Device Type 2', slug='device-type-2', manufacturer=manufacturers[0]),
  370. DeviceType(model='Device Type 3', slug='device-type-3', manufacturer=manufacturers[0]),
  371. ])
  372. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  373. cls.form_data = {
  374. 'manufacturer': manufacturers[1].pk,
  375. 'model': 'Device Type X',
  376. 'slug': 'device-type-x',
  377. 'part_number': '123ABC',
  378. 'u_height': 2,
  379. 'is_full_depth': True,
  380. 'subdevice_role': '', # CharField
  381. 'comments': 'Some comments',
  382. 'tags': [t.pk for t in tags],
  383. }
  384. cls.bulk_edit_data = {
  385. 'manufacturer': manufacturers[1].pk,
  386. 'u_height': 3,
  387. 'is_full_depth': False,
  388. }
  389. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  390. def test_devicetype_consoleports(self):
  391. devicetype = DeviceType.objects.first()
  392. console_ports = (
  393. ConsolePortTemplate(device_type=devicetype, name='Console Port 1'),
  394. ConsolePortTemplate(device_type=devicetype, name='Console Port 2'),
  395. ConsolePortTemplate(device_type=devicetype, name='Console Port 3'),
  396. )
  397. ConsolePortTemplate.objects.bulk_create(console_ports)
  398. url = reverse('dcim:devicetype_consoleports', kwargs={'pk': devicetype.pk})
  399. self.assertHttpStatus(self.client.get(url), 200)
  400. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  401. def test_devicetype_consoleserverports(self):
  402. devicetype = DeviceType.objects.first()
  403. console_server_ports = (
  404. ConsoleServerPortTemplate(device_type=devicetype, name='Console Server Port 1'),
  405. ConsoleServerPortTemplate(device_type=devicetype, name='Console Server Port 2'),
  406. ConsoleServerPortTemplate(device_type=devicetype, name='Console Server Port 3'),
  407. )
  408. ConsoleServerPortTemplate.objects.bulk_create(console_server_ports)
  409. url = reverse('dcim:devicetype_consoleserverports', kwargs={'pk': devicetype.pk})
  410. self.assertHttpStatus(self.client.get(url), 200)
  411. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  412. def test_devicetype_powerports(self):
  413. devicetype = DeviceType.objects.first()
  414. power_ports = (
  415. PowerPortTemplate(device_type=devicetype, name='Power Port 1'),
  416. PowerPortTemplate(device_type=devicetype, name='Power Port 2'),
  417. PowerPortTemplate(device_type=devicetype, name='Power Port 3'),
  418. )
  419. PowerPortTemplate.objects.bulk_create(power_ports)
  420. url = reverse('dcim:devicetype_powerports', kwargs={'pk': devicetype.pk})
  421. self.assertHttpStatus(self.client.get(url), 200)
  422. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  423. def test_devicetype_poweroutlets(self):
  424. devicetype = DeviceType.objects.first()
  425. power_outlets = (
  426. PowerOutletTemplate(device_type=devicetype, name='Power Outlet 1'),
  427. PowerOutletTemplate(device_type=devicetype, name='Power Outlet 2'),
  428. PowerOutletTemplate(device_type=devicetype, name='Power Outlet 3'),
  429. )
  430. PowerOutletTemplate.objects.bulk_create(power_outlets)
  431. url = reverse('dcim:devicetype_poweroutlets', kwargs={'pk': devicetype.pk})
  432. self.assertHttpStatus(self.client.get(url), 200)
  433. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  434. def test_devicetype_interfaces(self):
  435. devicetype = DeviceType.objects.first()
  436. interfaces = (
  437. InterfaceTemplate(device_type=devicetype, name='Interface 1'),
  438. InterfaceTemplate(device_type=devicetype, name='Interface 2'),
  439. InterfaceTemplate(device_type=devicetype, name='Interface 3'),
  440. )
  441. InterfaceTemplate.objects.bulk_create(interfaces)
  442. url = reverse('dcim:devicetype_interfaces', kwargs={'pk': devicetype.pk})
  443. self.assertHttpStatus(self.client.get(url), 200)
  444. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  445. def test_devicetype_rearports(self):
  446. devicetype = DeviceType.objects.first()
  447. rear_ports = (
  448. RearPortTemplate(device_type=devicetype, name='Rear Port 1'),
  449. RearPortTemplate(device_type=devicetype, name='Rear Port 2'),
  450. RearPortTemplate(device_type=devicetype, name='Rear Port 3'),
  451. )
  452. RearPortTemplate.objects.bulk_create(rear_ports)
  453. url = reverse('dcim:devicetype_rearports', kwargs={'pk': devicetype.pk})
  454. self.assertHttpStatus(self.client.get(url), 200)
  455. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  456. def test_devicetype_frontports(self):
  457. devicetype = DeviceType.objects.first()
  458. rear_ports = (
  459. RearPortTemplate(device_type=devicetype, name='Rear Port 1'),
  460. RearPortTemplate(device_type=devicetype, name='Rear Port 2'),
  461. RearPortTemplate(device_type=devicetype, name='Rear Port 3'),
  462. )
  463. RearPortTemplate.objects.bulk_create(rear_ports)
  464. front_ports = (
  465. FrontPortTemplate(device_type=devicetype, name='Front Port 1', rear_port=rear_ports[0], rear_port_position=1),
  466. FrontPortTemplate(device_type=devicetype, name='Front Port 2', rear_port=rear_ports[1], rear_port_position=1),
  467. FrontPortTemplate(device_type=devicetype, name='Front Port 3', rear_port=rear_ports[2], rear_port_position=1),
  468. )
  469. FrontPortTemplate.objects.bulk_create(front_ports)
  470. url = reverse('dcim:devicetype_frontports', kwargs={'pk': devicetype.pk})
  471. self.assertHttpStatus(self.client.get(url), 200)
  472. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  473. def test_devicetype_devicebays(self):
  474. devicetype = DeviceType.objects.first()
  475. device_bays = (
  476. DeviceBayTemplate(device_type=devicetype, name='Device Bay 1'),
  477. DeviceBayTemplate(device_type=devicetype, name='Device Bay 2'),
  478. DeviceBayTemplate(device_type=devicetype, name='Device Bay 3'),
  479. )
  480. DeviceBayTemplate.objects.bulk_create(device_bays)
  481. url = reverse('dcim:devicetype_devicebays', kwargs={'pk': devicetype.pk})
  482. self.assertHttpStatus(self.client.get(url), 200)
  483. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  484. def test_import_objects(self):
  485. """
  486. Custom import test for YAML-based imports (versus CSV)
  487. """
  488. IMPORT_DATA = """
  489. manufacturer: Generic
  490. model: TEST-1000
  491. slug: test-1000
  492. u_height: 2
  493. subdevice_role: parent
  494. comments: test comment
  495. console-ports:
  496. - name: Console Port 1
  497. type: de-9
  498. - name: Console Port 2
  499. type: de-9
  500. - name: Console Port 3
  501. type: de-9
  502. console-server-ports:
  503. - name: Console Server Port 1
  504. type: rj-45
  505. - name: Console Server Port 2
  506. type: rj-45
  507. - name: Console Server Port 3
  508. type: rj-45
  509. power-ports:
  510. - name: Power Port 1
  511. type: iec-60320-c14
  512. - name: Power Port 2
  513. type: iec-60320-c14
  514. - name: Power Port 3
  515. type: iec-60320-c14
  516. power-outlets:
  517. - name: Power Outlet 1
  518. type: iec-60320-c13
  519. power_port: Power Port 1
  520. feed_leg: A
  521. - name: Power Outlet 2
  522. type: iec-60320-c13
  523. power_port: Power Port 1
  524. feed_leg: A
  525. - name: Power Outlet 3
  526. type: iec-60320-c13
  527. power_port: Power Port 1
  528. feed_leg: A
  529. interfaces:
  530. - name: Interface 1
  531. type: 1000base-t
  532. mgmt_only: true
  533. - name: Interface 2
  534. type: 1000base-t
  535. - name: Interface 3
  536. type: 1000base-t
  537. rear-ports:
  538. - name: Rear Port 1
  539. type: 8p8c
  540. - name: Rear Port 2
  541. type: 8p8c
  542. - name: Rear Port 3
  543. type: 8p8c
  544. front-ports:
  545. - name: Front Port 1
  546. type: 8p8c
  547. rear_port: Rear Port 1
  548. - name: Front Port 2
  549. type: 8p8c
  550. rear_port: Rear Port 2
  551. - name: Front Port 3
  552. type: 8p8c
  553. rear_port: Rear Port 3
  554. device-bays:
  555. - name: Device Bay 1
  556. - name: Device Bay 2
  557. - name: Device Bay 3
  558. """
  559. # Create the manufacturer
  560. Manufacturer(name='Generic', slug='generic').save()
  561. # Add all required permissions to the test user
  562. self.add_permissions(
  563. 'dcim.view_devicetype',
  564. 'dcim.add_devicetype',
  565. 'dcim.add_consoleporttemplate',
  566. 'dcim.add_consoleserverporttemplate',
  567. 'dcim.add_powerporttemplate',
  568. 'dcim.add_poweroutlettemplate',
  569. 'dcim.add_interfacetemplate',
  570. 'dcim.add_frontporttemplate',
  571. 'dcim.add_rearporttemplate',
  572. 'dcim.add_devicebaytemplate',
  573. )
  574. form_data = {
  575. 'data': IMPORT_DATA,
  576. 'format': 'yaml'
  577. }
  578. response = self.client.post(reverse('dcim:devicetype_import'), data=form_data, follow=True)
  579. self.assertHttpStatus(response, 200)
  580. dt = DeviceType.objects.get(model='TEST-1000')
  581. self.assertEqual(dt.comments, 'test comment')
  582. # Verify all of the components were created
  583. self.assertEqual(dt.consoleporttemplates.count(), 3)
  584. cp1 = ConsolePortTemplate.objects.first()
  585. self.assertEqual(cp1.name, 'Console Port 1')
  586. self.assertEqual(cp1.type, ConsolePortTypeChoices.TYPE_DE9)
  587. self.assertEqual(dt.consoleserverporttemplates.count(), 3)
  588. csp1 = ConsoleServerPortTemplate.objects.first()
  589. self.assertEqual(csp1.name, 'Console Server Port 1')
  590. self.assertEqual(csp1.type, ConsolePortTypeChoices.TYPE_RJ45)
  591. self.assertEqual(dt.powerporttemplates.count(), 3)
  592. pp1 = PowerPortTemplate.objects.first()
  593. self.assertEqual(pp1.name, 'Power Port 1')
  594. self.assertEqual(pp1.type, PowerPortTypeChoices.TYPE_IEC_C14)
  595. self.assertEqual(dt.poweroutlettemplates.count(), 3)
  596. po1 = PowerOutletTemplate.objects.first()
  597. self.assertEqual(po1.name, 'Power Outlet 1')
  598. self.assertEqual(po1.type, PowerOutletTypeChoices.TYPE_IEC_C13)
  599. self.assertEqual(po1.power_port, pp1)
  600. self.assertEqual(po1.feed_leg, PowerOutletFeedLegChoices.FEED_LEG_A)
  601. self.assertEqual(dt.interfacetemplates.count(), 3)
  602. iface1 = InterfaceTemplate.objects.first()
  603. self.assertEqual(iface1.name, 'Interface 1')
  604. self.assertEqual(iface1.type, InterfaceTypeChoices.TYPE_1GE_FIXED)
  605. self.assertTrue(iface1.mgmt_only)
  606. self.assertEqual(dt.rearporttemplates.count(), 3)
  607. rp1 = RearPortTemplate.objects.first()
  608. self.assertEqual(rp1.name, 'Rear Port 1')
  609. self.assertEqual(dt.frontporttemplates.count(), 3)
  610. fp1 = FrontPortTemplate.objects.first()
  611. self.assertEqual(fp1.name, 'Front Port 1')
  612. self.assertEqual(fp1.rear_port, rp1)
  613. self.assertEqual(fp1.rear_port_position, 1)
  614. self.assertEqual(dt.devicebaytemplates.count(), 3)
  615. db1 = DeviceBayTemplate.objects.first()
  616. self.assertEqual(db1.name, 'Device Bay 1')
  617. def test_export_objects(self):
  618. url = reverse('dcim:devicetype_list')
  619. self.add_permissions('dcim.view_devicetype')
  620. # Test default YAML export
  621. response = self.client.get('{}?export'.format(url))
  622. self.assertEqual(response.status_code, 200)
  623. data = list(yaml.load_all(response.content, Loader=yaml.SafeLoader))
  624. self.assertEqual(len(data), 3)
  625. self.assertEqual(data[0]['manufacturer'], 'Manufacturer 1')
  626. self.assertEqual(data[0]['model'], 'Device Type 1')
  627. # Test table-based export
  628. response = self.client.get(f'{url}?export=table')
  629. self.assertHttpStatus(response, 200)
  630. self.assertEqual(response.get('Content-Type'), 'text/csv; charset=utf-8')
  631. #
  632. # DeviceType components
  633. #
  634. class ConsolePortTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
  635. model = ConsolePortTemplate
  636. @classmethod
  637. def setUpTestData(cls):
  638. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  639. devicetypes = (
  640. DeviceType(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'),
  641. DeviceType(manufacturer=manufacturer, model='Device Type 2', slug='device-type-2'),
  642. )
  643. DeviceType.objects.bulk_create(devicetypes)
  644. ConsolePortTemplate.objects.bulk_create((
  645. ConsolePortTemplate(device_type=devicetypes[0], name='Console Port Template 1'),
  646. ConsolePortTemplate(device_type=devicetypes[0], name='Console Port Template 2'),
  647. ConsolePortTemplate(device_type=devicetypes[0], name='Console Port Template 3'),
  648. ))
  649. cls.form_data = {
  650. 'device_type': devicetypes[1].pk,
  651. 'name': 'Console Port Template X',
  652. 'type': ConsolePortTypeChoices.TYPE_RJ45,
  653. }
  654. cls.bulk_create_data = {
  655. 'device_type': devicetypes[1].pk,
  656. 'name_pattern': 'Console Port Template [4-6]',
  657. 'type': ConsolePortTypeChoices.TYPE_RJ45,
  658. }
  659. cls.bulk_edit_data = {
  660. 'type': ConsolePortTypeChoices.TYPE_RJ45,
  661. }
  662. class ConsoleServerPortTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
  663. model = ConsoleServerPortTemplate
  664. @classmethod
  665. def setUpTestData(cls):
  666. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  667. devicetypes = (
  668. DeviceType(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'),
  669. DeviceType(manufacturer=manufacturer, model='Device Type 2', slug='device-type-2'),
  670. )
  671. DeviceType.objects.bulk_create(devicetypes)
  672. ConsoleServerPortTemplate.objects.bulk_create((
  673. ConsoleServerPortTemplate(device_type=devicetypes[0], name='Console Server Port Template 1'),
  674. ConsoleServerPortTemplate(device_type=devicetypes[0], name='Console Server Port Template 2'),
  675. ConsoleServerPortTemplate(device_type=devicetypes[0], name='Console Server Port Template 3'),
  676. ))
  677. cls.form_data = {
  678. 'device_type': devicetypes[1].pk,
  679. 'name': 'Console Server Port Template X',
  680. 'type': ConsolePortTypeChoices.TYPE_RJ45,
  681. }
  682. cls.bulk_create_data = {
  683. 'device_type': devicetypes[1].pk,
  684. 'name_pattern': 'Console Server Port Template [4-6]',
  685. 'type': ConsolePortTypeChoices.TYPE_RJ45,
  686. }
  687. cls.bulk_edit_data = {
  688. 'type': ConsolePortTypeChoices.TYPE_RJ45,
  689. }
  690. class PowerPortTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
  691. model = PowerPortTemplate
  692. @classmethod
  693. def setUpTestData(cls):
  694. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  695. devicetypes = (
  696. DeviceType(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'),
  697. DeviceType(manufacturer=manufacturer, model='Device Type 2', slug='device-type-2'),
  698. )
  699. DeviceType.objects.bulk_create(devicetypes)
  700. PowerPortTemplate.objects.bulk_create((
  701. PowerPortTemplate(device_type=devicetypes[0], name='Power Port Template 1'),
  702. PowerPortTemplate(device_type=devicetypes[0], name='Power Port Template 2'),
  703. PowerPortTemplate(device_type=devicetypes[0], name='Power Port Template 3'),
  704. ))
  705. cls.form_data = {
  706. 'device_type': devicetypes[1].pk,
  707. 'name': 'Power Port Template X',
  708. 'type': PowerPortTypeChoices.TYPE_IEC_C14,
  709. 'maximum_draw': 100,
  710. 'allocated_draw': 50,
  711. }
  712. cls.bulk_create_data = {
  713. 'device_type': devicetypes[1].pk,
  714. 'name_pattern': 'Power Port Template [4-6]',
  715. 'type': PowerPortTypeChoices.TYPE_IEC_C14,
  716. 'maximum_draw': 100,
  717. 'allocated_draw': 50,
  718. }
  719. cls.bulk_edit_data = {
  720. 'type': PowerPortTypeChoices.TYPE_IEC_C14,
  721. 'maximum_draw': 100,
  722. 'allocated_draw': 50,
  723. }
  724. class PowerOutletTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
  725. model = PowerOutletTemplate
  726. @classmethod
  727. def setUpTestData(cls):
  728. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  729. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  730. PowerOutletTemplate.objects.bulk_create((
  731. PowerOutletTemplate(device_type=devicetype, name='Power Outlet Template 1'),
  732. PowerOutletTemplate(device_type=devicetype, name='Power Outlet Template 2'),
  733. PowerOutletTemplate(device_type=devicetype, name='Power Outlet Template 3'),
  734. ))
  735. powerports = (
  736. PowerPortTemplate(device_type=devicetype, name='Power Port Template 1'),
  737. )
  738. PowerPortTemplate.objects.bulk_create(powerports)
  739. cls.form_data = {
  740. 'device_type': devicetype.pk,
  741. 'name': 'Power Outlet Template X',
  742. 'type': PowerOutletTypeChoices.TYPE_IEC_C13,
  743. 'power_port': powerports[0].pk,
  744. 'feed_leg': PowerOutletFeedLegChoices.FEED_LEG_B,
  745. }
  746. cls.bulk_create_data = {
  747. 'device_type': devicetype.pk,
  748. 'name_pattern': 'Power Outlet Template [4-6]',
  749. 'type': PowerOutletTypeChoices.TYPE_IEC_C13,
  750. 'power_port': powerports[0].pk,
  751. 'feed_leg': PowerOutletFeedLegChoices.FEED_LEG_B,
  752. }
  753. cls.bulk_edit_data = {
  754. 'type': PowerOutletTypeChoices.TYPE_IEC_C13,
  755. 'feed_leg': PowerOutletFeedLegChoices.FEED_LEG_B,
  756. }
  757. class InterfaceTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
  758. model = InterfaceTemplate
  759. @classmethod
  760. def setUpTestData(cls):
  761. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  762. devicetypes = (
  763. DeviceType(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'),
  764. DeviceType(manufacturer=manufacturer, model='Device Type 2', slug='device-type-2'),
  765. )
  766. DeviceType.objects.bulk_create(devicetypes)
  767. InterfaceTemplate.objects.bulk_create((
  768. InterfaceTemplate(device_type=devicetypes[0], name='Interface Template 1'),
  769. InterfaceTemplate(device_type=devicetypes[0], name='Interface Template 2'),
  770. InterfaceTemplate(device_type=devicetypes[0], name='Interface Template 3'),
  771. ))
  772. cls.form_data = {
  773. 'device_type': devicetypes[1].pk,
  774. 'name': 'Interface Template X',
  775. 'type': InterfaceTypeChoices.TYPE_1GE_GBIC,
  776. 'mgmt_only': True,
  777. }
  778. cls.bulk_create_data = {
  779. 'device_type': devicetypes[1].pk,
  780. 'name_pattern': 'Interface Template [4-6]',
  781. # Test that a label can be applied to each generated interface templates
  782. 'label_pattern': 'Interface Template Label [3-5]',
  783. 'type': InterfaceTypeChoices.TYPE_1GE_GBIC,
  784. 'mgmt_only': True,
  785. }
  786. cls.bulk_edit_data = {
  787. 'type': InterfaceTypeChoices.TYPE_1GE_GBIC,
  788. 'mgmt_only': True,
  789. }
  790. class FrontPortTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
  791. model = FrontPortTemplate
  792. @classmethod
  793. def setUpTestData(cls):
  794. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  795. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
  796. rearports = (
  797. RearPortTemplate(device_type=devicetype, name='Rear Port Template 1'),
  798. RearPortTemplate(device_type=devicetype, name='Rear Port Template 2'),
  799. RearPortTemplate(device_type=devicetype, name='Rear Port Template 3'),
  800. RearPortTemplate(device_type=devicetype, name='Rear Port Template 4'),
  801. RearPortTemplate(device_type=devicetype, name='Rear Port Template 5'),
  802. RearPortTemplate(device_type=devicetype, name='Rear Port Template 6'),
  803. )
  804. RearPortTemplate.objects.bulk_create(rearports)
  805. FrontPortTemplate.objects.bulk_create((
  806. FrontPortTemplate(device_type=devicetype, name='Front Port Template 1', rear_port=rearports[0], rear_port_position=1),
  807. FrontPortTemplate(device_type=devicetype, name='Front Port Template 2', rear_port=rearports[1], rear_port_position=1),
  808. FrontPortTemplate(device_type=devicetype, name='Front Port Template 3', rear_port=rearports[2], rear_port_position=1),
  809. ))
  810. cls.form_data = {
  811. 'device_type': devicetype.pk,
  812. 'name': 'Front Port X',
  813. 'type': PortTypeChoices.TYPE_8P8C,
  814. 'rear_port': rearports[3].pk,
  815. 'rear_port_position': 1,
  816. }
  817. cls.bulk_create_data = {
  818. 'device_type': devicetype.pk,
  819. 'name_pattern': 'Front Port [4-6]',
  820. 'type': PortTypeChoices.TYPE_8P8C,
  821. 'rear_port_set': [
  822. '{}:1'.format(rp.pk) for rp in rearports[3:6]
  823. ],
  824. }
  825. cls.bulk_edit_data = {
  826. 'type': PortTypeChoices.TYPE_8P8C,
  827. }
  828. class RearPortTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
  829. model = RearPortTemplate
  830. @classmethod
  831. def setUpTestData(cls):
  832. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  833. devicetypes = (
  834. DeviceType(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'),
  835. DeviceType(manufacturer=manufacturer, model='Device Type 2', slug='device-type-2'),
  836. )
  837. DeviceType.objects.bulk_create(devicetypes)
  838. RearPortTemplate.objects.bulk_create((
  839. RearPortTemplate(device_type=devicetypes[0], name='Rear Port Template 1'),
  840. RearPortTemplate(device_type=devicetypes[0], name='Rear Port Template 2'),
  841. RearPortTemplate(device_type=devicetypes[0], name='Rear Port Template 3'),
  842. ))
  843. cls.form_data = {
  844. 'device_type': devicetypes[1].pk,
  845. 'name': 'Rear Port Template X',
  846. 'type': PortTypeChoices.TYPE_8P8C,
  847. 'positions': 2,
  848. }
  849. cls.bulk_create_data = {
  850. 'device_type': devicetypes[1].pk,
  851. 'name_pattern': 'Rear Port Template [4-6]',
  852. 'type': PortTypeChoices.TYPE_8P8C,
  853. 'positions': 2,
  854. }
  855. cls.bulk_edit_data = {
  856. 'type': PortTypeChoices.TYPE_8P8C,
  857. }
  858. class DeviceBayTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase):
  859. model = DeviceBayTemplate
  860. @classmethod
  861. def setUpTestData(cls):
  862. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  863. devicetypes = (
  864. DeviceType(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1', subdevice_role=SubdeviceRoleChoices.ROLE_PARENT),
  865. DeviceType(manufacturer=manufacturer, model='Device Type 2', slug='device-type-2', subdevice_role=SubdeviceRoleChoices.ROLE_PARENT),
  866. )
  867. DeviceType.objects.bulk_create(devicetypes)
  868. DeviceBayTemplate.objects.bulk_create((
  869. DeviceBayTemplate(device_type=devicetypes[0], name='Device Bay Template 1'),
  870. DeviceBayTemplate(device_type=devicetypes[0], name='Device Bay Template 2'),
  871. DeviceBayTemplate(device_type=devicetypes[0], name='Device Bay Template 3'),
  872. ))
  873. cls.form_data = {
  874. 'device_type': devicetypes[1].pk,
  875. 'name': 'Device Bay Template X',
  876. }
  877. cls.bulk_create_data = {
  878. 'device_type': devicetypes[1].pk,
  879. 'name_pattern': 'Device Bay Template [4-6]',
  880. }
  881. cls.bulk_edit_data = {
  882. 'description': 'Foo bar',
  883. }
  884. class DeviceRoleTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
  885. model = DeviceRole
  886. @classmethod
  887. def setUpTestData(cls):
  888. DeviceRole.objects.bulk_create([
  889. DeviceRole(name='Device Role 1', slug='device-role-1'),
  890. DeviceRole(name='Device Role 2', slug='device-role-2'),
  891. DeviceRole(name='Device Role 3', slug='device-role-3'),
  892. ])
  893. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  894. cls.form_data = {
  895. 'name': 'Devie Role X',
  896. 'slug': 'device-role-x',
  897. 'color': 'c0c0c0',
  898. 'vm_role': False,
  899. 'description': 'New device role',
  900. 'tags': [t.pk for t in tags],
  901. }
  902. cls.csv_data = (
  903. "name,slug,color",
  904. "Device Role 4,device-role-4,ff0000",
  905. "Device Role 5,device-role-5,00ff00",
  906. "Device Role 6,device-role-6,0000ff",
  907. )
  908. cls.bulk_edit_data = {
  909. 'color': '00ff00',
  910. 'description': 'New description',
  911. }
  912. class PlatformTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
  913. model = Platform
  914. @classmethod
  915. def setUpTestData(cls):
  916. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  917. Platform.objects.bulk_create([
  918. Platform(name='Platform 1', slug='platform-1', manufacturer=manufacturer),
  919. Platform(name='Platform 2', slug='platform-2', manufacturer=manufacturer),
  920. Platform(name='Platform 3', slug='platform-3', manufacturer=manufacturer),
  921. ])
  922. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  923. cls.form_data = {
  924. 'name': 'Platform X',
  925. 'slug': 'platform-x',
  926. 'manufacturer': manufacturer.pk,
  927. 'napalm_driver': 'junos',
  928. 'napalm_args': None,
  929. 'description': 'A new platform',
  930. 'tags': [t.pk for t in tags],
  931. }
  932. cls.csv_data = (
  933. "name,slug,description",
  934. "Platform 4,platform-4,Fourth platform",
  935. "Platform 5,platform-5,Fifth platform",
  936. "Platform 6,platform-6,Sixth platform",
  937. )
  938. cls.bulk_edit_data = {
  939. 'napalm_driver': 'ios',
  940. 'description': 'New description',
  941. }
  942. class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  943. model = Device
  944. @classmethod
  945. def setUpTestData(cls):
  946. sites = (
  947. Site(name='Site 1', slug='site-1'),
  948. Site(name='Site 2', slug='site-2'),
  949. )
  950. Site.objects.bulk_create(sites)
  951. location = Location(site=sites[0], name='Location 1', slug='location-1')
  952. location.save()
  953. racks = (
  954. Rack(name='Rack 1', site=sites[0], location=location),
  955. Rack(name='Rack 2', site=sites[1]),
  956. )
  957. Rack.objects.bulk_create(racks)
  958. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  959. devicetypes = (
  960. DeviceType(model='Device Type 1', slug='device-type-1', manufacturer=manufacturer),
  961. DeviceType(model='Device Type 2', slug='device-type-2', manufacturer=manufacturer),
  962. )
  963. DeviceType.objects.bulk_create(devicetypes)
  964. deviceroles = (
  965. DeviceRole(name='Device Role 1', slug='device-role-1'),
  966. DeviceRole(name='Device Role 2', slug='device-role-2'),
  967. )
  968. DeviceRole.objects.bulk_create(deviceroles)
  969. platforms = (
  970. Platform(name='Platform 1', slug='platform-1'),
  971. Platform(name='Platform 2', slug='platform-2'),
  972. )
  973. Platform.objects.bulk_create(platforms)
  974. Device.objects.bulk_create([
  975. Device(name='Device 1', site=sites[0], rack=racks[0], device_type=devicetypes[0], device_role=deviceroles[0], platform=platforms[0]),
  976. Device(name='Device 2', site=sites[0], rack=racks[0], device_type=devicetypes[0], device_role=deviceroles[0], platform=platforms[0]),
  977. Device(name='Device 3', site=sites[0], rack=racks[0], device_type=devicetypes[0], device_role=deviceroles[0], platform=platforms[0]),
  978. ])
  979. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  980. VirtualChassis.objects.create(name='Virtual Chassis 1')
  981. cls.form_data = {
  982. 'device_type': devicetypes[1].pk,
  983. 'device_role': deviceroles[1].pk,
  984. 'tenant': None,
  985. 'platform': platforms[1].pk,
  986. 'name': 'Device X',
  987. 'serial': '123456',
  988. 'asset_tag': 'ABCDEF',
  989. 'site': sites[1].pk,
  990. 'rack': racks[1].pk,
  991. 'position': 1,
  992. 'face': DeviceFaceChoices.FACE_FRONT,
  993. 'status': DeviceStatusChoices.STATUS_PLANNED,
  994. 'primary_ip4': None,
  995. 'primary_ip6': None,
  996. 'cluster': None,
  997. 'virtual_chassis': None,
  998. 'vc_position': None,
  999. 'vc_priority': None,
  1000. 'comments': 'A new device',
  1001. 'tags': [t.pk for t in tags],
  1002. 'local_context_data': None,
  1003. }
  1004. cls.csv_data = (
  1005. "device_role,manufacturer,device_type,status,name,site,location,rack,position,face,virtual_chassis,vc_position,vc_priority",
  1006. "Device Role 1,Manufacturer 1,Device Type 1,active,Device 4,Site 1,Location 1,Rack 1,10,front,Virtual Chassis 1,1,10",
  1007. "Device Role 1,Manufacturer 1,Device Type 1,active,Device 5,Site 1,Location 1,Rack 1,20,front,Virtual Chassis 1,2,20",
  1008. "Device Role 1,Manufacturer 1,Device Type 1,active,Device 6,Site 1,Location 1,Rack 1,30,front,Virtual Chassis 1,3,30",
  1009. )
  1010. cls.bulk_edit_data = {
  1011. 'device_type': devicetypes[1].pk,
  1012. 'device_role': deviceroles[1].pk,
  1013. 'tenant': None,
  1014. 'platform': platforms[1].pk,
  1015. 'serial': '123456',
  1016. 'status': DeviceStatusChoices.STATUS_DECOMMISSIONING,
  1017. }
  1018. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1019. def test_device_consoleports(self):
  1020. device = Device.objects.first()
  1021. console_ports = (
  1022. ConsolePort(device=device, name='Console Port 1'),
  1023. ConsolePort(device=device, name='Console Port 2'),
  1024. ConsolePort(device=device, name='Console Port 3'),
  1025. )
  1026. ConsolePort.objects.bulk_create(console_ports)
  1027. url = reverse('dcim:device_consoleports', kwargs={'pk': device.pk})
  1028. self.assertHttpStatus(self.client.get(url), 200)
  1029. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1030. def test_device_consoleserverports(self):
  1031. device = Device.objects.first()
  1032. console_server_ports = (
  1033. ConsoleServerPort(device=device, name='Console Server Port 1'),
  1034. ConsoleServerPort(device=device, name='Console Server Port 2'),
  1035. ConsoleServerPort(device=device, name='Console Server Port 3'),
  1036. )
  1037. ConsoleServerPort.objects.bulk_create(console_server_ports)
  1038. url = reverse('dcim:device_consoleserverports', kwargs={'pk': device.pk})
  1039. self.assertHttpStatus(self.client.get(url), 200)
  1040. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1041. def test_device_powerports(self):
  1042. device = Device.objects.first()
  1043. power_ports = (
  1044. PowerPort(device=device, name='Power Port 1'),
  1045. PowerPort(device=device, name='Power Port 2'),
  1046. PowerPort(device=device, name='Power Port 3'),
  1047. )
  1048. PowerPort.objects.bulk_create(power_ports)
  1049. url = reverse('dcim:device_powerports', kwargs={'pk': device.pk})
  1050. self.assertHttpStatus(self.client.get(url), 200)
  1051. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1052. def test_device_poweroutlets(self):
  1053. device = Device.objects.first()
  1054. power_outlets = (
  1055. PowerOutlet(device=device, name='Power Outlet 1'),
  1056. PowerOutlet(device=device, name='Power Outlet 2'),
  1057. PowerOutlet(device=device, name='Power Outlet 3'),
  1058. )
  1059. PowerOutlet.objects.bulk_create(power_outlets)
  1060. url = reverse('dcim:device_poweroutlets', kwargs={'pk': device.pk})
  1061. self.assertHttpStatus(self.client.get(url), 200)
  1062. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1063. def test_device_interfaces(self):
  1064. device = Device.objects.first()
  1065. interfaces = (
  1066. Interface(device=device, name='Interface 1'),
  1067. Interface(device=device, name='Interface 2'),
  1068. Interface(device=device, name='Interface 3'),
  1069. )
  1070. Interface.objects.bulk_create(interfaces)
  1071. url = reverse('dcim:device_interfaces', kwargs={'pk': device.pk})
  1072. self.assertHttpStatus(self.client.get(url), 200)
  1073. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1074. def test_device_rearports(self):
  1075. device = Device.objects.first()
  1076. rear_ports = (
  1077. RearPort(device=device, name='Rear Port 1'),
  1078. RearPort(device=device, name='Rear Port 2'),
  1079. RearPort(device=device, name='Rear Port 3'),
  1080. )
  1081. RearPort.objects.bulk_create(rear_ports)
  1082. url = reverse('dcim:device_rearports', kwargs={'pk': device.pk})
  1083. self.assertHttpStatus(self.client.get(url), 200)
  1084. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1085. def test_device_frontports(self):
  1086. device = Device.objects.first()
  1087. rear_ports = (
  1088. RearPort(device=device, name='Rear Port 1'),
  1089. RearPort(device=device, name='Rear Port 2'),
  1090. RearPort(device=device, name='Rear Port 3'),
  1091. )
  1092. RearPort.objects.bulk_create(rear_ports)
  1093. front_ports = (
  1094. FrontPort(device=device, name='Front Port 1', rear_port=rear_ports[0], rear_port_position=1),
  1095. FrontPort(device=device, name='Front Port 2', rear_port=rear_ports[1], rear_port_position=1),
  1096. FrontPort(device=device, name='Front Port 3', rear_port=rear_ports[2], rear_port_position=1),
  1097. )
  1098. FrontPort.objects.bulk_create(front_ports)
  1099. url = reverse('dcim:device_frontports', kwargs={'pk': device.pk})
  1100. self.assertHttpStatus(self.client.get(url), 200)
  1101. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1102. def test_device_devicebays(self):
  1103. device = Device.objects.first()
  1104. device_bays = (
  1105. DeviceBay(device=device, name='Device Bay 1'),
  1106. DeviceBay(device=device, name='Device Bay 2'),
  1107. DeviceBay(device=device, name='Device Bay 3'),
  1108. )
  1109. DeviceBay.objects.bulk_create(device_bays)
  1110. url = reverse('dcim:device_devicebays', kwargs={'pk': device.pk})
  1111. self.assertHttpStatus(self.client.get(url), 200)
  1112. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1113. def test_device_inventory(self):
  1114. device = Device.objects.first()
  1115. inventory_items = (
  1116. InventoryItem(device=device, name='Inventory Item 1'),
  1117. InventoryItem(device=device, name='Inventory Item 2'),
  1118. InventoryItem(device=device, name='Inventory Item 3'),
  1119. )
  1120. for item in inventory_items:
  1121. item.save()
  1122. url = reverse('dcim:device_inventory', kwargs={'pk': device.pk})
  1123. self.assertHttpStatus(self.client.get(url), 200)
  1124. class ConsolePortTestCase(ViewTestCases.DeviceComponentViewTestCase):
  1125. model = ConsolePort
  1126. @classmethod
  1127. def setUpTestData(cls):
  1128. device = create_test_device('Device 1')
  1129. ConsolePort.objects.bulk_create([
  1130. ConsolePort(device=device, name='Console Port 1'),
  1131. ConsolePort(device=device, name='Console Port 2'),
  1132. ConsolePort(device=device, name='Console Port 3'),
  1133. ])
  1134. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  1135. cls.form_data = {
  1136. 'device': device.pk,
  1137. 'name': 'Console Port X',
  1138. 'type': ConsolePortTypeChoices.TYPE_RJ45,
  1139. 'description': 'A console port',
  1140. 'tags': sorted([t.pk for t in tags]),
  1141. }
  1142. cls.bulk_create_data = {
  1143. 'device': device.pk,
  1144. 'name_pattern': 'Console Port [4-6]',
  1145. # Test that a label can be applied to each generated console ports
  1146. 'label_pattern': 'Serial[3-5]',
  1147. 'type': ConsolePortTypeChoices.TYPE_RJ45,
  1148. 'description': 'A console port',
  1149. 'tags': sorted([t.pk for t in tags]),
  1150. }
  1151. cls.bulk_edit_data = {
  1152. 'type': ConsolePortTypeChoices.TYPE_RJ45,
  1153. 'description': 'New description',
  1154. }
  1155. cls.csv_data = (
  1156. "device,name",
  1157. "Device 1,Console Port 4",
  1158. "Device 1,Console Port 5",
  1159. "Device 1,Console Port 6",
  1160. )
  1161. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1162. def test_trace(self):
  1163. consoleport = ConsolePort.objects.first()
  1164. consoleserverport = ConsoleServerPort.objects.create(
  1165. device=consoleport.device,
  1166. name='Console Server Port 1'
  1167. )
  1168. Cable(termination_a=consoleport, termination_b=consoleserverport).save()
  1169. response = self.client.get(reverse('dcim:consoleport_trace', kwargs={'pk': consoleport.pk}))
  1170. self.assertHttpStatus(response, 200)
  1171. class ConsoleServerPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
  1172. model = ConsoleServerPort
  1173. @classmethod
  1174. def setUpTestData(cls):
  1175. device = create_test_device('Device 1')
  1176. ConsoleServerPort.objects.bulk_create([
  1177. ConsoleServerPort(device=device, name='Console Server Port 1'),
  1178. ConsoleServerPort(device=device, name='Console Server Port 2'),
  1179. ConsoleServerPort(device=device, name='Console Server Port 3'),
  1180. ])
  1181. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  1182. cls.form_data = {
  1183. 'device': device.pk,
  1184. 'name': 'Console Server Port X',
  1185. 'type': ConsolePortTypeChoices.TYPE_RJ45,
  1186. 'description': 'A console server port',
  1187. 'tags': [t.pk for t in tags],
  1188. }
  1189. cls.bulk_create_data = {
  1190. 'device': device.pk,
  1191. 'name_pattern': 'Console Server Port [4-6]',
  1192. 'type': ConsolePortTypeChoices.TYPE_RJ45,
  1193. 'description': 'A console server port',
  1194. 'tags': [t.pk for t in tags],
  1195. }
  1196. cls.bulk_edit_data = {
  1197. 'type': ConsolePortTypeChoices.TYPE_RJ11,
  1198. 'description': 'New description',
  1199. }
  1200. cls.csv_data = (
  1201. "device,name",
  1202. "Device 1,Console Server Port 4",
  1203. "Device 1,Console Server Port 5",
  1204. "Device 1,Console Server Port 6",
  1205. )
  1206. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1207. def test_trace(self):
  1208. consoleserverport = ConsoleServerPort.objects.first()
  1209. consoleport = ConsolePort.objects.create(
  1210. device=consoleserverport.device,
  1211. name='Console Port 1'
  1212. )
  1213. Cable(termination_a=consoleserverport, termination_b=consoleport).save()
  1214. response = self.client.get(reverse('dcim:consoleserverport_trace', kwargs={'pk': consoleserverport.pk}))
  1215. self.assertHttpStatus(response, 200)
  1216. class PowerPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
  1217. model = PowerPort
  1218. @classmethod
  1219. def setUpTestData(cls):
  1220. device = create_test_device('Device 1')
  1221. PowerPort.objects.bulk_create([
  1222. PowerPort(device=device, name='Power Port 1'),
  1223. PowerPort(device=device, name='Power Port 2'),
  1224. PowerPort(device=device, name='Power Port 3'),
  1225. ])
  1226. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  1227. cls.form_data = {
  1228. 'device': device.pk,
  1229. 'name': 'Power Port X',
  1230. 'type': PowerPortTypeChoices.TYPE_IEC_C14,
  1231. 'maximum_draw': 100,
  1232. 'allocated_draw': 50,
  1233. 'description': 'A power port',
  1234. 'tags': [t.pk for t in tags],
  1235. }
  1236. cls.bulk_create_data = {
  1237. 'device': device.pk,
  1238. 'name_pattern': 'Power Port [4-6]]',
  1239. 'type': PowerPortTypeChoices.TYPE_IEC_C14,
  1240. 'maximum_draw': 100,
  1241. 'allocated_draw': 50,
  1242. 'description': 'A power port',
  1243. 'tags': [t.pk for t in tags],
  1244. }
  1245. cls.bulk_edit_data = {
  1246. 'type': PowerPortTypeChoices.TYPE_IEC_C14,
  1247. 'maximum_draw': 100,
  1248. 'allocated_draw': 50,
  1249. 'description': 'New description',
  1250. }
  1251. cls.csv_data = (
  1252. "device,name",
  1253. "Device 1,Power Port 4",
  1254. "Device 1,Power Port 5",
  1255. "Device 1,Power Port 6",
  1256. )
  1257. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1258. def test_trace(self):
  1259. powerport = PowerPort.objects.first()
  1260. poweroutlet = PowerOutlet.objects.create(
  1261. device=powerport.device,
  1262. name='Power Outlet 1'
  1263. )
  1264. Cable(termination_a=powerport, termination_b=poweroutlet).save()
  1265. response = self.client.get(reverse('dcim:powerport_trace', kwargs={'pk': powerport.pk}))
  1266. self.assertHttpStatus(response, 200)
  1267. class PowerOutletTestCase(ViewTestCases.DeviceComponentViewTestCase):
  1268. model = PowerOutlet
  1269. @classmethod
  1270. def setUpTestData(cls):
  1271. device = create_test_device('Device 1')
  1272. powerports = (
  1273. PowerPort(device=device, name='Power Port 1'),
  1274. PowerPort(device=device, name='Power Port 2'),
  1275. )
  1276. PowerPort.objects.bulk_create(powerports)
  1277. PowerOutlet.objects.bulk_create([
  1278. PowerOutlet(device=device, name='Power Outlet 1', power_port=powerports[0]),
  1279. PowerOutlet(device=device, name='Power Outlet 2', power_port=powerports[0]),
  1280. PowerOutlet(device=device, name='Power Outlet 3', power_port=powerports[0]),
  1281. ])
  1282. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  1283. cls.form_data = {
  1284. 'device': device.pk,
  1285. 'name': 'Power Outlet X',
  1286. 'type': PowerOutletTypeChoices.TYPE_IEC_C13,
  1287. 'power_port': powerports[1].pk,
  1288. 'feed_leg': PowerOutletFeedLegChoices.FEED_LEG_B,
  1289. 'description': 'A power outlet',
  1290. 'tags': [t.pk for t in tags],
  1291. }
  1292. cls.bulk_create_data = {
  1293. 'device': device.pk,
  1294. 'name_pattern': 'Power Outlet [4-6]',
  1295. 'type': PowerOutletTypeChoices.TYPE_IEC_C13,
  1296. 'power_port': powerports[1].pk,
  1297. 'feed_leg': PowerOutletFeedLegChoices.FEED_LEG_B,
  1298. 'description': 'A power outlet',
  1299. 'tags': [t.pk for t in tags],
  1300. }
  1301. cls.bulk_edit_data = {
  1302. 'type': PowerOutletTypeChoices.TYPE_IEC_C15,
  1303. 'power_port': powerports[1].pk,
  1304. 'feed_leg': PowerOutletFeedLegChoices.FEED_LEG_B,
  1305. 'description': 'New description',
  1306. }
  1307. cls.csv_data = (
  1308. "device,name",
  1309. "Device 1,Power Outlet 4",
  1310. "Device 1,Power Outlet 5",
  1311. "Device 1,Power Outlet 6",
  1312. )
  1313. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1314. def test_trace(self):
  1315. poweroutlet = PowerOutlet.objects.first()
  1316. powerport = PowerPort.objects.first()
  1317. Cable(termination_a=poweroutlet, termination_b=powerport).save()
  1318. response = self.client.get(reverse('dcim:poweroutlet_trace', kwargs={'pk': poweroutlet.pk}))
  1319. self.assertHttpStatus(response, 200)
  1320. class InterfaceTestCase(ViewTestCases.DeviceComponentViewTestCase):
  1321. model = Interface
  1322. @classmethod
  1323. def setUpTestData(cls):
  1324. device = create_test_device('Device 1')
  1325. interfaces = (
  1326. Interface(device=device, name='Interface 1'),
  1327. Interface(device=device, name='Interface 2'),
  1328. Interface(device=device, name='Interface 3'),
  1329. Interface(device=device, name='LAG', type=InterfaceTypeChoices.TYPE_LAG),
  1330. Interface(device=device, name='_BRIDGE', type=InterfaceTypeChoices.TYPE_VIRTUAL), # Must be ordered last
  1331. )
  1332. Interface.objects.bulk_create(interfaces)
  1333. vlans = (
  1334. VLAN(vid=1, name='VLAN1', site=device.site),
  1335. VLAN(vid=101, name='VLAN101', site=device.site),
  1336. VLAN(vid=102, name='VLAN102', site=device.site),
  1337. VLAN(vid=103, name='VLAN103', site=device.site),
  1338. )
  1339. VLAN.objects.bulk_create(vlans)
  1340. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  1341. cls.form_data = {
  1342. 'device': device.pk,
  1343. 'name': 'Interface X',
  1344. 'type': InterfaceTypeChoices.TYPE_1GE_GBIC,
  1345. 'enabled': False,
  1346. 'bridge': interfaces[4].pk,
  1347. 'lag': interfaces[3].pk,
  1348. 'mac_address': EUI('01:02:03:04:05:06'),
  1349. 'wwn': EUI('01:02:03:04:05:06:07:08', version=64),
  1350. 'mtu': 65000,
  1351. 'mgmt_only': True,
  1352. 'description': 'A front port',
  1353. 'mode': InterfaceModeChoices.MODE_TAGGED,
  1354. 'tx_power': 10,
  1355. 'untagged_vlan': vlans[0].pk,
  1356. 'tagged_vlans': [v.pk for v in vlans[1:4]],
  1357. 'tags': [t.pk for t in tags],
  1358. }
  1359. cls.bulk_create_data = {
  1360. 'device': device.pk,
  1361. 'name_pattern': 'Interface [4-6]',
  1362. 'type': InterfaceTypeChoices.TYPE_1GE_GBIC,
  1363. 'enabled': False,
  1364. 'bridge': interfaces[4].pk,
  1365. 'lag': interfaces[3].pk,
  1366. 'mac_address': EUI('01:02:03:04:05:06'),
  1367. 'wwn': EUI('01:02:03:04:05:06:07:08', version=64),
  1368. 'mtu': 2000,
  1369. 'mgmt_only': True,
  1370. 'description': 'A front port',
  1371. 'mode': InterfaceModeChoices.MODE_TAGGED,
  1372. 'untagged_vlan': vlans[0].pk,
  1373. 'tagged_vlans': [v.pk for v in vlans[1:4]],
  1374. 'tags': [t.pk for t in tags],
  1375. }
  1376. cls.bulk_edit_data = {
  1377. 'type': InterfaceTypeChoices.TYPE_1GE_FIXED,
  1378. 'enabled': True,
  1379. 'lag': interfaces[3].pk,
  1380. 'mac_address': EUI('01:02:03:04:05:06'),
  1381. 'wwn': EUI('01:02:03:04:05:06:07:08', version=64),
  1382. 'mtu': 2000,
  1383. 'mgmt_only': True,
  1384. 'description': 'New description',
  1385. 'mode': InterfaceModeChoices.MODE_TAGGED,
  1386. 'tx_power': 10,
  1387. 'untagged_vlan': vlans[0].pk,
  1388. 'tagged_vlans': [v.pk for v in vlans[1:4]],
  1389. }
  1390. cls.csv_data = (
  1391. "device,name,type",
  1392. "Device 1,Interface 4,1000base-t",
  1393. "Device 1,Interface 5,1000base-t",
  1394. "Device 1,Interface 6,1000base-t",
  1395. )
  1396. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1397. def test_trace(self):
  1398. interface1, interface2 = Interface.objects.all()[:2]
  1399. Cable(termination_a=interface1, termination_b=interface2).save()
  1400. response = self.client.get(reverse('dcim:interface_trace', kwargs={'pk': interface1.pk}))
  1401. self.assertHttpStatus(response, 200)
  1402. class FrontPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
  1403. model = FrontPort
  1404. @classmethod
  1405. def setUpTestData(cls):
  1406. device = create_test_device('Device 1')
  1407. rearports = (
  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. RearPort(device=device, name='Rear Port 4'),
  1412. RearPort(device=device, name='Rear Port 5'),
  1413. RearPort(device=device, name='Rear Port 6'),
  1414. )
  1415. RearPort.objects.bulk_create(rearports)
  1416. FrontPort.objects.bulk_create([
  1417. FrontPort(device=device, name='Front Port 1', rear_port=rearports[0]),
  1418. FrontPort(device=device, name='Front Port 2', rear_port=rearports[1]),
  1419. FrontPort(device=device, name='Front Port 3', rear_port=rearports[2]),
  1420. ])
  1421. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  1422. cls.form_data = {
  1423. 'device': device.pk,
  1424. 'name': 'Front Port X',
  1425. 'type': PortTypeChoices.TYPE_8P8C,
  1426. 'rear_port': rearports[3].pk,
  1427. 'rear_port_position': 1,
  1428. 'description': 'New description',
  1429. 'tags': [t.pk for t in tags],
  1430. }
  1431. cls.bulk_create_data = {
  1432. 'device': device.pk,
  1433. 'name_pattern': 'Front Port [4-6]',
  1434. 'type': PortTypeChoices.TYPE_8P8C,
  1435. 'rear_port_set': [
  1436. '{}:1'.format(rp.pk) for rp in rearports[3:6]
  1437. ],
  1438. 'description': 'New description',
  1439. 'tags': [t.pk for t in tags],
  1440. }
  1441. cls.bulk_edit_data = {
  1442. 'type': PortTypeChoices.TYPE_8P8C,
  1443. 'description': 'New description',
  1444. }
  1445. cls.csv_data = (
  1446. "device,name,type,rear_port,rear_port_position",
  1447. "Device 1,Front Port 4,8p8c,Rear Port 4,1",
  1448. "Device 1,Front Port 5,8p8c,Rear Port 5,1",
  1449. "Device 1,Front Port 6,8p8c,Rear Port 6,1",
  1450. )
  1451. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1452. def test_trace(self):
  1453. frontport = FrontPort.objects.first()
  1454. interface = Interface.objects.create(
  1455. device=frontport.device,
  1456. name='Interface 1'
  1457. )
  1458. Cable(termination_a=frontport, termination_b=interface).save()
  1459. response = self.client.get(reverse('dcim:frontport_trace', kwargs={'pk': frontport.pk}))
  1460. self.assertHttpStatus(response, 200)
  1461. class RearPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
  1462. model = RearPort
  1463. @classmethod
  1464. def setUpTestData(cls):
  1465. device = create_test_device('Device 1')
  1466. RearPort.objects.bulk_create([
  1467. RearPort(device=device, name='Rear Port 1'),
  1468. RearPort(device=device, name='Rear Port 2'),
  1469. RearPort(device=device, name='Rear Port 3'),
  1470. ])
  1471. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  1472. cls.form_data = {
  1473. 'device': device.pk,
  1474. 'name': 'Rear Port X',
  1475. 'type': PortTypeChoices.TYPE_8P8C,
  1476. 'positions': 3,
  1477. 'description': 'A rear port',
  1478. 'tags': [t.pk for t in tags],
  1479. }
  1480. cls.bulk_create_data = {
  1481. 'device': device.pk,
  1482. 'name_pattern': 'Rear Port [4-6]',
  1483. 'type': PortTypeChoices.TYPE_8P8C,
  1484. 'positions': 3,
  1485. 'description': 'A rear port',
  1486. 'tags': [t.pk for t in tags],
  1487. }
  1488. cls.bulk_edit_data = {
  1489. 'type': PortTypeChoices.TYPE_8P8C,
  1490. 'description': 'New description',
  1491. }
  1492. cls.csv_data = (
  1493. "device,name,type,positions",
  1494. "Device 1,Rear Port 4,8p8c,1",
  1495. "Device 1,Rear Port 5,8p8c,1",
  1496. "Device 1,Rear Port 6,8p8c,1",
  1497. )
  1498. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1499. def test_trace(self):
  1500. rearport = RearPort.objects.first()
  1501. interface = Interface.objects.create(
  1502. device=rearport.device,
  1503. name='Interface 1'
  1504. )
  1505. Cable(termination_a=rearport, termination_b=interface).save()
  1506. response = self.client.get(reverse('dcim:rearport_trace', kwargs={'pk': rearport.pk}))
  1507. self.assertHttpStatus(response, 200)
  1508. class DeviceBayTestCase(ViewTestCases.DeviceComponentViewTestCase):
  1509. model = DeviceBay
  1510. @classmethod
  1511. def setUpTestData(cls):
  1512. device = create_test_device('Device 1')
  1513. # Update the DeviceType subdevice role to allow adding DeviceBays
  1514. DeviceType.objects.update(subdevice_role=SubdeviceRoleChoices.ROLE_PARENT)
  1515. DeviceBay.objects.bulk_create([
  1516. DeviceBay(device=device, name='Device Bay 1'),
  1517. DeviceBay(device=device, name='Device Bay 2'),
  1518. DeviceBay(device=device, name='Device Bay 3'),
  1519. ])
  1520. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  1521. cls.form_data = {
  1522. 'device': device.pk,
  1523. 'name': 'Device Bay X',
  1524. 'description': 'A device bay',
  1525. 'tags': [t.pk for t in tags],
  1526. }
  1527. cls.bulk_create_data = {
  1528. 'device': device.pk,
  1529. 'name_pattern': 'Device Bay [4-6]',
  1530. 'description': 'A device bay',
  1531. 'tags': [t.pk for t in tags],
  1532. }
  1533. cls.bulk_edit_data = {
  1534. 'description': 'New description',
  1535. }
  1536. cls.csv_data = (
  1537. "device,name",
  1538. "Device 1,Device Bay 4",
  1539. "Device 1,Device Bay 5",
  1540. "Device 1,Device Bay 6",
  1541. )
  1542. class InventoryItemTestCase(ViewTestCases.DeviceComponentViewTestCase):
  1543. model = InventoryItem
  1544. @classmethod
  1545. def setUpTestData(cls):
  1546. device = create_test_device('Device 1')
  1547. manufacturer, _ = Manufacturer.objects.get_or_create(name='Manufacturer 1', slug='manufacturer-1')
  1548. InventoryItem.objects.create(device=device, name='Inventory Item 1')
  1549. InventoryItem.objects.create(device=device, name='Inventory Item 2')
  1550. InventoryItem.objects.create(device=device, name='Inventory Item 3')
  1551. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  1552. cls.form_data = {
  1553. 'device': device.pk,
  1554. 'manufacturer': manufacturer.pk,
  1555. 'name': 'Inventory Item X',
  1556. 'parent': None,
  1557. 'discovered': False,
  1558. 'part_id': '123456',
  1559. 'serial': '123ABC',
  1560. 'asset_tag': 'ABC123',
  1561. 'description': 'An inventory item',
  1562. 'tags': [t.pk for t in tags],
  1563. }
  1564. cls.bulk_create_data = {
  1565. 'device': device.pk,
  1566. 'name_pattern': 'Inventory Item [4-6]',
  1567. 'manufacturer': manufacturer.pk,
  1568. 'parent': None,
  1569. 'discovered': False,
  1570. 'part_id': '123456',
  1571. 'serial': '123ABC',
  1572. 'description': 'An inventory item',
  1573. 'tags': [t.pk for t in tags],
  1574. }
  1575. cls.bulk_edit_data = {
  1576. 'part_id': '123456',
  1577. 'description': 'New description',
  1578. }
  1579. cls.csv_data = (
  1580. "device,name,parent",
  1581. "Device 1,Inventory Item 4,Inventory Item 1",
  1582. "Device 1,Inventory Item 5,Inventory Item 2",
  1583. "Device 1,Inventory Item 6,Inventory Item 3",
  1584. )
  1585. # TODO: Change base class to PrimaryObjectViewTestCase
  1586. # Blocked by lack of common creation view for cables (termination A must be initialized)
  1587. class CableTestCase(
  1588. ViewTestCases.GetObjectViewTestCase,
  1589. ViewTestCases.GetObjectChangelogViewTestCase,
  1590. ViewTestCases.EditObjectViewTestCase,
  1591. ViewTestCases.DeleteObjectViewTestCase,
  1592. ViewTestCases.ListObjectsViewTestCase,
  1593. ViewTestCases.BulkImportObjectsViewTestCase,
  1594. ViewTestCases.BulkEditObjectsViewTestCase,
  1595. ViewTestCases.BulkDeleteObjectsViewTestCase
  1596. ):
  1597. model = Cable
  1598. @classmethod
  1599. def setUpTestData(cls):
  1600. site = Site.objects.create(name='Site 1', slug='site-1')
  1601. manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
  1602. devicetype = DeviceType.objects.create(model='Device Type 1', manufacturer=manufacturer)
  1603. devicerole = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1')
  1604. devices = (
  1605. Device(name='Device 1', site=site, device_type=devicetype, device_role=devicerole),
  1606. Device(name='Device 2', site=site, device_type=devicetype, device_role=devicerole),
  1607. Device(name='Device 3', site=site, device_type=devicetype, device_role=devicerole),
  1608. Device(name='Device 4', site=site, device_type=devicetype, device_role=devicerole),
  1609. )
  1610. Device.objects.bulk_create(devices)
  1611. interfaces = (
  1612. Interface(device=devices[0], name='Interface 1', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  1613. Interface(device=devices[0], name='Interface 2', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  1614. Interface(device=devices[0], name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  1615. Interface(device=devices[1], name='Interface 1', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  1616. Interface(device=devices[1], name='Interface 2', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  1617. Interface(device=devices[1], name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  1618. Interface(device=devices[2], name='Interface 1', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  1619. Interface(device=devices[2], name='Interface 2', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  1620. Interface(device=devices[2], name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  1621. Interface(device=devices[3], name='Interface 1', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  1622. Interface(device=devices[3], name='Interface 2', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  1623. Interface(device=devices[3], name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_FIXED),
  1624. )
  1625. Interface.objects.bulk_create(interfaces)
  1626. Cable(termination_a=interfaces[0], termination_b=interfaces[3], type=CableTypeChoices.TYPE_CAT6).save()
  1627. Cable(termination_a=interfaces[1], termination_b=interfaces[4], type=CableTypeChoices.TYPE_CAT6).save()
  1628. Cable(termination_a=interfaces[2], termination_b=interfaces[5], type=CableTypeChoices.TYPE_CAT6).save()
  1629. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  1630. interface_ct = ContentType.objects.get_for_model(Interface)
  1631. cls.form_data = {
  1632. # Changing terminations not supported when editing an existing Cable
  1633. 'termination_a_type': interface_ct.pk,
  1634. 'termination_a_id': interfaces[0].pk,
  1635. 'termination_b_type': interface_ct.pk,
  1636. 'termination_b_id': interfaces[3].pk,
  1637. 'type': CableTypeChoices.TYPE_CAT6,
  1638. 'status': LinkStatusChoices.STATUS_PLANNED,
  1639. 'label': 'Label',
  1640. 'color': 'c0c0c0',
  1641. 'length': 100,
  1642. 'length_unit': CableLengthUnitChoices.UNIT_FOOT,
  1643. 'tags': [t.pk for t in tags],
  1644. }
  1645. cls.csv_data = (
  1646. "side_a_device,side_a_type,side_a_name,side_b_device,side_b_type,side_b_name",
  1647. "Device 3,dcim.interface,Interface 1,Device 4,dcim.interface,Interface 1",
  1648. "Device 3,dcim.interface,Interface 2,Device 4,dcim.interface,Interface 2",
  1649. "Device 3,dcim.interface,Interface 3,Device 4,dcim.interface,Interface 3",
  1650. )
  1651. cls.bulk_edit_data = {
  1652. 'type': CableTypeChoices.TYPE_CAT5E,
  1653. 'status': LinkStatusChoices.STATUS_CONNECTED,
  1654. 'label': 'New label',
  1655. 'color': '00ff00',
  1656. 'length': 50,
  1657. 'length_unit': CableLengthUnitChoices.UNIT_METER,
  1658. }
  1659. class VirtualChassisTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  1660. model = VirtualChassis
  1661. @classmethod
  1662. def setUpTestData(cls):
  1663. site = Site.objects.create(name='Site 1', slug='site-1')
  1664. manufacturer = Manufacturer.objects.create(name='Manufacturer', slug='manufacturer-1')
  1665. device_type = DeviceType.objects.create(
  1666. manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'
  1667. )
  1668. device_role = DeviceRole.objects.create(
  1669. name='Device Role', slug='device-role-1'
  1670. )
  1671. devices = (
  1672. Device(device_type=device_type, device_role=device_role, name='Device 1', site=site),
  1673. Device(device_type=device_type, device_role=device_role, name='Device 2', site=site),
  1674. Device(device_type=device_type, device_role=device_role, name='Device 3', site=site),
  1675. Device(device_type=device_type, device_role=device_role, name='Device 4', site=site),
  1676. Device(device_type=device_type, device_role=device_role, name='Device 5', site=site),
  1677. Device(device_type=device_type, device_role=device_role, name='Device 6', site=site),
  1678. Device(device_type=device_type, device_role=device_role, name='Device 7', site=site),
  1679. Device(device_type=device_type, device_role=device_role, name='Device 8', site=site),
  1680. Device(device_type=device_type, device_role=device_role, name='Device 9', site=site),
  1681. Device(device_type=device_type, device_role=device_role, name='Device 10', site=site),
  1682. Device(device_type=device_type, device_role=device_role, name='Device 11', site=site),
  1683. Device(device_type=device_type, device_role=device_role, name='Device 12', site=site),
  1684. )
  1685. Device.objects.bulk_create(devices)
  1686. # Create three VirtualChassis with three members each
  1687. vc1 = VirtualChassis.objects.create(name='VC1', master=devices[0], domain='domain-1')
  1688. Device.objects.filter(pk=devices[0].pk).update(virtual_chassis=vc1, vc_position=1)
  1689. Device.objects.filter(pk=devices[1].pk).update(virtual_chassis=vc1, vc_position=2)
  1690. Device.objects.filter(pk=devices[2].pk).update(virtual_chassis=vc1, vc_position=3)
  1691. vc2 = VirtualChassis.objects.create(name='VC2', master=devices[3], domain='domain-2')
  1692. Device.objects.filter(pk=devices[3].pk).update(virtual_chassis=vc2, vc_position=1)
  1693. Device.objects.filter(pk=devices[4].pk).update(virtual_chassis=vc2, vc_position=2)
  1694. Device.objects.filter(pk=devices[5].pk).update(virtual_chassis=vc2, vc_position=3)
  1695. vc3 = VirtualChassis.objects.create(name='VC3', master=devices[6], domain='domain-3')
  1696. Device.objects.filter(pk=devices[6].pk).update(virtual_chassis=vc3, vc_position=1)
  1697. Device.objects.filter(pk=devices[7].pk).update(virtual_chassis=vc3, vc_position=2)
  1698. Device.objects.filter(pk=devices[8].pk).update(virtual_chassis=vc3, vc_position=3)
  1699. cls.form_data = {
  1700. 'name': 'VC4',
  1701. 'domain': 'domain-4',
  1702. # Management form data for VC members
  1703. 'form-TOTAL_FORMS': 0,
  1704. 'form-INITIAL_FORMS': 3,
  1705. 'form-MIN_NUM_FORMS': 0,
  1706. 'form-MAX_NUM_FORMS': 1000,
  1707. }
  1708. cls.csv_data = (
  1709. "name,domain,master",
  1710. "VC4,Domain 4,Device 10",
  1711. "VC5,Domain 5,Device 11",
  1712. "VC6,Domain 6,Device 12",
  1713. )
  1714. cls.bulk_edit_data = {
  1715. 'domain': 'domain-x',
  1716. }
  1717. class PowerPanelTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  1718. model = PowerPanel
  1719. @classmethod
  1720. def setUpTestData(cls):
  1721. sites = (
  1722. Site(name='Site 1', slug='site-1'),
  1723. Site(name='Site 2', slug='site-2'),
  1724. )
  1725. Site.objects.bulk_create(sites)
  1726. locations = (
  1727. Location(name='Location 1', slug='location-1', site=sites[0]),
  1728. Location(name='Location 2', slug='location-2', site=sites[1]),
  1729. )
  1730. for location in locations:
  1731. location.save()
  1732. PowerPanel.objects.bulk_create((
  1733. PowerPanel(site=sites[0], location=locations[0], name='Power Panel 1'),
  1734. PowerPanel(site=sites[0], location=locations[0], name='Power Panel 2'),
  1735. PowerPanel(site=sites[0], location=locations[0], name='Power Panel 3'),
  1736. ))
  1737. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  1738. cls.form_data = {
  1739. 'site': sites[1].pk,
  1740. 'location': locations[1].pk,
  1741. 'name': 'Power Panel X',
  1742. 'tags': [t.pk for t in tags],
  1743. }
  1744. cls.csv_data = (
  1745. "site,location,name",
  1746. "Site 1,Location 1,Power Panel 4",
  1747. "Site 1,Location 1,Power Panel 5",
  1748. "Site 1,Location 1,Power Panel 6",
  1749. )
  1750. cls.bulk_edit_data = {
  1751. 'site': sites[1].pk,
  1752. 'location': locations[1].pk,
  1753. }
  1754. class PowerFeedTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  1755. model = PowerFeed
  1756. @classmethod
  1757. def setUpTestData(cls):
  1758. site = Site.objects.create(name='Site 1', slug='site-1')
  1759. powerpanels = (
  1760. PowerPanel(site=site, name='Power Panel 1'),
  1761. PowerPanel(site=site, name='Power Panel 2'),
  1762. )
  1763. PowerPanel.objects.bulk_create(powerpanels)
  1764. racks = (
  1765. Rack(site=site, name='Rack 1'),
  1766. Rack(site=site, name='Rack 2'),
  1767. )
  1768. Rack.objects.bulk_create(racks)
  1769. PowerFeed.objects.bulk_create((
  1770. PowerFeed(name='Power Feed 1', power_panel=powerpanels[0], rack=racks[0]),
  1771. PowerFeed(name='Power Feed 2', power_panel=powerpanels[0], rack=racks[0]),
  1772. PowerFeed(name='Power Feed 3', power_panel=powerpanels[0], rack=racks[0]),
  1773. ))
  1774. tags = create_tags('Alpha', 'Bravo', 'Charlie')
  1775. cls.form_data = {
  1776. 'name': 'Power Feed X',
  1777. 'power_panel': powerpanels[1].pk,
  1778. 'rack': racks[1].pk,
  1779. 'status': PowerFeedStatusChoices.STATUS_PLANNED,
  1780. 'type': PowerFeedTypeChoices.TYPE_REDUNDANT,
  1781. 'supply': PowerFeedSupplyChoices.SUPPLY_DC,
  1782. 'phase': PowerFeedPhaseChoices.PHASE_3PHASE,
  1783. 'voltage': 100,
  1784. 'amperage': 100,
  1785. 'max_utilization': 50,
  1786. 'comments': 'New comments',
  1787. 'tags': [t.pk for t in tags],
  1788. }
  1789. cls.csv_data = (
  1790. "site,power_panel,name,status,type,supply,phase,voltage,amperage,max_utilization",
  1791. "Site 1,Power Panel 1,Power Feed 4,active,primary,ac,single-phase,120,20,80",
  1792. "Site 1,Power Panel 1,Power Feed 5,active,primary,ac,single-phase,120,20,80",
  1793. "Site 1,Power Panel 1,Power Feed 6,active,primary,ac,single-phase,120,20,80",
  1794. )
  1795. cls.bulk_edit_data = {
  1796. 'power_panel': powerpanels[1].pk,
  1797. 'rack': racks[1].pk,
  1798. 'status': PowerFeedStatusChoices.STATUS_PLANNED,
  1799. 'type': PowerFeedTypeChoices.TYPE_REDUNDANT,
  1800. 'supply': PowerFeedSupplyChoices.SUPPLY_DC,
  1801. 'phase': PowerFeedPhaseChoices.PHASE_3PHASE,
  1802. 'voltage': 100,
  1803. 'amperage': 100,
  1804. 'max_utilization': 50,
  1805. 'comments': 'New comments',
  1806. }
  1807. @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
  1808. def test_trace(self):
  1809. manufacturer = Manufacturer.objects.create(name='Manufacturer', slug='manufacturer-1')
  1810. device_type = DeviceType.objects.create(
  1811. manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'
  1812. )
  1813. device_role = DeviceRole.objects.create(
  1814. name='Device Role', slug='device-role-1'
  1815. )
  1816. device = Device.objects.create(
  1817. site=Site.objects.first(), device_type=device_type, device_role=device_role
  1818. )
  1819. powerfeed = PowerFeed.objects.first()
  1820. powerport = PowerPort.objects.create(
  1821. device=device,
  1822. name='Power Port 1'
  1823. )
  1824. Cable(termination_a=powerfeed, termination_b=powerport).save()
  1825. response = self.client.get(reverse('dcim:powerfeed_trace', kwargs={'pk': powerfeed.pk}))
  1826. self.assertHttpStatus(response, 200)