From f9b76b3071f108b29a086c14e745da2f3921d82c Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Mon, 17 Dec 2018 21:11:01 +0100 Subject: [PATCH 1/1] Add basic paypal unit tests. --- src/paypal/rest.py | 21 ++++++----- src/paypal/tests.py | 86 +++++++++++++++++++++++++++++++++++++++++++++ src/paypal/views.py | 6 ++-- 3 files changed, 99 insertions(+), 14 deletions(-) create mode 100644 src/paypal/tests.py diff --git a/src/paypal/rest.py b/src/paypal/rest.py index 3590c6f1d..8927cabbf 100644 --- a/src/paypal/rest.py +++ b/src/paypal/rest.py @@ -9,9 +9,8 @@ import pytz from django.contrib.sites.models import Site from django.core.urlresolvers import reverse from django.utils import timezone -from paypalrestsdk import BillingPlan, BillingAgreement, ResourceNotFound from django.conf import settings -from .models import BillingPlan as BillingPlanModel, BillingAgreement as BillingAgreementModel +from .models import BillingPlan, BillingAgreement paypalrestsdk.configure(settings.PAYPAL_CONFIG) @@ -25,7 +24,7 @@ def absolute_url(url_name): def create_plan(amount): - billing_plan = BillingPlan({ + billing_plan = paypalrestsdk.BillingPlan({ "name": "Cykliczna darowizna na Wolne Lektury: %s zł" % amount, "description": "Cykliczna darowizna na wsparcie Wolnych Lektur", "merchant_preferences": { @@ -55,7 +54,7 @@ def create_plan(amount): raise PaypalError(billing_plan.error) if not billing_plan.activate(): raise PaypalError(billing_plan.error) - plan, created = BillingPlanModel.objects.get_or_create(amount=amount, defaults={'plan_id': billing_plan.id}) + plan, created = BillingPlan.objects.get_or_create(amount=amount, defaults={'plan_id': billing_plan.id}) return plan.plan_id @@ -67,13 +66,13 @@ def get_link(links, rel): def create_agreement(amount, app=False): try: - plan = BillingPlanModel.objects.get(amount=amount) - except BillingPlanModel.DoesNotExist: + plan = BillingPlan.objects.get(amount=amount) + except BillingPlan.DoesNotExist: plan_id = create_plan(amount) else: plan_id = plan.plan_id start = (timezone.now() + timedelta(0, 3600*24)).astimezone(pytz.utc).strftime('%Y-%m-%dT%H:%M:%SZ') - billing_agreement = BillingAgreement({ + billing_agreement = paypalrestsdk.BillingAgreement({ "name": u"Subskrypcja klubu WL", "description": u"Stałe wsparcie Wolnych Lektur kwotą %s złotych" % amount, "start_date": start, @@ -103,8 +102,8 @@ def agreement_approval_url(amount, app=False): def get_agreement(agreement_id): try: - return BillingAgreement.find(agreement_id) - except ResourceNotFound: + return paypalrestsdk.BillingAgreement.find(agreement_id) + except paypalrestsdk.ResourceNotFound: return None @@ -115,9 +114,9 @@ def check_agreement(agreement_id): def user_is_subscribed(user): - agreements = BillingAgreementModel.objects.filter(user=user) + agreements = BillingAgreement.objects.filter(user=user) return any(agreement.check_agreement() for agreement in agreements) def execute_agreement(token): - return BillingAgreement.execute(token) + return paypalrestsdk.BillingAgreement.execute(token) diff --git a/src/paypal/tests.py b/src/paypal/tests.py new file mode 100644 index 000000000..75228422e --- /dev/null +++ b/src/paypal/tests.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- +# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later. +# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. +# +from django.contrib.auth.models import User +from mock import Mock, patch, DEFAULT +from catalogue.test_utils import WLTestCase +from .models import BillingPlan + + +BillingAgreementMock = Mock( + execute=Mock( + return_value=Mock( + plan=Mock( + payment_definitions=[ + Mock( + amount={'value': '100'} + ) + ] + ) + ) + ) +) + + +class PaypalTests(WLTestCase): + @classmethod + def setUpClass(cls): + cls.user = User(username='test') + cls.user.set_password('test') + cls.user.save() + + @classmethod + def tearDownClass(cls): + cls.user.delete() + + def test_paypal_form(self): + response = self.client.get('/paypal/form/') + self.assertEqual(response.status_code, 200) + + def test_paypal_form_unauthorized(self): + """Legacy flow: only allow payment for logged-in users.""" + response = self.client.post('/paypal/form/', {"amount": "0"}) + self.assertEqual(response.status_code, 403) + + def test_paypal_form_invalid(self): + """Paypal form: error on bad input.""" + self.client.login(username='test', password='test') + + response = self.client.post('/paypal/form/', {"amount": "0"}) + self.assertEqual(response.status_code, 200) + self.assertEqual( + len(response.context['form'].errors['amount']), + 1) + + @patch.multiple('paypalrestsdk', + BillingPlan=DEFAULT, + BillingAgreement=DEFAULT + ) + def test_paypal_form_valid(self, BillingPlan, BillingAgreement): + self.client.login(username='test', password='test') + response = self.client.post('/paypal/form/', {"amount": "100"}) + self.assertEqual(response.status_code, 302) + # Assert: BillingPlan created? BillingAgreement created? + # Models created? + + @patch.multiple('paypalrestsdk', + BillingPlan=DEFAULT, + BillingAgreement=DEFAULT, + ) + def test_paypal_form_valid(self, BillingPlan, BillingAgreement): + self.client.login(username='test', password='test') + response = self.client.post('/paypal/app-form/', {"amount": "100"}) + self.assertEqual(response.status_code, 302) + + @patch.multiple('paypalrestsdk', + BillingAgreement=BillingAgreementMock + ) + def test_paypal_return(self): + self.client.login(username='test', password='test') + BillingPlan.objects.create(amount=100) + response = self.client.get('/paypal/return/?token=secret-token') + + def test_paypal_cancel(self): + response = self.client.get('/paypal/cancel/') + self.assertEqual(response.status_code, 200) diff --git a/src/paypal/views.py b/src/paypal/views.py index 6708f2d86..15a7cf68a 100644 --- a/src/paypal/views.py +++ b/src/paypal/views.py @@ -12,7 +12,7 @@ from django.shortcuts import render from api.piston_patch import HttpResponseAppRedirect from paypal.forms import PaypalSubscriptionForm from paypal.rest import execute_agreement, check_agreement, agreement_approval_url, PaypalError -from paypal.models import BillingAgreement as BillingAgreementModel, BillingPlan +from paypal.models import BillingAgreement, BillingPlan def paypal_form(request, app=False): @@ -37,13 +37,13 @@ def paypal_return(request, app=False): token = request.GET.get('token') if not token: raise Http404 - if not BillingAgreementModel.objects.filter(token=token): + if not BillingAgreement.objects.filter(token=token): resource = execute_agreement(token) if resource.id: amount = int(Decimal(resource.plan.payment_definitions[0].amount['value'])) plan = BillingPlan.objects.get(amount=amount) active = check_agreement(resource.id) - BillingAgreementModel.objects.create( + BillingAgreement.objects.create( agreement_id=resource.id, user=request.user, plan=plan, active=active, token=token) else: resource = None -- 2.20.1