test_views.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. import urllib.parse
  2. import uuid
  3. from django.contrib.auth.models import User
  4. from django.contrib.contenttypes.models import ContentType
  5. from django.urls import reverse
  6. from dcim.models import Site
  7. from extras.choices import *
  8. from extras.models import *
  9. from utilities.testing import ViewTestCases, TestCase
  10. class CustomFieldTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  11. model = CustomField
  12. @classmethod
  13. def setUpTestData(cls):
  14. site_ct = ContentType.objects.get_for_model(Site)
  15. custom_fields = (
  16. CustomField(name='field1', label='Field 1', type=CustomFieldTypeChoices.TYPE_TEXT),
  17. CustomField(name='field2', label='Field 2', type=CustomFieldTypeChoices.TYPE_TEXT),
  18. CustomField(name='field3', label='Field 3', type=CustomFieldTypeChoices.TYPE_TEXT),
  19. )
  20. for customfield in custom_fields:
  21. customfield.save()
  22. customfield.content_types.add(site_ct)
  23. cls.form_data = {
  24. 'name': 'field_x',
  25. 'label': 'Field X',
  26. 'type': 'text',
  27. 'content_types': [site_ct.pk],
  28. 'search_weight': 2000,
  29. 'filter_logic': CustomFieldFilterLogicChoices.FILTER_EXACT,
  30. 'default': None,
  31. 'weight': 200,
  32. 'required': True,
  33. 'ui_visibility': CustomFieldVisibilityChoices.VISIBILITY_READ_WRITE,
  34. }
  35. cls.csv_data = (
  36. 'name,label,type,content_types,object_type,weight,search_weight,filter_logic,choices,validation_minimum,validation_maximum,validation_regex,ui_visibility',
  37. 'field4,Field 4,text,dcim.site,,100,1000,exact,,,,[a-z]{3},read-write',
  38. 'field5,Field 5,integer,dcim.site,,100,2000,exact,,1,100,,read-write',
  39. 'field6,Field 6,select,dcim.site,,100,3000,exact,"A,B,C",,,,read-write',
  40. 'field7,Field 7,object,dcim.site,dcim.region,100,4000,exact,,,,,read-write',
  41. )
  42. cls.csv_update_data = (
  43. 'id,label',
  44. f'{custom_fields[0].pk},New label 1',
  45. f'{custom_fields[1].pk},New label 2',
  46. f'{custom_fields[2].pk},New label 3',
  47. )
  48. cls.bulk_edit_data = {
  49. 'required': True,
  50. 'weight': 200,
  51. }
  52. class CustomLinkTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  53. model = CustomLink
  54. @classmethod
  55. def setUpTestData(cls):
  56. site_ct = ContentType.objects.get_for_model(Site)
  57. custom_links = (
  58. CustomLink(name='Custom Link 1', enabled=True, link_text='Link 1', link_url='http://example.com/?1'),
  59. CustomLink(name='Custom Link 2', enabled=True, link_text='Link 2', link_url='http://example.com/?2'),
  60. CustomLink(name='Custom Link 3', enabled=False, link_text='Link 3', link_url='http://example.com/?3'),
  61. )
  62. CustomLink.objects.bulk_create(custom_links)
  63. for i, custom_link in enumerate(custom_links):
  64. custom_link.content_types.set([site_ct])
  65. cls.form_data = {
  66. 'name': 'Custom Link X',
  67. 'content_types': [site_ct.pk],
  68. 'enabled': False,
  69. 'weight': 100,
  70. 'button_class': CustomLinkButtonClassChoices.DEFAULT,
  71. 'link_text': 'Link X',
  72. 'link_url': 'http://example.com/?x'
  73. }
  74. cls.csv_data = (
  75. "name,content_types,enabled,weight,button_class,link_text,link_url",
  76. "Custom Link 4,dcim.site,True,100,blue,Link 4,http://exmaple.com/?4",
  77. "Custom Link 5,dcim.site,True,100,blue,Link 5,http://exmaple.com/?5",
  78. "Custom Link 6,dcim.site,False,100,blue,Link 6,http://exmaple.com/?6",
  79. )
  80. cls.csv_update_data = (
  81. "id,name",
  82. f"{custom_links[0].pk},Custom Link 7",
  83. f"{custom_links[1].pk},Custom Link 8",
  84. f"{custom_links[2].pk},Custom Link 9",
  85. )
  86. cls.bulk_edit_data = {
  87. 'button_class': CustomLinkButtonClassChoices.CYAN,
  88. 'enabled': False,
  89. 'weight': 200,
  90. }
  91. class ExportTemplateTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  92. model = ExportTemplate
  93. @classmethod
  94. def setUpTestData(cls):
  95. site_ct = ContentType.objects.get_for_model(Site)
  96. TEMPLATE_CODE = """{% for object in queryset %}{{ object }}{% endfor %}"""
  97. export_templates = (
  98. ExportTemplate(name='Export Template 1', template_code=TEMPLATE_CODE),
  99. ExportTemplate(name='Export Template 2', template_code=TEMPLATE_CODE),
  100. ExportTemplate(name='Export Template 3', template_code=TEMPLATE_CODE),
  101. )
  102. ExportTemplate.objects.bulk_create(export_templates)
  103. for et in export_templates:
  104. et.content_types.set([site_ct])
  105. cls.form_data = {
  106. 'name': 'Export Template X',
  107. 'content_types': [site_ct.pk],
  108. 'template_code': TEMPLATE_CODE,
  109. }
  110. cls.csv_data = (
  111. "name,content_types,template_code",
  112. f"Export Template 4,dcim.site,{TEMPLATE_CODE}",
  113. f"Export Template 5,dcim.site,{TEMPLATE_CODE}",
  114. f"Export Template 6,dcim.site,{TEMPLATE_CODE}",
  115. )
  116. cls.csv_update_data = (
  117. "id,name",
  118. f"{export_templates[0].pk},Export Template 7",
  119. f"{export_templates[1].pk},Export Template 8",
  120. f"{export_templates[2].pk},Export Template 9",
  121. )
  122. cls.bulk_edit_data = {
  123. 'mime_type': 'text/html',
  124. 'file_extension': 'html',
  125. 'as_attachment': True,
  126. }
  127. class WebhookTestCase(ViewTestCases.PrimaryObjectViewTestCase):
  128. model = Webhook
  129. @classmethod
  130. def setUpTestData(cls):
  131. site_ct = ContentType.objects.get_for_model(Site)
  132. webhooks = (
  133. Webhook(name='Webhook 1', payload_url='http://example.com/?1', type_create=True, http_method='POST'),
  134. Webhook(name='Webhook 2', payload_url='http://example.com/?2', type_create=True, http_method='POST'),
  135. Webhook(name='Webhook 3', payload_url='http://example.com/?3', type_create=True, http_method='POST'),
  136. )
  137. for webhook in webhooks:
  138. webhook.save()
  139. webhook.content_types.add(site_ct)
  140. cls.form_data = {
  141. 'name': 'Webhook X',
  142. 'content_types': [site_ct.pk],
  143. 'type_create': False,
  144. 'type_update': True,
  145. 'type_delete': True,
  146. 'payload_url': 'http://example.com/?x',
  147. 'http_method': 'GET',
  148. 'http_content_type': 'application/foo',
  149. 'conditions': None,
  150. }
  151. cls.csv_data = (
  152. "name,content_types,type_create,payload_url,http_method,http_content_type",
  153. "Webhook 4,dcim.site,True,http://example.com/?4,GET,application/json",
  154. "Webhook 5,dcim.site,True,http://example.com/?5,GET,application/json",
  155. "Webhook 6,dcim.site,True,http://example.com/?6,GET,application/json",
  156. )
  157. cls.csv_update_data = (
  158. "id,name",
  159. f"{webhooks[0].pk},Webhook 7",
  160. f"{webhooks[1].pk},Webhook 8",
  161. f"{webhooks[2].pk},Webhook 9",
  162. )
  163. cls.bulk_edit_data = {
  164. 'enabled': False,
  165. 'type_create': False,
  166. 'type_update': True,
  167. 'type_delete': True,
  168. 'http_method': 'GET',
  169. }
  170. class TagTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
  171. model = Tag
  172. @classmethod
  173. def setUpTestData(cls):
  174. tags = (
  175. Tag(name='Tag 1', slug='tag-1'),
  176. Tag(name='Tag 2', slug='tag-2'),
  177. Tag(name='Tag 3', slug='tag-3'),
  178. )
  179. Tag.objects.bulk_create(tags)
  180. cls.form_data = {
  181. 'name': 'Tag X',
  182. 'slug': 'tag-x',
  183. 'color': 'c0c0c0',
  184. 'comments': 'Some comments',
  185. }
  186. cls.csv_data = (
  187. "name,slug,color,description",
  188. "Tag 4,tag-4,ff0000,Fourth tag",
  189. "Tag 5,tag-5,00ff00,Fifth tag",
  190. "Tag 6,tag-6,0000ff,Sixth tag",
  191. )
  192. cls.csv_update_data = (
  193. "id,name,description",
  194. f"{tags[0].pk},Tag 7,Fourth tag7",
  195. f"{tags[1].pk},Tag 8,Fifth tag8",
  196. f"{tags[2].pk},Tag 9,Sixth tag9",
  197. )
  198. cls.bulk_edit_data = {
  199. 'color': '00ff00',
  200. }
  201. # TODO: Change base class to PrimaryObjectViewTestCase
  202. # Blocked by absence of standard create/edit, bulk create views
  203. class ConfigContextTestCase(
  204. ViewTestCases.GetObjectViewTestCase,
  205. ViewTestCases.GetObjectChangelogViewTestCase,
  206. ViewTestCases.DeleteObjectViewTestCase,
  207. ViewTestCases.ListObjectsViewTestCase,
  208. ViewTestCases.BulkEditObjectsViewTestCase,
  209. ViewTestCases.BulkDeleteObjectsViewTestCase
  210. ):
  211. model = ConfigContext
  212. @classmethod
  213. def setUpTestData(cls):
  214. site = Site.objects.create(name='Site 1', slug='site-1')
  215. # Create three ConfigContexts
  216. for i in range(1, 4):
  217. configcontext = ConfigContext(
  218. name='Config Context {}'.format(i),
  219. data={'foo': i}
  220. )
  221. configcontext.save()
  222. configcontext.sites.add(site)
  223. cls.form_data = {
  224. 'name': 'Config Context X',
  225. 'weight': 200,
  226. 'description': 'A new config context',
  227. 'is_active': True,
  228. 'regions': [],
  229. 'sites': [site.pk],
  230. 'roles': [],
  231. 'platforms': [],
  232. 'tenant_groups': [],
  233. 'tenants': [],
  234. 'tags': [],
  235. 'data': '{"foo": 123}',
  236. }
  237. cls.bulk_edit_data = {
  238. 'weight': 300,
  239. 'is_active': False,
  240. 'description': 'New description',
  241. }
  242. # TODO: Convert to StandardTestCases.Views
  243. class ObjectChangeTestCase(TestCase):
  244. user_permissions = (
  245. 'extras.view_objectchange',
  246. )
  247. @classmethod
  248. def setUpTestData(cls):
  249. site = Site(name='Site 1', slug='site-1')
  250. site.save()
  251. # Create three ObjectChanges
  252. user = User.objects.create_user(username='testuser2')
  253. for i in range(1, 4):
  254. oc = site.to_objectchange(action=ObjectChangeActionChoices.ACTION_UPDATE)
  255. oc.user = user
  256. oc.request_id = uuid.uuid4()
  257. oc.save()
  258. def test_objectchange_list(self):
  259. url = reverse('extras:objectchange_list')
  260. params = {
  261. "user": User.objects.first().pk,
  262. }
  263. response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params)))
  264. self.assertHttpStatus(response, 200)
  265. def test_objectchange(self):
  266. objectchange = ObjectChange.objects.first()
  267. response = self.client.get(objectchange.get_absolute_url())
  268. self.assertHttpStatus(response, 200)
  269. class JournalEntryTestCase(
  270. # ViewTestCases.GetObjectViewTestCase,
  271. ViewTestCases.CreateObjectViewTestCase,
  272. ViewTestCases.EditObjectViewTestCase,
  273. ViewTestCases.DeleteObjectViewTestCase,
  274. ViewTestCases.ListObjectsViewTestCase,
  275. ViewTestCases.BulkEditObjectsViewTestCase,
  276. ViewTestCases.BulkDeleteObjectsViewTestCase
  277. ):
  278. model = JournalEntry
  279. @classmethod
  280. def setUpTestData(cls):
  281. site_ct = ContentType.objects.get_for_model(Site)
  282. site = Site.objects.create(name='Site 1', slug='site-1')
  283. user = User.objects.create(username='User 1')
  284. JournalEntry.objects.bulk_create((
  285. JournalEntry(assigned_object=site, created_by=user, comments='First entry'),
  286. JournalEntry(assigned_object=site, created_by=user, comments='Second entry'),
  287. JournalEntry(assigned_object=site, created_by=user, comments='Third entry'),
  288. ))
  289. cls.form_data = {
  290. 'assigned_object_type': site_ct.pk,
  291. 'assigned_object_id': site.pk,
  292. 'kind': 'info',
  293. 'comments': 'A new entry',
  294. }
  295. cls.bulk_edit_data = {
  296. 'kind': 'success',
  297. 'comments': 'Overwritten',
  298. }
  299. class CustomLinkTest(TestCase):
  300. user_permissions = ['dcim.view_site']
  301. def test_view_object_with_custom_link(self):
  302. customlink = CustomLink(
  303. name='Test',
  304. link_text='FOO {{ obj.name }} BAR',
  305. link_url='http://example.com/?site={{ obj.slug }}',
  306. new_window=False
  307. )
  308. customlink.save()
  309. customlink.content_types.set([ContentType.objects.get_for_model(Site)])
  310. site = Site(name='Test Site', slug='test-site')
  311. site.save()
  312. response = self.client.get(site.get_absolute_url(), follow=True)
  313. self.assertEqual(response.status_code, 200)
  314. self.assertIn(f'FOO {site.name} BAR', str(response.content))