test_discover_saved_query_detail.py 14 KB

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