tests.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. from unittest import skipIf
  2. from django.conf import settings
  3. from django.test import TestCase
  4. from django.urls 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. class SubscriptionAPITestCase(TestCase):
  10. @classmethod
  11. def setUpTestData(cls):
  12. cls.user = baker.make("users.user")
  13. cls.organization = baker.make("organizations_ext.Organization")
  14. cls.organization.add_user(cls.user)
  15. cls.url = reverse("api:create_subscription")
  16. def setUp(self):
  17. self.client.force_login(self.user)
  18. def test_detail(self):
  19. customer = baker.make("djstripe.Customer", subscriber=self.organization)
  20. subscription = baker.make(
  21. "djstripe.Subscription",
  22. status="active",
  23. customer=customer,
  24. livemode=False,
  25. created=timezone.make_aware(timezone.datetime(2020, 1, 2)),
  26. )
  27. # Should get most recent
  28. baker.make(
  29. "djstripe.Subscription",
  30. status="active",
  31. customer=customer,
  32. livemode=False,
  33. created=timezone.make_aware(timezone.datetime(2020, 1, 1)),
  34. )
  35. # should not get canceled subscriptions
  36. baker.make(
  37. "djstripe.Subscription",
  38. status="canceled",
  39. customer=customer,
  40. livemode=False,
  41. created=timezone.make_aware(timezone.datetime(2020, 1, 3)),
  42. )
  43. baker.make("djstripe.Subscription")
  44. url = reverse("api:get_subscription", args=[self.organization.slug])
  45. res = self.client.get(url)
  46. self.assertContains(res, subscription.id)
  47. def test_events_count(self):
  48. """
  49. Event count should be accurate and work when there are multiple subscriptions for a given customer
  50. """
  51. customer = baker.make("djstripe.Customer", subscriber=self.organization)
  52. baker.make(
  53. "djstripe.Subscription",
  54. customer=customer,
  55. livemode=False,
  56. current_period_start=timezone.make_aware(timezone.datetime(2020, 1, 2)),
  57. current_period_end=timezone.make_aware(timezone.datetime(2020, 2, 2)),
  58. )
  59. baker.make(
  60. "djstripe.Subscription",
  61. customer=customer,
  62. livemode=False,
  63. status="Cancelled",
  64. current_period_start=timezone.make_aware(timezone.datetime(2019, 1, 2)),
  65. current_period_end=timezone.make_aware(timezone.datetime(2019, 2, 2)),
  66. )
  67. url = reverse(
  68. "api:get_subscription_events_count", args=[self.organization.slug]
  69. )
  70. with freeze_time(timezone.datetime(2020, 3, 1)):
  71. baker.make(
  72. "issue_events.IssueEvent",
  73. issue__project__organization=self.organization,
  74. )
  75. with freeze_time(timezone.datetime(2020, 1, 5)):
  76. baker.make("issue_events.IssueEvent")
  77. baker.make(
  78. "issue_events.IssueEvent",
  79. issue__project__organization=self.organization,
  80. )
  81. baker.make(
  82. "projects.IssueEventProjectHourlyStatistic",
  83. project__organization=self.organization,
  84. count=1,
  85. )
  86. baker.make(
  87. "performance.TransactionEvent",
  88. group__project__organization=self.organization,
  89. )
  90. baker.make(
  91. "projects.TransactionEventProjectHourlyStatistic",
  92. project__organization=self.organization,
  93. count=1,
  94. )
  95. baker.make(
  96. "releases.ReleaseFile",
  97. file__blob__size=1000000,
  98. release__organization=self.organization,
  99. _quantity=2,
  100. )
  101. res = self.client.get(url)
  102. self.assertEqual(
  103. res.json(),
  104. {
  105. "eventCount": 1,
  106. "fileSizeMB": 2,
  107. "transactionEventCount": 1,
  108. "uptimeCheckEventCount": 0,
  109. },
  110. )
  111. def test_events_count_without_customer(self):
  112. """
  113. Due to async nature of Stripe integration, a customer may not exist
  114. """
  115. baker.make("djstripe.Subscription", livemode=False)
  116. url = reverse(
  117. "api:get_subscription_events_count", args=[self.organization.slug]
  118. )
  119. res = self.client.get(url)
  120. self.assertEqual(sum(res.json().values()), 0)
  121. @skipIf(
  122. settings.STRIPE_TEST_PUBLIC_KEY == "fake", "requires real Stripe test API key"
  123. )
  124. def test_create_free(self):
  125. """
  126. Users should not be able to create a free subscription if they have another non-canceled subscription
  127. """
  128. price = baker.make(
  129. "djstripe.Price",
  130. unit_amount=0,
  131. id="price_1KO6e1J4NuO0bv3IEXhpWpzt",
  132. billing_scheme=BillingScheme.per_unit,
  133. )
  134. baker.make("djstripe.Product", id="prod_L4F8CtH20Oad6S", default_price=price)
  135. data = {"price": price.id, "organization": self.organization.id}
  136. res = self.client.post(self.url, data, content_type="application/json")
  137. self.assertEqual(res.json()["price"], price.id)
  138. # Second attempt should fail
  139. res = self.client.post(self.url, data)
  140. self.assertEqual(res.status_code, 400)
  141. def test_create_invalid_org(self):
  142. """Only owners may create subscriptions"""
  143. user = baker.make("users.user") # Non owner member
  144. plan = baker.make("djstripe.Plan", amount=0)
  145. self.organization.add_user(user)
  146. self.client.force_login(user)
  147. data = {"plan": plan.id, "organization": self.organization.id}
  148. res = self.client.post(self.url, data)
  149. self.assertEqual(res.status_code, 400)
  150. class ProductAPITestCase(TestCase):
  151. def test_product_list(self):
  152. price = baker.make(
  153. "djstripe.Price",
  154. unit_amount=0,
  155. billing_scheme=BillingScheme.per_unit,
  156. active=True,
  157. product__active=True,
  158. product__livemode=False,
  159. product__metadata={"events": 10, "is_public": "true"},
  160. )
  161. inactive_price = baker.make(
  162. "djstripe.Price",
  163. unit_amount=0,
  164. billing_scheme=BillingScheme.per_unit,
  165. active=False,
  166. product__active=False,
  167. product__livemode=False,
  168. product__metadata={"events": 10, "is_public": "true"},
  169. )
  170. hidden_price = baker.make(
  171. "djstripe.Price",
  172. unit_amount=0,
  173. billing_scheme=BillingScheme.per_unit,
  174. active=True,
  175. product__active=True,
  176. product__livemode=False,
  177. product__metadata={"events": 10, "is_public": "false"},
  178. )
  179. user = baker.make("users.user")
  180. self.client.force_login(user)
  181. res = self.client.get(reverse("api:list_products"))
  182. self.assertContains(res, price.id)
  183. self.assertNotContains(res, inactive_price.id)
  184. self.assertNotContains(res, hidden_price.id)
  185. # Price ID must be from a real price actually set up on Stripe Test account
  186. class StripeAPITestCase(TestCase):
  187. @skipIf(
  188. settings.STRIPE_TEST_PUBLIC_KEY == "fake", "requires real Stripe test API key"
  189. )
  190. def test_create_checkout(self):
  191. price = baker.make(
  192. "djstripe.Price",
  193. id="price_1MZhMWJ4NuO0bv3IGMoDoFFI",
  194. )
  195. user = baker.make("users.user")
  196. organization = baker.make("organizations_ext.Organization")
  197. organization.add_user(user)
  198. url = reverse(
  199. "api:create_stripe_subscription_checkout", args=[organization.slug]
  200. )
  201. self.client.force_login(user)
  202. data = {"price": price.id}
  203. res = self.client.post(url, data, content_type="application/json")
  204. self.assertEqual(res.status_code, 200)
  205. @skipIf(
  206. settings.STRIPE_TEST_PUBLIC_KEY == "fake", "requires real Stripe test API key"
  207. )
  208. def test_manage_billing(self):
  209. user = baker.make("users.user")
  210. organization = baker.make("organizations_ext.Organization")
  211. url = reverse("api:stripe_billing_portal", args=[organization.slug])
  212. organization.add_user(user)
  213. self.client.force_login(user)
  214. data = {"organization": organization.id}
  215. res = self.client.post(url, data)
  216. self.assertEqual(res.status_code, 200)