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