Repository: mdn/kuma

Issue:
T - Add system check to verify stripe config validity and reachability
As part of #6269 we discussed and implemented tests for the interaction with Stripe itself. I later removed those in favor for tests that mock the stripe wrapping helper functions, thereby allowing them to run without network. Still the point stands that we don't have any checks whether our application can successfully talk with Stripe.

Peter told me about [system checks](https://docs.djangoproject.com/en/1.11/topics/checks/), which could be an alternative to our (deleted) headless test for Stripe. One thing we could check there is whether [a stripe plan can be retrieved](https://stripe.com/docs/api/plans/retrieve). If that call succeeds we know that two of our three config keys for it are correct (`STRIPE_SECRET_KEY` and `STRIPE_PLAN_ID`).

That still leaves the interaction (and related assumptions) with Stripe itself untested, but I think it should cover our most pressing concerns.

cc @escattone @peterbe 




Discussion:
I support this plan. 
> Peter told me about [system checks](https://docs.djangoproject.com/en/1.11/topics/checks/), which could be an alternative to our (deleted) headless test

I'm sorry if I mumbled that. No, system checks are not an *alternative* to (headless) tests. It complements. System checks check the system. In particular, they would basically validate that the values you've put in for `settings.STRIPE_*` are sane. 

If we had an infinite amount of time we should have mocked unit tests, headless tests with a stage Stripe plan, system checks, and maybe even a system test(*). 

(*) A system test is when you've booted up a built docker image and before telling the load balancer to switch over to it, you do actual headless tests like checks against them. 
I didn't put that great, thanks for the correction. What I was trying to say is: for the particular things we wanted to test it could be an alternative, not a general alternative for all headless use-cases.

Resolving patch:
diff --git a/kuma/users/apps.py b/kuma/users/apps.py
--- a/kuma/users/apps.py
+++ b/kuma/users/apps.py
@@ -3,6 +3,9 @@
 from django.contrib.auth.apps import AuthConfig
 from django.utils.translation import ugettext_lazy as _
 
+# the checks self-register so we don't need to use anything from the import
+import kuma.users.checks  # noqa: F401
+
 
 class UserConfig(AuthConfig):
     """
diff --git a/kuma/users/checks.py b/kuma/users/checks.py
new file mode 100644
--- /dev/null
+++ b/kuma/users/checks.py
@@ -0,0 +1,38 @@
+import stripe
+from django.conf import settings
+from django.core.checks import Error, register
+
+
+STRIPE_PLAN_ERROR = "kuma.users.E001"
+STRIPE_PLAN_INACTIVE_ERROR = "kuma.users.E002"
+
+
+@register()
+def stripe_check(app_configs, **kwargs):
+    errors = []
+
+    # Unfortunately system checks get run with testing settings in our CI,
+    # so we need to check for the testing setting value
+    # Related issue: https://github.com/mdn/kuma/issues/6481
+    if settings.STRIPE_SECRET_KEY == "testing" or (
+        not settings.STRIPE_SECRET_KEY
+        and not settings.STRIPE_PUBLIC_KEY
+        and not settings.STRIPE_PLAN_ID
+    ):
+        return errors
+
+    try:
+        plan = stripe.Plan.retrieve(settings.STRIPE_PLAN_ID)
+        if not plan.active:
+            errors.append(
+                Error(
+                    f"{settings.STRIPE_PLAN_ID} points to an inactive Strip plan",
+                    id=STRIPE_PLAN_INACTIVE_ERROR,
+                )
+            )
+    except stripe.error.StripeError as error:
+        errors.append(
+            Error(f"unable to retrieve stripe plan: {error}", id=STRIPE_PLAN_ERROR)
+        )
+
+    return errors


Test patch:
diff --git a/kuma/settings/testing.py b/kuma/settings/testing.py
--- a/kuma/settings/testing.py
+++ b/kuma/settings/testing.py
@@ -92,9 +92,9 @@
 ENABLE_BCD_SIGNAL = True
 
 # Stripe API KEY settings
-STRIPE_PUBLIC_KEY = "wubba lubba dub duab"
-STRIPE_SECRET_KEY = "wubba lubba dub dub"
-STRIPE_PLAN_ID = "wubba lubba dub dub"
+STRIPE_PUBLIC_KEY = "testing"
+STRIPE_SECRET_KEY = "testing"
+STRIPE_PLAN_ID = "testing"
 
 # (peterbe) All existing tests will now assume this is always the case.
 # The day the *default* is to set MULTI_AUTH_ENABLED=True in settings/common.py