test_api.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. import datetime
  2. from django.contrib.contenttypes.models import ContentType
  3. from django.urls import reverse
  4. from django.utils import timezone
  5. from rest_framework import status
  6. from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Platform, Rack, RackGroup, RackRole, Region, Site
  7. from extras.api.views import ScriptViewSet
  8. from extras.choices import *
  9. from extras.constants import GRAPH_MODELS
  10. from extras.models import ConfigContext, Graph, ExportTemplate, Tag
  11. from extras.scripts import BooleanVar, IntegerVar, Script, StringVar
  12. from tenancy.models import Tenant, TenantGroup
  13. from utilities.testing import APITestCase, choices_to_dict
  14. class AppTest(APITestCase):
  15. def test_root(self):
  16. url = reverse('extras-api:api-root')
  17. response = self.client.get('{}?format=api'.format(url), **self.header)
  18. self.assertEqual(response.status_code, 200)
  19. def test_choices(self):
  20. url = reverse('extras-api:field-choice-list')
  21. response = self.client.get(url, **self.header)
  22. self.assertEqual(response.status_code, 200)
  23. # ExportTemplate
  24. self.assertEqual(choices_to_dict(response.data.get('export-template:template_language')), TemplateLanguageChoices.as_dict())
  25. # Graph
  26. content_types = ContentType.objects.filter(GRAPH_MODELS)
  27. graph_type_choices = {
  28. "{}.{}".format(ct.app_label, ct.model): str(ct) for ct in content_types
  29. }
  30. self.assertEqual(choices_to_dict(response.data.get('graph:type')), graph_type_choices)
  31. self.assertEqual(choices_to_dict(response.data.get('graph:template_language')), TemplateLanguageChoices.as_dict())
  32. # ObjectChange
  33. self.assertEqual(choices_to_dict(response.data.get('object-change:action')), ObjectChangeActionChoices.as_dict())
  34. class GraphTest(APITestCase):
  35. def setUp(self):
  36. super().setUp()
  37. site_ct = ContentType.objects.get_for_model(Site)
  38. self.graph1 = Graph.objects.create(
  39. type=site_ct,
  40. name='Test Graph 1',
  41. source='http://example.com/graphs.py?site={{ obj.name }}&foo=1'
  42. )
  43. self.graph2 = Graph.objects.create(
  44. type=site_ct,
  45. name='Test Graph 2',
  46. source='http://example.com/graphs.py?site={{ obj.name }}&foo=2'
  47. )
  48. self.graph3 = Graph.objects.create(
  49. type=site_ct,
  50. name='Test Graph 3',
  51. source='http://example.com/graphs.py?site={{ obj.name }}&foo=3'
  52. )
  53. def test_get_graph(self):
  54. url = reverse('extras-api:graph-detail', kwargs={'pk': self.graph1.pk})
  55. response = self.client.get(url, **self.header)
  56. self.assertEqual(response.data['name'], self.graph1.name)
  57. def test_list_graphs(self):
  58. url = reverse('extras-api:graph-list')
  59. response = self.client.get(url, **self.header)
  60. self.assertEqual(response.data['count'], 3)
  61. def test_create_graph(self):
  62. data = {
  63. 'type': 'dcim.site',
  64. 'name': 'Test Graph 4',
  65. 'source': 'http://example.com/graphs.py?site={{ obj.name }}&foo=4',
  66. }
  67. url = reverse('extras-api:graph-list')
  68. response = self.client.post(url, data, format='json', **self.header)
  69. self.assertHttpStatus(response, status.HTTP_201_CREATED)
  70. self.assertEqual(Graph.objects.count(), 4)
  71. graph4 = Graph.objects.get(pk=response.data['id'])
  72. self.assertEqual(graph4.type, ContentType.objects.get_for_model(Site))
  73. self.assertEqual(graph4.name, data['name'])
  74. self.assertEqual(graph4.source, data['source'])
  75. def test_create_graph_bulk(self):
  76. data = [
  77. {
  78. 'type': 'dcim.site',
  79. 'name': 'Test Graph 4',
  80. 'source': 'http://example.com/graphs.py?site={{ obj.name }}&foo=4',
  81. },
  82. {
  83. 'type': 'dcim.site',
  84. 'name': 'Test Graph 5',
  85. 'source': 'http://example.com/graphs.py?site={{ obj.name }}&foo=5',
  86. },
  87. {
  88. 'type': 'dcim.site',
  89. 'name': 'Test Graph 6',
  90. 'source': 'http://example.com/graphs.py?site={{ obj.name }}&foo=6',
  91. },
  92. ]
  93. url = reverse('extras-api:graph-list')
  94. response = self.client.post(url, data, format='json', **self.header)
  95. self.assertHttpStatus(response, status.HTTP_201_CREATED)
  96. self.assertEqual(Graph.objects.count(), 6)
  97. self.assertEqual(response.data[0]['name'], data[0]['name'])
  98. self.assertEqual(response.data[1]['name'], data[1]['name'])
  99. self.assertEqual(response.data[2]['name'], data[2]['name'])
  100. def test_update_graph(self):
  101. data = {
  102. 'type': 'dcim.site',
  103. 'name': 'Test Graph X',
  104. 'source': 'http://example.com/graphs.py?site={{ obj.name }}&foo=99',
  105. }
  106. url = reverse('extras-api:graph-detail', kwargs={'pk': self.graph1.pk})
  107. response = self.client.put(url, data, format='json', **self.header)
  108. self.assertHttpStatus(response, status.HTTP_200_OK)
  109. self.assertEqual(Graph.objects.count(), 3)
  110. graph1 = Graph.objects.get(pk=response.data['id'])
  111. self.assertEqual(graph1.type, ContentType.objects.get_for_model(Site))
  112. self.assertEqual(graph1.name, data['name'])
  113. self.assertEqual(graph1.source, data['source'])
  114. def test_delete_graph(self):
  115. url = reverse('extras-api:graph-detail', kwargs={'pk': self.graph1.pk})
  116. response = self.client.delete(url, **self.header)
  117. self.assertHttpStatus(response, status.HTTP_204_NO_CONTENT)
  118. self.assertEqual(Graph.objects.count(), 2)
  119. class ExportTemplateTest(APITestCase):
  120. def setUp(self):
  121. super().setUp()
  122. content_type = ContentType.objects.get_for_model(Device)
  123. self.exporttemplate1 = ExportTemplate.objects.create(
  124. content_type=content_type, name='Test Export Template 1',
  125. template_code='{% for obj in queryset %}{{ obj.name }}\n{% endfor %}'
  126. )
  127. self.exporttemplate2 = ExportTemplate.objects.create(
  128. content_type=content_type, name='Test Export Template 2',
  129. template_code='{% for obj in queryset %}{{ obj.name }}\n{% endfor %}'
  130. )
  131. self.exporttemplate3 = ExportTemplate.objects.create(
  132. content_type=content_type, name='Test Export Template 3',
  133. template_code='{% for obj in queryset %}{{ obj.name }}\n{% endfor %}'
  134. )
  135. def test_get_exporttemplate(self):
  136. url = reverse('extras-api:exporttemplate-detail', kwargs={'pk': self.exporttemplate1.pk})
  137. response = self.client.get(url, **self.header)
  138. self.assertEqual(response.data['name'], self.exporttemplate1.name)
  139. def test_list_exporttemplates(self):
  140. url = reverse('extras-api:exporttemplate-list')
  141. response = self.client.get(url, **self.header)
  142. self.assertEqual(response.data['count'], 3)
  143. def test_create_exporttemplate(self):
  144. data = {
  145. 'content_type': 'dcim.device',
  146. 'name': 'Test Export Template 4',
  147. 'template_code': '{% for obj in queryset %}{{ obj.name }}\n{% endfor %}',
  148. }
  149. url = reverse('extras-api:exporttemplate-list')
  150. response = self.client.post(url, data, format='json', **self.header)
  151. self.assertHttpStatus(response, status.HTTP_201_CREATED)
  152. self.assertEqual(ExportTemplate.objects.count(), 4)
  153. exporttemplate4 = ExportTemplate.objects.get(pk=response.data['id'])
  154. self.assertEqual(exporttemplate4.content_type, ContentType.objects.get_for_model(Device))
  155. self.assertEqual(exporttemplate4.name, data['name'])
  156. self.assertEqual(exporttemplate4.template_code, data['template_code'])
  157. def test_create_exporttemplate_bulk(self):
  158. data = [
  159. {
  160. 'content_type': 'dcim.device',
  161. 'name': 'Test Export Template 4',
  162. 'template_code': '{% for obj in queryset %}{{ obj.name }}\n{% endfor %}',
  163. },
  164. {
  165. 'content_type': 'dcim.device',
  166. 'name': 'Test Export Template 5',
  167. 'template_code': '{% for obj in queryset %}{{ obj.name }}\n{% endfor %}',
  168. },
  169. {
  170. 'content_type': 'dcim.device',
  171. 'name': 'Test Export Template 6',
  172. 'template_code': '{% for obj in queryset %}{{ obj.name }}\n{% endfor %}',
  173. },
  174. ]
  175. url = reverse('extras-api:exporttemplate-list')
  176. response = self.client.post(url, data, format='json', **self.header)
  177. self.assertHttpStatus(response, status.HTTP_201_CREATED)
  178. self.assertEqual(ExportTemplate.objects.count(), 6)
  179. self.assertEqual(response.data[0]['name'], data[0]['name'])
  180. self.assertEqual(response.data[1]['name'], data[1]['name'])
  181. self.assertEqual(response.data[2]['name'], data[2]['name'])
  182. def test_update_exporttemplate(self):
  183. data = {
  184. 'content_type': 'dcim.device',
  185. 'name': 'Test Export Template X',
  186. 'template_code': '{% for obj in queryset %}{{ obj.name }}\n{% endfor %}',
  187. }
  188. url = reverse('extras-api:exporttemplate-detail', kwargs={'pk': self.exporttemplate1.pk})
  189. response = self.client.put(url, data, format='json', **self.header)
  190. self.assertHttpStatus(response, status.HTTP_200_OK)
  191. self.assertEqual(ExportTemplate.objects.count(), 3)
  192. exporttemplate1 = ExportTemplate.objects.get(pk=response.data['id'])
  193. self.assertEqual(exporttemplate1.name, data['name'])
  194. self.assertEqual(exporttemplate1.template_code, data['template_code'])
  195. def test_delete_exporttemplate(self):
  196. url = reverse('extras-api:exporttemplate-detail', kwargs={'pk': self.exporttemplate1.pk})
  197. response = self.client.delete(url, **self.header)
  198. self.assertHttpStatus(response, status.HTTP_204_NO_CONTENT)
  199. self.assertEqual(ExportTemplate.objects.count(), 2)
  200. class TagTest(APITestCase):
  201. def setUp(self):
  202. super().setUp()
  203. self.tag1 = Tag.objects.create(name='Test Tag 1', slug='test-tag-1')
  204. self.tag2 = Tag.objects.create(name='Test Tag 2', slug='test-tag-2')
  205. self.tag3 = Tag.objects.create(name='Test Tag 3', slug='test-tag-3')
  206. def test_get_tag(self):
  207. url = reverse('extras-api:tag-detail', kwargs={'pk': self.tag1.pk})
  208. response = self.client.get(url, **self.header)
  209. self.assertEqual(response.data['name'], self.tag1.name)
  210. def test_list_tags(self):
  211. url = reverse('extras-api:tag-list')
  212. response = self.client.get(url, **self.header)
  213. self.assertEqual(response.data['count'], 3)
  214. def test_create_tag(self):
  215. data = {
  216. 'name': 'Test Tag 4',
  217. 'slug': 'test-tag-4',
  218. }
  219. url = reverse('extras-api:tag-list')
  220. response = self.client.post(url, data, format='json', **self.header)
  221. self.assertHttpStatus(response, status.HTTP_201_CREATED)
  222. self.assertEqual(Tag.objects.count(), 4)
  223. tag4 = Tag.objects.get(pk=response.data['id'])
  224. self.assertEqual(tag4.name, data['name'])
  225. self.assertEqual(tag4.slug, data['slug'])
  226. def test_create_tag_bulk(self):
  227. data = [
  228. {
  229. 'name': 'Test Tag 4',
  230. 'slug': 'test-tag-4',
  231. },
  232. {
  233. 'name': 'Test Tag 5',
  234. 'slug': 'test-tag-5',
  235. },
  236. {
  237. 'name': 'Test Tag 6',
  238. 'slug': 'test-tag-6',
  239. },
  240. ]
  241. url = reverse('extras-api:tag-list')
  242. response = self.client.post(url, data, format='json', **self.header)
  243. self.assertHttpStatus(response, status.HTTP_201_CREATED)
  244. self.assertEqual(Tag.objects.count(), 6)
  245. self.assertEqual(response.data[0]['name'], data[0]['name'])
  246. self.assertEqual(response.data[1]['name'], data[1]['name'])
  247. self.assertEqual(response.data[2]['name'], data[2]['name'])
  248. def test_update_tag(self):
  249. data = {
  250. 'name': 'Test Tag X',
  251. 'slug': 'test-tag-x',
  252. }
  253. url = reverse('extras-api:tag-detail', kwargs={'pk': self.tag1.pk})
  254. response = self.client.put(url, data, format='json', **self.header)
  255. self.assertHttpStatus(response, status.HTTP_200_OK)
  256. self.assertEqual(Tag.objects.count(), 3)
  257. tag1 = Tag.objects.get(pk=response.data['id'])
  258. self.assertEqual(tag1.name, data['name'])
  259. self.assertEqual(tag1.slug, data['slug'])
  260. def test_delete_tag(self):
  261. url = reverse('extras-api:tag-detail', kwargs={'pk': self.tag1.pk})
  262. response = self.client.delete(url, **self.header)
  263. self.assertHttpStatus(response, status.HTTP_204_NO_CONTENT)
  264. self.assertEqual(Tag.objects.count(), 2)
  265. class ConfigContextTest(APITestCase):
  266. def setUp(self):
  267. super().setUp()
  268. self.configcontext1 = ConfigContext.objects.create(
  269. name='Test Config Context 1',
  270. weight=100,
  271. data={'foo': 123}
  272. )
  273. self.configcontext2 = ConfigContext.objects.create(
  274. name='Test Config Context 2',
  275. weight=200,
  276. data={'bar': 456}
  277. )
  278. self.configcontext3 = ConfigContext.objects.create(
  279. name='Test Config Context 3',
  280. weight=300,
  281. data={'baz': 789}
  282. )
  283. def test_get_configcontext(self):
  284. url = reverse('extras-api:configcontext-detail', kwargs={'pk': self.configcontext1.pk})
  285. response = self.client.get(url, **self.header)
  286. self.assertEqual(response.data['name'], self.configcontext1.name)
  287. self.assertEqual(response.data['data'], self.configcontext1.data)
  288. def test_list_configcontexts(self):
  289. url = reverse('extras-api:configcontext-list')
  290. response = self.client.get(url, **self.header)
  291. self.assertEqual(response.data['count'], 3)
  292. def test_create_configcontext(self):
  293. region1 = Region.objects.create(name='Test Region 1', slug='test-region-1')
  294. region2 = Region.objects.create(name='Test Region 2', slug='test-region-2')
  295. site1 = Site.objects.create(name='Test Site 1', slug='test-site-1')
  296. site2 = Site.objects.create(name='Test Site 2', slug='test-site-2')
  297. role1 = DeviceRole.objects.create(name='Test Role 1', slug='test-role-1')
  298. role2 = DeviceRole.objects.create(name='Test Role 2', slug='test-role-2')
  299. platform1 = Platform.objects.create(name='Test Platform 1', slug='test-platform-1')
  300. platform2 = Platform.objects.create(name='Test Platform 2', slug='test-platform-2')
  301. tenantgroup1 = TenantGroup(name='Test Tenant Group 1', slug='test-tenant-group-1')
  302. tenantgroup1.save()
  303. tenantgroup2 = TenantGroup(name='Test Tenant Group 2', slug='test-tenant-group-2')
  304. tenantgroup2.save()
  305. tenant1 = Tenant.objects.create(name='Test Tenant 1', slug='test-tenant-1')
  306. tenant2 = Tenant.objects.create(name='Test Tenant 2', slug='test-tenant-2')
  307. tag1 = Tag.objects.create(name='Test Tag 1', slug='test-tag-1')
  308. tag2 = Tag.objects.create(name='Test Tag 2', slug='test-tag-2')
  309. data = {
  310. 'name': 'Test Config Context 4',
  311. 'weight': 1000,
  312. 'regions': [region1.pk, region2.pk],
  313. 'sites': [site1.pk, site2.pk],
  314. 'roles': [role1.pk, role2.pk],
  315. 'platforms': [platform1.pk, platform2.pk],
  316. 'tenant_groups': [tenantgroup1.pk, tenantgroup2.pk],
  317. 'tenants': [tenant1.pk, tenant2.pk],
  318. 'tags': [tag1.slug, tag2.slug],
  319. 'data': {'foo': 'XXX'}
  320. }
  321. url = reverse('extras-api:configcontext-list')
  322. response = self.client.post(url, data, format='json', **self.header)
  323. self.assertHttpStatus(response, status.HTTP_201_CREATED)
  324. self.assertEqual(ConfigContext.objects.count(), 4)
  325. configcontext4 = ConfigContext.objects.get(pk=response.data['id'])
  326. self.assertEqual(configcontext4.name, data['name'])
  327. self.assertEqual(region1.pk, data['regions'][0])
  328. self.assertEqual(region2.pk, data['regions'][1])
  329. self.assertEqual(site1.pk, data['sites'][0])
  330. self.assertEqual(site2.pk, data['sites'][1])
  331. self.assertEqual(role1.pk, data['roles'][0])
  332. self.assertEqual(role2.pk, data['roles'][1])
  333. self.assertEqual(platform1.pk, data['platforms'][0])
  334. self.assertEqual(platform2.pk, data['platforms'][1])
  335. self.assertEqual(tenantgroup1.pk, data['tenant_groups'][0])
  336. self.assertEqual(tenantgroup2.pk, data['tenant_groups'][1])
  337. self.assertEqual(tenant1.pk, data['tenants'][0])
  338. self.assertEqual(tenant2.pk, data['tenants'][1])
  339. self.assertEqual(tag1.slug, data['tags'][0])
  340. self.assertEqual(tag2.slug, data['tags'][1])
  341. self.assertEqual(configcontext4.data, data['data'])
  342. def test_create_configcontext_bulk(self):
  343. data = [
  344. {
  345. 'name': 'Test Config Context 4',
  346. 'data': {'more_foo': True},
  347. },
  348. {
  349. 'name': 'Test Config Context 5',
  350. 'data': {'more_bar': False},
  351. },
  352. {
  353. 'name': 'Test Config Context 6',
  354. 'data': {'more_baz': None},
  355. },
  356. ]
  357. url = reverse('extras-api:configcontext-list')
  358. response = self.client.post(url, data, format='json', **self.header)
  359. self.assertHttpStatus(response, status.HTTP_201_CREATED)
  360. self.assertEqual(ConfigContext.objects.count(), 6)
  361. for i in range(0, 3):
  362. self.assertEqual(response.data[i]['name'], data[i]['name'])
  363. self.assertEqual(response.data[i]['data'], data[i]['data'])
  364. def test_update_configcontext(self):
  365. region1 = Region.objects.create(name='Test Region 1', slug='test-region-1')
  366. region2 = Region.objects.create(name='Test Region 2', slug='test-region-2')
  367. data = {
  368. 'name': 'Test Config Context X',
  369. 'weight': 999,
  370. 'regions': [region1.pk, region2.pk],
  371. 'data': {'foo': 'XXX'}
  372. }
  373. url = reverse('extras-api:configcontext-detail', kwargs={'pk': self.configcontext1.pk})
  374. response = self.client.put(url, data, format='json', **self.header)
  375. self.assertHttpStatus(response, status.HTTP_200_OK)
  376. self.assertEqual(ConfigContext.objects.count(), 3)
  377. configcontext1 = ConfigContext.objects.get(pk=response.data['id'])
  378. self.assertEqual(configcontext1.name, data['name'])
  379. self.assertEqual(configcontext1.weight, data['weight'])
  380. self.assertEqual(sorted([r.pk for r in configcontext1.regions.all()]), sorted(data['regions']))
  381. self.assertEqual(configcontext1.data, data['data'])
  382. def test_delete_configcontext(self):
  383. url = reverse('extras-api:configcontext-detail', kwargs={'pk': self.configcontext1.pk})
  384. response = self.client.delete(url, **self.header)
  385. self.assertHttpStatus(response, status.HTTP_204_NO_CONTENT)
  386. self.assertEqual(ConfigContext.objects.count(), 2)
  387. def test_render_configcontext_for_object(self):
  388. # Create a Device for which we'll render a config context
  389. manufacturer = Manufacturer.objects.create(
  390. name='Test Manufacturer',
  391. slug='test-manufacturer'
  392. )
  393. device_type = DeviceType.objects.create(
  394. manufacturer=manufacturer,
  395. model='Test Device Type'
  396. )
  397. device_role = DeviceRole.objects.create(
  398. name='Test Role',
  399. slug='test-role'
  400. )
  401. site = Site.objects.create(
  402. name='Test Site',
  403. slug='test-site'
  404. )
  405. device = Device.objects.create(
  406. name='Test Device',
  407. device_type=device_type,
  408. device_role=device_role,
  409. site=site
  410. )
  411. # Test default config contexts (created at test setup)
  412. rendered_context = device.get_config_context()
  413. self.assertEqual(rendered_context['foo'], 123)
  414. self.assertEqual(rendered_context['bar'], 456)
  415. self.assertEqual(rendered_context['baz'], 789)
  416. # Add another context specific to the site
  417. configcontext4 = ConfigContext(
  418. name='Test Config Context 4',
  419. data={'site_data': 'ABC'}
  420. )
  421. configcontext4.save()
  422. configcontext4.sites.add(site)
  423. rendered_context = device.get_config_context()
  424. self.assertEqual(rendered_context['site_data'], 'ABC')
  425. # Override one of the default contexts
  426. configcontext5 = ConfigContext(
  427. name='Test Config Context 5',
  428. weight=2000,
  429. data={'foo': 999}
  430. )
  431. configcontext5.save()
  432. configcontext5.sites.add(site)
  433. rendered_context = device.get_config_context()
  434. self.assertEqual(rendered_context['foo'], 999)
  435. # Add a context which does NOT match our device and ensure it does not apply
  436. site2 = Site.objects.create(
  437. name='Test Site 2',
  438. slug='test-site-2'
  439. )
  440. configcontext6 = ConfigContext(
  441. name='Test Config Context 6',
  442. weight=2000,
  443. data={'bar': 999}
  444. )
  445. configcontext6.save()
  446. configcontext6.sites.add(site2)
  447. rendered_context = device.get_config_context()
  448. self.assertEqual(rendered_context['bar'], 456)
  449. class ScriptTest(APITestCase):
  450. class TestScript(Script):
  451. class Meta:
  452. name = "Test script"
  453. var1 = StringVar()
  454. var2 = IntegerVar()
  455. var3 = BooleanVar()
  456. def run(self, data, commit=True):
  457. self.log_info(data['var1'])
  458. self.log_success(data['var2'])
  459. self.log_failure(data['var3'])
  460. return 'Script complete'
  461. def get_test_script(self, *args):
  462. return self.TestScript
  463. def setUp(self):
  464. super().setUp()
  465. # Monkey-patch the API viewset's _get_script method to return our test script above
  466. ScriptViewSet._get_script = self.get_test_script
  467. def test_get_script(self):
  468. url = reverse('extras-api:script-detail', kwargs={'pk': None})
  469. response = self.client.get(url, **self.header)
  470. self.assertEqual(response.data['name'], self.TestScript.Meta.name)
  471. self.assertEqual(response.data['vars']['var1'], 'StringVar')
  472. self.assertEqual(response.data['vars']['var2'], 'IntegerVar')
  473. self.assertEqual(response.data['vars']['var3'], 'BooleanVar')
  474. def test_run_script(self):
  475. script_data = {
  476. 'var1': 'FooBar',
  477. 'var2': 123,
  478. 'var3': False,
  479. }
  480. data = {
  481. 'data': script_data,
  482. 'commit': True,
  483. }
  484. url = reverse('extras-api:script-detail', kwargs={'pk': None})
  485. response = self.client.post(url, data, format='json', **self.header)
  486. self.assertHttpStatus(response, status.HTTP_200_OK)
  487. self.assertEqual(response.data['log'][0]['status'], 'info')
  488. self.assertEqual(response.data['log'][0]['message'], script_data['var1'])
  489. self.assertEqual(response.data['log'][1]['status'], 'success')
  490. self.assertEqual(response.data['log'][1]['message'], script_data['var2'])
  491. self.assertEqual(response.data['log'][2]['status'], 'failure')
  492. self.assertEqual(response.data['log'][2]['message'], script_data['var3'])
  493. self.assertEqual(response.data['output'], 'Script complete')
  494. class CreatedUpdatedFilterTest(APITestCase):
  495. def setUp(self):
  496. super().setUp()
  497. self.site1 = Site.objects.create(name='Test Site 1', slug='test-site-1')
  498. self.rackgroup1 = RackGroup.objects.create(site=self.site1, name='Test Rack Group 1', slug='test-rack-group-1')
  499. self.rackrole1 = RackRole.objects.create(name='Test Rack Role 1', slug='test-rack-role-1', color='ff0000')
  500. self.rack1 = Rack.objects.create(
  501. site=self.site1, group=self.rackgroup1, role=self.rackrole1, name='Test Rack 1', u_height=42,
  502. )
  503. self.rack2 = Rack.objects.create(
  504. site=self.site1, group=self.rackgroup1, role=self.rackrole1, name='Test Rack 2', u_height=42,
  505. )
  506. # change the created and last_updated of one
  507. Rack.objects.filter(pk=self.rack2.pk).update(
  508. last_updated=datetime.datetime(2001, 2, 3, 1, 2, 3, 4, tzinfo=timezone.utc),
  509. created=datetime.datetime(2001, 2, 3)
  510. )
  511. def test_get_rack_created(self):
  512. url = reverse('dcim-api:rack-list')
  513. response = self.client.get('{}?created=2001-02-03'.format(url), **self.header)
  514. self.assertEqual(response.data['count'], 1)
  515. self.assertEqual(response.data['results'][0]['id'], self.rack2.pk)
  516. def test_get_rack_created_gte(self):
  517. url = reverse('dcim-api:rack-list')
  518. response = self.client.get('{}?created__gte=2001-02-04'.format(url), **self.header)
  519. self.assertEqual(response.data['count'], 1)
  520. self.assertEqual(response.data['results'][0]['id'], self.rack1.pk)
  521. def test_get_rack_created_lte(self):
  522. url = reverse('dcim-api:rack-list')
  523. response = self.client.get('{}?created__lte=2001-02-04'.format(url), **self.header)
  524. self.assertEqual(response.data['count'], 1)
  525. self.assertEqual(response.data['results'][0]['id'], self.rack2.pk)
  526. def test_get_rack_last_updated(self):
  527. url = reverse('dcim-api:rack-list')
  528. response = self.client.get('{}?last_updated=2001-02-03%2001:02:03.000004'.format(url), **self.header)
  529. self.assertEqual(response.data['count'], 1)
  530. self.assertEqual(response.data['results'][0]['id'], self.rack2.pk)
  531. def test_get_rack_last_updated_gte(self):
  532. url = reverse('dcim-api:rack-list')
  533. response = self.client.get('{}?last_updated__gte=2001-02-04%2001:02:03.000004'.format(url), **self.header)
  534. self.assertEqual(response.data['count'], 1)
  535. self.assertEqual(response.data['results'][0]['id'], self.rack1.pk)
  536. def test_get_rack_last_updated_lte(self):
  537. url = reverse('dcim-api:rack-list')
  538. response = self.client.get('{}?last_updated__lte=2001-02-04%2001:02:03.000004'.format(url), **self.header)
  539. self.assertEqual(response.data['count'], 1)
  540. self.assertEqual(response.data['results'][0]['id'], self.rack2.pk)