test_api.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  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.models import ConfigContext, Graph, ExportTemplate, Tag
  10. from extras.scripts import BooleanVar, IntegerVar, Script, StringVar
  11. from extras.utils import FeatureQuery
  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(FeatureQuery('graphs').get_query())
  27. graph_type_choices = {
  28. "{}.{}".format(ct.app_label, ct.model): ct.name 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.objects.create(name='Test Tenant Group 1', slug='test-tenant-group-1')
  302. tenantgroup2 = TenantGroup.objects.create(name='Test Tenant Group 2', slug='test-tenant-group-2')
  303. tenant1 = Tenant.objects.create(name='Test Tenant 1', slug='test-tenant-1')
  304. tenant2 = Tenant.objects.create(name='Test Tenant 2', slug='test-tenant-2')
  305. tag1 = Tag.objects.create(name='Test Tag 1', slug='test-tag-1')
  306. tag2 = Tag.objects.create(name='Test Tag 2', slug='test-tag-2')
  307. data = {
  308. 'name': 'Test Config Context 4',
  309. 'weight': 1000,
  310. 'regions': [region1.pk, region2.pk],
  311. 'sites': [site1.pk, site2.pk],
  312. 'roles': [role1.pk, role2.pk],
  313. 'platforms': [platform1.pk, platform2.pk],
  314. 'tenant_groups': [tenantgroup1.pk, tenantgroup2.pk],
  315. 'tenants': [tenant1.pk, tenant2.pk],
  316. 'tags': [tag1.slug, tag2.slug],
  317. 'data': {'foo': 'XXX'}
  318. }
  319. url = reverse('extras-api:configcontext-list')
  320. response = self.client.post(url, data, format='json', **self.header)
  321. self.assertHttpStatus(response, status.HTTP_201_CREATED)
  322. self.assertEqual(ConfigContext.objects.count(), 4)
  323. configcontext4 = ConfigContext.objects.get(pk=response.data['id'])
  324. self.assertEqual(configcontext4.name, data['name'])
  325. self.assertEqual(region1.pk, data['regions'][0])
  326. self.assertEqual(region2.pk, data['regions'][1])
  327. self.assertEqual(site1.pk, data['sites'][0])
  328. self.assertEqual(site2.pk, data['sites'][1])
  329. self.assertEqual(role1.pk, data['roles'][0])
  330. self.assertEqual(role2.pk, data['roles'][1])
  331. self.assertEqual(platform1.pk, data['platforms'][0])
  332. self.assertEqual(platform2.pk, data['platforms'][1])
  333. self.assertEqual(tenantgroup1.pk, data['tenant_groups'][0])
  334. self.assertEqual(tenantgroup2.pk, data['tenant_groups'][1])
  335. self.assertEqual(tenant1.pk, data['tenants'][0])
  336. self.assertEqual(tenant2.pk, data['tenants'][1])
  337. self.assertEqual(tag1.slug, data['tags'][0])
  338. self.assertEqual(tag2.slug, data['tags'][1])
  339. self.assertEqual(configcontext4.data, data['data'])
  340. def test_create_configcontext_bulk(self):
  341. data = [
  342. {
  343. 'name': 'Test Config Context 4',
  344. 'data': {'more_foo': True},
  345. },
  346. {
  347. 'name': 'Test Config Context 5',
  348. 'data': {'more_bar': False},
  349. },
  350. {
  351. 'name': 'Test Config Context 6',
  352. 'data': {'more_baz': None},
  353. },
  354. ]
  355. url = reverse('extras-api:configcontext-list')
  356. response = self.client.post(url, data, format='json', **self.header)
  357. self.assertHttpStatus(response, status.HTTP_201_CREATED)
  358. self.assertEqual(ConfigContext.objects.count(), 6)
  359. for i in range(0, 3):
  360. self.assertEqual(response.data[i]['name'], data[i]['name'])
  361. self.assertEqual(response.data[i]['data'], data[i]['data'])
  362. def test_update_configcontext(self):
  363. region1 = Region.objects.create(name='Test Region 1', slug='test-region-1')
  364. region2 = Region.objects.create(name='Test Region 2', slug='test-region-2')
  365. data = {
  366. 'name': 'Test Config Context X',
  367. 'weight': 999,
  368. 'regions': [region1.pk, region2.pk],
  369. 'data': {'foo': 'XXX'}
  370. }
  371. url = reverse('extras-api:configcontext-detail', kwargs={'pk': self.configcontext1.pk})
  372. response = self.client.put(url, data, format='json', **self.header)
  373. self.assertHttpStatus(response, status.HTTP_200_OK)
  374. self.assertEqual(ConfigContext.objects.count(), 3)
  375. configcontext1 = ConfigContext.objects.get(pk=response.data['id'])
  376. self.assertEqual(configcontext1.name, data['name'])
  377. self.assertEqual(configcontext1.weight, data['weight'])
  378. self.assertEqual(sorted([r.pk for r in configcontext1.regions.all()]), sorted(data['regions']))
  379. self.assertEqual(configcontext1.data, data['data'])
  380. def test_delete_configcontext(self):
  381. url = reverse('extras-api:configcontext-detail', kwargs={'pk': self.configcontext1.pk})
  382. response = self.client.delete(url, **self.header)
  383. self.assertHttpStatus(response, status.HTTP_204_NO_CONTENT)
  384. self.assertEqual(ConfigContext.objects.count(), 2)
  385. def test_render_configcontext_for_object(self):
  386. # Create a Device for which we'll render a config context
  387. manufacturer = Manufacturer.objects.create(
  388. name='Test Manufacturer',
  389. slug='test-manufacturer'
  390. )
  391. device_type = DeviceType.objects.create(
  392. manufacturer=manufacturer,
  393. model='Test Device Type'
  394. )
  395. device_role = DeviceRole.objects.create(
  396. name='Test Role',
  397. slug='test-role'
  398. )
  399. site = Site.objects.create(
  400. name='Test Site',
  401. slug='test-site'
  402. )
  403. device = Device.objects.create(
  404. name='Test Device',
  405. device_type=device_type,
  406. device_role=device_role,
  407. site=site
  408. )
  409. # Test default config contexts (created at test setup)
  410. rendered_context = device.get_config_context()
  411. self.assertEqual(rendered_context['foo'], 123)
  412. self.assertEqual(rendered_context['bar'], 456)
  413. self.assertEqual(rendered_context['baz'], 789)
  414. # Add another context specific to the site
  415. configcontext4 = ConfigContext(
  416. name='Test Config Context 4',
  417. data={'site_data': 'ABC'}
  418. )
  419. configcontext4.save()
  420. configcontext4.sites.add(site)
  421. rendered_context = device.get_config_context()
  422. self.assertEqual(rendered_context['site_data'], 'ABC')
  423. # Override one of the default contexts
  424. configcontext5 = ConfigContext(
  425. name='Test Config Context 5',
  426. weight=2000,
  427. data={'foo': 999}
  428. )
  429. configcontext5.save()
  430. configcontext5.sites.add(site)
  431. rendered_context = device.get_config_context()
  432. self.assertEqual(rendered_context['foo'], 999)
  433. # Add a context which does NOT match our device and ensure it does not apply
  434. site2 = Site.objects.create(
  435. name='Test Site 2',
  436. slug='test-site-2'
  437. )
  438. configcontext6 = ConfigContext(
  439. name='Test Config Context 6',
  440. weight=2000,
  441. data={'bar': 999}
  442. )
  443. configcontext6.save()
  444. configcontext6.sites.add(site2)
  445. rendered_context = device.get_config_context()
  446. self.assertEqual(rendered_context['bar'], 456)
  447. class ScriptTest(APITestCase):
  448. class TestScript(Script):
  449. class Meta:
  450. name = "Test script"
  451. var1 = StringVar()
  452. var2 = IntegerVar()
  453. var3 = BooleanVar()
  454. def run(self, data, commit=True):
  455. self.log_info(data['var1'])
  456. self.log_success(data['var2'])
  457. self.log_failure(data['var3'])
  458. return 'Script complete'
  459. def get_test_script(self, *args):
  460. return self.TestScript
  461. def setUp(self):
  462. super().setUp()
  463. # Monkey-patch the API viewset's _get_script method to return our test script above
  464. ScriptViewSet._get_script = self.get_test_script
  465. def test_get_script(self):
  466. url = reverse('extras-api:script-detail', kwargs={'pk': None})
  467. response = self.client.get(url, **self.header)
  468. self.assertEqual(response.data['name'], self.TestScript.Meta.name)
  469. self.assertEqual(response.data['vars']['var1'], 'StringVar')
  470. self.assertEqual(response.data['vars']['var2'], 'IntegerVar')
  471. self.assertEqual(response.data['vars']['var3'], 'BooleanVar')
  472. def test_run_script(self):
  473. script_data = {
  474. 'var1': 'FooBar',
  475. 'var2': 123,
  476. 'var3': False,
  477. }
  478. data = {
  479. 'data': script_data,
  480. 'commit': True,
  481. }
  482. url = reverse('extras-api:script-detail', kwargs={'pk': None})
  483. response = self.client.post(url, data, format='json', **self.header)
  484. self.assertHttpStatus(response, status.HTTP_200_OK)
  485. self.assertEqual(response.data['log'][0]['status'], 'info')
  486. self.assertEqual(response.data['log'][0]['message'], script_data['var1'])
  487. self.assertEqual(response.data['log'][1]['status'], 'success')
  488. self.assertEqual(response.data['log'][1]['message'], script_data['var2'])
  489. self.assertEqual(response.data['log'][2]['status'], 'failure')
  490. self.assertEqual(response.data['log'][2]['message'], script_data['var3'])
  491. self.assertEqual(response.data['output'], 'Script complete')
  492. class CreatedUpdatedFilterTest(APITestCase):
  493. def setUp(self):
  494. super().setUp()
  495. self.site1 = Site.objects.create(name='Test Site 1', slug='test-site-1')
  496. self.rackgroup1 = RackGroup.objects.create(site=self.site1, name='Test Rack Group 1', slug='test-rack-group-1')
  497. self.rackrole1 = RackRole.objects.create(name='Test Rack Role 1', slug='test-rack-role-1', color='ff0000')
  498. self.rack1 = Rack.objects.create(
  499. site=self.site1, group=self.rackgroup1, role=self.rackrole1, name='Test Rack 1', u_height=42,
  500. )
  501. self.rack2 = Rack.objects.create(
  502. site=self.site1, group=self.rackgroup1, role=self.rackrole1, name='Test Rack 2', u_height=42,
  503. )
  504. # change the created and last_updated of one
  505. Rack.objects.filter(pk=self.rack2.pk).update(
  506. last_updated=datetime.datetime(2001, 2, 3, 1, 2, 3, 4, tzinfo=timezone.utc),
  507. created=datetime.datetime(2001, 2, 3)
  508. )
  509. def test_get_rack_created(self):
  510. url = reverse('dcim-api:rack-list')
  511. response = self.client.get('{}?created=2001-02-03'.format(url), **self.header)
  512. self.assertEqual(response.data['count'], 1)
  513. self.assertEqual(response.data['results'][0]['id'], self.rack2.pk)
  514. def test_get_rack_created_gte(self):
  515. url = reverse('dcim-api:rack-list')
  516. response = self.client.get('{}?created__gte=2001-02-04'.format(url), **self.header)
  517. self.assertEqual(response.data['count'], 1)
  518. self.assertEqual(response.data['results'][0]['id'], self.rack1.pk)
  519. def test_get_rack_created_lte(self):
  520. url = reverse('dcim-api:rack-list')
  521. response = self.client.get('{}?created__lte=2001-02-04'.format(url), **self.header)
  522. self.assertEqual(response.data['count'], 1)
  523. self.assertEqual(response.data['results'][0]['id'], self.rack2.pk)
  524. def test_get_rack_last_updated(self):
  525. url = reverse('dcim-api:rack-list')
  526. response = self.client.get('{}?last_updated=2001-02-03%2001:02:03.000004'.format(url), **self.header)
  527. self.assertEqual(response.data['count'], 1)
  528. self.assertEqual(response.data['results'][0]['id'], self.rack2.pk)
  529. def test_get_rack_last_updated_gte(self):
  530. url = reverse('dcim-api:rack-list')
  531. response = self.client.get('{}?last_updated__gte=2001-02-04%2001:02:03.000004'.format(url), **self.header)
  532. self.assertEqual(response.data['count'], 1)
  533. self.assertEqual(response.data['results'][0]['id'], self.rack1.pk)
  534. def test_get_rack_last_updated_lte(self):
  535. url = reverse('dcim-api:rack-list')
  536. response = self.client.get('{}?last_updated__lte=2001-02-04%2001:02:03.000004'.format(url), **self.header)
  537. self.assertEqual(response.data['count'], 1)
  538. self.assertEqual(response.data['results'][0]['id'], self.rack2.pk)