Skip to content

Commit

Permalink
Merge pull request #18 from oscaro/feature/test_notifications
Browse files Browse the repository at this point in the history
Skip Adyen's test notifications
  • Loading branch information
maiksprenger committed Sep 29, 2015
2 parents f17e99c + 73e16c2 commit 8c0ec82
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 23 deletions.
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

0 comments on commit 8c0ec82

Please sign in to comment.