test_api.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. import urllib.parse
  2. from django.conf import settings
  3. from django.contrib.contenttypes.models import ContentType
  4. from django.test import Client, TestCase, override_settings
  5. from django.urls import reverse
  6. from rest_framework import status
  7. from dcim.models import Region, Site
  8. from extras.choices import CustomFieldTypeChoices
  9. from extras.models import CustomField
  10. from ipam.models import VLAN
  11. from utilities.testing import APITestCase, disable_warnings
  12. class WritableNestedSerializerTest(APITestCase):
  13. """
  14. Test the operation of WritableNestedSerializer using VLANSerializer as our test subject.
  15. """
  16. def setUp(self):
  17. super().setUp()
  18. self.region_a = Region.objects.create(name='Region A', slug='region-a')
  19. self.site1 = Site.objects.create(region=self.region_a, name='Site 1', slug='site-1')
  20. self.site2 = Site.objects.create(region=self.region_a, name='Site 2', slug='site-2')
  21. def test_related_by_pk(self):
  22. data = {
  23. 'vid': 100,
  24. 'name': 'Test VLAN 100',
  25. 'site': self.site1.pk,
  26. }
  27. url = reverse('ipam-api:vlan-list')
  28. self.add_permissions('ipam.add_vlan')
  29. response = self.client.post(url, data, format='json', **self.header)
  30. self.assertHttpStatus(response, status.HTTP_201_CREATED)
  31. self.assertEqual(response.data['site']['id'], self.site1.pk)
  32. vlan = VLAN.objects.get(pk=response.data['id'])
  33. self.assertEqual(vlan.site, self.site1)
  34. def test_related_by_pk_no_match(self):
  35. data = {
  36. 'vid': 100,
  37. 'name': 'Test VLAN 100',
  38. 'site': 999,
  39. }
  40. url = reverse('ipam-api:vlan-list')
  41. self.add_permissions('ipam.add_vlan')
  42. with disable_warnings('django.request'):
  43. response = self.client.post(url, data, format='json', **self.header)
  44. self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
  45. self.assertEqual(VLAN.objects.count(), 0)
  46. self.assertTrue(response.data['site'][0].startswith("Related object not found"))
  47. def test_related_by_attributes(self):
  48. data = {
  49. 'vid': 100,
  50. 'name': 'Test VLAN 100',
  51. 'site': {
  52. 'name': 'Site 1'
  53. },
  54. }
  55. url = reverse('ipam-api:vlan-list')
  56. self.add_permissions('ipam.add_vlan')
  57. response = self.client.post(url, data, format='json', **self.header)
  58. self.assertHttpStatus(response, status.HTTP_201_CREATED)
  59. self.assertEqual(response.data['site']['id'], self.site1.pk)
  60. vlan = VLAN.objects.get(pk=response.data['id'])
  61. self.assertEqual(vlan.site, self.site1)
  62. def test_related_by_attributes_no_match(self):
  63. data = {
  64. 'vid': 100,
  65. 'name': 'Test VLAN 100',
  66. 'site': {
  67. 'name': 'Site X'
  68. },
  69. }
  70. url = reverse('ipam-api:vlan-list')
  71. self.add_permissions('ipam.add_vlan')
  72. with disable_warnings('django.request'):
  73. response = self.client.post(url, data, format='json', **self.header)
  74. self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
  75. self.assertEqual(VLAN.objects.count(), 0)
  76. self.assertTrue(response.data['site'][0].startswith("Related object not found"))
  77. def test_related_by_attributes_multiple_matches(self):
  78. data = {
  79. 'vid': 100,
  80. 'name': 'Test VLAN 100',
  81. 'site': {
  82. 'region': {
  83. "name": "Region A",
  84. },
  85. },
  86. }
  87. url = reverse('ipam-api:vlan-list')
  88. self.add_permissions('ipam.add_vlan')
  89. with disable_warnings('django.request'):
  90. response = self.client.post(url, data, format='json', **self.header)
  91. self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
  92. self.assertEqual(VLAN.objects.count(), 0)
  93. self.assertTrue(response.data['site'][0].startswith("Multiple objects match"))
  94. def test_related_by_invalid(self):
  95. data = {
  96. 'vid': 100,
  97. 'name': 'Test VLAN 100',
  98. 'site': 'XXX',
  99. }
  100. url = reverse('ipam-api:vlan-list')
  101. self.add_permissions('ipam.add_vlan')
  102. with disable_warnings('django.request'):
  103. response = self.client.post(url, data, format='json', **self.header)
  104. self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
  105. self.assertEqual(VLAN.objects.count(), 0)
  106. class APIPaginationTestCase(APITestCase):
  107. user_permissions = ('dcim.view_site',)
  108. @classmethod
  109. def setUpTestData(cls):
  110. cls.url = reverse('dcim-api:site-list')
  111. # Create a large number of Sites for testing
  112. Site.objects.bulk_create([
  113. Site(name=f'Site {i}', slug=f'site-{i}') for i in range(1, 101)
  114. ])
  115. def test_default_page_size(self):
  116. response = self.client.get(self.url, format='json', **self.header)
  117. page_size = settings.PAGINATE_COUNT
  118. self.assertLess(page_size, 100, "Default page size not sufficient for data set")
  119. self.assertHttpStatus(response, status.HTTP_200_OK)
  120. self.assertEqual(response.data['count'], 100)
  121. self.assertTrue(response.data['next'].endswith(f'?limit={page_size}&offset={page_size}'))
  122. self.assertIsNone(response.data['previous'])
  123. self.assertEqual(len(response.data['results']), page_size)
  124. def test_custom_page_size(self):
  125. response = self.client.get(f'{self.url}?limit=10', format='json', **self.header)
  126. self.assertHttpStatus(response, status.HTTP_200_OK)
  127. self.assertEqual(response.data['count'], 100)
  128. self.assertTrue(response.data['next'].endswith(f'?limit=10&offset=10'))
  129. self.assertIsNone(response.data['previous'])
  130. self.assertEqual(len(response.data['results']), 10)
  131. @override_settings(MAX_PAGE_SIZE=20)
  132. def test_max_page_size(self):
  133. response = self.client.get(f'{self.url}?limit=0', format='json', **self.header)
  134. self.assertHttpStatus(response, status.HTTP_200_OK)
  135. self.assertEqual(response.data['count'], 100)
  136. self.assertTrue(response.data['next'].endswith(f'?limit=20&offset=20'))
  137. self.assertIsNone(response.data['previous'])
  138. self.assertEqual(len(response.data['results']), 20)
  139. @override_settings(MAX_PAGE_SIZE=0)
  140. def test_max_page_size_disabled(self):
  141. response = self.client.get(f'{self.url}?limit=0', format='json', **self.header)
  142. self.assertHttpStatus(response, status.HTTP_200_OK)
  143. self.assertEqual(response.data['count'], 100)
  144. self.assertIsNone(response.data['next'])
  145. self.assertIsNone(response.data['previous'])
  146. self.assertEqual(len(response.data['results']), 100)
  147. class APIDocsTestCase(TestCase):
  148. def setUp(self):
  149. self.client = Client()
  150. # Populate a CustomField to activate CustomFieldSerializer
  151. content_type = ContentType.objects.get_for_model(Site)
  152. self.cf_text = CustomField(type=CustomFieldTypeChoices.TYPE_TEXT, name='test')
  153. self.cf_text.save()
  154. self.cf_text.content_types.set([content_type])
  155. self.cf_text.save()
  156. def test_api_docs(self):
  157. url = reverse('api_docs')
  158. params = {
  159. "format": "openapi",
  160. }
  161. response = self.client.get('{}?{}'.format(url, urllib.parse.urlencode(params)))
  162. self.assertEqual(response.status_code, 200)