|
47 | 47 | BallotDocEventFactory, DocumentAuthorFactory, |
48 | 48 | NewRevisionDocEventFactory, |
49 | 49 | StatusChangeFactory, DocExtResourceFactory, |
50 | | - RgDraftFactory, BcpFactory, RfcAuthorFactory) |
| 50 | + RgDraftFactory, BcpFactory, StdFactory, |
| 51 | + FyiFactory, RfcAuthorFactory) |
51 | 52 | from ietf.doc.forms import NotifyForm |
52 | 53 | from ietf.doc.fields import SearchableDocumentsField |
53 | 54 | from ietf.doc.utils import ( |
54 | 55 | create_ballot_if_not_open, |
| 56 | + external_canonical_url, |
55 | 57 | investigate_fragment, |
56 | 58 | uppercase_std_abbreviated_name, |
57 | 59 | DraftAliasGenerator, |
@@ -2345,6 +2347,98 @@ def test_template_tags(self): |
2345 | 2347 | failures, tests = doctest.testmod(ietf_filters) |
2346 | 2348 | self.assertEqual(failures, 0) |
2347 | 2349 |
|
| 2350 | +@override_settings(RFC_EDITOR_INFO_BASE_URL="https://www.rfc-editor.example.org/info/") |
| 2351 | +class CanonicalUrlTests(TestCase): |
| 2352 | + """Tests of the rel=canonical link declared by document pages""" |
| 2353 | + |
| 2354 | + def canonical_href(self, r): |
| 2355 | + """Extract the canonical href from a response, asserting that it is usable |
| 2356 | +
|
| 2357 | + An empty href resolves to the current URL and an href of "None" resolves to a |
| 2358 | + URL that does not exist - neither is visible when eyeballing a rendered page. |
| 2359 | + """ |
| 2360 | + self.assertEqual(r.status_code, 200) |
| 2361 | + links = PyQuery(r.content)("link[rel='canonical']") |
| 2362 | + self.assertEqual(len(links), 1) |
| 2363 | + href = links.attr("href") |
| 2364 | + self.assertNotIn(href, ["", "None", None]) |
| 2365 | + return href |
| 2366 | + |
| 2367 | + def test_external_canonical_url(self): |
| 2368 | + for doc in [WgRfcFactory(), BcpFactory(), StdFactory(), FyiFactory()]: |
| 2369 | + self.assertEqual( |
| 2370 | + external_canonical_url(doc), |
| 2371 | + f"https://www.rfc-editor.example.org/info/{doc.name}/", |
| 2372 | + f"{doc.type_id} belongs to the RFC Editor", |
| 2373 | + ) |
| 2374 | + for doc in [WgDraftFactory(), CharterFactory(), StatusChangeFactory()]: |
| 2375 | + self.assertIsNone(external_canonical_url(doc), f"{doc.type_id} is ours") |
| 2376 | + |
| 2377 | + def test_rfc_pages_canonicalize_to_rfc_editor(self): |
| 2378 | + rfc = WgRfcFactory() |
| 2379 | + rfc.save_with_history([DocEventFactory(doc=rfc)]) |
| 2380 | + (Path(settings.RFC_PATH) / rfc.get_base_name()).touch() |
| 2381 | + expected = f"https://www.rfc-editor.example.org/info/{rfc.name}/" |
| 2382 | + |
| 2383 | + for viewname in [ |
| 2384 | + "ietf.doc.views_doc.document_main", |
| 2385 | + "ietf.doc.views_doc.document_html", |
| 2386 | + ]: |
| 2387 | + url = urlreverse(viewname, kwargs=dict(name=rfc.name)) |
| 2388 | + r = self.client.get(url) |
| 2389 | + self.assertEqual(self.canonical_href(r), expected, f"{url} canonical") |
| 2390 | + |
| 2391 | + def test_draft_pages_canonicalize_to_datatracker(self): |
| 2392 | + draft = WgDraftFactory() |
| 2393 | + # an active draft's file is in both of these - see Document.get_file_path() |
| 2394 | + for dir in [settings.INTERNET_DRAFT_PATH, settings.INTERNET_ALL_DRAFTS_ARCHIVE_DIR]: |
| 2395 | + (Path(dir) / draft.get_base_name()).touch() |
| 2396 | + |
| 2397 | + for viewname in [ |
| 2398 | + "ietf.doc.views_doc.document_main", |
| 2399 | + "ietf.doc.views_doc.document_html", |
| 2400 | + ]: |
| 2401 | + url = urlreverse(viewname, kwargs=dict(name=draft.name)) |
| 2402 | + r = self.client.get(url) |
| 2403 | + self.assertEqual( |
| 2404 | + self.canonical_href(r), |
| 2405 | + f"{settings.IDTRACKER_BASE_URL}{url}", |
| 2406 | + f"{url} canonical", |
| 2407 | + ) |
| 2408 | + |
| 2409 | + def test_subseries_pages_canonicalize_to_rfc_editor(self): |
| 2410 | + for doc in [BcpFactory(), StdFactory(), FyiFactory()]: |
| 2411 | + url = urlreverse( |
| 2412 | + "ietf.doc.views_doc.document_main", kwargs=dict(name=doc.name) |
| 2413 | + ) |
| 2414 | + r = self.client.get(url) |
| 2415 | + self.assertEqual( |
| 2416 | + self.canonical_href(r), |
| 2417 | + f"https://www.rfc-editor.example.org/info/{doc.name}/", |
| 2418 | + f"{url} canonical", |
| 2419 | + ) |
| 2420 | + |
| 2421 | + |
| 2422 | +class SubseriesHtmlRedirectTests(TestCase): |
| 2423 | + """Tests of the /doc/html/ redirects for the bcp/std/fyi subseries |
| 2424 | +
|
| 2425 | + These patterns interpolate RFC_EDITOR_INFO_BASE_URL when the URLconf is imported, |
| 2426 | + so override_settings cannot reach them - build the expectation from the setting. |
| 2427 | + """ |
| 2428 | + |
| 2429 | + def test_subseries_html_redirects_to_rfc_editor(self): |
| 2430 | + for name in ["bcp1", "std2", "fyi3"]: |
| 2431 | + for suffix in ["", "/", ".txt", ".html"]: |
| 2432 | + url = f"/doc/html/{name}{suffix}" |
| 2433 | + r = self.client.get(url) |
| 2434 | + self.assertEqual(r.status_code, 302, url) |
| 2435 | + self.assertEqual( |
| 2436 | + r["Location"], |
| 2437 | + f"{settings.RFC_EDITOR_INFO_BASE_URL}{name}/", |
| 2438 | + url, |
| 2439 | + ) |
| 2440 | + |
| 2441 | + |
2348 | 2442 | class ReferencesTest(TestCase): |
2349 | 2443 |
|
2350 | 2444 | def test_references(self): |
|
0 commit comments