Skip to content

Commit

Permalink
Add QueryableFake gateway
Browse files Browse the repository at this point in the history
  • Loading branch information
christopherdcunha committed Mar 14, 2019
1 parent 268c0d6 commit ebfc9ed
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 1 deletion.
8 changes: 8 additions & 0 deletions docs/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ General Settings
Twilio_.
* ``'two_factor.gateways.fake.Fake'`` for development, recording tokens to the
default logger.
* ``'two_factor.gateways.fake.QueryableFake'`` for testing, recording tokens
to the ``QueryableFake`` singleton.

``TWO_FACTOR_SMS_GATEWAY`` (default: ``None``)
Which gateway to use for sending text messages. Should be set to a module or
Expand All @@ -28,6 +30,8 @@ General Settings
Twilio_.
* ``'two_factor.gateways.fake.Fake'`` for development, recording tokens to the
default logger.
* ``'two_factor.gateways.fake.QueryableFake'`` for testing, recording tokens
to the ``QueryableFake`` singleton.

``LOGIN_URL``
Should point to the login view provided by this application as described in
Expand Down Expand Up @@ -118,6 +122,10 @@ Fake Gateway
------------
.. autoclass:: two_factor.gateways.fake.Fake

QueryableFake Gateway
------------
.. autoclass:: two_factor.gateways.fake.QueryableFake

.. _LOGIN_URL: https://docs.djangoproject.com/en/dev/ref/settings/#login-url
.. _LOGIN_REDIRECT_URL: https://docs.djangoproject.com/en/dev/ref/settings/#login-redirect-url
.. _LOGOUT_REDIRECT_URL: https://docs.djangoproject.com/en/dev/ref/settings/#logout-redirect-url
Expand Down
14 changes: 13 additions & 1 deletion tests/test_gateways.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from django.utils.six.moves.urllib.parse import urlencode
from phonenumber_field.phonenumber import PhoneNumber

from two_factor.gateways.fake import Fake
from two_factor.gateways.fake import Fake, QueryableFake
from two_factor.gateways.twilio.gateway import Twilio

try:
Expand Down Expand Up @@ -117,3 +117,15 @@ def test_gateway(self, logger):
fake.send_sms(device=Mock(number=PhoneNumber.from_string('+123')), token=code)
logger.info.assert_called_with(
'Fake SMS to %s: "Your token is: %s"', '+123', code)


class QueryableFakeGatewayTest(TestCase):
def test_gateway(self):
fake = QueryableFake()

for code in ['654321', '87654321']:
fake.make_call(device=Mock(number=PhoneNumber.from_string('+123')), token=code)
self.assertEqual(fake.call_tokens['+123'].pop(), code)

fake.send_sms(device=Mock(number=PhoneNumber.from_string('+123')), token=code)
self.assertEqual(fake.sms_tokens['+123'].pop(), code)
42 changes: 42 additions & 0 deletions two_factor/gateways/fake.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from collections import defaultdict
import logging

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -33,3 +34,44 @@ def make_call(device, token):
@staticmethod
def send_sms(device, token):
logger.info('Fake SMS to %s: "Your token is: %s"', device.number.as_e164, token)


class QueryableFake(object):
"""A Fake gateway that can be queried.
For example, you may use this in your unit tests::
>>> from django.test import TestCase, override_settings
>>> from django.contrib.auth import get_user_model
>>> from django.conf import settings
>>> from two_factor.gateways.fake import QueryableFake
>>> from two_factor.models import PhoneDevice
>>> from phonenumber_field.phonenumber import PhoneNumber
>>>
>>> class MyTestCase(TestCase):
... @override_settings(
... TWO_FACTOR_SMS_GATEWAY='two_factor.gateways.fake.QueryableFake',
... )
... def test_something(self):
... user = get_user_model().objects.create(...)
... PhoneDevice.objects.create(
... user=user, name='default', method='sms',
... number=PhoneNumber.from_string('+441234567890'),
... )
... self.client.post(settings.LOGIN_URL,
... 'username': user.username,
... 'password': 'password',
... })
... token = QueryableFake.sms_tokens['+441234567890'].pop()
... self.client.post(settings.LOGIN_URL, {'token': token})
"""
sms_tokens = defaultdict(list)
call_tokens = defaultdict(list)

@classmethod
def make_call(cls, device, token):
cls.call_tokens[str(device.number)].append(token)

@classmethod
def send_sms(cls, device, token):
cls.sms_tokens[str(device.number)].append(token)

0 comments on commit ebfc9ed

Please sign in to comment.