test_api.py 11 KB

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