2
0

test_api.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. from django.contrib.auth import get_user_model
  2. from django.contrib.auth.models import Group
  3. from django.contrib.contenttypes.models import ContentType
  4. from django.urls import reverse
  5. from users.models import ObjectPermission, Token
  6. from utilities.testing import APIViewTestCases, APITestCase, create_test_user
  7. from utilities.utils import deepmerge
  8. User = get_user_model()
  9. class AppTest(APITestCase):
  10. def test_root(self):
  11. url = reverse('users-api:api-root')
  12. response = self.client.get(f'{url}?format=api', **self.header)
  13. self.assertEqual(response.status_code, 200)
  14. class UserTest(APIViewTestCases.APIViewTestCase):
  15. model = User
  16. view_namespace = 'users'
  17. brief_fields = ['display', 'id', 'url', 'username']
  18. validation_excluded_fields = ['password']
  19. create_data = [
  20. {
  21. 'username': 'User_4',
  22. 'password': 'password4',
  23. },
  24. {
  25. 'username': 'User_5',
  26. 'password': 'password5',
  27. },
  28. {
  29. 'username': 'User_6',
  30. 'password': 'password6',
  31. },
  32. ]
  33. bulk_update_data = {
  34. 'email': 'test@example.com',
  35. }
  36. @classmethod
  37. def setUpTestData(cls):
  38. users = (
  39. User(username='User_1', password='password1'),
  40. User(username='User_2', password='password2'),
  41. User(username='User_3', password='password3'),
  42. )
  43. User.objects.bulk_create(users)
  44. def test_that_password_is_changed(self):
  45. """
  46. Test that password is changed
  47. """
  48. obj_perm = ObjectPermission(
  49. name='Test permission',
  50. actions=['change']
  51. )
  52. obj_perm.save()
  53. obj_perm.users.add(self.user)
  54. obj_perm.object_types.add(ContentType.objects.get_for_model(self.model))
  55. user_credentials = {
  56. 'username': 'user1',
  57. 'password': 'abc123',
  58. }
  59. user = User.objects.create_user(**user_credentials)
  60. data = {
  61. 'password': 'newpassword'
  62. }
  63. url = reverse('users-api:user-detail', kwargs={'pk': user.id})
  64. response = self.client.patch(url, data, format='json', **self.header)
  65. self.assertEqual(response.status_code, 200)
  66. updated_user = User.objects.get(id=user.id)
  67. self.assertTrue(updated_user.check_password(data['password']))
  68. class GroupTest(APIViewTestCases.APIViewTestCase):
  69. model = Group
  70. view_namespace = 'users'
  71. brief_fields = ['display', 'id', 'name', 'url']
  72. create_data = [
  73. {
  74. 'name': 'Group 4',
  75. },
  76. {
  77. 'name': 'Group 5',
  78. },
  79. {
  80. 'name': 'Group 6',
  81. },
  82. ]
  83. @classmethod
  84. def setUpTestData(cls):
  85. users = (
  86. Group(name='Group 1'),
  87. Group(name='Group 2'),
  88. Group(name='Group 3'),
  89. )
  90. Group.objects.bulk_create(users)
  91. def test_bulk_update_objects(self):
  92. """
  93. Disabled test. There's no attribute we can set in bulk for Groups.
  94. """
  95. return
  96. class TokenTest(
  97. # No GraphQL support for Token
  98. APIViewTestCases.GetObjectViewTestCase,
  99. APIViewTestCases.ListObjectsViewTestCase,
  100. APIViewTestCases.CreateObjectViewTestCase,
  101. APIViewTestCases.UpdateObjectViewTestCase,
  102. APIViewTestCases.DeleteObjectViewTestCase
  103. ):
  104. model = Token
  105. brief_fields = ['display', 'id', 'key', 'url', 'write_enabled']
  106. bulk_update_data = {
  107. 'description': 'New description',
  108. }
  109. def setUp(self):
  110. super().setUp()
  111. # Apply grant_token permission to enable the creation of Tokens for other Users
  112. self.add_permissions('users.grant_token')
  113. @classmethod
  114. def setUpTestData(cls):
  115. users = (
  116. create_test_user('User 1'),
  117. create_test_user('User 2'),
  118. create_test_user('User 3'),
  119. )
  120. tokens = (
  121. Token(user=users[0]),
  122. Token(user=users[1]),
  123. Token(user=users[2]),
  124. )
  125. # Use save() instead of bulk_create() to ensure keys get automatically generated
  126. for token in tokens:
  127. token.save()
  128. cls.create_data = [
  129. {
  130. 'user': users[0].pk,
  131. },
  132. {
  133. 'user': users[1].pk,
  134. },
  135. {
  136. 'user': users[2].pk,
  137. },
  138. ]
  139. def test_provision_token_valid(self):
  140. """
  141. Test the provisioning of a new REST API token given a valid username and password.
  142. """
  143. user_credentials = {
  144. 'username': 'user1',
  145. 'password': 'abc123',
  146. }
  147. user = User.objects.create_user(**user_credentials)
  148. data = {
  149. **user_credentials,
  150. 'description': 'My API token',
  151. 'expires': '2099-12-31T23:59:59Z',
  152. }
  153. url = reverse('users-api:token_provision')
  154. response = self.client.post(url, data, format='json', **self.header)
  155. self.assertEqual(response.status_code, 201)
  156. self.assertIn('key', response.data)
  157. self.assertEqual(len(response.data['key']), 40)
  158. self.assertEqual(response.data['description'], data['description'])
  159. self.assertEqual(response.data['expires'], data['expires'])
  160. token = Token.objects.get(user=user)
  161. self.assertEqual(token.key, response.data['key'])
  162. def test_provision_token_invalid(self):
  163. """
  164. Test the behavior of the token provisioning view when invalid credentials are supplied.
  165. """
  166. data = {
  167. 'username': 'nonexistentuser',
  168. 'password': 'abc123',
  169. }
  170. url = reverse('users-api:token_provision')
  171. response = self.client.post(url, data, format='json', **self.header)
  172. self.assertEqual(response.status_code, 403)
  173. def test_provision_token_other_user(self):
  174. """
  175. Test provisioning a Token for a different User with & without the grant_token permission.
  176. """
  177. # Clear grant_token permission assigned by setUpTestData
  178. ObjectPermission.objects.filter(users=self.user).delete()
  179. self.add_permissions('users.add_token')
  180. user2 = User.objects.create_user(username='testuser2')
  181. data = {
  182. 'user': user2.id,
  183. }
  184. url = reverse('users-api:token-list')
  185. # Attempt to create a new Token for User2 *without* the grant_token permission
  186. response = self.client.post(url, data, format='json', **self.header)
  187. self.assertEqual(response.status_code, 403)
  188. # Assign grant_token permission and successfully create a new Token for User2
  189. self.add_permissions('users.grant_token')
  190. response = self.client.post(url, data, format='json', **self.header)
  191. self.assertEqual(response.status_code, 201)
  192. class ObjectPermissionTest(
  193. # No GraphQL support for ObjectPermission
  194. APIViewTestCases.GetObjectViewTestCase,
  195. APIViewTestCases.ListObjectsViewTestCase,
  196. APIViewTestCases.CreateObjectViewTestCase,
  197. APIViewTestCases.UpdateObjectViewTestCase,
  198. APIViewTestCases.DeleteObjectViewTestCase
  199. ):
  200. model = ObjectPermission
  201. brief_fields = ['actions', 'display', 'enabled', 'groups', 'id', 'name', 'object_types', 'url', 'users']
  202. @classmethod
  203. def setUpTestData(cls):
  204. groups = (
  205. Group(name='Group 1'),
  206. Group(name='Group 2'),
  207. Group(name='Group 3'),
  208. )
  209. Group.objects.bulk_create(groups)
  210. users = (
  211. User(username='User 1', is_active=True),
  212. User(username='User 2', is_active=True),
  213. User(username='User 3', is_active=True),
  214. )
  215. User.objects.bulk_create(users)
  216. object_type = ContentType.objects.get(app_label='dcim', model='device')
  217. for i in range(3):
  218. objectpermission = ObjectPermission(
  219. name=f'Permission {i+1}',
  220. actions=['view', 'add', 'change', 'delete'],
  221. constraints={'name': f'TEST{i+1}'}
  222. )
  223. objectpermission.save()
  224. objectpermission.object_types.add(object_type)
  225. objectpermission.groups.add(groups[i])
  226. objectpermission.users.add(users[i])
  227. cls.create_data = [
  228. {
  229. 'name': 'Permission 4',
  230. 'object_types': ['dcim.site'],
  231. 'groups': [groups[0].pk],
  232. 'users': [users[0].pk],
  233. 'actions': ['view', 'add', 'change', 'delete'],
  234. 'constraints': {'name': 'TEST4'},
  235. },
  236. {
  237. 'name': 'Permission 5',
  238. 'object_types': ['dcim.site'],
  239. 'groups': [groups[1].pk],
  240. 'users': [users[1].pk],
  241. 'actions': ['view', 'add', 'change', 'delete'],
  242. 'constraints': {'name': 'TEST5'},
  243. },
  244. {
  245. 'name': 'Permission 6',
  246. 'object_types': ['dcim.site'],
  247. 'groups': [groups[2].pk],
  248. 'users': [users[2].pk],
  249. 'actions': ['view', 'add', 'change', 'delete'],
  250. 'constraints': {'name': 'TEST6'},
  251. },
  252. ]
  253. cls.bulk_update_data = {
  254. 'description': 'New description',
  255. }
  256. class UserConfigTest(APITestCase):
  257. def test_get(self):
  258. """
  259. Retrieve user configuration via GET request.
  260. """
  261. userconfig = self.user.config
  262. url = reverse('users-api:userconfig-list')
  263. response = self.client.get(url, **self.header)
  264. self.assertEqual(response.data, {})
  265. data = {
  266. "a": 123,
  267. "b": 456,
  268. "c": 789,
  269. }
  270. userconfig.data = data
  271. userconfig.save()
  272. response = self.client.get(url, **self.header)
  273. self.assertEqual(response.data, data)
  274. def test_patch(self):
  275. """
  276. Set user config via PATCH requests.
  277. """
  278. userconfig = self.user.config
  279. url = reverse('users-api:userconfig-list')
  280. data = {
  281. "a": {
  282. "a1": "X",
  283. "a2": "Y",
  284. },
  285. "b": {
  286. "b1": "Z",
  287. }
  288. }
  289. response = self.client.patch(url, data=data, format='json', **self.header)
  290. self.assertDictEqual(response.data, data)
  291. userconfig.refresh_from_db()
  292. self.assertDictEqual(userconfig.data, data)
  293. update_data = {
  294. "c": 123
  295. }
  296. response = self.client.patch(url, data=update_data, format='json', **self.header)
  297. new_data = deepmerge(data, update_data)
  298. self.assertDictEqual(response.data, new_data)
  299. userconfig.refresh_from_db()
  300. self.assertDictEqual(userconfig.data, new_data)