/ conftest.py
conftest.py
1 import json 2 import sys 3 from pathlib import Path 4 from typing import Any 5 6 import pytest 7 8 # Add rules/ to sys.path so that `from simple_types import ...` inside rules works 9 # when pytest runs from the curator root directory. 10 sys.path.insert(0, str(Path(__file__).parent / "rules")) 11 12 13 @pytest.fixture 14 def valid_nip35_event() -> dict[str, Any]: 15 """Minimal valid NIP-35 event (kind 2003) with valid infohash and file tags.""" 16 return { 17 "id": "a" * 64, # Valid 64-char hex 18 "pubkey": "b" * 64, # Valid 64-char hex 19 "created_at": 1234567890, 20 "kind": 2003, 21 "tags": [ 22 ["title", "Example Torrent"], 23 ["x", "c" * 40], # Valid 40-char hex infohash 24 ["file", "example.mkv", "1073741824"], # 1GB file 25 ], 26 "content": "Example torrent description", 27 "sig": "d" * 128, # Valid 128-char hex signature 28 } 29 30 31 @pytest.fixture 32 def invalid_nip35_event_no_infohash(valid_nip35_event: dict[str, Any]) -> dict[str, Any]: 33 """NIP-35 event missing the 'x' tag (infohash).""" 34 event = valid_nip35_event.copy() 35 event["tags"] = [tag for tag in event["tags"] if tag[0] != "x"] 36 return event 37 38 39 @pytest.fixture 40 def invalid_nip35_event_bad_infohash(valid_nip35_event: dict[str, Any]) -> dict[str, Any]: 41 """NIP-35 event with invalid infohash (too short).""" 42 event = valid_nip35_event.copy() 43 event["tags"] = [ 44 tag if tag[0] != "x" else ["x", "abc123"] 45 for tag in event["tags"] 46 ] 47 return event 48 49 50 @pytest.fixture 51 def load_event_fixture(): 52 """Factory fixture to load events from JSON fixture files.""" 53 def _load(filename: str) -> list[dict[str, Any]]: 54 fixture_path = Path(__file__).parent / "tests" / "fixtures" / filename 55 with open(fixture_path) as f: 56 return json.load(f) 57 return _load 58 59 60 @pytest.fixture 61 def make_event(valid_nip35_event: dict[str, Any]): 62 """Factory fixture to create events with custom overrides.""" 63 def _make(**kwargs) -> dict[str, Any]: 64 event = valid_nip35_event.copy() 65 66 # Handle tags specially - allow override or merge 67 if "tags" in kwargs: 68 event["tags"] = kwargs.pop("tags") 69 70 # Override other fields 71 event.update(kwargs) 72 return event 73 74 return _make 75 76 77 @pytest.fixture 78 def sample_torrent_event() -> dict[str, Any]: 79 """Well-formed NIP-35 event with all required fields and multiple file tags.""" 80 return { 81 "id": "0" * 64, 82 "pubkey": "1" * 64, 83 "created_at": 1234567890, 84 "kind": 2003, 85 "tags": [ 86 ["title", "Test Movie 1080p BluRay"], 87 ["x", "abc123def456abc123def456abc123def4567890"], # 40-char hex 88 ["file", "Movie.mkv", "5368709120"], # 5GB 89 ["file", "Subs/English.srt", "52428"], # 51KB 90 ["tracker", "udp://tracker.example.com:6969/announce"], 91 ["i", "tcat:movies"], 92 ["t", "action"], 93 ], 94 "content": "A sample movie torrent for testing", 95 "sig": "2" * 128, 96 } 97 98 99 @pytest.fixture 100 def sample_invalid_event() -> dict[str, Any]: 101 """Event missing required fields (no infohash 'x' tag).""" 102 return { 103 "id": "3" * 64, 104 "pubkey": "4" * 64, 105 "created_at": 1234567890, 106 "kind": 2003, 107 "tags": [ 108 ["title", "Invalid Event"], 109 ["file", "test.txt", "1024"], 110 ], 111 "content": "Missing infohash", 112 "sig": "5" * 128, 113 } 114 115 116 @pytest.fixture 117 def sample_large_event() -> dict[str, Any]: 118 """Event with maximum-size fields (stress test).""" 119 return { 120 "id": "a" * 64, 121 "pubkey": "b" * 64, 122 "created_at": 1234567890, 123 "kind": 2003, 124 "tags": [ 125 ["title", "X" * 500], # Very long title 126 ["x", "c" * 40], 127 ["file", "a" * 255 + ".mkv", "1099511627776"], # 255-char filename, 1TB file 128 ] + [["file", f"file{i}.mp4", str(1024 * 1024 * i)] for i in range(100)], # 100 files 129 "content": "Y" * 10000, # Very long content 130 "sig": "d" * 128, 131 } 132 133 134 @pytest.fixture 135 def mock_ruleset() -> dict[str, Any]: 136 """Minimal ruleset config for testing.""" 137 return { 138 "name": "test-ruleset", 139 "version": "1.0.0", 140 "rules": [ 141 { 142 "id": "D-SCHEMA-03", 143 "type": "deterministic", 144 "enabled": True, 145 "requirements": [], 146 }, 147 { 148 "id": "P-QUALITY-01", 149 "type": "probabilistic", 150 "enabled": True, 151 "requirements": [], 152 }, 153 ], 154 } 155 156 157 @pytest.fixture 158 def test_client(): 159 """FastAPI TestClient fixture for integration tests.""" 160 try: 161 from main import app 162 from fastapi.testclient import TestClient 163 return TestClient(app) 164 except Exception as e: 165 pytest.skip(f"Failed to import app: {e}")