Skip to content

Commit 9adacaa

Browse files
committed
Ensure KeyringItem is validated
- 'testserver' is not a valid netloc so fails Django's validation. - tests for very long URLs
1 parent 14adf1b commit 9adacaa

2 files changed

Lines changed: 55 additions & 26 deletions

File tree

testproject/home/tests.py

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ def hook_any(obj, is_cacheable: bool):
3939

4040

4141
class WagtailCacheTest(TestCase):
42+
client_headers = {"SERVER_NAME": "example.com"}
43+
4244
@classmethod
4345
def get_content_type(cls, modelname: str):
4446
ctype, _ = ContentType.objects.get_or_create(
@@ -145,23 +147,23 @@ def head_hit(self, url: str):
145147
"""
146148
HEAD a page and test that it was served from the cache.
147149
"""
148-
response = self.client.head(url)
150+
response = self.client.head(url, **self.client_headers)
149151
self.assertEqual(response.get(self.header_name, None), Status.HIT.value)
150152
return response
151153

152154
def get_hit(self, url: str):
153155
"""
154156
Gets a page and tests that it was served from the cache.
155157
"""
156-
response = self.client.get(url)
158+
response = self.client.get(url, **self.client_headers)
157159
self.assertEqual(response.get(self.header_name, None), Status.HIT.value)
158160
return response
159161

160162
def head_miss(self, url: str):
161163
"""
162164
HEAD a page and test that it was not served from the cache.
163165
"""
164-
response = self.client.head(url)
166+
response = self.client.head(url, **self.client_headers)
165167
self.assertEqual(
166168
response.get(self.header_name, None), Status.MISS.value
167169
)
@@ -170,7 +172,7 @@ def get_miss(self, url: str):
170172
"""
171173
Gets a page and tests that it was not served from the cache.
172174
"""
173-
response = self.client.get(url)
175+
response = self.client.get(url, **self.client_headers)
174176
self.assertEqual(
175177
response.get(self.header_name, None), Status.MISS.value
176178
)
@@ -181,7 +183,7 @@ def head_skip(self, url: str):
181183
HEAD a page and test that it was intentionally not served from the
182184
cache.
183185
"""
184-
response = self.client.head(url)
186+
response = self.client.head(url, **self.client_headers)
185187
self.assertEqual(
186188
response.get(self.header_name, None), Status.SKIP.value
187189
)
@@ -195,7 +197,7 @@ def get_skip(self, url: str):
195197
Gets a page and tests that it was intentionally not served from
196198
the cache.
197199
"""
198-
response = self.client.get(url)
200+
response = self.client.get(url, **self.client_headers)
199201
self.assertEqual(
200202
response.get(self.header_name, None), Status.SKIP.value
201203
)
@@ -209,7 +211,7 @@ def get_error(self, url: str):
209211
"""
210212
Gets a page and tests that an error in the cache backend was handled.
211213
"""
212-
response = self.client.get(url)
214+
response = self.client.get(url, **self.client_headers)
213215
self.assertEqual(response.status_code, 200)
214216
self.assertEqual(
215217
response.get(self.header_name, None), Status.ERROR.value
@@ -220,7 +222,7 @@ def head_error(self, url: str):
220222
"""
221223
HEAD a page and tests that an error in the cache backend was handled.
222224
"""
223-
response = self.client.head(url)
225+
response = self.client.head(url, **self.client_headers)
224226
self.assertEqual(response.status_code, 200)
225227
self.assertEqual(
226228
response.get(self.header_name, None), Status.ERROR.value
@@ -232,7 +234,7 @@ def post_skip(self, url: str):
232234
POSTS a page and tests that it was intentionally not served from
233235
the cache.
234236
"""
235-
response = self.client.post(url)
237+
response = self.client.post(url, **self.client_headers)
236238
self.assertEqual(
237239
response.get(self.header_name, None), Status.SKIP.value
238240
)
@@ -292,6 +294,9 @@ def test_querystrings(self):
292294
# A get with both should also hit, since it is the second request.
293295
self.head_hit(page.get_url() + "?valid=0&utm_code=0")
294296
self.get_hit(page.get_url() + "?valid=0&utm_code=0")
297+
# A get with a very long querysting should return an error
298+
self.head_error(page.get_url() + "?" + "a" * 2000)
299+
self.get_error(page.get_url() + "?" + "a" * 2000)
295300

296301
@override_settings(WAGTAIL_CACHE_IGNORE_COOKIES=False)
297302
def test_cookie_page(self):
@@ -384,6 +389,7 @@ def test_page_restricted(self):
384389
"password": "the cybers",
385390
"return_url": self.page_cachedpage_restricted.get_url(),
386391
},
392+
**self.client_headers,
387393
)
388394
self.assertRedirects(
389395
response, self.page_cachedpage_restricted.get_url()
@@ -493,7 +499,9 @@ def test_template_response_view_hit(self):
493499

494500
def test_admin(self):
495501
self.client.force_login(self.user)
496-
response = self.client.get(reverse("wagtailcache:index"))
502+
response = self.client.get(
503+
reverse("wagtailcache:index"), **self.client_headers
504+
)
497505
self.client.logout()
498506
self.assertEqual(response.status_code, 200)
499507

@@ -504,7 +512,9 @@ def test_admin_clearcache(self):
504512
self.get_hit(self.page_cachedpage.get_url())
505513
# Now log in as admin and clear the cache.
506514
self.client.force_login(self.user)
507-
response = self.client.get(reverse("wagtailcache:clearcache"))
515+
response = self.client.get(
516+
reverse("wagtailcache:clearcache"), **self.client_headers
517+
)
508518
self.client.logout()
509519
self.assertEqual(response.status_code, 302)
510520
# Now the page should miss cache.
@@ -519,7 +529,7 @@ def test_cache_keyring(self):
519529
self.get_miss(self.page_cachedpage.get_url())
520530
self.assertEqual(KeyringItem.objects.count(), 1)
521531
# Get first key from keyring
522-
url = "http://%s%s" % ("testserver", self.page_cachedpage.get_url())
532+
url = "http://%s%s" % ("example.com", self.page_cachedpage.get_url())
523533
keyring_item = KeyringItem.objects.active_for_url_regexes(url).first()
524534
# Compare Keys
525535
self.assertEqual(keyring_item.url, url)
@@ -558,22 +568,30 @@ def test_clear_cache_url(self):
558568
@override_settings(WAGTAIL_CACHE=True)
559569
def test_enable_wagtailcache(self):
560570
# Intentionally enable wagtail-cache, make sure it works.
561-
response = self.client.get(self.page_cachedpage.get_url())
571+
response = self.client.get(
572+
self.page_cachedpage.get_url(), **self.client_headers
573+
)
562574
self.assertIsNotNone(response.get(self.header_name, None))
563575

564576
@override_settings(WAGTAIL_CACHE=False)
565577
def test_disable_wagtailcache(self):
566578
# Intentionally disable wagtail-cache, make sure it is inactive.
567-
response = self.client.get(self.page_cachedpage.get_url())
579+
response = self.client.get(
580+
self.page_cachedpage.get_url(), **self.client_headers
581+
)
568582
self.assertIsNone(response.get(self.header_name, None))
569583

570584
@override_settings(WAGTAIL_CACHE_BACKEND="zero")
571585
def test_zero_timeout(self):
572586
# Wagtail-cache should ignore the page when a timeout is zero.
573-
response = self.client.get(self.page_cachedpage.get_url())
587+
response = self.client.get(
588+
self.page_cachedpage.get_url(), **self.client_headers
589+
)
574590
self.assertIsNone(response.get(self.header_name, None))
575591
# Second should also not cache.
576-
response = self.client.get(self.page_cachedpage.get_url())
592+
response = self.client.get(
593+
self.page_cachedpage.get_url(), **self.client_headers
594+
)
577595
self.assertIsNone(response.get(self.header_name, None))
578596
# Load admin panel to render the zero timeout.
579597
self.test_admin()
@@ -607,19 +625,23 @@ def test_page_error_set(self):
607625
def test_timeout_jitter(self):
608626
# Wagtail-cache should apply jitter to the timeout.
609627
url = self.page_cachedpage.get_url()
610-
self.client.get(url)
628+
self.client.get(url, **self.client_headers)
611629
time.sleep(1.5)
612630
self.get_hit(url)
613631

614632
# ---- HOOKS ---------------------------------------------------------------
615633

616634
def test_request_hook_true(self):
617635
# A POST should never be cached.
618-
response = self.client.post(reverse("cached_view"))
636+
response = self.client.post(
637+
reverse("cached_view"), **self.client_headers
638+
)
619639
self.assertEqual(
620640
response.get(self.header_name, None), Status.SKIP.value
621641
)
622-
response = self.client.post(reverse("cached_view"))
642+
response = self.client.post(
643+
reverse("cached_view"), **self.client_headers
644+
)
623645
self.assertEqual(
624646
response.get(self.header_name, None), Status.SKIP.value
625647
)
@@ -631,11 +653,15 @@ def test_request_hook_true(self):
631653
# the response still has the final say in whether or not the response is
632654
# cached. However a simple POST request where the response does not
633655
# forbid caching will in fact get cached!
634-
response = self.client.post(reverse("cached_view"))
656+
response = self.client.post(
657+
reverse("cached_view"), **self.client_headers
658+
)
635659
self.assertEqual(
636660
response.get(self.header_name, None), Status.MISS.value
637661
)
638-
response = self.client.post(reverse("cached_view"))
662+
response = self.client.post(
663+
reverse("cached_view"), **self.client_headers
664+
)
639665
self.assertEqual(response.get(self.header_name, None), Status.HIT.value)
640666

641667
def test_request_hook_false(self):

wagtailcache/models.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,14 @@ def set(self, url, key, expiry) -> "KeyringItem":
1919
"""
2020
Create or update a keyring item, clearing expired items too.
2121
"""
22-
item, _ = self.update_or_create(
23-
defaults={"expiry": expiry},
24-
url=url,
25-
key=key,
26-
)
22+
# Ensure `full_clean` is called to validate the model.
23+
try:
24+
item = self.get(url=url, key=key)
25+
item.expiry = expiry
26+
except KeyringItem.DoesNotExist:
27+
item = KeyringItem(url=url, key=key, expiry=expiry)
28+
item.full_clean()
29+
item.save()
2730

2831
if wagtailcache_settings.WAGTAIL_CACHE_CLEAR_EXPIRED_ON_SET:
2932
self.clear_expired()

0 commit comments

Comments
 (0)