Skip to content

Commit 510ebd0

Browse files
ecilveksauvipy
authored andcommitted
Feature/test for clear expired (#680)
* document force migration sequence forr application model * add tests for clear_expired * add tests for clear_tokens * add tests for clear_expired * fix isort * Update tests/test_models.py Co-Authored-By: ecilveks <[email protected]> * CR changes * fix isort for upstream * add logging about what is to be deleted * also log when no refresh tokens are to be deleted
1 parent 32bba99 commit 510ebd0

File tree

3 files changed

+98
-6
lines changed

3 files changed

+98
-6
lines changed

docs/advanced_topics.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,15 @@ Be aware that, when you intend to swap the application model, you should create
4848
migration defining the swapped application model prior to setting OAUTH2_PROVIDER_APPLICATION_MODEL.
4949
You'll run into models.E022 in Core system checks if you don't get the order right.
5050

51+
You can force your migration providing the custom model to run in the right order by
52+
adding::
53+
54+
run_before = [
55+
('oauth2_provider', '0001_initial'),
56+
]
57+
58+
to the migration class.
59+
5160
That's all, now Django OAuth Toolkit will use your model wherever an Application instance is needed.
5261

5362
**Notice:** `OAUTH2_PROVIDER_APPLICATION_MODEL` is the only setting variable that is not namespaced, this

oauth2_provider/models.py

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from datetime import timedelta
22
from urllib.parse import parse_qsl, urlparse
3+
import logging
34

45
from django.apps import apps
56
from django.conf import settings
@@ -14,6 +15,8 @@
1415
from .settings import oauth2_settings
1516
from .validators import RedirectURIValidator, WildcardSet
1617

18+
logger = logging.getLogger(__name__)
19+
1720

1821
class AbstractApplication(models.Model):
1922
"""
@@ -436,7 +439,30 @@ def clear_expired():
436439

437440
with transaction.atomic():
438441
if refresh_expire_at:
439-
refresh_token_model.objects.filter(revoked__lt=refresh_expire_at).delete()
440-
refresh_token_model.objects.filter(access_token__expires__lt=refresh_expire_at).delete()
441-
access_token_model.objects.filter(refresh_token__isnull=True, expires__lt=now).delete()
442-
grant_model.objects.filter(expires__lt=now).delete()
442+
revoked = refresh_token_model.objects.filter(
443+
revoked__lt=refresh_expire_at,
444+
)
445+
expired = refresh_token_model.objects.filter(
446+
access_token__expires__lt=refresh_expire_at,
447+
)
448+
449+
logger.info('%s Revoked refresh tokens to be deleted', revoked.count())
450+
logger.info('%s Expired refresh tokens to be deleted', expired.count())
451+
452+
revoked.delete()
453+
expired.delete()
454+
else:
455+
logger.info('refresh_expire_at is %s. No refresh tokens deleted.',
456+
refresh_expire_at)
457+
458+
access_tokens = access_token_model.objects.filter(
459+
refresh_token__isnull=True,
460+
expires__lt=now
461+
)
462+
grants = grant_model.objects.filter(expires__lt=now)
463+
464+
logger.info('%s Expired access tokens to be deleted', access_tokens.count())
465+
logger.info('%s Expired grant tokens to be deleted', grants.count())
466+
467+
access_tokens.delete()
468+
grants.delete()

tests/test_models.py

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1+
from datetime import datetime as dt
2+
3+
import pytest
14
from django.contrib.auth import get_user_model
2-
from django.core.exceptions import ValidationError
5+
from django.core.exceptions import ImproperlyConfigured, ValidationError
36
from django.test import TestCase
47
from django.test.utils import override_settings
58
from django.utils import timezone
69

710
from oauth2_provider.models import (
8-
get_access_token_model, get_application_model,
11+
clear_expired, get_access_token_model, get_application_model,
912
get_grant_model, get_refresh_token_model
1013
)
1114
from oauth2_provider.settings import oauth2_settings
@@ -19,6 +22,7 @@
1922

2023

2124
class TestModels(TestCase):
25+
2226
def setUp(self):
2327
self.user = UserModel.objects.create_user("test_user", "[email protected]", "123456")
2428

@@ -118,6 +122,7 @@ def test_scopes_property(self):
118122
OAUTH2_PROVIDER_GRANT_MODEL="tests.SampleGrant"
119123
)
120124
class TestCustomModels(TestCase):
125+
121126
def setUp(self):
122127
self.user = UserModel.objects.create_user("test_user", "[email protected]", "123456")
123128

@@ -260,6 +265,7 @@ def test_expires_can_be_none(self):
260265

261266

262267
class TestAccessTokenModel(TestCase):
268+
263269
def setUp(self):
264270
self.user = UserModel.objects.create_user("test_user", "[email protected]", "123456")
265271

@@ -289,3 +295,54 @@ class TestRefreshTokenModel(TestCase):
289295
def test_str(self):
290296
refresh_token = RefreshToken(token="test_token")
291297
self.assertEqual("%s" % refresh_token, refresh_token.token)
298+
299+
300+
class TestClearExpired(TestCase):
301+
302+
def setUp(self):
303+
self.user = UserModel.objects.create_user("test_user", "[email protected]", "123456")
304+
# Insert two tokens on database.
305+
AccessToken.objects.create(
306+
id=1,
307+
token="555",
308+
expires=dt.now(),
309+
scope=2,
310+
application_id=3,
311+
user_id=1,
312+
created=dt.now(),
313+
updated=dt.now(),
314+
source_refresh_token_id="0",
315+
)
316+
AccessToken.objects.create(
317+
id=2,
318+
token="666",
319+
expires=dt.now(),
320+
scope=2,
321+
application_id=3,
322+
user_id=1,
323+
created=dt.now(),
324+
updated=dt.now(),
325+
source_refresh_token_id="1",
326+
)
327+
328+
def test_clear_expired_tokens(self):
329+
oauth2_settings.REFRESH_TOKEN_EXPIRE_SECONDS = 60
330+
assert clear_expired() is None
331+
332+
def test_clear_expired_tokens_incorect_timetype(self):
333+
oauth2_settings.REFRESH_TOKEN_EXPIRE_SECONDS = "A"
334+
with pytest.raises(ImproperlyConfigured) as excinfo:
335+
clear_expired()
336+
result = excinfo.value.__class__.__name__
337+
assert result == "ImproperlyConfigured"
338+
339+
def test_clear_expired_tokens_with_tokens(self):
340+
self.client.login(username="test_user", password="123456")
341+
oauth2_settings.REFRESH_TOKEN_EXPIRE_SECONDS = 0
342+
ttokens = AccessToken.objects.count()
343+
expiredt = AccessToken.objects.filter(expires__lte=dt.now()).count()
344+
assert ttokens == 2
345+
assert expiredt == 2
346+
clear_expired()
347+
expiredt = AccessToken.objects.filter(expires__lte=dt.now()).count()
348+
assert expiredt == 0

0 commit comments

Comments
 (0)