2016-04-14 23:39:37 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
2017-02-09 22:58:43 +01:00
|
|
|
|
|
|
|
import glob
|
2018-01-26 21:12:58 +01:00
|
|
|
import os
|
|
|
|
import re
|
2017-02-09 22:58:43 +01:00
|
|
|
from datetime import timedelta
|
2018-01-22 21:50:22 +01:00
|
|
|
from mock import MagicMock, patch, call
|
2017-08-25 00:12:36 +02:00
|
|
|
from typing import List, Dict, Any, Optional
|
2017-02-09 22:58:43 +01:00
|
|
|
|
2016-04-14 23:39:37 +02:00
|
|
|
from django.conf import settings
|
|
|
|
from django.core.management import call_command
|
2018-01-26 21:15:51 +01:00
|
|
|
from django.test import TestCase, override_settings
|
2018-03-18 20:31:48 +01:00
|
|
|
from zerver.lib.actions import do_create_user
|
2018-05-04 01:04:12 +02:00
|
|
|
from zerver.lib.management import ZulipBaseCommand, CommandError, check_config
|
2017-02-09 22:58:43 +01:00
|
|
|
from zerver.lib.test_classes import ZulipTestCase
|
|
|
|
from zerver.lib.test_helpers import stdout_suppressed
|
2017-10-07 00:29:18 +02:00
|
|
|
from zerver.lib.test_runner import slow
|
2018-03-17 18:11:26 +01:00
|
|
|
from zerver.models import get_user_profile_by_email
|
2018-01-22 21:50:22 +01:00
|
|
|
|
2017-08-25 00:12:36 +02:00
|
|
|
from zerver.models import get_realm, UserProfile, Realm
|
2016-06-22 21:16:02 +02:00
|
|
|
from confirmation.models import RealmCreationKey, generate_realm_creation_url
|
2017-02-09 22:58:43 +01:00
|
|
|
|
2018-05-04 01:04:12 +02:00
|
|
|
class TestCheckConfig(ZulipTestCase):
|
|
|
|
def test_check_config(self) -> None:
|
|
|
|
with self.assertRaisesRegex(CommandError, "Error: You must set ZULIP_ADMINISTRATOR in /etc/zulip/settings.py."):
|
|
|
|
check_config()
|
|
|
|
|
|
|
|
|
2017-07-07 20:35:31 +02:00
|
|
|
class TestZulipBaseCommand(ZulipTestCase):
|
2017-11-05 10:51:25 +01:00
|
|
|
def setUp(self) -> None:
|
2017-08-19 21:00:19 +02:00
|
|
|
self.zulip_realm = get_realm("zulip")
|
2017-08-25 00:12:36 +02:00
|
|
|
self.command = ZulipBaseCommand()
|
2017-08-19 21:00:19 +02:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_get_realm(self) -> None:
|
2017-08-25 00:12:36 +02:00
|
|
|
self.assertEqual(self.command.get_realm(dict(realm_id='zulip')), self.zulip_realm)
|
|
|
|
self.assertEqual(self.command.get_realm(dict(realm_id=None)), None)
|
|
|
|
self.assertEqual(self.command.get_realm(dict(realm_id='1')), self.zulip_realm)
|
2017-08-07 21:32:10 +02:00
|
|
|
with self.assertRaisesRegex(CommandError, "There is no realm with id"):
|
2017-08-25 00:12:36 +02:00
|
|
|
self.command.get_realm(dict(realm_id='17'))
|
2017-08-07 21:32:10 +02:00
|
|
|
with self.assertRaisesRegex(CommandError, "There is no realm with id"):
|
2017-08-25 00:12:36 +02:00
|
|
|
self.command.get_realm(dict(realm_id='mit'))
|
2017-07-07 20:35:31 +02:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_get_user(self) -> None:
|
2017-07-07 20:35:31 +02:00
|
|
|
mit_realm = get_realm("zephyr")
|
|
|
|
user_profile = self.example_user("hamlet")
|
|
|
|
email = user_profile.email
|
|
|
|
|
2017-08-25 00:12:36 +02:00
|
|
|
self.assertEqual(self.command.get_user(email, self.zulip_realm), user_profile)
|
|
|
|
self.assertEqual(self.command.get_user(email, None), user_profile)
|
|
|
|
|
|
|
|
error_message = "The realm '<Realm: zephyr 2>' does not contain a user with email"
|
|
|
|
with self.assertRaisesRegex(CommandError, error_message):
|
|
|
|
self.command.get_user(email, mit_realm)
|
|
|
|
|
2017-07-07 20:35:31 +02:00
|
|
|
with self.assertRaisesRegex(CommandError, "server does not contain a user with email"):
|
2017-08-25 00:12:36 +02:00
|
|
|
self.command.get_user('invalid_email@example.com', None)
|
2018-03-18 20:31:48 +01:00
|
|
|
|
|
|
|
do_create_user(email, 'password', mit_realm, 'full_name', 'short_name')
|
|
|
|
|
|
|
|
with self.assertRaisesRegex(CommandError, "server contains multiple users with that email"):
|
|
|
|
self.command.get_user(email, None)
|
2017-07-07 20:35:31 +02:00
|
|
|
|
2018-03-17 18:11:26 +01:00
|
|
|
def test_get_user_profile_by_email(self) -> None:
|
|
|
|
user_profile = self.example_user("hamlet")
|
|
|
|
email = user_profile.email
|
|
|
|
|
|
|
|
self.assertEqual(get_user_profile_by_email(email), user_profile)
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def get_users_sorted(self, options: Dict[str, Any], realm: Optional[Realm]) -> List[UserProfile]:
|
2017-08-25 00:12:36 +02:00
|
|
|
user_profiles = self.command.get_users(options, realm)
|
|
|
|
return sorted(user_profiles, key = lambda x: x.email)
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_get_users(self) -> None:
|
2017-08-25 00:12:36 +02:00
|
|
|
user_emails = self.example_email("hamlet") + "," + self.example_email("iago")
|
|
|
|
expected_user_profiles = [self.example_user("hamlet"), self.example_user("iago")]
|
|
|
|
user_profiles = self.get_users_sorted(dict(users=user_emails), self.zulip_realm)
|
|
|
|
self.assertEqual(user_profiles, expected_user_profiles)
|
|
|
|
user_profiles = self.get_users_sorted(dict(users=user_emails), None)
|
|
|
|
self.assertEqual(user_profiles, expected_user_profiles)
|
2017-08-19 21:00:19 +02:00
|
|
|
|
2017-08-25 00:12:36 +02:00
|
|
|
user_emails = self.example_email("iago") + "," + self.mit_email("sipbtest")
|
|
|
|
expected_user_profiles = [self.example_user("iago"), self.mit_user("sipbtest")]
|
|
|
|
user_profiles = self.get_users_sorted(dict(users=user_emails), None)
|
|
|
|
self.assertEqual(user_profiles, expected_user_profiles)
|
|
|
|
error_message = "The realm '<Realm: zulip 1>' does not contain a user with email"
|
|
|
|
with self.assertRaisesRegex(CommandError, error_message):
|
|
|
|
self.command.get_users(dict(users=user_emails), self.zulip_realm)
|
2017-08-19 21:00:19 +02:00
|
|
|
|
2017-08-25 00:12:36 +02:00
|
|
|
self.assertEqual(self.command.get_users(dict(users=self.example_email("iago")), self.zulip_realm),
|
2017-08-19 21:00:19 +02:00
|
|
|
[self.example_user("iago")])
|
2017-08-25 00:12:36 +02:00
|
|
|
|
|
|
|
self.assertEqual(self.command.get_users(dict(users=None), None), [])
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_get_users_with_all_users_argument_enabled(self) -> None:
|
2017-08-25 00:12:36 +02:00
|
|
|
user_emails = self.example_email("hamlet") + "," + self.example_email("iago")
|
|
|
|
expected_user_profiles = [self.example_user("hamlet"), self.example_user("iago")]
|
|
|
|
user_profiles = self.get_users_sorted(dict(users=user_emails, all_users=False), self.zulip_realm)
|
|
|
|
self.assertEqual(user_profiles, expected_user_profiles)
|
|
|
|
error_message = "You can't use both -u/--users and -a/--all-users."
|
|
|
|
with self.assertRaisesRegex(CommandError, error_message):
|
|
|
|
self.command.get_users(dict(users=user_emails, all_users=True), None)
|
|
|
|
|
|
|
|
expected_user_profiles = sorted(UserProfile.objects.filter(realm=self.zulip_realm),
|
|
|
|
key = lambda x: x.email)
|
|
|
|
user_profiles = self.get_users_sorted(dict(users=None, all_users=True), self.zulip_realm)
|
|
|
|
self.assertEqual(user_profiles, expected_user_profiles)
|
|
|
|
|
|
|
|
error_message = "You have to pass either -u/--users or -a/--all-users."
|
|
|
|
with self.assertRaisesRegex(CommandError, error_message):
|
|
|
|
self.command.get_users(dict(users=None, all_users=False), None)
|
|
|
|
|
|
|
|
error_message = "The --all-users option requires a realm; please pass --realm."
|
|
|
|
with self.assertRaisesRegex(CommandError, error_message):
|
|
|
|
self.command.get_users(dict(users=None, all_users=True), None)
|
2017-08-19 21:00:19 +02:00
|
|
|
|
2017-02-09 22:58:43 +01:00
|
|
|
class TestCommandsCanStart(TestCase):
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def setUp(self) -> None:
|
2017-02-09 22:58:43 +01:00
|
|
|
self.commands = filter(
|
|
|
|
lambda filename: filename != '__init__',
|
|
|
|
map(
|
|
|
|
lambda file: os.path.basename(file).replace('.py', ''),
|
|
|
|
glob.iglob('*/management/commands/*.py')
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2017-10-07 00:29:18 +02:00
|
|
|
@slow("Aggregate of runs dozens of individual --help tests")
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_management_commands_show_help(self) -> None:
|
2017-02-09 22:58:43 +01:00
|
|
|
with stdout_suppressed() as stdout:
|
|
|
|
for command in self.commands:
|
|
|
|
print('Testing management command: {}'.format(command),
|
|
|
|
file=stdout)
|
|
|
|
|
|
|
|
with self.assertRaises(SystemExit):
|
|
|
|
call_command(command, '--help')
|
2017-03-24 07:55:20 +01:00
|
|
|
# zerver/management/commands/runtornado.py sets this to True;
|
|
|
|
# we need to reset it here. See #3685 for details.
|
|
|
|
settings.RUNNING_INSIDE_TORNADO = False
|
2016-04-14 23:39:37 +02:00
|
|
|
|
|
|
|
class TestSendWebhookFixtureMessage(TestCase):
|
|
|
|
COMMAND_NAME = 'send_webhook_fixture_message'
|
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def setUp(self) -> None:
|
2016-04-14 23:39:37 +02:00
|
|
|
self.fixture_path = os.path.join('some', 'fake', 'path.json')
|
|
|
|
self.url = '/some/url/with/hook'
|
|
|
|
|
|
|
|
@patch('zerver.management.commands.send_webhook_fixture_message.Command.print_help')
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_check_if_command_exits_when_fixture_param_is_empty(self, print_help_mock: MagicMock) -> None:
|
2016-04-14 23:39:37 +02:00
|
|
|
with self.assertRaises(SystemExit):
|
|
|
|
call_command(self.COMMAND_NAME, url=self.url)
|
|
|
|
|
2016-11-22 01:44:16 +01:00
|
|
|
print_help_mock.assert_any_call('./manage.py', self.COMMAND_NAME)
|
2016-04-14 23:39:37 +02:00
|
|
|
|
|
|
|
@patch('zerver.management.commands.send_webhook_fixture_message.Command.print_help')
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_check_if_command_exits_when_url_param_is_empty(self, print_help_mock: MagicMock) -> None:
|
2016-04-14 23:39:37 +02:00
|
|
|
with self.assertRaises(SystemExit):
|
|
|
|
call_command(self.COMMAND_NAME, fixture=self.fixture_path)
|
|
|
|
|
2016-11-22 01:44:16 +01:00
|
|
|
print_help_mock.assert_any_call('./manage.py', self.COMMAND_NAME)
|
2016-04-14 23:39:37 +02:00
|
|
|
|
|
|
|
@patch('zerver.management.commands.send_webhook_fixture_message.os.path.exists')
|
2017-11-17 07:00:53 +01:00
|
|
|
def test_check_if_command_exits_when_fixture_path_does_not_exist(
|
|
|
|
self, os_path_exists_mock: MagicMock) -> None:
|
2016-04-14 23:39:37 +02:00
|
|
|
os_path_exists_mock.return_value = False
|
|
|
|
|
|
|
|
with self.assertRaises(SystemExit):
|
|
|
|
call_command(self.COMMAND_NAME, fixture=self.fixture_path, url=self.url)
|
|
|
|
|
|
|
|
os_path_exists_mock.assert_any_call(os.path.join(settings.DEPLOY_ROOT, self.fixture_path))
|
|
|
|
|
|
|
|
@patch('zerver.management.commands.send_webhook_fixture_message.os.path.exists')
|
|
|
|
@patch('zerver.management.commands.send_webhook_fixture_message.Client')
|
|
|
|
@patch('zerver.management.commands.send_webhook_fixture_message.ujson')
|
|
|
|
@patch("zerver.management.commands.send_webhook_fixture_message.open", create=True)
|
|
|
|
def test_check_if_command_post_request_to_url_with_fixture(self,
|
2017-11-20 03:22:57 +01:00
|
|
|
open_mock: MagicMock,
|
|
|
|
ujson_mock: MagicMock,
|
|
|
|
client_mock: MagicMock,
|
|
|
|
os_path_exists_mock: MagicMock) -> None:
|
2016-04-14 23:39:37 +02:00
|
|
|
ujson_mock.loads.return_value = '{}'
|
|
|
|
ujson_mock.dumps.return_value = {}
|
|
|
|
os_path_exists_mock.return_value = True
|
|
|
|
|
|
|
|
client = client_mock()
|
|
|
|
|
2017-10-20 18:16:38 +02:00
|
|
|
with self.assertRaises(SystemExit):
|
|
|
|
call_command(self.COMMAND_NAME, fixture=self.fixture_path, url=self.url)
|
2016-04-14 23:39:37 +02:00
|
|
|
self.assertTrue(ujson_mock.dumps.called)
|
|
|
|
self.assertTrue(ujson_mock.loads.called)
|
|
|
|
self.assertTrue(open_mock.called)
|
2017-10-09 06:20:35 +02:00
|
|
|
client.post.assert_called_once_with(self.url, {}, content_type="application/json",
|
|
|
|
HTTP_HOST="zulip.testserver")
|
2016-06-22 21:16:02 +02:00
|
|
|
|
2016-08-23 02:08:42 +02:00
|
|
|
class TestGenerateRealmCreationLink(ZulipTestCase):
|
2016-06-22 21:16:02 +02:00
|
|
|
COMMAND_NAME = "generate_realm_creation_link"
|
|
|
|
|
2018-01-26 21:15:51 +01:00
|
|
|
@override_settings(OPEN_REALM_CREATION=False)
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_generate_link_and_create_realm(self) -> None:
|
2016-06-22 21:16:02 +02:00
|
|
|
email = "user1@test.com"
|
2018-01-29 19:58:52 +01:00
|
|
|
generated_link = generate_realm_creation_url(by_admin=True)
|
2016-06-22 21:16:02 +02:00
|
|
|
|
2018-01-26 21:19:20 +01:00
|
|
|
# Get realm creation page
|
2018-01-26 21:15:51 +01:00
|
|
|
result = self.client_get(generated_link)
|
|
|
|
self.assert_in_success_response([u"Create a new Zulip organization"], result)
|
2016-06-22 21:16:02 +02:00
|
|
|
|
2018-01-26 21:19:20 +01:00
|
|
|
# Enter email
|
2018-01-26 21:15:51 +01:00
|
|
|
self.assertIsNone(get_realm('test'))
|
|
|
|
result = self.client_post(generated_link, {'email': email})
|
|
|
|
self.assertEqual(result.status_code, 302)
|
|
|
|
self.assertTrue(re.search('/accounts/do_confirm/\w+$', result["Location"]))
|
2018-01-26 21:19:20 +01:00
|
|
|
|
|
|
|
# Bypass sending mail for confirmation, go straight to creation form
|
2018-01-26 21:15:51 +01:00
|
|
|
result = self.client_get(result["Location"])
|
|
|
|
self.assert_in_response('action="/accounts/register/"', result)
|
2016-06-22 21:16:02 +02:00
|
|
|
|
2018-01-26 21:19:20 +01:00
|
|
|
# Original link is now dead
|
2018-01-26 21:15:51 +01:00
|
|
|
result = self.client_get(generated_link)
|
|
|
|
self.assert_in_success_response(["The organization creation link has expired or is not valid."], result)
|
2016-06-22 21:16:02 +02:00
|
|
|
|
2018-01-26 21:15:51 +01:00
|
|
|
@override_settings(OPEN_REALM_CREATION=False)
|
2018-01-26 21:12:58 +01:00
|
|
|
def test_generate_link_confirm_email(self) -> None:
|
|
|
|
email = "user1@test.com"
|
|
|
|
generated_link = generate_realm_creation_url(by_admin=False)
|
|
|
|
|
2018-01-26 21:15:51 +01:00
|
|
|
result = self.client_post(generated_link, {'email': email})
|
|
|
|
self.assertEqual(result.status_code, 302)
|
|
|
|
self.assertTrue(re.search('/accounts/send_confirm/{}$'.format(email),
|
|
|
|
result["Location"]))
|
|
|
|
result = self.client_get(result["Location"])
|
|
|
|
self.assert_in_response("Check your email so we can get started", result)
|
2018-01-26 21:12:58 +01:00
|
|
|
|
2018-01-26 21:15:51 +01:00
|
|
|
# Original link is now dead
|
|
|
|
result = self.client_get(generated_link)
|
|
|
|
self.assert_in_success_response(["The organization creation link has expired or is not valid."], result)
|
2018-01-26 21:12:58 +01:00
|
|
|
|
2018-01-26 21:15:51 +01:00
|
|
|
@override_settings(OPEN_REALM_CREATION=False)
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_realm_creation_with_random_link(self) -> None:
|
2018-01-26 21:15:51 +01:00
|
|
|
# Realm creation attempt with an invalid link should fail
|
2018-02-28 16:41:21 +01:00
|
|
|
random_link = "/new/5e89081eb13984e0f3b130bf7a4121d153f1614b"
|
2018-01-26 21:15:51 +01:00
|
|
|
result = self.client_get(random_link)
|
|
|
|
self.assert_in_success_response(["The organization creation link has expired or is not valid."], result)
|
2016-06-22 21:16:02 +02:00
|
|
|
|
2018-01-26 21:15:51 +01:00
|
|
|
@override_settings(OPEN_REALM_CREATION=False)
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_realm_creation_with_expired_link(self) -> None:
|
2018-01-26 21:15:51 +01:00
|
|
|
generated_link = generate_realm_creation_url(by_admin=True)
|
|
|
|
key = generated_link[-24:]
|
|
|
|
# Manually expire the link by changing the date of creation
|
|
|
|
obj = RealmCreationKey.objects.get(creation_key=key)
|
|
|
|
obj.date_created = obj.date_created - timedelta(days=settings.REALM_CREATION_LINK_VALIDITY_DAYS + 1)
|
|
|
|
obj.save()
|
|
|
|
|
|
|
|
result = self.client_get(generated_link)
|
|
|
|
self.assert_in_success_response(["The organization creation link has expired or is not valid."], result)
|
2018-01-22 21:50:22 +01:00
|
|
|
|
|
|
|
class TestCalculateFirstVisibleMessageID(ZulipTestCase):
|
|
|
|
COMMAND_NAME = 'calculate_first_visible_message_id'
|
|
|
|
|
|
|
|
def test_check_if_command_calls_maybe_update_first_visible_message_id(self) -> None:
|
|
|
|
with patch('zerver.lib.message.maybe_update_first_visible_message_id') as m:
|
|
|
|
call_command(self.COMMAND_NAME, "--realm=zulip", "--lookback-hours=30")
|
|
|
|
m.assert_called_with(get_realm("zulip"), 30)
|
|
|
|
|
|
|
|
with patch('zerver.lib.message.maybe_update_first_visible_message_id') as m:
|
|
|
|
call_command(self.COMMAND_NAME, "--lookback-hours=35")
|
|
|
|
calls = [call(realm, 35) for realm in Realm.objects.all()]
|
|
|
|
m.has_calls(calls, any_order=True)
|