test_discover_saved_query_detail.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. import pytest
  2. from django.urls import NoReverseMatch, reverse
  3. from sentry.discover.models import DiscoverSavedQuery, DiscoverSavedQueryProject
  4. from sentry.testutils.cases import APITestCase, SnubaTestCase
  5. class DiscoverSavedQueryDetailTest(APITestCase, SnubaTestCase):
  6. feature_name = "organizations:discover"
  7. def setUp(self):
  8. super().setUp()
  9. self.login_as(user=self.user)
  10. self.org = self.create_organization(owner=self.user)
  11. self.org_without_access = self.create_organization()
  12. self.project_ids = [
  13. self.create_project(organization=self.org).id,
  14. self.create_project(organization=self.org).id,
  15. ]
  16. query = {"fields": ["test"], "conditions": [], "limit": 10}
  17. model = DiscoverSavedQuery.objects.create(
  18. organization=self.org, created_by_id=self.user.id, name="Test query", query=query
  19. )
  20. model.set_projects(self.project_ids)
  21. self.query_id = model.id
  22. invalid = DiscoverSavedQuery.objects.create(
  23. organization=self.org_without_access, name="Query without access", query=query
  24. )
  25. invalid.set_projects(self.project_ids)
  26. self.query_id_without_access = invalid.id
  27. def test_invalid_id(self):
  28. with pytest.raises(NoReverseMatch):
  29. reverse("sentry-api-0-discover-saved-query-detail", args=[self.org.slug, "not-an-id"])
  30. def test_get(self):
  31. with self.feature(self.feature_name):
  32. url = reverse(
  33. "sentry-api-0-discover-saved-query-detail", args=[self.org.slug, self.query_id]
  34. )
  35. response = self.client.get(url)
  36. assert response.status_code == 200, response.content
  37. assert response.data["id"] == str(self.query_id)
  38. assert set(response.data["projects"]) == set(self.project_ids)
  39. assert response.data["fields"] == ["test"]
  40. assert response.data["conditions"] == []
  41. assert response.data["limit"] == 10
  42. def test_get_discover_query_flag(self):
  43. with self.feature("organizations:discover-query"):
  44. url = reverse(
  45. "sentry-api-0-discover-saved-query-detail", args=[self.org.slug, self.query_id]
  46. )
  47. response = self.client.get(url)
  48. assert response.status_code == 200, response.content
  49. assert response.data["id"] == str(self.query_id)
  50. assert set(response.data["projects"]) == set(self.project_ids)
  51. assert response.data["fields"] == ["test"]
  52. assert response.data["conditions"] == []
  53. assert response.data["limit"] == 10
  54. def test_get_version(self):
  55. query = {"fields": ["event_id"], "query": "event.type:error", "limit": 10, "version": 2}
  56. model = DiscoverSavedQuery.objects.create(
  57. organization=self.org, created_by_id=self.user.id, name="v2 query", query=query
  58. )
  59. model.set_projects(self.project_ids)
  60. with self.feature(self.feature_name):
  61. url = reverse(
  62. "sentry-api-0-discover-saved-query-detail", args=[self.org.slug, model.id]
  63. )
  64. response = self.client.get(url)
  65. assert response.status_code == 200, response.content
  66. assert response.data["id"] == str(model.id)
  67. assert set(response.data["projects"]) == set(self.project_ids)
  68. assert response.data["fields"] == ["event_id"]
  69. assert response.data["query"] == "event.type:error"
  70. assert response.data["limit"] == 10
  71. assert response.data["version"] == 2
  72. def test_get_org_without_access(self):
  73. with self.feature(self.feature_name):
  74. url = reverse(
  75. "sentry-api-0-discover-saved-query-detail",
  76. args=[self.org_without_access.slug, self.query_id],
  77. )
  78. response = self.client.get(url)
  79. assert response.status_code == 403, response.content
  80. def test_get_homepage_query(self):
  81. query = {"fields": ["event_id"], "query": "event.type:error", "limit": 10, "version": 2}
  82. model = DiscoverSavedQuery.objects.create(
  83. organization=self.org,
  84. created_by_id=self.user.id,
  85. name="v2 query",
  86. query=query,
  87. is_homepage=True,
  88. )
  89. model.set_projects(self.project_ids)
  90. with self.feature(self.feature_name):
  91. url = reverse(
  92. "sentry-api-0-discover-saved-query-detail", args=[self.org.slug, model.id]
  93. )
  94. response = self.client.get(url)
  95. assert response.status_code == 404, response.content
  96. def test_put(self):
  97. with self.feature(self.feature_name):
  98. url = reverse(
  99. "sentry-api-0-discover-saved-query-detail", args=[self.org.slug, self.query_id]
  100. )
  101. response = self.client.put(
  102. url,
  103. {
  104. "name": "New query",
  105. "projects": self.project_ids,
  106. "fields": [],
  107. "range": "24h",
  108. "limit": 20,
  109. "conditions": [],
  110. "aggregations": [],
  111. "orderby": "-time",
  112. },
  113. )
  114. assert response.status_code == 200, response.content
  115. assert response.data["id"] == str(self.query_id)
  116. assert set(response.data["projects"]) == set(self.project_ids)
  117. assert response.data["fields"] == []
  118. assert response.data["conditions"] == []
  119. assert response.data["limit"] == 20
  120. def test_put_with_interval(self):
  121. with self.feature(self.feature_name):
  122. url = reverse(
  123. "sentry-api-0-discover-saved-query-detail", args=[self.org.slug, self.query_id]
  124. )
  125. response = self.client.put(
  126. url,
  127. {
  128. "name": "New query",
  129. "projects": self.project_ids,
  130. "fields": ["transaction", "count()"],
  131. "range": "24h",
  132. "interval": "10m",
  133. "version": 2,
  134. "orderby": "-count",
  135. },
  136. )
  137. assert response.status_code == 200, response.content
  138. assert response.data["fields"] == ["transaction", "count()"]
  139. assert response.data["interval"] == "10m"
  140. def test_put_query_without_access(self):
  141. with self.feature(self.feature_name):
  142. url = reverse(
  143. "sentry-api-0-discover-saved-query-detail",
  144. args=[self.org.slug, self.query_id_without_access],
  145. )
  146. response = self.client.put(
  147. url, {"name": "New query", "projects": self.project_ids, "range": "24h"}
  148. )
  149. assert response.status_code == 404
  150. def test_put_query_with_team(self):
  151. team = self.create_team(organization=self.org, members=[self.user])
  152. project = self.create_project(organization=self.org, teams=[team])
  153. query = DiscoverSavedQuery.objects.create(
  154. organization=self.org,
  155. created_by_id=self.user.id,
  156. name="Test query",
  157. query={"fields": ["test"], "conditions": [], "limit": 10},
  158. )
  159. query.set_projects([project.id])
  160. with self.feature(self.feature_name):
  161. url = reverse(
  162. "sentry-api-0-discover-saved-query-detail",
  163. args=[self.org.slug, query.id],
  164. )
  165. response = self.client.put(url, {"name": "New query", "projects": [], "range": "24h"})
  166. assert response.status_code == 200
  167. def test_put_query_without_team(self):
  168. team = self.create_team(organization=self.org, members=[])
  169. project = self.create_project(organization=self.org, teams=[team])
  170. query = DiscoverSavedQuery.objects.create(
  171. organization=self.org,
  172. created_by_id=self.user.id,
  173. name="Test query",
  174. query={"fields": ["test"], "conditions": [], "limit": 10},
  175. )
  176. query.set_projects([project.id])
  177. with self.feature(self.feature_name):
  178. url = reverse(
  179. "sentry-api-0-discover-saved-query-detail",
  180. args=[self.org.slug, query.id],
  181. )
  182. response = self.client.put(url, {"name": "New query", "projects": [], "range": "24h"})
  183. assert response.status_code == 400
  184. assert "No Projects found, join a Team" == response.data["detail"]
  185. def test_put_homepage_query(self):
  186. query = {"fields": ["event_id"], "query": "event.type:error", "limit": 10, "version": 2}
  187. model = DiscoverSavedQuery.objects.create(
  188. organization=self.org,
  189. created_by_id=self.user.id,
  190. name="v2 query",
  191. query=query,
  192. is_homepage=True,
  193. )
  194. model.set_projects(self.project_ids)
  195. with self.feature(self.feature_name):
  196. url = reverse(
  197. "sentry-api-0-discover-saved-query-detail",
  198. args=[self.org.slug, model.id],
  199. )
  200. response = self.client.put(
  201. url, {"name": "New query", "projects": [], "range": "24h", "fields": []}
  202. )
  203. assert response.status_code == 404, response.content
  204. def test_put_org_without_access(self):
  205. with self.feature(self.feature_name):
  206. url = reverse(
  207. "sentry-api-0-discover-saved-query-detail",
  208. args=[self.org_without_access.slug, self.query_id],
  209. )
  210. response = self.client.put(
  211. url, {"name": "New query", "projects": self.project_ids, "range": "24h"}
  212. )
  213. assert response.status_code == 403, response.content
  214. def test_delete(self):
  215. with self.feature(self.feature_name):
  216. url = reverse(
  217. "sentry-api-0-discover-saved-query-detail", args=[self.org.slug, self.query_id]
  218. )
  219. response = self.client.delete(url)
  220. assert response.status_code == 204
  221. assert self.client.get(url).status_code == 404
  222. def test_delete_removes_projects(self):
  223. with self.feature(self.feature_name):
  224. url = reverse(
  225. "sentry-api-0-discover-saved-query-detail", args=[self.org.slug, self.query_id]
  226. )
  227. self.client.delete(url)
  228. projects = list(
  229. DiscoverSavedQueryProject.objects.filter(discover_saved_query=self.query_id)
  230. )
  231. assert projects == []
  232. def test_delete_query_without_access(self):
  233. with self.feature(self.feature_name):
  234. url = reverse(
  235. "sentry-api-0-discover-saved-query-detail",
  236. args=[self.org.slug, self.query_id_without_access],
  237. )
  238. response = self.client.delete(url)
  239. assert response.status_code == 404
  240. def test_delete_org_without_access(self):
  241. with self.feature(self.feature_name):
  242. url = reverse(
  243. "sentry-api-0-discover-saved-query-detail",
  244. args=[self.org_without_access.slug, self.query_id],
  245. )
  246. response = self.client.delete(url)
  247. assert response.status_code == 403, response.content
  248. def test_delete_homepage_query(self):
  249. query = {"fields": ["event_id"], "query": "event.type:error", "limit": 10, "version": 2}
  250. model = DiscoverSavedQuery.objects.create(
  251. organization=self.org,
  252. created_by_id=self.user.id,
  253. name="v2 query",
  254. query=query,
  255. is_homepage=True,
  256. )
  257. model.set_projects(self.project_ids)
  258. with self.feature(self.feature_name):
  259. url = reverse(
  260. "sentry-api-0-discover-saved-query-detail",
  261. args=[self.org.slug, model.id],
  262. )
  263. response = self.client.delete(url)
  264. assert response.status_code == 404, response.content
  265. class OrganizationDiscoverQueryVisitTest(APITestCase, SnubaTestCase):
  266. def setUp(self):
  267. super().setUp()
  268. self.login_as(user=self.user)
  269. self.org = self.create_organization(owner=self.user)
  270. self.org_without_access = self.create_organization()
  271. self.project_ids = [
  272. self.create_project(organization=self.org).id,
  273. self.create_project(organization=self.org).id,
  274. ]
  275. q = {"fields": ["test"], "conditions": [], "limit": 10}
  276. self.query = DiscoverSavedQuery.objects.create(
  277. organization=self.org, created_by_id=self.user.id, name="Test query", query=q
  278. )
  279. self.query.set_projects(self.project_ids)
  280. def url(self, query_id):
  281. return reverse(
  282. "sentry-api-0-discover-saved-query-visit",
  283. kwargs={"organization_id_or_slug": self.org.slug, "query_id": query_id},
  284. )
  285. def test_visit_query(self):
  286. last_visited = self.query.last_visited
  287. assert self.query.visits == 1
  288. with self.feature("organizations:discover-query"):
  289. response = self.client.post(self.url(self.query.id))
  290. assert response.status_code == 204
  291. query = DiscoverSavedQuery.objects.get(id=self.query.id)
  292. assert query.visits == 2
  293. assert query.last_visited > last_visited
  294. def test_visit_query_no_access(self):
  295. last_visited = self.query.last_visited
  296. assert self.query.visits == 1
  297. with self.feature({"organizations:discover-query": False}):
  298. response = self.client.post(self.url(self.query.id))
  299. assert response.status_code == 404
  300. query = DiscoverSavedQuery.objects.get(id=self.query.id)
  301. assert query.visits == 1
  302. assert query.last_visited == last_visited