"""Regression coverage for opt-in persistent sessions and explicit logout.""" from django.contrib.auth import get_user_model from django.test import TestCase from rest_framework.test import APIClient from rest_framework_simplejwt.tokens import RefreshToken from .models import PersistentLoginSession class PersistentLoginTests(TestCase): def setUp(self): self.user = get_user_model().objects.create_user(username='persistent-user', password='correct-secret-123') self.client = APIClient() def login(self): response = self.client.post('/api/auth/login/', { 'username': 'persistent-user', 'password': 'correct-secret-123', }, format='json') self.assertEqual(response.status_code, 200, response.data) return response.data def test_refresh_is_persistent_without_an_expiration_date(self): tokens = self.login() session = PersistentLoginSession.objects.get(token_hash__isnull=False) self.assertIsNone(session.revoked_at) self.assertFalse(hasattr(session, 'expires_at')) self.assertNotIn('.', tokens['refresh']) # opaque, not a time-limited JWT for _ in range(3): response = self.client.post('/api/auth/refresh/', {'refresh': tokens['refresh']}, format='json') self.assertEqual(response.status_code, 200) self.assertIn('access', response.data) def test_logout_revokes_refresh_and_access(self): tokens = self.login() authenticated = APIClient() authenticated.credentials(HTTP_AUTHORIZATION=f"Bearer {tokens['access']}") self.assertEqual(authenticated.get('/api/auth/me/').status_code, 200) self.assertEqual(self.client.post('/api/auth/logout/', {'refresh': tokens['refresh']}, format='json').status_code, 204) self.assertEqual(self.client.post('/api/auth/refresh/', {'refresh': tokens['refresh']}, format='json').status_code, 401) self.assertEqual(authenticated.get('/api/auth/me/').status_code, 401) def test_password_change_invalidates_existing_session(self): tokens = self.login() self.user.set_password('different-secret-456') self.user.save(update_fields=['password']) self.assertEqual(self.client.post('/api/auth/refresh/', {'refresh': tokens['refresh']}, format='json').status_code, 401) authenticated = APIClient() authenticated.credentials(HTTP_AUTHORIZATION=f"Bearer {tokens['access']}") self.assertEqual(authenticated.get('/api/auth/me/').status_code, 401) def test_legacy_refresh_can_upgrade(self): old_refresh = str(RefreshToken.for_user(self.user)) response = self.client.post('/api/auth/refresh/', {'refresh': old_refresh}, format='json') self.assertEqual(response.status_code, 200, response.data) self.assertIn('access', response.data) self.assertIn('refresh', response.data) self.assertNotIn('.', response.data['refresh']) def test_invalid_credentials_never_create_a_session(self): response = self.client.post('/api/auth/login/', { 'username': 'persistent-user', 'password': 'wrong', }, format='json') self.assertIn(response.status_code, (400, 401)) self.assertFalse(PersistentLoginSession.objects.exists())