test_organization_events_span_metrics.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. import pytest
  2. from django.urls import reverse
  3. from sentry.testutils import MetricsEnhancedPerformanceTestCase
  4. from sentry.testutils.helpers.datetime import before_now
  5. from sentry.testutils.silo import region_silo_test
  6. pytestmark = pytest.mark.sentry_metrics
  7. @region_silo_test
  8. class OrganizationEventsMetricsEnhancedPerformanceEndpointTest(MetricsEnhancedPerformanceTestCase):
  9. viewname = "sentry-api-0-organization-events"
  10. # Poor intentionally omitted for test_measurement_rating_that_does_not_exist
  11. METRIC_STRINGS = [
  12. "foo_transaction",
  13. "bar_transaction",
  14. ]
  15. def setUp(self):
  16. super().setUp()
  17. self.min_ago = before_now(minutes=1)
  18. self.six_min_ago = before_now(minutes=6)
  19. self.features = {
  20. "organizations:starfish-view": True,
  21. }
  22. def do_request(self, query, features=None):
  23. if features is None:
  24. features = {"organizations:discover-basic": True}
  25. features.update(self.features)
  26. self.login_as(user=self.user)
  27. url = reverse(
  28. self.viewname,
  29. kwargs={"organization_slug": self.organization.slug},
  30. )
  31. with self.feature(features):
  32. return self.client.get(url, query, format="json")
  33. def test_p50_with_no_data(self):
  34. response = self.do_request(
  35. {
  36. "field": ["p50()"],
  37. "query": "",
  38. "project": self.project.id,
  39. "dataset": "spansMetrics",
  40. }
  41. )
  42. assert response.status_code == 200, response.content
  43. data = response.data["data"]
  44. meta = response.data["meta"]
  45. assert len(data) == 1
  46. assert data[0]["p50()"] == 0
  47. assert meta["dataset"] == "spansMetrics"
  48. def test_count(self):
  49. self.store_span_metric(
  50. 1,
  51. timestamp=self.min_ago,
  52. )
  53. response = self.do_request(
  54. {
  55. "field": ["count()"],
  56. "query": "",
  57. "project": self.project.id,
  58. "dataset": "spansMetrics",
  59. }
  60. )
  61. assert response.status_code == 200, response.content
  62. data = response.data["data"]
  63. meta = response.data["meta"]
  64. assert len(data) == 1
  65. assert data[0]["count()"] == 1
  66. assert meta["dataset"] == "spansMetrics"
  67. def test_count_unique(self):
  68. self.store_span_metric(
  69. 1,
  70. "user",
  71. timestamp=self.min_ago,
  72. )
  73. self.store_span_metric(
  74. 2,
  75. "user",
  76. timestamp=self.min_ago,
  77. )
  78. response = self.do_request(
  79. {
  80. "field": ["count_unique(user)"],
  81. "query": "",
  82. "project": self.project.id,
  83. "dataset": "spansMetrics",
  84. }
  85. )
  86. assert response.status_code == 200, response.content
  87. data = response.data["data"]
  88. meta = response.data["meta"]
  89. assert len(data) == 1
  90. assert data[0]["count_unique(user)"] == 2
  91. assert meta["dataset"] == "spansMetrics"
  92. def test_sum(self):
  93. self.store_span_metric(
  94. 321,
  95. timestamp=self.min_ago,
  96. )
  97. self.store_span_metric(
  98. 99,
  99. timestamp=self.min_ago,
  100. )
  101. response = self.do_request(
  102. {
  103. "field": ["sum(span.duration)"],
  104. "query": "",
  105. "project": self.project.id,
  106. "dataset": "spansMetrics",
  107. }
  108. )
  109. assert response.status_code == 200, response.content
  110. data = response.data["data"]
  111. meta = response.data["meta"]
  112. assert len(data) == 1
  113. assert data[0]["sum(span.duration)"] == 420
  114. assert meta["dataset"] == "spansMetrics"
  115. def test_percentile(self):
  116. self.store_span_metric(
  117. 1,
  118. timestamp=self.min_ago,
  119. )
  120. response = self.do_request(
  121. {
  122. "field": ["percentile(span.duration, 0.95)"],
  123. "query": "",
  124. "project": self.project.id,
  125. "dataset": "spansMetrics",
  126. }
  127. )
  128. assert response.status_code == 200, response.content
  129. data = response.data["data"]
  130. meta = response.data["meta"]
  131. assert len(data) == 1
  132. assert data[0]["percentile(span.duration, 0.95)"] == 1
  133. assert meta["dataset"] == "spansMetrics"
  134. def test_p50(self):
  135. self.store_span_metric(
  136. 1,
  137. timestamp=self.min_ago,
  138. )
  139. response = self.do_request(
  140. {
  141. "field": ["p50()"],
  142. "query": "",
  143. "project": self.project.id,
  144. "dataset": "spansMetrics",
  145. }
  146. )
  147. assert response.status_code == 200, response.content
  148. data = response.data["data"]
  149. meta = response.data["meta"]
  150. assert len(data) == 1
  151. assert data[0]["p50()"] == 1
  152. assert meta["dataset"] == "spansMetrics"
  153. def test_eps(self):
  154. for _ in range(6):
  155. self.store_span_metric(
  156. 1,
  157. timestamp=self.min_ago,
  158. )
  159. response = self.do_request(
  160. {
  161. "field": ["eps()", "sps()"],
  162. "query": "",
  163. "project": self.project.id,
  164. "dataset": "spansMetrics",
  165. "statsPeriod": "10m",
  166. }
  167. )
  168. assert response.status_code == 200, response.content
  169. data = response.data["data"]
  170. meta = response.data["meta"]
  171. assert len(data) == 1
  172. assert data[0]["eps()"] == 0.01
  173. assert data[0]["sps()"] == 0.01
  174. assert meta["dataset"] == "spansMetrics"
  175. def test_epm(self):
  176. for _ in range(6):
  177. self.store_span_metric(
  178. 1,
  179. timestamp=self.min_ago,
  180. )
  181. response = self.do_request(
  182. {
  183. "field": ["epm()", "spm()"],
  184. "query": "",
  185. "project": self.project.id,
  186. "dataset": "spansMetrics",
  187. "statsPeriod": "10m",
  188. }
  189. )
  190. assert response.status_code == 200, response.content
  191. data = response.data["data"]
  192. meta = response.data["meta"]
  193. assert len(data) == 1
  194. assert data[0]["epm()"] == 0.6
  195. assert data[0]["spm()"] == 0.6
  196. assert meta["dataset"] == "spansMetrics"
  197. def test_time_spent_percentage(self):
  198. for _ in range(4):
  199. self.store_span_metric(
  200. 1,
  201. tags={"transaction": "foo_transaction"},
  202. timestamp=self.min_ago,
  203. )
  204. self.store_span_metric(
  205. 1,
  206. tags={"transaction": "bar_transaction"},
  207. timestamp=self.min_ago,
  208. )
  209. response = self.do_request(
  210. {
  211. "field": ["transaction", "time_spent_percentage()"],
  212. "query": "",
  213. "orderby": ["-time_spent_percentage()"],
  214. "project": self.project.id,
  215. "dataset": "spansMetrics",
  216. "statsPeriod": "10m",
  217. }
  218. )
  219. assert response.status_code == 200, response.content
  220. data = response.data["data"]
  221. meta = response.data["meta"]
  222. assert len(data) == 2
  223. assert data[0]["time_spent_percentage()"] == 0.8
  224. assert data[0]["transaction"] == "foo_transaction"
  225. assert data[1]["time_spent_percentage()"] == 0.2
  226. assert data[1]["transaction"] == "bar_transaction"
  227. assert meta["dataset"] == "spansMetrics"
  228. def test_http_error_rate_and_count(self):
  229. for _ in range(4):
  230. self.store_span_metric(
  231. 1,
  232. tags={"span.status_code": "500"},
  233. timestamp=self.min_ago,
  234. )
  235. self.store_span_metric(
  236. 1,
  237. tags={"span.status_code": "200"},
  238. timestamp=self.min_ago,
  239. )
  240. response = self.do_request(
  241. {
  242. "field": ["http_error_count()", "http_error_rate()"],
  243. "query": "",
  244. "orderby": ["-http_error_rate()"],
  245. "project": self.project.id,
  246. "dataset": "spansMetrics",
  247. "statsPeriod": "10m",
  248. }
  249. )
  250. assert response.status_code == 200, response.content
  251. data = response.data["data"]
  252. meta = response.data["meta"]
  253. assert len(data) == 1
  254. assert data[0]["http_error_rate()"] == 0.8
  255. assert meta["dataset"] == "spansMetrics"
  256. assert meta["fields"]["http_error_count()"] == "integer"
  257. assert meta["fields"]["http_error_rate()"] == "percentage"
  258. def test_percentile_percent_change(self):
  259. self.store_span_metric(
  260. 5,
  261. timestamp=self.six_min_ago,
  262. )
  263. self.store_span_metric(
  264. 10,
  265. timestamp=self.min_ago,
  266. )
  267. response = self.do_request(
  268. {
  269. "field": ["percentile_percent_change(span.duration, 0.95)"],
  270. "query": "",
  271. "orderby": ["-percentile_percent_change(span.duration, 0.95)"],
  272. "project": self.project.id,
  273. "dataset": "spansMetrics",
  274. "statsPeriod": "10m",
  275. }
  276. )
  277. assert response.status_code == 200, response.content
  278. data = response.data["data"]
  279. meta = response.data["meta"]
  280. assert len(data) == 1
  281. assert data[0]["percentile_percent_change(span.duration, 0.95)"] == 1
  282. assert meta["dataset"] == "spansMetrics"
  283. assert meta["fields"]["percentile_percent_change(span.duration, 0.95)"] == "percent_change"
  284. def test_http_error_count_percent_change(self):
  285. for _ in range(4):
  286. self.store_span_metric(
  287. 1,
  288. tags={"span.status_code": "500"},
  289. timestamp=self.six_min_ago,
  290. )
  291. self.store_span_metric(
  292. 1,
  293. tags={"span.status_code": "500"},
  294. timestamp=self.min_ago,
  295. )
  296. response = self.do_request(
  297. {
  298. "field": ["http_error_count_percent_change()"],
  299. "query": "",
  300. "orderby": ["-http_error_count_percent_change()"],
  301. "project": self.project.id,
  302. "dataset": "spansMetrics",
  303. "statsPeriod": "10m",
  304. }
  305. )
  306. assert response.status_code == 200, response.content
  307. data = response.data["data"]
  308. meta = response.data["meta"]
  309. assert len(data) == 1
  310. assert data[0]["http_error_count_percent_change()"] == -0.75
  311. assert meta["dataset"] == "spansMetrics"
  312. assert meta["fields"]["http_error_count_percent_change()"] == "percent_change"
  313. def test_epm_percent_change(self):
  314. for _ in range(4):
  315. self.store_span_metric(
  316. 1,
  317. timestamp=self.six_min_ago,
  318. )
  319. self.store_span_metric(
  320. 1,
  321. timestamp=self.min_ago,
  322. )
  323. response = self.do_request(
  324. {
  325. "field": ["epm_percent_change()", "spm_percent_change()"],
  326. "query": "",
  327. "orderby": ["-epm_percent_change()"],
  328. "project": self.project.id,
  329. "dataset": "spansMetrics",
  330. "statsPeriod": "10m",
  331. }
  332. )
  333. assert response.status_code == 200, response.content
  334. data = response.data["data"]
  335. meta = response.data["meta"]
  336. assert len(data) == 1
  337. assert data[0]["epm_percent_change()"] == pytest.approx(-0.75)
  338. assert data[0]["spm_percent_change()"] == pytest.approx(-0.75)
  339. assert meta["dataset"] == "spansMetrics"
  340. assert meta["fields"]["epm_percent_change()"] == "percent_change"
  341. assert meta["fields"]["spm_percent_change()"] == "percent_change"
  342. def test_eps_percent_change(self):
  343. for _ in range(4):
  344. self.store_span_metric(
  345. 1,
  346. timestamp=self.min_ago,
  347. )
  348. self.store_span_metric(
  349. 1,
  350. timestamp=self.six_min_ago,
  351. )
  352. response = self.do_request(
  353. {
  354. "field": ["eps_percent_change()", "sps_percent_change()"],
  355. "query": "",
  356. "orderby": ["-eps_percent_change()"],
  357. "project": self.project.id,
  358. "dataset": "spansMetrics",
  359. "statsPeriod": "10m",
  360. }
  361. )
  362. assert response.status_code == 200, response.content
  363. data = response.data["data"]
  364. meta = response.data["meta"]
  365. assert len(data) == 1
  366. assert data[0]["eps_percent_change()"] == pytest.approx(3)
  367. assert data[0]["sps_percent_change()"] == pytest.approx(3)
  368. assert meta["dataset"] == "spansMetrics"
  369. assert meta["fields"]["eps_percent_change()"] == "percent_change"
  370. assert meta["fields"]["sps_percent_change()"] == "percent_change"