Skip to content

Commit 2b392f8

Browse files
authored
Add /libraries/x.x.x redirect (boostorg#1937) (boostorg#1949)
1 parent 724ece3 commit 2b392f8

File tree

4 files changed

+112
-13
lines changed

4 files changed

+112
-13
lines changed

config/urls.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,11 @@
387387
),
388388
]
389389
+ [
390+
path(
391+
"libraries/<str:requested_version>/",
392+
RedirectToLibrariesView.as_view(),
393+
name="redirect-to-library-list-view",
394+
),
390395
# Redirects for old boost.org urls.
391396
re_path(
392397
r"^libs/(?P<libname>[^/]+)/(?P<path>.*)/?$",

core/tests/test_views.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,84 @@ def test_markdown_view_trailing_slash(tp):
149149
tp.response_200(res)
150150

151151

152+
def test_doc_libs_get_content_with_db_cache(request_factory):
153+
"""Test DocLibsTemplateView.get_content with database caching enabled."""
154+
from core.views import DocLibsTemplateView
155+
156+
# Mock S3 returning content
157+
mock_s3_result = {
158+
"content": b"<html>Test content</html>",
159+
"content_type": "text/html",
160+
}
161+
162+
with patch("core.views.ENABLE_DB_CACHE", True), patch(
163+
"core.views.DocLibsTemplateView.get_from_database", return_value=None
164+
) as mock_get_from_db, patch(
165+
"core.views.DocLibsTemplateView.get_from_s3", return_value=mock_s3_result
166+
) as mock_get_from_s3, patch(
167+
"core.views.DocLibsTemplateView.save_to_database"
168+
) as mock_save_to_db:
169+
170+
view = DocLibsTemplateView()
171+
view.request = request_factory.get("/doc/libs/test/")
172+
result = view.get_content("test/path")
173+
174+
# verify database was checked first
175+
mock_get_from_db.assert_called_once_with("static_content_test/path")
176+
# verify S3 was called after cache miss
177+
mock_get_from_s3.assert_called_once_with("test/path")
178+
# verify content was saved to database
179+
mock_save_to_db.assert_called_once_with(
180+
"static_content_test/path", mock_s3_result
181+
)
182+
183+
assert result["content"] == mock_s3_result["content"]
184+
assert result["content_type"] == mock_s3_result["content_type"]
185+
assert "redirect" in result
186+
187+
188+
def test_doc_libs_get_content_without_db_cache(request_factory):
189+
"""Test DocLibsTemplateView.get_content with database caching disabled."""
190+
from core.views import DocLibsTemplateView
191+
192+
# Mock S3 returning content
193+
mock_s3_result = {
194+
"content": b"<html>Test content</html>",
195+
"content_type": "text/html",
196+
}
197+
198+
with patch("core.views.ENABLE_DB_CACHE", False), patch(
199+
"core.views.DocLibsTemplateView.get_from_s3", return_value=mock_s3_result
200+
) as mock_get_from_s3:
201+
202+
view = DocLibsTemplateView()
203+
view.request = request_factory.get("/doc/libs/test/")
204+
result = view.get_content("test/path")
205+
206+
# verify S3 was called directly
207+
mock_get_from_s3.assert_called_once_with("test/path")
208+
209+
assert result["content"] == mock_s3_result["content"]
210+
assert result["content_type"] == mock_s3_result["content_type"]
211+
assert "redirect" in result
212+
213+
214+
@patch("core.views.DocLibsTemplateView.get_from_s3")
215+
def test_doc_libs_get_content_not_found(mock_get_from_s3, request_factory):
216+
"""Test DocLibsTemplateView.get_content when content is not found."""
217+
from core.views import DocLibsTemplateView, ContentNotFoundException
218+
219+
# mock S3 returning None (content not found)
220+
mock_get_from_s3.return_value = None
221+
222+
request = request_factory.get("/doc/libs/test/")
223+
view = DocLibsTemplateView()
224+
view.request = request
225+
226+
with pytest.raises(ContentNotFoundException, match="Content not found"):
227+
view.get_content("nonexistent/path")
228+
229+
152230
def test_markdown_view_top_level_includes_extension(tp):
153231
res = tp.get("/markdown/foo.html")
154232
tp.response_200(res)

core/views.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -559,21 +559,22 @@ def get_content(self, content_path):
559559
# For now at least we're only going to cache docs this way, user guides and
560560
# will continue to be cached as they were
561561

562-
if not ENABLE_DB_CACHE:
563-
return self.get_from_s3(content_path)
564-
565-
cache_key = f"static_content_{content_path}"
566-
# check to see if in db, if not retrieve from s3 and save to db
567-
result = self.get_from_database(cache_key)
568-
if not result and (result := self.get_from_s3(content_path)):
569-
self.save_to_database(cache_key, result)
562+
result = None
563+
if ENABLE_DB_CACHE:
564+
cache_key = f"static_content_{content_path}"
565+
# check to see if in db, if not retrieve from s3 and save to db
566+
result = self.get_from_database(cache_key)
567+
if not result and (result := self.get_from_s3(content_path)):
568+
self.save_to_database(cache_key, result)
569+
elif content_data := self.get_from_s3(content_path):
570+
# structure is to allow for redirect/return to be handled in a unified way
571+
result = {
572+
"content": content_data.get("content"),
573+
"content_type": content_data.get("content_type"),
574+
}
570575

571576
if result is None:
572-
logger.info(
573-
"get_content_from_s3_view_no_valid_object",
574-
key=content_path,
575-
status_code=404,
576-
)
577+
logger.info(f"get_content_from_s3_view_no_valid_object {content_path=}")
577578
raise ContentNotFoundException("Content not found")
578579

579580
result["redirect"] = get_meta_redirect_from_html(result["content"])

libraries/tests/test_views.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,3 +335,18 @@ def test_library_detail_context_missing_readme(tp, user, library_version):
335335
tp.response_200(response)
336336
assert "description" in response.context
337337
assert response.context["description"] == README_MISSING
338+
339+
340+
def test_redirect_to_library_list_view(library_version, tp):
341+
"""
342+
GET /libraries/{version_string}/
343+
Test that redirection occurs to the proper libraries list view
344+
"""
345+
url = tp.reverse("redirect-to-library-list-view", "1.79.0")
346+
347+
response = tp.get(url, follow=False)
348+
tp.response_302(response)
349+
350+
# Should redirect to the libraries-list view with the version slug
351+
expected_redirect = "/libraries/1.79.0/grid/"
352+
assert response.url == expected_redirect

0 commit comments

Comments
 (0)