"""Pytest-фикстуры для face-service. Подключение к локальному pgvector через DATABASE_URL из корневого .env. Тесты re-id логики работают на чистых эмбеддингах — модель InsightFace не нужна. """ import os import sys import uuid from pathlib import Path import pytest from dotenv import load_dotenv # Подгружаем корневой .env и .env сервиса. load_dotenv(Path(__file__).parent.parent / ".env") load_dotenv(Path(__file__).parent.parent.parent.parent / ".env") sys.path.insert(0, str(Path(__file__).parent.parent)) # Импортируем после load_dotenv, чтобы DATABASE_URL подцепился. from database import get_connection # noqa: E402 @pytest.fixture def db_conn(): conn = get_connection() yield conn conn.close() @pytest.fixture def seed_camera_and_track(db_conn): """Создаёт уникальные camera_id + track_id для теста и убирает после.""" camera_ids = [] track_ids = [] def _make(zone_code: str = "A"): cam_id = str(uuid.uuid4()) zone_id = str(uuid.uuid4()) track_id = str(uuid.uuid4()) with db_conn.cursor() as cur: cur.execute( "INSERT INTO zones (id, code, name) VALUES (%s, %s::\"ZoneCode\", %s)" " ON CONFLICT (code) DO NOTHING RETURNING id", (zone_id, zone_code, f"test-zone-{zone_code}"), ) row = cur.fetchone() if row is None: cur.execute('SELECT id FROM zones WHERE code = %s::"ZoneCode"', (zone_code,)) zone_id = str(cur.fetchone()[0]) cur.execute( "INSERT INTO cameras (id, name, zone_id) VALUES (%s, %s, %s)", (cam_id, f"test-cam-{cam_id[:6]}", zone_id), ) cur.execute( "INSERT INTO tracks (id, status, first_seen_at, last_seen_at, updated_at)" " VALUES (%s, 'UNMATCHED', NOW(), NOW(), NOW())", (track_id,), ) db_conn.commit() camera_ids.append(cam_id) track_ids.append(track_id) return cam_id, track_id yield _make # Cleanup with db_conn.cursor() as cur: if track_ids: cur.execute( "DELETE FROM face_embeddings WHERE track_id = ANY(%s::uuid[])", (track_ids,), ) cur.execute("DELETE FROM tracks WHERE id = ANY(%s::uuid[])", (track_ids,)) if camera_ids: cur.execute("DELETE FROM cameras WHERE id = ANY(%s::uuid[])", (camera_ids,)) db_conn.commit()