diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/payment_stripe/tests | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/payment_stripe/tests')
| -rw-r--r-- | addons/payment_stripe/tests/__init__.py | 2 | ||||
| -rw-r--r-- | addons/payment_stripe/tests/stripe_mocks.py | 31 | ||||
| -rw-r--r-- | addons/payment_stripe/tests/test_stripe.py | 318 |
3 files changed, 351 insertions, 0 deletions
diff --git a/addons/payment_stripe/tests/__init__.py b/addons/payment_stripe/tests/__init__.py new file mode 100644 index 00000000..228d5775 --- /dev/null +++ b/addons/payment_stripe/tests/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import test_stripe diff --git a/addons/payment_stripe/tests/stripe_mocks.py b/addons/payment_stripe/tests/stripe_mocks.py new file mode 100644 index 00000000..6364fbf1 --- /dev/null +++ b/addons/payment_stripe/tests/stripe_mocks.py @@ -0,0 +1,31 @@ +checkout_session_signature = 't=1591264652,v1=1f0d3e035d8de956396b1d91727267fbbf483253e7702e46357b4d2bfa078ba4,v0=20d76342f4704d49f8f89db03acff7cf04afa48ca70a22d608b4649b332c1f51' +checkout_session_body = b'{\n "id": "evt_1GqFpHAlCFm536g8NYSLoccF",\n "object": "event",\n "api_version": "2019-05-16",\n "created": 1591264651,\n "data": {\n "object": {\n "id": "cs_test_SI8yz61JCZ4gxd7Z5oGfQSn9ZbubC6SZF3bJTxvy2PVqSd3dzbDV1kyd",\n "object": "checkout.session",\n "billing_address_collection": null,\n "cancel_url": "https://httpbin.org/post",\n "client_reference_id": null,\n "customer": "cus_HP3xLqXMIwBfTg",\n "customer_email": null,\n "display_items": [\n {\n "amount": 1500,\n "currency": "usd",\n "custom": {\n "description": "comfortable cotton t-shirt",\n "images": null,\n "name": "t-shirt"\n },\n "quantity": 2,\n "type": "custom"\n }\n ],\n "livemode": false,\n "locale": null,\n "metadata": {\n },\n "mode": "payment",\n "payment_intent": "pi_1GqFpCAlCFm536g8HsBSvSEt",\n "payment_method_types": [\n "card"\n ],\n "setup_intent": null,\n "shipping": null,\n "shipping_address_collection": null,\n "submit_type": null,\n "subscription": null,\n "success_url": "https://httpbin.org/post"\n }\n },\n "livemode": false,\n "pending_webhooks": 2,\n "request": {\n "id": null,\n "idempotency_key": null\n },\n "type": "checkout.session.completed"\n}' + +checkout_session_object = {'billing_address_collection': None, + 'cancel_url': 'https://httpbin.org/post', + 'client_reference_id': "tx_ref_test_handle_checkout_webhook", + 'customer': 'cus_HOgyjnjdgY6pmY', + 'customer_email': None, + 'display_items': [{'amount': 1500, + 'currency': 'usd', + 'custom': {'description': 'comfortable ' + 'cotton ' + 't-shirt', + 'images': None, + 'name': 't-shirt'}, + 'quantity': 2, + 'type': 'custom'}], + 'id': 'cs_test_sbTG0yGwTszAqFUP8Ulecr1bUwEyQEo29M8taYvdP7UA6Qr37qX6uA6w', + 'livemode': False, + 'locale': None, + 'metadata': {}, + 'mode': 'payment', + 'object': 'checkout.session', + 'payment_intent': 'pi_1GptaRAlCFm536g8AfCF6Zi0', + 'payment_method_types': ['card'], + 'setup_intent': None, + 'shipping': None, + 'shipping_address_collection': None, + 'submit_type': None, + 'subscription': None, + 'success_url': 'https://httpbin.org/post'} diff --git a/addons/payment_stripe/tests/test_stripe.py b/addons/payment_stripe/tests/test_stripe.py new file mode 100644 index 00000000..2ac28193 --- /dev/null +++ b/addons/payment_stripe/tests/test_stripe.py @@ -0,0 +1,318 @@ +# -*- coding: utf-8 -*- +import odoo +from odoo import fields +from odoo.exceptions import ValidationError +from odoo.addons.payment.tests.common import PaymentAcquirerCommon +from unittest.mock import patch +from . import stripe_mocks +from ..models.payment import STRIPE_SIGNATURE_AGE_TOLERANCE +from odoo.tools import mute_logger + + +class StripeCommon(PaymentAcquirerCommon): + + @classmethod + def setUpClass(cls, chart_template_ref=None): + super().setUpClass(chart_template_ref=chart_template_ref) + cls.stripe = cls.env.ref('payment.payment_acquirer_stripe') + cls.stripe.write({ + 'stripe_secret_key': 'sk_test_KJtHgNwt2KS3xM7QJPr4O5E8', + 'stripe_publishable_key': 'pk_test_QSPnimmb4ZhtkEy3Uhdm4S6J', + 'stripe_webhook_secret': 'whsec_vG1fL6CMUouQ7cObF2VJprLVXT5jBLxB', + 'state': 'test', + }) + cls.token = cls.env['payment.token'].create({ + 'name': 'Test Card', + 'acquirer_id': cls.stripe.id, + 'acquirer_ref': 'cus_G27S7FqQ2w3fuH', + 'stripe_payment_method': 'pm_1FW3DdAlCFm536g8eQoSCejY', + 'partner_id': cls.buyer.id, + 'verified': True, + }) + cls.ideal_icon = cls.env.ref("payment.payment_icon_cc_ideal") + cls.bancontact_icon = cls.env.ref("payment.payment_icon_cc_bancontact") + cls.p24_icon = cls.env.ref("payment.payment_icon_cc_p24") + cls.eps_icon = cls.env.ref("payment.payment_icon_cc_eps") + cls.giropay_icon = cls.env.ref("payment.payment_icon_cc_giropay") + cls.all_icons = [cls.ideal_icon, cls.bancontact_icon, cls.p24_icon, cls.eps_icon, cls.giropay_icon] + cls.stripe.write({'payment_icon_ids': [(5, 0, 0)]}) + + +@odoo.tests.tagged('post_install', '-at_install', '-standard', 'external') +class StripeTest(StripeCommon): + + def run(self, result=None): + with mute_logger('odoo.addons.payment.models.payment_acquirer', 'odoo.addons.payment_stripe.models.payment'): + StripeCommon.run(self, result) + + def test_10_stripe_s2s(self): + self.assertEqual(self.stripe.state, 'test', 'test without test environment') + # Create transaction + tx = self.env['payment.transaction'].create({ + 'reference': 'stripe_test_10_%s' % fields.datetime.now().strftime('%Y%m%d_%H%M%S'), + 'currency_id': self.currency_euro.id, + 'acquirer_id': self.stripe.id, + 'partner_id': self.buyer_id, + 'payment_token_id': self.token.id, + 'type': 'server2server', + 'amount': 115.0 + }) + tx.with_context(off_session=True).stripe_s2s_do_transaction() + + # Check state + self.assertEqual(tx.state, 'done', 'Stripe: Transcation has been discarded.') + + def test_20_stripe_form_render(self): + self.assertEqual(self.stripe.state, 'test', 'test without test environment') + + # ---------------------------------------- + # Test: button direct rendering + # ---------------------------------------- + + # render the button + self.stripe.render('SO404', 320.0, self.currency_euro.id, values=self.buyer_values).decode('utf-8') + + def test_30_stripe_form_management(self): + self.assertEqual(self.stripe.state, 'test', 'test without test environment') + ref = 'stripe_test_30_%s' % fields.datetime.now().strftime('%Y%m%d_%H%M%S') + tx = self.env['payment.transaction'].create({ + 'amount': 4700.0, + 'acquirer_id': self.stripe.id, + 'currency_id': self.currency_euro.id, + 'reference': ref, + 'partner_name': 'Norbert Buyer', + 'partner_country_id': self.country_france.id, + 'payment_token_id': self.token.id, + }) + res = tx.with_context(off_session=True)._stripe_create_payment_intent() + tx.stripe_payment_intent = res.get('payment_intent') + + # typical data posted by Stripe after client has successfully paid + stripe_post_data = {'reference': ref} + # validate it + tx.form_feedback(stripe_post_data, 'stripe') + self.assertEqual(tx.state, 'done', 'Stripe: validation did not put tx into done state') + self.assertEqual(tx.acquirer_reference, stripe_post_data.get('id'), 'Stripe: validation did not update tx id') + + def test_add_available_payment_method_types_local_enabled(self): + self.stripe.payment_icon_ids = [(6, 0, [i.id for i in self.all_icons])] + tx_values = { + 'billing_partner_country': self.env.ref('base.be'), + 'currency': self.env.ref('base.EUR'), + 'type': 'form' + } + stripe_session_data = {} + + self.stripe._add_available_payment_method_types(stripe_session_data, tx_values) + + actual = {pmt for key, pmt in stripe_session_data.items() if key.startswith('payment_method_types')} + self.assertEqual({'card', 'bancontact'}, actual) + + def test_add_available_payment_method_types_local_enabled_2(self): + self.stripe.payment_icon_ids = [(6, 0, [i.id for i in self.all_icons])] + tx_values = { + 'billing_partner_country': self.env.ref('base.pl'), + 'currency': self.env.ref('base.PLN'), + 'type': 'form' + } + stripe_session_data = {} + + self.stripe._add_available_payment_method_types(stripe_session_data, tx_values) + + actual = {pmt for key, pmt in stripe_session_data.items() if key.startswith('payment_method_types')} + self.assertEqual({'card', 'p24'}, actual) + + def test_add_available_payment_method_types_pmt_does_not_exist(self): + self.bancontact_icon.unlink() + tx_values = { + 'billing_partner_country': self.env.ref('base.be'), + 'currency': self.env.ref('base.EUR'), + 'type': 'form' + } + stripe_session_data = {} + + self.stripe._add_available_payment_method_types(stripe_session_data, tx_values) + + actual = {pmt for key, pmt in stripe_session_data.items() if key.startswith('payment_method_types')} + self.assertEqual({'card', 'bancontact'}, actual) + + def test_add_available_payment_method_types_local_disabled(self): + tx_values = { + 'billing_partner_country': self.env.ref('base.be'), + 'currency': self.env.ref('base.EUR'), + 'type': 'form' + } + stripe_session_data = {} + + self.stripe._add_available_payment_method_types(stripe_session_data, tx_values) + + actual = {pmt for key, pmt in stripe_session_data.items() if key.startswith('payment_method_types')} + self.assertEqual({'card'}, actual) + + def test_add_available_payment_method_types_local_all_but_bancontact(self): + self.stripe.payment_icon_ids = [(4, icon.id) for icon in self.all_icons if icon.name.lower() != 'bancontact'] + tx_values = { + 'billing_partner_country': self.env.ref('base.be'), + 'currency': self.env.ref('base.EUR'), + 'type': 'form' + } + stripe_session_data = {} + + self.stripe._add_available_payment_method_types(stripe_session_data, tx_values) + + actual = {pmt for key, pmt in stripe_session_data.items() if key.startswith('payment_method_types')} + self.assertEqual({'card'}, actual) + + def test_add_available_payment_method_types_recurrent(self): + tx_values = { + 'billing_partner_country': self.env.ref('base.be'), + 'currency': self.env.ref('base.EUR'), + 'type': 'form_save' + } + stripe_session_data = {} + + self.stripe._add_available_payment_method_types(stripe_session_data, tx_values) + + actual = {pmt for key, pmt in stripe_session_data.items() if key.startswith('payment_method_types')} + self.assertEqual({'card'}, actual) + + def test_discarded_webhook(self): + self.assertFalse(self.env['payment.acquirer']._handle_stripe_webhook(dict(type='payment.intent.succeeded'))) + + def test_handle_checkout_webhook_no_secret(self): + self.stripe.stripe_webhook_secret = None + + with self.assertRaises(ValidationError): + self.env['payment.acquirer']._handle_stripe_webhook(dict(type='checkout.session.completed')) + + @patch('odoo.addons.payment_stripe.models.payment.request') + @patch('odoo.addons.payment_stripe.models.payment.datetime') + def test_handle_checkout_webhook(self, dt, request): + # pass signature verification + dt.utcnow.return_value.timestamp.return_value = 1591264652 + request.httprequest.headers = {'Stripe-Signature': stripe_mocks.checkout_session_signature} + request.httprequest.data = stripe_mocks.checkout_session_body + # test setup + tx = self.env['payment.transaction'].create({ + 'reference': 'tx_ref_test_handle_checkout_webhook', + 'currency_id': self.currency_euro.id, + 'acquirer_id': self.stripe.id, + 'partner_id': self.buyer_id, + 'payment_token_id': self.token.id, + 'type': 'server2server', + 'amount': 30 + }) + res = tx.with_context(off_session=True)._stripe_create_payment_intent() + tx.stripe_payment_intent = res.get('payment_intent') + stripe_object = stripe_mocks.checkout_session_object + + actual = self.stripe._handle_checkout_webhook(stripe_object) + + self.assertTrue(actual) + + @patch('odoo.addons.payment_stripe.models.payment.request') + @patch('odoo.addons.payment_stripe.models.payment.datetime') + def test_handle_checkout_webhook_wrong_amount(self, dt, request): + # pass signature verification + dt.utcnow.return_value.timestamp.return_value = 1591264652 + request.httprequest.headers = {'Stripe-Signature': stripe_mocks.checkout_session_signature} + request.httprequest.data = stripe_mocks.checkout_session_body + # test setup + bad_tx = self.env['payment.transaction'].create({ + 'reference': 'tx_ref_test_handle_checkout_webhook_wrong_amount', + 'currency_id': self.currency_euro.id, + 'acquirer_id': self.stripe.id, + 'partner_id': self.buyer_id, + 'payment_token_id': self.token.id, + 'type': 'server2server', + 'amount': 10 + }) + wrong_amount_stripe_payment_intent = bad_tx.with_context(off_session=True)._stripe_create_payment_intent() + tx = self.env['payment.transaction'].create({ + 'reference': 'tx_ref_test_handle_checkout_webhook', + 'currency_id': self.currency_euro.id, + 'acquirer_id': self.stripe.id, + 'partner_id': self.buyer_id, + 'payment_token_id': self.token.id, + 'type': 'server2server', + 'amount': 30 + }) + tx.stripe_payment_intent = wrong_amount_stripe_payment_intent.get('payment_intent') + stripe_object = stripe_mocks.checkout_session_object + + actual = self.env['payment.acquirer']._handle_checkout_webhook(stripe_object) + + self.assertFalse(actual) + + def test_handle_checkout_webhook_no_odoo_tx(self): + stripe_object = stripe_mocks.checkout_session_object + + actual = self.stripe._handle_checkout_webhook(stripe_object) + + self.assertFalse(actual) + + @patch('odoo.addons.payment_stripe.models.payment.request') + @patch('odoo.addons.payment_stripe.models.payment.datetime') + def test_handle_checkout_webhook_no_stripe_tx(self, dt, request): + # pass signature verification + dt.utcnow.return_value.timestamp.return_value = 1591264652 + request.httprequest.headers = {'Stripe-Signature': stripe_mocks.checkout_session_signature} + request.httprequest.data = stripe_mocks.checkout_session_body + # test setup + self.env['payment.transaction'].create({ + 'reference': 'tx_ref_test_handle_checkout_webhook', + 'currency_id': self.currency_euro.id, + 'acquirer_id': self.stripe.id, + 'partner_id': self.buyer_id, + 'payment_token_id': self.token.id, + 'type': 'server2server', + 'amount': 30 + }) + stripe_object = stripe_mocks.checkout_session_object + + with self.assertRaises(ValidationError): + self.stripe._handle_checkout_webhook(stripe_object) + + @patch('odoo.addons.payment_stripe.models.payment.request') + @patch('odoo.addons.payment_stripe.models.payment.datetime') + def test_verify_stripe_signature(self, dt, request): + dt.utcnow.return_value.timestamp.return_value = 1591264652 + request.httprequest.headers = {'Stripe-Signature': stripe_mocks.checkout_session_signature} + request.httprequest.data = stripe_mocks.checkout_session_body + + actual = self.stripe._verify_stripe_signature() + + self.assertTrue(actual) + + @patch('odoo.addons.payment_stripe.models.payment.request') + @patch('odoo.addons.payment_stripe.models.payment.datetime') + def test_verify_stripe_signature_tampered_body(self, dt, request): + dt.utcnow.return_value.timestamp.return_value = 1591264652 + request.httprequest.headers = {'Stripe-Signature': stripe_mocks.checkout_session_signature} + request.httprequest.data = stripe_mocks.checkout_session_body.replace(b'1500', b'10') + + with self.assertRaises(ValidationError): + self.stripe._verify_stripe_signature() + + @patch('odoo.addons.payment_stripe.models.payment.request') + @patch('odoo.addons.payment_stripe.models.payment.datetime') + def test_verify_stripe_signature_wrong_secret(self, dt, request): + dt.utcnow.return_value.timestamp.return_value = 1591264652 + request.httprequest.headers = {'Stripe-Signature': stripe_mocks.checkout_session_signature} + request.httprequest.data = stripe_mocks.checkout_session_body + self.stripe.write({ + 'stripe_webhook_secret': 'whsec_vG1fL6CMUouQ7cObF2VJprL_TAMPERED', + }) + + with self.assertRaises(ValidationError): + self.stripe._verify_stripe_signature() + + @patch('odoo.addons.payment_stripe.models.payment.request') + @patch('odoo.addons.payment_stripe.models.payment.datetime') + def test_verify_stripe_signature_too_old(self, dt, request): + dt.utcnow.return_value.timestamp.return_value = 1591264652 + STRIPE_SIGNATURE_AGE_TOLERANCE + 1 + request.httprequest.headers = {'Stripe-Signature': stripe_mocks.checkout_session_signature} + request.httprequest.data = stripe_mocks.checkout_session_body + + with self.assertRaises(ValidationError): + self.stripe._verify_stripe_signature() |
