Changeset View
Changeset View
Standalone View
Standalone View
looper/tests/base.py
- This file was added.
| import datetime | |||||
| import logging | |||||
| from typing import Optional | |||||
| import django.utils | |||||
| from django.contrib.auth.models import User | |||||
| from django.test.testcases import TestCase | |||||
| from django.test.utils import override_settings | |||||
| from looper.models import Gateway, Plan, Subscription | |||||
| log = logging.getLogger(__name__) | |||||
| @override_settings( | |||||
| STATICFILES_STORAGE='django.contrib.staticfiles.storage.StaticFilesStorage', | |||||
| EMAIL_BACKEND='django.core.mail.backends.locmem.EmailBackend', | |||||
| ) | |||||
| class AbstractBaseTestCase(TestCase): | |||||
| """Applies certain overrides to settings we always need.""" | |||||
| class AbstractLooperTestCase(AbstractBaseTestCase): | |||||
| log = log.getChild('AbstractLooperTestCase') | |||||
| fixtures = ['devfund', 'testuser', 'systemuser'] | |||||
| def setUp(self) -> None: | |||||
| super().setUp() | |||||
| self.create_default_user() | |||||
| self.get_default_plan() | |||||
| def create_default_user(self) -> None: | |||||
| self.user = User.objects.get(email='harry@blender.org') | |||||
| self.user.paymentmethod_set.create(gateway=Gateway.default(), token='123') | |||||
| self.payment_method = self.user.customer.payment_method_default | |||||
| def get_default_plan(self) -> None: | |||||
| self.plan = Plan.objects.get(name='Gold') | |||||
| self.planvar = self.plan.variations.active().get( | |||||
| currency='EUR', interval_unit='month', interval_length=1 | |||||
| ) | |||||
| def create_subscription(self, **extra: object) -> Subscription: | |||||
| subscription = Subscription.objects.create( | |||||
| plan=self.plan, | |||||
| user=self.user, | |||||
| price=self.planvar.price, | |||||
| currency=self.planvar.currency, | |||||
| payment_method=self.payment_method, | |||||
| interval_unit=self.planvar.interval_unit, | |||||
| interval_length=self.planvar.interval_length, | |||||
| **extra, | |||||
| ) | |||||
| self.assertEqual('on-hold', subscription.status) | |||||
| return subscription | |||||
| def create_active_subscription(self) -> Subscription: | |||||
| subs = self.create_subscription() | |||||
| now = django.utils.timezone.now() | |||||
| subs.next_payment = now + datetime.timedelta(days=4) | |||||
| subs.save(update_fields={'next_payment'}) | |||||
| self.log.debug('Activating subscription pk=%d', subs.pk) | |||||
| order = subs.generate_order() | |||||
| order.status = 'paid' | |||||
| order.save() | |||||
| subs.refresh_from_db() | |||||
| self.assertEqual('active', subs.status) | |||||
| return subs | |||||
| def create_on_hold_subscription(self) -> Subscription: | |||||
| subs = self.create_active_subscription() | |||||
| now = django.utils.timezone.now() | |||||
| self.log.debug('Mimicking overdue payment on subscription pk=%d', subs.pk) | |||||
| subs.next_payment = now - datetime.timedelta(days=1) | |||||
| subs.status = 'on-hold' | |||||
| subs.save() | |||||
| subs.generate_order() | |||||
| subs.refresh_from_db() | |||||
| return subs | |||||
| def assertAlmostEqualDateTime( | |||||
| self, | |||||
| expect: Optional[datetime.datetime], | |||||
| actual: Optional[datetime.datetime], | |||||
| margin_seconds: float = 1.0, | |||||
| ) -> None: | |||||
| from django.utils.timezone import utc | |||||
| self.assertIsNotNone(expect) | |||||
| self.assertIsNotNone(actual) | |||||
| assert isinstance(expect, datetime.datetime) | |||||
| assert isinstance(actual, datetime.datetime) | |||||
| expect_utc = expect.astimezone(utc) | |||||
| actual_utc = actual.astimezone(utc) | |||||
| difference = expect_utc.timestamp() - actual_utc.timestamp() | |||||
| if abs(difference) < margin_seconds: | |||||
| return | |||||
| # Make sure that the difference shown is never negative. timedelta | |||||
| # objects are a bit strange in that they will always show positive | |||||
| # time: '-1 hour' is shown as '-1 day +23 hours'. | |||||
| if difference < 0: | |||||
| diff = actual_utc - expect_utc | |||||
| else: | |||||
| diff = expect_utc - actual_utc | |||||
| self.fail( | |||||
| f'Expected and actual timestamps differ {diff}:\n' | |||||
| f' Expected: {expect}\n' | |||||
| f' Actual : {actual}' | |||||
| ) | |||||