test_organization_discover_query.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. from __future__ import absolute_import
  2. from datetime import datetime, timedelta
  3. from sentry.testutils import APITestCase
  4. from django.core.urlresolvers import reverse
  5. from sentry.testutils import SnubaTestCase
  6. class OrganizationDiscoverQueryTest(APITestCase, SnubaTestCase):
  7. def setUp(self):
  8. super(OrganizationDiscoverQueryTest, self).setUp()
  9. one_second_ago = datetime.now() - timedelta(seconds=1)
  10. self.login_as(user=self.user)
  11. self.org = self.create_organization(owner=self.user, name='foo')
  12. self.project = self.create_project(
  13. name='bar',
  14. organization=self.org,
  15. )
  16. self.group = self.create_group(project=self.project, short_id=20)
  17. self.event = self.create_event(
  18. group=self.group,
  19. message="message!",
  20. platform="python",
  21. datetime=one_second_ago,
  22. tags={'environment': 'production'},
  23. data={
  24. 'exception': {
  25. 'values': [
  26. {
  27. 'type': 'ValidationError',
  28. 'value': 'Bad request',
  29. 'mechanism': {
  30. 'type': '1',
  31. 'value': '1',
  32. },
  33. 'stacktrace': {
  34. 'frames': [
  35. {
  36. 'function': '?',
  37. 'filename': 'http://localhost:1337/error.js',
  38. 'lineno': 29,
  39. 'colno': 3,
  40. 'in_app': True
  41. },
  42. ]
  43. },
  44. }
  45. ]
  46. }
  47. },
  48. )
  49. def test(self):
  50. with self.feature('organizations:discover'):
  51. url = reverse('sentry-api-0-organization-discover-query', args=[self.org.slug])
  52. response = self.client.post(url, {
  53. 'projects': [self.project.id],
  54. 'fields': ['message', 'platform'],
  55. 'start': (datetime.now() - timedelta(seconds=10)).strftime('%Y-%m-%dT%H:%M:%S'),
  56. 'end': (datetime.now()).strftime('%Y-%m-%dT%H:%M:%S'),
  57. 'orderby': '-timestamp',
  58. })
  59. assert response.status_code == 200, response.content
  60. assert len(response.data['data']) == 1
  61. assert response.data['data'][0]['message'] == 'message!'
  62. assert response.data['data'][0]['platform'] == 'python'
  63. def test_relative_dates(self):
  64. with self.feature('organizations:discover'):
  65. url = reverse('sentry-api-0-organization-discover-query', args=[self.org.slug])
  66. response = self.client.post(url, {
  67. 'projects': [self.project.id],
  68. 'fields': ['message', 'platform'],
  69. 'range': '1d',
  70. 'orderby': '-timestamp',
  71. })
  72. assert response.status_code == 200, response.content
  73. assert len(response.data['data']) == 1
  74. assert response.data['data'][0]['message'] == 'message!'
  75. assert response.data['data'][0]['platform'] == 'python'
  76. def test_invalid_date_request(self):
  77. with self.feature('organizations:discover'):
  78. url = reverse('sentry-api-0-organization-discover-query', args=[self.org.slug])
  79. response = self.client.post(url, {
  80. 'projects': [self.project.id],
  81. 'fields': ['message', 'platform'],
  82. 'range': '1d',
  83. 'start': (datetime.now() - timedelta(seconds=10)).strftime('%Y-%m-%dT%H:%M:%S'),
  84. 'end': (datetime.now()).strftime('%Y-%m-%dT%H:%M:%S'),
  85. 'orderby': '-timestamp',
  86. })
  87. assert response.status_code == 400, response.content
  88. def test_invalid_range_value(self):
  89. with self.feature('organizations:discover'):
  90. url = reverse('sentry-api-0-organization-discover-query', args=[self.org.slug])
  91. response = self.client.post(url, {
  92. 'projects': [self.project.id],
  93. 'fields': ['message', 'platform'],
  94. 'range': '1x',
  95. 'orderby': '-timestamp',
  96. })
  97. assert response.status_code == 400, response.content
  98. def test_invalid_aggregation_function(self):
  99. with self.feature('organizations:discover'):
  100. url = reverse('sentry-api-0-organization-discover-query', args=[self.org.slug])
  101. response = self.client.post(url, {
  102. 'projects': [self.project.id],
  103. 'fields': ['message', 'platform'],
  104. 'aggregations': [['test', 'test', 'test']],
  105. 'range': '14d',
  106. 'orderby': '-timestamp',
  107. })
  108. assert response.status_code == 400, response.content
  109. def test_boolean_condition(self):
  110. with self.feature('organizations:discover'):
  111. url = reverse('sentry-api-0-organization-discover-query', args=[self.org.slug])
  112. response = self.client.post(url, {
  113. 'projects': [self.project.id],
  114. 'fields': ['message', 'platform', 'stack.in_app'],
  115. 'conditions': [['stack.in_app', '=', True]],
  116. 'start': (datetime.now() - timedelta(seconds=10)).strftime('%Y-%m-%dT%H:%M:%S'),
  117. 'end': (datetime.now()).strftime('%Y-%m-%dT%H:%M:%S'),
  118. 'orderby': '-timestamp',
  119. })
  120. assert response.status_code == 200, response.content
  121. assert len(response.data['data']) == 1
  122. assert response.data['data'][0]['message'] == 'message!'
  123. assert response.data['data'][0]['platform'] == 'python'
  124. def test_array_join(self):
  125. with self.feature('organizations:discover'):
  126. url = reverse('sentry-api-0-organization-discover-query', args=[self.org.slug])
  127. response = self.client.post(url, {
  128. 'projects': [self.project.id],
  129. 'fields': ['message', 'error.type'],
  130. 'start': (datetime.now() - timedelta(seconds=10)).strftime('%Y-%m-%dT%H:%M:%S'),
  131. 'end': (datetime.now() + timedelta(seconds=10)).strftime('%Y-%m-%dT%H:%M:%S'),
  132. 'orderby': '-timestamp',
  133. })
  134. assert response.status_code == 200, response.content
  135. assert len(response.data['data']) == 1
  136. assert response.data['data'][0]['error.type'] == 'ValidationError'
  137. def test_array_condition_equals(self):
  138. with self.feature('organizations:discover'):
  139. url = reverse('sentry-api-0-organization-discover-query', args=[self.org.slug])
  140. response = self.client.post(url, {
  141. 'projects': [self.project.id],
  142. 'conditions': [['error.type', '=', 'ValidationError']],
  143. 'fields': ['message'],
  144. 'start': (datetime.now() - timedelta(seconds=10)).strftime('%Y-%m-%dT%H:%M:%S'),
  145. 'end': (datetime.now()).strftime('%Y-%m-%dT%H:%M:%S'),
  146. 'orderby': '-timestamp',
  147. })
  148. assert response.status_code == 200, response.content
  149. assert len(response.data['data']) == 1
  150. def test_array_condition_not_equals(self):
  151. with self.feature('organizations:discover'):
  152. url = reverse('sentry-api-0-organization-discover-query', args=[self.org.slug])
  153. response = self.client.post(url, {
  154. 'projects': [self.project.id],
  155. 'conditions': [['error.type', '!=', 'ValidationError']],
  156. 'fields': ['message'],
  157. 'start': (datetime.now() - timedelta(seconds=10)).strftime('%Y-%m-%dT%H:%M:%S'),
  158. 'end': (datetime.now()).strftime('%Y-%m-%dT%H:%M:%S'),
  159. 'orderby': '-timestamp',
  160. })
  161. assert response.status_code == 200, response.content
  162. assert len(response.data['data']) == 0
  163. def test_select_project_name(self):
  164. with self.feature('organizations:discover'):
  165. url = reverse('sentry-api-0-organization-discover-query', args=[self.org.slug])
  166. response = self.client.post(url, {
  167. 'projects': [self.project.id],
  168. 'fields': ['project.name'],
  169. 'range': '14d',
  170. 'orderby': '-timestamp',
  171. })
  172. assert response.status_code == 200, response.content
  173. assert len(response.data['data']) == 1
  174. assert(response.data['data'][0]['project.name']) == 'bar'
  175. def test_groupby_project_name(self):
  176. with self.feature('organizations:discover'):
  177. url = reverse('sentry-api-0-organization-discover-query', args=[self.org.slug])
  178. response = self.client.post(url, {
  179. 'projects': [self.project.id],
  180. 'aggregations': [['count()', '', 'count']],
  181. 'fields': ['project.name'],
  182. 'range': '14d',
  183. 'orderby': '-count',
  184. })
  185. assert response.status_code == 200, response.content
  186. assert len(response.data['data']) == 1
  187. assert(response.data['data'][0]['project.name']) == 'bar'
  188. assert(response.data['data'][0]['count']) == 1
  189. def test_uniq_project_name(self):
  190. with self.feature('organizations:discover'):
  191. url = reverse('sentry-api-0-organization-discover-query', args=[self.org.slug])
  192. response = self.client.post(url, {
  193. 'projects': [self.project.id],
  194. 'aggregations': [['uniq', 'project.name', 'uniq_project_name']],
  195. 'range': '14d',
  196. 'orderby': '-uniq_project_name',
  197. })
  198. assert response.status_code == 200, response.content
  199. assert len(response.data['data']) == 1
  200. assert(response.data['data'][0]['uniq_project_name']) == 1
  201. def test_select_issue_id(self):
  202. with self.feature('organizations:discover'):
  203. url = reverse('sentry-api-0-organization-discover-query', args=[self.org.slug])
  204. response = self.client.post(url, {
  205. 'projects': [self.project.id],
  206. 'fields': ['issue.id'],
  207. 'range': '14d',
  208. 'orderby': '-timestamp',
  209. })
  210. assert response.status_code == 200, response.content
  211. assert len(response.data['data']) == 1
  212. assert(response.data['data'][0]['issue.id']) == '20'
  213. def test_groupby_issue_id(self):
  214. with self.feature('organizations:discover'):
  215. url = reverse('sentry-api-0-organization-discover-query', args=[self.org.slug])
  216. response = self.client.post(url, {
  217. 'projects': [self.project.id],
  218. 'aggregations': [['count()', '', 'count']],
  219. 'fields': ['issue.id'],
  220. 'range': '14d',
  221. 'orderby': '-count',
  222. })
  223. assert response.status_code == 200, response.content
  224. assert len(response.data['data']) == 1
  225. assert(response.data['data'][0]['issue.id']) == '20'
  226. assert(response.data['data'][0]['count']) == 1
  227. def test_uniq_issue_id(self):
  228. with self.feature('organizations:discover'):
  229. url = reverse('sentry-api-0-organization-discover-query', args=[self.org.slug])
  230. response = self.client.post(url, {
  231. 'projects': [self.project.id],
  232. 'aggregations': [['uniq', 'issue.id', 'uniq_issue_id']],
  233. 'range': '14d',
  234. 'orderby': '-uniq_issue_id',
  235. })
  236. assert response.status_code == 200, response.content
  237. assert len(response.data['data']) == 1
  238. assert(response.data['data'][0]['uniq_issue_id']) == 1
  239. def test_meta_types(self):
  240. with self.feature('organizations:discover'):
  241. url = reverse('sentry-api-0-organization-discover-query', args=[self.org.slug])
  242. response = self.client.post(url, {
  243. 'projects': [self.project.id],
  244. 'fields': ['project.id', 'project.name'],
  245. 'aggregations': [['count()', '', 'count']],
  246. 'range': '14d',
  247. 'orderby': '-count',
  248. })
  249. assert response.status_code == 200, response.content
  250. assert response.data['meta'] == [
  251. {'name': 'project.id', 'type': 'integer'},
  252. {'name': 'project.name', 'type': 'string'},
  253. {'name': 'count', 'type': 'integer'}
  254. ]