tests.py 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. from unittest import skipIf
  2. from unittest.mock import patch
  3. from django.conf import settings
  4. from django.shortcuts import reverse
  5. from django.utils import timezone
  6. from djstripe.enums import BillingScheme
  7. from freezegun import freeze_time
  8. from model_bakery import baker
  9. from rest_framework.test import APITestCase
  10. from glitchtip import test_utils # pylint: disable=unused-import
  11. class SubscriptionAPITestCase(APITestCase):
  12. def setUp(self):
  13. self.user = baker.make("users.user")
  14. self.organization = baker.make("organizations_ext.Organization")
  15. self.organization.add_user(self.user)
  16. self.client.force_login(self.user)
  17. self.url = reverse("subscription-list")
  18. def test_list(self):
  19. customer = baker.make("djstripe.Customer", subscriber=self.organization)
  20. subscription = baker.make(
  21. "djstripe.Subscription", customer=customer, livemode=False
  22. )
  23. subscription2 = baker.make("djstripe.Subscription", livemode=False)
  24. subscription3 = baker.make(
  25. "djstripe.Subscription", customer=customer, livemode=True
  26. )
  27. res = self.client.get(self.url)
  28. self.assertContains(res, subscription.id)
  29. self.assertNotContains(res, subscription2.id)
  30. self.assertNotContains(res, subscription3.id)
  31. def test_detail(self):
  32. customer = baker.make("djstripe.Customer", subscriber=self.organization)
  33. subscription = baker.make(
  34. "djstripe.Subscription",
  35. customer=customer,
  36. livemode=False,
  37. created=timezone.make_aware(timezone.datetime(2020, 1, 2)),
  38. )
  39. # Should only get most recent
  40. baker.make(
  41. "djstripe.Subscription",
  42. customer=customer,
  43. livemode=False,
  44. created=timezone.make_aware(timezone.datetime(2020, 1, 1)),
  45. )
  46. baker.make("djstripe.Subscription")
  47. url = reverse("subscription-detail", args=[self.organization.slug])
  48. res = self.client.get(url)
  49. self.assertContains(res, subscription.id)
  50. def test_events_count(self):
  51. """
  52. Event count should be accurate and work when there are multiple subscriptions for a given customer
  53. """
  54. customer = baker.make("djstripe.Customer", subscriber=self.organization)
  55. baker.make(
  56. "djstripe.Subscription",
  57. customer=customer,
  58. livemode=False,
  59. current_period_start=timezone.make_aware(timezone.datetime(2020, 1, 2)),
  60. current_period_end=timezone.make_aware(timezone.datetime(2020, 2, 2)),
  61. )
  62. baker.make(
  63. "djstripe.Subscription",
  64. customer=customer,
  65. livemode=False,
  66. status="Cancelled",
  67. current_period_start=timezone.make_aware(timezone.datetime(2019, 1, 2)),
  68. current_period_end=timezone.make_aware(timezone.datetime(2019, 2, 2)),
  69. )
  70. url = (
  71. reverse("subscription-detail", args=[self.organization.slug])
  72. + "events_count/"
  73. )
  74. with freeze_time(timezone.datetime(2020, 3, 1)):
  75. baker.make("events.Event", issue__project__organization=self.organization)
  76. with freeze_time(timezone.datetime(2020, 1, 5)):
  77. baker.make("events.Event")
  78. baker.make("events.Event", issue__project__organization=self.organization)
  79. baker.make(
  80. "performance.TransactionEvent",
  81. group__project__organization=self.organization,
  82. )
  83. baker.make(
  84. "releases.ReleaseFile",
  85. file__blob__size=1000000,
  86. release__organization=self.organization,
  87. _quantity=2,
  88. )
  89. res = self.client.get(url)
  90. self.assertEqual(
  91. res.data,
  92. {
  93. "eventCount": 1,
  94. "fileSizeMB": 2,
  95. "transactionEventCount": 1,
  96. "uptimeCheckEventCount": 0,
  97. },
  98. )
  99. def test_events_count_without_customer(self):
  100. """
  101. Due to async nature of Stripe integration, a customer may not exist
  102. """
  103. baker.make("djstripe.Subscription", livemode=False)
  104. url = (
  105. reverse("subscription-detail", args=[self.organization.slug])
  106. + "events_count/"
  107. )
  108. res = self.client.get(url)
  109. self.assertEqual(sum(res.data.values()), 0)
  110. @patch("djstripe.models.Customer.subscribe")
  111. def test_create(self, djstripe_customer_subscribe_mock):
  112. customer = baker.make(
  113. "djstripe.Customer", subscriber=self.organization, livemode=False
  114. )
  115. price = baker.make(
  116. "djstripe.Price", unit_amount=0, billing_scheme=BillingScheme.per_unit
  117. )
  118. subscription = baker.make(
  119. "djstripe.Subscription",
  120. customer=customer,
  121. livemode=False,
  122. )
  123. djstripe_customer_subscribe_mock.return_value = subscription
  124. data = {"price": price.id, "organization": self.organization.id}
  125. res = self.client.post(self.url, data)
  126. self.assertEqual(res.data["price"], price.id)
  127. def test_create_invalid_org(self):
  128. """Only owners may create subscriptions"""
  129. user = baker.make("users.user") # Non owner member
  130. plan = baker.make("djstripe.Plan", amount=0)
  131. self.organization.add_user(user)
  132. self.client.force_login(user)
  133. data = {"plan": plan.id, "organization": self.organization.id}
  134. res = self.client.post(self.url, data)
  135. self.assertEqual(res.status_code, 400)
  136. class ProductAPITestCase(APITestCase):
  137. def test_product_list(self):
  138. price = baker.make(
  139. "djstripe.Price",
  140. unit_amount=0,
  141. billing_scheme=BillingScheme.per_unit,
  142. active=True,
  143. product__active=True,
  144. product__livemode=False,
  145. product__metadata={"events": 10, "is_public": "true"},
  146. )
  147. inactive_price = baker.make(
  148. "djstripe.Price",
  149. unit_amount=0,
  150. billing_scheme=BillingScheme.per_unit,
  151. active=False,
  152. product__active=False,
  153. product__livemode=False,
  154. product__metadata={"events": 10, "is_public": "true"},
  155. )
  156. hidden_price = baker.make(
  157. "djstripe.Price",
  158. unit_amount=0,
  159. billing_scheme=BillingScheme.per_unit,
  160. active=True,
  161. product__active=True,
  162. product__livemode=False,
  163. product__metadata={"events": 10, "is_public": "false"},
  164. )
  165. user = baker.make("users.user")
  166. self.client.force_login(user)
  167. res = self.client.get(reverse("product-list"))
  168. self.assertContains(res, price.id)
  169. self.assertNotContains(res, inactive_price.id)
  170. self.assertNotContains(res, hidden_price.id)
  171. # Price ID must be from a real price actually set up on Stripe Test account
  172. class StripeAPITestCase(APITestCase):
  173. @skipIf(
  174. settings.STRIPE_TEST_PUBLIC_KEY == "fake", "requires real Stripe test API key"
  175. )
  176. def test_create_checkout(self):
  177. url = reverse("create-stripe-subscription-checkout")
  178. price = baker.make(
  179. "djstripe.Price",
  180. id="price_1MZhMWJ4NuO0bv3IGMoDoFFI",
  181. )
  182. user = baker.make("users.user")
  183. organization = baker.make("organizations_ext.Organization")
  184. organization.add_user(user)
  185. self.client.force_login(user)
  186. data = {"price": price.id, "organization": organization.id}
  187. res = self.client.post(url, data)
  188. self.assertEqual(res.status_code, 200)
  189. @skipIf(
  190. settings.STRIPE_TEST_PUBLIC_KEY == "fake", "requires real Stripe test API key"
  191. )
  192. def test_manage_billing(self):
  193. url = reverse("create-billing-portal")
  194. user = baker.make("users.user")
  195. organization = baker.make("organizations_ext.Organization")
  196. organization.add_user(user)
  197. self.client.force_login(user)
  198. data = {"organization": organization.id}
  199. res = self.client.post(url, data)
  200. self.assertEqual(res.status_code, 200)
  201. class SubscriptionIntegrationAPITestCase(APITestCase):
  202. def setUp(self):
  203. self.user = baker.make("users.user")
  204. self.organization = baker.make("organizations_ext.Organization")
  205. self.organization.add_user(self.user)
  206. # Make these in this manner to avoid syncing data to stripe actual
  207. self.price = baker.make(
  208. "djstripe.Price",
  209. active=True,
  210. unit_amount=0,
  211. billing_scheme=BillingScheme.per_unit,
  212. )
  213. self.customer = baker.make(
  214. "djstripe.Customer", subscriber=self.organization, livemode=False
  215. )
  216. self.client.force_login(self.user)
  217. self.list_url = reverse("subscription-list")
  218. self.detail_url = reverse("subscription-detail", args=[self.organization.slug])
  219. @patch("djstripe.models.Customer.subscribe")
  220. def test_new_org_flow(self, djstripe_customer_subscribe_mock):
  221. """Test checking if subscription exists and when not, creating a free tier one"""
  222. res = self.client.get(self.detail_url)
  223. self.assertFalse(res.data["id"]) # No subscription, user should create one
  224. subscription = baker.make(
  225. "djstripe.Subscription",
  226. customer=self.customer,
  227. livemode=False,
  228. )
  229. djstripe_customer_subscribe_mock.return_value = subscription
  230. data = {"price": self.price.id, "organization": self.organization.id}
  231. res = self.client.post(self.list_url, data)
  232. self.assertContains(res, self.price.id, status_code=201)
  233. djstripe_customer_subscribe_mock.assert_called_once()
  234. res = self.client.get(self.detail_url)
  235. self.assertEqual(res.data["id"], subscription.id)