"""Unit tests for PostgresEventStore using a mocked psycopg2 pool.""" from __future__ import annotations import json from unittest.mock import MagicMock, patch import pytest # Patch psycopg2 before importing the module under test import sys mock_psycopg2 = MagicMock() mock_psycopg2.extras = MagicMock() sys.modules.setdefault("psycopg2", mock_psycopg2) sys.modules.setdefault("psycopg2.extras", mock_psycopg2.extras) sys.modules.setdefault("psycopg2.pool", MagicMock()) from app.infrastructure.perception.base_event_store import BaseEventStore SAMPLE_ROW = { "id": "pg-001", "source": "国标委", "source_label": "国家标准化管理委员会", "standard_code": "GB 18384-2025", "title": "电动汽车安全要求", "summary": "新增要求", "full_text_url": "https://openstd.samr.gov.cn", "status": "enacted", "impact_level": "high", "published_at": "2025-11-15", "effective_at": "2026-07-01", "category": "电动汽车安全", "tags": ["电池安全"], "obligations": None, "deadlines": None, "scope": None, "penalties": None, "content_hash": "abc123", "previous_hash": None, "change_summary": None, "changed_sections": None, "affected_docs": None, "crawled_at": "2026-06-05T10:00:00+00:00", "processed_at": None, "raw_storage_key": None, } def _make_store_with_pool(mock_pool): with patch("psycopg2.pool.ThreadedConnectionPool", return_value=mock_pool): with patch( "app.infrastructure.perception.postgres_event_store.PostgresEventStore._ensure_schema" ): from app.infrastructure.perception.postgres_event_store import PostgresEventStore return PostgresEventStore() def _cursor_returning(rows): cursor = MagicMock() cursor.__enter__ = lambda s: s cursor.__exit__ = MagicMock(return_value=False) cursor.fetchall.return_value = rows cursor.fetchone.return_value = rows[0] if rows else None return cursor def test_is_base_event_store(): mock_pool = MagicMock() store = _make_store_with_pool(mock_pool) assert isinstance(store, BaseEventStore) def test_filter_returns_list(): mock_pool = MagicMock() conn = MagicMock() conn.__enter__ = lambda s: s conn.__exit__ = MagicMock(return_value=False) cursor = _cursor_returning([SAMPLE_ROW]) conn.cursor.return_value = cursor mock_pool.getconn.return_value = conn store = _make_store_with_pool(mock_pool) result = store.filter(limit=10) assert isinstance(result, list) def test_stats_returns_correct_keys(): mock_pool = MagicMock() conn = MagicMock() conn.__enter__ = lambda s: s conn.__exit__ = MagicMock(return_value=False) cursor = MagicMock() cursor.__enter__ = lambda s: s cursor.__exit__ = MagicMock(return_value=False) cursor.fetchone.return_value = {"count": 5} conn.cursor.return_value = cursor mock_pool.getconn.return_value = conn store = _make_store_with_pool(mock_pool) stats = store.stats() for key in ("total", "high_impact", "medium_impact", "recent_90d"): assert key in stats