2016-02-08 04:00:12 +01:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
2017-03-08 12:41:46 +01:00
|
|
|
import importlib
|
|
|
|
import os
|
|
|
|
import ujson
|
|
|
|
|
2016-02-08 04:00:12 +01:00
|
|
|
import django.core.urlresolvers
|
|
|
|
from django.test import TestCase
|
2017-03-09 09:20:38 +01:00
|
|
|
from typing import List, Optional
|
2017-03-08 12:41:46 +01:00
|
|
|
|
|
|
|
from zerver.lib.test_classes import ZulipTestCase
|
2017-10-07 00:29:18 +02:00
|
|
|
from zerver.lib.test_runner import slow
|
2017-03-08 12:41:46 +01:00
|
|
|
from zerver.models import Stream
|
2016-02-08 04:00:12 +01:00
|
|
|
from zproject import urls
|
|
|
|
|
2017-03-08 12:41:46 +01:00
|
|
|
class PublicURLTest(ZulipTestCase):
|
|
|
|
"""
|
|
|
|
Account creation URLs are accessible even when not logged in. Authenticated
|
|
|
|
URLs redirect to a page.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def fetch(self, method, urls, expected_status):
|
|
|
|
# type: (str, List[str], 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="Expected %d, received %d for %s to %s" % (
|
|
|
|
expected_status, response.status_code, method, url))
|
|
|
|
|
2017-10-07 00:29:18 +02:00
|
|
|
@slow("Tests dozens of endpoints, including all of our /help/ documents")
|
2017-03-08 12:41:46 +01:00
|
|
|
def test_public_urls(self):
|
|
|
|
# type: () -> 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/",
|
|
|
|
"/help/"],
|
|
|
|
302: ["/", "/en/", "/ru/"],
|
|
|
|
401: ["/json/streams/%d/members" % (denmark_stream_id,),
|
|
|
|
"/api/v1/users/me/subscriptions",
|
|
|
|
"/api/v1/messages",
|
|
|
|
"/json/messages",
|
|
|
|
"/api/v1/streams",
|
|
|
|
],
|
2017-10-02 19:51:17 +02:00
|
|
|
404: ["/help/nonexistent", "/help/include/admin"],
|
2017-03-08 12:41:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
# Add all files in 'templates/zerver/help' directory (except for 'main.html' and
|
|
|
|
# 'index.md') to `get_urls['200']` list.
|
|
|
|
for doc in os.listdir('./templates/zerver/help'):
|
|
|
|
if doc.startswith(".") or '~' in doc or '#' in doc:
|
|
|
|
continue # nocoverage -- just here for convenience
|
|
|
|
if doc not in {'main.html', 'index.md', 'include'}:
|
2017-05-17 21:56:24 +02:00
|
|
|
get_urls[200].append('/help/' + os.path.splitext(doc)[0]) # Strip the extension.
|
2017-03-08 12:41:46 +01:00
|
|
|
|
|
|
|
post_urls = {200: ["/accounts/login/"],
|
|
|
|
302: ["/accounts/logout/"],
|
|
|
|
401: ["/json/messages",
|
2017-07-31 20:55:57 +02:00
|
|
|
"/json/invites",
|
2017-03-08 12:41:46 +01:00
|
|
|
"/json/subscriptions/exists",
|
2017-05-09 07:01:42 +02:00
|
|
|
"/api/v1/users/me/subscriptions/properties",
|
2017-03-08 12:41:46 +01:00
|
|
|
"/json/fetch_api_key",
|
|
|
|
"/json/users/me/pointer",
|
|
|
|
"/json/users/me/subscriptions",
|
|
|
|
"/api/v1/users/me/subscriptions",
|
|
|
|
],
|
|
|
|
400: ["/api/v1/external/github",
|
|
|
|
"/api/v1/fetch_api_key",
|
|
|
|
],
|
|
|
|
}
|
2017-07-31 20:44:52 +02:00
|
|
|
patch_urls = {
|
|
|
|
401: ["/json/settings"],
|
|
|
|
}
|
2017-03-08 12:41:46 +01:00
|
|
|
put_urls = {401: ["/json/users/me/pointer"],
|
|
|
|
}
|
2017-09-27 10:11:59 +02:00
|
|
|
for status_code, url_set in get_urls.items():
|
2017-03-08 12:41:46 +01:00
|
|
|
self.fetch("client_get", url_set, status_code)
|
2017-09-27 10:11:59 +02:00
|
|
|
for status_code, url_set in post_urls.items():
|
2017-03-08 12:41:46 +01:00
|
|
|
self.fetch("client_post", url_set, status_code)
|
2017-09-27 10:11:59 +02:00
|
|
|
for status_code, url_set in patch_urls.items():
|
2017-07-31 20:44:52 +02:00
|
|
|
self.fetch("client_patch", url_set, status_code)
|
2017-09-27 10:11:59 +02:00
|
|
|
for status_code, url_set in put_urls.items():
|
2017-03-08 12:41:46 +01:00
|
|
|
self.fetch("client_put", url_set, status_code)
|
|
|
|
|
|
|
|
def test_get_gcid_when_not_configured(self):
|
|
|
|
# type: () -> None
|
|
|
|
with self.settings(GOOGLE_CLIENT_ID=None):
|
|
|
|
resp = self.client_get("/api/v1/fetch_google_client_id")
|
|
|
|
self.assertEqual(400, resp.status_code,
|
|
|
|
msg="Expected 400, received %d for GET /api/v1/fetch_google_client_id" % (
|
|
|
|
resp.status_code,))
|
2017-08-16 09:52:31 +02:00
|
|
|
self.assertEqual('error', resp.json()['result'])
|
2017-03-08 12:41:46 +01:00
|
|
|
|
|
|
|
def test_get_gcid_when_configured(self):
|
|
|
|
# type: () -> None
|
|
|
|
with self.settings(GOOGLE_CLIENT_ID="ABCD"):
|
|
|
|
resp = self.client_get("/api/v1/fetch_google_client_id")
|
|
|
|
self.assertEqual(200, resp.status_code,
|
|
|
|
msg="Expected 200, received %d for GET /api/v1/fetch_google_client_id" % (
|
|
|
|
resp.status_code,))
|
|
|
|
data = ujson.loads(resp.content)
|
|
|
|
self.assertEqual('success', data['result'])
|
|
|
|
self.assertEqual('ABCD', data['google_client_id'])
|
|
|
|
|
2016-02-08 04:00:12 +01:00
|
|
|
class URLResolutionTest(TestCase):
|
2017-03-09 09:20:38 +01:00
|
|
|
def get_callback_string(self, pattern):
|
|
|
|
# type: (django.core.urlresolvers.RegexURLPattern) -> Optional[str]
|
|
|
|
callback_str = hasattr(pattern, 'lookup_str') and 'lookup_str'
|
|
|
|
callback_str = callback_str or '_callback_str'
|
|
|
|
return getattr(pattern, callback_str, None)
|
|
|
|
|
2016-02-08 04:00:12 +01:00
|
|
|
def check_function_exists(self, module_name, view):
|
2016-06-04 20:28:02 +02:00
|
|
|
# type: (str, str) -> None
|
2016-02-08 04:00:12 +01:00
|
|
|
module = importlib.import_module(module_name)
|
|
|
|
self.assertTrue(hasattr(module, view), "View %s.%s does not exist" % (module_name, view))
|
|
|
|
|
|
|
|
# Tests that all views in urls.v1_api_and_json_patterns exist
|
|
|
|
def test_rest_api_url_resolution(self):
|
2016-06-04 20:28:02 +02:00
|
|
|
# type: () -> None
|
2016-02-08 04:00:12 +01:00
|
|
|
for pattern in urls.v1_api_and_json_patterns:
|
2017-03-09 09:20:38 +01:00
|
|
|
callback_str = self.get_callback_string(pattern)
|
|
|
|
if callback_str and hasattr(pattern, "default_args"):
|
|
|
|
for func_string in pattern.default_args.values():
|
2017-08-22 19:01:17 +02:00
|
|
|
if isinstance(func_string, tuple):
|
|
|
|
func_string = func_string[0]
|
2017-03-09 09:20:38 +01:00
|
|
|
module_name, view = func_string.rsplit('.', 1)
|
|
|
|
self.check_function_exists(module_name, view)
|
2016-02-08 04:00:12 +01:00
|
|
|
|
|
|
|
# Tests function-based views declared in urls.urlpatterns for
|
|
|
|
# whether the function exists. We at present do not test the
|
|
|
|
# class-based views.
|
|
|
|
def test_non_api_url_resolution(self):
|
2016-06-04 20:28:02 +02:00
|
|
|
# type: () -> None
|
2016-02-08 04:00:12 +01:00
|
|
|
for pattern in urls.urlpatterns:
|
2017-03-09 09:20:38 +01:00
|
|
|
callback_str = self.get_callback_string(pattern)
|
|
|
|
if callback_str:
|
|
|
|
(module_name, base_view) = callback_str.rsplit(".", 1)
|
|
|
|
self.check_function_exists(module_name, base_view)
|