test_discover_saved_queries.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. from __future__ import absolute_import
  2. from sentry.testutils import APITestCase, SnubaTestCase
  3. from django.core.urlresolvers import reverse
  4. from sentry.discover.models import DiscoverSavedQuery
  5. from sentry.testutils.helpers.datetime import before_now
  6. class DiscoverSavedQueryBase(APITestCase, SnubaTestCase):
  7. def setUp(self):
  8. super(DiscoverSavedQueryBase, self).setUp()
  9. self.login_as(user=self.user)
  10. self.org = self.create_organization(owner=self.user)
  11. self.project_ids = [
  12. self.create_project(organization=self.org).id,
  13. self.create_project(organization=self.org).id,
  14. ]
  15. self.project_ids_without_access = [self.create_project().id]
  16. query = {"fields": ["test"], "conditions": [], "limit": 10}
  17. model = DiscoverSavedQuery.objects.create(
  18. organization=self.org, created_by=self.user, name="Test query", query=query, version=1
  19. )
  20. model.set_projects(self.project_ids)
  21. class DiscoverSavedQueriesTest(DiscoverSavedQueryBase):
  22. feature_name = "organizations:discover"
  23. def test_get(self):
  24. url = reverse("sentry-api-0-discover-saved-queries", args=[self.org.slug])
  25. with self.feature(self.feature_name):
  26. response = self.client.get(url)
  27. assert response.status_code == 200, response.content
  28. assert len(response.data) == 1
  29. assert response.data[0]["name"] == "Test query"
  30. assert response.data[0]["projects"] == self.project_ids
  31. assert response.data[0]["fields"] == ["test"]
  32. assert response.data[0]["conditions"] == []
  33. assert response.data[0]["limit"] == 10
  34. assert response.data[0]["version"] == 1
  35. def test_get_version_filter(self):
  36. url = reverse("sentry-api-0-discover-saved-queries", args=[self.org.slug])
  37. with self.feature(self.feature_name):
  38. response = self.client.get(url, format="json", data={"query": "version:1"})
  39. assert response.status_code == 200, response.content
  40. assert len(response.data) == 1
  41. assert response.data[0]["name"] == "Test query"
  42. with self.feature(self.feature_name):
  43. response = self.client.get(url, format="json", data={"query": "version:2"})
  44. assert response.status_code == 200, response.content
  45. assert len(response.data) == 0
  46. def test_get_name_filter(self):
  47. url = reverse("sentry-api-0-discover-saved-queries", args=[self.org.slug])
  48. with self.feature(self.feature_name):
  49. response = self.client.get(url, format="json", data={"query": "Test"})
  50. assert response.status_code == 200, response.content
  51. assert len(response.data) == 1
  52. assert response.data[0]["name"] == "Test query"
  53. with self.feature(self.feature_name):
  54. # Also available as the name: filter.
  55. response = self.client.get(url, format="json", data={"query": "name:Test"})
  56. assert response.status_code == 200, response.content
  57. assert len(response.data) == 1
  58. assert response.data[0]["name"] == "Test query"
  59. with self.feature(self.feature_name):
  60. response = self.client.get(url, format="json", data={"query": "name:Nope"})
  61. assert response.status_code == 200, response.content
  62. assert len(response.data) == 0
  63. def test_get_all_paginated(self):
  64. for i in range(0, 10):
  65. query = {"fields": ["test"], "conditions": [], "limit": 10}
  66. model = DiscoverSavedQuery.objects.create(
  67. organization=self.org,
  68. created_by=self.user,
  69. name="My query {}".format(i),
  70. query=query,
  71. version=1,
  72. )
  73. model.set_projects(self.project_ids)
  74. url = reverse("sentry-api-0-discover-saved-queries", args=[self.org.slug])
  75. with self.feature(self.feature_name):
  76. response = self.client.get(url, data={"per_page": 1})
  77. assert response.status_code == 200, response.content
  78. assert len(response.data) == 1
  79. url = reverse("sentry-api-0-discover-saved-queries", args=[self.org.slug])
  80. with self.feature(self.feature_name):
  81. # The all parameter ignores pagination and returns all values.
  82. response = self.client.get(url, data={"per_page": 1, "all": 1})
  83. assert response.status_code == 200, response.content
  84. assert len(response.data) == 11
  85. def test_get_sortby(self):
  86. query = {"fields": ["message"], "query": "", "limit": 10}
  87. model = DiscoverSavedQuery.objects.create(
  88. organization=self.org,
  89. created_by=self.user,
  90. name="My query",
  91. query=query,
  92. version=2,
  93. date_created=before_now(minutes=10),
  94. date_updated=before_now(minutes=10),
  95. )
  96. model.set_projects(self.project_ids)
  97. url = reverse("sentry-api-0-discover-saved-queries", args=[self.org.slug])
  98. sort_options = {
  99. "dateCreated": True,
  100. "-dateCreated": False,
  101. "dateUpdated": True,
  102. "-dateUpdated": False,
  103. "name": True,
  104. "-name": False,
  105. }
  106. for sorting, forward_sort in sort_options.items():
  107. with self.feature(self.feature_name):
  108. response = self.client.get(url, data={"sortBy": sorting})
  109. assert response.status_code == 200
  110. values = [row[sorting.strip("-")] for row in response.data]
  111. if not forward_sort:
  112. values = list(reversed(values))
  113. assert list(sorted(values)) == values
  114. def test_post(self):
  115. with self.feature(self.feature_name):
  116. url = reverse("sentry-api-0-discover-saved-queries", args=[self.org.slug])
  117. response = self.client.post(
  118. url,
  119. {
  120. "name": "New query",
  121. "projects": self.project_ids,
  122. "fields": [],
  123. "range": "24h",
  124. "limit": 20,
  125. "conditions": [],
  126. "aggregations": [],
  127. "orderby": "-time",
  128. },
  129. )
  130. assert response.status_code == 201, response.content
  131. assert response.data["name"] == "New query"
  132. assert response.data["projects"] == self.project_ids
  133. assert response.data["range"] == "24h"
  134. assert not hasattr(response.data, "start")
  135. assert not hasattr(response.data, "end")
  136. def test_post_invalid_projects(self):
  137. with self.feature(self.feature_name):
  138. url = reverse("sentry-api-0-discover-saved-queries", args=[self.org.slug])
  139. response = self.client.post(
  140. url,
  141. {
  142. "name": "New query",
  143. "projects": self.project_ids_without_access,
  144. "fields": [],
  145. "range": "24h",
  146. "limit": 20,
  147. "conditions": [],
  148. "aggregations": [],
  149. "orderby": "-time",
  150. },
  151. )
  152. assert response.status_code == 403, response.content
  153. def test_post_all_projects(self):
  154. with self.feature(self.feature_name):
  155. url = reverse("sentry-api-0-discover-saved-queries", args=[self.org.slug])
  156. response = self.client.post(
  157. url,
  158. {
  159. "name": "All projects",
  160. "projects": [-1],
  161. "conditions": [],
  162. "fields": ["title", "count()"],
  163. "range": "24h",
  164. "orderby": "time",
  165. },
  166. )
  167. assert response.status_code == 201, response.content
  168. assert response.data["projects"] == [-1]
  169. assert response.data["name"] == "All projects"
  170. def test_post_cannot_use_version_two_fields(self):
  171. with self.feature(self.feature_name):
  172. url = reverse("sentry-api-0-discover-saved-queries", args=[self.org.slug])
  173. response = self.client.post(
  174. url,
  175. {
  176. "name": "New query",
  177. "projects": self.project_ids,
  178. "fields": ["id"],
  179. "range": "24h",
  180. "limit": 20,
  181. "environment": ["dev"],
  182. "yAxis": "count(id)",
  183. "aggregations": [],
  184. "orderby": "-time",
  185. },
  186. )
  187. assert response.status_code == 400, response.content
  188. assert "cannot use the environment, yAxis attribute(s)" in response.content
  189. class DiscoverSavedQueriesVersion2Test(DiscoverSavedQueryBase):
  190. feature_name = "organizations:events-v2"
  191. def test_post_invalid_conditions(self):
  192. with self.feature(self.feature_name):
  193. url = reverse("sentry-api-0-discover-saved-queries", args=[self.org.slug])
  194. response = self.client.post(
  195. url,
  196. {
  197. "name": "New query",
  198. "projects": self.project_ids,
  199. "fields": ["title", "count()"],
  200. "range": "24h",
  201. "version": 2,
  202. "conditions": [["field", "=", "value"]],
  203. },
  204. )
  205. assert response.status_code == 400, response.content
  206. assert "cannot use the conditions attribute(s)" in response.content
  207. def test_post_require_selected_fields(self):
  208. with self.feature(self.feature_name):
  209. url = reverse("sentry-api-0-discover-saved-queries", args=[self.org.slug])
  210. response = self.client.post(
  211. url,
  212. {
  213. "name": "New query",
  214. "projects": self.project_ids,
  215. "fields": [],
  216. "range": "24h",
  217. "version": 2,
  218. },
  219. )
  220. assert response.status_code == 400, response.content
  221. assert "include at least one field" in response.content
  222. def test_post_success(self):
  223. with self.feature(self.feature_name):
  224. url = reverse("sentry-api-0-discover-saved-queries", args=[self.org.slug])
  225. response = self.client.post(
  226. url,
  227. {
  228. "name": "new query",
  229. "projects": self.project_ids,
  230. "fields": ["title", "count()", "project"],
  231. "environment": ["dev"],
  232. "query": "event.type:error browser.name:Firefox",
  233. "range": "24h",
  234. "tags": ["release", "environment"],
  235. "yAxis": "count(id)",
  236. "version": 2,
  237. },
  238. )
  239. assert response.status_code == 201, response.content
  240. data = response.data
  241. assert data["fields"] == ["title", "count()", "project"]
  242. assert data["range"] == "24h"
  243. assert data["environment"] == ["dev"]
  244. assert data["query"] == "event.type:error browser.name:Firefox"
  245. assert data["tags"] == ["release", "environment"]
  246. assert data["yAxis"] == "count(id)"
  247. assert data["version"] == 2
  248. def test_post_all_projects(self):
  249. with self.feature(self.feature_name):
  250. url = reverse("sentry-api-0-discover-saved-queries", args=[self.org.slug])
  251. response = self.client.post(
  252. url,
  253. {
  254. "name": "New query",
  255. "projects": [-1],
  256. "fields": ["title", "count()"],
  257. "range": "24h",
  258. "version": 2,
  259. },
  260. )
  261. assert response.status_code == 201, response.content
  262. assert response.data["projects"] == [-1]