You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Include a brief description of the changes in this PR. Bullet points are your friend.
Notes to Reviewer
Anything to note to the team? Any tips on how to review, or where to start?
Legal Boilerplate
Look, I get it. The entity doing business as "Sentry" was incorporated in the State of Delaware in 2015 as Functional Software, Inc. In 2022 this entity acquired Codecov and as result Sentry is going to need some rights from me in order to utilize my contributions in this PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Sentry can use, modify, copy, and redistribute my contributions, under Sentry's choice of terms.
self = <MagicMock name='send_email' id='140026230297360'>
calls = [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennife...me='andrea62', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025')]
any_order = False
def assert_has_calls(self, calls, any_order=False):
"""assert the mock has been called with the specified calls.
The `mock_calls` list is checked for the calls.
If `any_order` is False (the default) then the calls must be
sequential. There can be extra calls before or after the
specified calls.
If `any_order` is True then the calls can be in any order, but
they must all appear in `mock_calls`."""
expected = [self._call_matcher(c) for c in calls]
cause = next((e for e in expected if isinstance(e, Exception)), None)
all_calls = _CallList(self._call_matcher(c) for c in self.mock_calls)
if not any_order:
if expected not in all_calls:
if cause is None:
problem = 'Calls not found.'
else:
problem = ('Error processing expected calls.\n'
'Errors: {}').format(
[e if isinstance(e, Exception) else None
for e in expected])
> raise AssertionError(
f'{problem}\n'
f'Expected: {_CallList(calls)}'
f'{self._calls_repr(prefix=" Actual").rstrip(".")}'
) from cause
E AssertionError: Calls not found.
E Expected: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennifermendoza', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea23', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea62', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025')]
E Actual: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennifermendoza', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea23', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea62', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='spalmurray-codecov', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None)]
.../local/lib/python3.12/unittest/mock.py:986: AssertionError
During handling of the above exception, another exception occurred:
self = <billing.tests.test_views.StripeWebhookHandlerTests testMethod=test_invoice_payment_failed_sends_email_to_admins>
retrieve_paymentintent_mock = <MagicMock name='retrieve' id='140026268371520'>
mocked_send_email = <MagicMock name='send_email' id='140026230297360'>
@patch("services.task.TaskService.send_email")
@patch("services.billing.stripe.PaymentIntent.retrieve")
def test_invoice_payment_failed_sends_email_to_admins(
self,
retrieve_paymentintent_mock,
mocked_send_email,
):
non_admin = OwnerFactory(email="[email protected]")
admin_1 = OwnerFactory(email="[email protected]")
admin_2 = OwnerFactory(email="[email protected]")
self.owner.admins = [admin_1.ownerid, admin_2.ownerid]
self.owner.plan_activated_users = [non_admin.ownerid]
self.owner.email = "[email protected]"
self.owner.save()
retrieve_paymentintent_mock.return_value = MockPaymentIntent()
response = self._send_event(
payload={
"type": "invoice.payment_failed",
"data": {
"object": {
"customer": self.owner.stripe_customer_id,
"subscription": self.owner.stripe_subscription_id,
"total": 24000,
"hosted_invoice_url": "https://stripe.com",
"payment_intent": "payment_intent_asdf",
}
},
}
)
self.owner.refresh_from_db()
assert response.status_code == status.HTTP_204_NO_CONTENT
assert self.owner.delinquent is True
expected_calls = [
call(
to_addr=self.owner.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=self.owner.username,
amount=240,
card_type="visa",
last_four="1234",
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
call(
to_addr=admin_1.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=admin_1.username,
amount=240,
card_type="visa",
last_four="1234",
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
call(
to_addr=admin_2.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=admin_2.username,
amount=240,
card_type="visa",
last_four="1234",
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
]
> mocked_send_email.assert_has_calls(expected_calls)
E AssertionError: Calls not found.
E Expected: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennifermendoza', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea23', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea62', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025')]
E Actual: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennifermendoza', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea23', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea62', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='spalmurray-codecov', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None)]
E
E pytest introspection follows:
E
E Kwargs:
E assert {'amount': 24...: 'visa', ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': True,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...: 'visa', ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': True,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...: 'visa', ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': True,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...: 'visa', ...} == {}
E
E Left contains 13 more items:
E {'amount': 240.0,
E 'bank_last_four': None,
E 'bank_name': None,
E 'card_type': 'visa',
E 'cta_link': 'https://stripe.com',...
E
E ...Full output truncated (9 lines hidden), use '-vv' to show
billing/tests/test_views.py:393: AssertionError
self = <MagicMock name='send_email' id='140026210109296'>
calls = [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82...ame='christina95', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025')]
any_order = False
def assert_has_calls(self, calls, any_order=False):
"""assert the mock has been called with the specified calls.
The `mock_calls` list is checked for the calls.
If `any_order` is False (the default) then the calls must be
sequential. There can be extra calls before or after the
specified calls.
If `any_order` is True then the calls can be in any order, but
they must all appear in `mock_calls`."""
expected = [self._call_matcher(c) for c in calls]
cause = next((e for e in expected if isinstance(e, Exception)), None)
all_calls = _CallList(self._call_matcher(c) for c in self.mock_calls)
if not any_order:
if expected not in all_calls:
if cause is None:
problem = 'Calls not found.'
else:
problem = ('Error processing expected calls.\n'
'Errors: {}').format(
[e if isinstance(e, Exception) else None
for e in expected])
> raise AssertionError(
f'{problem}\n'
f'Expected: {_CallList(calls)}'
f'{self._calls_repr(prefix=" Actual").rstrip(".")}'
) from cause
E AssertionError: Calls not found.
E Expected: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christian42', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christina95', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025')]
E Actual: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christian42', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christina95', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='spalmurray-codecov', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None)]
.../local/lib/python3.12/unittest/mock.py:986: AssertionError
During handling of the above exception, another exception occurred:
self = <billing.tests.test_views.StripeWebhookHandlerTests testMethod=test_invoice_payment_failed_sends_email_to_admins_no_card>
retrieve_paymentintent_mock = <MagicMock name='retrieve' id='140026268371040'>
mocked_send_email = <MagicMock name='send_email' id='140026210109296'>
@patch("services.task.TaskService.send_email")
@patch("services.billing.stripe.PaymentIntent.retrieve")
def test_invoice_payment_failed_sends_email_to_admins_no_card(
self,
retrieve_paymentintent_mock,
mocked_send_email,
):
non_admin = OwnerFactory(email="[email protected]")
admin_1 = OwnerFactory(email="[email protected]")
admin_2 = OwnerFactory(email="[email protected]")
self.owner.admins = [admin_1.ownerid, admin_2.ownerid]
self.owner.plan_activated_users = [non_admin.ownerid]
self.owner.email = "[email protected]"
self.owner.save()
retrieve_paymentintent_mock.return_value = MockPaymentIntent(noCard=True)
response = self._send_event(
payload={
"type": "invoice.payment_failed",
"data": {
"object": {
"customer": self.owner.stripe_customer_id,
"subscription": self.owner.stripe_subscription_id,
"default_payment_method": None,
"total": 24000,
"hosted_invoice_url": "https://stripe.com",
"payment_intent": "payment_intent_asdf",
}
},
}
)
self.owner.refresh_from_db()
assert response.status_code == status.HTTP_204_NO_CONTENT
assert self.owner.delinquent is True
expected_calls = [
call(
to_addr=self.owner.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=self.owner.username,
amount=240,
card_type=None,
last_four=None,
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
call(
to_addr=admin_1.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=admin_1.username,
amount=240,
card_type=None,
last_four=None,
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
call(
to_addr=admin_2.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=admin_2.username,
amount=240,
card_type=None,
last_four=None,
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
]
> mocked_send_email.assert_has_calls(expected_calls)
E AssertionError: Calls not found.
E Expected: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christian42', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christina95', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025')]
E Actual: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christian42', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christina95', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='spalmurray-codecov', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None)]
E
E pytest introspection follows:
E
E Kwargs:
E assert {'amount': 24...e': None, ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': False,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...e': None, ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': False,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...e': None, ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': False,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...e': None, ...} == {}
E
E Left contains 13 more items:
E {'amount': 240.0,
E 'bank_last_four': None,
E 'bank_name': None,
E 'card_type': None,
E 'cta_link': 'https://stripe.com',...
E
E ...Full output truncated (9 lines hidden), use '-vv' to show
billing/tests/test_views.py:467: AssertionError
self = <MagicMock name='send_email' id='140026230297360'>
calls = [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennife...me='andrea62', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025')]
any_order = False
def assert_has_calls(self, calls, any_order=False):
"""assert the mock has been called with the specified calls.
The `mock_calls` list is checked for the calls.
If `any_order` is False (the default) then the calls must be
sequential. There can be extra calls before or after the
specified calls.
If `any_order` is True then the calls can be in any order, but
they must all appear in `mock_calls`."""
expected = [self._call_matcher(c) for c in calls]
cause = next((e for e in expected if isinstance(e, Exception)), None)
all_calls = _CallList(self._call_matcher(c) for c in self.mock_calls)
if not any_order:
if expected not in all_calls:
if cause is None:
problem = 'Calls not found.'
else:
problem = ('Error processing expected calls.\n'
'Errors: {}').format(
[e if isinstance(e, Exception) else None
for e in expected])
> raise AssertionError(
f'{problem}\n'
f'Expected: {_CallList(calls)}'
f'{self._calls_repr(prefix=" Actual").rstrip(".")}'
) from cause
E AssertionError: Calls not found.
E Expected: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennifermendoza', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea23', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea62', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025')]
E Actual: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennifermendoza', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea23', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea62', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='spalmurray-codecov', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None)]
.../local/lib/python3.12/unittest/mock.py:986: AssertionError
During handling of the above exception, another exception occurred:
self = <billing.tests.test_views.StripeWebhookHandlerTests testMethod=test_invoice_payment_failed_sends_email_to_admins>
retrieve_paymentintent_mock = <MagicMock name='retrieve' id='140026268371520'>
mocked_send_email = <MagicMock name='send_email' id='140026230297360'>
@patch("services.task.TaskService.send_email")
@patch("services.billing.stripe.PaymentIntent.retrieve")
def test_invoice_payment_failed_sends_email_to_admins(
self,
retrieve_paymentintent_mock,
mocked_send_email,
):
non_admin = OwnerFactory(email="[email protected]")
admin_1 = OwnerFactory(email="[email protected]")
admin_2 = OwnerFactory(email="[email protected]")
self.owner.admins = [admin_1.ownerid, admin_2.ownerid]
self.owner.plan_activated_users = [non_admin.ownerid]
self.owner.email = "[email protected]"
self.owner.save()
retrieve_paymentintent_mock.return_value = MockPaymentIntent()
response = self._send_event(
payload={
"type": "invoice.payment_failed",
"data": {
"object": {
"customer": self.owner.stripe_customer_id,
"subscription": self.owner.stripe_subscription_id,
"total": 24000,
"hosted_invoice_url": "https://stripe.com",
"payment_intent": "payment_intent_asdf",
}
},
}
)
self.owner.refresh_from_db()
assert response.status_code == status.HTTP_204_NO_CONTENT
assert self.owner.delinquent is True
expected_calls = [
call(
to_addr=self.owner.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=self.owner.username,
amount=240,
card_type="visa",
last_four="1234",
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
call(
to_addr=admin_1.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=admin_1.username,
amount=240,
card_type="visa",
last_four="1234",
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
call(
to_addr=admin_2.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=admin_2.username,
amount=240,
card_type="visa",
last_four="1234",
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
]
> mocked_send_email.assert_has_calls(expected_calls)
E AssertionError: Calls not found.
E Expected: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennifermendoza', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea23', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea62', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025')]
E Actual: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennifermendoza', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea23', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea62', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='spalmurray-codecov', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None)]
E
E pytest introspection follows:
E
E Kwargs:
E assert {'amount': 24...: 'visa', ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': True,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...: 'visa', ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': True,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...: 'visa', ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': True,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...: 'visa', ...} == {}
E
E Left contains 13 more items:
E {'amount': 240.0,
E 'bank_last_four': None,
E 'bank_name': None,
E 'card_type': 'visa',
E 'cta_link': 'https://stripe.com',...
E
E ...Full output truncated (9 lines hidden), use '-vv' to show
billing/tests/test_views.py:393: AssertionError
self = <MagicMock name='send_email' id='140026210109296'>
calls = [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82...ame='christina95', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025')]
any_order = False
def assert_has_calls(self, calls, any_order=False):
"""assert the mock has been called with the specified calls.
The `mock_calls` list is checked for the calls.
If `any_order` is False (the default) then the calls must be
sequential. There can be extra calls before or after the
specified calls.
If `any_order` is True then the calls can be in any order, but
they must all appear in `mock_calls`."""
expected = [self._call_matcher(c) for c in calls]
cause = next((e for e in expected if isinstance(e, Exception)), None)
all_calls = _CallList(self._call_matcher(c) for c in self.mock_calls)
if not any_order:
if expected not in all_calls:
if cause is None:
problem = 'Calls not found.'
else:
problem = ('Error processing expected calls.\n'
'Errors: {}').format(
[e if isinstance(e, Exception) else None
for e in expected])
> raise AssertionError(
f'{problem}\n'
f'Expected: {_CallList(calls)}'
f'{self._calls_repr(prefix=" Actual").rstrip(".")}'
) from cause
E AssertionError: Calls not found.
E Expected: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christian42', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christina95', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025')]
E Actual: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christian42', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christina95', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='spalmurray-codecov', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None)]
.../local/lib/python3.12/unittest/mock.py:986: AssertionError
During handling of the above exception, another exception occurred:
self = <billing.tests.test_views.StripeWebhookHandlerTests testMethod=test_invoice_payment_failed_sends_email_to_admins_no_card>
retrieve_paymentintent_mock = <MagicMock name='retrieve' id='140026268371040'>
mocked_send_email = <MagicMock name='send_email' id='140026210109296'>
@patch("services.task.TaskService.send_email")
@patch("services.billing.stripe.PaymentIntent.retrieve")
def test_invoice_payment_failed_sends_email_to_admins_no_card(
self,
retrieve_paymentintent_mock,
mocked_send_email,
):
non_admin = OwnerFactory(email="[email protected]")
admin_1 = OwnerFactory(email="[email protected]")
admin_2 = OwnerFactory(email="[email protected]")
self.owner.admins = [admin_1.ownerid, admin_2.ownerid]
self.owner.plan_activated_users = [non_admin.ownerid]
self.owner.email = "[email protected]"
self.owner.save()
retrieve_paymentintent_mock.return_value = MockPaymentIntent(noCard=True)
response = self._send_event(
payload={
"type": "invoice.payment_failed",
"data": {
"object": {
"customer": self.owner.stripe_customer_id,
"subscription": self.owner.stripe_subscription_id,
"default_payment_method": None,
"total": 24000,
"hosted_invoice_url": "https://stripe.com",
"payment_intent": "payment_intent_asdf",
}
},
}
)
self.owner.refresh_from_db()
assert response.status_code == status.HTTP_204_NO_CONTENT
assert self.owner.delinquent is True
expected_calls = [
call(
to_addr=self.owner.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=self.owner.username,
amount=240,
card_type=None,
last_four=None,
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
call(
to_addr=admin_1.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=admin_1.username,
amount=240,
card_type=None,
last_four=None,
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
call(
to_addr=admin_2.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=admin_2.username,
amount=240,
card_type=None,
last_four=None,
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
]
> mocked_send_email.assert_has_calls(expected_calls)
E AssertionError: Calls not found.
E Expected: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christian42', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christina95', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025')]
E Actual: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christian42', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christina95', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='spalmurray-codecov', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None)]
E
E pytest introspection follows:
E
E Kwargs:
E assert {'amount': 24...e': None, ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': False,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...e': None, ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': False,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...e': None, ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': False,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...e': None, ...} == {}
E
E Left contains 13 more items:
E {'amount': 240.0,
E 'bank_last_four': None,
E 'bank_name': None,
E 'card_type': None,
E 'cta_link': 'https://stripe.com',...
E
E ...Full output truncated (9 lines hidden), use '-vv' to show
billing/tests/test_views.py:467: AssertionError
self = <MagicMock name='send_email' id='140026230297360'>
calls = [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennife...me='andrea62', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025')]
any_order = False
def assert_has_calls(self, calls, any_order=False):
"""assert the mock has been called with the specified calls.
The `mock_calls` list is checked for the calls.
If `any_order` is False (the default) then the calls must be
sequential. There can be extra calls before or after the
specified calls.
If `any_order` is True then the calls can be in any order, but
they must all appear in `mock_calls`."""
expected = [self._call_matcher(c) for c in calls]
cause = next((e for e in expected if isinstance(e, Exception)), None)
all_calls = _CallList(self._call_matcher(c) for c in self.mock_calls)
if not any_order:
if expected not in all_calls:
if cause is None:
problem = 'Calls not found.'
else:
problem = ('Error processing expected calls.\n'
'Errors: {}').format(
[e if isinstance(e, Exception) else None
for e in expected])
> raise AssertionError(
f'{problem}\n'
f'Expected: {_CallList(calls)}'
f'{self._calls_repr(prefix=" Actual").rstrip(".")}'
) from cause
E AssertionError: Calls not found.
E Expected: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennifermendoza', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea23', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea62', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025')]
E Actual: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennifermendoza', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea23', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea62', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='spalmurray-codecov', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None)]
.../local/lib/python3.12/unittest/mock.py:986: AssertionError
During handling of the above exception, another exception occurred:
self = <billing.tests.test_views.StripeWebhookHandlerTests testMethod=test_invoice_payment_failed_sends_email_to_admins>
retrieve_paymentintent_mock = <MagicMock name='retrieve' id='140026268371520'>
mocked_send_email = <MagicMock name='send_email' id='140026230297360'>
@patch("services.task.TaskService.send_email")
@patch("services.billing.stripe.PaymentIntent.retrieve")
def test_invoice_payment_failed_sends_email_to_admins(
self,
retrieve_paymentintent_mock,
mocked_send_email,
):
non_admin = OwnerFactory(email="[email protected]")
admin_1 = OwnerFactory(email="[email protected]")
admin_2 = OwnerFactory(email="[email protected]")
self.owner.admins = [admin_1.ownerid, admin_2.ownerid]
self.owner.plan_activated_users = [non_admin.ownerid]
self.owner.email = "[email protected]"
self.owner.save()
retrieve_paymentintent_mock.return_value = MockPaymentIntent()
response = self._send_event(
payload={
"type": "invoice.payment_failed",
"data": {
"object": {
"customer": self.owner.stripe_customer_id,
"subscription": self.owner.stripe_subscription_id,
"total": 24000,
"hosted_invoice_url": "https://stripe.com",
"payment_intent": "payment_intent_asdf",
}
},
}
)
self.owner.refresh_from_db()
assert response.status_code == status.HTTP_204_NO_CONTENT
assert self.owner.delinquent is True
expected_calls = [
call(
to_addr=self.owner.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=self.owner.username,
amount=240,
card_type="visa",
last_four="1234",
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
call(
to_addr=admin_1.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=admin_1.username,
amount=240,
card_type="visa",
last_four="1234",
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
call(
to_addr=admin_2.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=admin_2.username,
amount=240,
card_type="visa",
last_four="1234",
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
]
> mocked_send_email.assert_has_calls(expected_calls)
E AssertionError: Calls not found.
E Expected: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennifermendoza', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea23', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea62', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025')]
E Actual: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennifermendoza', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea23', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea62', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='spalmurray-codecov', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None)]
E
E pytest introspection follows:
E
E Kwargs:
E assert {'amount': 24...: 'visa', ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': True,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...: 'visa', ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': True,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...: 'visa', ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': True,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...: 'visa', ...} == {}
E
E Left contains 13 more items:
E {'amount': 240.0,
E 'bank_last_four': None,
E 'bank_name': None,
E 'card_type': 'visa',
E 'cta_link': 'https://stripe.com',...
E
E ...Full output truncated (9 lines hidden), use '-vv' to show
billing/tests/test_views.py:393: AssertionError
self = <MagicMock name='send_email' id='140026210109296'>
calls = [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82...ame='christina95', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025')]
any_order = False
def assert_has_calls(self, calls, any_order=False):
"""assert the mock has been called with the specified calls.
The `mock_calls` list is checked for the calls.
If `any_order` is False (the default) then the calls must be
sequential. There can be extra calls before or after the
specified calls.
If `any_order` is True then the calls can be in any order, but
they must all appear in `mock_calls`."""
expected = [self._call_matcher(c) for c in calls]
cause = next((e for e in expected if isinstance(e, Exception)), None)
all_calls = _CallList(self._call_matcher(c) for c in self.mock_calls)
if not any_order:
if expected not in all_calls:
if cause is None:
problem = 'Calls not found.'
else:
problem = ('Error processing expected calls.\n'
'Errors: {}').format(
[e if isinstance(e, Exception) else None
for e in expected])
> raise AssertionError(
f'{problem}\n'
f'Expected: {_CallList(calls)}'
f'{self._calls_repr(prefix=" Actual").rstrip(".")}'
) from cause
E AssertionError: Calls not found.
E Expected: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christian42', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christina95', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025')]
E Actual: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christian42', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christina95', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='spalmurray-codecov', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None)]
.../local/lib/python3.12/unittest/mock.py:986: AssertionError
During handling of the above exception, another exception occurred:
self = <billing.tests.test_views.StripeWebhookHandlerTests testMethod=test_invoice_payment_failed_sends_email_to_admins_no_card>
retrieve_paymentintent_mock = <MagicMock name='retrieve' id='140026268371040'>
mocked_send_email = <MagicMock name='send_email' id='140026210109296'>
@patch("services.task.TaskService.send_email")
@patch("services.billing.stripe.PaymentIntent.retrieve")
def test_invoice_payment_failed_sends_email_to_admins_no_card(
self,
retrieve_paymentintent_mock,
mocked_send_email,
):
non_admin = OwnerFactory(email="[email protected]")
admin_1 = OwnerFactory(email="[email protected]")
admin_2 = OwnerFactory(email="[email protected]")
self.owner.admins = [admin_1.ownerid, admin_2.ownerid]
self.owner.plan_activated_users = [non_admin.ownerid]
self.owner.email = "[email protected]"
self.owner.save()
retrieve_paymentintent_mock.return_value = MockPaymentIntent(noCard=True)
response = self._send_event(
payload={
"type": "invoice.payment_failed",
"data": {
"object": {
"customer": self.owner.stripe_customer_id,
"subscription": self.owner.stripe_subscription_id,
"default_payment_method": None,
"total": 24000,
"hosted_invoice_url": "https://stripe.com",
"payment_intent": "payment_intent_asdf",
}
},
}
)
self.owner.refresh_from_db()
assert response.status_code == status.HTTP_204_NO_CONTENT
assert self.owner.delinquent is True
expected_calls = [
call(
to_addr=self.owner.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=self.owner.username,
amount=240,
card_type=None,
last_four=None,
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
call(
to_addr=admin_1.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=admin_1.username,
amount=240,
card_type=None,
last_four=None,
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
call(
to_addr=admin_2.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=admin_2.username,
amount=240,
card_type=None,
last_four=None,
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
]
> mocked_send_email.assert_has_calls(expected_calls)
E AssertionError: Calls not found.
E Expected: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christian42', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christina95', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025')]
E Actual: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christian42', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christina95', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='spalmurray-codecov', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None)]
E
E pytest introspection follows:
E
E Kwargs:
E assert {'amount': 24...e': None, ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': False,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...e': None, ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': False,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...e': None, ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': False,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...e': None, ...} == {}
E
E Left contains 13 more items:
E {'amount': 240.0,
E 'bank_last_four': None,
E 'bank_name': None,
E 'card_type': None,
E 'cta_link': 'https://stripe.com',...
E
E ...Full output truncated (9 lines hidden), use '-vv' to show
billing/tests/test_views.py:467: AssertionError
self = <MagicMock name='send_email' id='140026230297360'>
calls = [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennife...me='andrea62', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025')]
any_order = False
def assert_has_calls(self, calls, any_order=False):
"""assert the mock has been called with the specified calls.
The `mock_calls` list is checked for the calls.
If `any_order` is False (the default) then the calls must be
sequential. There can be extra calls before or after the
specified calls.
If `any_order` is True then the calls can be in any order, but
they must all appear in `mock_calls`."""
expected = [self._call_matcher(c) for c in calls]
cause = next((e for e in expected if isinstance(e, Exception)), None)
all_calls = _CallList(self._call_matcher(c) for c in self.mock_calls)
if not any_order:
if expected not in all_calls:
if cause is None:
problem = 'Calls not found.'
else:
problem = ('Error processing expected calls.\n'
'Errors: {}').format(
[e if isinstance(e, Exception) else None
for e in expected])
> raise AssertionError(
f'{problem}\n'
f'Expected: {_CallList(calls)}'
f'{self._calls_repr(prefix=" Actual").rstrip(".")}'
) from cause
E AssertionError: Calls not found.
E Expected: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennifermendoza', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea23', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea62', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025')]
E Actual: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennifermendoza', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea23', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea62', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='spalmurray-codecov', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None)]
.../local/lib/python3.12/unittest/mock.py:986: AssertionError
During handling of the above exception, another exception occurred:
self = <billing.tests.test_views.StripeWebhookHandlerTests testMethod=test_invoice_payment_failed_sends_email_to_admins>
retrieve_paymentintent_mock = <MagicMock name='retrieve' id='140026268371520'>
mocked_send_email = <MagicMock name='send_email' id='140026230297360'>
@patch("services.task.TaskService.send_email")
@patch("services.billing.stripe.PaymentIntent.retrieve")
def test_invoice_payment_failed_sends_email_to_admins(
self,
retrieve_paymentintent_mock,
mocked_send_email,
):
non_admin = OwnerFactory(email="[email protected]")
admin_1 = OwnerFactory(email="[email protected]")
admin_2 = OwnerFactory(email="[email protected]")
self.owner.admins = [admin_1.ownerid, admin_2.ownerid]
self.owner.plan_activated_users = [non_admin.ownerid]
self.owner.email = "[email protected]"
self.owner.save()
retrieve_paymentintent_mock.return_value = MockPaymentIntent()
response = self._send_event(
payload={
"type": "invoice.payment_failed",
"data": {
"object": {
"customer": self.owner.stripe_customer_id,
"subscription": self.owner.stripe_subscription_id,
"total": 24000,
"hosted_invoice_url": "https://stripe.com",
"payment_intent": "payment_intent_asdf",
}
},
}
)
self.owner.refresh_from_db()
assert response.status_code == status.HTTP_204_NO_CONTENT
assert self.owner.delinquent is True
expected_calls = [
call(
to_addr=self.owner.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=self.owner.username,
amount=240,
card_type="visa",
last_four="1234",
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
call(
to_addr=admin_1.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=admin_1.username,
amount=240,
card_type="visa",
last_four="1234",
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
call(
to_addr=admin_2.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=admin_2.username,
amount=240,
card_type="visa",
last_four="1234",
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
]
> mocked_send_email.assert_has_calls(expected_calls)
E AssertionError: Calls not found.
E Expected: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennifermendoza', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea23', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea62', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025')]
E Actual: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennifermendoza', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea23', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea62', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='spalmurray-codecov', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None)]
E
E pytest introspection follows:
E
E Kwargs:
E assert {'amount': 24...: 'visa', ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': True,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...: 'visa', ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': True,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...: 'visa', ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': True,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...: 'visa', ...} == {}
E
E Left contains 13 more items:
E {'amount': 240.0,
E 'bank_last_four': None,
E 'bank_name': None,
E 'card_type': 'visa',
E 'cta_link': 'https://stripe.com',...
E
E ...Full output truncated (9 lines hidden), use '-vv' to show
billing/tests/test_views.py:393: AssertionError
self = <MagicMock name='send_email' id='140026210109296'>
calls = [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82...ame='christina95', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025')]
any_order = False
def assert_has_calls(self, calls, any_order=False):
"""assert the mock has been called with the specified calls.
The `mock_calls` list is checked for the calls.
If `any_order` is False (the default) then the calls must be
sequential. There can be extra calls before or after the
specified calls.
If `any_order` is True then the calls can be in any order, but
they must all appear in `mock_calls`."""
expected = [self._call_matcher(c) for c in calls]
cause = next((e for e in expected if isinstance(e, Exception)), None)
all_calls = _CallList(self._call_matcher(c) for c in self.mock_calls)
if not any_order:
if expected not in all_calls:
if cause is None:
problem = 'Calls not found.'
else:
problem = ('Error processing expected calls.\n'
'Errors: {}').format(
[e if isinstance(e, Exception) else None
for e in expected])
> raise AssertionError(
f'{problem}\n'
f'Expected: {_CallList(calls)}'
f'{self._calls_repr(prefix=" Actual").rstrip(".")}'
) from cause
E AssertionError: Calls not found.
E Expected: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christian42', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christina95', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025')]
E Actual: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christian42', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christina95', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='spalmurray-codecov', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None)]
.../local/lib/python3.12/unittest/mock.py:986: AssertionError
During handling of the above exception, another exception occurred:
self = <billing.tests.test_views.StripeWebhookHandlerTests testMethod=test_invoice_payment_failed_sends_email_to_admins_no_card>
retrieve_paymentintent_mock = <MagicMock name='retrieve' id='140026268371040'>
mocked_send_email = <MagicMock name='send_email' id='140026210109296'>
@patch("services.task.TaskService.send_email")
@patch("services.billing.stripe.PaymentIntent.retrieve")
def test_invoice_payment_failed_sends_email_to_admins_no_card(
self,
retrieve_paymentintent_mock,
mocked_send_email,
):
non_admin = OwnerFactory(email="[email protected]")
admin_1 = OwnerFactory(email="[email protected]")
admin_2 = OwnerFactory(email="[email protected]")
self.owner.admins = [admin_1.ownerid, admin_2.ownerid]
self.owner.plan_activated_users = [non_admin.ownerid]
self.owner.email = "[email protected]"
self.owner.save()
retrieve_paymentintent_mock.return_value = MockPaymentIntent(noCard=True)
response = self._send_event(
payload={
"type": "invoice.payment_failed",
"data": {
"object": {
"customer": self.owner.stripe_customer_id,
"subscription": self.owner.stripe_subscription_id,
"default_payment_method": None,
"total": 24000,
"hosted_invoice_url": "https://stripe.com",
"payment_intent": "payment_intent_asdf",
}
},
}
)
self.owner.refresh_from_db()
assert response.status_code == status.HTTP_204_NO_CONTENT
assert self.owner.delinquent is True
expected_calls = [
call(
to_addr=self.owner.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=self.owner.username,
amount=240,
card_type=None,
last_four=None,
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
call(
to_addr=admin_1.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=admin_1.username,
amount=240,
card_type=None,
last_four=None,
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
call(
to_addr=admin_2.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=admin_2.username,
amount=240,
card_type=None,
last_four=None,
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
]
> mocked_send_email.assert_has_calls(expected_calls)
E AssertionError: Calls not found.
E Expected: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christian42', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christina95', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025')]
E Actual: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christian42', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christina95', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='spalmurray-codecov', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None)]
E
E pytest introspection follows:
E
E Kwargs:
E assert {'amount': 24...e': None, ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': False,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...e': None, ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': False,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...e': None, ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': False,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...e': None, ...} == {}
E
E Left contains 13 more items:
E {'amount': 240.0,
E 'bank_last_four': None,
E 'bank_name': None,
E 'card_type': None,
E 'cta_link': 'https://stripe.com',...
E
E ...Full output truncated (9 lines hidden), use '-vv' to show
billing/tests/test_views.py:467: AssertionError
self = <MagicMock name='send_email' id='140026230297360'>
calls = [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennife...me='andrea62', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025')]
any_order = False
def assert_has_calls(self, calls, any_order=False):
"""assert the mock has been called with the specified calls.
The `mock_calls` list is checked for the calls.
If `any_order` is False (the default) then the calls must be
sequential. There can be extra calls before or after the
specified calls.
If `any_order` is True then the calls can be in any order, but
they must all appear in `mock_calls`."""
expected = [self._call_matcher(c) for c in calls]
cause = next((e for e in expected if isinstance(e, Exception)), None)
all_calls = _CallList(self._call_matcher(c) for c in self.mock_calls)
if not any_order:
if expected not in all_calls:
if cause is None:
problem = 'Calls not found.'
else:
problem = ('Error processing expected calls.\n'
'Errors: {}').format(
[e if isinstance(e, Exception) else None
for e in expected])
> raise AssertionError(
f'{problem}\n'
f'Expected: {_CallList(calls)}'
f'{self._calls_repr(prefix=" Actual").rstrip(".")}'
) from cause
E AssertionError: Calls not found.
E Expected: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennifermendoza', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea23', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea62', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025')]
E Actual: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennifermendoza', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea23', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea62', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='spalmurray-codecov', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None)]
/usr/local/lib/python3.12/unittest/mock.py:986: AssertionError
During handling of the above exception, another exception occurred:
self = <billing.tests.test_views.StripeWebhookHandlerTests testMethod=test_invoice_payment_failed_sends_email_to_admins>
retrieve_paymentintent_mock = <MagicMock name='retrieve' id='140026268371520'>
mocked_send_email = <MagicMock name='send_email' id='140026230297360'>
@patch("services.task.TaskService.send_email")
@patch("services.billing.stripe.PaymentIntent.retrieve")
def test_invoice_payment_failed_sends_email_to_admins(
self,
retrieve_paymentintent_mock,
mocked_send_email,
):
non_admin = OwnerFactory(email="[email protected]")
admin_1 = OwnerFactory(email="[email protected]")
admin_2 = OwnerFactory(email="[email protected]")
self.owner.admins = [admin_1.ownerid, admin_2.ownerid]
self.owner.plan_activated_users = [non_admin.ownerid]
self.owner.email = "[email protected]"
self.owner.save()
retrieve_paymentintent_mock.return_value = MockPaymentIntent()
response = self._send_event(
payload={
"type": "invoice.payment_failed",
"data": {
"object": {
"customer": self.owner.stripe_customer_id,
"subscription": self.owner.stripe_subscription_id,
"total": 24000,
"hosted_invoice_url": "https://stripe.com",
"payment_intent": "payment_intent_asdf",
}
},
}
)
self.owner.refresh_from_db()
assert response.status_code == status.HTTP_204_NO_CONTENT
assert self.owner.delinquent is True
expected_calls = [
call(
to_addr=self.owner.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=self.owner.username,
amount=240,
card_type="visa",
last_four="1234",
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
call(
to_addr=admin_1.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=admin_1.username,
amount=240,
card_type="visa",
last_four="1234",
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
call(
to_addr=admin_2.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=admin_2.username,
amount=240,
card_type="visa",
last_four="1234",
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
]
> mocked_send_email.assert_has_calls(expected_calls)
E AssertionError: Calls not found.
E Expected: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennifermendoza', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea23', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea62', amount=240, card_type='visa', last_four='1234', cta_link='https://stripe.com', date='January 21, 2025')]
E Actual: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='jennifermendoza', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea23', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='andrea62', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='spalmurray-codecov', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=True, card_type='visa', last_four='1234', is_us_bank=False, bank_name=None, bank_last_four=None)]
E
E pytest introspection follows:
E
E Kwargs:
E assert {'amount': 24...: 'visa', ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': True,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...: 'visa', ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': True,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...: 'visa', ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': True,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...: 'visa', ...} == {}
E
E Left contains 13 more items:
E {'amount': 240.0,
E 'bank_last_four': None,
E 'bank_name': None,
E 'card_type': 'visa',
E 'cta_link': 'https://stripe.com',...
E
E ...Full output truncated (9 lines hidden), use '-vv' to show
billing/tests/test_views.py:393: AssertionError
self = <MagicMock name='send_email' id='140026210109296'>
calls = [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82...ame='christina95', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025')]
any_order = False
def assert_has_calls(self, calls, any_order=False):
"""assert the mock has been called with the specified calls.
The `mock_calls` list is checked for the calls.
If `any_order` is False (the default) then the calls must be
sequential. There can be extra calls before or after the
specified calls.
If `any_order` is True then the calls can be in any order, but
they must all appear in `mock_calls`."""
expected = [self._call_matcher(c) for c in calls]
cause = next((e for e in expected if isinstance(e, Exception)), None)
all_calls = _CallList(self._call_matcher(c) for c in self.mock_calls)
if not any_order:
if expected not in all_calls:
if cause is None:
problem = 'Calls not found.'
else:
problem = ('Error processing expected calls.\n'
'Errors: {}').format(
[e if isinstance(e, Exception) else None
for e in expected])
> raise AssertionError(
f'{problem}\n'
f'Expected: {_CallList(calls)}'
f'{self._calls_repr(prefix=" Actual").rstrip(".")}'
) from cause
E AssertionError: Calls not found.
E Expected: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christian42', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christina95', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025')]
E Actual: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christian42', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christina95', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='spalmurray-codecov', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None)]
/usr/local/lib/python3.12/unittest/mock.py:986: AssertionError
During handling of the above exception, another exception occurred:
self = <billing.tests.test_views.StripeWebhookHandlerTests testMethod=test_invoice_payment_failed_sends_email_to_admins_no_card>
retrieve_paymentintent_mock = <MagicMock name='retrieve' id='140026268371040'>
mocked_send_email = <MagicMock name='send_email' id='140026210109296'>
@patch("services.task.TaskService.send_email")
@patch("services.billing.stripe.PaymentIntent.retrieve")
def test_invoice_payment_failed_sends_email_to_admins_no_card(
self,
retrieve_paymentintent_mock,
mocked_send_email,
):
non_admin = OwnerFactory(email="[email protected]")
admin_1 = OwnerFactory(email="[email protected]")
admin_2 = OwnerFactory(email="[email protected]")
self.owner.admins = [admin_1.ownerid, admin_2.ownerid]
self.owner.plan_activated_users = [non_admin.ownerid]
self.owner.email = "[email protected]"
self.owner.save()
retrieve_paymentintent_mock.return_value = MockPaymentIntent(noCard=True)
response = self._send_event(
payload={
"type": "invoice.payment_failed",
"data": {
"object": {
"customer": self.owner.stripe_customer_id,
"subscription": self.owner.stripe_subscription_id,
"default_payment_method": None,
"total": 24000,
"hosted_invoice_url": "https://stripe.com",
"payment_intent": "payment_intent_asdf",
}
},
}
)
self.owner.refresh_from_db()
assert response.status_code == status.HTTP_204_NO_CONTENT
assert self.owner.delinquent is True
expected_calls = [
call(
to_addr=self.owner.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=self.owner.username,
amount=240,
card_type=None,
last_four=None,
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
call(
to_addr=admin_1.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=admin_1.username,
amount=240,
card_type=None,
last_four=None,
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
call(
to_addr=admin_2.email,
subject="Your Codecov payment failed",
template_name="failed-payment",
name=admin_2.username,
amount=240,
card_type=None,
last_four=None,
cta_link="https://stripe.com",
date=datetime.now().strftime("%B %-d, %Y"),
),
]
> mocked_send_email.assert_has_calls(expected_calls)
E AssertionError: Calls not found.
E Expected: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christian42', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025'),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christina95', amount=240, card_type=None, last_four=None, cta_link='https://stripe.com', date='January 21, 2025')]
E Actual: [call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='corey82', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christian42', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='christina95', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None),
E call(to_addr='[email protected]', subject='Your Codecov payment failed', template_name='failed-payment', name='spalmurray-codecov', amount=240.0, cta_link='https://stripe.com', date='January 21, 2025', is_credit_card=False, card_type=None, last_four=None, is_us_bank=False, bank_name=None, bank_last_four=None)]
E
E pytest introspection follows:
E
E Kwargs:
E assert {'amount': 24...e': None, ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': False,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...e': None, ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': False,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...e': None, ...} == {'amount': 24...1, 2025', ...}
E
E Omitting 9 identical items, use -vv to show
E Left contains 4 more items:
E {'bank_last_four': None,
E 'bank_name': None,
E 'is_credit_card': False,
E 'is_us_bank': False}
E Use -v to get more diff
E Kwargs:
E assert {'amount': 24...e': None, ...} == {}
E
E Left contains 13 more items:
E {'amount': 240.0,
E 'bank_last_four': None,
E 'bank_name': None,
E 'card_type': None,
E 'cta_link': 'https://stripe.com',...
E
E ...Full output truncated (9 lines hidden), use '-vv' to show
billing/tests/test_views.py:467: AssertionError
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Purpose/Motivation
What is the feature? Why is this being done?
Links to relevant tickets
What does this PR do?
Include a brief description of the changes in this PR. Bullet points are your friend.
Notes to Reviewer
Anything to note to the team? Any tips on how to review, or where to start?
Legal Boilerplate
Look, I get it. The entity doing business as "Sentry" was incorporated in the State of Delaware in 2015 as Functional Software, Inc. In 2022 this entity acquired Codecov and as result Sentry is going to need some rights from me in order to utilize my contributions in this PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Sentry can use, modify, copy, and redistribute my contributions, under Sentry's choice of terms.