Coverage for test\test_session.py: 93%
56 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-21 20:31 +0100
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-21 20:31 +0100
1from http import cookies
2import os
3import json
4import pytest
5from datetime import datetime, timedelta, timezone
6from nexios import get_application, NexiosApp
7from nexios.http import Request, Response
8from nexios.session.base import BaseSessionInterface
9from nexios.session.file import FileSessionManager
10from nexios.session.signed_cookies import SignedSessionManager
11from nexios.testing import Client
12from nexios.config import MakeConfig, get_config, set_config
13from typing import Tuple, Dict, Any
16# Fixtures for different session configurations
17@pytest.fixture
18async def file_session_client(tmp_path) -> Tuple[Client, NexiosApp]:
19 """Client with file-based session configuration"""
20 app = get_application(
21 MakeConfig(
22 {
23 "secret_key": "file_session_secret",
24 "session": {
25 "session_cookie_name": "file_session",
26 "session_permanent": True,
27 "session_expiration_time": 30,
28 "manager": FileSessionManager,
29 },
30 "session_file_name": str(tmp_path / "sessions"),
31 "SESSION_FILE_STORAGE_PATH": str(tmp_path / "sessions"),
32 }
33 )
34 )
35 async with Client(app) as client:
36 yield client, app
39@pytest.fixture
40async def signed_session_client() -> Tuple[Client, NexiosApp]:
41 """Client with signed cookie session configuration"""
42 app = get_application(
43 MakeConfig(
44 {
45 "secret_key": "signed_session_secret",
46 "session": {
47 "session_cookie_name": "signed_session",
48 "session_permanent": True,
49 "session_expiration_time": 30,
50 "manager": SignedSessionManager,
51 },
52 }
53 )
54 )
55 async with Client(app) as client:
56 yield client, app
59# # Test session middleware
60async def test_session_middleware_initialization(
61 file_session_client: Tuple[Client, NexiosApp],
62):
63 client, app = file_session_client
65 @app.get("/test-session")
66 async def test_session(req: Request, res: Response):
68 req.session["key"] = "value"
69 return res.text("OK")
71 response = await client.get("/test-session")
72 assert response.status_code == 200
73 assert response.text == "OK"
76async def test_session_middleware_no_secret_key():
77 app = get_application(MakeConfig({"secret_key": None}))
79 @app.get("/test-session")
80 async def test_session(req: Request, res: Response):
81 try:
82 req.session["key"] = "value"
83 except AssertionError:
84 return res.text("No session", status_code=512)
85 return res.text("OK")
87 async with Client(app) as client:
88 response = await client.get("/test-session")
89 assert response.status_code == 512
90 assert response.text == "No session"
93# # Test file session manager
94# async def test_file_session_operations(
95# file_session_client: Tuple[Client, NexiosApp], tmp_path
96# ):
97# client, app = file_session_client
99# @app.get("/set-session")
100# async def set_session(req: Request, res: Response):
101# req.session["test_key"] = "test_value"
102# req.session["user"] = {"id": 1, "name": "Test"}
103# return res.text("Session set")
105# @app.get("/get-session")
106# async def get_session(req: Request, res: Response):
107# return res.json(
108# {"test_key": req.session.get("test_key"), "user": req.session.get("user")}
109# )
111# @app.get("/delete-session")
112# async def delete_session(req: Request, res: Response):
113# del req.session["test_key"]
114# return res.text("Session deleted")
116# @app.get("/clear-session")
117# async def clear_session(req: Request, res: Response):
118# req.session.clear()
119# return res.text("Session cleared")
121# # # Set session
122# response = await client.get("/set-session")
123# assert response.status_code == 200
125# # Verify cookie was set
126# assert "file_session" in response.cookies
128# session_id = response.cookies["file_session"]
130# # # Verify session file was created
131# session_file = tmp_path / "sessions" / f"{session_id}.json"
132# assert session_file.exists()
134# response = await client.get("/get-session")
135# assert response.status_code == 200
136# # assert response.json() == {
137# # "test_key": "test_value",
138# # "user": {"id": 1, "name": "Test"},
139# # }
141# # Delete item from session
142# response = await client.get("/delete-session")
143# # assert response.status_code == 200
145# # Verify deletion
146# response = await client.get("/get-session")
147# # assert response.json()["test_key"] is None
149# # Clear session
150# response = await client.get("/clear-session")
151# # assert response.status_code == 200
152# # assert not session_file.exists()
155# # Test signed cookie session manager
156# async def test_signed_session_operations(signed_session_client: Tuple[Client, NexiosApp]):
157# client, app = signed_session_client
159# @app.get("/set-session")
160# async def set_session(req: Request, res: Response):
161# req.session["test_key"] = "test_value"
162# req.session["user"] = {"id": 1, "name": "Test"}
163# return res.text("Session set")
165# @app.get("/get-session")
166# async def get_session(req: Request, res: Response):
167# return res.json({
168# "test_key": req.session.get("test_key"),
169# "user": req.session.get("user")
170# })
172# # Set session
173# response = await client.get("/set-session")
174# assert response.status_code == 200
176# # Verify cookie was set
177# assert "signed_session" in response.cookies
178# session_cookie = response.cookies["signed_session"]
180# # Get session
181# response = await client.get("/get-session")
182# assert response.status_code == 200
183# assert response.json() == {
184# "test_key": "test_value",
185# "user": {"id": 1, "name": "Test"}
186# }
188# # Test with invalid cookie
189# client.cookies["signed_session"] = "invalid.token"
190# response = await client.get("/get-session")
191# assert response.status_code == 200
192# assert response.json() == {
193# "test_key": None,
194# "user": None
195# }
197# # Test session expiration
198# async def test_session_expiration(file_session_client: Tuple[Client, NexiosApp]):
199# client, app = file_session_client
201# @app.get("/set-expiring-session")
202# async def set_expiring_session(req: Request, res: Response):
203# req.session["temp"] = "data"
204# # Set expiration to 1 second from now
205# req.session._session_cache["__expires"] = (
206# datetime.now(timezone.utc) + timedelta(seconds=1)
207# ).isoformat()
208# return res.text("Session set")
210# @app.get("/check-expired")
211# async def check_expired(req: Request, res: Response):
212# return res.json({"expired": req.session.has_expired()})
214# # Set session
215# response = await client.get("/set-expiring-session")
216# assert response.status_code == 200
218# # Check immediately - should not be expired
219# response = await client.get("/check-expired")
220# assert response.status_code == 200
221# assert response.json()["expired"] is False
223# # Wait for expiration
224# import time
225# time.sleep(2)
227# # Check again - should be expired
228# response = await client.get("/check-expired")
229# assert response.status_code == 200
230# assert response.json()["expired"] is True
232# # Test session cookie settings
233# async def test_session_cookie_settings(file_session_client: Tuple[Client, NexiosApp]):
234# client, app = file_session_client
236# # Update cookie settings
237# app.config.session.session_cookie_httponly = True
238# app.config.session.session_cookie_secure = True
239# app.config.session.session_cookie_samesite = "lax"
240# app.config.session.session_cookie_path = "/test"
241# app.config.session.session_cookie_domain = "example.com"
243# @app.get("/set-cookie-settings")
244# async def set_cookie_settings(req: Request, res: Response):
245# req.session["test"] = "value"
246# return res.text("OK")
248# response = await client.get("/set-cookie-settings")
249# assert response.status_code == 200
252# cookie = response.cookies["file_session"]
253# assert cookie["httponly"] is True
254# assert cookie["secure"] is True
255# assert cookie["samesite"] == "lax"
256# assert cookie["path"] == "/test"
257# assert cookie["domain"] == "example.com"
258# async def test_signed_session_operations(
259# signed_session_client: Tuple[Client, NexiosApp],
260# ):
261# client, app = signed_session_client
263# @app.get("/set-session")
264# async def set_session(req: Request, res: Response):
265# req.session["test_key"] = "test_value"
266# req.session["user"] = {"id": 1, "name": "Test"}
267# return res.text("Session set")
269# @app.get("/get-session")
270# async def get_session(req: Request, res: Response):
271# return res.json(
272# {"test_key": req.session.get("test_key"), "user": req.session.get("user")}
273# )
275# # Set session
276# response = await client.get("/set-session")
277# assert response.status_code == 200
279# # Verify cookie was set
280# assert "signed_session" in response.cookies
281# session_cookie = response.cookies["signed_session"]
283# # Get session
284# response = await client.get("/get-session")
285# assert response.status_code == 200
286# assert response.json() == {
287# "test_key": "test_value",
288# "user": {"id": 1, "name": "Test"},
289# }
291# # Test with invalid cookie
292# client.cookies["signed_session"] = "invalid.token"
293# response = await client.get("/get-session")
294# assert response.status_code == 200
295# assert response.json() == {"test_key": None, "user": None}
298# Test session cookie settings
299async def test_session_cookie_settings(file_session_client: Tuple[Client, NexiosApp]):
300 client, app = file_session_client
302 # Update cookie settings
303 app.config.session.session_cookie_httponly = True
304 app.config.session.session_permanent = False
306 @app.get("/set-cookie-settings")
307 async def set_cookie_settings(req: Request, res: Response):
308 req.session["test"] = "value"
309 return res.text("OK")
311 response = await client.get("/set-cookie-settings")
312 assert response.status_code == 200
314 cookie = response.cookies["file_session"]
315 # assert cookie["httponly"] is True
316 # assert cookie["secure"] is True
317 # assert cookie["samesite"] == "lax"
318 # assert cookie["path"] == "/test"
319 # assert cookie["domain"] == "example.com"
322# # Test session middleware with custom manager
323# async def test_custom_session_manager(file_session_client: Tuple[Client, NexiosApp]):
324# # Define a simple in-memory session manager for testing
325# class MemorySessionManager(BaseSessionInterface):
326# _store: Dict[str, Dict[str, Any]] = {}
328# async def load(self):
329# self._session_cache = self._store.get(self.session_key, {})
331# async def save(self):
332# self._store[self.session_key] = self._session_cache
334# # app = get_application(MakeConfig({
335# # "secret_key": "custom_session_secret",
336# # "session": {
337# # "manager": MemorySessionManager,
338# # "session_cookie_name": "custom_session"
339# # }
340# # }))
341# client, app = file_session_client
342# app.config.session.manager = MemorySessionManager
343# app.config.session.session_cookie_name = "custom"
345# @app.get("/test-custom-manager")
346# async def test_custom_manager(req: Request, res: Response):
348# if "count" not in req.session:
349# req.session["count"] = 1
350# else:
352# req.session["count"] += 1
353# return res.json({"count": req.session["count"]})
355# async with Client(app) as client:
356# # First request
357# response = await client.get("/test-custom-manager")
358# assert response.status_code == 200
359# assert response.json()["count"] == 1
361# # Second request
362# response = await client.get("/test-custom-manager")
363# assert response.status_code == 200
364# assert response.json()["count"] == 2
366# # New client should start fresh
367# async with Client(app) as new_client:
368# response = await new_client.get("/test-custom-manager")
369# assert response.status_code == 200
370# assert response.json()["count"] == 1