Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skip Adyen's test notifications #18

Merged
merged 1 commit into from
Sep 29, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion adyen/facade.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,10 +219,17 @@ def assess_notification_relevance(self, request):
if request.POST.get(Constants.EVENT_CODE) != Constants.EVENT_CODE_AUTHORISATION:
return False, True

reference = request.POST[Constants.PSP_REFERENCE]

# Adyen has a notification check that can be run from their control panel.
# It's useful to debug connection problems between Adyen and our servers.
# So we acknowledge them, but must not process them.
if Constants.TEST_REFERENCE_PREFIX in reference:
return False, True

# Adyen duplicates many notifications. This bit makes sure we ignore them.
# "Duplicate notifications have the same corresponding values for their eventCode and
# pspReference fields." https://docs.adyen.com/display/TD/Accept+notifications
reference = request.POST[Constants.PSP_REFERENCE]
# The event code gets checked above, so we only need to check for the reference now.
if AdyenTransaction.objects.filter(reference=reference).exists():
# We already stored a transaction with this reference, so we can ignore the
Expand Down
5 changes: 5 additions & 0 deletions adyen/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class Constants:
PAYMENT_RESULT_ERROR = 'ERROR'

PSP_REFERENCE = 'pspReference'
TEST_REFERENCE_PREFIX = 'test_AUTHORISATION'
REASON = 'reason'
RECURRING_CONTRACT = 'recurringContract'
SECRET_KEY = 'secret_key'
Expand Down Expand Up @@ -370,6 +371,10 @@ def process(self):


class PaymentRedirection(BaseResponse):
"""
Class used to process payment notifications from the user; when they paid on Adyen
and get redirected back to our site. HTTP GET from user's browser.
"""
REQUIRED_FIELDS = (
Constants.AUTH_RESULT,
Constants.MERCHANT_REFERENCE,
Expand Down
70 changes: 48 additions & 22 deletions tests/test_adyen.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,9 @@ def test_form_fields_with_missing_mandatory_field(self):


class TestAdyenPaymentResponse(AdyenTestCase):
"""
Test case that tests Adyen payment responses (user redirected from Adyen to us)
"""

def setUp(self):
super().setUp()
Expand Down Expand Up @@ -396,40 +399,55 @@ def test_handle_tampered_payment(self):
num_recorded_transactions = AdyenTransaction.objects.all().count()
self.assertEqual(num_recorded_transactions, 0)

def test_assess_notification_relevance(self):

self.request.method = 'POST'
class TestAdyenPaymentNotification(AdyenTestCase):
"""
Test case that tests Adyen payment notifications (Adyen servers POST'ing to us)
"""

# If this is an `AUTHORISATION` request targeting the proper platform,
# we should both process and acknowledge it.
self.request.POST = deepcopy(AUTHORISED_PAYMENT_PARAMS_POST)
must_process, must_ack = self.scaffold.assess_notification_relevance(self.request)
self.assertTupleEqual((must_process, must_ack), (True, True))
def setUp(self):
super().setUp()
request = Mock()
request.method = 'POST'
# Most tests use unproxied requests, the case of proxied ones
# is unit-tested by the `test_get_origin_ip_address` method.
request.META = {'REMOTE_ADDR': '127.0.0.1'}
request.POST = deepcopy(AUTHORISED_PAYMENT_PARAMS_POST)
self.request = request

def test_valid_request(self):
"""
If this is an `AUTHORISATION` request targeting the proper platform,
we should both process and acknowledge it. This test is needed
as a base assumption for the tests below.
"""
assert (True, True) == self.scaffold.assess_notification_relevance(self.request)

# If there is a mismatch between the request origin and target platforms,
# we should just let it be.
def test_platform_mismatch_live_notification(self):
"""
If there is a mismatch between the request origin and target platforms,
we should just let it be.
"""
self.request.POST['live'] = 'true'
must_process, must_ack = self.scaffold.assess_notification_relevance(self.request)
self.assertTupleEqual((must_process, must_ack), (False, False))
assert (False, False) == self.scaffold.assess_notification_relevance(self.request)

def test_platform_mismatch_live_server(self):
self.request.POST['live'] = 'false'
with self.settings(ADYEN_ACTION_URL='https://live.adyen.com/hpp/select.shtml'):
must_process, must_ack = self.scaffold.assess_notification_relevance(self.request)
self.assertTupleEqual((must_process, must_ack), (False, False))
assert (False, False) == self.scaffold.assess_notification_relevance(self.request)

# If this is not an `AUTHORISATION` request, we should acknowledge it
# but not try to process it.
self.request.POST['eventCode'] = 'REPORT_AVAILABLE'
must_process, must_ack = self.scaffold.assess_notification_relevance(self.request)
self.assertTupleEqual((must_process, must_ack), (False, True))
def test_non_authorisation(self):
"""
If this is not an `AUTHORISATION` request, we should acknowledge it
but not try to process it.
"""
self.request.POST[Constants.EVENT_CODE] = 'REPORT_AVAILABLE'
assert (False, True) == self.scaffold.assess_notification_relevance(self.request)

def test_assert_duplicate_notifications(self):
def test_duplicate_notifications(self):
"""
This test tests that duplicate notifications are ignored.
"""
self.request.method = 'POST'
self.request.POST = deepcopy(AUTHORISED_PAYMENT_PARAMS_POST)

# We have a valid request. So let's confirm that we think we should process
# and acknowledge it.
assert (True, True) == self.scaffold.assess_notification_relevance(self.request)
Expand All @@ -441,6 +459,14 @@ def test_assert_duplicate_notifications(self):
# any more. But we still acknowledge it.
assert (False, True) == self.scaffold.assess_notification_relevance(self.request)

def test_test_notification(self):
"""
Adyen can send test notifications even to the live system for debugging
connection problems. We should acknowledge them, but not process.
"""
self.request.POST[Constants.PSP_REFERENCE] = Constants.TEST_REFERENCE_PREFIX + '_5'
assert (False, True) == self.scaffold.assess_notification_relevance(self.request)


class MockClient:
secret_key = None
Expand Down