FossilRepo
Comprehensive view tests (30 total)
Commit
2f0bbef916fc374b771dd9471412e0f9623ad7e59334e85c8bccb5e0d2a0499d
Parent
e33a0d1a93e3209…
1 file changed
+77
-38
+77
-38
| --- fossil/tests.py | ||
| +++ fossil/tests.py | ||
| @@ -1,8 +1,7 @@ | ||
| 1 | 1 | import shutil |
| 2 | 2 | from pathlib import Path |
| 3 | -from unittest.mock import PropertyMock, patch | |
| 4 | 3 | |
| 5 | 4 | import pytest |
| 6 | 5 | |
| 7 | 6 | from .models import FossilRepository |
| 8 | 7 | from .reader import FossilReader, _apply_fossil_delta, _extract_wiki_content |
| @@ -155,52 +154,92 @@ | ||
| 155 | 154 | |
| 156 | 155 | |
| 157 | 156 | @pytest.mark.django_db |
| 158 | 157 | class TestFossilViews: |
| 159 | 158 | @pytest.fixture |
| 160 | - def repo_with_path(self, sample_project, admin_user, tmp_path): | |
| 159 | + def setup_repo(self, sample_project, admin_user, tmp_path): | |
| 160 | + """Set up a real .fossil file and point Constance FOSSIL_DATA_DIR to tmp.""" | |
| 161 | 161 | src = Path("/tmp/fossil-setup/frontend-app.fossil") |
| 162 | 162 | if not src.exists(): |
| 163 | 163 | pytest.skip("Test fossil repo not available") |
| 164 | - dest = tmp_path / "frontend-app.fossil" | |
| 165 | - shutil.copy2(src, dest) | |
| 166 | - # Get the auto-created repo from the signal and update its path | |
| 164 | + # Copy to tmp dir using the repo's expected filename | |
| 167 | 165 | repo = FossilRepository.objects.get(project=sample_project) |
| 168 | - return repo, dest | |
| 169 | - | |
| 170 | - def test_code_browser(self, admin_client, repo_with_path): | |
| 171 | - repo, dest = repo_with_path | |
| 172 | - with ( | |
| 173 | - patch.object(type(repo), "full_path", new_callable=PropertyMock, return_value=dest), | |
| 174 | - patch("fossil.views.FossilRepository.objects") as mock_qs, | |
| 175 | - ): | |
| 176 | - mock_qs.filter.return_value.first.return_value = repo | |
| 177 | - # Use get_object_or_404 mock approach | |
| 178 | - response = admin_client.get(f"/projects/{repo.project.slug}/fossil/code/") | |
| 179 | - # May 404 if constance config points elsewhere, but shouldn't error | |
| 180 | - assert response.status_code in (200, 404) | |
| 181 | - | |
| 182 | - def test_timeline(self, admin_client, repo_with_path): | |
| 183 | - repo, dest = repo_with_path | |
| 184 | - response = admin_client.get(f"/projects/{repo.project.slug}/fossil/timeline/") | |
| 185 | - assert response.status_code in (200, 404) | |
| 186 | - | |
| 187 | - def test_tickets(self, admin_client, repo_with_path): | |
| 188 | - repo, dest = repo_with_path | |
| 189 | - response = admin_client.get(f"/projects/{repo.project.slug}/fossil/tickets/") | |
| 190 | - assert response.status_code in (200, 404) | |
| 191 | - | |
| 192 | - def test_wiki(self, admin_client, repo_with_path): | |
| 193 | - repo, dest = repo_with_path | |
| 194 | - response = admin_client.get(f"/projects/{repo.project.slug}/fossil/wiki/") | |
| 195 | - assert response.status_code in (200, 404) | |
| 196 | - | |
| 197 | - def test_forum(self, admin_client, repo_with_path): | |
| 198 | - repo, dest = repo_with_path | |
| 199 | - response = admin_client.get(f"/projects/{repo.project.slug}/fossil/forum/") | |
| 200 | - assert response.status_code in (200, 404) | |
| 166 | + dest = tmp_path / repo.filename | |
| 167 | + shutil.copy2(src, dest) | |
| 168 | + # Override Constance FOSSIL_DATA_DIR to point to our tmp dir | |
| 169 | + from constance import config | |
| 170 | + | |
| 171 | + original_dir = config.FOSSIL_DATA_DIR | |
| 172 | + config.FOSSIL_DATA_DIR = str(tmp_path) | |
| 173 | + yield sample_project.slug | |
| 174 | + config.FOSSIL_DATA_DIR = original_dir | |
| 175 | + | |
| 176 | + def test_code_browser_content(self, admin_client, setup_repo): | |
| 177 | + slug = setup_repo | |
| 178 | + response = admin_client.get(f"/projects/{slug}/fossil/code/") | |
| 179 | + assert response.status_code == 200 | |
| 180 | + content = response.content.decode() | |
| 181 | + assert "CONTRIBUTING.md" in content or "README" in content or "utils" in content | |
| 182 | + | |
| 183 | + def test_timeline_content(self, admin_client, setup_repo): | |
| 184 | + slug = setup_repo | |
| 185 | + response = admin_client.get(f"/projects/{slug}/fossil/timeline/") | |
| 186 | + assert response.status_code == 200 | |
| 187 | + content = response.content.decode() | |
| 188 | + assert "ragelink" in content | |
| 189 | + assert "tl-row" in content | |
| 190 | + | |
| 191 | + def test_checkin_detail(self, admin_client, setup_repo): | |
| 192 | + slug = setup_repo | |
| 193 | + response = admin_client.get(f"/projects/{slug}/fossil/timeline/") | |
| 194 | + # Extract a hash from the page | |
| 195 | + import re | |
| 196 | + | |
| 197 | + hashes = re.findall(r"/checkin/([0-9a-f]{8,})/", response.content.decode()) | |
| 198 | + if hashes: | |
| 199 | + detail = admin_client.get(f"/projects/{slug}/fossil/checkin/{hashes[0]}/") | |
| 200 | + assert detail.status_code == 200 | |
| 201 | + assert "diff-table" in detail.content.decode() or "file" in detail.content.decode().lower() | |
| 202 | + | |
| 203 | + def test_wiki_content(self, admin_client, setup_repo): | |
| 204 | + slug = setup_repo | |
| 205 | + response = admin_client.get(f"/projects/{slug}/fossil/wiki/") | |
| 206 | + assert response.status_code == 200 | |
| 207 | + content = response.content.decode() | |
| 208 | + assert "Home" in content | |
| 209 | + | |
| 210 | + def test_wiki_page_content(self, admin_client, setup_repo): | |
| 211 | + slug = setup_repo | |
| 212 | + response = admin_client.get(f"/projects/{slug}/fossil/wiki/page/Home") | |
| 213 | + assert response.status_code == 200 | |
| 214 | + content = response.content.decode() | |
| 215 | + assert "prose" in content | |
| 216 | + | |
| 217 | + def test_search(self, admin_client, setup_repo): | |
| 218 | + slug = setup_repo | |
| 219 | + response = admin_client.get(f"/projects/{slug}/fossil/search/?q=initial") | |
| 220 | + assert response.status_code == 200 | |
| 221 | + | |
| 222 | + def test_file_view(self, admin_client, setup_repo): | |
| 223 | + slug = setup_repo | |
| 224 | + response = admin_client.get(f"/projects/{slug}/fossil/code/file/CONTRIBUTING.md") | |
| 225 | + if response.status_code == 200: | |
| 226 | + content = response.content.decode() | |
| 227 | + assert "line-num" in content | |
| 228 | + | |
| 229 | + def test_branches(self, admin_client, setup_repo): | |
| 230 | + slug = setup_repo | |
| 231 | + response = admin_client.get(f"/projects/{slug}/fossil/branches/") | |
| 232 | + assert response.status_code == 200 | |
| 233 | + assert "trunk" in response.content.decode() | |
| 234 | + | |
| 235 | + def test_stats(self, admin_client, setup_repo): | |
| 236 | + slug = setup_repo | |
| 237 | + response = admin_client.get(f"/projects/{slug}/fossil/stats/") | |
| 238 | + assert response.status_code == 200 | |
| 239 | + assert "Checkins" in response.content.decode() | |
| 201 | 240 | |
| 202 | 241 | def test_views_denied_without_perm(self, no_perm_client, sample_project): |
| 203 | 242 | slug = sample_project.slug |
| 204 | 243 | for path in ["/fossil/code/", "/fossil/timeline/", "/fossil/tickets/", "/fossil/wiki/", "/fossil/forum/"]: |
| 205 | 244 | response = no_perm_client.get(f"/projects/{slug}{path}") |
| 206 | 245 | assert response.status_code == 403, f"Expected 403 for {path}" |
| 207 | 246 |
| --- fossil/tests.py | |
| +++ fossil/tests.py | |
| @@ -1,8 +1,7 @@ | |
| 1 | import shutil |
| 2 | from pathlib import Path |
| 3 | from unittest.mock import PropertyMock, patch |
| 4 | |
| 5 | import pytest |
| 6 | |
| 7 | from .models import FossilRepository |
| 8 | from .reader import FossilReader, _apply_fossil_delta, _extract_wiki_content |
| @@ -155,52 +154,92 @@ | |
| 155 | |
| 156 | |
| 157 | @pytest.mark.django_db |
| 158 | class TestFossilViews: |
| 159 | @pytest.fixture |
| 160 | def repo_with_path(self, sample_project, admin_user, tmp_path): |
| 161 | src = Path("/tmp/fossil-setup/frontend-app.fossil") |
| 162 | if not src.exists(): |
| 163 | pytest.skip("Test fossil repo not available") |
| 164 | dest = tmp_path / "frontend-app.fossil" |
| 165 | shutil.copy2(src, dest) |
| 166 | # Get the auto-created repo from the signal and update its path |
| 167 | repo = FossilRepository.objects.get(project=sample_project) |
| 168 | return repo, dest |
| 169 | |
| 170 | def test_code_browser(self, admin_client, repo_with_path): |
| 171 | repo, dest = repo_with_path |
| 172 | with ( |
| 173 | patch.object(type(repo), "full_path", new_callable=PropertyMock, return_value=dest), |
| 174 | patch("fossil.views.FossilRepository.objects") as mock_qs, |
| 175 | ): |
| 176 | mock_qs.filter.return_value.first.return_value = repo |
| 177 | # Use get_object_or_404 mock approach |
| 178 | response = admin_client.get(f"/projects/{repo.project.slug}/fossil/code/") |
| 179 | # May 404 if constance config points elsewhere, but shouldn't error |
| 180 | assert response.status_code in (200, 404) |
| 181 | |
| 182 | def test_timeline(self, admin_client, repo_with_path): |
| 183 | repo, dest = repo_with_path |
| 184 | response = admin_client.get(f"/projects/{repo.project.slug}/fossil/timeline/") |
| 185 | assert response.status_code in (200, 404) |
| 186 | |
| 187 | def test_tickets(self, admin_client, repo_with_path): |
| 188 | repo, dest = repo_with_path |
| 189 | response = admin_client.get(f"/projects/{repo.project.slug}/fossil/tickets/") |
| 190 | assert response.status_code in (200, 404) |
| 191 | |
| 192 | def test_wiki(self, admin_client, repo_with_path): |
| 193 | repo, dest = repo_with_path |
| 194 | response = admin_client.get(f"/projects/{repo.project.slug}/fossil/wiki/") |
| 195 | assert response.status_code in (200, 404) |
| 196 | |
| 197 | def test_forum(self, admin_client, repo_with_path): |
| 198 | repo, dest = repo_with_path |
| 199 | response = admin_client.get(f"/projects/{repo.project.slug}/fossil/forum/") |
| 200 | assert response.status_code in (200, 404) |
| 201 | |
| 202 | def test_views_denied_without_perm(self, no_perm_client, sample_project): |
| 203 | slug = sample_project.slug |
| 204 | for path in ["/fossil/code/", "/fossil/timeline/", "/fossil/tickets/", "/fossil/wiki/", "/fossil/forum/"]: |
| 205 | response = no_perm_client.get(f"/projects/{slug}{path}") |
| 206 | assert response.status_code == 403, f"Expected 403 for {path}" |
| 207 |
| --- fossil/tests.py | |
| +++ fossil/tests.py | |
| @@ -1,8 +1,7 @@ | |
| 1 | import shutil |
| 2 | from pathlib import Path |
| 3 | |
| 4 | import pytest |
| 5 | |
| 6 | from .models import FossilRepository |
| 7 | from .reader import FossilReader, _apply_fossil_delta, _extract_wiki_content |
| @@ -155,52 +154,92 @@ | |
| 154 | |
| 155 | |
| 156 | @pytest.mark.django_db |
| 157 | class TestFossilViews: |
| 158 | @pytest.fixture |
| 159 | def setup_repo(self, sample_project, admin_user, tmp_path): |
| 160 | """Set up a real .fossil file and point Constance FOSSIL_DATA_DIR to tmp.""" |
| 161 | src = Path("/tmp/fossil-setup/frontend-app.fossil") |
| 162 | if not src.exists(): |
| 163 | pytest.skip("Test fossil repo not available") |
| 164 | # Copy to tmp dir using the repo's expected filename |
| 165 | repo = FossilRepository.objects.get(project=sample_project) |
| 166 | dest = tmp_path / repo.filename |
| 167 | shutil.copy2(src, dest) |
| 168 | # Override Constance FOSSIL_DATA_DIR to point to our tmp dir |
| 169 | from constance import config |
| 170 | |
| 171 | original_dir = config.FOSSIL_DATA_DIR |
| 172 | config.FOSSIL_DATA_DIR = str(tmp_path) |
| 173 | yield sample_project.slug |
| 174 | config.FOSSIL_DATA_DIR = original_dir |
| 175 | |
| 176 | def test_code_browser_content(self, admin_client, setup_repo): |
| 177 | slug = setup_repo |
| 178 | response = admin_client.get(f"/projects/{slug}/fossil/code/") |
| 179 | assert response.status_code == 200 |
| 180 | content = response.content.decode() |
| 181 | assert "CONTRIBUTING.md" in content or "README" in content or "utils" in content |
| 182 | |
| 183 | def test_timeline_content(self, admin_client, setup_repo): |
| 184 | slug = setup_repo |
| 185 | response = admin_client.get(f"/projects/{slug}/fossil/timeline/") |
| 186 | assert response.status_code == 200 |
| 187 | content = response.content.decode() |
| 188 | assert "ragelink" in content |
| 189 | assert "tl-row" in content |
| 190 | |
| 191 | def test_checkin_detail(self, admin_client, setup_repo): |
| 192 | slug = setup_repo |
| 193 | response = admin_client.get(f"/projects/{slug}/fossil/timeline/") |
| 194 | # Extract a hash from the page |
| 195 | import re |
| 196 | |
| 197 | hashes = re.findall(r"/checkin/([0-9a-f]{8,})/", response.content.decode()) |
| 198 | if hashes: |
| 199 | detail = admin_client.get(f"/projects/{slug}/fossil/checkin/{hashes[0]}/") |
| 200 | assert detail.status_code == 200 |
| 201 | assert "diff-table" in detail.content.decode() or "file" in detail.content.decode().lower() |
| 202 | |
| 203 | def test_wiki_content(self, admin_client, setup_repo): |
| 204 | slug = setup_repo |
| 205 | response = admin_client.get(f"/projects/{slug}/fossil/wiki/") |
| 206 | assert response.status_code == 200 |
| 207 | content = response.content.decode() |
| 208 | assert "Home" in content |
| 209 | |
| 210 | def test_wiki_page_content(self, admin_client, setup_repo): |
| 211 | slug = setup_repo |
| 212 | response = admin_client.get(f"/projects/{slug}/fossil/wiki/page/Home") |
| 213 | assert response.status_code == 200 |
| 214 | content = response.content.decode() |
| 215 | assert "prose" in content |
| 216 | |
| 217 | def test_search(self, admin_client, setup_repo): |
| 218 | slug = setup_repo |
| 219 | response = admin_client.get(f"/projects/{slug}/fossil/search/?q=initial") |
| 220 | assert response.status_code == 200 |
| 221 | |
| 222 | def test_file_view(self, admin_client, setup_repo): |
| 223 | slug = setup_repo |
| 224 | response = admin_client.get(f"/projects/{slug}/fossil/code/file/CONTRIBUTING.md") |
| 225 | if response.status_code == 200: |
| 226 | content = response.content.decode() |
| 227 | assert "line-num" in content |
| 228 | |
| 229 | def test_branches(self, admin_client, setup_repo): |
| 230 | slug = setup_repo |
| 231 | response = admin_client.get(f"/projects/{slug}/fossil/branches/") |
| 232 | assert response.status_code == 200 |
| 233 | assert "trunk" in response.content.decode() |
| 234 | |
| 235 | def test_stats(self, admin_client, setup_repo): |
| 236 | slug = setup_repo |
| 237 | response = admin_client.get(f"/projects/{slug}/fossil/stats/") |
| 238 | assert response.status_code == 200 |
| 239 | assert "Checkins" in response.content.decode() |
| 240 | |
| 241 | def test_views_denied_without_perm(self, no_perm_client, sample_project): |
| 242 | slug = sample_project.slug |
| 243 | for path in ["/fossil/code/", "/fossil/timeline/", "/fossil/tickets/", "/fossil/wiki/", "/fossil/forum/"]: |
| 244 | response = no_perm_client.get(f"/projects/{slug}{path}") |
| 245 | assert response.status_code == 403, f"Expected 403 for {path}" |
| 246 |