Skip to content

Commit 8e6f21a

Browse files
committed
test: test the package subscribe/unsubscribe
1 parent 567a532 commit 8e6f21a

File tree

1 file changed

+340
-0
lines changed

1 file changed

+340
-0
lines changed
Lines changed: 340 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
from allauth.socialaccount.models import SocialAccount
2+
from django.contrib.auth.models import User
3+
from django.test import Client, TestCase
4+
from django.urls import reverse
5+
6+
from shared.models.nix_evaluation import (
7+
NixChannel,
8+
NixDerivation,
9+
NixDerivationMeta,
10+
NixEvaluation,
11+
NixMaintainer,
12+
)
13+
14+
15+
class SubscriptionTests(TestCase):
16+
def setUp(self) -> None:
17+
# Create test user with social account
18+
self.user = User.objects.create_user(username="testuser", password="testpass")
19+
self.user.is_staff = True
20+
self.user.save()
21+
22+
SocialAccount.objects.get_or_create(
23+
user=self.user,
24+
provider="github",
25+
uid="123456",
26+
extra_data={"login": "testuser"},
27+
)
28+
29+
self.client = Client()
30+
self.client.login(username="testuser", password="testpass")
31+
32+
# Create test NixDerivation data for package validation
33+
self.maintainer = NixMaintainer.objects.create(
34+
github_id=123,
35+
github="testmaintainer",
36+
name="Test Maintainer",
37+
38+
)
39+
self.meta = NixDerivationMeta.objects.create(
40+
description="Test package",
41+
insecure=False,
42+
available=True,
43+
broken=False,
44+
unfree=False,
45+
unsupported=False,
46+
)
47+
self.meta.maintainers.add(self.maintainer)
48+
49+
self.evaluation = NixEvaluation.objects.create(
50+
channel=NixChannel.objects.create(
51+
staging_branch="release-24.05",
52+
channel_branch="nixos-24.05",
53+
head_sha1_commit="deadbeef",
54+
state=NixChannel.ChannelState.STABLE,
55+
release_version="24.05",
56+
repository="https://github.com/NixOS/nixpkgs",
57+
),
58+
commit_sha1="deadbeef",
59+
state=NixEvaluation.EvaluationState.COMPLETED,
60+
)
61+
62+
# Create valid packages that can be subscribed to
63+
self.valid_package1 = NixDerivation.objects.create(
64+
attribute="firefox",
65+
derivation_path="/nix/store/firefox.drv",
66+
name="firefox-120.0",
67+
metadata=self.meta,
68+
system="x86_64-linux",
69+
parent_evaluation=self.evaluation,
70+
)
71+
72+
# Create separate metadata for chromium
73+
self.meta2 = NixDerivationMeta.objects.create(
74+
description="Test chromium package",
75+
insecure=False,
76+
available=True,
77+
broken=False,
78+
unfree=False,
79+
unsupported=False,
80+
)
81+
self.meta2.maintainers.add(self.maintainer)
82+
83+
self.valid_package2 = NixDerivation.objects.create(
84+
attribute="chromium",
85+
derivation_path="/nix/store/chromium.drv",
86+
name="chromium-119.0",
87+
metadata=self.meta2,
88+
system="x86_64-linux",
89+
parent_evaluation=self.evaluation,
90+
)
91+
92+
def test_user_subscribes_to_valid_package_success(self) -> None:
93+
"""Test successful subscription to an existing package"""
94+
url = reverse("webview:subscriptions:add")
95+
response = self.client.post(url, {"package_name": "firefox"})
96+
97+
# Should redirect for non-HTMX request
98+
self.assertEqual(response.status_code, 302)
99+
self.assertIn("subscriptions", response.url)
100+
101+
# Follow redirect and check subscription center context
102+
response = self.client.get(response.url)
103+
self.assertEqual(response.status_code, 200)
104+
105+
# Verify subscription appears in context
106+
self.assertIn("package_subscriptions", response.context)
107+
self.assertIn("firefox", response.context["package_subscriptions"])
108+
109+
def test_user_subscribes_to_invalid_package_fails(self) -> None:
110+
"""Test subscription fails for non-existent package"""
111+
url = reverse("webview:subscriptions:add")
112+
response = self.client.post(url, {"package_name": "nonexistent-package"})
113+
114+
# Should redirect for non-HTMX request
115+
self.assertEqual(response.status_code, 302)
116+
117+
# Follow redirect and check for error message and context
118+
response = self.client.get(response.url)
119+
self.assertEqual(response.status_code, 200)
120+
121+
# Check that error message is in Django messages
122+
messages = list(response.context["messages"])
123+
self.assertTrue(any("does not exist" in str(message) for message in messages))
124+
125+
# Verify no invalid subscription in context
126+
self.assertIn("package_subscriptions", response.context)
127+
self.assertEqual(response.context["package_subscriptions"], [])
128+
129+
def test_user_subscribes_to_valid_package_success_htmx(self) -> None:
130+
"""Test successful subscription to an existing package via HTMX"""
131+
url = reverse("webview:subscriptions:add")
132+
response = self.client.post(
133+
url, {"package_name": "firefox"}, HTTP_HX_REQUEST="true"
134+
)
135+
136+
# Should return 200 with component template for HTMX request
137+
self.assertEqual(response.status_code, 200)
138+
self.assertTemplateUsed(response, "subscriptions/components/packages.html")
139+
140+
# Verify subscription appears in context
141+
self.assertIn("package_subscriptions", response.context)
142+
self.assertIn("firefox", response.context["package_subscriptions"])
143+
144+
# Should not have error message
145+
self.assertNotIn("error_message", response.context)
146+
147+
def test_user_subscribes_to_invalid_package_fails_htmx(self) -> None:
148+
"""Test subscription fails for non-existent package via HTMX"""
149+
url = reverse("webview:subscriptions:add")
150+
response = self.client.post(
151+
url, {"package_name": "nonexistent-package"}, HTTP_HX_REQUEST="true"
152+
)
153+
154+
# Should return 200 with component template for HTMX request
155+
self.assertEqual(response.status_code, 200)
156+
self.assertTemplateUsed(response, "subscriptions/components/packages.html")
157+
158+
# Check that error message is in context
159+
self.assertIn("error_message", response.context)
160+
self.assertIn("does not exist", response.context["error_message"])
161+
162+
# Verify no invalid subscription in context
163+
self.assertIn("package_subscriptions", response.context)
164+
self.assertNotIn(
165+
"nonexistent-package", response.context["package_subscriptions"]
166+
)
167+
168+
def test_user_subscribes_to_empty_package_name_fails_htmx(self) -> None:
169+
"""Test subscription fails for empty package name via HTMX"""
170+
url = reverse("webview:subscriptions:add")
171+
response = self.client.post(url, {"package_name": ""}, HTTP_HX_REQUEST="true")
172+
173+
# Should return 200 with component template for HTMX request
174+
self.assertEqual(response.status_code, 200)
175+
self.assertTemplateUsed(response, "subscriptions/components/packages.html")
176+
177+
# Check that error message is in context
178+
self.assertIn("error_message", response.context)
179+
self.assertIn("cannot be empty", response.context["error_message"])
180+
181+
# Verify no subscriptions in context
182+
self.assertIn("package_subscriptions", response.context)
183+
self.assertEqual(response.context["package_subscriptions"], [])
184+
185+
def test_user_cannot_subscribe_to_same_package_twice_htmx(self) -> None:
186+
"""Test duplicate subscription prevention via HTMX"""
187+
url = reverse("webview:subscriptions:add")
188+
189+
# First subscription should succeed
190+
response = self.client.post(
191+
url, {"package_name": "firefox"}, HTTP_HX_REQUEST="true"
192+
)
193+
self.assertEqual(response.status_code, 200)
194+
self.assertIn("firefox", response.context["package_subscriptions"])
195+
196+
# Second subscription to same package should fail
197+
response = self.client.post(
198+
url, {"package_name": "firefox"}, HTTP_HX_REQUEST="true"
199+
)
200+
201+
# Should return 200 with component template
202+
self.assertEqual(response.status_code, 200)
203+
self.assertTemplateUsed(response, "subscriptions/components/packages.html")
204+
205+
# Check that error message is in context
206+
self.assertIn("error_message", response.context)
207+
self.assertIn("already subscribed", response.context["error_message"])
208+
209+
# Verify firefox still appears only once in context
210+
self.assertIn("package_subscriptions", response.context)
211+
self.assertIn("firefox", response.context["package_subscriptions"])
212+
213+
def test_user_unsubscribes_from_package_success_htmx(self) -> None:
214+
"""Test successful unsubscription via HTMX"""
215+
# First subscribe to a package via HTMX
216+
add_url = reverse("webview:subscriptions:add")
217+
self.client.post(add_url, {"package_name": "firefox"}, HTTP_HX_REQUEST="true")
218+
219+
# Now unsubscribe via HTMX
220+
remove_url = reverse("webview:subscriptions:remove")
221+
response = self.client.post(
222+
remove_url, {"package_name": "firefox"}, HTTP_HX_REQUEST="true"
223+
)
224+
225+
# Should return 200 with component template for HTMX request
226+
self.assertEqual(response.status_code, 200)
227+
self.assertTemplateUsed(response, "subscriptions/components/packages.html")
228+
229+
# Verify subscription was removed from context
230+
self.assertIn("package_subscriptions", response.context)
231+
self.assertNotIn("firefox", response.context["package_subscriptions"])
232+
self.assertEqual(response.context["package_subscriptions"], [])
233+
234+
# Should not have error message
235+
self.assertNotIn("error_message", response.context)
236+
237+
def test_user_cannot_unsubscribe_from_non_subscribed_package_htmx(self) -> None:
238+
"""Test unsubscription fails for packages not subscribed to via HTMX"""
239+
url = reverse("webview:subscriptions:remove")
240+
response = self.client.post(
241+
url, {"package_name": "firefox"}, HTTP_HX_REQUEST="true"
242+
)
243+
244+
# Should return 200 with component template for HTMX request
245+
self.assertEqual(response.status_code, 200)
246+
self.assertTemplateUsed(response, "subscriptions/components/packages.html")
247+
248+
# Check that error message is in context
249+
self.assertIn("error_message", response.context)
250+
self.assertIn("not subscribed", response.context["error_message"])
251+
252+
# Verify empty subscriptions in context
253+
self.assertIn("package_subscriptions", response.context)
254+
self.assertEqual(response.context["package_subscriptions"], [])
255+
256+
def test_subscription_center_shows_user_subscriptions(self) -> None:
257+
"""Test that the center displays user's current subscriptions"""
258+
# First add some subscriptions via HTMX
259+
add_url = reverse("webview:subscriptions:add")
260+
self.client.post(add_url, {"package_name": "firefox"}, HTTP_HX_REQUEST="true")
261+
262+
# Add second package
263+
self.client.post(add_url, {"package_name": "chromium"}, HTTP_HX_REQUEST="true")
264+
265+
# Check subscription center shows both subscriptions
266+
response = self.client.get(reverse("webview:subscriptions:center"))
267+
self.assertEqual(response.status_code, 200)
268+
269+
# Check context contains both subscriptions
270+
self.assertIn("package_subscriptions", response.context)
271+
subscriptions = response.context["package_subscriptions"]
272+
self.assertIn("firefox", subscriptions)
273+
self.assertIn("chromium", subscriptions)
274+
self.assertEqual(len(subscriptions), 2)
275+
276+
def test_subscription_center_shows_empty_state(self) -> None:
277+
"""Test empty state when user has no subscriptions"""
278+
response = self.client.get(reverse("webview:subscriptions:center"))
279+
self.assertEqual(response.status_code, 200)
280+
281+
# Check context shows empty subscriptions
282+
self.assertIn("package_subscriptions", response.context)
283+
self.assertEqual(response.context["package_subscriptions"], [])
284+
285+
def test_subscription_center_requires_login(self) -> None:
286+
"""Test that subscription center redirects when not logged in"""
287+
# Logout the user
288+
self.client.logout()
289+
290+
response = self.client.get(reverse("webview:subscriptions:center"))
291+
self.assertEqual(response.status_code, 302)
292+
self.assertIn("login", response.url)
293+
294+
# Test add endpoint also requires login
295+
response = self.client.post(
296+
reverse("webview:subscriptions:add"), {"package_name": "firefox"}
297+
)
298+
self.assertEqual(response.status_code, 302)
299+
self.assertIn("login", response.url)
300+
301+
# Test remove endpoint also requires login
302+
response = self.client.post(
303+
reverse("webview:subscriptions:remove"), {"package_name": "firefox"}
304+
)
305+
self.assertEqual(response.status_code, 302)
306+
self.assertIn("login", response.url)
307+
308+
# Test HTMX requests also require login
309+
response = self.client.post(
310+
reverse("webview:subscriptions:add"),
311+
{"package_name": "firefox"},
312+
HTTP_HX_REQUEST="true",
313+
)
314+
self.assertEqual(response.status_code, 302)
315+
self.assertIn("login", response.url)
316+
317+
response = self.client.post(
318+
reverse("webview:subscriptions:remove"),
319+
{"package_name": "firefox"},
320+
HTTP_HX_REQUEST="true",
321+
)
322+
self.assertEqual(response.status_code, 302)
323+
self.assertIn("login", response.url)
324+
325+
def test_user_unsubscribes_from_empty_package_name_fails_htmx(self) -> None:
326+
"""Test unsubscription fails for empty package name via HTMX"""
327+
url = reverse("webview:subscriptions:remove")
328+
response = self.client.post(url, {"package_name": ""}, HTTP_HX_REQUEST="true")
329+
330+
# Should return 200 with component template for HTMX request
331+
self.assertEqual(response.status_code, 200)
332+
self.assertTemplateUsed(response, "subscriptions/components/packages.html")
333+
334+
# Check that error message is in context
335+
self.assertIn("error_message", response.context)
336+
self.assertIn("required", response.context["error_message"])
337+
338+
# Verify empty subscriptions in context
339+
self.assertIn("package_subscriptions", response.context)
340+
self.assertEqual(response.context["package_subscriptions"], [])

0 commit comments

Comments
 (0)