Repository: dj-stripe/dj-stripe

Issue:
CancelSubscriptionViewTest failing on stable/1.2
eg https://travis-ci.org/dj-stripe/dj-stripe/jobs/449553096

```AuthenticationError: No API key provided. (HINT: set your API key using "stripe.api_key = <API-KEY>"). You can generate API keys from the Stripe web interface.  See https://stripe.com/api for details, or email support@stripe.com if you have any questions.```




Discussion:
I'm not familiar with the tests, but I think that's happening because it's trying to do Subscription.api_retrieve() here: https://github.com/dj-stripe/dj-stripe/blob/stable/1.2/djstripe/models.py#L3017 

Should we also be patching Subscription.retrieve in the failing tests? 
`@patch("stripe.Subscription.retrieve", return_value=deepcopy(FAKE_SUBSCRIPTION))` 

eg 
tests.test_views.CancelSubscriptionViewTest.test_cancel_next_url
Ah, it's because of the change in behaviour in f64af57c1410fcfe03af58b1cb1aace56bb56717, test_views needs to be updated to match.

Resolving patch:
diff --git a/djstripe/models.py b/djstripe/models.py
--- a/djstripe/models.py
+++ b/djstripe/models.py
@@ -2995,7 +2995,7 @@ def extend(self, delta):
 
         return self.update(prorate=False, trial_end=period_end)
 
-    def cancel(self, at_period_end=djstripe_settings.CANCELLATION_AT_PERIOD_END):
+    def cancel(self, at_period_end=None):
         """
         Cancels this subscription. If you set the at_period_end parameter to true, the subscription will remain active
         until the end of the period, at which point it will be canceled and not renewed. By default, the subscription
@@ -3018,6 +3018,8 @@ def cancel(self, at_period_end=djstripe_settings.CANCELLATION_AT_PERIOD_END):
         .. important:: If a subscription is cancelled during a trial period, the ``at_period_end`` flag will be \
         overridden to False so that the trial ends immediately and the customer's card isn't charged.
         """
+        if at_period_end is None:
+            at_period_end = djstripe_settings.CANCELLATION_AT_PERIOD_END
 
         # If plan has trial days and customer cancels before trial period ends, then end subscription now,
         #     i.e. at_period_end=False


Test patch:
diff --git a/tests/test_views.py b/tests/test_views.py
--- a/tests/test_views.py
+++ b/tests/test_views.py
@@ -11,16 +11,23 @@
 from copy import deepcopy
 
 from django.contrib.auth import get_user, get_user_model
+from django.test import override_settings
 from django.test.testcases import TestCase
 from django.urls import reverse
 from mock import patch
 
 from djstripe.models import Customer, Plan, Subscription
+from djstripe import settings as djstripe_settings
 
 from . import (
     FAKE_CUSTOMER, FAKE_PLAN, FAKE_SUBSCRIPTION, FAKE_SUBSCRIPTION_CANCELED, FAKE_SUBSCRIPTION_CANCELED_AT_PERIOD_END
 )
 
+try:
+    reload
+except NameError:
+    from importlib import reload
+
 
 class CancelSubscriptionViewTest(TestCase):
     def setUp(self):
@@ -36,31 +43,60 @@ def setUp(self):
         stripe_customer.subscriber = self.user
         stripe_customer.save()
 
+    def tearDown(self):
+        reload(djstripe_settings)
+
+    # use DJSTRIPE_PRORATION_POLICY=True to get CANCELLATION_AT_PERIOD_END=False
+    @override_settings(DJSTRIPE_PRORATION_POLICY=True)
     @patch("stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER))
+    @patch("stripe.Subscription.retrieve", return_value=deepcopy(FAKE_SUBSCRIPTION))
     @patch("djstripe.models.Subscription._api_delete", return_value=FAKE_SUBSCRIPTION_CANCELED)
-    def test_cancel(self, cancel_subscription_mock, customer_retrieve_mock):
-        Subscription.sync_from_stripe_data(FAKE_SUBSCRIPTION)
+    def test_cancel(self, cancel_subscription_mock, subscription_retrieve_mock, customer_retrieve_mock):
+        reload(djstripe_settings)
+
+        subscription = Subscription.sync_from_stripe_data(FAKE_SUBSCRIPTION)
+
+        self.assertFalse(subscription.cancel_at_period_end)
+        self.assertEqual(subscription.status, "active")
 
         response = self.client.post(self.url)
 
-        cancel_subscription_mock.assert_called_once_with(at_period_end=True)
+        subscription.refresh_from_db()
+        self.assertFalse(subscription.cancel_at_period_end)
+        self.assertEqual(subscription.status, "canceled")
+        subscription_retrieve_mock.assert_not_called()
+        cancel_subscription_mock.assert_called_once_with()
+
         self.assertRedirects(response, reverse("home"))
         self.assertTrue(self.user.is_authenticated)
 
     @patch("stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER))
+    @patch("stripe.Subscription.retrieve", return_value=deepcopy(FAKE_SUBSCRIPTION))
     @patch("djstripe.models.Subscription._api_delete", return_value=FAKE_SUBSCRIPTION_CANCELED_AT_PERIOD_END)
-    def test_cancel_at_period_end(self, cancel_subscription_mock, customer_retrieve_mock):
-        Subscription.sync_from_stripe_data(FAKE_SUBSCRIPTION)
+    def test_cancel_at_period_end(self, cancel_subscription_mock, subscription_retrieve_mock, customer_retrieve_mock):
+        subscription = Subscription.sync_from_stripe_data(FAKE_SUBSCRIPTION)
+
+        self.assertFalse(subscription.cancel_at_period_end)
 
         response = self.client.post(self.url)
 
-        cancel_subscription_mock.assert_called_once_with(at_period_end=True)
+        subscription.refresh_from_db()
+        self.assertTrue(subscription.cancel_at_period_end)
+
+        # behaviour changed in https://github.com/dj-stripe/dj-stripe/commit/f64af57c1410fcfe03af58b1cb1aace56bb56717
+        subscription_retrieve_mock.assert_called_once()
+        cancel_subscription_mock.assert_not_called()
         self.assertRedirects(response, reverse("home"))
         self.assertTrue(self.user.is_authenticated)
 
+    # use DJSTRIPE_PRORATION_POLICY=True to get CANCELLATION_AT_PERIOD_END=False
+    @override_settings(DJSTRIPE_PRORATION_POLICY=True)
     @patch("stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER))
+    @patch("stripe.Subscription.retrieve", return_value=deepcopy(FAKE_SUBSCRIPTION))
     @patch("djstripe.models.Subscription._api_delete", return_value=FAKE_SUBSCRIPTION_CANCELED)
-    def test_cancel_next_url(self, cancel_subscription_mock, customer_retrieve_mock):
+    def test_cancel_next_url(self, cancel_subscription_mock, subscription_retrieve_mock, customer_retrieve_mock):
+        reload(djstripe_settings)
+
         Subscription.sync_from_stripe_data(FAKE_SUBSCRIPTION)
 
         response = self.client.post(self.url + "?next=/test")