You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

262 lines
9.7 KiB

5 years ago
  1. from django.core import mail
  2. from django.conf import settings
  3. from django.test.utils import override_settings
  4. from hc.test import BaseTestCase
  5. from hc.accounts.models import Member, Project
  6. from hc.api.models import TokenBucket
  7. class ProjectTestCase(BaseTestCase):
  8. def setUp(self):
  9. super().setUp()
  10. self.url = "/projects/%s/settings/" % self.project.code
  11. def test_it_checks_access(self):
  12. self.client.login(username="[email protected]", password="password")
  13. r = self.client.get(self.url)
  14. self.assertEqual(r.status_code, 404)
  15. def test_it_allows_team_access(self):
  16. self.client.login(username="[email protected]", password="password")
  17. r = self.client.get(self.url)
  18. self.assertContains(r, "Change Project Name")
  19. def test_it_shows_api_keys(self):
  20. self.project.api_key_readonly = "R" * 32
  21. self.project.save()
  22. self.client.login(username="[email protected]", password="password")
  23. form = {"show_api_keys": "1"}
  24. r = self.client.post(self.url, form)
  25. self.assertEqual(r.status_code, 200)
  26. self.assertContains(r, "X" * 32)
  27. self.assertContains(r, "R" * 32)
  28. self.assertContains(r, "Prometheus metrics endpoint")
  29. def test_it_creates_api_key(self):
  30. self.client.login(username="[email protected]", password="password")
  31. form = {"create_api_keys": "1"}
  32. r = self.client.post(self.url, form)
  33. self.assertEqual(r.status_code, 200)
  34. self.project.refresh_from_db()
  35. api_key = self.project.api_key
  36. self.assertTrue(len(api_key) > 10)
  37. self.assertFalse("b'" in api_key)
  38. def test_it_revokes_api_key(self):
  39. self.project.api_key_readonly = "R" * 32
  40. self.project.save()
  41. self.client.login(username="[email protected]", password="password")
  42. form = {"revoke_api_keys": "1"}
  43. r = self.client.post(self.url, form)
  44. self.assertEqual(r.status_code, 200)
  45. self.project.refresh_from_db()
  46. self.assertEqual(self.project.api_key, "")
  47. self.assertEqual(self.project.api_key_readonly, "")
  48. def test_it_adds_team_member(self):
  49. self.client.login(username="[email protected]", password="password")
  50. form = {"invite_team_member": "1", "email": "[email protected]", "rw": "1"}
  51. r = self.client.post(self.url, form)
  52. self.assertEqual(r.status_code, 200)
  53. members = self.project.member_set.all()
  54. self.assertEqual(members.count(), 2)
  55. member = Member.objects.get(
  56. project=self.project, user__email="[email protected]"
  57. )
  58. # The read-write flag should be set
  59. self.assertTrue(member.rw)
  60. # The new user should not have their own project
  61. self.assertFalse(member.user.project_set.exists())
  62. # And an email should have been sent
  63. subj = f"You have been invited to join Alices Project on {settings.SITE_NAME}"
  64. self.assertHTMLEqual(mail.outbox[0].subject, subj)
  65. def test_it_adds_readonly_team_member(self):
  66. self.client.login(username="[email protected]", password="password")
  67. form = {"invite_team_member": "1", "email": "[email protected]"}
  68. r = self.client.post(self.url, form)
  69. self.assertEqual(r.status_code, 200)
  70. member = Member.objects.get(
  71. project=self.project, user__email="[email protected]"
  72. )
  73. # The new user should not have their own project
  74. self.assertFalse(member.rw)
  75. def test_it_adds_member_from_another_team(self):
  76. # With team limit at zero, we should not be able to invite any new users
  77. self.profile.team_limit = 0
  78. self.profile.save()
  79. # But Charlie will have an existing membership in another Alice's project
  80. # so Alice *should* be able to invite Charlie:
  81. p2 = Project.objects.create(owner=self.alice)
  82. Member.objects.create(user=self.charlie, project=p2)
  83. self.client.login(username="[email protected]", password="password")
  84. form = {"invite_team_member": "1", "email": "[email protected]"}
  85. r = self.client.post(self.url, form)
  86. self.assertEqual(r.status_code, 200)
  87. q = Member.objects.filter(project=self.project, user=self.charlie)
  88. self.assertEqual(q.count(), 1)
  89. # And this should not have affected the rate limit:
  90. q = TokenBucket.objects.filter(value="invite-%d" % self.alice.id)
  91. self.assertFalse(q.exists())
  92. def test_it_rejects_duplicate_membership(self):
  93. self.client.login(username="[email protected]", password="password")
  94. form = {"invite_team_member": "1", "email": "[email protected]"}
  95. r = self.client.post(self.url, form)
  96. self.assertContains(r, "[email protected] is already a member")
  97. # The number of memberships should have not increased
  98. self.assertEqual(self.project.member_set.count(), 1)
  99. def test_it_rejects_owner_as_a_member(self):
  100. self.client.login(username="[email protected]", password="password")
  101. form = {"invite_team_member": "1", "email": "[email protected]"}
  102. r = self.client.post(self.url, form)
  103. self.assertContains(r, "[email protected] is already a member")
  104. # The number of memberships should have not increased
  105. self.assertEqual(self.project.member_set.count(), 1)
  106. def test_it_rejects_too_long_email_addresses(self):
  107. self.client.login(username="[email protected]", password="password")
  108. aaa = "a" * 300
  109. form = {"invite_team_member": "1", "email": f"frank+{aaa}@example.org"}
  110. r = self.client.post(self.url, form)
  111. self.assertEqual(r.status_code, 200)
  112. # No email should have been sent
  113. self.assertEqual(len(mail.outbox), 0)
  114. @override_settings(SECRET_KEY="test-secret")
  115. def test_it_rate_limits_invites(self):
  116. obj = TokenBucket(value="invite-%d" % self.alice.id)
  117. obj.tokens = 0
  118. obj.save()
  119. self.client.login(username="[email protected]", password="password")
  120. form = {"invite_team_member": "1", "email": "[email protected]"}
  121. r = self.client.post(self.url, form)
  122. self.assertContains(r, "Too Many Requests")
  123. self.assertEqual(len(mail.outbox), 0)
  124. def test_it_requires_owner_to_add_team_member(self):
  125. self.client.login(username="[email protected]", password="password")
  126. form = {"invite_team_member": "1", "email": "[email protected]"}
  127. r = self.client.post(self.url, form)
  128. self.assertEqual(r.status_code, 403)
  129. def test_it_checks_team_size(self):
  130. self.profile.team_limit = 0
  131. self.profile.save()
  132. self.client.login(username="[email protected]", password="password")
  133. form = {"invite_team_member": "1", "email": "[email protected]"}
  134. r = self.client.post(self.url, form)
  135. self.assertEqual(r.status_code, 403)
  136. def test_it_removes_team_member(self):
  137. self.client.login(username="[email protected]", password="password")
  138. form = {"remove_team_member": "1", "email": "[email protected]"}
  139. r = self.client.post(self.url, form)
  140. self.assertEqual(r.status_code, 200)
  141. self.assertFalse(Member.objects.exists())
  142. def test_it_requires_owner_to_remove_team_member(self):
  143. self.client.login(username="[email protected]", password="password")
  144. form = {"remove_team_member": "1", "email": "[email protected]"}
  145. r = self.client.post(self.url, form)
  146. self.assertEqual(r.status_code, 403)
  147. def test_it_checks_membership_when_removing_team_member(self):
  148. self.client.login(username="[email protected]", password="password")
  149. url = "/projects/%s/settings/" % self.charlies_project.code
  150. form = {"remove_team_member": "1", "email": "[email protected]"}
  151. r = self.client.post(url, form)
  152. self.assertEqual(r.status_code, 400)
  153. def test_it_sets_project_name(self):
  154. self.client.login(username="[email protected]", password="password")
  155. form = {"set_project_name": "1", "name": "Alpha Team"}
  156. r = self.client.post(self.url, form)
  157. self.assertEqual(r.status_code, 200)
  158. self.project.refresh_from_db()
  159. self.assertEqual(self.project.name, "Alpha Team")
  160. def test_it_shows_invite_suggestions(self):
  161. p2 = Project.objects.create(owner=self.alice)
  162. self.client.login(username="[email protected]", password="password")
  163. r = self.client.get("/projects/%s/settings/" % p2.code)
  164. self.assertContains(r, "Add Users from Other Teams")
  165. self.assertContains(r, "[email protected]")
  166. def test_it_checks_rw_access_when_updating_project_name(self):
  167. self.bobs_membership.rw = False
  168. self.bobs_membership.save()
  169. self.client.login(username="[email protected]", password="password")
  170. form = {"set_project_name": "1", "name": "Alpha Team"}
  171. r = self.client.post(self.url, form)
  172. self.assertEqual(r.status_code, 403)
  173. def test_it_hides_actions_for_readonly_users(self):
  174. self.bobs_membership.rw = False
  175. self.bobs_membership.save()
  176. self.client.login(username="[email protected]", password="password")
  177. r = self.client.get(self.url)
  178. self.assertNotContains(r, "#set-project-name-modal", status_code=200)
  179. self.assertNotContains(r, "Show API Keys")
  180. @override_settings(PROMETHEUS_ENABLED=False)
  181. def test_it_hides_prometheus_link_if_prometheus_not_enabled(self):
  182. self.project.api_key_readonly = "R" * 32
  183. self.project.save()
  184. self.client.login(username="[email protected]", password="password")
  185. form = {"show_api_keys": "1"}
  186. r = self.client.post(self.url, form)
  187. self.assertEqual(r.status_code, 200)
  188. self.assertNotContains(r, "Prometheus metrics endpoint")