FossilRepo

fossilrepo / tests / test_shunning.py
Blame History Raw 227 lines
1
from unittest.mock import MagicMock, patch
2
3
import pytest
4
from django.contrib.auth.models import User
5
from django.test import Client
6
7
from fossil.models import FossilRepository
8
from organization.models import Team
9
from projects.models import ProjectTeam
10
11
12
@pytest.fixture
13
def fossil_repo_obj(sample_project):
14
"""Return the auto-created FossilRepository for sample_project."""
15
return FossilRepository.objects.get(project=sample_project, deleted_at__isnull=True)
16
17
18
@pytest.fixture
19
def writer_user(db, admin_user, sample_project):
20
"""User with write access but not admin."""
21
writer = User.objects.create_user(username="writer", password="testpass123")
22
team = Team.objects.create(name="Writers", organization=sample_project.organization, created_by=admin_user)
23
team.members.add(writer)
24
ProjectTeam.objects.create(project=sample_project, team=team, role="write", created_by=admin_user)
25
return writer
26
27
28
@pytest.fixture
29
def writer_client(writer_user):
30
client = Client()
31
client.login(username="writer", password="testpass123")
32
return client
33
34
35
# --- Shun List View Tests ---
36
37
38
@pytest.mark.django_db
39
class TestShunListView:
40
def test_list_shunned_as_admin(self, admin_client, sample_project, fossil_repo_obj):
41
with patch("fossil.cli.FossilCLI") as mock_cli_cls:
42
cli_instance = MagicMock()
43
cli_instance.is_available.return_value = True
44
cli_instance.shun_list.return_value = ["abc123def456", "789012345678"]
45
mock_cli_cls.return_value = cli_instance
46
# Patch exists_on_disk
47
with patch.object(type(fossil_repo_obj), "exists_on_disk", new_callable=lambda: property(lambda self: True)):
48
response = admin_client.get(f"/projects/{sample_project.slug}/fossil/admin/shun/")
49
assert response.status_code == 200
50
content = response.content.decode()
51
assert "Shunned Artifacts" in content
52
53
def test_list_empty(self, admin_client, sample_project, fossil_repo_obj):
54
with patch("fossil.cli.FossilCLI") as mock_cli_cls:
55
cli_instance = MagicMock()
56
cli_instance.is_available.return_value = True
57
cli_instance.shun_list.return_value = []
58
mock_cli_cls.return_value = cli_instance
59
with patch.object(type(fossil_repo_obj), "exists_on_disk", new_callable=lambda: property(lambda self: True)):
60
response = admin_client.get(f"/projects/{sample_project.slug}/fossil/admin/shun/")
61
assert response.status_code == 200
62
assert "No artifacts have been shunned" in response.content.decode()
63
64
def test_list_denied_for_writer(self, writer_client, sample_project, fossil_repo_obj):
65
response = writer_client.get(f"/projects/{sample_project.slug}/fossil/admin/shun/")
66
assert response.status_code == 403
67
68
def test_list_denied_for_no_perm(self, no_perm_client, sample_project):
69
response = no_perm_client.get(f"/projects/{sample_project.slug}/fossil/admin/shun/")
70
assert response.status_code == 403
71
72
def test_list_denied_for_anon(self, client, sample_project):
73
response = client.get(f"/projects/{sample_project.slug}/fossil/admin/shun/")
74
assert response.status_code == 302 # redirect to login
75
76
77
# --- Shun Artifact View Tests ---
78
79
80
@pytest.mark.django_db
81
class TestShunArtifactView:
82
def test_shun_artifact_success(self, admin_client, sample_project, fossil_repo_obj):
83
with patch("fossil.cli.FossilCLI") as mock_cli_cls:
84
cli_instance = MagicMock()
85
cli_instance.is_available.return_value = True
86
cli_instance.shun.return_value = {"success": True, "message": "Artifact shunned"}
87
mock_cli_cls.return_value = cli_instance
88
with patch.object(type(fossil_repo_obj), "exists_on_disk", new_callable=lambda: property(lambda self: True)):
89
response = admin_client.post(
90
f"/projects/{sample_project.slug}/fossil/admin/shun/add/",
91
{
92
"artifact_uuid": "a1b2c3d4e5f67890",
93
"confirmation": "a1b2c3d4",
94
"reason": "Leaked secret",
95
},
96
)
97
assert response.status_code == 302
98
assert response.url == f"/projects/{sample_project.slug}/fossil/admin/shun/"
99
100
def test_shun_requires_confirmation(self, admin_client, sample_project, fossil_repo_obj):
101
response = admin_client.post(
102
f"/projects/{sample_project.slug}/fossil/admin/shun/add/",
103
{
104
"artifact_uuid": "a1b2c3d4e5f67890",
105
"confirmation": "wrong",
106
"reason": "test",
107
},
108
)
109
assert response.status_code == 302 # redirects with error message
110
111
def test_shun_empty_uuid_rejected(self, admin_client, sample_project, fossil_repo_obj):
112
response = admin_client.post(
113
f"/projects/{sample_project.slug}/fossil/admin/shun/add/",
114
{
115
"artifact_uuid": "",
116
"confirmation": "",
117
},
118
)
119
assert response.status_code == 302
120
121
def test_shun_invalid_uuid_format(self, admin_client, sample_project, fossil_repo_obj):
122
response = admin_client.post(
123
f"/projects/{sample_project.slug}/fossil/admin/shun/add/",
124
{
125
"artifact_uuid": "not-a-hex-hash!!!",
126
"confirmation": "not-a-he",
127
},
128
)
129
assert response.status_code == 302
130
131
def test_shun_get_redirects(self, admin_client, sample_project, fossil_repo_obj):
132
response = admin_client.get(f"/projects/{sample_project.slug}/fossil/admin/shun/add/")
133
assert response.status_code == 302
134
135
def test_shun_denied_for_writer(self, writer_client, sample_project, fossil_repo_obj):
136
response = writer_client.post(
137
f"/projects/{sample_project.slug}/fossil/admin/shun/add/",
138
{
139
"artifact_uuid": "a1b2c3d4e5f67890",
140
"confirmation": "a1b2c3d4",
141
},
142
)
143
assert response.status_code == 403
144
145
def test_shun_denied_for_anon(self, client, sample_project):
146
response = client.post(
147
f"/projects/{sample_project.slug}/fossil/admin/shun/add/",
148
{
149
"artifact_uuid": "a1b2c3d4e5f67890",
150
"confirmation": "a1b2c3d4",
151
},
152
)
153
assert response.status_code == 302 # redirect to login
154
155
def test_shun_cli_failure(self, admin_client, sample_project, fossil_repo_obj):
156
with patch("fossil.cli.FossilCLI") as mock_cli_cls:
157
cli_instance = MagicMock()
158
cli_instance.is_available.return_value = True
159
cli_instance.shun.return_value = {"success": False, "message": "Unknown artifact"}
160
mock_cli_cls.return_value = cli_instance
161
with patch.object(type(fossil_repo_obj), "exists_on_disk", new_callable=lambda: property(lambda self: True)):
162
response = admin_client.post(
163
f"/projects/{sample_project.slug}/fossil/admin/shun/add/",
164
{
165
"artifact_uuid": "a1b2c3d4e5f67890",
166
"confirmation": "a1b2c3d4",
167
"reason": "test",
168
},
169
)
170
assert response.status_code == 302
171
172
173
# --- CLI Shun Method Tests ---
174
175
176
@pytest.mark.django_db
177
class TestFossilCLIShun:
178
def test_shun_calls_fossil_binary(self):
179
from fossil.cli import FossilCLI
180
181
cli = FossilCLI(binary="/usr/bin/fossil")
182
with patch("subprocess.run") as mock_run:
183
mock_run.return_value = MagicMock(returncode=0, stdout="Artifact shunned\n", stderr="")
184
result = cli.shun("/tmp/test.fossil", "abc123def456", reason="test")
185
assert result["success"] is True
186
assert "Artifact shunned" in result["message"]
187
call_args = mock_run.call_args[0][0]
188
assert "shun" in call_args
189
assert "abc123def456" in call_args
190
191
def test_shun_returns_failure(self):
192
from fossil.cli import FossilCLI
193
194
cli = FossilCLI(binary="/usr/bin/fossil")
195
with patch("subprocess.run") as mock_run:
196
mock_run.return_value = MagicMock(returncode=1, stdout="", stderr="Not found")
197
result = cli.shun("/tmp/test.fossil", "nonexistent")
198
assert result["success"] is False
199
assert "Not found" in result["message"]
200
201
def test_shun_list_returns_uuids(self):
202
from fossil.cli import FossilCLI
203
204
cli = FossilCLI(binary="/usr/bin/fossil")
205
with patch("subprocess.run") as mock_run:
206
mock_run.return_value = MagicMock(returncode=0, stdout="abc123\ndef456\n", stderr="")
207
result = cli.shun_list("/tmp/test.fossil")
208
assert result == ["abc123", "def456"]
209
210
def test_shun_list_empty(self):
211
from fossil.cli import FossilCLI
212
213
cli = FossilCLI(binary="/usr/bin/fossil")
214
with patch("subprocess.run") as mock_run:
215
mock_run.return_value = MagicMock(returncode=0, stdout="", stderr="")
216
result = cli.shun_list("/tmp/test.fossil")
217
assert result == []
218
219
def test_shun_list_failure_returns_empty(self):
220
from fossil.cli import FossilCLI
221
222
cli = FossilCLI(binary="/usr/bin/fossil")
223
with patch("subprocess.run") as mock_run:
224
mock_run.return_value = MagicMock(returncode=1, stdout="", stderr="error")
225
result = cli.shun_list("/tmp/test.fossil")
226
assert result == []
227

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button