""" Tests for web/db.py — user store and refresh token management. """ import pytest from pathlib import Path @pytest.fixture def tmp_db(tmp_path, monkeypatch): """Point web.db at a temp file for each test.""" import web.db as db_mod db_path = tmp_path / "test_web.db" monkeypatch.setattr(db_mod, "DB_FILE", db_path) db_mod.init_db() return db_mod class TestInitDb: def test_creates_superadmin_on_first_run(self, tmp_db): import os admin_user = os.environ["WEB_ADMIN_USER"] user = tmp_db.get_user_by_username(admin_user) assert user is not None assert user["role"] == "superadmin" assert user["is_active"] == 1 def test_second_init_does_not_duplicate(self, tmp_db): import os admin_user = os.environ["WEB_ADMIN_USER"] tmp_db.init_db() # second call users = tmp_db.list_users() assert len([u for u in users if u["username"] == admin_user]) == 1 class TestUserCRUD: def test_create_and_get_user(self, tmp_db): uid = tmp_db.create_user("alice", "pass1", "reader") user = tmp_db.get_user_by_id(uid) assert user["username"] == "alice" assert user["role"] == "reader" def test_get_by_username(self, tmp_db): tmp_db.create_user("bob", "pass2", "admin") user = tmp_db.get_user_by_username("bob") assert user is not None assert user["role"] == "admin" def test_update_role(self, tmp_db): uid = tmp_db.create_user("carol", "pass3", "reader") tmp_db.update_user(uid, role="admin") user = tmp_db.get_user_by_id(uid) assert user["role"] == "admin" def test_update_password_is_hashed(self, tmp_db): from web.auth import verify_password uid = tmp_db.create_user("dave", "oldpass", "reader") tmp_db.update_user(uid, password="newpass") user = tmp_db.get_user_by_id(uid) assert verify_password("newpass", user["password_hash"]) assert not verify_password("oldpass", user["password_hash"]) def test_deactivate_user(self, tmp_db): uid = tmp_db.create_user("eve", "pass4", "reader") tmp_db.deactivate_user(uid) # get_user_by_username filters is_active=1 assert tmp_db.get_user_by_username("eve") is None # get_user_by_id still returns the row user = tmp_db.get_user_by_id(uid) assert user["is_active"] == 0 def test_list_users(self, tmp_db): tmp_db.create_user("u1", "p", "reader") tmp_db.create_user("u2", "p", "admin") users = tmp_db.list_users() usernames = [u["username"] for u in users] assert "u1" in usernames assert "u2" in usernames class TestRefreshTokens: def test_store_and_validate(self, tmp_db): from datetime import datetime, timedelta, timezone import uuid jti = str(uuid.uuid4()) expires_at = datetime.now(timezone.utc) + timedelta(days=7) tmp_db.store_refresh_token(jti, "user-x", expires_at) assert tmp_db.is_refresh_token_valid(jti) def test_revoked_token_invalid(self, tmp_db): from datetime import datetime, timedelta, timezone import uuid jti = str(uuid.uuid4()) expires_at = datetime.now(timezone.utc) + timedelta(days=7) tmp_db.store_refresh_token(jti, "user-x", expires_at) tmp_db.revoke_refresh_token(jti) assert not tmp_db.is_refresh_token_valid(jti) def test_expired_token_invalid(self, tmp_db): from datetime import datetime, timedelta, timezone import uuid jti = str(uuid.uuid4()) expires_at = datetime.now(timezone.utc) - timedelta(seconds=1) tmp_db.store_refresh_token(jti, "user-x", expires_at) assert not tmp_db.is_refresh_token_valid(jti) def test_unknown_jti_invalid(self, tmp_db): assert not tmp_db.is_refresh_token_valid("nonexistent-jti")