test_api.py 98 KB

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