snapshot of https://github.com/zulip/zulip.git @ 48c69911c7dd4e03b20552eb3bd77ad8151c1357 (2026-09-15)
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
This commit is contained in:
207
zerver/tests/test_urls.py
Normal file
207
zerver/tests/test_urls.py
Normal file
@@ -0,0 +1,207 @@
|
||||
import os
|
||||
from unittest import mock
|
||||
|
||||
from django.test import Client
|
||||
|
||||
from zerver.lib.test_classes import ZulipTestCase
|
||||
from zerver.lib.url_redirects import (
|
||||
API_DOCUMENTATION_REDIRECTS,
|
||||
LANDING_PAGE_REDIRECTS,
|
||||
POLICY_DOCUMENTATION_REDIRECTS,
|
||||
)
|
||||
from zerver.models import Stream
|
||||
|
||||
|
||||
class PublicURLTest(ZulipTestCase):
|
||||
"""
|
||||
Account creation URLs are accessible even when not logged in. Authenticated
|
||||
URLs redirect to a page.
|
||||
"""
|
||||
|
||||
def fetch(self, method: str, urls: list[str], expected_status: int) -> None:
|
||||
for url in urls:
|
||||
# e.g. self.client_post(url) if method is "post"
|
||||
response = getattr(self, method)(url)
|
||||
self.assertEqual(
|
||||
response.status_code,
|
||||
expected_status,
|
||||
msg=f"Expected {expected_status}, received {response.status_code} for {method} to {url}",
|
||||
)
|
||||
|
||||
def test_api_doc_pages(self) -> None:
|
||||
# Test all files in api_docs documentation directory (except for 'index.md',
|
||||
# 'missing.md', "api-doc-template.md", `api_docs/include/` and `api_docs/unmerged.d/` files).
|
||||
|
||||
api_doc_urls = []
|
||||
for doc in os.listdir("./api_docs/"):
|
||||
if doc.startswith(".") or "~" in doc or "#" in doc:
|
||||
continue # nocoverage -- just here for convenience
|
||||
if doc in {"index.md", "include", "missing.md", "api-doc-template.md", "unmerged.d"}:
|
||||
continue
|
||||
url = "/api/" + os.path.splitext(doc)[0] # Strip the extension.
|
||||
api_doc_urls.append(url)
|
||||
|
||||
expected_tag = """<meta property="og:description" content="This is an API docs page" />"""
|
||||
|
||||
for url in api_doc_urls:
|
||||
with mock.patch(
|
||||
"zerver.lib.html_to_text.html_to_text", return_value="This is an API docs page"
|
||||
) as m:
|
||||
response = self.client_get(url)
|
||||
m.assert_called_once()
|
||||
self.assertIn(expected_tag, response.content.decode())
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_design_testing_pages(self) -> None:
|
||||
urls = {
|
||||
"/devtools/buttons/": "Button styles browser",
|
||||
"/devtools/banners/": "Banner styles browser",
|
||||
"/devtools/inputs/": "Input styles browser",
|
||||
}
|
||||
|
||||
for url, expected_content in urls.items():
|
||||
result = self.client_get(url)
|
||||
self.assertEqual(result.status_code, 200)
|
||||
self.assert_in_success_response([expected_content], result)
|
||||
|
||||
def test_public_urls(self) -> None:
|
||||
"""
|
||||
Test which views are accessible when not logged in.
|
||||
"""
|
||||
# FIXME: We should also test the Tornado URLs -- this codepath
|
||||
# can't do so because this Django test mechanism doesn't go
|
||||
# through Tornado.
|
||||
denmark_stream_id = Stream.objects.get(name="Denmark").id
|
||||
get_urls = {
|
||||
200: [
|
||||
"/accounts/home/",
|
||||
"/accounts/login/",
|
||||
"/en/accounts/home/",
|
||||
"/ru/accounts/home/",
|
||||
"/en/accounts/login/",
|
||||
"/ru/accounts/login/",
|
||||
"/api/",
|
||||
# Since web-public streams are enabled in this `zulip`
|
||||
# instance, the public access experience is loaded directly.
|
||||
"/",
|
||||
"/en/",
|
||||
"/ru/",
|
||||
],
|
||||
400: [
|
||||
"/json/messages",
|
||||
],
|
||||
401: [
|
||||
f"/json/streams/{denmark_stream_id}/members",
|
||||
"/api/v1/users/me/subscriptions",
|
||||
"/api/v1/messages",
|
||||
"/api/v1/streams",
|
||||
],
|
||||
404: [
|
||||
"/api/api-doc-template",
|
||||
"/api/nonexistent",
|
||||
"/api/include/admin",
|
||||
"/api/" + "z" * 1000,
|
||||
],
|
||||
}
|
||||
|
||||
post_urls = {
|
||||
200: ["/accounts/login/"],
|
||||
302: ["/accounts/logout/"],
|
||||
401: [
|
||||
"/json/messages",
|
||||
"/json/invites",
|
||||
"/api/v1/users/me/subscriptions/properties",
|
||||
"/json/fetch_api_key",
|
||||
"/json/users/me/subscriptions",
|
||||
"/api/v1/users/me/subscriptions",
|
||||
"/json/export/realm",
|
||||
],
|
||||
400: [
|
||||
"/api/v1/external/github",
|
||||
"/api/v1/fetch_api_key",
|
||||
],
|
||||
}
|
||||
patch_urls = {
|
||||
401: ["/json/settings"],
|
||||
}
|
||||
|
||||
for status_code, url_set in get_urls.items():
|
||||
self.fetch("client_get", url_set, status_code)
|
||||
for status_code, url_set in post_urls.items():
|
||||
self.fetch("client_post", url_set, status_code)
|
||||
for status_code, url_set in patch_urls.items():
|
||||
self.fetch("client_patch", url_set, status_code)
|
||||
|
||||
def test_config_error_endpoints_dev_env(self) -> None:
|
||||
"""
|
||||
The content of these pages is tested separately.
|
||||
Here we simply sanity-check that all the URLs load
|
||||
correctly.
|
||||
"""
|
||||
auth_error_pages = [
|
||||
"apple",
|
||||
"dev_not_supported",
|
||||
"github",
|
||||
"gitlab",
|
||||
"google",
|
||||
"ldap",
|
||||
"remote_user_backend_disabled",
|
||||
"remote_user_header_missing",
|
||||
"saml",
|
||||
"smtp",
|
||||
]
|
||||
urls = [f"/config-error/{err_page_name}" for err_page_name in auth_error_pages]
|
||||
with self.settings(DEVELOPMENT=True):
|
||||
for url in urls:
|
||||
with self.assertLogs("django.request", level="ERROR") as m:
|
||||
response = self.client_get(url)
|
||||
self.assertEqual(response.status_code, 500)
|
||||
self.assert_in_response("Configuration error", response)
|
||||
self.assertEqual(
|
||||
m.output,
|
||||
[f"ERROR:django.request:Internal Server Error: {url}"],
|
||||
)
|
||||
|
||||
|
||||
class ErrorPageTest(ZulipTestCase):
|
||||
def test_bogus_http_host(self) -> None:
|
||||
# This tests that we've successfully worked around a certain bug in
|
||||
# Django's exception handling. The enforce_csrf_checks=True,
|
||||
# secure=True, and HTTP_REFERER with an `https:` scheme are all
|
||||
# there to get us down just the right path for Django to blow up
|
||||
# when presented with an HTTP_HOST that's not a valid DNS name.
|
||||
client = Client(enforce_csrf_checks=True)
|
||||
result = client.post(
|
||||
"/json/users", secure=True, HTTP_REFERER="https://somewhere", HTTP_HOST="$nonsense"
|
||||
)
|
||||
self.assertEqual(result.status_code, 400)
|
||||
|
||||
|
||||
class RedirectURLTest(ZulipTestCase):
|
||||
def test_api_redirects(self) -> None:
|
||||
for redirect in API_DOCUMENTATION_REDIRECTS:
|
||||
if redirect.old_url not in [
|
||||
"/api/incoming-webhooks-overview",
|
||||
"/api/incoming-webhooks-walkthrough",
|
||||
]:
|
||||
result = self.client_get(redirect.old_url, follow=True)
|
||||
self.assert_in_success_response(["API documentation home"], result)
|
||||
|
||||
result = self.client_get(redirect.old_url)
|
||||
self.assertEqual(result.status_code, 301)
|
||||
self.assertIn(redirect.new_url, result["Location"])
|
||||
|
||||
def test_policy_redirects(self) -> None:
|
||||
for redirect in POLICY_DOCUMENTATION_REDIRECTS:
|
||||
result = self.client_get(redirect.old_url, follow=True)
|
||||
self.assert_in_success_response(["Policies", "Archive"], result)
|
||||
|
||||
def test_landing_page_redirects(self) -> None:
|
||||
for redirect in LANDING_PAGE_REDIRECTS:
|
||||
if redirect.old_url != "/try-zulip/":
|
||||
result = self.client_get(redirect.old_url, follow=True)
|
||||
self.assert_in_success_response(["Download"], result)
|
||||
|
||||
result = self.client_get(redirect.old_url)
|
||||
self.assertEqual(result.status_code, 301)
|
||||
self.assertIn(redirect.new_url, result["Location"])
|
||||
Reference in New Issue
Block a user