From fec2a31b906382d710c573d7e44ef57bdb8c751d Mon Sep 17 00:00:00 2001 From: piyush-jaiswal Date: Wed, 20 Aug 2025 23:43:54 +0530 Subject: [PATCH 1/4] Improve JWT tests --- tests/test_auth.py | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/tests/test_auth.py b/tests/test_auth.py index 6565475..f27f3a1 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -1,12 +1,17 @@ +import math + import pytest from app.models import User from tests import utils +from flask_jwt_extended import decode_token class TestAuth: TEST_EMAIL = "testuser@example.com" TEST_PASSWORD = "testpassword" + ACCESS_TOKEN_DELTA = 10800 # 3 hours in seconds + REFRESH_TOKEN_DELTA = 259200 # 3 days in seconds @pytest.fixture(autouse=True) def setup(self, client): @@ -41,6 +46,33 @@ def _test_invalid_request_data(self, endpoint, expected_status=400): response = self.client.post(endpoint, data="not json data") assert response.status_code == 415 + def _decode_token(self, token): + return decode_token(token, allow_expired=False) + + def _assert_jwt_structure(self, token, expected_sub, expected_type, fresh=False): + assert token.count(".") == 2, f"Token does not have three segments: {token}" + payload = self._decode_token(token) + assert payload["sub"] == expected_sub + assert payload["type"] == expected_type + assert "iat" in payload + assert "exp" in payload + assert "jti" in payload + assert payload["fresh"] is fresh + + # Expiry check + expected_delta = None + if expected_type == "access": + expected_delta = self.ACCESS_TOKEN_DELTA + if expected_type == "refresh": + expected_delta = self.REFRESH_TOKEN_DELTA + + if expected_delta is not None: + actual_delta = payload["exp"] - payload["iat"] + # Allow a small margin (e.g., 0-2 seconds) for processing time + assert math.isclose(actual_delta, expected_delta, abs_tol=2), ( + f"Token expiry delta {actual_delta} != expected {expected_delta}" + ) + def test_register_success(self, register_user): response = register_user(self.TEST_EMAIL, self.TEST_PASSWORD) @@ -81,8 +113,9 @@ def test_login_success(self, register_user, login_user): data = response.get_json() assert "access_token" in data assert "refresh_token" in data - assert len(data["access_token"]) > 0 - assert len(data["refresh_token"]) > 0 + + self._assert_jwt_structure(data["access_token"], expected_sub="1", expected_type="access", fresh=True) + self._assert_jwt_structure(data["refresh_token"], expected_sub="1", expected_type="refresh") def test_login_invalid_password(self, register_user, login_user): register_user(self.TEST_EMAIL, self.TEST_PASSWORD) @@ -109,6 +142,8 @@ def test_refresh_token(self, register_user, login_user): assert data["access_token"] != original_access_token assert "refresh_token" not in data + self._assert_jwt_structure(data["access_token"], expected_sub="1", expected_type="access", fresh=False) + def test_refresh_token_invalid(self, register_user, login_user): # Access token test register_user(self.TEST_EMAIL, self.TEST_PASSWORD) From 242d4edf0f8926a0ecdfd05c5745306bd4b8b830 Mon Sep 17 00:00:00 2001 From: piyushj Date: Thu, 21 Aug 2025 00:02:39 +0530 Subject: [PATCH 2/4] Use flask app_context for decode_token Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- tests/test_auth.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_auth.py b/tests/test_auth.py index f27f3a1..c902785 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -47,8 +47,9 @@ def _test_invalid_request_data(self, endpoint, expected_status=400): assert response.status_code == 415 def _decode_token(self, token): - return decode_token(token, allow_expired=False) - + # Needs Flask app context for secret/algorithms from current_app.config + with self.client.application.app_context(): + return decode_token(token, allow_expired=False) def _assert_jwt_structure(self, token, expected_sub, expected_type, fresh=False): assert token.count(".") == 2, f"Token does not have three segments: {token}" payload = self._decode_token(token) From 4f4a698e64499e6692bba6150820e47060806d8e Mon Sep 17 00:00:00 2001 From: piyush-jaiswal Date: Thu, 21 Aug 2025 00:12:18 +0530 Subject: [PATCH 3/4] improve code --- tests/test_auth.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_auth.py b/tests/test_auth.py index c902785..f6d09a1 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -64,7 +64,7 @@ def _assert_jwt_structure(self, token, expected_sub, expected_type, fresh=False) expected_delta = None if expected_type == "access": expected_delta = self.ACCESS_TOKEN_DELTA - if expected_type == "refresh": + elif expected_type == "refresh": expected_delta = self.REFRESH_TOKEN_DELTA if expected_delta is not None: @@ -143,7 +143,7 @@ def test_refresh_token(self, register_user, login_user): assert data["access_token"] != original_access_token assert "refresh_token" not in data - self._assert_jwt_structure(data["access_token"], expected_sub="1", expected_type="access", fresh=False) + self._assert_jwt_structure(data["access_token"], expected_sub="1", expected_type="access") def test_refresh_token_invalid(self, register_user, login_user): # Access token test From eaff7aa90281435149cc35d9c32c032a8e0895f9 Mon Sep 17 00:00:00 2001 From: piyush-jaiswal Date: Thu, 21 Aug 2025 00:14:15 +0530 Subject: [PATCH 4/4] use actual user id in tests --- tests/test_auth.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/test_auth.py b/tests/test_auth.py index f6d09a1..52e07ab 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -115,8 +115,9 @@ def test_login_success(self, register_user, login_user): assert "access_token" in data assert "refresh_token" in data - self._assert_jwt_structure(data["access_token"], expected_sub="1", expected_type="access", fresh=True) - self._assert_jwt_structure(data["refresh_token"], expected_sub="1", expected_type="refresh") + user = self._verify_user_in_db(self.TEST_EMAIL) + self._assert_jwt_structure(data["access_token"], expected_sub=str(user.id), expected_type="access", fresh=True) + self._assert_jwt_structure(data["refresh_token"], expected_sub=str(user.id), expected_type="refresh") def test_login_invalid_password(self, register_user, login_user): register_user(self.TEST_EMAIL, self.TEST_PASSWORD) @@ -143,7 +144,8 @@ def test_refresh_token(self, register_user, login_user): assert data["access_token"] != original_access_token assert "refresh_token" not in data - self._assert_jwt_structure(data["access_token"], expected_sub="1", expected_type="access") + user = self._verify_user_in_db(self.TEST_EMAIL) + self._assert_jwt_structure(data["access_token"], expected_sub=str(user.id), expected_type="access") def test_refresh_token_invalid(self, register_user, login_user): # Access token test