test_api.py 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. from django.test import TestCase
  2. from django.urls import reverse
  3. from django.utils import timezone
  4. from model_bakery import baker
  5. from apps.organizations_ext.constants import OrganizationUserRole
  6. from ..models import Project, ProjectKey
  7. class ProjectsAPITestCase(TestCase):
  8. @classmethod
  9. def setUpTestData(cls):
  10. cls.user = baker.make("users.user")
  11. cls.organization = baker.make("organizations_ext.Organization")
  12. cls.org_user = cls.organization.add_user(
  13. cls.user, role=OrganizationUserRole.OWNER
  14. )
  15. cls.project = baker.make(
  16. "projects.Project",
  17. organization=cls.organization,
  18. name="Alpha",
  19. first_event=timezone.now(),
  20. )
  21. cls.team = baker.make(
  22. "teams.Team",
  23. organization=cls.organization,
  24. members=[cls.org_user],
  25. projects=[cls.project],
  26. )
  27. cls.url = reverse("api:list_projects")
  28. cls.detail_url = reverse(
  29. "api:get_project", args=[cls.organization.slug, cls.project.slug]
  30. )
  31. cls.update_url = reverse(
  32. "api:update_project", args=[cls.organization.slug, cls.project.slug]
  33. )
  34. def setUp(self):
  35. self.client.force_login(self.user)
  36. def test_projects_api_list(self):
  37. # Ensure project annotate_is_member works with two teams on one project
  38. baker.make(
  39. "teams.Team",
  40. organization=self.organization,
  41. members=[self.org_user],
  42. projects=[self.project],
  43. )
  44. res = self.client.get(self.url)
  45. self.assertContains(res, self.organization.name)
  46. data = res.json()[0]
  47. self.assertIsInstance(data["id"], str)
  48. self.assertEqual(data["name"], self.project.name)
  49. self.assertTrue(data["isMember"])
  50. data_keys = res.json()[0].keys()
  51. self.assertNotIn("keys", data_keys, "Project keys shouldn't be in list")
  52. self.assertNotIn("teams", data_keys, "Teams shouldn't be in list")
  53. def test_default_ordering(self):
  54. projectA = self.project
  55. projectZ = baker.make(
  56. "projects.Project", organization=self.organization, name="Z Proj"
  57. )
  58. baker.make("projects.Project", organization=self.organization, name="B Proj")
  59. res = self.client.get(self.url)
  60. data = res.json()
  61. self.assertEqual(data[0]["name"], projectA.name)
  62. self.assertEqual(data[2]["name"], projectZ.name)
  63. def test_projects_api_retrieve(self):
  64. res = self.client.get(self.detail_url)
  65. self.assertTrue(res.json()["firstEvent"])
  66. def test_projects_api_update(self):
  67. self.assertEqual(self.project.event_throttle_rate, 0)
  68. self.assertEqual(self.project.platform, None)
  69. res = self.client.put(
  70. self.update_url,
  71. {
  72. "name": "New Name",
  73. "eventThrottleRate": 50,
  74. "platform": "python",
  75. },
  76. content_type="application/json",
  77. )
  78. self.assertEqual(res.status_code, 200)
  79. self.project.refresh_from_db()
  80. self.assertEqual(self.project.name, "New Name")
  81. self.assertEqual(self.project.event_throttle_rate, 50)
  82. self.assertEqual(self.project.platform, "python")
  83. def test_projects_pagination(self):
  84. """
  85. Test link header pagination
  86. """
  87. page_size = 50
  88. firstProject = self.project
  89. baker.make(
  90. "projects.Project",
  91. organization=self.organization,
  92. name="B",
  93. _quantity=page_size,
  94. )
  95. lastProject = baker.make(
  96. "projects.Project",
  97. organization=self.organization,
  98. name="Last Alphabetically",
  99. )
  100. res = self.client.get(self.url)
  101. self.assertNotContains(res, lastProject.name)
  102. self.assertContains(res, firstProject.name)
  103. link_header = res.get("Link")
  104. self.assertIn('results="true"', link_header)
  105. def test_project_isolation(self):
  106. """Users should only access projects in their organization"""
  107. user2 = baker.make("users.user")
  108. org2 = baker.make("organizations_ext.Organization")
  109. org2.add_user(user2)
  110. project1 = self.project
  111. project2 = baker.make("projects.Project", organization=org2)
  112. res = self.client.get(self.url)
  113. self.assertContains(res, project1.name)
  114. self.assertNotContains(res, project2.name)
  115. def test_project_delete(self):
  116. team = baker.make("teams.Team", organization=self.organization)
  117. self.project.teams.add(team)
  118. res = self.client.delete(self.detail_url)
  119. self.assertEqual(res.status_code, 204)
  120. self.assertEqual(Project.objects.all().count(), 0)
  121. def test_project_invalid_delete(self):
  122. """Cannot delete projects that are not in the organization the user is an admin of"""
  123. organization = baker.make("organizations_ext.Organization")
  124. organization.add_user(self.user, OrganizationUserRole.ADMIN)
  125. project = baker.make("projects.Project")
  126. url = reverse("api:delete_project", args=[organization.slug, project.slug])
  127. res = self.client.delete(url)
  128. self.assertEqual(res.status_code, 404)
  129. class TeamProjectsAPITestCase(TestCase):
  130. def setUp(self):
  131. self.user = baker.make("users.user")
  132. self.organization = baker.make("organizations_ext.Organization")
  133. self.organization.add_user(self.user, OrganizationUserRole.ADMIN)
  134. self.team = baker.make("teams.Team", organization=self.organization)
  135. self.client.force_login(self.user)
  136. self.url = reverse(
  137. "api:list_team_projects", args=[self.organization.slug, self.team.slug]
  138. )
  139. def test_list(self):
  140. project = baker.make("projects.Project", organization=self.organization)
  141. project.teams.add(self.team)
  142. not_my_project = baker.make("projects.Project")
  143. res = self.client.get(self.url)
  144. self.assertContains(res, project.name)
  145. self.assertNotContains(res, not_my_project.name)
  146. # If a user is in multiple orgs, that user will have multiple org users.
  147. # Make sure endpoint doesn't show projects from other orgs
  148. second_org = baker.make("organizations_ext.Organization")
  149. second_org.add_user(self.user, OrganizationUserRole.ADMIN)
  150. project_in_second_org = baker.make("projects.Project", organization=second_org)
  151. res = self.client.get(self.url)
  152. self.assertNotContains(res, project_in_second_org.name)
  153. # Only show projects that are associated with the team in the URL.
  154. # If a project is on another team in the same org, it should not show
  155. project_teamless = baker.make(
  156. "projects.Project", organization=self.organization
  157. )
  158. res = self.client.get(self.url)
  159. self.assertNotContains(res, project_teamless)
  160. def test_create(self):
  161. data = {"name": "test-team"}
  162. res = self.client.post(self.url, data, content_type="application/json")
  163. res = self.assertContains(res, data["name"], status_code=201)
  164. res = self.client.get(self.url)
  165. self.assertContains(res, data["name"])
  166. self.assertEqual(ProjectKey.objects.all().count(), 1)
  167. def test_projects_api_create_unique_slug(self):
  168. name = "test project"
  169. data = {"name": name}
  170. res = self.client.post(self.url, data, content_type="application/json")
  171. first_project = Project.objects.get()
  172. res = self.client.post(self.url, data, content_type="application/json")
  173. self.assertContains(res, name, status_code=201)
  174. projects = Project.objects.all()
  175. self.assertNotEqual(projects[0].slug, projects[1].slug)
  176. self.assertEqual(ProjectKey.objects.all().count(), 2)
  177. org2 = baker.make("organizations_ext.Organization")
  178. org2_project = Project.objects.create(name=name, organization=org2)
  179. # The same slug can exist between multiple organizations
  180. self.assertEqual(first_project.slug, org2_project.slug)
  181. def test_projects_api_project_has_team(self):
  182. """
  183. The frontend UI requires you to assign a new project to a team, so make sure
  184. that the new project has a team associated with it
  185. """
  186. name = "test project"
  187. data = {"name": name}
  188. self.client.post(self.url, data, content_type="application/json")
  189. project = Project.objects.first()
  190. self.assertEqual(project.teams.all().count(), 1)
  191. def test_project_reserved_words(self):
  192. data = {"name": "new"}
  193. res = self.client.post(self.url, data, content_type="application/json")
  194. self.assertContains(res, "new-1", status_code=201)
  195. self.client.post(self.url, data)
  196. self.assertFalse(Project.objects.filter(slug="new").exists())