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.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. self.content_type = ContentType.objects.get_for_model(Device)
  123. self.exporttemplate1 = ExportTemplate.objects.create(
  124. content_type=self.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=self.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=self.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': self.content_type.pk,
  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_id, data['content_type'])
  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': self.content_type.pk,
  161. 'name': 'Test Export Template 4',
  162. 'template_code': '{% for obj in queryset %}{{ obj.name }}\n{% endfor %}',
  163. },
  164. {
  165. 'content_type': self.content_type.pk,
  166. 'name': 'Test Export Template 5',
  167. 'template_code': '{% for obj in queryset %}{{ obj.name }}\n{% endfor %}',
  168. },
  169. {
  170. 'content_type': self.content_type.pk,
  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': self.content_type.pk,
  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):
  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)