Manage Atom feeds in a persistent git repository
1"""Tests for Git store functionality.""" 2 3import json 4from datetime import datetime 5 6import pytest 7from pydantic import HttpUrl 8 9from thicket.core.git_store import GitStore 10from thicket.models import AtomEntry, DuplicateMap, UserMetadata 11 12 13class TestGitStore: 14 """Test the GitStore class.""" 15 16 def test_init_new_repo(self, temp_dir): 17 """Test initializing a new Git repository.""" 18 repo_path = temp_dir / "test_repo" 19 store = GitStore(repo_path) 20 21 assert store.repo_path == repo_path 22 assert store.repo is not None 23 assert repo_path.exists() 24 assert (repo_path / ".git").exists() 25 assert (repo_path / "index.json").exists() 26 assert (repo_path / "duplicates.json").exists() 27 28 def test_init_existing_repo(self, temp_dir): 29 """Test initializing with existing repository.""" 30 repo_path = temp_dir / "test_repo" 31 32 # Create first store 33 store1 = GitStore(repo_path) 34 store1.add_user("testuser", display_name="Test User") 35 36 # Create second store pointing to same repo 37 store2 = GitStore(repo_path) 38 user = store2.get_user("testuser") 39 40 assert user is not None 41 assert user.username == "testuser" 42 assert user.display_name == "Test User" 43 44 def test_add_user(self, temp_dir): 45 """Test adding a user to the Git store.""" 46 store = GitStore(temp_dir / "test_repo") 47 48 user = store.add_user( 49 username="testuser", 50 display_name="Test User", 51 email="test@example.com", 52 homepage="https://example.com", 53 icon="https://example.com/icon.png", 54 feeds=["https://example.com/feed.xml"], 55 ) 56 57 assert isinstance(user, UserMetadata) 58 assert user.username == "testuser" 59 assert user.display_name == "Test User" 60 assert user.email == "test@example.com" 61 assert user.homepage == "https://example.com" 62 assert user.icon == "https://example.com/icon.png" 63 assert user.feeds == ["https://example.com/feed.xml"] 64 assert user.directory == "testuser" 65 66 # Check that user directory was created 67 user_dir = store.repo_path / "testuser" 68 assert user_dir.exists() 69 assert (user_dir / "metadata.json").exists() 70 71 # Check metadata file content 72 with open(user_dir / "metadata.json") as f: 73 metadata = json.load(f) 74 assert metadata["username"] == "testuser" 75 assert metadata["display_name"] == "Test User" 76 77 def test_get_user(self, temp_dir): 78 """Test getting user metadata.""" 79 store = GitStore(temp_dir / "test_repo") 80 81 # Add user 82 store.add_user("testuser", display_name="Test User") 83 84 # Get user 85 user = store.get_user("testuser") 86 assert user is not None 87 assert user.username == "testuser" 88 assert user.display_name == "Test User" 89 90 # Try to get non-existent user 91 non_user = store.get_user("nonexistent") 92 assert non_user is None 93 94 def test_store_entry(self, temp_dir): 95 """Test storing an entry.""" 96 store = GitStore(temp_dir / "test_repo") 97 98 # Add user first 99 store.add_user("testuser") 100 101 # Create test entry 102 entry = AtomEntry( 103 id="https://example.com/entry/1", 104 title="Test Entry", 105 link=HttpUrl("https://example.com/entry/1"), 106 updated=datetime.now(), 107 summary="Test entry summary", 108 content="<p>Test content</p>", 109 ) 110 111 # Store entry 112 result = store.store_entry("testuser", entry) 113 assert result is True 114 115 # Check that entry file was created 116 user_dir = store.repo_path / "testuser" 117 entry_files = list(user_dir.glob("*.json")) 118 entry_files = [f for f in entry_files if f.name != "metadata.json"] 119 assert len(entry_files) == 1 120 121 # Check entry content 122 with open(entry_files[0]) as f: 123 stored_entry = json.load(f) 124 assert stored_entry["title"] == "Test Entry" 125 assert stored_entry["id"] == "https://example.com/entry/1" 126 127 def test_get_entry(self, temp_dir): 128 """Test retrieving an entry.""" 129 store = GitStore(temp_dir / "test_repo") 130 131 # Add user and entry 132 store.add_user("testuser") 133 entry = AtomEntry( 134 id="https://example.com/entry/1", 135 title="Test Entry", 136 link=HttpUrl("https://example.com/entry/1"), 137 updated=datetime.now(), 138 ) 139 store.store_entry("testuser", entry) 140 141 # Get entry 142 retrieved = store.get_entry("testuser", "https://example.com/entry/1") 143 assert retrieved is not None 144 assert retrieved.title == "Test Entry" 145 assert retrieved.id == "https://example.com/entry/1" 146 147 # Try to get non-existent entry 148 non_entry = store.get_entry("testuser", "https://example.com/nonexistent") 149 assert non_entry is None 150 151 def test_list_entries(self, temp_dir): 152 """Test listing entries for a user.""" 153 store = GitStore(temp_dir / "test_repo") 154 155 # Add user 156 store.add_user("testuser") 157 158 # Add multiple entries 159 for i in range(3): 160 entry = AtomEntry( 161 id=f"https://example.com/entry/{i}", 162 title=f"Test Entry {i}", 163 link=HttpUrl(f"https://example.com/entry/{i}"), 164 updated=datetime.now(), 165 ) 166 store.store_entry("testuser", entry) 167 168 # List all entries 169 entries = store.list_entries("testuser") 170 assert len(entries) == 3 171 172 # List with limit 173 limited = store.list_entries("testuser", limit=2) 174 assert len(limited) == 2 175 176 # List for non-existent user 177 none_entries = store.list_entries("nonexistent") 178 assert len(none_entries) == 0 179 180 def test_duplicates(self, temp_dir): 181 """Test duplicate management.""" 182 store = GitStore(temp_dir / "test_repo") 183 184 # Get initial duplicates (should be empty) 185 duplicates = store.get_duplicates() 186 assert isinstance(duplicates, DuplicateMap) 187 assert len(duplicates.duplicates) == 0 188 189 # Add duplicate 190 store.add_duplicate("https://example.com/dup", "https://example.com/canonical") 191 192 # Check duplicate was added 193 duplicates = store.get_duplicates() 194 assert len(duplicates.duplicates) == 1 195 assert duplicates.is_duplicate("https://example.com/dup") 196 assert duplicates.get_canonical("https://example.com/dup") == "https://example.com/canonical" 197 198 # Remove duplicate 199 result = store.remove_duplicate("https://example.com/dup") 200 assert result is True 201 202 # Check duplicate was removed 203 duplicates = store.get_duplicates() 204 assert len(duplicates.duplicates) == 0 205 assert not duplicates.is_duplicate("https://example.com/dup") 206 207 def test_search_entries(self, temp_dir): 208 """Test searching entries.""" 209 store = GitStore(temp_dir / "test_repo") 210 211 # Add user 212 store.add_user("testuser") 213 214 # Add entries with different content 215 entries_data = [ 216 ("Test Python Programming", "Learning Python basics"), 217 ("JavaScript Tutorial", "Advanced JavaScript concepts"), 218 ("Python Web Development", "Building web apps with Python"), 219 ] 220 221 for title, summary in entries_data: 222 entry = AtomEntry( 223 id=f"https://example.com/entry/{title.lower().replace(' ', '-')}", 224 title=title, 225 link=HttpUrl(f"https://example.com/entry/{title.lower().replace(' ', '-')}"), 226 updated=datetime.now(), 227 summary=summary, 228 ) 229 store.store_entry("testuser", entry) 230 231 # Search for Python entries 232 results = store.search_entries("Python") 233 assert len(results) == 2 234 235 # Search for specific user 236 results = store.search_entries("Python", username="testuser") 237 assert len(results) == 2 238 239 # Search with limit 240 results = store.search_entries("Python", limit=1) 241 assert len(results) == 1 242 243 # Search for non-existent term 244 results = store.search_entries("NonExistent") 245 assert len(results) == 0 246 247 def test_get_stats(self, temp_dir): 248 """Test getting repository statistics.""" 249 store = GitStore(temp_dir / "test_repo") 250 251 # Get initial stats 252 stats = store.get_stats() 253 assert stats["total_users"] == 0 254 assert stats["total_entries"] == 0 255 assert stats["total_duplicates"] == 0 256 257 # Add user and entries 258 store.add_user("testuser") 259 for i in range(3): 260 entry = AtomEntry( 261 id=f"https://example.com/entry/{i}", 262 title=f"Test Entry {i}", 263 link=HttpUrl(f"https://example.com/entry/{i}"), 264 updated=datetime.now(), 265 ) 266 store.store_entry("testuser", entry) 267 268 # Add duplicate 269 store.add_duplicate("https://example.com/dup", "https://example.com/canonical") 270 271 # Get updated stats 272 stats = store.get_stats() 273 assert stats["total_users"] == 1 274 assert stats["total_entries"] == 3 275 assert stats["total_duplicates"] == 1 276 assert "last_updated" in stats 277 assert "repository_size" in stats