tests.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. from collections.abc import Iterable, Mapping
  2. from typing import Optional
  3. from django.test import TestCase
  4. from django.urls import reverse
  5. from model_bakery import baker
  6. from prometheus_client import Metric
  7. from prometheus_client.parser import text_string_to_metric_families
  8. from glitchtip.test_utils import generators # noqa: F401
  9. from .metrics import clear_metrics_cache, organizations_metric, projects_metric
  10. def get_sample_value(
  11. metric_families: Iterable[Metric],
  12. metric_name: str,
  13. metric_type: str,
  14. labels: Mapping[str, str],
  15. ) -> Optional[float]:
  16. for metric_family in metric_families:
  17. if metric_family.name != metric_name or metric_family.type != metric_type:
  18. continue
  19. for metric in metric_family.samples:
  20. if metric[1] != labels:
  21. continue
  22. return metric.value
  23. return None
  24. def parse_prometheus_text(text: str) -> list[Metric]:
  25. parser = text_string_to_metric_families(text)
  26. return list(parser)
  27. class ObservabilityAPITestCase(TestCase):
  28. @classmethod
  29. def setUpTestData(cls):
  30. cls.user = baker.make("users.user", is_staff=True)
  31. cls.url = reverse("api:django_prometheus_metrics")
  32. def setUp(self):
  33. self.client.force_login(self.user)
  34. def _get_metrics(self) -> list[Metric]:
  35. resp = self.client.get(self.url)
  36. return parse_prometheus_text(resp.content.decode("utf-8"))
  37. def test_get_metrics_and_cache(self):
  38. clear_metrics_cache()
  39. with self.assertNumQueries(2):
  40. resp = self.client.get(self.url)
  41. self.assertEqual(resp.status_code, 200)
  42. with self.assertNumQueries(1):
  43. resp = self.client.get(self.url)
  44. self.assertEqual(resp.status_code, 200)
  45. def test_org_metric(self):
  46. before_orgs_metric = get_sample_value(
  47. self._get_metrics(),
  48. organizations_metric._name,
  49. organizations_metric._type,
  50. {},
  51. )
  52. # create new org; must invalidate the cache
  53. org = baker.make("organizations_ext.Organization")
  54. metrics = self._get_metrics()
  55. orgs_metric = get_sample_value(
  56. metrics, organizations_metric._name, organizations_metric._type, {}
  57. )
  58. self.assertEqual(orgs_metric, before_orgs_metric + 1)
  59. # delete org and test again
  60. org.delete()
  61. metrics = self._get_metrics()
  62. orgs_metric = get_sample_value(
  63. metrics, organizations_metric._name, organizations_metric._type, {}
  64. )
  65. self.assertEqual(orgs_metric, before_orgs_metric)
  66. def test_project_metric(self):
  67. # create new org
  68. org = baker.make("organizations_ext.Organization")
  69. # no projects yet
  70. metrics = self._get_metrics()
  71. projs_metric = get_sample_value(
  72. metrics,
  73. projects_metric._name,
  74. projects_metric._type,
  75. {"organization": org.slug},
  76. )
  77. self.assertEqual(projs_metric, 0)
  78. # create new project
  79. proj = baker.make("projects.Project", organization=org)
  80. # test
  81. metrics = self._get_metrics()
  82. projs_metric = get_sample_value(
  83. metrics,
  84. projects_metric._name,
  85. projects_metric._type,
  86. {"organization": org.slug},
  87. )
  88. self.assertEqual(projs_metric, 1)
  89. # delete project
  90. proj.force_delete()
  91. # test
  92. metrics = self._get_metrics()
  93. projs_metric = get_sample_value(
  94. metrics,
  95. projects_metric._name,
  96. projects_metric._type,
  97. {"organization": org.slug},
  98. )
  99. self.assertEqual(projs_metric, 0)