test_organization_discover_query.py 11 KB

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