test_admin_views.py 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. """
  2. Tests for admin snapshot views and search functionality.
  3. Tests cover:
  4. - Admin snapshot list view
  5. - Admin grid view
  6. - Search functionality (both admin and public)
  7. - Snapshot progress statistics
  8. """
  9. import pytest
  10. from django.test import TestCase, Client, override_settings
  11. from django.urls import reverse
  12. from django.contrib.auth import get_user_model
  13. pytestmark = pytest.mark.django_db
  14. User = get_user_model()
  15. @pytest.fixture
  16. def admin_user(db):
  17. """Create admin user for tests."""
  18. return User.objects.create_superuser(
  19. username='testadmin',
  20. email='[email protected]',
  21. password='testpassword'
  22. )
  23. @pytest.fixture
  24. def crawl(admin_user, db):
  25. """Create test crawl."""
  26. from archivebox.crawls.models import Crawl
  27. return Crawl.objects.create(
  28. urls='https://example.com',
  29. created_by=admin_user,
  30. )
  31. @pytest.fixture
  32. def snapshot(crawl, db):
  33. """Create test snapshot."""
  34. from archivebox.core.models import Snapshot
  35. return Snapshot.objects.create(
  36. url='https://example.com',
  37. crawl=crawl,
  38. status=Snapshot.StatusChoices.STARTED,
  39. )
  40. class TestSnapshotProgressStats:
  41. """Tests for Snapshot.get_progress_stats() method."""
  42. def test_get_progress_stats_empty(self, snapshot):
  43. """Test progress stats with no archive results."""
  44. stats = snapshot.get_progress_stats()
  45. assert stats['total'] == 0
  46. assert stats['succeeded'] == 0
  47. assert stats['failed'] == 0
  48. assert stats['running'] == 0
  49. assert stats['pending'] == 0
  50. assert stats['percent'] == 0
  51. assert stats['output_size'] == 0
  52. assert stats['is_sealed'] is False
  53. def test_get_progress_stats_with_results(self, snapshot, db):
  54. """Test progress stats with various archive result statuses."""
  55. from archivebox.core.models import ArchiveResult
  56. # Create some archive results
  57. ArchiveResult.objects.create(
  58. snapshot=snapshot,
  59. plugin='wget',
  60. status='succeeded',
  61. output_size=1000,
  62. )
  63. ArchiveResult.objects.create(
  64. snapshot=snapshot,
  65. plugin='screenshot',
  66. status='succeeded',
  67. output_size=2000,
  68. )
  69. ArchiveResult.objects.create(
  70. snapshot=snapshot,
  71. plugin='pdf',
  72. status='failed',
  73. )
  74. ArchiveResult.objects.create(
  75. snapshot=snapshot,
  76. plugin='readability',
  77. status='started',
  78. )
  79. stats = snapshot.get_progress_stats()
  80. assert stats['total'] == 4
  81. assert stats['succeeded'] == 2
  82. assert stats['failed'] == 1
  83. assert stats['running'] == 1
  84. assert stats['output_size'] == 3000
  85. assert stats['percent'] == 75 # (2 succeeded + 1 failed) / 4 total
  86. def test_get_progress_stats_sealed(self, snapshot):
  87. """Test progress stats for sealed snapshot."""
  88. from archivebox.core.models import Snapshot
  89. snapshot.status = Snapshot.StatusChoices.SEALED
  90. snapshot.save()
  91. stats = snapshot.get_progress_stats()
  92. assert stats['is_sealed'] is True
  93. class TestAdminSnapshotListView:
  94. """Tests for the admin snapshot list view."""
  95. def test_list_view_renders(self, client, admin_user):
  96. """Test that the list view renders successfully."""
  97. client.login(username='testadmin', password='testpassword')
  98. url = reverse('admin:core_snapshot_changelist')
  99. response = client.get(url)
  100. assert response.status_code == 200
  101. def test_list_view_with_snapshots(self, client, admin_user, snapshot):
  102. """Test list view with snapshots displays them."""
  103. client.login(username='testadmin', password='testpassword')
  104. url = reverse('admin:core_snapshot_changelist')
  105. response = client.get(url)
  106. assert response.status_code == 200
  107. assert b'example.com' in response.content
  108. def test_grid_view_renders(self, client, admin_user):
  109. """Test that the grid view renders successfully."""
  110. client.login(username='testadmin', password='testpassword')
  111. url = reverse('admin:grid')
  112. response = client.get(url)
  113. assert response.status_code == 200
  114. def test_view_mode_switcher_present(self, client, admin_user):
  115. """Test that view mode switcher is present."""
  116. client.login(username='testadmin', password='testpassword')
  117. url = reverse('admin:core_snapshot_changelist')
  118. response = client.get(url)
  119. assert response.status_code == 200
  120. # Check for view mode toggle elements
  121. assert b'snapshot-view-mode' in response.content
  122. assert b'snapshot-view-list' in response.content
  123. assert b'snapshot-view-grid' in response.content
  124. class TestAdminSnapshotSearch:
  125. """Tests for admin snapshot search functionality."""
  126. def test_search_by_url(self, client, admin_user, snapshot):
  127. """Test searching snapshots by URL."""
  128. client.login(username='testadmin', password='testpassword')
  129. url = reverse('admin:core_snapshot_changelist')
  130. response = client.get(url, {'q': 'example.com'})
  131. assert response.status_code == 200
  132. # The search should find the example.com snapshot
  133. assert b'example.com' in response.content
  134. def test_search_by_title(self, client, admin_user, crawl, db):
  135. """Test searching snapshots by title."""
  136. from archivebox.core.models import Snapshot
  137. Snapshot.objects.create(
  138. url='https://example.com/titled',
  139. title='Unique Title For Testing',
  140. crawl=crawl,
  141. )
  142. client.login(username='testadmin', password='testpassword')
  143. url = reverse('admin:core_snapshot_changelist')
  144. response = client.get(url, {'q': 'Unique Title'})
  145. assert response.status_code == 200
  146. def test_search_by_tag(self, client, admin_user, snapshot, db):
  147. """Test searching snapshots by tag."""
  148. from archivebox.core.models import Tag
  149. tag = Tag.objects.create(name='test-search-tag')
  150. snapshot.tags.add(tag)
  151. client.login(username='testadmin', password='testpassword')
  152. url = reverse('admin:core_snapshot_changelist')
  153. response = client.get(url, {'q': 'test-search-tag'})
  154. assert response.status_code == 200
  155. def test_empty_search(self, client, admin_user):
  156. """Test empty search returns all snapshots."""
  157. client.login(username='testadmin', password='testpassword')
  158. url = reverse('admin:core_snapshot_changelist')
  159. response = client.get(url, {'q': ''})
  160. assert response.status_code == 200
  161. def test_no_results_search(self, client, admin_user):
  162. """Test search with no results."""
  163. client.login(username='testadmin', password='testpassword')
  164. url = reverse('admin:core_snapshot_changelist')
  165. response = client.get(url, {'q': 'nonexistent-url-xyz789'})
  166. assert response.status_code == 200
  167. class TestPublicIndexSearch:
  168. """Tests for public index search functionality."""
  169. @pytest.fixture
  170. def public_snapshot(self, crawl, db):
  171. """Create sealed snapshot for public index."""
  172. from archivebox.core.models import Snapshot
  173. return Snapshot.objects.create(
  174. url='https://public-example.com',
  175. title='Public Example Website',
  176. crawl=crawl,
  177. status=Snapshot.StatusChoices.SEALED,
  178. )
  179. @override_settings(PUBLIC_INDEX=True)
  180. def test_public_search_by_url(self, client, public_snapshot):
  181. """Test public search by URL."""
  182. response = client.get('/public/', {'q': 'public-example.com'})
  183. assert response.status_code == 200
  184. @override_settings(PUBLIC_INDEX=True)
  185. def test_public_search_by_title(self, client, public_snapshot):
  186. """Test public search by title."""
  187. response = client.get('/public/', {'q': 'Public Example'})
  188. assert response.status_code == 200
  189. @override_settings(PUBLIC_INDEX=True)
  190. def test_public_search_query_type_meta(self, client, public_snapshot):
  191. """Test public search with query_type=meta."""
  192. response = client.get('/public/', {'q': 'example', 'query_type': 'meta'})
  193. assert response.status_code == 200
  194. @override_settings(PUBLIC_INDEX=True)
  195. def test_public_search_query_type_url(self, client, public_snapshot):
  196. """Test public search with query_type=url."""
  197. response = client.get('/public/', {'q': 'public-example.com', 'query_type': 'url'})
  198. assert response.status_code == 200
  199. @override_settings(PUBLIC_INDEX=True)
  200. def test_public_search_query_type_title(self, client, public_snapshot):
  201. """Test public search with query_type=title."""
  202. response = client.get('/public/', {'q': 'Website', 'query_type': 'title'})
  203. assert response.status_code == 200