From e23792d3e60a7cac6e0448595bd5c351b084ef46 Mon Sep 17 00:00:00 2001 From: Oscar Chen Date: Thu, 11 Jan 2024 22:45:02 -0700 Subject: [PATCH] Add unit tests for token operations --- .gitignore | 3 + requirements.txt | 4 +- tests/manage.py | 22 +++++++ tests/test_jwt/__init__.py | 0 tests/test_jwt/test_token_operations.py | 79 +++++++++++++++++++++++++ tests/test_something.py | 6 -- tests/urls.py | 1 + 7 files changed, 107 insertions(+), 8 deletions(-) create mode 100755 tests/manage.py create mode 100644 tests/test_jwt/__init__.py create mode 100644 tests/test_jwt/test_token_operations.py delete mode 100644 tests/test_something.py create mode 100644 tests/urls.py diff --git a/.gitignore b/.gitignore index 859e9f9..70991b1 100644 --- a/.gitignore +++ b/.gitignore @@ -148,3 +148,6 @@ NOTE*.csv .idea .pylintrc + +mock-jwt-signing.pem +mock-jwt-signing.pub diff --git a/requirements.txt b/requirements.txt index cde8b9f..75f578b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,10 +3,10 @@ black==23.11.0 cryptography==41.0.7 Django>=4.2 django-ninja>=1.0 -django-stubs[compatible-mypy]==4.2.6 +django-stubs[compatible-mypy]==4.2.7 freezegun==1.2.2 isort==5.12.0 -mypy==1.6.1 +mypy>=1.7 pre-commit==3.4.0 pyjwt>=2.6 pylint==3.0.2 diff --git a/tests/manage.py b/tests/manage.py new file mode 100755 index 0000000..bcb59f3 --- /dev/null +++ b/tests/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main() -> None: + """Run administrative tasks.""" + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tests.settings") + try: + from django.core.management import execute_from_command_line # pylint: disable=C0415 + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == "__main__": + main() diff --git a/tests/test_jwt/__init__.py b/tests/test_jwt/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_jwt/test_token_operations.py b/tests/test_jwt/test_token_operations.py new file mode 100644 index 0000000..01d5510 --- /dev/null +++ b/tests/test_jwt/test_token_operations.py @@ -0,0 +1,79 @@ +from django.test import TestCase +from freezegun import freeze_time +from jwt import DecodeError, ExpiredSignatureError, InvalidTokenError + +from ninja_simple_jwt.jwt.key_creation import make_and_save_key_pair +from ninja_simple_jwt.jwt.token_operations import TokenTypes, decode_token, encode_token + + +class TestEncodeToken(TestCase): + def setUp(self) -> None: + make_and_save_key_pair() + + def test_encode_token(self) -> None: + test_payload = { + "name": "bebe", + } + + with freeze_time("2024-01-11 12:00:01"): + token, token_data = encode_token(payload=test_payload, token_type=TokenTypes.REFRESH) + + self.assertIsNotNone(token, "token created") + self.assertEqual(token_data["exp"], 1707566401, "Token data has correct expiry time.") + self.assertEqual(token_data["iat"], 1704974401, "Token data has correct issue time.") + self.assertEqual(token_data["token_type"], TokenTypes.REFRESH, "Token data has correct token type.") + self.assertEqual(token_data["name"], "bebe", "Token data has correct payload data.") + self.assertIsNotNone(token_data["jti"], "Token data has jti claim.") + + def test_decode_token(self) -> None: + test_payload = { + "name": "bebe", + } + with freeze_time("2024-01-11 12:00:01"): + token, _ = encode_token(payload=test_payload, token_type=TokenTypes.ACCESS) + decoded_data = decode_token(token, token_type=TokenTypes.ACCESS) + + self.assertEqual(decoded_data["exp"], 1704975301, "Token has correct expiry time.") + self.assertEqual(decoded_data["iat"], 1704974401, "Token has correct issue time.") + self.assertEqual(decoded_data["token_type"], TokenTypes.ACCESS, "Token has correct token type.") + self.assertEqual(decoded_data["name"], "bebe", "Token has correct payload data.") + self.assertIsNotNone(decoded_data["jti"], "Token has jti claim.") + + def test_decode_token_with_wrong_token_type_raises_invalid_token_exception(self) -> None: + exception_raised = False + test_payload = { + "name": "bebe", + } + with freeze_time("2024-01-11 12:00:01"): + token, _ = encode_token(payload=test_payload, token_type=TokenTypes.REFRESH) + + try: + decode_token(token, token_type=TokenTypes.ACCESS) + except InvalidTokenError: + exception_raised = True + + self.assertTrue(exception_raised, "Exception raised as expected.") + + def test_decode_invalid_token_raises_decode_error_exception(self) -> None: + exception_raised = False + + try: + decode_token("not.real.token", token_type=TokenTypes.REFRESH) + except DecodeError: + exception_raised = True + + self.assertTrue(exception_raised, "Exception raised as expected.") + + def test_decode_expired_token_raises_expired_signature_exception(self) -> None: + exception_raised = False + + with freeze_time("2000-01-01 12:00:00"): + token, _ = encode_token(payload={}, token_type=TokenTypes.ACCESS) + + with freeze_time("2020-01-01 12:00:00"): + try: + decode_token(token, token_type=TokenTypes.ACCESS) + except ExpiredSignatureError: + exception_raised = True + + self.assertTrue(exception_raised, "Exception raised as expected.") diff --git a/tests/test_something.py b/tests/test_something.py deleted file mode 100644 index 8e7d132..0000000 --- a/tests/test_something.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.test import TestCase - - -class TestTox(TestCase): - def test_something(self) -> None: - self.assertTrue(bool(1)) diff --git a/tests/urls.py b/tests/urls.py new file mode 100644 index 0000000..fc225bc --- /dev/null +++ b/tests/urls.py @@ -0,0 +1 @@ +urlpatterns = [] # type: ignore