2013-03-20 22:08:48 +01:00
# -*- coding: utf-8 -*-
2013-04-23 18:51:17 +02:00
from __future__ import absolute_import
2013-03-20 22:08:48 +01:00
2012-08-31 20:11:15 +02:00
from django . test import TestCase
2012-11-14 20:50:47 +01:00
from django . test . simple import DjangoTestSuiteRunner
2012-11-08 00:48:43 +01:00
from django . utils . timezone import now
2013-08-13 19:21:45 +02:00
from django . core . exceptions import ValidationError
2012-08-31 20:11:15 +02:00
from django . db . models import Q
2012-08-28 18:44:51 +02:00
2013-07-29 23:03:31 +02:00
from zerver . models import Message , UserProfile , Stream , Recipient , Subscription , \
2013-07-02 00:20:43 +02:00
get_display_recipient , Realm , Client , \
2013-07-02 21:50:05 +02:00
PreregistrationUser , UserMessage , \
2013-08-22 23:55:37 +02:00
get_user_profile_by_email , email_to_domain , get_realm
2013-07-29 23:03:31 +02:00
from zerver . tornadoviews import json_get_updates , api_get_messages
2013-08-28 21:37:21 +02:00
from zerver . decorator import RespondAsynchronously , \
RequestVariableConversionError , profiled , JsonableError
2013-07-29 23:03:31 +02:00
from zerver . lib . initial_password import initial_password
2013-08-28 21:29:55 +02:00
from zerver . lib . actions import check_send_message , gather_subscriptions , \
2013-08-22 23:55:37 +02:00
create_stream_if_needed , do_add_subscription , compute_mit_user_fullname , \
do_add_realm_emoji , do_remove_realm_emoji
2013-07-29 23:03:31 +02:00
from zerver . lib . rate_limiter import add_ratelimit_rule , remove_ratelimit_rule
from zerver . lib import bugdown
from zerver . lib . cache import bounce_key_prefix_for_testing
from zerver . lib . rate_limiter import clear_user_history
2013-09-03 22:41:17 +02:00
from zerver . lib . alert_words import alert_words_in_realm , user_alert_words , \
add_user_alert_words , remove_user_alert_words
2013-08-13 19:21:45 +02:00
from zerver . forms import not_mit_mailing_list
2012-08-28 18:44:51 +02:00
2013-08-22 17:37:02 +02:00
import base64
2012-09-27 19:58:42 +02:00
from django . conf import settings
2013-06-19 20:08:48 +02:00
import os
import random
2012-10-02 17:47:18 +02:00
import re
2013-01-10 19:41:49 +01:00
import sys
2013-06-20 18:47:19 +02:00
import time
2013-06-18 23:55:55 +02:00
import ujson
2013-07-16 22:24:55 +02:00
import urllib
2013-03-14 22:12:25 +01:00
import urllib2
from StringIO import StringIO
from boto . s3 . connection import S3Connection
from boto . s3 . key import Key
2013-01-10 19:41:49 +01:00
2013-02-12 21:04:30 +01:00
def bail ( msg ) :
print ' \n ERROR: %s \n ' % ( msg , )
sys . exit ( 1 )
2013-01-10 19:41:49 +01:00
try :
settings . TEST_SUITE
except :
2013-08-06 22:51:47 +02:00
bail ( ' Test suite only runs correctly with --settings=zproject.test_settings ' )
2013-02-12 21:04:30 +01:00
2013-03-28 16:27:24 +01:00
# Even though we don't use pygments directly in this file, we need
# this import.
2013-02-12 21:04:30 +01:00
try :
import pygments
except ImportError :
bail ( ' The Pygments library is required to run the backend test suite. ' )
2012-09-27 19:58:42 +02:00
2012-10-02 17:47:18 +02:00
def find_key_by_email ( address ) :
from django . core . mail import outbox
key_regex = re . compile ( " accounts/do_confirm/([a-f0-9] {40} )> " )
for message in reversed ( outbox ) :
if address in message . to :
return key_regex . search ( message . body ) . groups ( ) [ 0 ]
2012-08-31 20:11:15 +02:00
2013-01-02 21:43:49 +01:00
def message_ids ( result ) :
return set ( message [ ' id ' ] for message in result [ ' messages ' ] )
2013-07-02 00:35:11 +02:00
def message_stream_count ( user_profile ) :
return UserMessage . objects . \
select_related ( " message " ) . \
filter ( user_profile = user_profile ) . \
count ( )
2013-07-01 21:22:29 +02:00
def get_user_messages ( user_profile ) :
query = UserMessage . objects . \
select_related ( " message " ) . \
filter ( user_profile = user_profile ) . \
order_by ( ' message ' )
return [ um . message for um in query ]
2013-07-02 15:53:48 +02:00
def most_recent_message ( user_profile ) :
query = UserMessage . objects . \
select_related ( " message " ) . \
filter ( user_profile = user_profile ) . \
order_by ( ' -message ' )
return query [ 0 ] . message # Django does LIMIT here
2013-06-20 20:46:28 +02:00
def slow ( expected_run_time , slowness_reason ) :
'''
This is a decorate that annotates a test as being " known
to be slow . " The decorator will set expected_run_time and slowness_reason
as atributes of the function . Other code can use this annotation
as needed , e . g . to exclude these tests in " fast " mode .
'''
def decorator ( f ) :
f . expected_run_time = expected_run_time
f . slowness_reason = slowness_reason
return f
return decorator
2013-06-20 23:27:08 +02:00
def is_known_slow_test ( test_method ) :
return hasattr ( test_method , ' slowness_reason ' )
2013-07-01 18:06:19 +02:00
API_KEYS = { }
2012-08-31 20:11:15 +02:00
class AuthedTestCase ( TestCase ) :
2013-07-16 22:24:55 +02:00
def client_patch ( self , url , info ) :
# self.client.patch will be available in later versions of Django,
# although we may still want our version for the url encoding
info = urllib . urlencode ( info )
return self . client . generic ( ' PATCH ' , url , info )
2012-10-12 17:49:22 +02:00
def login ( self , email , password = None ) :
if password is None :
password = initial_password ( email )
2012-08-31 20:11:15 +02:00
return self . client . post ( ' /accounts/login/ ' ,
2012-10-12 17:49:22 +02:00
{ ' username ' : email , ' password ' : password } )
2012-08-31 20:11:15 +02:00
def register ( self , username , password ) :
2012-10-02 17:47:18 +02:00
self . client . post ( ' /accounts/home/ ' ,
2013-07-24 20:56:42 +02:00
{ ' email ' : username + ' @zulip.com ' } )
2013-01-04 19:06:34 +01:00
return self . submit_reg_form_for_user ( username , password )
def submit_reg_form_for_user ( self , username , password ) :
"""
Stage two of the two - step registration process .
If things are working correctly the account should be fully
registered after this call .
"""
2012-08-31 20:11:15 +02:00
return self . client . post ( ' /accounts/register/ ' ,
2012-11-02 21:13:35 +01:00
{ ' full_name ' : username , ' password ' : password ,
2013-07-24 20:56:42 +02:00
' key ' : find_key_by_email ( username + ' @zulip.com ' ) ,
2012-11-02 21:13:35 +01:00
' terms ' : True } )
2013-01-04 19:06:34 +01:00
2012-11-15 19:42:17 +01:00
def get_api_key ( self , email ) :
2013-07-01 18:06:19 +02:00
if email not in API_KEYS :
2013-07-02 21:50:05 +02:00
API_KEYS [ email ] = get_user_profile_by_email ( email ) . api_key
2013-07-01 18:06:19 +02:00
return API_KEYS [ email ]
2012-08-31 20:11:15 +02:00
2013-08-22 17:37:02 +02:00
def api_auth ( self , email ) :
credentials = " %s : %s " % ( email , self . get_api_key ( email ) )
return {
' HTTP_AUTHORIZATION ' : ' Basic ' + base64 . b64encode ( credentials )
}
2013-03-22 21:46:27 +01:00
def get_streams ( self , email ) :
"""
Helper function to get the stream names for a user
"""
2013-07-02 21:50:05 +02:00
user_profile = get_user_profile_by_email ( email )
2013-03-22 21:46:27 +01:00
subs = Subscription . objects . filter (
user_profile = user_profile ,
active = True ,
recipient__type = Recipient . STREAM )
return [ get_display_recipient ( sub . recipient ) for sub in subs ]
2013-03-22 15:07:50 +01:00
def send_message ( self , sender_name , recipient_name , message_type ,
content = " test content " , subject = " test " ) :
2013-07-02 21:50:05 +02:00
sender = get_user_profile_by_email ( sender_name )
2012-10-03 21:16:34 +02:00
if message_type == Recipient . PERSONAL :
2013-08-28 21:29:55 +02:00
message_type_name = " private "
2012-08-31 20:11:15 +02:00
else :
2013-08-28 21:29:55 +02:00
message_type_name = " stream "
recipient_list = [ recipient_name ] # Doesn't work for group PMs.
2012-10-22 19:23:11 +02:00
( sending_client , _ ) = Client . objects . get_or_create ( name = " test suite " )
2013-08-28 21:29:55 +02:00
return check_send_message (
sender , sending_client , message_type_name , recipient_list , subject ,
content , forged = False , forged_timestamp = None ,
forwarder_user_profile = sender , realm = sender . realm )
2012-08-31 20:11:15 +02:00
2013-07-19 18:33:32 +02:00
def get_old_messages ( self , anchor = 1 , num_before = 100 , num_after = 100 ) :
2013-03-27 20:06:02 +01:00
post_params = { " anchor " : anchor , " num_before " : num_before ,
" num_after " : num_after }
result = self . client . post ( " /json/get_old_messages " , dict ( post_params ) )
2013-06-18 23:55:55 +02:00
data = ujson . loads ( result . content )
2013-03-27 20:06:02 +01:00
return data [ ' messages ' ]
2012-10-10 23:13:04 +02:00
def users_subscribed_to_stream ( self , stream_name , realm_domain ) :
2012-09-05 22:30:50 +02:00
realm = Realm . objects . get ( domain = realm_domain )
2012-10-10 23:13:04 +02:00
stream = Stream . objects . get ( name = stream_name , realm = realm )
2012-10-10 22:57:21 +02:00
recipient = Recipient . objects . get ( type_id = stream . id , type = Recipient . STREAM )
2012-09-05 21:55:40 +02:00
subscriptions = Subscription . objects . filter ( recipient = recipient )
2012-08-31 20:11:15 +02:00
2013-03-29 19:37:21 +01:00
return [ subscription . user_profile for subscription in subscriptions ]
2012-08-31 20:11:15 +02:00
2012-09-06 21:34:38 +02:00
def assert_json_success ( self , result ) :
"""
Successful POSTs return a 200 and JSON of the form { " result " : " success " ,
" msg " : " " } .
"""
2013-01-17 18:12:02 +01:00
self . assertEqual ( result . status_code , 200 )
2013-06-18 23:55:55 +02:00
json = ujson . loads ( result . content )
2013-01-17 18:12:02 +01:00
self . assertEqual ( json . get ( " result " ) , " success " )
2012-09-06 21:34:38 +02:00
# We have a msg key for consistency with errors, but it typically has an
# empty value.
2013-01-02 22:07:09 +01:00
self . assertIn ( " msg " , json )
2012-09-06 21:34:38 +02:00
2012-12-20 23:57:26 +01:00
def get_json_error ( self , result ) :
2013-01-17 18:12:02 +01:00
self . assertEqual ( result . status_code , 400 )
2013-06-18 23:55:55 +02:00
json = ujson . loads ( result . content )
2013-01-17 18:12:02 +01:00
self . assertEqual ( json . get ( " result " ) , " error " )
2012-12-20 23:57:26 +01:00
return json [ ' msg ' ]
2012-09-06 21:34:38 +02:00
def assert_json_error ( self , result , msg ) :
"""
Invalid POSTs return a 400 and JSON of the form { " result " : " error " ,
" msg " : " reason " } .
"""
2013-01-17 18:12:02 +01:00
self . assertEqual ( self . get_json_error ( result ) , msg )
2012-12-20 23:57:26 +01:00
def assert_json_error_contains ( self , result , msg_substring ) :
self . assertIn ( msg_substring , self . get_json_error ( result ) )
2012-08-31 20:11:15 +02:00
2013-04-18 17:13:21 +02:00
def fixture_data ( self , type , action , file_type = ' json ' ) :
2013-04-01 23:46:55 +02:00
return open ( os . path . join ( os . path . dirname ( __file__ ) ,
2013-04-18 17:13:21 +02:00
" fixtures/ %s / %s _ %s . %s " % ( type , type , action , file_type ) ) ) . read ( )
2013-04-02 19:02:49 +02:00
2013-06-25 16:18:39 +02:00
# Subscribe to a stream directly
2013-05-01 19:19:31 +02:00
def subscribe_to_stream ( self , email , stream_name ) :
2013-07-24 20:56:42 +02:00
stream , _ = create_stream_if_needed ( Realm . objects . get ( domain = " zulip.com " ) , stream_name )
2013-07-02 21:50:05 +02:00
user_profile = get_user_profile_by_email ( email )
2013-05-01 19:19:31 +02:00
do_add_subscription ( user_profile , stream , no_log = True )
2013-06-25 16:18:39 +02:00
# Subscribe to a stream by making an API request
def common_subscribe_to_streams ( self , email , streams , extra_post_data = { } , invite_only = False ) :
api_key = self . get_api_key ( email )
post_data = { ' email ' : email ,
' api-key ' : api_key ,
2013-06-24 21:32:56 +02:00
' subscriptions ' : ujson . dumps ( [ { " name " : stream } for stream in streams ] ) ,
2013-06-25 16:18:39 +02:00
' invite_only ' : ujson . dumps ( invite_only ) }
post_data . update ( extra_post_data )
result = self . client . post ( " /api/v1/subscriptions/add " , post_data )
return result
2013-04-02 19:02:49 +02:00
def send_json_payload ( self , email , url , payload , stream_name = None , * * post_params ) :
if stream_name != None :
2013-05-01 19:19:31 +02:00
self . subscribe_to_stream ( email , stream_name )
2013-04-02 19:02:49 +02:00
result = self . client . post ( url , payload , * * post_params )
self . assert_json_success ( result )
# Check the correct message was sent
msg = Message . objects . filter ( ) . order_by ( ' -id ' ) [ 0 ]
self . assertEqual ( msg . sender . email , email )
self . assertEqual ( get_display_recipient ( msg . recipient ) , stream_name )
return msg
2012-08-31 20:11:15 +02:00
class PublicURLTest ( TestCase ) :
"""
Account creation URLs are accessible even when not logged in . Authenticated
URLs redirect to a page .
"""
2013-01-23 17:58:40 +01:00
def fetch ( self , method , urls , expected_status ) :
2012-08-31 20:11:15 +02:00
for url in urls :
2013-01-23 17:58:40 +01:00
if method == " get " :
response = self . client . get ( url )
else :
response = self . client . post ( url )
2012-08-31 20:11:15 +02:00
self . assertEqual ( response . status_code , expected_status ,
2013-01-23 17:58:40 +01:00
msg = " Expected %d , received %d for %s to %s " % (
expected_status , response . status_code , method , url ) )
2012-08-31 20:11:15 +02:00
def test_public_urls ( self ) :
"""
2012-11-01 19:59:23 +01:00
Test which views are accessible when not logged in .
2012-08-31 20:11:15 +02:00
"""
2012-10-16 23:24:58 +02:00
# FIXME: We should also test the Tornado URLs -- this codepath
# can't do so because this Django test mechanism doesn't go
# through Tornado.
2013-01-23 17:58:40 +01:00
get_urls = { 200 : [ " /accounts/home/ " , " /accounts/login/ " ] ,
302 : [ " / " ] ,
2012-08-31 20:11:15 +02:00
}
2013-01-23 17:58:40 +01:00
post_urls = { 200 : [ " /accounts/login/ " ] ,
302 : [ " /accounts/logout/ " ] ,
401 : [ " /json/get_public_streams " ,
" /json/get_old_messages " ,
" /json/update_pointer " ,
" /json/send_message " ,
" /json/invite_users " ,
" /json/settings/change " ,
" /json/subscriptions/list " ,
" /json/subscriptions/remove " ,
" /json/subscriptions/exists " ,
" /json/subscriptions/add " ,
" /json/subscriptions/property " ,
" /json/get_subscribers " ,
" /json/fetch_api_key " ,
] ,
400 : [ " /api/v1/get_profile " ,
" /api/v1/get_old_messages " ,
" /api/v1/get_public_streams " ,
" /api/v1/subscriptions/list " ,
" /api/v1/subscriptions/add " ,
" /api/v1/subscriptions/remove " ,
" /api/v1/get_subscribers " ,
" /api/v1/send_message " ,
" /api/v1/update_pointer " ,
" /api/v1/external/github " ,
" /api/v1/fetch_api_key " ,
] ,
}
for status_code , url_set in get_urls . iteritems ( ) :
self . fetch ( " get " , url_set , status_code )
for status_code , url_set in post_urls . iteritems ( ) :
self . fetch ( " post " , url_set , status_code )
2012-08-31 20:11:15 +02:00
class LoginTest ( AuthedTestCase ) :
"""
Logging in , registration , and logging out .
"""
def test_login ( self ) :
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
user_profile = get_user_profile_by_email ( ' hamlet@zulip.com ' )
2013-03-29 17:39:53 +01:00
self . assertEqual ( self . client . session [ ' _auth_user_id ' ] , user_profile . id )
2012-08-31 20:11:15 +02:00
def test_login_bad_password ( self ) :
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " , " wrongpassword " )
2012-08-31 20:11:15 +02:00
self . assertIsNone ( self . client . session . get ( ' _auth_user_id ' , None ) )
def test_register ( self ) :
self . register ( " test " , " test " )
2013-07-24 20:56:42 +02:00
user_profile = get_user_profile_by_email ( ' test@zulip.com ' )
2013-03-29 17:39:53 +01:00
self . assertEqual ( self . client . session [ ' _auth_user_id ' ] , user_profile . id )
2012-08-31 20:11:15 +02:00
def test_logout ( self ) :
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2012-08-31 20:11:15 +02:00
self . client . post ( ' /accounts/logout/ ' )
self . assertIsNone ( self . client . session . get ( ' _auth_user_id ' , None ) )
2013-03-20 22:08:48 +01:00
def test_non_ascii_login ( self ) :
"""
You can log in even if your password contain non - ASCII characters .
"""
2013-07-24 20:56:42 +02:00
email = " test@zulip.com "
2013-03-20 22:08:48 +01:00
password = u " hümbüǵ "
# Registering succeeds.
self . register ( " test " , password )
2013-07-02 21:50:05 +02:00
user_profile = get_user_profile_by_email ( email )
2013-03-29 17:39:53 +01:00
self . assertEqual ( self . client . session [ ' _auth_user_id ' ] , user_profile . id )
2013-03-20 22:08:48 +01:00
self . client . post ( ' /accounts/logout/ ' )
self . assertIsNone ( self . client . session . get ( ' _auth_user_id ' , None ) )
# Logging in succeeds.
self . client . post ( ' /accounts/logout/ ' )
self . login ( email , password )
2013-03-29 17:39:53 +01:00
self . assertEqual ( self . client . session [ ' _auth_user_id ' ] , user_profile . id )
2012-08-31 20:11:15 +02:00
2012-10-03 21:16:34 +02:00
class PersonalMessagesTest ( AuthedTestCase ) :
2012-08-31 20:11:15 +02:00
def test_auto_subbed_to_personals ( self ) :
"""
Newly created users are auto - subbed to the ability to receive
personals .
"""
self . register ( " test " , " test " )
2013-07-24 20:56:42 +02:00
user_profile = get_user_profile_by_email ( ' test@zulip.com ' )
2013-07-02 15:53:48 +02:00
old_messages_count = message_stream_count ( user_profile )
2013-07-24 20:56:42 +02:00
self . send_message ( " test@zulip.com " , " test@zulip.com " , Recipient . PERSONAL )
2013-07-02 15:53:48 +02:00
new_messages_count = message_stream_count ( user_profile )
self . assertEqual ( new_messages_count , old_messages_count + 1 )
2012-08-31 20:11:15 +02:00
2013-03-29 19:37:21 +01:00
recipient = Recipient . objects . get ( type_id = user_profile . id ,
type = Recipient . PERSONAL )
2013-07-02 15:53:48 +02:00
self . assertEqual ( most_recent_message ( user_profile ) . recipient , recipient )
2012-08-31 20:11:15 +02:00
2013-06-20 21:32:11 +02:00
@slow ( 0.36 , " checks several profiles " )
2012-08-31 20:11:15 +02:00
def test_personal_to_self ( self ) :
"""
If you send a personal to yourself , only you see it .
"""
2013-03-29 19:37:21 +01:00
old_user_profiles = list ( UserProfile . objects . all ( ) )
2012-08-31 20:11:15 +02:00
self . register ( " test1 " , " test1 " )
2012-10-03 21:16:34 +02:00
old_messages = [ ]
2013-03-29 19:37:21 +01:00
for user_profile in old_user_profiles :
2013-07-02 00:35:11 +02:00
old_messages . append ( message_stream_count ( user_profile ) )
2012-08-31 20:11:15 +02:00
2013-07-24 20:56:42 +02:00
self . send_message ( " test1@zulip.com " , " test1@zulip.com " , Recipient . PERSONAL )
2012-08-31 20:11:15 +02:00
2012-10-03 21:16:34 +02:00
new_messages = [ ]
2013-03-29 19:37:21 +01:00
for user_profile in old_user_profiles :
2013-07-02 00:35:11 +02:00
new_messages . append ( message_stream_count ( user_profile ) )
2012-08-31 20:11:15 +02:00
2012-10-03 21:16:34 +02:00
self . assertEqual ( old_messages , new_messages )
2012-08-31 20:11:15 +02:00
2013-07-24 20:56:42 +02:00
user_profile = get_user_profile_by_email ( " test1@zulip.com " )
2013-03-29 19:37:21 +01:00
recipient = Recipient . objects . get ( type_id = user_profile . id , type = Recipient . PERSONAL )
2013-07-02 16:15:10 +02:00
self . assertEqual ( most_recent_message ( user_profile ) . recipient , recipient )
2012-08-31 20:11:15 +02:00
2013-03-22 15:07:50 +01:00
def assert_personal ( self , sender_email , receiver_email , content = " test content " ) :
2012-08-31 20:11:15 +02:00
"""
2013-03-22 15:07:50 +01:00
Send a private message from ` sender_email ` to ` receiver_email ` and check
that only those two parties actually received the message .
2012-08-31 20:11:15 +02:00
"""
2013-07-02 21:50:05 +02:00
sender = get_user_profile_by_email ( sender_email )
receiver = get_user_profile_by_email ( receiver_email )
2012-08-31 20:11:15 +02:00
2013-07-02 00:35:11 +02:00
sender_messages = message_stream_count ( sender )
receiver_messages = message_stream_count ( receiver )
2012-08-31 20:11:15 +02:00
2013-03-28 20:43:34 +01:00
other_user_profiles = UserProfile . objects . filter ( ~ Q ( email = sender_email ) &
~ Q ( email = receiver_email ) )
2012-10-03 21:16:34 +02:00
old_other_messages = [ ]
2013-03-29 19:37:21 +01:00
for user_profile in other_user_profiles :
2013-07-02 00:35:11 +02:00
old_other_messages . append ( message_stream_count ( user_profile ) )
2012-08-28 18:44:51 +02:00
2013-03-22 15:07:50 +01:00
self . send_message ( sender_email , receiver_email , Recipient . PERSONAL , content )
2012-08-28 18:44:51 +02:00
2012-10-03 21:16:34 +02:00
# Users outside the conversation don't get the message.
new_other_messages = [ ]
2013-03-29 19:37:21 +01:00
for user_profile in other_user_profiles :
2013-07-02 00:35:11 +02:00
new_other_messages . append ( message_stream_count ( user_profile ) )
2012-08-31 20:11:15 +02:00
2012-10-03 21:16:34 +02:00
self . assertEqual ( old_other_messages , new_other_messages )
2012-08-31 20:11:15 +02:00
2012-10-03 21:16:34 +02:00
# The personal message is in the streams of both the sender and receiver.
2013-07-02 00:35:11 +02:00
self . assertEqual ( message_stream_count ( sender ) ,
2013-03-22 15:07:50 +01:00
sender_messages + 1 )
2013-07-02 00:35:11 +02:00
self . assertEqual ( message_stream_count ( receiver ) ,
2013-03-22 15:07:50 +01:00
receiver_messages + 1 )
2012-08-31 20:11:15 +02:00
2012-09-10 19:43:11 +02:00
recipient = Recipient . objects . get ( type_id = receiver . id , type = Recipient . PERSONAL )
2013-07-02 16:15:10 +02:00
self . assertEqual ( most_recent_message ( sender ) . recipient , recipient )
self . assertEqual ( most_recent_message ( receiver ) . recipient , recipient )
2012-08-31 20:11:15 +02:00
2013-06-20 21:32:11 +02:00
@slow ( 0.28 , " assert_personal checks several profiles " )
2013-03-22 15:07:50 +01:00
def test_personal ( self ) :
"""
If you send a personal , only you and the recipient see it .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
self . assert_personal ( " hamlet@zulip.com " , " othello@zulip.com " )
2013-03-22 15:07:50 +01:00
2013-06-20 21:32:11 +02:00
@slow ( 0.28 , " assert_personal checks several profiles " )
2013-03-22 15:07:50 +01:00
def test_non_ascii_personal ( self ) :
"""
Sending a PM containing non - ASCII characters succeeds .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
self . assert_personal ( " hamlet@zulip.com " , " othello@zulip.com " , u " hümbüǵ " )
2013-03-22 15:07:50 +01:00
2012-10-10 23:13:04 +02:00
class StreamMessagesTest ( AuthedTestCase ) :
2012-08-31 20:11:15 +02:00
2013-03-22 15:07:50 +01:00
def assert_stream_message ( self , stream_name , subject = " test subject " ,
content = " test content " ) :
2012-08-31 20:11:15 +02:00
"""
2013-03-22 15:07:50 +01:00
Check that messages sent to a stream reach all subscribers to that stream .
2012-08-31 20:11:15 +02:00
"""
2013-07-24 20:56:42 +02:00
subscribers = self . users_subscribed_to_stream ( stream_name , " zulip.com " )
2012-10-03 21:16:34 +02:00
old_subscriber_messages = [ ]
2012-08-31 20:11:15 +02:00
for subscriber in subscribers :
2013-07-02 00:35:11 +02:00
old_subscriber_messages . append ( message_stream_count ( subscriber ) )
2012-08-31 20:11:15 +02:00
2013-03-29 19:37:21 +01:00
non_subscribers = [ user_profile for user_profile in UserProfile . objects . all ( )
if user_profile not in subscribers ]
2012-10-03 21:16:34 +02:00
old_non_subscriber_messages = [ ]
2012-08-31 20:11:15 +02:00
for non_subscriber in non_subscribers :
2013-07-02 00:35:11 +02:00
old_non_subscriber_messages . append ( message_stream_count ( non_subscriber ) )
2012-08-31 20:11:15 +02:00
2013-03-28 20:43:34 +01:00
a_subscriber_email = subscribers [ 0 ] . email
2012-10-12 17:49:22 +02:00
self . login ( a_subscriber_email )
2013-03-22 15:07:50 +01:00
self . send_message ( a_subscriber_email , stream_name , Recipient . STREAM ,
subject , content )
2012-08-31 20:11:15 +02:00
2013-03-22 15:07:50 +01:00
# Did all of the subscribers get the message?
2012-10-03 21:16:34 +02:00
new_subscriber_messages = [ ]
2012-08-31 20:11:15 +02:00
for subscriber in subscribers :
2013-07-02 00:35:11 +02:00
new_subscriber_messages . append ( message_stream_count ( subscriber ) )
2012-08-31 20:11:15 +02:00
2013-03-22 15:07:50 +01:00
# Did non-subscribers not get the message?
2012-10-03 21:16:34 +02:00
new_non_subscriber_messages = [ ]
2012-08-31 20:11:15 +02:00
for non_subscriber in non_subscribers :
2013-07-02 00:35:11 +02:00
new_non_subscriber_messages . append ( message_stream_count ( non_subscriber ) )
2012-08-31 20:11:15 +02:00
2012-10-03 21:16:34 +02:00
self . assertEqual ( old_non_subscriber_messages , new_non_subscriber_messages )
self . assertEqual ( new_subscriber_messages , [ elt + 1 for elt in old_subscriber_messages ] )
2012-09-04 22:31:56 +02:00
2013-06-25 19:45:12 +02:00
def test_message_mentions ( self ) :
2013-07-24 20:41:09 +02:00
user_profile = get_user_profile_by_email ( " iago@zulip.com " )
2013-06-25 19:45:12 +02:00
self . subscribe_to_stream ( user_profile . email , " Denmark " )
2013-07-24 20:41:09 +02:00
self . send_message ( " hamlet@zulip.com " , " Denmark " , Recipient . STREAM ,
2013-06-25 19:45:12 +02:00
content = " test @**Iago** rules " )
2013-07-02 16:15:10 +02:00
message = most_recent_message ( user_profile )
2013-06-25 19:45:12 +02:00
assert ( UserMessage . objects . get ( user_profile = user_profile , message = message ) . flags . mentioned . is_set )
2013-07-01 20:17:52 +02:00
@slow ( 0.28 , ' checks all users ' )
2013-03-22 15:07:50 +01:00
def test_message_to_stream ( self ) :
"""
If you send a message to a stream , everyone subscribed to the stream
receives the messages .
"""
self . assert_stream_message ( " Scotland " )
2013-06-20 21:32:11 +02:00
@slow ( 0.37 , ' checks all users ' )
2013-03-22 15:07:50 +01:00
def test_non_ascii_stream_message ( self ) :
"""
Sending a stream message containing non - ASCII characters in the stream
name , subject , or message body succeeds .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-03-22 15:07:50 +01:00
# Subscribe everyone to a stream with non-ASCII characters.
non_ascii_stream_name = u " hümbüǵ "
2013-07-24 20:56:42 +02:00
realm = Realm . objects . get ( domain = " zulip.com " )
2013-03-22 15:07:50 +01:00
stream , _ = create_stream_if_needed ( realm , non_ascii_stream_name )
for user_profile in UserProfile . objects . filter ( realm = realm ) :
do_add_subscription ( user_profile , stream , no_log = True )
self . assert_stream_message ( non_ascii_stream_name , subject = u " hümbüǵ " ,
content = u " hümbüǵ " )
2013-08-08 16:49:32 +02:00
class UserChangesTest ( AuthedTestCase ) :
def test_update_api_key ( self ) :
email = " hamlet@zulip.com "
self . login ( email )
user = get_user_profile_by_email ( email )
old_api_key = user . api_key
result = self . client . post ( ' /json/users/me/api_key/regenerate ' )
self . assert_json_success ( result )
new_api_key = ujson . loads ( result . content ) [ ' api_key ' ]
self . assertNotEqual ( old_api_key , new_api_key )
user = get_user_profile_by_email ( email )
self . assertEqual ( new_api_key , user . api_key )
2013-07-03 21:34:32 +02:00
class BotTest ( AuthedTestCase ) :
def assert_num_bots_equal ( self , count ) :
result = self . client . post ( " /json/get_bots " )
self . assert_json_success ( result )
json = ujson . loads ( result . content )
self . assertEqual ( count , len ( json [ ' bots ' ] ) )
def create_bot ( self ) :
bot_info = {
' full_name ' : ' The Bot of Hamlet ' ,
' short_name ' : ' hambot ' ,
}
result = self . client . post ( " /json/create_bot " , bot_info )
self . assert_json_success ( result )
2013-07-03 21:54:10 +02:00
def deactivate_bot ( self ) :
2013-07-24 20:56:42 +02:00
result = self . client . delete ( " /json/users/hambot-bot@zulip.com " )
2013-07-03 21:54:10 +02:00
self . assert_json_success ( result )
2013-07-03 21:34:32 +02:00
def test_add_bot ( self ) :
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-07-03 21:34:32 +02:00
self . assert_num_bots_equal ( 0 )
self . create_bot ( )
self . assert_num_bots_equal ( 1 )
2013-07-03 21:54:10 +02:00
def test_deactivate_bot ( self ) :
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-07-03 21:54:10 +02:00
self . assert_num_bots_equal ( 0 )
self . create_bot ( )
self . assert_num_bots_equal ( 1 )
self . deactivate_bot ( )
# You can deactivate the same bot twice.
self . deactivate_bot ( )
self . assert_num_bots_equal ( 0 )
def test_deactivate_bogus_bot ( self ) :
# Deleting a bogus bot will succeed silently.
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-07-03 21:54:10 +02:00
self . assert_num_bots_equal ( 0 )
self . create_bot ( )
self . assert_num_bots_equal ( 1 )
2013-07-24 20:56:42 +02:00
result = self . client . delete ( " /json/users/bogus-bot@zulip.com " )
2013-07-08 23:34:43 +02:00
self . assert_json_error ( result , ' No such user ' )
2013-07-03 21:54:10 +02:00
self . assert_num_bots_equal ( 1 )
def test_bot_deactivation_attacks ( self ) :
# You cannot deactivate somebody else's bot.
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-07-03 21:54:10 +02:00
self . assert_num_bots_equal ( 0 )
self . create_bot ( )
self . assert_num_bots_equal ( 1 )
# Have Othello try to deactivate both Hamlet and
# Hamlet's bot.
2013-07-24 20:41:09 +02:00
self . login ( " othello@zulip.com " )
2013-07-03 21:54:10 +02:00
2013-07-24 20:41:09 +02:00
result = self . client . delete ( " /json/users/hamlet@zulip.com " )
2013-07-08 23:34:43 +02:00
self . assert_json_error ( result , ' Insufficient permission ' )
2013-07-03 21:54:10 +02:00
2013-07-24 20:56:42 +02:00
result = self . client . delete ( " /json/users/hambot-bot@zulip.com " )
2013-07-08 23:34:43 +02:00
self . assert_json_error ( result , ' Insufficient permission ' )
2013-07-03 21:54:10 +02:00
# But we don't actually deactivate the other person's bot.
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-07-03 21:54:10 +02:00
self . assert_num_bots_equal ( 1 )
2013-07-19 17:45:06 +02:00
def test_bot_permissions ( self ) :
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-07-19 17:45:06 +02:00
self . assert_num_bots_equal ( 0 )
self . create_bot ( )
self . assert_num_bots_equal ( 1 )
# Have Othello try to mess with Hamlet's bots.
2013-07-24 20:41:09 +02:00
self . login ( " othello@zulip.com " )
2013-07-19 17:45:06 +02:00
2013-07-24 20:41:09 +02:00
result = self . client . post ( " /json/bots/hambot-bot@zulip.com/api_key/regenerate " )
2013-07-19 17:45:06 +02:00
self . assert_json_error ( result , ' Insufficient permission ' )
2013-07-23 15:57:32 +02:00
bot_info = {
' full_name ' : ' Fred ' ,
}
2013-08-01 19:35:39 +02:00
result = self . client_patch ( " /json/bots/hambot-bot@zulip.com " , bot_info )
2013-07-23 15:57:32 +02:00
self . assert_json_error ( result , ' Insufficient permission ' )
2013-07-16 22:25:34 +02:00
def get_bot ( self ) :
result = self . client . post ( " /json/get_bots " )
bots = ujson . loads ( result . content ) [ ' bots ' ]
return bots [ 0 ]
2013-07-19 17:45:06 +02:00
def test_update_api_key ( self ) :
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-07-19 17:45:06 +02:00
self . create_bot ( )
bot = self . get_bot ( )
old_api_key = bot [ ' api_key ' ]
2013-07-24 20:41:09 +02:00
result = self . client . post ( ' /json/bots/hambot-bot@zulip.com/api_key/regenerate ' )
2013-07-19 17:45:06 +02:00
self . assert_json_success ( result )
new_api_key = ujson . loads ( result . content ) [ ' api_key ' ]
self . assertNotEqual ( old_api_key , new_api_key )
bot = self . get_bot ( )
self . assertEqual ( new_api_key , bot [ ' api_key ' ] )
2013-07-16 22:25:34 +02:00
def test_patch_bot_full_name ( self ) :
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-07-16 22:25:34 +02:00
bot_info = {
' full_name ' : ' The Bot of Hamlet ' ,
' short_name ' : ' hambot ' ,
}
result = self . client . post ( " /json/create_bot " , bot_info )
self . assert_json_success ( result )
bot_info = {
' full_name ' : ' Fred ' ,
}
2013-08-01 19:35:39 +02:00
result = self . client_patch ( " /json/bots/hambot-bot@zulip.com " , bot_info )
2013-07-16 22:25:34 +02:00
self . assert_json_success ( result )
full_name = ujson . loads ( result . content ) [ ' full_name ' ]
self . assertEqual ( ' Fred ' , full_name )
bot = self . get_bot ( )
self . assertEqual ( ' Fred ' , bot [ ' full_name ' ] )
def test_patch_bogus_bot ( self ) :
# Deleting a bogus bot will succeed silently.
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-07-16 22:25:34 +02:00
self . create_bot ( )
bot_info = {
' full_name ' : ' Fred ' ,
}
2013-08-01 19:35:39 +02:00
result = self . client_patch ( " /json/bots/nonexistent-bot@zulip.com " , bot_info )
2013-07-16 22:25:34 +02:00
self . assert_json_error ( result , ' No such user ' )
self . assert_num_bots_equal ( 1 )
2012-09-06 20:53:13 +02:00
class PointerTest ( AuthedTestCase ) :
def test_update_pointer ( self ) :
"""
Posting a pointer to / update ( in the form { " pointer " : pointer } ) changes
the pointer we store for your UserProfile .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
self . assertEqual ( get_user_profile_by_email ( " hamlet@zulip.com " ) . pointer , - 1 )
2013-08-28 21:29:55 +02:00
msg_id = self . send_message ( " othello@zulip.com " , " Verona " , Recipient . STREAM )
2013-08-19 21:05:23 +02:00
result = self . client . post ( " /json/update_pointer " , { " pointer " : msg_id } )
2012-09-06 21:34:38 +02:00
self . assert_json_success ( result )
2013-08-19 21:05:23 +02:00
self . assertEqual ( get_user_profile_by_email ( " hamlet@zulip.com " ) . pointer , msg_id )
2012-09-06 20:53:13 +02:00
2012-11-15 19:42:17 +01:00
def test_api_update_pointer ( self ) :
"""
Same as above , but for the API view
"""
2013-07-24 20:41:09 +02:00
email = " hamlet@zulip.com "
2012-11-15 19:42:17 +01:00
api_key = self . get_api_key ( email )
2013-07-02 21:50:05 +02:00
self . assertEqual ( get_user_profile_by_email ( email ) . pointer , - 1 )
2013-08-28 21:29:55 +02:00
msg_id = self . send_message ( " othello@zulip.com " , " Verona " , Recipient . STREAM )
2012-11-15 19:42:17 +01:00
result = self . client . post ( " /api/v1/update_pointer " , { " email " : email ,
" api-key " : api_key ,
2013-08-19 21:05:23 +02:00
" pointer " : msg_id } )
2012-11-15 19:42:17 +01:00
self . assert_json_success ( result )
2013-08-19 21:05:23 +02:00
self . assertEqual ( get_user_profile_by_email ( email ) . pointer , msg_id )
2012-11-15 19:42:17 +01:00
2012-09-06 20:53:13 +02:00
def test_missing_pointer ( self ) :
"""
2012-10-16 21:42:40 +02:00
Posting json to / json / update_pointer which does not contain a pointer key / value pair
2012-09-06 20:53:13 +02:00
returns a 400 and error message .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
self . assertEqual ( get_user_profile_by_email ( " hamlet@zulip.com " ) . pointer , - 1 )
2012-10-16 21:42:40 +02:00
result = self . client . post ( " /json/update_pointer " , { " foo " : 1 } )
2012-11-09 18:45:22 +01:00
self . assert_json_error ( result , " Missing ' pointer ' argument " )
2013-07-24 20:41:09 +02:00
self . assertEqual ( get_user_profile_by_email ( " hamlet@zulip.com " ) . pointer , - 1 )
2012-09-06 20:53:13 +02:00
def test_invalid_pointer ( self ) :
"""
2012-10-16 21:42:40 +02:00
Posting json to / json / update_pointer with an invalid pointer returns a 400 and error
2012-09-06 20:53:13 +02:00
message .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
self . assertEqual ( get_user_profile_by_email ( " hamlet@zulip.com " ) . pointer , - 1 )
2012-10-16 21:42:40 +02:00
result = self . client . post ( " /json/update_pointer " , { " pointer " : " foo " } )
2012-11-09 18:45:22 +01:00
self . assert_json_error ( result , " Bad value for ' pointer ' : foo " )
2013-07-24 20:41:09 +02:00
self . assertEqual ( get_user_profile_by_email ( " hamlet@zulip.com " ) . pointer , - 1 )
2012-09-06 20:53:13 +02:00
def test_pointer_out_of_range ( self ) :
"""
2012-10-16 21:42:40 +02:00
Posting json to / json / update_pointer with an out of range ( < 0 ) pointer returns a 400
2012-09-06 20:53:13 +02:00
and error message .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
self . assertEqual ( get_user_profile_by_email ( " hamlet@zulip.com " ) . pointer , - 1 )
2012-10-16 21:42:40 +02:00
result = self . client . post ( " /json/update_pointer " , { " pointer " : - 2 } )
2012-12-19 20:26:48 +01:00
self . assert_json_error ( result , " Bad value for ' pointer ' : -2 " )
2013-07-24 20:41:09 +02:00
self . assertEqual ( get_user_profile_by_email ( " hamlet@zulip.com " ) . pointer , - 1 )
2012-09-06 21:46:03 +02:00
2012-10-03 21:16:34 +02:00
class MessagePOSTTest ( AuthedTestCase ) :
2012-09-06 21:46:03 +02:00
2012-10-03 21:16:34 +02:00
def test_message_to_self ( self ) :
2012-09-06 21:46:03 +02:00
"""
2012-10-10 23:13:04 +02:00
Sending a message to a stream to which you are subscribed is
2012-10-03 21:16:34 +02:00
successful .
2012-09-06 21:46:03 +02:00
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2012-11-09 18:42:03 +01:00
result = self . client . post ( " /json/send_message " , { " type " : " stream " ,
2012-11-14 23:21:46 +01:00
" to " : " Verona " ,
2012-11-09 18:42:03 +01:00
" client " : " test suite " ,
" content " : " Test message " ,
" subject " : " Test subject " } )
2012-09-06 21:46:03 +02:00
self . assert_json_success ( result )
2012-11-15 19:42:17 +01:00
def test_api_message_to_self ( self ) :
"""
Same as above , but for the API view
"""
2013-07-24 20:41:09 +02:00
email = " hamlet@zulip.com "
2012-11-15 19:42:17 +01:00
api_key = self . get_api_key ( email )
result = self . client . post ( " /api/v1/send_message " , { " type " : " stream " ,
2012-11-14 23:21:46 +01:00
" to " : " Verona " ,
2012-11-15 19:42:17 +01:00
" client " : " test suite " ,
" content " : " Test message " ,
" subject " : " Test subject " ,
" email " : email ,
" api-key " : api_key } )
self . assert_json_success ( result )
2012-10-10 23:13:04 +02:00
def test_message_to_nonexistent_stream ( self ) :
2012-09-06 21:46:03 +02:00
"""
2012-11-01 16:09:24 +01:00
Sending a message to a nonexistent stream fails .
2012-09-06 21:46:03 +02:00
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2012-10-10 23:13:04 +02:00
self . assertFalse ( Stream . objects . filter ( name = " nonexistent_stream " ) )
2012-11-09 18:42:03 +01:00
result = self . client . post ( " /json/send_message " , { " type " : " stream " ,
2012-11-14 23:21:46 +01:00
" to " : " nonexistent_stream " ,
2012-11-09 18:42:03 +01:00
" client " : " test suite " ,
" content " : " Test message " ,
" subject " : " Test subject " } )
2012-10-30 21:50:58 +01:00
self . assert_json_error ( result , " Stream does not exist " )
2012-09-06 21:46:03 +02:00
2012-10-03 21:16:34 +02:00
def test_personal_message ( self ) :
2012-09-06 21:46:03 +02:00
"""
2012-10-03 21:16:34 +02:00
Sending a personal message to a valid username is successful .
2012-09-06 21:46:03 +02:00
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2012-11-08 00:38:21 +01:00
result = self . client . post ( " /json/send_message " , { " type " : " private " ,
2012-11-09 18:42:03 +01:00
" content " : " Test message " ,
" client " : " test suite " ,
2013-07-24 20:41:09 +02:00
" to " : " othello@zulip.com " } )
2012-09-06 21:46:03 +02:00
self . assert_json_success ( result )
2012-10-03 21:16:34 +02:00
def test_personal_message_to_nonexistent_user ( self ) :
2012-09-06 21:46:03 +02:00
"""
2012-10-03 21:16:34 +02:00
Sending a personal message to an invalid email returns error JSON .
2012-09-06 21:46:03 +02:00
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2012-11-08 00:38:21 +01:00
result = self . client . post ( " /json/send_message " , { " type " : " private " ,
2012-11-09 18:42:03 +01:00
" content " : " Test message " ,
" client " : " test suite " ,
2012-11-14 23:21:46 +01:00
" to " : " nonexistent " } )
2012-10-12 20:29:23 +02:00
self . assert_json_error ( result , " Invalid email ' nonexistent ' " )
2012-09-06 21:53:26 +02:00
def test_invalid_type ( self ) :
"""
2012-10-03 21:16:34 +02:00
Sending a message of unknown type returns error JSON .
2012-09-06 21:53:26 +02:00
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2012-11-09 18:42:03 +01:00
result = self . client . post ( " /json/send_message " , { " type " : " invalid type " ,
" content " : " Test message " ,
" client " : " test suite " ,
2013-07-24 20:41:09 +02:00
" to " : " othello@zulip.com " } )
2012-10-03 00:10:55 +02:00
self . assert_json_error ( result , " Invalid message type " )
2012-09-06 23:55:04 +02:00
2013-08-16 23:29:05 +02:00
def test_empty_message ( self ) :
"""
Sending a message that is empty or only whitespace should fail
"""
self . login ( " hamlet@zulip.com " )
result = self . client . post ( " /json/send_message " , { " type " : " private " ,
" content " : " " ,
" client " : " test suite " ,
" to " : " othello@zulip.com " } )
self . assert_json_error ( result , " Message must not be empty " )
2013-01-07 18:02:55 +01:00
def test_mirrored_huddle ( self ) :
"""
Sending a mirrored huddle message works
"""
self . login ( " starnine@mit.edu " )
result = self . client . post ( " /json/send_message " , { " type " : " private " ,
" sender " : " sipbtest@mit.edu " ,
" content " : " Test message " ,
" client " : " zephyr_mirror " ,
2013-06-18 23:55:55 +02:00
" to " : ujson . dumps ( [ " starnine@mit.edu " ,
" espuser@mit.edu " ] ) } )
2013-01-07 18:02:55 +01:00
self . assert_json_success ( result )
def test_mirrored_personal ( self ) :
"""
Sending a mirrored personal message works
"""
self . login ( " starnine@mit.edu " )
result = self . client . post ( " /json/send_message " , { " type " : " private " ,
" sender " : " sipbtest@mit.edu " ,
" content " : " Test message " ,
" client " : " zephyr_mirror " ,
" to " : " starnine@mit.edu " } )
self . assert_json_success ( result )
2013-08-13 19:46:39 +02:00
def test_duplicated_mirrored_huddle ( self ) :
"""
Sending two mirrored huddles in the row return the same ID
"""
msg = { " type " : " private " ,
" sender " : " sipbtest@mit.edu " ,
" content " : " Test message " ,
" client " : " zephyr_mirror " ,
" to " : ujson . dumps ( [ " sipbcert@mit.edu " ,
" starnine@mit.edu " ] ) }
self . login ( " starnine@mit.edu " )
result1 = self . client . post ( " /json/send_message " , msg )
self . login ( " sipbcert@mit.edu " )
result2 = self . client . post ( " /json/send_message " , msg )
self . assertEqual ( ujson . loads ( result1 . content ) [ ' id ' ] ,
ujson . loads ( result2 . content ) [ ' id ' ] )
2012-12-03 02:02:53 +01:00
class SubscriptionPropertiesTest ( AuthedTestCase ) :
2013-04-08 18:01:01 +02:00
def test_get_stream_color ( self ) :
2012-12-03 02:02:53 +01:00
"""
A GET request to
2013-04-08 19:34:04 +02:00
/ json / subscriptions / property ? property = color + stream_name = foo returns
the color for stream foo .
2012-12-03 02:02:53 +01:00
"""
2013-07-24 20:41:09 +02:00
test_email = " hamlet@zulip.com "
2012-12-03 02:02:53 +01:00
self . login ( test_email )
2013-07-02 21:50:05 +02:00
subs = gather_subscriptions ( get_user_profile_by_email ( test_email ) ) [ 0 ]
2012-12-03 02:02:53 +01:00
result = self . client . get ( " /json/subscriptions/property " ,
2013-04-08 19:34:04 +02:00
{ " property " : " color " ,
" stream_name " : subs [ 0 ] [ ' name ' ] } )
2012-12-03 02:02:53 +01:00
self . assert_json_success ( result )
2013-06-18 23:55:55 +02:00
json = ujson . loads ( result . content )
2012-12-03 02:02:53 +01:00
2013-04-08 19:34:04 +02:00
self . assertIn ( " stream_name " , json )
self . assertIn ( " value " , json )
self . assertIsInstance ( json [ " stream_name " ] , basestring )
self . assertIsInstance ( json [ " value " ] , basestring )
self . assertEqual ( json [ " stream_name " ] , subs [ 0 ] [ " name " ] )
self . assertEqual ( json [ " value " ] , subs [ 0 ] [ " color " ] )
2012-12-03 02:02:53 +01:00
def test_set_stream_color ( self ) :
"""
A POST request to / json / subscriptions / property with stream_name and
color data sets the stream color , and for that stream only .
"""
2013-07-24 20:41:09 +02:00
test_email = " hamlet@zulip.com "
2012-12-03 02:02:53 +01:00
self . login ( test_email )
2013-07-02 21:50:05 +02:00
old_subs , _ = gather_subscriptions ( get_user_profile_by_email ( test_email ) )
2013-01-29 21:40:16 +01:00
sub = old_subs [ 0 ]
stream_name = sub [ ' name ' ]
old_color = sub [ ' color ' ]
2013-02-05 19:47:43 +01:00
invite_only = sub [ ' invite_only ' ]
2013-08-12 21:13:07 +02:00
email_address = sub [ ' email_address ' ]
2012-12-03 02:02:53 +01:00
new_color = " #ffffff " # TODO: ensure that this is different from old_color
result = self . client . post ( " /json/subscriptions/property " ,
2013-04-08 18:01:01 +02:00
{ " property " : " color " ,
2012-12-03 02:02:53 +01:00
" stream_name " : stream_name ,
2013-04-08 18:01:01 +02:00
" value " : " #ffffff " } )
2012-12-03 02:02:53 +01:00
self . assert_json_success ( result )
2013-07-02 21:50:05 +02:00
new_subs = gather_subscriptions ( get_user_profile_by_email ( test_email ) ) [ 0 ]
2013-04-08 19:34:04 +02:00
sub = { ' name ' : stream_name , ' in_home_view ' : True , ' color ' : new_color ,
2013-08-12 21:13:07 +02:00
' invite_only ' : invite_only , ' notifications ' : False ,
' email_address ' : email_address }
2013-04-08 19:34:04 +02:00
self . assertIn ( sub , new_subs )
2012-12-03 02:02:53 +01:00
2013-04-08 19:34:04 +02:00
new_subs . remove ( sub )
sub [ ' color ' ] = old_color
old_subs . remove ( sub )
2012-12-03 02:02:53 +01:00
self . assertEqual ( old_subs , new_subs )
def test_set_color_missing_stream_name ( self ) :
"""
2013-04-08 18:01:01 +02:00
Updating the color property requires a stream_name .
2012-12-03 02:02:53 +01:00
"""
2013-07-24 20:41:09 +02:00
test_email = " hamlet@zulip.com "
2012-12-03 02:02:53 +01:00
self . login ( test_email )
result = self . client . post ( " /json/subscriptions/property " ,
2013-04-08 18:01:01 +02:00
{ " property " : " color " ,
" value " : " #ffffff " } )
2012-12-03 02:02:53 +01:00
2013-01-18 18:20:58 +01:00
self . assert_json_error ( result , " Missing ' stream_name ' argument " )
2012-12-03 02:02:53 +01:00
def test_set_color_missing_color ( self ) :
"""
2013-04-08 18:01:01 +02:00
Updating the color property requires a color .
2012-12-03 02:02:53 +01:00
"""
2013-07-24 20:41:09 +02:00
test_email = " hamlet@zulip.com "
2012-12-03 02:02:53 +01:00
self . login ( test_email )
2013-07-02 21:50:05 +02:00
subs = gather_subscriptions ( get_user_profile_by_email ( test_email ) ) [ 0 ]
2012-12-03 02:02:53 +01:00
result = self . client . post ( " /json/subscriptions/property " ,
2013-04-08 18:01:01 +02:00
{ " property " : " color " ,
2013-04-08 19:34:04 +02:00
" stream_name " : subs [ 0 ] [ " name " ] } )
2012-12-03 02:02:53 +01:00
2013-04-08 18:01:01 +02:00
self . assert_json_error ( result , " Missing ' value ' argument " )
2012-12-03 02:02:53 +01:00
def test_set_invalid_property ( self ) :
"""
Trying to set an invalid property returns a JSON error .
"""
2013-07-24 20:41:09 +02:00
test_email = " hamlet@zulip.com "
2013-04-08 19:34:04 +02:00
self . login ( test_email )
2013-07-02 21:50:05 +02:00
subs = gather_subscriptions ( get_user_profile_by_email ( test_email ) ) [ 0 ]
2012-12-03 02:02:53 +01:00
result = self . client . post ( " /json/subscriptions/property " ,
2013-04-08 19:34:04 +02:00
{ " property " : " bad " ,
" stream_name " : subs [ 0 ] [ " name " ] } )
2012-12-03 02:02:53 +01:00
self . assert_json_error ( result ,
2013-04-08 19:34:04 +02:00
" Unknown subscription property: bad " )
2012-12-03 02:02:53 +01:00
2013-01-29 19:47:28 +01:00
class SubscriptionAPITest ( AuthedTestCase ) :
def setUp ( self ) :
"""
All tests will be logged in as hamlet . Also save various useful values
as attributes that tests can access .
"""
2013-07-24 20:41:09 +02:00
self . test_email = " hamlet@zulip.com "
2013-01-29 19:47:28 +01:00
self . login ( self . test_email )
2013-07-02 21:50:05 +02:00
self . user_profile = get_user_profile_by_email ( self . test_email )
2013-01-29 19:47:28 +01:00
self . realm = self . user_profile . realm
self . streams = self . get_streams ( self . test_email )
2013-06-25 16:15:36 +02:00
def make_random_stream_names ( self , existing_stream_names ) :
2013-01-29 19:47:28 +01:00
"""
Helper function to make up random stream names . It takes
existing_stream_names and randomly appends a digit to the end of each ,
but avoids names that appear in the list names_to_avoid .
"""
random_streams = [ ]
2013-06-25 16:15:36 +02:00
all_stream_names = [ stream . name for stream in Stream . objects . filter ( realm = self . realm ) ]
2013-01-29 19:47:28 +01:00
for stream in existing_stream_names :
random_stream = stream + str ( random . randint ( 0 , 9 ) )
2013-06-25 16:15:36 +02:00
if not random_stream in all_stream_names :
2013-01-29 19:47:28 +01:00
random_streams . append ( random_stream )
return random_streams
def test_successful_subscriptions_list ( self ) :
"""
Calling / json / subscriptions / list should successfully return your subscriptions .
"""
result = self . client . post ( " /json/subscriptions/list " , { } )
self . assert_json_success ( result )
2013-06-18 23:55:55 +02:00
json = ujson . loads ( result . content )
2013-01-29 19:47:28 +01:00
self . assertIn ( " subscriptions " , json )
2013-01-29 21:40:16 +01:00
for stream in json [ " subscriptions " ] :
tests: assert that text objects are instances of basestring, since they might be str or unicode.
This fixes tests that have been failing for me for, well, months, that
I've been ignoring:
======================================================================
FAIL: test_successful_subscriptions_list (zephyr.tests.SubscriptionAPITest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/jesstess/dev/humbug/zephyr/tests.py", line 631, in test_successful_subscriptions_list
self.assertIsInstance(stream['name'], str)
AssertionError: u'Denmark' is not an instance of <type 'str'>
======================================================================
FAIL: test_get_stream_colors (zephyr.tests.SubscriptionPropertiesTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/jesstess/dev/humbug/zephyr/tests.py", line 515, in test_get_stream_colors
self.assertIsInstance(color, str)
AssertionError: u'#c2c2c2' is not an instance of <type 'str'>
----------------------------------------------------------------------
The more comprehensive fix to this is going through both our API and
JSON calls and ensuring that we always return unicode objects,
documenting that, and then testing that more specifically. For now, at
least have passing tests.
(imported from commit ed1875ea1f66c1f1e89f80502c0d6abb323dc489)
2013-03-21 19:19:03 +01:00
self . assertIsInstance ( stream [ ' name ' ] , basestring )
self . assertIsInstance ( stream [ ' color ' ] , basestring )
2013-02-05 19:47:43 +01:00
self . assertIsInstance ( stream [ ' invite_only ' ] , bool )
2013-01-29 19:47:28 +01:00
# check that the stream name corresponds to an actual stream
try :
2013-01-29 21:40:16 +01:00
Stream . objects . get ( name__iexact = stream [ ' name ' ] , realm = self . realm )
2013-01-29 19:47:28 +01:00
except Stream . DoesNotExist :
self . fail ( " stream does not exist " )
2013-01-29 21:40:16 +01:00
list_streams = [ stream [ ' name ' ] for stream in json [ " subscriptions " ] ]
2013-01-29 19:47:28 +01:00
# also check that this matches the list of your subscriptions
self . assertItemsEqual ( list_streams , self . streams )
2013-06-25 16:29:32 +02:00
def helper_check_subs_before_and_after_add ( self , subscriptions , other_params ,
2013-06-25 16:53:45 +02:00
subscribed , already_subscribed ,
2013-08-28 00:24:25 +02:00
email , new_subs , invite_only = False ) :
2013-01-29 19:47:28 +01:00
"""
2013-01-31 20:58:58 +01:00
Check result of adding subscriptions .
You can add subscriptions for yourself or possibly many
principals , which is why e - mails map to subscriptions in the
result .
The result json is of the form
{ " msg " : " " ,
" result " : " success " ,
2013-07-24 20:41:09 +02:00
" already_subscribed " : { " iago@zulip.com " : [ " Venice " , " Verona " ] } ,
" subscribed " : { " iago@zulip.com " : [ " Venice8 " ] } }
2013-01-29 19:47:28 +01:00
"""
2013-08-28 00:24:25 +02:00
result = self . common_subscribe_to_streams ( self . test_email , subscriptions ,
other_params , invite_only = invite_only )
2013-01-29 19:47:28 +01:00
self . assert_json_success ( result )
2013-06-18 23:55:55 +02:00
json = ujson . loads ( result . content )
2013-06-25 16:53:45 +02:00
self . assertItemsEqual ( subscribed , json [ " subscribed " ] [ email ] )
self . assertItemsEqual ( already_subscribed , json [ " already_subscribed " ] [ email ] )
2013-01-29 19:47:28 +01:00
new_streams = self . get_streams ( email )
self . assertItemsEqual ( new_streams , new_subs )
def test_successful_subscriptions_add ( self ) :
"""
Calling / json / subscriptions / add should successfully add streams , and
should determine which are new subscriptions vs which were already
subscribed . We randomly generate stream names to add , because it
doesn ' t matter whether the stream already exists.
"""
self . assertNotEqual ( len ( self . streams ) , 0 ) # necessary for full test coverage
2013-06-25 16:15:36 +02:00
add_streams = self . make_random_stream_names ( self . streams )
2013-01-29 19:47:28 +01:00
self . assertNotEqual ( len ( add_streams ) , 0 ) # necessary for full test coverage
2013-06-25 16:29:32 +02:00
self . helper_check_subs_before_and_after_add ( self . streams + add_streams , { } ,
2013-06-25 16:53:45 +02:00
add_streams , self . streams , self . test_email , self . streams + add_streams )
2013-01-29 19:47:28 +01:00
2013-03-22 21:46:27 +01:00
def test_non_ascii_stream_subscription ( self ) :
"""
Subscribing to a stream name with non - ASCII characters succeeds .
"""
2013-06-25 16:29:32 +02:00
self . helper_check_subs_before_and_after_add ( self . streams + [ u " hümbüǵ " ] , { } ,
2013-06-25 16:53:45 +02:00
[ u " hümbüǵ " ] , self . streams , self . test_email , self . streams + [ u " hümbüǵ " ] )
2013-03-22 21:46:27 +01:00
2013-01-29 19:47:28 +01:00
def test_subscriptions_add_too_long ( self ) :
"""
Calling / json / subscriptions / add on a stream whose name is > 30
characters should return a JSON error .
"""
# character limit is 30 characters
long_stream_name = " a " * 31
2013-06-25 16:29:32 +02:00
result = self . common_subscribe_to_streams ( self . test_email , [ long_stream_name ] )
2013-01-29 19:47:28 +01:00
self . assert_json_error ( result ,
" Stream name ( %s ) too long. " % ( long_stream_name , ) )
def test_subscriptions_add_invalid_stream ( self ) :
"""
Calling / json / subscriptions / add on a stream whose name is invalid ( as
2013-07-29 23:03:31 +02:00
defined by valid_stream_name in zerver / views . py ) should return a JSON
2013-01-29 19:47:28 +01:00
error .
"""
# currently, the only invalid name is the empty string
invalid_stream_name = " "
2013-06-25 16:29:32 +02:00
result = self . common_subscribe_to_streams ( self . test_email , [ invalid_stream_name ] )
2013-01-29 19:47:28 +01:00
self . assert_json_error ( result ,
" Invalid stream name ( %s ). " % ( invalid_stream_name , ) )
2013-08-28 00:24:25 +02:00
def assert_adding_subscriptions_for_principal ( self , invitee , streams , invite_only = False ) :
2013-01-29 19:47:28 +01:00
"""
Calling / json / subscriptions / add on behalf of another principal ( for
whom you have permission to add subscriptions ) should successfully add
those subscriptions and send a message to the subscribee notifying
them .
"""
2013-07-02 21:50:05 +02:00
other_profile = get_user_profile_by_email ( invitee )
2013-03-22 22:05:06 +01:00
current_streams = self . get_streams ( invitee )
2013-01-29 19:47:28 +01:00
self . assertIsInstance ( other_profile , UserProfile )
self . assertNotEqual ( len ( current_streams ) , 0 ) # necessary for full test coverage
2013-03-22 22:05:06 +01:00
self . assertNotEqual ( len ( streams ) , 0 ) # necessary for full test coverage
streams_to_sub = streams [ : 1 ] # just add one, to make the message easier to check
2013-01-29 19:47:28 +01:00
streams_to_sub . extend ( current_streams )
2013-06-25 16:29:32 +02:00
self . helper_check_subs_before_and_after_add ( streams_to_sub ,
2013-06-25 16:53:45 +02:00
{ " principals " : ujson . dumps ( [ invitee ] ) } , streams [ : 1 ] , current_streams ,
2013-08-28 00:24:25 +02:00
invitee , streams_to_sub , invite_only = invite_only )
2013-01-29 19:47:28 +01:00
# verify that the user was sent a message informing them about the subscription
msg = Message . objects . latest ( ' id ' )
self . assertEqual ( msg . recipient . type , msg . recipient . PERSONAL )
2013-03-28 20:20:31 +01:00
self . assertEqual ( msg . sender_id ,
2013-07-24 20:23:35 +02:00
get_user_profile_by_email ( " notification-bot@zulip.com " ) . id )
2013-01-29 19:47:28 +01:00
expected_msg = ( " Hi there! We thought you ' d like to know that %s just "
2013-08-28 00:24:25 +02:00
" subscribed you to the %s stream ' %s ' "
% ( self . user_profile . full_name ,
' **invite-only** ' if invite_only else ' ' ,
streams [ 0 ] ) )
if not Stream . objects . get ( name = streams [ 0 ] ) . invite_only :
expected_msg + = ( " \n You can see historical content on a "
" non-invite-only stream by narrowing to it. " )
2013-01-29 19:47:28 +01:00
self . assertEqual ( msg . content , expected_msg )
recipients = get_display_recipient ( msg . recipient )
self . assertEqual ( len ( recipients ) , 1 )
2013-03-22 22:05:06 +01:00
self . assertEqual ( recipients [ 0 ] [ ' email ' ] , invitee )
2013-07-01 20:17:52 +02:00
@slow ( 0.15 , " common_subscribe_to_streams is slow " )
2013-03-22 22:05:06 +01:00
def test_subscriptions_add_for_principal ( self ) :
"""
You can subscribe other people to streams .
"""
2013-07-24 20:41:09 +02:00
invitee = " iago@zulip.com "
2013-03-22 22:05:06 +01:00
current_streams = self . get_streams ( invitee )
2013-06-25 16:15:36 +02:00
invite_streams = self . make_random_stream_names ( current_streams )
2013-03-22 22:05:06 +01:00
self . assert_adding_subscriptions_for_principal ( invitee , invite_streams )
2013-08-28 00:24:25 +02:00
@slow ( 0.15 , " common_subscribe_to_streams is slow " )
def test_subscriptions_add_for_principal_invite_only ( self ) :
"""
You can subscribe other people to invite only streams .
"""
invitee = " iago@zulip.com "
current_streams = self . get_streams ( invitee )
invite_streams = self . make_random_stream_names ( current_streams )
self . assert_adding_subscriptions_for_principal ( invitee , invite_streams ,
invite_only = True )
2013-07-01 20:17:52 +02:00
@slow ( 0.15 , " common_subscribe_to_streams is slow " )
2013-03-22 22:05:06 +01:00
def test_non_ascii_subscription_for_principal ( self ) :
"""
You can subscribe other people to streams even if they containing
non - ASCII characters .
"""
2013-07-24 20:41:09 +02:00
self . assert_adding_subscriptions_for_principal ( " iago@zulip.com " , [ u " hümbüǵ " ] )
2013-01-29 19:47:28 +01:00
def test_subscription_add_invalid_principal ( self ) :
"""
2013-06-25 16:29:32 +02:00
Calling subscribe on behalf of a principal that does not exist
should return a JSON error .
2013-01-29 19:47:28 +01:00
"""
2013-07-24 20:56:42 +02:00
invalid_principal = " rosencrantz-and-guildenstern@zulip.com "
2013-01-29 19:47:28 +01:00
# verify that invalid_principal actually doesn't exist
with self . assertRaises ( UserProfile . DoesNotExist ) :
2013-07-02 21:50:05 +02:00
get_user_profile_by_email ( invalid_principal )
2013-06-25 16:29:32 +02:00
result = self . common_subscribe_to_streams ( self . test_email , self . streams ,
{ " principals " : ujson . dumps ( [ invalid_principal ] ) } )
2013-01-29 19:47:28 +01:00
self . assert_json_error ( result , " User not authorized to execute queries on behalf of ' %s ' "
% ( invalid_principal , ) )
def test_subscription_add_principal_other_realm ( self ) :
"""
2013-06-25 16:29:32 +02:00
Calling subscribe on behalf of a principal in another realm
should return a JSON error .
2013-01-29 19:47:28 +01:00
"""
principal = " starnine@mit.edu "
2013-07-02 21:50:05 +02:00
profile = get_user_profile_by_email ( principal )
2013-01-29 19:47:28 +01:00
# verify that principal exists (thus, the reason for the error is the cross-realming)
self . assertIsInstance ( profile , UserProfile )
2013-06-25 16:29:32 +02:00
result = self . common_subscribe_to_streams ( self . test_email , self . streams ,
{ " principals " : ujson . dumps ( [ principal ] ) } )
2013-01-29 19:47:28 +01:00
self . assert_json_error ( result , " User not authorized to execute queries on behalf of ' %s ' "
% ( principal , ) )
2013-06-25 16:29:32 +02:00
def helper_check_subs_before_and_after_remove ( self , subscriptions , json_dict ,
email , new_subs ) :
2013-01-31 20:58:58 +01:00
"""
Check result of removing subscriptions .
Unlike adding subscriptions , you can only remove subscriptions
for yourself , so the result format is different .
{ " msg " : " " ,
" removed " : [ " Denmark " , " Scotland " , " Verona " ] ,
" not_subscribed " : [ " Rome " ] , " result " : " success " }
"""
2013-06-25 16:29:32 +02:00
result = self . client . post ( " /json/subscriptions/remove " ,
{ " subscriptions " : ujson . dumps ( subscriptions ) } )
2013-01-31 20:58:58 +01:00
self . assert_json_success ( result )
2013-06-18 23:55:55 +02:00
json = ujson . loads ( result . content )
2013-01-31 20:58:58 +01:00
for key , val in json_dict . iteritems ( ) :
self . assertItemsEqual ( val , json [ key ] ) # we don't care about the order of the items
new_streams = self . get_streams ( email )
self . assertItemsEqual ( new_streams , new_subs )
2013-01-29 19:47:28 +01:00
def test_successful_subscriptions_remove ( self ) :
"""
Calling / json / subscriptions / remove should successfully remove streams ,
and should determine which were removed vs which weren ' t subscribed to.
We cannot randomly generate stream names because the remove code
verifies whether streams exist .
"""
if len ( self . streams ) < 2 :
self . fail ( ) # necesssary for full test coverage
streams_to_remove = self . streams [ 1 : ]
not_subbed = [ ]
for stream in Stream . objects . all ( ) :
if not stream . name in self . streams :
not_subbed . append ( stream . name )
random . shuffle ( not_subbed )
self . assertNotEqual ( len ( not_subbed ) , 0 ) # necessary for full test coverage
try_to_remove = not_subbed [ : 3 ] # attempt to remove up to 3 streams not already subbed to
streams_to_remove . extend ( try_to_remove )
2013-06-25 16:29:32 +02:00
self . helper_check_subs_before_and_after_remove ( streams_to_remove ,
2013-01-31 20:58:58 +01:00
{ " removed " : self . streams [ 1 : ] , " not_subscribed " : try_to_remove } ,
self . test_email , [ self . streams [ 0 ] ] )
2013-01-29 19:47:28 +01:00
def test_subscriptions_remove_fake_stream ( self ) :
"""
Calling / json / subscriptions / remove on a stream that doesn ' t exist
should return a JSON error .
"""
2013-06-25 16:15:36 +02:00
random_streams = self . make_random_stream_names ( self . streams )
2013-01-29 19:47:28 +01:00
self . assertNotEqual ( len ( random_streams ) , 0 ) # necessary for full test coverage
streams_to_remove = random_streams [ : 1 ] # pick only one fake stream, to make checking the error message easy
result = self . client . post ( " /json/subscriptions/remove " ,
2013-06-18 23:55:55 +02:00
{ " subscriptions " : ujson . dumps ( streams_to_remove ) } )
2013-01-30 22:40:00 +01:00
self . assert_json_error ( result , " Stream(s) ( %s ) do not exist " % ( random_streams [ 0 ] , ) )
2013-01-29 19:47:28 +01:00
def helper_subscriptions_exists ( self , stream , exists , subscribed ) :
"""
A helper function that calls / json / subscriptions / exists on a stream and
verifies that the returned JSON dictionary has the exists and
subscribed values passed in as parameters . ( If subscribed should not be
present , pass in None . )
"""
result = self . client . post ( " /json/subscriptions/exists " ,
{ " stream " : stream } )
2013-06-18 23:55:55 +02:00
json = ujson . loads ( result . content )
2013-01-29 19:47:28 +01:00
self . assertIn ( " exists " , json )
self . assertEqual ( json [ " exists " ] , exists )
2013-03-21 19:58:30 +01:00
if exists :
self . assert_json_success ( result )
else :
self . assertEquals ( result . status_code , 404 )
2013-01-29 19:47:28 +01:00
if not subscribed is None :
self . assertIn ( " subscribed " , json )
self . assertEqual ( json [ " subscribed " ] , subscribed )
def test_successful_subscriptions_exists_subbed ( self ) :
"""
Calling / json / subscriptions / exist on a stream to which you are subbed
should return that it exists and that you are subbed .
"""
self . assertNotEqual ( len ( self . streams ) , 0 ) # necessary for full test coverage
self . helper_subscriptions_exists ( self . streams [ 0 ] , True , True )
def test_successful_subscriptions_exists_not_subbed ( self ) :
"""
Calling / json / subscriptions / exist on a stream to which you are not
subbed should return that it exists and that you are not subbed .
"""
all_stream_names = [ stream . name for stream in Stream . objects . filter ( realm = self . realm ) ]
streams_not_subbed = list ( set ( all_stream_names ) - set ( self . streams ) )
self . assertNotEqual ( len ( streams_not_subbed ) , 0 ) # necessary for full test coverage
self . helper_subscriptions_exists ( streams_not_subbed [ 0 ] , True , False )
def test_subscriptions_does_not_exist ( self ) :
"""
Calling / json / subscriptions / exist on a stream that doesn ' t exist should
return that it doesn ' t exist.
"""
2013-06-25 16:15:36 +02:00
random_streams = self . make_random_stream_names ( self . streams )
2013-01-29 19:47:28 +01:00
self . assertNotEqual ( len ( random_streams ) , 0 ) # necessary for full test coverage
self . helper_subscriptions_exists ( random_streams [ 0 ] , False , None )
def test_subscriptions_exist_invalid_name ( self ) :
"""
Calling / json / subscriptions / exist on a stream whose name is invalid ( as
2013-07-29 23:03:31 +02:00
defined by valid_stream_name in zerver / views . py ) should return a JSON
2013-01-29 19:47:28 +01:00
error .
"""
# currently, the only invalid stream name is the empty string
invalid_stream_name = " "
result = self . client . post ( " /json/subscriptions/exists " ,
{ " stream " : invalid_stream_name } )
self . assert_json_error ( result , " Invalid characters in stream name " )
2012-12-08 18:01:17 +01:00
class GetOldMessagesTest ( AuthedTestCase ) :
def post_with_params ( self , modified_params ) :
2012-12-19 23:58:02 +01:00
post_params = { " anchor " : 1 , " num_before " : 1 , " num_after " : 1 }
2012-12-08 18:01:17 +01:00
post_params . update ( modified_params )
2013-01-02 21:56:00 +01:00
result = self . client . post ( " /json/get_old_messages " , dict ( post_params ) )
self . assert_json_success ( result )
2013-06-18 23:55:55 +02:00
return ujson . loads ( result . content )
2012-12-08 18:01:17 +01:00
def check_well_formed_messages_response ( self , result ) :
self . assertIn ( " messages " , result )
2013-01-02 22:07:09 +01:00
self . assertIsInstance ( result [ " messages " ] , list )
2012-12-08 18:01:17 +01:00
for message in result [ " messages " ] :
for field in ( " content " , " content_type " , " display_recipient " ,
2013-06-10 21:35:48 +02:00
" avatar_url " , " recipient_id " , " sender_full_name " ,
2012-12-08 18:01:17 +01:00
" sender_short_name " , " timestamp " ) :
self . assertIn ( field , message )
2013-06-10 21:35:48 +02:00
# TODO: deprecate soon in favor of avatar_url
self . assertIn ( ' gravatar_hash ' , message )
2012-12-08 18:01:17 +01:00
2013-01-02 21:56:00 +01:00
def test_successful_get_old_messages ( self ) :
2012-12-08 18:01:17 +01:00
"""
A call to / json / get_old_messages with valid parameters returns a list of
messages .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-01-03 19:46:29 +01:00
self . check_well_formed_messages_response ( self . post_with_params ( { } ) )
2012-12-08 18:01:17 +01:00
2012-12-19 23:58:02 +01:00
def test_get_old_messages_with_narrow_pm_with ( self ) :
2012-12-08 18:01:17 +01:00
"""
2012-12-19 23:58:02 +01:00
A request for old messages with a narrow by pm - with only returns
conversations with that user .
2012-12-08 18:01:17 +01:00
"""
2013-07-24 20:41:09 +02:00
me = ' hamlet@zulip.com '
2012-12-19 23:58:02 +01:00
def dr_emails ( dr ) :
return ' , ' . join ( sorted ( set ( [ r [ ' email ' ] for r in dr ] + [ me ] ) ) )
2013-07-02 21:50:05 +02:00
personals = [ m for m in get_user_messages ( get_user_profile_by_email ( me ) )
2012-12-19 23:58:02 +01:00
if m . recipient . type == Recipient . PERSONAL
or m . recipient . type == Recipient . HUDDLE ]
if not personals :
# FIXME: This is bad. We should use test data that is guaranteed
# to contain some personals for every user. See #617.
return
emails = dr_emails ( get_display_recipient ( personals [ 0 ] . recipient ) )
2012-12-08 18:01:17 +01:00
2012-12-19 23:58:02 +01:00
self . login ( me )
2013-06-18 23:55:55 +02:00
result = self . post_with_params ( { " narrow " : ujson . dumps (
2012-12-19 23:58:02 +01:00
[ [ ' pm-with ' , emails ] ] ) } )
2012-12-08 18:01:17 +01:00
self . check_well_formed_messages_response ( result )
for message in result [ " messages " ] :
2013-01-17 18:12:02 +01:00
self . assertEqual ( dr_emails ( message [ ' display_recipient ' ] ) , emails )
2012-12-08 18:01:17 +01:00
2013-01-02 21:56:00 +01:00
def test_get_old_messages_with_narrow_stream ( self ) :
2012-12-08 18:01:17 +01:00
"""
2012-12-19 23:58:02 +01:00
A request for old messages with a narrow by stream only returns
messages for that stream .
2012-12-08 18:01:17 +01:00
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-05-24 21:14:36 +02:00
# We need to susbcribe to a stream and then send a message to
# it to ensure that we actually have a stream message in this
# narrow view.
2013-07-24 20:56:42 +02:00
realm = Realm . objects . get ( domain = " zulip.com " )
2013-05-24 21:14:36 +02:00
stream , _ = create_stream_if_needed ( realm , " Scotland " )
2013-07-24 20:41:09 +02:00
do_add_subscription ( get_user_profile_by_email ( " hamlet@zulip.com " ) ,
2013-05-24 21:14:36 +02:00
stream , no_log = True )
2013-07-24 20:41:09 +02:00
self . send_message ( " hamlet@zulip.com " , " Scotland " , Recipient . STREAM )
messages = get_user_messages ( get_user_profile_by_email ( " hamlet@zulip.com " ) )
2012-12-08 18:01:17 +01:00
stream_messages = filter ( lambda msg : msg . recipient . type == Recipient . STREAM ,
messages )
stream_name = get_display_recipient ( stream_messages [ 0 ] . recipient )
stream_id = stream_messages [ 0 ] . recipient . id
2013-06-18 23:55:55 +02:00
result = self . post_with_params ( { " narrow " : ujson . dumps (
2012-12-19 23:58:02 +01:00
[ [ ' stream ' , stream_name ] ] ) } )
2012-12-08 18:01:17 +01:00
self . check_well_formed_messages_response ( result )
for message in result [ " messages " ] :
2013-01-17 18:12:02 +01:00
self . assertEqual ( message [ " type " ] , " stream " )
self . assertEqual ( message [ " recipient_id " ] , stream_id )
2012-12-08 18:01:17 +01:00
2013-02-28 22:10:22 +01:00
def test_get_old_messages_with_narrow_sender ( self ) :
"""
A request for old messages with a narrow by sender only returns
messages sent by that person .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-02-28 22:10:22 +01:00
# We need to send a message here to ensure that we actually
# have a stream message in this narrow view.
2013-07-24 20:41:09 +02:00
self . send_message ( " hamlet@zulip.com " , " Scotland " , Recipient . STREAM )
self . send_message ( " othello@zulip.com " , " Scotland " , Recipient . STREAM )
self . send_message ( " othello@zulip.com " , " hamlet@zulip.com " , Recipient . PERSONAL )
self . send_message ( " iago@zulip.com " , " Scotland " , Recipient . STREAM )
2013-02-28 22:10:22 +01:00
2013-06-18 23:55:55 +02:00
result = self . post_with_params ( { " narrow " : ujson . dumps (
2013-07-24 20:41:09 +02:00
[ [ ' sender ' , " othello@zulip.com " ] ] ) } )
2013-02-28 22:10:22 +01:00
self . check_well_formed_messages_response ( result )
for message in result [ " messages " ] :
2013-07-24 20:41:09 +02:00
self . assertEqual ( message [ " sender_email " ] , " othello@zulip.com " )
2013-02-28 22:10:22 +01:00
2012-12-08 18:01:17 +01:00
def test_missing_params ( self ) :
"""
2012-12-19 23:58:02 +01:00
anchor , num_before , and num_after are all required
2012-12-08 18:01:17 +01:00
POST parameters for get_old_messages .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2012-12-08 18:01:17 +01:00
2012-12-19 23:58:02 +01:00
required_args = ( ( " anchor " , 1 ) , ( " num_before " , 1 ) , ( " num_after " , 1 ) )
2012-12-08 18:01:17 +01:00
for i in range ( len ( required_args ) ) :
2013-01-03 20:32:53 +01:00
post_params = dict ( required_args [ : i ] + required_args [ i + 1 : ] )
2012-12-08 18:01:17 +01:00
result = self . client . post ( " /json/get_old_messages " , post_params )
self . assert_json_error ( result ,
" Missing ' %s ' argument " % ( required_args [ i ] [ 0 ] , ) )
def test_bad_int_params ( self ) :
"""
2013-03-11 20:11:24 +01:00
num_before , num_after , and narrow must all be non - negative
2012-12-08 18:01:17 +01:00
integers or strings that can be converted to non - negative integers .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2012-12-08 18:01:17 +01:00
2013-03-11 20:11:24 +01:00
other_params = [ ( " narrow " , { } ) , ( " anchor " , 0 ) ]
int_params = [ " num_before " , " num_after " ]
2012-12-08 18:01:17 +01:00
bad_types = ( False , " " , " -1 " , - 1 )
for idx , param in enumerate ( int_params ) :
for type in bad_types :
# Rotate through every bad type for every integer
# parameter, one at a time.
post_params = dict ( other_params + [ ( param , type ) ] + \
[ ( other_param , 0 ) for other_param in \
int_params [ : idx ] + int_params [ idx + 1 : ] ]
)
result = self . client . post ( " /json/get_old_messages " , post_params )
self . assert_json_error ( result ,
" Bad value for ' %s ' : %s " % ( param , type ) )
def test_bad_narrow_type ( self ) :
"""
2012-12-19 23:58:02 +01:00
narrow must be a list of string pairs .
2012-12-08 18:01:17 +01:00
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2012-12-08 18:01:17 +01:00
other_params = [ ( " anchor " , 0 ) , ( " num_before " , 0 ) , ( " num_after " , 0 ) ]
2012-12-19 23:58:02 +01:00
bad_types = ( False , 0 , ' ' , ' { malformed json, ' ,
2013-01-02 21:43:49 +01:00
' {foo: 3} ' , ' [1,2] ' , ' [[ " x " , " y " , " z " ]] ' )
2012-12-08 18:01:17 +01:00
for type in bad_types :
post_params = dict ( other_params + [ ( " narrow " , type ) ] )
result = self . client . post ( " /json/get_old_messages " , post_params )
self . assert_json_error ( result ,
" Bad value for ' narrow ' : %s " % ( type , ) )
2013-01-02 21:43:49 +01:00
def test_old_empty_narrow ( self ) :
"""
' {} ' is accepted to mean ' no narrow ' , for use by old mobile clients .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-01-02 21:43:49 +01:00
all_result = self . post_with_params ( { } )
narrow_result = self . post_with_params ( { ' narrow ' : ' {} ' } )
for r in ( all_result , narrow_result ) :
self . check_well_formed_messages_response ( r )
self . assertEqual ( message_ids ( all_result ) , message_ids ( narrow_result ) )
2012-12-19 23:58:02 +01:00
def test_bad_narrow_operator ( self ) :
"""
Unrecognized narrow operators are rejected .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2012-12-19 23:58:02 +01:00
for operator in [ ' ' , ' foo ' , ' stream:verona ' , ' __init__ ' ] :
params = dict ( anchor = 0 , num_before = 0 , num_after = 0 ,
2013-06-18 23:55:55 +02:00
narrow = ujson . dumps ( [ [ operator , ' ' ] ] ) )
2012-12-19 23:58:02 +01:00
result = self . client . post ( " /json/get_old_messages " , params )
self . assert_json_error_contains ( result ,
" Invalid narrow operator: unknown operator " )
def exercise_bad_narrow_operand ( self , operator , operands , error_msg ) :
2012-12-08 18:01:17 +01:00
other_params = [ ( " anchor " , 0 ) , ( " num_before " , 0 ) , ( " num_after " , 0 ) ]
2012-12-19 23:58:02 +01:00
for operand in operands :
post_params = dict ( other_params + [
2013-06-18 23:55:55 +02:00
( " narrow " , ujson . dumps ( [ [ operator , operand ] ] ) ) ] )
2012-12-08 18:01:17 +01:00
result = self . client . post ( " /json/get_old_messages " , post_params )
2012-12-19 23:58:02 +01:00
self . assert_json_error_contains ( result , error_msg )
2012-12-08 18:01:17 +01:00
def test_bad_narrow_stream_content ( self ) :
"""
If an invalid stream name is requested in get_old_messages , an error is
returned .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2012-12-19 23:58:02 +01:00
bad_stream_content = ( 0 , [ ] , [ " x " , " y " ] )
self . exercise_bad_narrow_operand ( " stream " , bad_stream_content ,
" Bad value for ' narrow ' " )
2012-12-08 18:01:17 +01:00
def test_bad_narrow_one_on_one_email_content ( self ) :
"""
2012-12-19 23:58:02 +01:00
If an invalid ' pm-with ' is requested in get_old_messages , an
2012-12-08 18:01:17 +01:00
error is returned .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2012-12-19 23:58:02 +01:00
bad_stream_content = ( 0 , [ ] , [ " x " , " y " ] )
self . exercise_bad_narrow_operand ( " pm-with " , bad_stream_content ,
" Bad value for ' narrow ' " )
def test_bad_narrow_nonexistent_stream ( self ) :
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2012-12-19 23:58:02 +01:00
self . exercise_bad_narrow_operand ( " stream " , [ ' non-existent stream ' ] ,
" Invalid narrow operator: unknown stream " )
def test_bad_narrow_nonexistent_email ( self ) :
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-07-24 20:56:42 +02:00
self . exercise_bad_narrow_operand ( " pm-with " , [ ' non-existent-user@zulip.com ' ] ,
2012-12-19 23:58:02 +01:00
" Invalid narrow operator: unknown user " )
2013-07-08 20:46:58 +02:00
def test_message_without_rendered_content ( self ) :
""" Older messages may not have rendered_content in the database """
m = Message . objects . all ( ) . order_by ( ' -id ' ) [ 0 ]
m . rendered_content = m . rendered_content_version = None
m . content = ' test content '
# Use to_dict_uncached directly to avoid having to deal with memcached
d = m . to_dict_uncached ( True )
self . assertEqual ( d [ ' content ' ] , ' <p>test content</p> ' )
2013-09-03 23:28:49 +02:00
class EditMessageTest ( AuthedTestCase ) :
def check_message ( self , msg_id , subject = None , content = None ) :
msg = Message . objects . get ( id = msg_id )
cached = msg . to_dict ( False )
uncached = msg . to_dict_uncached ( False )
self . assertEqual ( cached , uncached )
if subject :
self . assertEqual ( msg . subject , subject )
if content :
self . assertEqual ( msg . content , content )
return msg
def test_save_message ( self ) :
# This is also tested by a client test, but here we can verify
# the cache against the database
self . login ( " hamlet@zulip.com " )
msg_id = self . send_message ( " hamlet@zulip.com " , " Scotland " , Recipient . STREAM ,
subject = " editing " , content = " before edit " )
result = self . client . post ( " /json/update_message " , {
' message_id ' : msg_id ,
' content ' : ' after edit '
} )
self . assert_json_success ( result )
self . check_message ( msg_id , content = " after edit " )
result = self . client . post ( " /json/update_message " , {
' message_id ' : msg_id ,
' subject ' : ' edited '
} )
self . assert_json_success ( result )
self . check_message ( msg_id , subject = " edited " )
def test_propagate_topic ( self ) :
self . login ( " hamlet@zulip.com " )
id1 = self . send_message ( " hamlet@zulip.com " , " Scotland " , Recipient . STREAM ,
subject = " topic1 " )
id2 = self . send_message ( " iago@zulip.com " , " Scotland " , Recipient . STREAM ,
subject = " topic1 " )
id3 = self . send_message ( " iago@zulip.com " , " Rome " , Recipient . STREAM ,
subject = " topic1 " )
id4 = self . send_message ( " hamlet@zulip.com " , " Scotland " , Recipient . STREAM ,
subject = " topic2 " )
id5 = self . send_message ( " iago@zulip.com " , " Scotland " , Recipient . STREAM ,
subject = " topic1 " )
result = self . client . post ( " /json/update_message " , {
' message_id ' : id1 ,
' subject ' : ' edited ' ,
' propagate_subject ' : True
} )
self . assert_json_success ( result )
self . check_message ( id1 , subject = " edited " )
self . check_message ( id2 , subject = " edited " )
self . check_message ( id3 , subject = " topic1 " )
self . check_message ( id4 , subject = " topic2 " )
self . check_message ( id5 , subject = " edited " )
2013-01-04 19:06:34 +01:00
class InviteUserTest ( AuthedTestCase ) :
def invite ( self , users , streams ) :
"""
2013-08-06 21:32:15 +02:00
Invites the specified users to Zulip with the specified streams .
2013-01-04 19:06:34 +01:00
users should be a string containing the users to invite , comma or
newline separated .
streams should be a list of strings .
"""
return self . client . post ( " /json/invite_users " ,
{ " invitee_emails " : users ,
" stream " : streams } )
2013-02-07 18:50:18 +01:00
def check_sent_emails ( self , correct_recipients ) :
from django . core . mail import outbox
self . assertEqual ( len ( outbox ) , len ( correct_recipients ) )
email_recipients = [ email . recipients ( ) [ 0 ] for email in outbox ]
self . assertItemsEqual ( email_recipients , correct_recipients )
2013-01-04 19:06:34 +01:00
def test_successful_invite_user ( self ) :
"""
A call to / json / invite_users with valid parameters causes an invitation
email to be sent .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-07-24 20:56:42 +02:00
invitee = " alice-test@zulip.com "
2013-02-07 18:50:18 +01:00
self . assert_json_success ( self . invite ( invitee , [ " Denmark " ] ) )
self . assertTrue ( find_key_by_email ( invitee ) )
self . check_sent_emails ( [ invitee ] )
2013-01-04 19:06:34 +01:00
def test_multi_user_invite ( self ) :
"""
Invites multiple users with a variety of delimiters .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-01-04 19:06:34 +01:00
# Intentionally use a weird string.
self . assert_json_success ( self . invite (
2013-07-24 20:56:42 +02:00
""" bob-test@zulip.com, carol-test@zulip.com,
dave - test @zulip.com
2013-01-04 19:06:34 +01:00
2013-07-24 20:56:42 +02:00
earl - test @zulip.com """ , [ " Denmark " ]))
2013-01-04 19:06:34 +01:00
for user in ( " bob " , " carol " , " dave " , " earl " ) :
2013-07-24 20:56:42 +02:00
self . assertTrue ( find_key_by_email ( " %s -test@zulip.com " % user ) )
self . check_sent_emails ( [ " bob-test@zulip.com " , " carol-test@zulip.com " ,
" dave-test@zulip.com " , " earl-test@zulip.com " ] )
2013-01-04 19:06:34 +01:00
2013-02-07 16:26:58 +01:00
def test_missing_or_invalid_params ( self ) :
2013-01-04 19:06:34 +01:00
"""
2013-02-07 16:26:58 +01:00
Tests inviting with various missing or invalid parameters .
2013-01-04 19:06:34 +01:00
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-01-04 19:06:34 +01:00
self . assert_json_error (
2013-07-24 20:56:42 +02:00
self . client . post ( " /json/invite_users " , { " invitee_emails " : " foo@zulip.com " } ) ,
2013-01-04 19:06:34 +01:00
" You must specify at least one stream for invitees to join. " )
for address in ( " noatsign.com " , " outsideyourdomain@example.net " ) :
self . assert_json_error (
self . invite ( address , [ " Denmark " ] ) ,
2013-02-07 16:26:58 +01:00
" Some emails did not validate, so we didn ' t send any invitations. " )
2013-02-07 18:50:18 +01:00
self . check_sent_emails ( [ ] )
2013-01-04 19:06:34 +01:00
def test_invalid_stream ( self ) :
"""
Tests inviting to a non - existent stream .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-07-24 20:56:42 +02:00
self . assert_json_error ( self . invite ( " iago-test@zulip.com " , [ " NotARealStream " ] ) ,
2013-01-04 19:06:34 +01:00
" Stream does not exist: NotARealStream. No invites were sent. " )
2013-02-07 18:50:18 +01:00
self . check_sent_emails ( [ ] )
2012-12-21 01:06:53 +01:00
2013-02-07 17:07:24 +01:00
def test_invite_existing_user ( self ) :
"""
2013-08-06 21:32:15 +02:00
If you invite an address already using Zulip , no invitation is sent .
2013-02-07 17:07:24 +01:00
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-02-07 17:07:24 +01:00
self . assert_json_error (
self . client . post ( " /json/invite_users " ,
2013-07-24 20:41:09 +02:00
{ " invitee_emails " : " hamlet@zulip.com " ,
2013-02-07 17:07:24 +01:00
" stream " : [ " Denmark " ] } ) ,
" We weren ' t able to invite anyone. " )
self . assertRaises ( PreregistrationUser . DoesNotExist ,
lambda : PreregistrationUser . objects . get (
2013-07-24 20:41:09 +02:00
email = " hamlet@zulip.com " ) )
2013-02-07 18:50:18 +01:00
self . check_sent_emails ( [ ] )
2013-02-07 17:07:24 +01:00
def test_invite_some_existing_some_new ( self ) :
"""
If you invite a mix of already existing and new users , invitations are
only sent to the new users .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
existing = [ " hamlet@zulip.com " , " othello@zulip.com " ]
2013-07-24 20:56:42 +02:00
new = [ " foo-test@zulip.com " , " bar-test@zulip.com " ]
2013-02-07 17:07:24 +01:00
result = self . client . post ( " /json/invite_users " ,
{ " invitee_emails " : " \n " . join ( existing + new ) ,
" stream " : [ " Denmark " ] } )
self . assert_json_error ( result ,
2013-07-29 19:47:31 +02:00
" Some of those addresses are already using Zulip, \
2013-02-07 17:07:24 +01:00
so we didn ' t send them an invitation. We did send invitations to everyone else! " )
2013-02-07 18:50:18 +01:00
# We only created accounts for the new users.
2013-02-07 17:07:24 +01:00
for email in existing :
self . assertRaises ( PreregistrationUser . DoesNotExist ,
lambda : PreregistrationUser . objects . get (
email = email ) )
for email in new :
self . assertTrue ( PreregistrationUser . objects . get ( email = email ) )
2013-02-07 18:50:18 +01:00
# We only sent emails to the new users.
self . check_sent_emails ( new )
2013-07-02 19:10:50 +02:00
@slow ( 0.20 , ' inviting is slow ' )
def test_invite_outside_domain_in_closed_realm ( self ) :
2013-02-07 17:07:24 +01:00
"""
2013-07-02 19:10:50 +02:00
In a realm with ` restricted_to_domain = True ` , you can ' t invite people
2013-02-07 17:07:24 +01:00
with a different domain from that of the realm or your e - mail address .
"""
2013-08-06 17:40:44 +02:00
zulip_realm = Realm . objects . get ( domain = " zulip.com " )
zulip_realm . restricted_to_domain = True
zulip_realm . save ( )
2013-07-02 19:10:50 +02:00
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-02-07 17:07:24 +01:00
external_address = " foo@example.com "
self . assert_json_error (
self . invite ( external_address , [ " Denmark " ] ) ,
" Some emails did not validate, so we didn ' t send any invitations. " )
2013-07-02 19:10:50 +02:00
@slow ( 0.20 , ' inviting is slow ' )
def test_invite_outside_domain_in_open_realm ( self ) :
"""
In a realm with ` restricted_to_domain = False ` , you can invite people
with a different domain from that of the realm or your e - mail address .
"""
2013-08-06 17:40:44 +02:00
zulip_realm = Realm . objects . get ( domain = " zulip.com " )
zulip_realm . restricted_to_domain = False
zulip_realm . save ( )
2013-02-07 17:07:24 +01:00
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-07-02 19:10:50 +02:00
external_address = " foo@example.com "
2013-02-07 17:07:24 +01:00
self . assert_json_success ( self . invite ( external_address , [ " Denmark " ] ) )
2013-02-07 18:50:18 +01:00
self . check_sent_emails ( [ external_address ] )
2013-02-06 17:27:40 +01:00
2013-03-22 21:46:27 +01:00
def test_invite_with_non_ascii_streams ( self ) :
"""
Inviting someone to streams with non - ASCII characters succeeds .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-07-24 20:56:42 +02:00
invitee = " alice-test@zulip.com "
2013-03-22 21:46:27 +01:00
stream_name = u " hümbüǵ "
2013-07-24 20:56:42 +02:00
realm = Realm . objects . get ( domain = " zulip.com " )
2013-03-22 21:46:27 +01:00
stream , _ = create_stream_if_needed ( realm , stream_name )
# Make sure we're subscribed before inviting someone.
do_add_subscription (
2013-07-24 20:41:09 +02:00
get_user_profile_by_email ( " hamlet@zulip.com " ) ,
2013-03-22 21:46:27 +01:00
stream , no_log = True )
self . assert_json_success ( self . invite ( invitee , [ stream_name ] ) )
2012-12-21 01:06:53 +01:00
class ChangeSettingsTest ( AuthedTestCase ) :
def post_with_params ( self , modified_params ) :
post_params = { " full_name " : " Foo Bar " ,
2013-07-24 20:41:09 +02:00
" old_password " : initial_password ( " hamlet@zulip.com " ) ,
2012-12-21 01:06:53 +01:00
" new_password " : " foobar1 " , " confirm_password " : " foobar1 " ,
2013-05-08 20:39:29 +02:00
" enable_desktop_notifications " : " " ,
" enable_offline_email_notifications " : " " ,
" enable_sounds " : " " }
2012-12-21 01:06:53 +01:00
post_params . update ( modified_params )
return self . client . post ( " /json/settings/change " , dict ( post_params ) )
def check_well_formed_change_settings_response ( self , result ) :
self . assertIn ( " full_name " , result )
self . assertIn ( " enable_desktop_notifications " , result )
2013-05-08 20:39:29 +02:00
self . assertIn ( " enable_sounds " , result )
self . assertIn ( " enable_offline_email_notifications " , result )
2012-12-21 01:06:53 +01:00
2012-12-21 16:59:08 +01:00
def test_successful_change_settings ( self ) :
2012-12-21 01:06:53 +01:00
"""
A call to / json / settings / change with valid parameters changes the user ' s
settings correctly and returns correct values .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2012-12-21 01:06:53 +01:00
json_result = self . post_with_params ( { } )
self . assert_json_success ( json_result )
2013-06-18 23:55:55 +02:00
result = ujson . loads ( json_result . content )
2012-12-21 01:06:53 +01:00
self . check_well_formed_change_settings_response ( result )
2013-07-24 20:41:09 +02:00
self . assertEqual ( get_user_profile_by_email ( " hamlet@zulip.com " ) .
2012-12-21 01:06:53 +01:00
full_name , " Foo Bar " )
2013-07-24 20:41:09 +02:00
self . assertEqual ( get_user_profile_by_email ( " hamlet@zulip.com " ) .
2012-12-21 01:06:53 +01:00
enable_desktop_notifications , False )
self . client . post ( ' /accounts/logout/ ' )
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " , " foobar1 " )
user_profile = get_user_profile_by_email ( ' hamlet@zulip.com ' )
2013-03-29 17:39:53 +01:00
self . assertEqual ( self . client . session [ ' _auth_user_id ' ] , user_profile . id )
2012-12-21 01:06:53 +01:00
2012-12-21 16:59:08 +01:00
def test_missing_params ( self ) :
"""
full_name , old_password , and new_password are all required POST
parameters for json_change_settings . ( enable_desktop_notifications is
false by default )
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2012-12-21 16:59:08 +01:00
required_params = ( ( " full_name " , " Foo Bar " ) ,
2013-07-24 20:41:09 +02:00
( " old_password " , initial_password ( " hamlet@zulip.com " ) ) ,
( " new_password " , initial_password ( " hamlet@zulip.com " ) ) ,
( " confirm_password " , initial_password ( " hamlet@zulip.com " ) ) )
2012-12-21 16:59:08 +01:00
for i in range ( len ( required_params ) ) :
2013-01-03 20:32:53 +01:00
post_params = dict ( required_params [ : i ] + required_params [ i + 1 : ] )
2012-12-21 16:59:08 +01:00
result = self . client . post ( " /json/settings/change " , post_params )
self . assert_json_error ( result ,
" Missing ' %s ' argument " % ( required_params [ i ] [ 0 ] , ) )
2012-12-21 01:06:53 +01:00
def test_mismatching_passwords ( self ) :
"""
new_password and confirm_password must match
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2012-12-21 01:06:53 +01:00
result = self . post_with_params ( { " new_password " : " mismatched_password " } )
self . assert_json_error ( result ,
" New password must match confirmation password! " )
def test_wrong_old_password ( self ) :
"""
new_password and confirm_password must match
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2012-12-21 01:06:53 +01:00
result = self . post_with_params ( { " old_password " : " bad_password " } )
self . assert_json_error ( result , " Wrong password! " )
2013-08-13 19:21:45 +02:00
class MITNameTest ( TestCase ) :
def test_valid_hesiod ( self ) :
self . assertEquals ( compute_mit_user_fullname ( " starnine@mit.edu " ) , " Athena Consulting Exchange User " )
self . assertEquals ( compute_mit_user_fullname ( " sipbexch@mit.edu " ) , " Exch Sipb " )
def test_invalid_hesiod ( self ) :
self . assertEquals ( compute_mit_user_fullname ( " 1234567890@mit.edu " ) , " 1234567890@mit.edu " )
self . assertEquals ( compute_mit_user_fullname ( " ec-discuss@mit.edu " ) , " ec-discuss@mit.edu " )
def test_mailinglist ( self ) :
self . assertRaises ( ValidationError , not_mit_mailing_list , " 1234567890@mit.edu " )
self . assertRaises ( ValidationError , not_mit_mailing_list , " ec-discuss@mit.edu " )
def test_notmailinglist ( self ) :
self . assertTrue ( not_mit_mailing_list ( " sipbexch@mit.edu " ) )
2013-03-14 22:12:25 +01:00
class S3Test ( AuthedTestCase ) :
test_uris = [ ]
2013-06-20 20:46:28 +02:00
@slow ( 2.6 , " has to contact external S3 service " )
2013-03-14 22:12:25 +01:00
def test_file_upload ( self ) :
"""
A call to / json / upload_file should return a uri and actually create an object .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-08-06 22:20:02 +02:00
fp = StringIO ( " zulip! " )
fp . name = " zulip.txt "
2013-03-14 22:12:25 +01:00
result = self . client . post ( " /json/upload_file " , { ' file ' : fp } )
self . assert_json_success ( result )
2013-06-18 23:55:55 +02:00
json = ujson . loads ( result . content )
2013-03-14 22:12:25 +01:00
self . assertIn ( " uri " , json )
uri = json [ " uri " ]
self . test_uris . append ( uri )
2013-08-06 22:20:02 +02:00
self . assertEquals ( " zulip! " , urllib2 . urlopen ( uri ) . read ( ) . strip ( ) )
2013-03-14 22:12:25 +01:00
def test_multiple_upload_failure ( self ) :
"""
Attempting to upload two files should fail .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-03-14 22:12:25 +01:00
fp = StringIO ( " bah! " )
fp . name = " a.txt "
fp2 = StringIO ( " pshaw! " )
fp2 . name = " b.txt "
result = self . client . post ( " /json/upload_file " , { ' f1 ' : fp , ' f2 ' : fp2 } )
self . assert_json_error ( result , " You may only upload one file at a time " )
def test_no_file_upload_failure ( self ) :
"""
Calling this endpoint with no files should fail .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-03-14 22:12:25 +01:00
result = self . client . post ( " /json/upload_file " )
self . assert_json_error ( result , " You must specify a file to upload " )
def tearDown ( self ) :
# clean up
conn = S3Connection ( settings . S3_KEY , settings . S3_SECRET_KEY )
for uri in self . test_uris :
2013-03-27 21:26:00 +01:00
key = Key ( conn . get_bucket ( settings . S3_BUCKET ) )
2013-03-14 22:12:25 +01:00
key . name = urllib2 . urlparse . urlparse ( uri ) . path [ 1 : ]
key . delete ( )
self . test_uris . remove ( uri )
2013-07-02 00:11:59 +02:00
class DummyStream :
def closed ( self ) :
return False
class DummyObject :
pass
class DummyTornadoRequest :
def __init__ ( self ) :
self . connection = DummyObject ( )
self . connection . stream = DummyStream ( )
2012-12-21 01:06:53 +01:00
2012-09-06 23:55:04 +02:00
class DummyHandler ( object ) :
2012-11-28 07:59:57 +01:00
def __init__ ( self , assert_callback ) :
self . assert_callback = assert_callback
2013-07-02 00:11:59 +02:00
self . request = DummyTornadoRequest ( )
2012-09-06 23:55:04 +02:00
2012-11-28 07:59:57 +01:00
# Mocks RequestHandler.async_callback, which wraps a callback to
# handle exceptions. We return the callback as-is.
def async_callback ( self , cb ) :
return cb
2012-09-06 23:55:04 +02:00
2012-11-28 07:59:57 +01:00
def write ( self , response ) :
raise NotImplemented
2013-08-06 22:21:12 +02:00
def zulip_finish ( self , response , * ignore ) :
2012-11-28 07:59:57 +01:00
if self . assert_callback :
self . assert_callback ( response )
2012-10-01 22:57:01 +02:00
2013-07-02 00:11:59 +02:00
2012-10-29 19:53:56 +01:00
class DummySession ( object ) :
session_key = " 0 "
2012-09-06 23:55:04 +02:00
class POSTRequestMock ( object ) :
method = " POST "
2013-03-29 17:39:53 +01:00
def __init__ ( self , post_data , user_profile , assert_callback = None ) :
2013-03-22 15:57:31 +01:00
self . REQUEST = self . POST = post_data
2013-03-29 17:39:53 +01:00
self . user = user_profile
2012-09-06 23:55:04 +02:00
self . _tornado_handler = DummyHandler ( assert_callback )
2012-10-29 19:53:56 +01:00
self . session = DummySession ( )
2012-11-09 18:22:13 +01:00
self . META = { ' PATH_INFO ' : ' test ' }
2012-09-06 23:55:04 +02:00
2012-09-27 21:44:54 +02:00
class GetUpdatesTest ( AuthedTestCase ) :
2012-09-06 23:55:04 +02:00
2012-11-15 19:42:17 +01:00
def common_test_get_updates ( self , view_func , extra_post_data = { } ) :
2013-07-24 20:41:09 +02:00
user_profile = get_user_profile_by_email ( " hamlet@zulip.com " )
2013-07-02 00:11:59 +02:00
message_content = ' tornado test message '
self . got_callback = False
2012-09-06 23:55:04 +02:00
2012-11-28 07:59:57 +01:00
def callback ( response ) :
2013-07-02 00:11:59 +02:00
self . got_callback = True
msg = response [ ' messages ' ] [ 0 ]
if str ( msg [ ' content_type ' ] ) == ' text/html ' :
self . assertEqual ( ' <p> %s </p> ' % message_content , msg [ ' content ' ] )
else :
self . assertEqual ( message_content , msg [ ' content ' ] )
2012-09-06 23:55:04 +02:00
2013-01-17 21:03:43 +01:00
post_data = { }
2012-11-15 19:42:17 +01:00
post_data . update ( extra_post_data )
2013-03-29 17:39:53 +01:00
request = POSTRequestMock ( post_data , user_profile , callback )
2013-01-17 18:12:02 +01:00
self . assertEqual ( view_func ( request ) , RespondAsynchronously )
2013-07-24 20:41:09 +02:00
self . send_message ( " hamlet@zulip.com " , " hamlet@zulip.com " ,
2013-07-02 00:11:59 +02:00
Recipient . PERSONAL , message_content )
self . assertTrue ( self . got_callback )
2012-11-15 19:42:17 +01:00
def test_json_get_updates ( self ) :
"""
json_get_updates returns messages with IDs greater than the
last_received ID .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2012-11-15 19:42:17 +01:00
self . common_test_get_updates ( json_get_updates )
def test_api_get_messages ( self ) :
"""
Same as above , but for the API view
"""
2013-07-24 20:41:09 +02:00
email = " hamlet@zulip.com "
2012-11-15 19:42:17 +01:00
api_key = self . get_api_key ( email )
self . common_test_get_updates ( api_get_messages , { ' email ' : email , ' api-key ' : api_key } )
2012-09-06 23:55:04 +02:00
def test_missing_last_received ( self ) :
"""
2012-10-30 21:54:30 +01:00
Calling json_get_updates without any arguments should work
2012-09-06 23:55:04 +02:00
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
user_profile = get_user_profile_by_email ( " hamlet@zulip.com " )
2012-09-06 23:55:04 +02:00
2013-03-29 17:39:53 +01:00
request = POSTRequestMock ( { } , user_profile )
2013-01-17 18:12:02 +01:00
self . assertEqual ( json_get_updates ( request ) , RespondAsynchronously )
2012-10-30 21:54:30 +01:00
2012-12-19 20:19:46 +01:00
def test_bad_input ( self ) :
"""
Specifying a bad value for ' pointer ' should return an error
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
user_profile = get_user_profile_by_email ( " hamlet@zulip.com " )
2012-12-19 20:19:46 +01:00
2013-03-29 17:39:53 +01:00
request = POSTRequestMock ( { ' pointer ' : ' foo ' } , user_profile )
2012-12-19 20:19:46 +01:00
self . assertRaises ( RequestVariableConversionError , json_get_updates , request )
2013-01-22 20:07:51 +01:00
class GetProfileTest ( AuthedTestCase ) :
def common_update_pointer ( self , email , pointer ) :
self . login ( email )
2013-08-19 21:05:23 +02:00
result = self . client . post ( " /json/update_pointer " , { " pointer " : pointer } )
2013-01-22 20:07:51 +01:00
self . assert_json_success ( result )
def common_get_profile ( self , email ) :
2013-07-02 21:50:05 +02:00
user_profile = get_user_profile_by_email ( email )
2013-07-02 18:13:26 +02:00
self . send_message ( email , " Verona " , Recipient . STREAM , " hello " )
2013-01-22 20:07:51 +01:00
api_key = self . get_api_key ( email )
2013-01-28 22:59:25 +01:00
result = self . client . post ( " /api/v1/get_profile " , { ' email ' : email , ' api-key ' : api_key } )
2013-01-22 20:07:51 +01:00
2013-07-02 16:15:10 +02:00
max_id = most_recent_message ( user_profile ) . id
2013-01-22 20:07:51 +01:00
self . assert_json_success ( result )
2013-06-18 23:55:55 +02:00
json = ujson . loads ( result . content )
2013-01-22 20:07:51 +01:00
self . assertIn ( " client_id " , json )
self . assertIn ( " max_message_id " , json )
self . assertIn ( " pointer " , json )
2013-01-17 18:12:02 +01:00
self . assertEqual ( json [ " max_message_id " ] , max_id )
2013-01-22 20:07:51 +01:00
return json
def test_api_get_empty_profile ( self ) :
"""
Ensure get_profile returns a max message id and returns successfully
"""
2013-07-24 20:41:09 +02:00
json = self . common_get_profile ( " othello@zulip.com " )
2013-01-17 18:12:02 +01:00
self . assertEqual ( json [ " pointer " ] , - 1 )
2013-01-22 20:07:51 +01:00
def test_profile_with_pointer ( self ) :
"""
Ensure get_profile returns a proper pointer id after the pointer is updated
"""
2013-08-19 21:05:23 +02:00
2013-08-28 21:29:55 +02:00
id1 = self . send_message ( " othello@zulip.com " , " Verona " , Recipient . STREAM )
id2 = self . send_message ( " othello@zulip.com " , " Verona " , Recipient . STREAM )
2013-08-19 21:05:23 +02:00
2013-07-24 20:41:09 +02:00
json = self . common_get_profile ( " hamlet@zulip.com " )
2013-01-22 20:07:51 +01:00
2013-08-19 21:05:23 +02:00
self . common_update_pointer ( " hamlet@zulip.com " , id2 )
2013-07-24 20:41:09 +02:00
json = self . common_get_profile ( " hamlet@zulip.com " )
2013-08-19 21:05:23 +02:00
self . assertEqual ( json [ " pointer " ] , id2 )
2013-01-22 20:07:51 +01:00
2013-08-19 21:05:23 +02:00
self . common_update_pointer ( " hamlet@zulip.com " , id1 )
2013-07-24 20:41:09 +02:00
json = self . common_get_profile ( " hamlet@zulip.com " )
2013-08-19 21:05:23 +02:00
self . assertEqual ( json [ " pointer " ] , id2 ) # pointer does not move backwards
result = self . client . post ( " /json/update_pointer " , { " pointer " : 99999999 } )
self . assert_json_error ( result , " Invalid message ID " )
2012-12-19 20:19:46 +01:00
2013-01-23 16:18:08 +01:00
class GetPublicStreamsTest ( AuthedTestCase ) :
def test_public_streams ( self ) :
"""
Ensure that get_public_streams successfully returns a list of streams
"""
2013-07-24 20:41:09 +02:00
email = ' hamlet@zulip.com '
2013-01-28 22:59:25 +01:00
self . login ( email )
2013-01-23 16:18:08 +01:00
2013-08-22 17:37:02 +02:00
result = self . client . post ( " /json/get_public_streams " )
2013-01-23 16:18:08 +01:00
self . assert_json_success ( result )
2013-06-18 23:55:55 +02:00
json = ujson . loads ( result . content )
2013-01-23 16:18:08 +01:00
self . assertIn ( " streams " , json )
self . assertIsInstance ( json [ " streams " ] , list )
2013-08-22 17:37:02 +02:00
def test_public_streams_api ( self ) :
"""
Ensure that get_public_streams successfully returns a list of streams
"""
email = ' hamlet@zulip.com '
self . login ( email )
# Check it correctly lists the user's subs with include_public=false
result = self . client . get ( " /api/v1/streams?include_public=false " , * * self . api_auth ( email ) )
result2 = self . client . post ( " /json/subscriptions/list " , { } )
self . assert_json_success ( result )
json = ujson . loads ( result . content )
self . assertIn ( " streams " , json )
self . assertIsInstance ( json [ " streams " ] , list )
self . assert_json_success ( result2 )
json2 = ujson . loads ( result2 . content )
self . assertEqual ( sorted ( [ s [ " name " ] for s in json [ " streams " ] ] ) ,
sorted ( [ s [ " name " ] for s in json2 [ " subscriptions " ] ] ) )
# Check it correctly lists all public streams with include_subscribed=false
result = self . client . get ( " /api/v1/streams?include_public=true&include_subscribed=false " ,
* * self . api_auth ( email ) )
self . assert_json_success ( result )
json = ujson . loads ( result . content )
all_streams = [ stream . name for stream in
Stream . objects . filter ( realm = get_user_profile_by_email ( email ) . realm ) ]
self . assertEqual ( sorted ( s [ " name " ] for s in json [ " streams " ] ) ,
sorted ( all_streams ) )
# Check non-superuser can't use include_all_active
result = self . client . get ( " /api/v1/streams?include_all_active=true " ,
* * self . api_auth ( email ) )
self . assertEqual ( result . status_code , 400 )
2013-01-23 20:39:35 +01:00
class InviteOnlyStreamTest ( AuthedTestCase ) :
2013-08-28 21:37:21 +02:00
def test_must_be_subbed_to_send ( self ) :
"""
If you try to send a message to an invite - only stream to which
you aren ' t subscribed, you ' ll get a 400.
"""
self . login ( " hamlet@zulip.com " )
# Create Saxony as an invite-only stream.
self . assert_json_success (
self . common_subscribe_to_streams ( " hamlet@zulip.com " , [ " Saxony " ] ,
invite_only = True ) )
email = " cordelia@zulip.com "
with self . assertRaises ( JsonableError ) :
self . send_message ( email , " Saxony " , Recipient . STREAM )
2013-01-23 20:39:35 +01:00
2013-02-05 20:06:35 +01:00
def test_list_respects_invite_only_bit ( self ) :
"""
Make sure that / json / subscriptions / list properly returns
the invite - only bit for streams that are invite - only
"""
2013-07-24 20:41:09 +02:00
email = ' hamlet@zulip.com '
2013-02-05 20:06:35 +01:00
self . login ( email )
2013-06-25 16:18:39 +02:00
result1 = self . common_subscribe_to_streams ( email , [ " Saxony " ] , invite_only = True )
2013-02-05 20:06:35 +01:00
self . assert_json_success ( result1 )
2013-06-25 16:18:39 +02:00
result2 = self . common_subscribe_to_streams ( email , [ " Normandy " ] , invite_only = False )
2013-02-05 20:06:35 +01:00
self . assert_json_success ( result2 )
result = self . client . post ( " /json/subscriptions/list " , { } )
self . assert_json_success ( result )
2013-06-18 23:55:55 +02:00
json = ujson . loads ( result . content )
2013-02-05 20:06:35 +01:00
self . assertIn ( " subscriptions " , json )
for sub in json [ " subscriptions " ] :
if sub [ ' name ' ] == " Normandy " :
self . assertEqual ( sub [ ' invite_only ' ] , False , " Normandy was mistakenly marked invite-only " )
if sub [ ' name ' ] == " Saxony " :
self . assertEqual ( sub [ ' invite_only ' ] , True , " Saxony was not properly marked invite-only " )
2013-07-01 20:17:52 +02:00
@slow ( 0.15 , " lots of queries " )
2013-01-23 20:39:35 +01:00
def test_inviteonly ( self ) :
# Creating an invite-only stream is allowed
2013-07-24 20:41:09 +02:00
email = ' hamlet@zulip.com '
2013-01-28 22:59:25 +01:00
2013-06-25 16:18:39 +02:00
result = self . common_subscribe_to_streams ( email , [ " Saxony " ] , invite_only = True )
2013-01-23 20:39:35 +01:00
self . assert_json_success ( result )
2013-06-18 23:55:55 +02:00
json = ujson . loads ( result . content )
2013-01-31 20:58:58 +01:00
self . assertEqual ( json [ " subscribed " ] , { email : [ ' Saxony ' ] } )
self . assertEqual ( json [ " already_subscribed " ] , { } )
2013-01-23 20:39:35 +01:00
# Subscribing oneself to an invite-only stream is not allowed
2013-07-24 20:41:09 +02:00
email = " othello@zulip.com "
2013-02-04 22:32:18 +01:00
self . login ( email )
2013-06-25 16:18:39 +02:00
result = self . common_subscribe_to_streams ( email , [ " Saxony " ] )
2013-08-22 17:54:57 +02:00
self . assert_json_error ( result , ' Unable to access stream (Saxony). ' )
2013-01-23 20:39:35 +01:00
2013-08-15 23:17:00 +02:00
# authorization_errors_fatal=False works
email = " othello@zulip.com "
self . login ( email )
result = self . common_subscribe_to_streams ( email , [ " Saxony " ] ,
extra_post_data = { ' authorization_errors_fatal ' : ujson . dumps ( False ) } )
self . assert_json_success ( result )
json = ujson . loads ( result . content )
self . assertEqual ( json [ " unauthorized " ] , [ ' Saxony ' ] )
self . assertEqual ( json [ " subscribed " ] , { } )
self . assertEqual ( json [ " already_subscribed " ] , { } )
2013-01-23 20:39:35 +01:00
# Inviting another user to an invite-only stream is allowed
2013-07-24 20:41:09 +02:00
email = ' hamlet@zulip.com '
2013-02-04 22:32:18 +01:00
self . login ( email )
2013-06-25 16:18:39 +02:00
result = self . common_subscribe_to_streams (
email , [ " Saxony " ] ,
2013-07-24 20:41:09 +02:00
extra_post_data = { ' principals ' : ujson . dumps ( [ " othello@zulip.com " ] ) } )
2013-08-15 23:17:00 +02:00
self . assert_json_success ( result )
2013-06-18 23:55:55 +02:00
json = ujson . loads ( result . content )
2013-07-24 20:41:09 +02:00
self . assertEqual ( json [ " subscribed " ] , { " othello@zulip.com " : [ ' Saxony ' ] } )
2013-01-31 20:58:58 +01:00
self . assertEqual ( json [ " already_subscribed " ] , { } )
2013-01-23 20:39:35 +01:00
# Make sure both users are subscribed to this stream
2013-01-30 22:40:00 +01:00
result = self . client . post ( " /api/v1/get_subscribers " , { ' email ' : email ,
2013-01-28 22:59:25 +01:00
' api-key ' : self . get_api_key ( email ) ,
' stream ' : ' Saxony ' } )
2013-01-23 20:39:35 +01:00
self . assert_json_success ( result )
2013-06-18 23:55:55 +02:00
json = ujson . loads ( result . content )
2013-01-23 20:39:35 +01:00
2013-07-24 20:41:09 +02:00
self . assertTrue ( ' othello@zulip.com ' in json [ ' subscribers ' ] )
self . assertTrue ( ' hamlet@zulip.com ' in json [ ' subscribers ' ] )
2013-01-23 20:39:35 +01:00
2013-02-05 04:24:16 +01:00
class GetSubscribersTest ( AuthedTestCase ) :
def setUp ( self ) :
2013-07-24 20:41:09 +02:00
self . email = " hamlet@zulip.com "
2013-02-05 04:24:16 +01:00
self . api_key = self . get_api_key ( self . email )
2013-07-02 21:50:05 +02:00
self . user_profile = get_user_profile_by_email ( self . email )
2013-02-05 04:24:16 +01:00
self . login ( self . email )
def check_well_formed_result ( self , result , stream_name , domain ) :
"""
A successful call to get_subscribers returns the list of subscribers in
the form :
{ " msg " : " " ,
" result " : " success " ,
2013-07-24 20:41:09 +02:00
" subscribers " : [ " hamlet@zulip.com " , " prospero@zulip.com " ] }
2013-02-05 04:24:16 +01:00
"""
self . assertIn ( " subscribers " , result )
self . assertIsInstance ( result [ " subscribers " ] , list )
2013-03-28 20:43:34 +01:00
true_subscribers = [ user_profile . email for user_profile in self . users_subscribed_to_stream (
2013-02-05 04:24:16 +01:00
stream_name , domain ) ]
self . assertItemsEqual ( result [ " subscribers " ] , true_subscribers )
def make_subscriber_request ( self , stream_name ) :
return self . client . post ( " /json/get_subscribers " ,
{ ' email ' : self . email , ' api-key ' : self . api_key ,
' stream ' : stream_name } )
def make_successful_subscriber_request ( self , stream_name ) :
result = self . make_subscriber_request ( stream_name )
self . assert_json_success ( result )
2013-06-18 23:55:55 +02:00
self . check_well_formed_result ( ujson . loads ( result . content ) ,
2013-02-05 04:24:16 +01:00
stream_name , self . user_profile . realm . domain )
def test_subscriber ( self ) :
"""
get_subscribers returns the list of subscribers .
"""
2013-06-12 21:15:32 +02:00
stream_name = gather_subscriptions ( self . user_profile ) [ 0 ] [ 0 ] [ ' name ' ]
2013-02-05 04:24:16 +01:00
self . make_successful_subscriber_request ( stream_name )
def test_nonsubscriber ( self ) :
"""
Even a non - subscriber to a public stream can query a stream ' s membership
with get_subscribers .
"""
# Create a stream for which Hamlet is the only subscriber.
stream_name = " Saxony "
2013-06-25 16:29:32 +02:00
self . common_subscribe_to_streams ( self . email , [ stream_name ] )
2013-07-24 20:41:09 +02:00
other_email = " othello@zulip.com "
2013-02-05 04:24:16 +01:00
# Fetch the subscriber list as a non-member.
self . login ( other_email )
self . make_successful_subscriber_request ( stream_name )
def test_subscriber_private_stream ( self ) :
"""
A subscriber to a private stream can query that stream ' s membership.
"""
stream_name = " Saxony "
2013-06-25 16:29:32 +02:00
self . common_subscribe_to_streams ( self . email , [ stream_name ] ,
invite_only = True )
2013-02-05 04:24:16 +01:00
self . make_successful_subscriber_request ( stream_name )
def test_nonsubscriber_private_stream ( self ) :
"""
A non - subscriber to a private stream can ' t query that stream ' s membership .
"""
# Create a private stream for which Hamlet is the only subscriber.
stream_name = " Saxony "
2013-06-25 16:29:32 +02:00
self . common_subscribe_to_streams ( self . email , [ stream_name ] ,
invite_only = True )
2013-07-24 20:41:09 +02:00
other_email = " othello@zulip.com "
2013-02-05 04:24:16 +01:00
# Try to fetch the subscriber list as a non-member.
self . login ( other_email )
result = self . make_subscriber_request ( stream_name )
self . assert_json_error ( result ,
" Unable to retrieve subscribers for invite-only stream " )
2013-06-05 19:23:19 +02:00
def bugdown_convert ( text ) :
2013-07-24 20:56:42 +02:00
return bugdown . convert ( text , " zulip.com " )
2013-01-24 20:20:21 +01:00
2013-06-05 19:23:19 +02:00
class BugdownTest ( TestCase ) :
2013-01-24 20:20:21 +01:00
def common_bugdown_test ( self , text , expected ) :
2013-06-05 19:23:19 +02:00
converted = bugdown_convert ( text )
2013-01-17 18:12:02 +01:00
self . assertEqual ( converted , expected )
2013-01-24 20:20:21 +01:00
def test_codeblock_hilite ( self ) :
fenced_code = \
""" Hamlet said:
~ ~ ~ ~ . python
def speak ( self ) :
x = 1
~ ~ ~ ~ """
expected_convert = \
""" <p>Hamlet said:</p>
< div class = " codehilite " > < pre > < span class = " k " > def < / span > < span class = " nf " > \
speak < / span > < span class = " p " > ( < / span > < span class = " bp " > self < / span > < span class = " p " > ) : < / span >
< span class = " n " > x < / span > < span class = " o " > = < / span > < span class = " mi " > 1 < / span >
< / pre > < / div > """
self . common_bugdown_test ( fenced_code , expected_convert )
def test_codeblock_multiline ( self ) :
fenced_code = \
""" Hamlet once said
2013-01-25 23:02:35 +01:00
~ ~ ~ ~
2013-01-24 20:20:21 +01:00
def func ( ) :
x = 1
y = 2
z = 3
2013-01-25 23:02:35 +01:00
~ ~ ~ ~
2013-01-24 20:20:21 +01:00
And all was good . """
expected_convert = \
""" <p>Hamlet once said</p>
< div class = " codehilite " > < pre > def func ( ) :
x = 1
y = 2
z = 3
< / pre > < / div >
< p > And all was good . < / p > """
self . common_bugdown_test ( fenced_code , expected_convert )
def test_hanging_multi_codeblock ( self ) :
fenced_code = \
""" Hamlet said:
~ ~ ~ ~
def speak ( self ) :
x = 1
~ ~ ~ ~
Then he mentioned ` ` ` ` y = 4 + x * * 2 ` ` ` ` and
~ ~ ~ ~
def foobar ( self ) :
return self . baz ( ) """
expected_convert = \
""" <p>Hamlet said:</p>
< div class = " codehilite " > < pre > def speak ( self ) :
x = 1
< / pre > < / div >
< p > Then he mentioned < code > y = 4 + x * * 2 < / code > and < / p >
< div class = " codehilite " > < pre > def foobar ( self ) :
return self . baz ( )
< / pre > < / div > """
self . common_bugdown_test ( fenced_code , expected_convert )
def test_dangerous_block ( self ) :
fenced_code = u ' xxxxxx xxxxx xxxxxxxx xxxx. x xxxx xxxxxxxxxx: \n \n ``` \
" xxxx xxxx \\ xxxxx \\ xxxxxx " ` ` ` \n \nxxx xxxx xxxxx : ` ` ` xx . xxxxxxx ( x \' ^xxxx$ \' \
, xx . xxxxxxxxx ) ` ` ` \n \nxxxxxxx \' x xxxx xxxxxxxxxx ``` \' xxxx \' ```, xxxxx \
xxxxxxxxx xxxxx ^ xxx $ xxxxxx xxxxx xxxxxxxxxxxx xxx xxxx xx x xxxx xx xxxx xx xxx xxxxx xxxxxx ? '
expected = """ <p>xxxxxx xxxxx xxxxxxxx xxxx. x xxxx xxxxxxxxxx:</p> \n \
< p > < code > " xxxx xxxx \\ xxxxx \\ xxxxxx " < / code > < / p > \n < p > xxx xxxx xxxxx : < code > xx . xxxxxxx \
( x \' ^xxxx$ \' , xx.xxxxxxxxx)</code></p> \n <p>xxxxxxx \' x xxxx xxxxxxxxxx <code> \' xxxx \' \
< / code > , xxxxx xxxxxxxxx xxxxx ^ xxx $ xxxxxx xxxxx xxxxxxxxxxxx xxx xxxx xx x \
xxxx xx xxxx xx xxx xxxxx xxxxxx ? < / p > """
self . common_bugdown_test ( fenced_code , expected )
fenced_code = """ ``` one ```
` ` ` two ` ` `
~ ~ ~ ~
x = 1 """
expected_convert = ' <p><code>one</code></p> \n <p><code>two</code></p> \n <div class= " codehilite " ><pre>x = 1 \n </pre></div> '
self . common_bugdown_test ( fenced_code , expected_convert )
2013-01-24 19:35:28 +01:00
def test_ulist_standard ( self ) :
ulisted = """ Some text with a list:
* One item
* Two items
* Three items """
expected = """ <p>Some text with a list:</p>
< ul >
< li > One item < / li >
< li > Two items < / li >
< li > Three items < / li >
< / ul > """
self . common_bugdown_test ( ulisted , expected )
def test_ulist_hanging ( self ) :
ulisted = """ Some text with a hanging list:
* One item
* Two items
* Three items """
expected = """ <p>Some text with a hanging list:</p>
< ul >
< li > One item < / li >
< li > Two items < / li >
< li > Three items < / li >
< / ul > """
self . common_bugdown_test ( ulisted , expected )
def test_ulist_hanging_mixed ( self ) :
ulisted = """ Plain list
* Alpha
* Beta
Then hang it off :
* Ypsilon
* Zeta """
expected = """ <p>Plain list</p>
< ul >
< li >
< p > Alpha < / p >
< / li >
< li >
< p > Beta < / p >
< / li >
< / ul >
< p > Then hang it off : < / p >
< ul >
< li > Ypsilon < / li >
< li > Zeta < / li >
< / ul > """
self . common_bugdown_test ( ulisted , expected )
def test_hanging_multi ( self ) :
ulisted = """ Plain list
* Alpha
* Beta
And Again :
* A
* B
* C
Once more for feeling :
* Q
* E
* D """
expected = ' <p>Plain list</p> \n <ul> \n <li>Alpha</li> \n <li>Beta \
< / li > \n < / ul > \n < p > And Again : < / p > \n < ul > \n < li > A < / li > \n < li > B < / li > \n < li > C \
< / li > \n < / ul > \n < p > Once more for feeling : < / p > \n < ul > \n < li > Q < / li > \n < li > E \
< / li > \n < li > D < / li > \n < / ul > '
self . common_bugdown_test ( ulisted , expected )
def test_ulist_codeblock ( self ) :
ulisted_code = """ ~~~
int x = 3
* 4 ;
~ ~ ~ """
expected = ' <div class= " codehilite " ><pre>int x = 3 \n * 4; \n </pre></div> '
self . common_bugdown_test ( ulisted_code , expected )
2013-01-29 16:15:25 +01:00
def test_malformed_fence ( self ) :
bad = " ~~~~~~~~xxxxxxxxx: xxxxxxxxxxxx xxxxx x xxxxxxxx~~~~~~ "
good = " <p>~~~~~~~~xxxxxxxxx: xxxxxxxxxxxx xxxxx x xxxxxxxx~~~~~~</p> "
self . common_bugdown_test ( bad , good )
2013-01-31 21:17:43 +01:00
def test_italic_bold ( self ) :
''' Italics (*foo*, _foo_) and bold syntax __foo__ are disabled.
Bold * * foo * * still works . '''
self . common_bugdown_test ( ' _foo_ ' , ' <p>_foo_</p> ' )
self . common_bugdown_test ( ' *foo* ' , ' <p>*foo*</p> ' )
self . common_bugdown_test ( ' __foo__ ' , ' <p>__foo__</p> ' )
self . common_bugdown_test ( ' **foo** ' , ' <p><strong>foo</strong></p> ' )
2013-06-20 20:46:28 +02:00
@slow ( 1.1 , ' lots of examples ' )
2013-02-01 20:05:14 +01:00
def test_linkify ( self ) :
2013-02-01 23:15:22 +01:00
def replaced ( payload , url , phrase = ' ' ) :
2013-07-08 16:46:52 +02:00
target = " target= \" _blank \" "
2013-02-26 22:41:39 +01:00
if url [ : 4 ] == ' http ' :
2013-02-01 23:15:22 +01:00
href = url
elif ' @ ' in url :
href = ' mailto: ' + url
2013-07-08 16:46:52 +02:00
target = " "
2013-02-01 23:15:22 +01:00
else :
href = ' http:// ' + url
2013-07-08 16:46:52 +02:00
return payload % ( " <a href= \" %s \" %s title= \" %s \" > %s </a> " % ( href , target , href , url ) , )
2013-02-01 20:05:14 +01:00
conversions = \
2013-02-01 23:15:22 +01:00
[
# General linkification tests
( ' http://www.google.com ' , " <p> %s </p> " , ' http://www.google.com ' ) ,
2013-02-01 20:05:14 +01:00
( ' https://www.google.com ' , " <p> %s </p> " , ' https://www.google.com ' ) ,
2013-02-05 19:04:45 +01:00
( ' http://www.theregister.co.uk/foo/bar ' , " <p> %s </p> " , ' http://www.theregister.co.uk/foo/bar ' ) ,
2013-02-01 20:05:14 +01:00
( ' some text https://www.google.com/ ' , " <p>some text %s </p> " , ' https://www.google.com/ ' ) ,
( ' with short example.com url ' , " <p>with short %s url</p> " , ' example.com ' ) ,
( ' t.co ' , " <p> %s </p> " , ' t.co ' ) ,
( ' go to views.org please ' , " <p>go to %s please</p> " , ' views.org ' ) ,
( ' http://foo.com/blah_blah/ ' , " <p> %s </p> " , ' http://foo.com/blah_blah/ ' ) ,
( ' python class views.py is ' , " <p>python class views.py is</p> " , ' ' ) ,
2013-07-24 20:56:42 +02:00
( ' with www www.zulip.com/foo ok? ' , " <p>with www %s ok?</p> " , ' www.zulip.com/foo ' ) ,
2013-02-01 20:05:14 +01:00
( ' allow questions like foo.com? ' , " <p>allow questions like %s ?</p> " , ' foo.com ' ) ,
( ' " is.gd/foo/ " ' , " <p> \" %s \" </p> " , ' is.gd/foo/ ' ) ,
( ' end of sentence https://t.co. ' , " <p>end of sentence %s .</p> " , ' https://t.co ' ) ,
( ' (Something like http://foo.com/blah_blah) ' , " <p>(Something like %s )</p> " , ' http://foo.com/blah_blah ' ) ,
( ' " is.gd/foo/ " ' , " <p> \" %s \" </p> " , ' is.gd/foo/ ' ) ,
( ' end with a quote www.google.com " ' , " <p>end with a quote %s \" </p> " , ' www.google.com ' ) ,
2013-02-06 15:33:24 +01:00
( ' http://www.guardian.co.uk/foo/bar ' , " <p> %s </p> " , ' http://www.guardian.co.uk/foo/bar ' ) ,
( ' from http://supervisord.org/running.html: ' , " <p>from %s :</p> " , ' http://supervisord.org/running.html ' ) ,
( ' http://raven.io ' , " <p> %s </p> " , ' http://raven.io ' ) ,
2013-07-24 20:56:42 +02:00
( ' at https://zulip.com/api. Check it! ' , " <p>at %s . Check it!</p> " , ' https://zulip.com/api ' ) ,
2013-02-11 20:54:55 +01:00
( ' goo.gl/abc ' , " <p> %s </p> " , ' goo.gl/abc ' ) ,
2013-04-02 17:08:00 +02:00
( ' I spent a year at ucl.ac.uk ' , " <p>I spent a year at %s </p> " , ' ucl.ac.uk ' ) ,
2013-04-29 22:22:07 +02:00
( ' http://a.cc/i/FMXO ' , " <p> %s </p> " , ' http://a.cc/i/FMXO ' ) ,
2013-02-11 20:54:55 +01:00
( ' http://fmota.eu/blog/test.html ' , " <p> %s </p> " , ' http://fmota.eu/blog/test.html ' ) ,
( ' http://j.mp/14Hwm3X ' , " <p> %s </p> " , ' http://j.mp/14Hwm3X ' ) ,
( ' http://localhost:9991/?show_debug=1 ' , " <p> %s </p> " , ' http://localhost:9991/?show_debug=1 ' ) ,
2013-04-29 22:22:07 +02:00
( ' anyone before? (http://a.cc/i/FMXO) ' , " <p>anyone before? ( %s )</p> " , ' http://a.cc/i/FMXO ' ) ,
2013-03-29 19:45:22 +01:00
( ' (http://en.wikipedia.org/wiki/Each-way_(bet)) ' ,
' <p>( %s )</p> ' , ' http://en.wikipedia.org/wiki/Each-way_(bet) ' ) ,
( ' (http://en.wikipedia.org/wiki/Each-way_(bet)_(more_parens)) ' ,
' <p>( %s )</p> ' , ' http://en.wikipedia.org/wiki/Each-way_(bet)_(more_parens) ' ) ,
( ' http://en.wikipedia.org/wiki/Qt_(framework) ' , ' <p> %s </p> ' , ' http://en.wikipedia.org/wiki/Qt_(framework) ' ) ,
2013-04-02 19:36:37 +02:00
( ' http://fr.wikipedia.org/wiki/Fichier:SMirC-facepalm.svg ' ,
' <p> %s </p> ' , ' http://fr.wikipedia.org/wiki/Fichier:SMirC-facepalm.svg ' ) ,
# Changed to .mov from .png to avoid inline preview
( ' https://en.wikipedia.org/wiki/File:Methamphetamine_from_ephedrine_with_HI_en.mov ' , ' <p> %s </p> ' ,
' https://en.wikipedia.org/wiki/File:Methamphetamine_from_ephedrine_with_HI_en.mov ' ) ,
( ' https://jira.atlassian.com/browse/JRA-31953?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel ' ,
' <p> %s </p> ' , ' https://jira.atlassian.com/browse/JRA-31953?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel ' ) ,
( ' http://web.archive.org/web/20120630032016/http://web.mit.edu/mitcard/idpolicies.html ' , ' <p> %s </p> ' ,
' http://web.archive.org/web/20120630032016/http://web.mit.edu/mitcard/idpolicies.html ' ) ,
2013-08-06 21:32:15 +02:00
( ' https://www.dropbox.com/sh/7d0ved3h5kf7dj8/_aD5_ceDFY?lst#f:Zulip-062-subscriptions-page-3rd-ver.fw.png ' ,
' <p> %s </p> ' , ' https://www.dropbox.com/sh/7d0ved3h5kf7dj8/_aD5_ceDFY?lst#f:Zulip-062-subscriptions-page-3rd-ver.fw.png ' ) ,
2013-03-29 20:17:33 +01:00
( ' http://www.postgresql.org/message-id/14040.1364490185@sss.pgh.pa.us ' , ' <p> %s </p> ' ,
' http://www.postgresql.org/message-id/14040.1364490185@sss.pgh.pa.us ' ) ,
2013-02-01 20:05:14 +01:00
2013-02-26 22:41:39 +01:00
# XSS sanitization; URL is rendered as plain text
( ' javascript:alert( \' hi \' );.com ' , " <p>javascript:alert( ' hi ' );.com</p> " , ' ' ) ,
2013-07-05 19:23:14 +02:00
( ' javascript:foo.com ' , " <p>javascript: %s </p> " , ' foo.com ' ) ,
2013-04-02 19:57:35 +02:00
( ' javascript://foo.com ' , " <p>javascript://foo.com</p> " , ' ' ) ,
( ' foobarscript://foo.com ' , " <p>foobarscript://foo.com</p> " , ' ' ) ,
2013-07-05 19:23:14 +02:00
( ' about:blank.com ' , " <p>about: %s </p> " , ' blank.com ' ) ,
2013-02-26 22:41:39 +01:00
( ' [foo](javascript:foo.com) ' , " <p>[foo](javascript:foo.com)</p> " , ' ' ) ,
2013-04-02 19:57:35 +02:00
( ' [foo](javascript://foo.com) ' , " <p>[foo](javascript://foo.com)</p> " , ' ' ) ,
2013-02-26 22:41:39 +01:00
2013-04-02 19:57:35 +02:00
# Other weird URL schemes are also blocked
( ' aim:addbuddy?screenname=foo ' , " <p>aim:addbuddy?screenname=foo</p> " , ' ' ) ,
( ' itms://itunes.com/apps/appname ' , " <p>itms://itunes.com/apps/appname</p> " , ' ' ) ,
( ' [foo](itms://itunes.com/apps/appname) ' , " <p>[foo](itms://itunes.com/apps/appname)</p> " , ' ' ) ,
2013-02-26 22:41:39 +01:00
# Make sure we HTML-escape the invalid URL on output.
# ' and " aren't escaped here, because we aren't in attribute context.
( ' javascript:<i> " foo&bar " </i> ' ,
' <p>javascript:<i> " foo&bar " </i></p> ' , ' ' ) ,
( ' [foo](javascript:<i> " foo&bar " </i>) ' ,
' <p>[foo](javascript:<i> " foo&bar " </i>)</p> ' , ' ' ) ,
2013-02-01 23:15:22 +01:00
# Emails
2013-07-08 16:46:52 +02:00
( ' a@b.com ' , " <p> %s </p> " , ' a@b.com ' ) ,
( ' <a@b.com> ' , " <p>< %s ></p> " , ' a@b.com ' ) ,
( ' a@b.com/foo ' , " <p>a@b.com/foo</p> " , ' ' ) ,
2013-03-29 20:17:33 +01:00
( ' http://leo@foo.com/my/file ' , " <p> %s </p> " , ' http://leo@foo.com/my/file ' ) ,
2013-02-01 23:15:22 +01:00
2013-02-01 20:05:14 +01:00
( ' http://example.com/something?with,commas,in,url, but not at end ' ,
2013-02-06 15:33:24 +01:00
" <p> %s , but not at end</p> " , ' http://example.com/something?with,commas,in,url ' ) ,
2013-02-11 20:54:55 +01:00
( ' http://www.yelp.com/biz/taim-mobile-falafel-and-smoothie-truck-new-york#query ' ,
" <p> %s </p> " , ' http://www.yelp.com/biz/taim-mobile-falafel-and-smoothie-truck-new-york#query ' ) ,
2013-02-01 20:05:14 +01:00
( ' some text https://www.google.com/baz_(match)?with=foo&bar=baz with extras ' ,
" <p>some text %s with extras</p> " , ' https://www.google.com/baz_(match)?with=foo&bar=baz ' ) ,
( ' hash it http://foo.com/blah_(wikipedia)_blah#cite-1 ' ,
2013-02-06 15:33:24 +01:00
" <p>hash it %s </p> " , ' http://foo.com/blah_(wikipedia)_blah#cite-1 ' ) ,
2013-04-02 19:36:37 +02:00
2013-03-01 19:20:53 +01:00
# This last one was originally a .gif but was changed to .mov
# to avoid triggering the inline image preview support
( ' http://technet.microsoft.com/en-us/library/Cc751099.rk20_25_big(l=en-us).mov ' ,
2013-02-06 15:33:24 +01:00
" <p> %s </p> " ,
2013-06-14 22:53:49 +02:00
' http://technet.microsoft.com/en-us/library/Cc751099.rk20_25_big(l=en-us).mov ' ) ,
# Just because it has a TLD and parentheses in it doesn't mean it's a link. Trac #1364
( ' a.commandstuff() ' , ' <p>a.commandstuff()</p> ' , ' ' ) ,
2013-06-21 00:06:52 +02:00
( ' love...it ' , ' <p>love...it</p> ' , ' ' ) ,
2013-07-05 19:23:14 +02:00
( ' sorry,http://example.com/ ' , ' <p>sorry, %s </p> ' , ' http://example.com/ ' ) ,
2013-06-14 22:53:49 +02:00
]
2013-02-01 20:05:14 +01:00
for inline_url , reference , url in conversions :
try :
2013-02-01 23:15:22 +01:00
match = replaced ( reference , url , phrase = inline_url )
2013-02-01 20:05:14 +01:00
except TypeError :
match = reference
2013-06-05 19:23:19 +02:00
converted = bugdown_convert ( inline_url )
2013-02-01 20:05:14 +01:00
self . assertEqual ( match , converted )
2013-06-20 21:32:11 +02:00
@slow ( 0.545 , ' BugDown is slow, several items to test ' )
2013-04-02 19:36:37 +02:00
def test_manual_links ( self ) :
# These are links that the default markdown XSS fails due to to : in the path
2013-05-22 21:31:52 +02:00
urls = ( ( ' [Haskell NYC Meetup](http://www.meetsup.com/r/email/www/0/co1.1_grp/http://www.meetup.com/NY-Haskell/events/108707682/ \
? a = co1 .1 _grp & rv = co1 .1 ) ' , " <p><a href= \" http://www.meetsup.com/r/email/www/0/co1.1_grp/http://www.meetup.com/NY-Haskell/events/ \
108707682 / ? a = co1 .1 _grp & amp ; rv = co1 .1 \" target= \" _blank \" title= \" http://www.meetsup.com/r/email/www/0/co1.1_grp/http://www.meetup.com/ \
2013-04-02 19:36:37 +02:00
NY - Haskell / events / 108707682 / ? a = co1 .1 _grp & amp ; rv = co1 .1 \" >Haskell NYC Meetup</a></p> " ) ,
( ' [link](http://htmlpreview.github.com/?https://github.com/becdot/jsset/index.html) ' ,
' <p><a href= " http://htmlpreview.github.com/?https://github.com/becdot/jsset/index.html " target= " _blank " title= \
" http://htmlpreview.github.com/?https://github.com/becdot/jsset/index.html " > link < / a > < / p > ' ),
2013-03-29 19:45:22 +01:00
( ' [YOLO](http://en.wikipedia.org/wiki/YOLO_(motto)) ' ,
' <p><a href= " http://en.wikipedia.org/wiki/YOLO_(motto) " target= " _blank " title= " http://en.wikipedia.org/wiki/YOLO_(motto) " \
2013-03-29 20:17:33 +01:00
> YOLO < / a > < / p > ' ),
2013-07-24 20:56:42 +02:00
( ' Sent to http_something_real@zulip.com ' , ' <p>Sent to <a href= " mailto:http_something_real@zulip.com " \
title = " mailto:http_something_real@zulip.com " > http_something_real @zulip.com < / a > < / p > ' ),
2013-07-24 20:41:09 +02:00
( ' Sent to othello@zulip.com ' , ' <p>Sent to <a href= " mailto:othello@zulip.com " title= " mailto:othello@zulip.com " > \
othello @zulip.com < / a > < / p > ' )
2013-04-02 19:36:37 +02:00
)
for input , output in urls :
2013-06-05 19:23:19 +02:00
converted = bugdown_convert ( input )
2013-04-02 19:36:37 +02:00
self . assertEqual ( output , converted )
2013-02-11 20:54:55 +01:00
def test_linkify_interference ( self ) :
# Check our auto links don't interfere with normal markdown linkification
2013-04-02 19:57:35 +02:00
msg = ' link: xx, x xxxxx xx xxxx xx \n \n [xxxxx #xx](http://xxxxxxxxx:xxxx/xxx/xxxxxx %x xxxxx/xx/): \
2013-02-11 20:54:55 +01:00
* * xxxxxxx * * \n \nxxxxxxx xxxxx xxxx xxxxx : \n ` xxxxxx ` : xxxxxxx \n ` xxxxxx ` : xxxxx \n ` xxxxxx ` : xxxxx xxxxx '
2013-06-05 19:23:19 +02:00
converted = bugdown_convert ( msg )
2013-02-11 20:54:55 +01:00
2013-04-02 19:57:35 +02:00
self . assertEqual ( converted , ' <p>link: xx, x xxxxx xx xxxx xx</p> \n <p><a href= " http://xxxxxxxxx:xxxx/ \
xxx / xxxxxx % xxxxxx / xx / " target= " _blank " title= " http : / / xxxxxxxxx : xxxx / xxx / xxxxxx % xxxxxx / xx / " >xxxxx #xx</a>:<strong> \
2013-02-11 20:54:55 +01:00
xxxxxxx < / strong > < / p > \n < p > xxxxxxx xxxxx xxxx xxxxx : < br > \n < code > xxxxxx < / code > : xxxxxxx < br > \n < code > xxxxxx < / code > : xxxxx \
< br > \n < code > xxxxxx < / code > : xxxxx xxxxx < / p > ' )
2013-03-01 19:20:53 +01:00
def test_inline_image ( self ) :
msg = ' Google logo today: https://www.google.com/images/srpr/logo4w.png \n Kinda boring '
2013-06-05 19:23:19 +02:00
converted = bugdown_convert ( msg )
2013-03-01 19:20:53 +01:00
2013-04-26 22:06:18 +02:00
self . assertEqual ( converted , ' <p>Google logo today: <a href= " https://www.google.com/images/srpr/logo4w.png " target= " _blank " title= " https://www.google.com/images/srpr/logo4w.png " >https://www.google.com/images/srpr/logo4w.png</a><br> \n Kinda boring</p> \n <div class= " message_inline_image " ><a href= " https://www.google.com/images/srpr/logo4w.png " target= " _blank " title= " https://www.google.com/images/srpr/logo4w.png " ><img src= " https://www.google.com/images/srpr/logo4w.png " ></a></div> ' )
2013-03-01 19:20:53 +01:00
2013-08-28 22:45:26 +02:00
# If there are two images, both should be previewed.
2013-03-08 21:44:06 +01:00
msg = ' Google logo today: https://www.google.com/images/srpr/logo4w.png \n Kinda boringGoogle logo today: https://www.google.com/images/srpr/logo4w.png \n Kinda boring '
2013-06-05 19:23:19 +02:00
converted = bugdown_convert ( msg )
2013-03-08 21:44:06 +01:00
2013-04-26 22:06:18 +02:00
self . assertEqual ( converted , ' <p>Google logo today: <a href= " https://www.google.com/images/srpr/logo4w.png " target= " _blank " title= " https://www.google.com/images/srpr/logo4w.png " >https://www.google.com/images/srpr/logo4w.png</a><br> \n Kinda boringGoogle logo today: <a href= " https://www.google.com/images/srpr/logo4w.png " target= " _blank " title= " https://www.google.com/images/srpr/logo4w.png " >https://www.google.com/images/srpr/logo4w.png</a><br> \n Kinda boring</p> \n <div class= " message_inline_image " ><a href= " https://www.google.com/images/srpr/logo4w.png " target= " _blank " title= " https://www.google.com/images/srpr/logo4w.png " ><img src= " https://www.google.com/images/srpr/logo4w.png " ></a></div><div class= " message_inline_image " ><a href= " https://www.google.com/images/srpr/logo4w.png " target= " _blank " title= " https://www.google.com/images/srpr/logo4w.png " ><img src= " https://www.google.com/images/srpr/logo4w.png " ></a></div> ' )
2013-03-08 21:44:06 +01:00
2013-08-28 22:45:26 +02:00
# http images should be converted to https via our Camo integration
msg = ' Google logo today: http://www.google.com/images/srpr/logo4w.png '
converted = bugdown_convert ( msg )
self . assertEqual ( converted , ' <p>Google logo today: <a href= " http://www.google.com/images/srpr/logo4w.png " target= " _blank " title= " http://www.google.com/images/srpr/logo4w.png " >http://www.google.com/images/srpr/logo4w.png</a></p> \n <div class= " message_inline_image " ><a href= " http://www.google.com/images/srpr/logo4w.png " target= " _blank " title= " http://www.google.com/images/srpr/logo4w.png " ><img src= " https://external-content.zulipcdn.net/4882a845c6edd9a945bfe5f33734ce0aed8170f3/687474703a2f2f7777772e676f6f676c652e636f6d2f696d616765732f737270722f6c6f676f34772e706e67 " ></a></div> ' )
2013-03-08 21:44:06 +01:00
2013-09-04 22:32:22 +02:00
# in mit.edu, https images should be converted to https via our Camo integration
message = Message ( sender = get_user_profile_by_email ( " starnine@mit.edu " ) )
msg = ' Google logo today: https://www.google.com/images/srpr/logo4w.png '
converted = bugdown . convert ( msg , " mit.com " , message = message )
self . assertEqual ( converted , ' <p>Google logo today: <a href= " https://www.google.com/images/srpr/logo4w.png " target= " _blank " title= " https://www.google.com/images/srpr/logo4w.png " >https://www.google.com/images/srpr/logo4w.png</a></p> \n <div class= " message_inline_image " ><a href= " https://www.google.com/images/srpr/logo4w.png " target= " _blank " title= " https://www.google.com/images/srpr/logo4w.png " ><img src= " https://external-content.zulipcdn.net/cadb491a68c9272ffd7e571703d7f8c51542acc8/68747470733a2f2f7777772e676f6f676c652e636f6d2f696d616765732f737270722f6c6f676f34772e706e67 " ></a></div> ' )
2013-03-01 19:20:53 +01:00
def test_inline_youtube ( self ) :
msg = ' Check out the debate: http://www.youtube.com/watch?v=hx1mjT73xYE '
2013-06-05 19:23:19 +02:00
converted = bugdown_convert ( msg )
2013-03-01 19:20:53 +01:00
2013-06-21 16:52:46 +02:00
if settings . USING_EMBEDLY :
self . assertEqual ( converted , ' <p>Check out the debate: <a href= " http://www.youtube.com/watch?v=hx1mjT73xYE " target= " _blank " title= " http://www.youtube.com/watch?v=hx1mjT73xYE " >http://www.youtube.com/watch?v=hx1mjT73xYE</a></p> \n <iframe width= " 250 " height= " 141 " src= " http://www.youtube.com/embed/hx1mjT73xYE?feature=oembed " frameborder= " 0 " allowfullscreen></iframe> ' )
else :
2013-09-04 21:12:33 +02:00
self . assertEqual ( converted , ' <p>Check out the debate: <a href= " http://www.youtube.com/watch?v=hx1mjT73xYE " target= " _blank " title= " http://www.youtube.com/watch?v=hx1mjT73xYE " >http://www.youtube.com/watch?v=hx1mjT73xYE</a></p> \n <div class= " message_inline_image " ><a href= " http://www.youtube.com/watch?v=hx1mjT73xYE " target= " _blank " title= " http://www.youtube.com/watch?v=hx1mjT73xYE " ><img src= " https://i.ytimg.com/vi/hx1mjT73xYE/default.jpg " ></a></div> ' )
2013-03-01 19:20:53 +01:00
2013-03-04 16:38:42 +01:00
def test_inline_dropbox ( self ) :
msg = ' Look at how hilarious our old office was: https://www.dropbox.com/s/ymdijjcg67hv2ta/IMG_0923.JPG '
2013-06-05 19:23:19 +02:00
converted = bugdown_convert ( msg )
2013-03-04 16:38:42 +01:00
2013-04-26 22:06:18 +02:00
self . assertEqual ( converted , ' <p>Look at how hilarious our old office was: <a href= " https://www.dropbox.com/s/ymdijjcg67hv2ta/IMG_0923.JPG " target= " _blank " title= " https://www.dropbox.com/s/ymdijjcg67hv2ta/IMG_0923.JPG " >https://www.dropbox.com/s/ymdijjcg67hv2ta/IMG_0923.JPG</a></p> \n <div class= " message_inline_image " ><a href= " https://www.dropbox.com/s/ymdijjcg67hv2ta/IMG_0923.JPG " target= " _blank " title= " https://www.dropbox.com/s/ymdijjcg67hv2ta/IMG_0923.JPG " ><img src= " https://www.dropbox.com/s/ymdijjcg67hv2ta/IMG_0923.JPG?dl=1 " ></a></div> ' )
2013-03-04 16:38:42 +01:00
2013-03-12 22:30:40 +01:00
msg = ' Look at my hilarious drawing: https://www.dropbox.com/sh/inlugx9d25r314h/JYwv59v4Jv/credit_card_rushmore.jpg '
2013-06-05 19:23:19 +02:00
converted = bugdown_convert ( msg )
2013-03-12 22:30:40 +01:00
2013-04-26 22:06:18 +02:00
self . assertEqual ( converted , ' <p>Look at my hilarious drawing: <a href= " https://www.dropbox.com/sh/inlugx9d25r314h/JYwv59v4Jv/credit_card_rushmore.jpg " target= " _blank " title= " https://www.dropbox.com/sh/inlugx9d25r314h/JYwv59v4Jv/credit_card_rushmore.jpg " >https://www.dropbox.com/sh/inlugx9d25r314h/JYwv59v4Jv/credit_card_rushmore.jpg</a></p> \n <div class= " message_inline_image " ><a href= " https://www.dropbox.com/sh/inlugx9d25r314h/JYwv59v4Jv/credit_card_rushmore.jpg " target= " _blank " title= " https://www.dropbox.com/sh/inlugx9d25r314h/JYwv59v4Jv/credit_card_rushmore.jpg " ><img src= " https://www.dropbox.com/sh/inlugx9d25r314h/JYwv59v4Jv/credit_card_rushmore.jpg?dl=1 " ></a></div> ' )
2013-03-12 22:30:40 +01:00
2013-03-04 16:38:42 +01:00
# Make sure we're not overzealous in our conversion:
msg = ' Look at the new dropbox logo: https://www.dropbox.com/static/images/home_logo.png '
2013-06-05 19:23:19 +02:00
converted = bugdown_convert ( msg )
2013-03-04 16:38:42 +01:00
2013-04-26 22:06:18 +02:00
self . assertEqual ( converted , ' <p>Look at the new dropbox logo: <a href= " https://www.dropbox.com/static/images/home_logo.png " target= " _blank " title= " https://www.dropbox.com/static/images/home_logo.png " >https://www.dropbox.com/static/images/home_logo.png</a></p> \n <div class= " message_inline_image " ><a href= " https://www.dropbox.com/static/images/home_logo.png " target= " _blank " title= " https://www.dropbox.com/static/images/home_logo.png " ><img src= " https://www.dropbox.com/static/images/home_logo.png " ></a></div> ' )
2013-03-04 16:38:42 +01:00
2013-03-08 06:27:16 +01:00
def test_inline_interesting_links ( self ) :
def make_link ( url ) :
return ' <a href= " %s " target= " _blank " title= " %s " > %s </a> ' % ( url , url , url )
def make_inline_twitter_preview ( url ) :
## As of right now, all previews are mocked to be the exact same tweet
return """ <div class= " inline-preview-twitter " ><div class= " twitter-tweet " ><a href= " %s " target= " _blank " ><img class= " twitter-avatar " src= " https://si0.twimg.com/profile_images/1380912173/Screen_shot_2011-06-03_at_7.35.36_PM_normal.png " ></a><p>@twitter meets @seepicturely at #tcdisrupt cc.@boscomonkey @episod http://t.co/6J2EgYM</p><span>- Eoin McMillan (@imeoin)</span></div></div> """ % ( url , )
msg = ' http://www.twitter.com '
2013-06-05 19:23:19 +02:00
converted = bugdown_convert ( msg )
2013-03-08 06:27:16 +01:00
self . assertEqual ( converted , ' <p> %s </p> ' % make_link ( ' http://www.twitter.com ' ) )
msg = ' http://www.twitter.com/wdaher/ '
2013-06-05 19:23:19 +02:00
converted = bugdown_convert ( msg )
2013-03-08 06:27:16 +01:00
self . assertEqual ( converted , ' <p> %s </p> ' % make_link ( ' http://www.twitter.com/wdaher/ ' ) )
msg = ' http://www.twitter.com/wdaher/status/3 '
2013-06-05 19:23:19 +02:00
converted = bugdown_convert ( msg )
2013-03-08 06:27:16 +01:00
self . assertEqual ( converted , ' <p> %s </p> ' % make_link ( ' http://www.twitter.com/wdaher/status/3 ' ) )
# id too long
msg = ' http://www.twitter.com/wdaher/status/2879779692873154569 '
2013-06-05 19:23:19 +02:00
converted = bugdown_convert ( msg )
2013-03-08 06:27:16 +01:00
self . assertEqual ( converted , ' <p> %s </p> ' % make_link ( ' http://www.twitter.com/wdaher/status/2879779692873154569 ' ) )
2013-05-29 21:38:16 +02:00
# id too large (i.e. tweet doesn't exist)
msg = ' http://www.twitter.com/wdaher/status/999999999999999999 '
2013-06-05 19:23:19 +02:00
converted = bugdown_convert ( msg )
2013-05-29 21:38:16 +02:00
self . assertEqual ( converted , ' <p> %s </p> ' % make_link ( ' http://www.twitter.com/wdaher/status/999999999999999999 ' ) )
2013-03-08 06:27:16 +01:00
msg = ' http://www.twitter.com/wdaher/status/287977969287315456 '
2013-06-05 19:23:19 +02:00
converted = bugdown_convert ( msg )
2013-03-08 06:27:16 +01:00
self . assertEqual ( converted , ' <p> %s </p> \n %s ' % ( make_link ( ' http://www.twitter.com/wdaher/status/287977969287315456 ' ) ,
make_inline_twitter_preview ( ' http://www.twitter.com/wdaher/status/287977969287315456 ' ) ) )
msg = ' https://www.twitter.com/wdaher/status/287977969287315456 '
2013-06-05 19:23:19 +02:00
converted = bugdown_convert ( msg )
2013-03-08 06:27:16 +01:00
self . assertEqual ( converted , ' <p> %s </p> \n %s ' % ( make_link ( ' https://www.twitter.com/wdaher/status/287977969287315456 ' ) ,
make_inline_twitter_preview ( ' https://www.twitter.com/wdaher/status/287977969287315456 ' ) ) )
msg = ' http://twitter.com/wdaher/status/287977969287315456 '
2013-06-05 19:23:19 +02:00
converted = bugdown_convert ( msg )
2013-03-08 06:27:16 +01:00
self . assertEqual ( converted , ' <p> %s </p> \n %s ' % ( make_link ( ' http://twitter.com/wdaher/status/287977969287315456 ' ) ,
make_inline_twitter_preview ( ' http://twitter.com/wdaher/status/287977969287315456 ' ) ) )
2013-03-01 22:07:27 +01:00
2013-03-08 21:44:06 +01:00
# Only one should get converted
msg = ' http://twitter.com/wdaher/status/287977969287315456 http://twitter.com/wdaher/status/287977969287315457 '
2013-06-05 19:23:19 +02:00
converted = bugdown_convert ( msg )
2013-03-08 21:44:06 +01:00
self . assertEqual ( converted , ' <p> %s %s </p> \n %s ' % ( make_link ( ' http://twitter.com/wdaher/status/287977969287315456 ' ) ,
make_link ( ' http://twitter.com/wdaher/status/287977969287315457 ' ) ,
make_inline_twitter_preview ( ' http://twitter.com/wdaher/status/287977969287315456 ' ) ) )
2013-03-01 22:07:27 +01:00
def test_emoji ( self ) :
def emoji_img ( name , filename = None ) :
if filename == None :
filename = name [ 1 : - 1 ]
return ' <img alt= " %s " class= " emoji " src= " static/third/gemoji/images/emoji/ %s .png " title= " %s " > ' % ( name , filename , name )
# Spot-check a few emoji
test_cases = [ ( ' :poop: ' , emoji_img ( ' :poop: ' ) ) ,
( ' :hankey: ' , emoji_img ( ' :hankey: ' ) ) ,
( ' :whale: ' , emoji_img ( ' :whale: ' ) ) ,
( ' :fakeemoji: ' , ' :fakeemoji: ' ) ,
( ' :even faker smile: ' , ' :even faker smile: ' ) ,
2013-03-05 21:53:35 +01:00
]
2013-03-01 22:07:27 +01:00
2013-06-20 16:24:40 +02:00
# Check a random sample of our 800+ emojis to make
# sure that bugdown builds the correct image tag.
emojis = bugdown . emoji_list
emojis = random . sample ( emojis , 15 )
for img in emojis :
2013-06-27 20:07:55 +02:00
emoji_text = " : %s : " % ( img , )
2013-03-01 22:07:27 +01:00
test_cases . append ( ( emoji_text , emoji_img ( emoji_text ) ) )
for input , expected in test_cases :
2013-06-05 19:23:19 +02:00
self . assertEqual ( bugdown_convert ( input ) , ' <p> %s </p> ' % expected )
2013-03-01 22:07:27 +01:00
# Comprehensive test of a bunch of things together
msg = ' test :smile: again :poop: \n :) foo:)bar x::y::z :wasted waste: :fakeemojithisshouldnotrender: '
2013-06-05 19:23:19 +02:00
converted = bugdown_convert ( msg )
2013-03-01 22:07:27 +01:00
self . assertEqual ( converted , ' <p>test ' + emoji_img ( ' :smile: ' ) + ' again ' + emoji_img ( ' :poop: ' ) + ' <br> \n '
2013-03-05 21:53:35 +01:00
+ ' :) foo:)bar x::y::z :wasted waste: :fakeemojithisshouldnotrender:</p> ' )
2013-03-01 22:07:27 +01:00
2013-08-06 22:23:55 +02:00
msg = ' :smile:, :smile:; :smile: '
converted = bugdown_convert ( msg )
self . assertEqual ( converted ,
' <p> ' +
emoji_img ( ' :smile: ' ) +
' , ' +
emoji_img ( ' :smile: ' ) +
' ; ' +
emoji_img ( ' :smile: ' ) +
' </p> ' )
2013-03-01 22:07:27 +01:00
2013-08-22 23:55:37 +02:00
def test_realm_emoji ( self ) :
def emoji_img ( name , url ) :
return ' <img alt= " %s " class= " emoji " src= " %s " title= " %s " > ' % ( name , url , name )
zulip_realm = get_realm ( ' zulip.com ' )
url = " https://zulip.com/test_realm_emoji.png "
do_add_realm_emoji ( zulip_realm , " test " , url )
# Needs to mock an actual message because that's how bugdown obtains the realm
msg = Message ( sender = get_user_profile_by_email ( " hamlet@zulip.com " ) )
converted = bugdown . convert ( " :test: " , " zulip.com " , msg )
self . assertEqual ( converted , ' <p> %s </p> ' % ( emoji_img ( ' :test: ' , url ) ) )
do_remove_realm_emoji ( zulip_realm , ' test ' )
converted = bugdown . convert ( " :test: " , " zulip.com " , msg )
self . assertEqual ( converted , ' <p>:test:</p> ' )
2013-02-14 17:45:17 +01:00
def test_multiline_strong ( self ) :
msg = " Welcome to **the jungle** "
2013-06-05 19:23:19 +02:00
converted = bugdown_convert ( msg )
2013-02-14 17:45:17 +01:00
self . assertEqual ( converted , ' <p>Welcome to <strong>the jungle</strong></p> ' )
msg = """ You can check out **any time you ' d like
But you can never leave * * """
2013-06-05 19:23:19 +02:00
converted = bugdown_convert ( msg )
2013-02-14 17:45:17 +01:00
self . assertEqual ( converted , " <p>You can check out **any time you ' d like<br> \n But you can never leave**</p> " )
2013-06-05 17:45:57 +02:00
def test_realm_patterns ( self ) :
2013-09-05 21:12:56 +02:00
msg = " We should fix #224 and #115, but not issue#124 or #1124z or [trac #15](https://trac.zulip.net/ticket/16) today. "
2013-06-05 17:45:57 +02:00
converted = bugdown_convert ( msg )
2013-09-05 21:12:56 +02:00
self . assertEqual ( converted , ' <p>We should fix <a href= " https://trac.zulip.net/ticket/224 " target= " _blank " title= " https://trac.zulip.net/ticket/224 " >#224</a> and <a href= " https://trac.zulip.net/ticket/115 " target= " _blank " title= " https://trac.zulip.net/ticket/115 " >#115</a>, but not issue#124 or #1124z or <a href= " https://trac.zulip.net/ticket/16 " target= " _blank " title= " https://trac.zulip.net/ticket/16 " >trac #15</a> today.</p> ' )
2013-06-05 17:45:57 +02:00
2013-02-11 17:23:01 +01:00
class UserPresenceTests ( AuthedTestCase ) :
def common_init ( self , email ) :
self . login ( email )
api_key = self . get_api_key ( email )
return api_key
def test_get_empty ( self ) :
2013-07-24 20:41:09 +02:00
email = " hamlet@zulip.com "
2013-02-11 17:23:01 +01:00
api_key = self . common_init ( email )
result = self . client . post ( " /json/get_active_statuses " , { ' email ' : email , ' api-key ' : api_key } )
self . assert_json_success ( result )
2013-06-18 23:55:55 +02:00
json = ujson . loads ( result . content )
2013-02-11 17:23:01 +01:00
for email , presence in json [ ' presences ' ] . items ( ) :
self . assertEqual ( presence , { } )
def test_set_idle ( self ) :
2013-07-24 20:41:09 +02:00
email = " hamlet@zulip.com "
2013-02-11 17:23:01 +01:00
api_key = self . common_init ( email )
client = ' website '
def test_result ( result ) :
self . assert_json_success ( result )
2013-06-18 23:55:55 +02:00
json = ujson . loads ( result . content )
2013-02-11 17:23:01 +01:00
self . assertEqual ( json [ ' presences ' ] [ email ] [ client ] [ ' status ' ] , ' idle ' )
self . assertIn ( ' timestamp ' , json [ ' presences ' ] [ email ] [ client ] )
self . assertIsInstance ( json [ ' presences ' ] [ email ] [ client ] [ ' timestamp ' ] , int )
2013-07-24 20:41:09 +02:00
self . assertEqual ( json [ ' presences ' ] . keys ( ) , [ ' hamlet@zulip.com ' ] )
2013-02-11 17:23:01 +01:00
return json [ ' presences ' ] [ email ] [ client ] [ ' timestamp ' ]
result = self . client . post ( " /json/update_active_status " , { ' email ' : email , ' api-key ' : api_key , ' status ' : ' idle ' } )
test_result ( result )
result = self . client . post ( " /json/get_active_statuses " , { ' email ' : email , ' api-key ' : api_key } )
timestamp = test_result ( result )
2013-07-24 20:41:09 +02:00
email = " othello@zulip.com "
2013-02-11 17:23:01 +01:00
api_key = self . common_init ( email )
self . client . post ( " /json/update_active_status " , { ' email ' : email , ' api-key ' : api_key , ' status ' : ' idle ' } )
result = self . client . post ( " /json/get_active_statuses " , { ' email ' : email , ' api-key ' : api_key } )
self . assert_json_success ( result )
2013-06-18 23:55:55 +02:00
json = ujson . loads ( result . content )
2013-02-11 17:23:01 +01:00
self . assertEqual ( json [ ' presences ' ] [ email ] [ client ] [ ' status ' ] , ' idle ' )
2013-07-24 20:41:09 +02:00
self . assertEqual ( json [ ' presences ' ] [ ' hamlet@zulip.com ' ] [ client ] [ ' status ' ] , ' idle ' )
self . assertEqual ( json [ ' presences ' ] . keys ( ) , [ ' hamlet@zulip.com ' , ' othello@zulip.com ' ] )
2013-02-11 17:23:01 +01:00
newer_timestamp = json [ ' presences ' ] [ email ] [ client ] [ ' timestamp ' ]
self . assertGreaterEqual ( newer_timestamp , timestamp )
def test_set_active ( self ) :
2013-07-24 20:41:09 +02:00
email = " hamlet@zulip.com "
2013-02-11 17:23:01 +01:00
api_key = self . common_init ( email )
client = ' website '
self . client . post ( " /json/update_active_status " , { ' email ' : email , ' api-key ' : api_key , ' status ' : ' idle ' } )
result = self . client . post ( " /json/get_active_statuses " , { ' email ' : email , ' api-key ' : api_key } )
self . assert_json_success ( result )
2013-06-18 23:55:55 +02:00
json = ujson . loads ( result . content )
2013-02-11 17:23:01 +01:00
self . assertEqual ( json [ ' presences ' ] [ email ] [ client ] [ ' status ' ] , ' idle ' )
2013-07-24 20:41:09 +02:00
email = " othello@zulip.com "
2013-02-11 17:23:01 +01:00
api_key = self . common_init ( email )
self . client . post ( " /json/update_active_status " , { ' email ' : email , ' api-key ' : api_key , ' status ' : ' idle ' } )
result = self . client . post ( " /json/get_active_statuses " , { ' email ' : email , ' api-key ' : api_key } )
self . assert_json_success ( result )
2013-06-18 23:55:55 +02:00
json = ujson . loads ( result . content )
2013-02-11 17:23:01 +01:00
self . assertEqual ( json [ ' presences ' ] [ email ] [ client ] [ ' status ' ] , ' idle ' )
2013-07-24 20:41:09 +02:00
self . assertEqual ( json [ ' presences ' ] [ ' hamlet@zulip.com ' ] [ client ] [ ' status ' ] , ' idle ' )
2013-02-11 17:23:01 +01:00
self . client . post ( " /json/update_active_status " , { ' email ' : email , ' api-key ' : api_key , ' status ' : ' active ' } )
result = self . client . post ( " /json/get_active_statuses " , { ' email ' : email , ' api-key ' : api_key } )
self . assert_json_success ( result )
2013-06-18 23:55:55 +02:00
json = ujson . loads ( result . content )
2013-02-11 17:23:01 +01:00
self . assertEqual ( json [ ' presences ' ] [ email ] [ client ] [ ' status ' ] , ' active ' )
2013-07-24 20:41:09 +02:00
self . assertEqual ( json [ ' presences ' ] [ ' hamlet@zulip.com ' ] [ client ] [ ' status ' ] , ' idle ' )
2013-02-11 17:23:01 +01:00
2013-02-12 18:42:14 +01:00
def test_no_mit ( self ) :
# MIT never gets a list of users
email = " espuser@mit.edu "
api_key = self . common_init ( email )
result = self . client . post ( " /json/update_active_status " , { ' email ' : email , ' api-key ' : api_key , ' status ' : ' idle ' } )
self . assert_json_success ( result )
2013-06-18 23:55:55 +02:00
json = ujson . loads ( result . content )
2013-02-12 18:42:14 +01:00
self . assertEqual ( json [ ' presences ' ] , { } )
2013-02-11 17:23:01 +01:00
def test_same_realm ( self ) :
2013-02-12 18:42:14 +01:00
email = " espuser@mit.edu "
2013-02-11 17:23:01 +01:00
api_key = self . common_init ( email )
client = ' website '
self . client . post ( " /json/update_active_status " , { ' email ' : email , ' api-key ' : api_key , ' status ' : ' idle ' } )
result = self . client . post ( " /accounts/logout/ " )
2013-07-24 20:41:09 +02:00
# Ensure we don't see hamlet@zulip.com information leakage
email = " hamlet@zulip.com "
2013-02-11 17:23:01 +01:00
api_key = self . common_init ( email )
2013-02-12 18:42:14 +01:00
2013-02-11 17:23:01 +01:00
result = self . client . post ( " /json/update_active_status " , { ' email ' : email , ' api-key ' : api_key , ' status ' : ' idle ' } )
self . assert_json_success ( result )
2013-06-18 23:55:55 +02:00
json = ujson . loads ( result . content )
2013-02-11 17:23:01 +01:00
self . assertEqual ( json [ ' presences ' ] [ email ] [ client ] [ ' status ' ] , ' idle ' )
2013-07-24 20:56:42 +02:00
# We only want @zulip.com emails
2013-02-11 17:23:01 +01:00
for email in json [ ' presences ' ] . keys ( ) :
2013-07-24 20:41:09 +02:00
self . assertEqual ( email_to_domain ( email ) , ' zulip.com ' )
2013-02-11 17:23:01 +01:00
2013-03-06 21:04:53 +01:00
class UnreadCountTests ( AuthedTestCase ) :
2013-07-19 18:34:54 +02:00
def setUp ( self ) :
2013-08-28 21:29:55 +02:00
self . unread_msg_ids = [ self . send_message (
" iago@zulip.com " , " hamlet@zulip.com " , Recipient . PERSONAL , " hello " ) ,
self . send_message (
" iago@zulip.com " , " hamlet@zulip.com " , Recipient . PERSONAL , " hello2 " ) ]
2013-03-06 21:04:53 +01:00
def test_new_message ( self ) :
# Sending a new message results in unread UserMessages being created
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-03-06 21:04:53 +01:00
content = " Test message for unset read bit "
2013-07-24 20:41:09 +02:00
last_msg = self . send_message ( " hamlet@zulip.com " , " Verona " , Recipient . STREAM , content )
2013-07-02 16:08:12 +02:00
user_messages = list ( UserMessage . objects . filter ( message = last_msg ) )
2013-07-19 18:34:54 +02:00
self . assertEqual ( len ( user_messages ) > 0 , True )
2013-07-02 16:08:12 +02:00
for um in user_messages :
2013-03-06 21:04:53 +01:00
self . assertEqual ( um . message . content , content )
2013-07-24 20:41:09 +02:00
if um . user_profile . email != " hamlet@zulip.com " :
2013-03-06 21:04:53 +01:00
self . assertFalse ( um . flags . read )
def test_update_flags ( self ) :
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-03-06 21:04:53 +01:00
2013-07-19 18:34:54 +02:00
result = self . client . post ( " /json/update_message_flags " ,
2013-08-28 21:29:55 +02:00
{ " messages " : ujson . dumps ( self . unread_msg_ids ) ,
2013-07-19 18:34:54 +02:00
" op " : " add " ,
" flag " : " read " } )
2013-03-06 21:04:53 +01:00
self . assert_json_success ( result )
# Ensure we properly set the flags
2013-07-19 18:34:54 +02:00
found = 0
2013-03-06 21:04:53 +01:00
for msg in self . get_old_messages ( ) :
2013-08-28 21:29:55 +02:00
if msg [ ' id ' ] in self . unread_msg_ids :
2013-03-06 21:04:53 +01:00
self . assertEqual ( msg [ ' flags ' ] , [ ' read ' ] )
2013-07-19 18:34:54 +02:00
found + = 1
self . assertEqual ( found , 2 )
2013-03-06 21:04:53 +01:00
2013-08-28 21:29:55 +02:00
result = self . client . post ( " /json/update_message_flags " ,
{ " messages " : ujson . dumps ( [ self . unread_msg_ids [ 1 ] ] ) ,
" op " : " remove " , " flag " : " read " } )
2013-03-06 21:04:53 +01:00
self . assert_json_success ( result )
# Ensure we properly remove just one flag
for msg in self . get_old_messages ( ) :
2013-08-28 21:29:55 +02:00
if msg [ ' id ' ] == self . unread_msg_ids [ 0 ] :
2013-03-06 21:04:53 +01:00
self . assertEqual ( msg [ ' flags ' ] , [ ' read ' ] )
2013-08-28 21:29:55 +02:00
elif msg [ ' id ' ] == self . unread_msg_ids [ 1 ] :
2013-03-06 21:04:53 +01:00
self . assertEqual ( msg [ ' flags ' ] , [ ] )
def test_update_all_flags ( self ) :
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-03-06 21:04:53 +01:00
2013-06-18 23:55:55 +02:00
result = self . client . post ( " /json/update_message_flags " , { " messages " : ujson . dumps ( [ 1 , 2 ] ) ,
2013-03-06 21:04:53 +01:00
" op " : " add " ,
" flag " : " read " } )
self . assert_json_success ( result )
2013-06-18 23:55:55 +02:00
result = self . client . post ( " /json/update_message_flags " , { " messages " : ujson . dumps ( [ ] ) ,
2013-03-06 21:04:53 +01:00
" op " : " remove " ,
" flag " : " read " ,
2013-06-18 23:55:55 +02:00
" all " : ujson . dumps ( True ) } )
2013-03-06 21:04:53 +01:00
self . assert_json_success ( result )
for msg in self . get_old_messages ( ) :
self . assertEqual ( msg [ ' flags ' ] , [ ] )
2013-03-27 20:06:02 +01:00
class StarTests ( AuthedTestCase ) :
def change_star ( self , messages , add = True ) :
return self . client . post ( " /json/update_message_flags " ,
2013-06-18 23:55:55 +02:00
{ " messages " : ujson . dumps ( messages ) ,
2013-03-27 20:06:02 +01:00
" op " : " add " if add else " remove " ,
" flag " : " starred " } )
def test_change_star ( self ) :
"""
You can set a message as starred / un - starred through
/ json / update_message_flags .
"""
2013-07-24 20:41:09 +02:00
self . login ( " hamlet@zulip.com " )
2013-03-27 20:06:02 +01:00
message_ids = [ 1 , 2 ]
# Star a few messages.
result = self . change_star ( message_ids )
self . assert_json_success ( result )
for msg in self . get_old_messages ( ) :
if msg [ ' id ' ] in message_ids :
2013-04-09 17:56:32 +02:00
self . assertEqual ( msg [ ' flags ' ] , [ ' read ' , ' starred ' ] )
2013-03-27 20:06:02 +01:00
else :
2013-04-09 17:56:32 +02:00
self . assertEqual ( msg [ ' flags ' ] , [ ' read ' ] )
2013-03-27 20:06:02 +01:00
result = self . change_star ( message_ids , False )
self . assert_json_success ( result )
# Remove the stars.
for msg in self . get_old_messages ( ) :
if msg [ ' id ' ] in message_ids :
2013-04-09 17:56:32 +02:00
self . assertEqual ( msg [ ' flags ' ] , [ ' read ' ] )
2013-03-27 20:06:02 +01:00
def test_new_message ( self ) :
"""
New messages aren ' t starred.
"""
2013-07-24 20:41:09 +02:00
test_email = " hamlet@zulip.com "
2013-03-27 20:06:02 +01:00
self . login ( test_email )
content = " Test message for star "
self . send_message ( test_email , " Verona " , Recipient . STREAM ,
content = content )
sent_message = UserMessage . objects . filter (
2013-07-02 21:50:05 +02:00
user_profile = get_user_profile_by_email ( test_email )
2013-03-27 20:06:02 +01:00
) . order_by ( " id " ) . reverse ( ) [ 0 ]
self . assertEqual ( sent_message . message . content , content )
self . assertFalse ( sent_message . flags . starred )
2013-03-27 16:05:39 +01:00
class JiraHookTests ( AuthedTestCase ) :
def send_jira_message ( self , action ) :
2013-07-24 20:41:09 +02:00
email = " hamlet@zulip.com "
2013-03-27 16:05:39 +01:00
api_key = self . get_api_key ( email )
2013-06-27 20:07:55 +02:00
url = " /api/v1/external/jira?api_key= %s " % ( api_key , )
2013-04-30 20:34:29 +02:00
return self . send_json_payload ( email ,
url ,
2013-04-18 17:13:21 +02:00
self . fixture_data ( ' jira ' , action ) ,
2013-04-02 19:02:49 +02:00
stream_name = " jira " ,
content_type = " application/json " )
2013-03-27 16:05:39 +01:00
2013-05-20 19:09:18 +02:00
def test_unknown ( self ) :
2013-07-24 20:41:09 +02:00
email = " hamlet@zulip.com "
2013-05-20 19:09:18 +02:00
api_key = self . get_api_key ( email )
2013-06-27 20:07:55 +02:00
url = " /api/v1/external/jira?api_key= %s " % ( api_key , )
2013-05-20 19:09:18 +02:00
result = self . client . post ( url , self . fixture_data ( ' jira ' , ' unknown ' ) ,
stream_name = " jira " ,
content_type = " application/json " )
self . assert_json_error ( result , ' Unknown JIRA event type ' )
2013-04-30 17:35:43 +02:00
def test_custom_stream ( self ) :
2013-07-24 20:41:09 +02:00
email = " hamlet@zulip.com "
2013-04-30 17:35:43 +02:00
api_key = self . get_api_key ( email )
action = ' created '
2013-06-27 20:07:55 +02:00
url = " /api/v1/external/jira?api_key= %s &stream=jira_custom " % ( api_key , )
2013-04-30 17:35:43 +02:00
msg = self . send_json_payload ( email , url ,
self . fixture_data ( ' jira ' , action ) ,
stream_name = " jira_custom " ,
content_type = " application/json " )
self . assertEqual ( msg . subject , " BUG-15: New bug with hook " )
self . assertEqual ( msg . content , """ Leo Franchi **created** [BUG-15](http://lfranchi.com:8080/browse/BUG-15) priority Major, assigned to **no one**:
> New bug with hook """ )
2013-03-27 16:05:39 +01:00
def test_created ( self ) :
msg = self . send_jira_message ( ' created ' )
self . assertEqual ( msg . subject , " BUG-15: New bug with hook " )
self . assertEqual ( msg . content , """ Leo Franchi **created** [BUG-15](http://lfranchi.com:8080/browse/BUG-15) priority Major, assigned to **no one**:
> New bug with hook """ )
def test_commented ( self ) :
msg = self . send_jira_message ( ' commented ' )
self . assertEqual ( msg . subject , " BUG-15: New bug with hook " )
self . assertEqual ( msg . content , """ Leo Franchi **updated** [BUG-15](http://lfranchi.com:8080/browse/BUG-15):
> Adding a comment . Oh , what a comment it is ! """ )
def test_deleted ( self ) :
msg = self . send_jira_message ( ' deleted ' )
self . assertEqual ( msg . subject , " BUG-15: New bug with hook " )
self . assertEqual ( msg . content , " Leo Franchi **deleted** [BUG-15](http://lfranchi.com:8080/browse/BUG-15)! " )
def test_reassigned ( self ) :
msg = self . send_jira_message ( ' reassigned ' )
self . assertEqual ( msg . subject , " BUG-15: New bug with hook " )
self . assertEqual ( msg . content , """ Leo Franchi **updated** [BUG-15](http://lfranchi.com:8080/browse/BUG-15):
* Changed assignee from * * None * * to * * Leo Franchi * *
""" )
def test_reopened ( self ) :
msg = self . send_jira_message ( ' reopened ' )
self . assertEqual ( msg . subject , " BUG-7: More cowbell polease " )
self . assertEqual ( msg . content , """ Leo Franchi **updated** [BUG-7](http://lfranchi.com:8080/browse/BUG-7):
* Changed status from * * Resolved * * to * * Reopened * *
> Re - opened yeah ! """ )
def test_resolved ( self ) :
msg = self . send_jira_message ( ' resolved ' )
self . assertEqual ( msg . subject , " BUG-13: Refreshing the page loses the user ' s current posi... " )
self . assertEqual ( msg . content , """ Leo Franchi **updated** [BUG-13](http://lfranchi.com:8080/browse/BUG-13):
* Changed status from * * Open * * to * * Resolved * *
* Changed assignee from * * None * * to * * Leo Franchi * *
> Fixed it , finally ! """ )
2013-05-23 19:54:06 +02:00
def test_workflow_postfuncion ( self ) :
msg = self . send_jira_message ( ' postfunction_hook ' )
self . assertEqual ( msg . subject , " TEST-5: PostTest " )
self . assertEqual ( msg . content , """ Leo Franchi [Administrator] **transitioned** [TEST-5](https://lfranchi-test.atlassian.net/browse/TEST-5) from Resolved to Reopened """ )
def test_workflow_postfunction ( self ) :
msg = self . send_jira_message ( ' postfunction_hook ' )
self . assertEqual ( msg . subject , " TEST-5: PostTest " )
self . assertEqual ( msg . content , """ Leo Franchi [Administrator] **transitioned** [TEST-5](https://lfranchi-test.atlassian.net/browse/TEST-5) from Resolved to Reopened """ )
def test_workflow_postfunction_started ( self ) :
msg = self . send_jira_message ( ' postfunction_started ' )
self . assertEqual ( msg . subject , " TEST-7: Gluttony of Post Functions " )
self . assertEqual ( msg . content , """ Leo Franchi [Administrator] **transitioned** [TEST-7](https://lfranchi-test.atlassian.net/browse/TEST-7) from Open to Underway """ )
def test_workflow_postfunction_resolved ( self ) :
msg = self . send_jira_message ( ' postfunction_resolved ' )
self . assertEqual ( msg . subject , " TEST-7: Gluttony of Post Functions " )
self . assertEqual ( msg . content , """ Leo Franchi [Administrator] **transitioned** [TEST-7](https://lfranchi-test.atlassian.net/browse/TEST-7) from Open to Resolved """ )
2013-04-01 23:46:55 +02:00
class BeanstalkHookTests ( AuthedTestCase ) :
def http_auth ( self , username , password ) :
import base64
credentials = base64 . b64encode ( ' %s : %s ' % ( username , password ) )
2013-06-27 20:07:55 +02:00
auth_string = ' Basic %s ' % ( credentials , )
2013-04-01 23:46:55 +02:00
return auth_string
def send_beanstalk_message ( self , action ) :
2013-07-24 20:41:09 +02:00
email = " hamlet@zulip.com "
2013-04-01 23:46:55 +02:00
api_key = self . get_api_key ( email )
2013-04-18 17:13:21 +02:00
data = { ' payload ' : self . fixture_data ( ' beanstalk ' , action ) }
2013-04-02 19:02:49 +02:00
return self . send_json_payload ( email , " /api/v1/external/beanstalk " ,
2013-04-02 22:55:42 +02:00
data ,
2013-04-02 19:02:49 +02:00
stream_name = " commits " ,
HTTP_AUTHORIZATION = self . http_auth ( email , api_key ) )
2013-04-01 23:46:55 +02:00
def test_git_single ( self ) :
msg = self . send_beanstalk_message ( ' git_singlecommit ' )
self . assertEqual ( msg . subject , " work-test " )
self . assertEqual ( msg . content , """ Leo Franchi [pushed](http://lfranchi-svn.beanstalkapp.com/work-test) to branch master
* [ e50508d ] ( http : / / lfranchi - svn . beanstalkapp . com / work - test / changesets / e50508df ) : add some stuff
""" )
2013-07-01 20:17:52 +02:00
@slow ( 0.20 , " lots of queries " )
2013-04-01 23:46:55 +02:00
def test_git_multiple ( self ) :
msg = self . send_beanstalk_message ( ' git_multiple ' )
self . assertEqual ( msg . subject , " work-test " )
self . assertEqual ( msg . content , """ Leo Franchi [pushed](http://lfranchi-svn.beanstalkapp.com/work-test) to branch master
* [ edf529c ] ( http : / / lfranchi - svn . beanstalkapp . com / work - test / changesets / edf529c7 ) : Added new file
* [ c2a191b ] ( http : / / lfranchi - svn . beanstalkapp . com / work - test / changesets / c2a191b9 ) : Filled in new file with some stuff
* [ 2009815 ] ( http : / / lfranchi - svn . beanstalkapp . com / work - test / changesets / 20098158 ) : More work to fix some bugs
""" )
def test_svn_addremove ( self ) :
msg = self . send_beanstalk_message ( ' svn_addremove ' )
self . assertEqual ( msg . subject , " svn r3 " )
self . assertEqual ( msg . content , """ Leo Franchi pushed [revision 3](http://lfranchi-svn.beanstalkapp.com/work-test/changesets/3):
> Removed a file and added another one ! """ )
def test_svn_changefile ( self ) :
msg = self . send_beanstalk_message ( ' svn_changefile ' )
self . assertEqual ( msg . subject , " svn r2 " )
self . assertEqual ( msg . content , """ Leo Franchi pushed [revision 2](http://lfranchi-svn.beanstalkapp.com/work-test/changesets/2):
> Added some code """ )
2013-04-02 19:02:49 +02:00
class GithubHookTests ( AuthedTestCase ) :
2013-05-01 17:32:19 +02:00
def assert_content ( self , msg ) :
self . assertEqual ( msg . content , """ rtomayko [pushed](http://github.com/mojombo/grit/compare/4c8124f...a47fd41) to branch master
* [ 06 f63b4 ] ( http : / / github . com / mojombo / grit / commit / 06 f63b43050935962f84fe54473a7c5de7977325 ) : stub git call for Grit #heads test f:15 Case#1
* [ 5057e76 ] ( http : / / github . com / mojombo / grit / commit / 5057e76 a11abd02e83b7d3d3171c4b68d9c88480 ) : clean up heads test f : 2 hrs
* [ a47fd41 ] ( http : / / github . com / mojombo / grit / commit / a47fd41f3aa4610ea527dcc1669dfdb9c15c5425 ) : add more comments throughout
""" )
2013-05-01 19:19:31 +02:00
def test_spam_branch_is_ignored ( self ) :
2013-07-24 20:41:09 +02:00
email = " hamlet@zulip.com "
2013-05-01 19:19:31 +02:00
api_key = self . get_api_key ( email )
stream = ' commits '
data = { ' email ' : email ,
' api-key ' : api_key ,
' branches ' : ' dev,staging ' ,
' stream ' : stream ,
' event ' : ' push ' ,
' payload ' : self . fixture_data ( ' github ' , ' sample ' ) }
url = ' /api/v1/external/github '
# We subscribe to the stream in this test, even though
# it won't get written, to avoid failing for the wrong
# reason.
self . subscribe_to_stream ( email , stream )
2013-05-22 21:31:52 +02:00
2013-07-02 15:53:48 +02:00
prior_count = Message . objects . count ( )
2013-05-01 19:19:31 +02:00
result = self . client . post ( url , data )
self . assert_json_success ( result )
2013-07-02 15:53:48 +02:00
after_count = Message . objects . count ( )
2013-05-01 19:19:31 +02:00
self . assertEqual ( prior_count , after_count )
def test_user_specified_branches ( self ) :
2013-07-24 20:41:09 +02:00
email = " hamlet@zulip.com "
2013-05-01 19:19:31 +02:00
api_key = self . get_api_key ( email )
stream = ' my_commits '
data = { ' email ' : email ,
' api-key ' : api_key ,
' stream ' : stream ,
' branches ' : ' master,staging ' ,
' event ' : ' push ' ,
' payload ' : self . fixture_data ( ' github ' , ' sample ' ) }
msg = self . send_json_payload ( email , " /api/v1/external/github " ,
data ,
stream_name = stream )
self . assertEqual ( msg . subject , " grit " )
self . assert_content ( msg )
2013-05-01 17:32:19 +02:00
def test_user_specified_stream ( self ) :
# Around May 2013 the github webhook started to specify the stream.
# Before then, the stream was hard coded to "commits".
2013-07-24 20:41:09 +02:00
email = " hamlet@zulip.com "
2013-04-02 19:02:49 +02:00
api_key = self . get_api_key ( email )
2013-05-01 17:32:19 +02:00
stream = ' my_commits '
2013-04-02 19:02:49 +02:00
data = { ' email ' : email ,
' api-key ' : api_key ,
2013-05-01 17:32:19 +02:00
' stream ' : stream ,
2013-04-02 19:02:49 +02:00
' event ' : ' push ' ,
2013-05-01 17:32:19 +02:00
' payload ' : self . fixture_data ( ' github ' , ' sample ' ) }
msg = self . send_json_payload ( email , " /api/v1/external/github " ,
data ,
stream_name = stream )
2013-04-02 19:02:49 +02:00
self . assertEqual ( msg . subject , " grit " )
2013-05-01 17:32:19 +02:00
self . assert_content ( msg )
2013-04-02 19:02:49 +02:00
2013-05-01 17:32:19 +02:00
def test_legacy_hook ( self ) :
2013-07-24 20:41:09 +02:00
email = " hamlet@zulip.com "
2013-05-01 17:32:19 +02:00
api_key = self . get_api_key ( email )
data = { ' email ' : email ,
' api-key ' : api_key ,
' event ' : ' push ' ,
' payload ' : self . fixture_data ( ' github ' , ' sample ' ) }
msg = self . send_json_payload ( email , " /api/v1/external/github " ,
data ,
stream_name = " commits " )
self . assertEqual ( msg . subject , " grit " )
self . assert_content ( msg )
2013-04-02 19:02:49 +02:00
2013-04-18 17:13:21 +02:00
class PivotalHookTests ( AuthedTestCase ) :
def send_pivotal_message ( self , name ) :
2013-07-24 20:41:09 +02:00
email = " hamlet@zulip.com "
2013-04-18 17:13:21 +02:00
api_key = self . get_api_key ( email )
return self . send_json_payload ( email , " /api/v1/external/pivotal?api_key= %s &stream= %s " % ( api_key , " pivotal " ) ,
self . fixture_data ( ' pivotal ' , name , file_type = ' xml ' ) ,
stream_name = " pivotal " ,
content_type = " application/xml " )
def test_accepted ( self ) :
msg = self . send_pivotal_message ( ' accepted ' )
self . assertEqual ( msg . subject , ' My new Feature story ' )
self . assertEqual ( msg . content , ' Leo Franchi accepted " My new Feature story " \
[ ( view ) ] ( https : / / www . pivotaltracker . com / s / projects / 807213 / stories / 48276573 ) ' )
def test_commented ( self ) :
msg = self . send_pivotal_message ( ' commented ' )
self . assertEqual ( msg . subject , ' Comment added ' )
self . assertEqual ( msg . content , ' Leo Franchi added comment: " FIX THIS NOW " \
[ ( view ) ] ( https : / / www . pivotaltracker . com / s / projects / 807213 / stories / 48276573 ) ' )
def test_created ( self ) :
msg = self . send_pivotal_message ( ' created ' )
self . assertEqual ( msg . subject , ' My new Feature story ' )
self . assertEqual ( msg . content , ' Leo Franchi added " My new Feature story " \
( unscheduled feature ) : \n \n > This is my long description \n \n \
[ ( view ) ] ( https : / / www . pivotaltracker . com / s / projects / 807213 / stories / 48276573 ) ' )
def test_delivered ( self ) :
msg = self . send_pivotal_message ( ' delivered ' )
self . assertEqual ( msg . subject , ' Another new story ' )
self . assertEqual ( msg . content , ' Leo Franchi delivered " Another new story " \
[ ( view ) ] ( https : / / www . pivotaltracker . com / s / projects / 807213 / stories / 48278289 ) ' )
def test_finished ( self ) :
msg = self . send_pivotal_message ( ' finished ' )
self . assertEqual ( msg . subject , ' Another new story ' )
self . assertEqual ( msg . content , ' Leo Franchi finished " Another new story " \
[ ( view ) ] ( https : / / www . pivotaltracker . com / s / projects / 807213 / stories / 48278289 ) ' )
def test_moved ( self ) :
msg = self . send_pivotal_message ( ' moved ' )
self . assertEqual ( msg . subject , ' My new Feature story ' )
self . assertEqual ( msg . content , ' Leo Franchi edited " My new Feature story " \
[ ( view ) ] ( https : / / www . pivotaltracker . com / s / projects / 807213 / stories / 48276573 ) ' )
def test_rejected ( self ) :
msg = self . send_pivotal_message ( ' rejected ' )
self . assertEqual ( msg . subject , ' Another new story ' )
self . assertEqual ( msg . content , ' Leo Franchi rejected " Another new story " with comments: \
" Not good enough, sorry " [ ( view ) ] ( https : / / www . pivotaltracker . com / s / projects / 807213 / stories / 48278289 ) ' )
def test_started ( self ) :
msg = self . send_pivotal_message ( ' started ' )
self . assertEqual ( msg . subject , ' Another new story ' )
self . assertEqual ( msg . content , ' Leo Franchi started " Another new story " \
[ ( view ) ] ( https : / / www . pivotaltracker . com / s / projects / 807213 / stories / 48278289 ) ' )
def test_created_estimate ( self ) :
msg = self . send_pivotal_message ( ' created_estimate ' )
self . assertEqual ( msg . subject , ' Another new story ' )
self . assertEqual ( msg . content , ' Leo Franchi added " Another new story " \
( unscheduled feature worth 2 story points ) : \n \n > Some loong description \n \n \
[ ( view ) ] ( https : / / www . pivotaltracker . com / s / projects / 807213 / stories / 48278289 ) ' )
def test_type_changed ( self ) :
msg = self . send_pivotal_message ( ' type_changed ' )
self . assertEqual ( msg . subject , ' My new Feature story ' )
self . assertEqual ( msg . content , ' Leo Franchi edited " My new Feature story " \
[ ( view ) ] ( https : / / www . pivotaltracker . com / s / projects / 807213 / stories / 48276573 ) ' )
2013-07-23 21:50:29 +02:00
class NewRelicHookTests ( AuthedTestCase ) :
def send_new_relic_message ( self , name ) :
2013-07-24 20:41:09 +02:00
email = " hamlet@zulip.com "
2013-07-23 21:50:29 +02:00
api_key = self . get_api_key ( email )
return self . send_json_payload ( email , " /api/v1/external/newrelic?api_key= %s &stream= %s " % ( api_key , " newrelic " ) ,
self . fixture_data ( ' newrelic ' , name , file_type = ' txt ' ) ,
stream_name = " newrelic " ,
content_type = " application/x-www-form-urlencoded " )
def test_alert ( self ) :
msg = self . send_new_relic_message ( ' alert ' )
self . assertEqual ( msg . subject , " Apdex score fell below critical level of 0.90 " )
self . assertEqual ( msg . content , ' Alert opened on [application name]: \
Apdex score fell below critical level of 0.90 \n \
[ View alert ] ( https : / / rpm . newrelc . com / accounts / [ account_id ] / applications / [ application_id ] / incidents / [ incident_id ] ) ' )
def test_deployment ( self ) :
msg = self . send_new_relic_message ( ' deployment ' )
self . assertEqual ( msg . subject , ' Test App deploy ' )
self . assertEqual ( msg . content , ' `1242` deployed by **Zulip Test** \n \
Description sent via curl \n \nChangelog string ' )
2013-05-29 23:58:07 +02:00
class RateLimitTests ( AuthedTestCase ) :
def setUp ( self ) :
settings . RATE_LIMITING = True
add_ratelimit_rule ( 1 , 5 )
def tearDown ( self ) :
settings . RATE_LIMITING = False
remove_ratelimit_rule ( 1 , 5 )
def send_api_message ( self , email , api_key , content ) :
return self . client . post ( " /api/v1/send_message " , { " type " : " stream " ,
" to " : " Verona " ,
" client " : " test suite " ,
" content " : content ,
" subject " : " Test subject " ,
" email " : email ,
" api-key " : api_key } )
def test_headers ( self ) :
2013-07-24 20:41:09 +02:00
email = " hamlet@zulip.com "
2013-07-02 21:50:05 +02:00
user = get_user_profile_by_email ( email )
2013-06-20 23:18:39 +02:00
clear_user_history ( user )
2013-05-29 23:58:07 +02:00
api_key = self . get_api_key ( email )
2013-06-19 22:44:06 +02:00
2013-05-29 23:58:07 +02:00
result = self . send_api_message ( email , api_key , " some stuff " )
self . assertTrue ( ' X-RateLimit-Remaining ' in result )
self . assertTrue ( ' X-RateLimit-Limit ' in result )
self . assertTrue ( ' X-RateLimit-Reset ' in result )
def test_ratelimit_decrease ( self ) :
2013-07-24 20:41:09 +02:00
email = " hamlet@zulip.com "
2013-07-02 21:50:05 +02:00
user = get_user_profile_by_email ( email )
2013-06-20 23:18:39 +02:00
clear_user_history ( user )
2013-05-29 23:58:07 +02:00
api_key = self . get_api_key ( email )
result = self . send_api_message ( email , api_key , " some stuff " )
limit = int ( result [ ' X-RateLimit-Remaining ' ] )
result = self . send_api_message ( email , api_key , " some stuff 2 " )
newlimit = int ( result [ ' X-RateLimit-Remaining ' ] )
self . assertEqual ( limit , newlimit + 1 )
2013-06-20 20:46:28 +02:00
@slow ( 1.1 , ' has to sleep to work ' )
2013-05-29 23:58:07 +02:00
def test_hit_ratelimits ( self ) :
2013-07-24 20:41:09 +02:00
email = " cordelia@zulip.com "
2013-07-02 21:50:05 +02:00
user = get_user_profile_by_email ( email )
2013-06-20 23:18:39 +02:00
clear_user_history ( user )
2013-05-29 23:58:07 +02:00
api_key = self . get_api_key ( email )
2013-06-20 23:18:39 +02:00
for i in range ( 6 ) :
2013-05-29 23:58:07 +02:00
result = self . send_api_message ( email , api_key , " some stuff %s " % ( i , ) )
self . assertEqual ( result . status_code , 403 )
2013-06-18 23:55:55 +02:00
json = ujson . loads ( result . content )
2013-05-29 23:58:07 +02:00
self . assertEqual ( json . get ( " result " ) , " error " )
self . assertIn ( " API usage exceeded rate limit, try again in " , json . get ( " msg " ) )
2013-06-20 23:18:39 +02:00
# We actually wait a second here, rather than force-clearing our history,
# to make sure the rate-limiting code automatically forgives a user
# after some time has passed.
2013-05-29 23:58:07 +02:00
time . sleep ( 1 )
2013-06-20 23:18:39 +02:00
2013-05-29 23:58:07 +02:00
result = self . send_api_message ( email , api_key , " Good message " )
self . assert_json_success ( result )
2013-04-18 17:13:21 +02:00
2013-09-03 22:41:17 +02:00
class AlertWordTests ( AuthedTestCase ) :
def test_default_no_words ( self ) :
email = " cordelia@zulip.com "
user = get_user_profile_by_email ( email )
words = user_alert_words ( user )
self . assertEqual ( words , [ ] )
def test_add_word ( self ) :
email = " cordelia@zulip.com "
user = get_user_profile_by_email ( email )
add_user_alert_words ( user , [ ' alert ' , ' word ' ] )
words = user_alert_words ( user )
self . assertEqual ( words , [ ' alert ' , ' word ' ] )
def test_remove_word ( self ) :
email = " cordelia@zulip.com "
user = get_user_profile_by_email ( email )
add_user_alert_words ( user , [ ' alert ' , ' word ' ] )
remove_user_alert_words ( user , [ ' alert ' ] )
words = user_alert_words ( user )
self . assertEqual ( words , [ ' word ' ] )
def test_realm_words ( self ) :
email = " cordelia@zulip.com "
user1 = get_user_profile_by_email ( email )
add_user_alert_words ( user1 , [ ' alert ' , ' word ' ] )
email = " othello@zulip.com "
user2 = get_user_profile_by_email ( email )
add_user_alert_words ( user2 , [ ' another ' ] )
realm_words = alert_words_in_realm ( user2 . realm )
self . assertEqual ( len ( realm_words ) , 2 )
self . assertEqual ( realm_words . keys ( ) , [ user1 , user2 ] )
self . assertEqual ( realm_words [ user1 ] , [ ' alert ' , ' word ' ] )
self . assertEqual ( realm_words [ user2 ] , [ ' another ' ] )
def test_json_list_default ( self ) :
self . login ( " hamlet@zulip.com " )
result = self . client . get ( ' /json/users/me/alert_words ' )
self . assert_json_success ( result )
data = ujson . loads ( result . content )
self . assertEqual ( data [ ' alert_words ' ] , [ ] )
def test_json_list_add ( self ) :
self . login ( " hamlet@zulip.com " )
result = self . client_patch ( ' /json/users/me/alert_words ' , { ' alert_words ' : ujson . dumps ( [ ' one ' , ' two ' , ' three ' ] ) } )
self . assert_json_success ( result )
result = self . client . get ( ' /json/users/me/alert_words ' )
self . assert_json_success ( result )
data = ujson . loads ( result . content )
self . assertEqual ( data [ ' alert_words ' ] , [ ' one ' , ' two ' , ' three ' ] )
def test_json_list_remove ( self ) :
self . login ( " hamlet@zulip.com " )
result = self . client_patch ( ' /json/users/me/alert_words ' , { ' alert_words ' : ujson . dumps ( [ ' one ' , ' two ' , ' three ' ] ) } )
self . assert_json_success ( result )
data = urllib . urlencode ( { ' alert_words ' : ujson . dumps ( [ ' one ' ] ) } )
result = self . client . delete ( ' /json/users/me/alert_words ' , data )
self . assert_json_success ( result )
result = self . client . get ( ' /json/users/me/alert_words ' )
self . assert_json_success ( result )
data = ujson . loads ( result . content )
self . assertEqual ( data [ ' alert_words ' ] , [ ' two ' , ' three ' ] )
def test_json_list_set ( self ) :
self . login ( " hamlet@zulip.com " )
result = self . client_patch ( ' /json/users/me/alert_words ' , { ' alert_words ' : ujson . dumps ( [ ' one ' , ' two ' , ' three ' ] ) } )
self . assert_json_success ( result )
data = urllib . urlencode ( { ' alert_words ' : ujson . dumps ( [ ' a ' , ' b ' , ' c ' ] ) } )
result = self . client . put ( ' /json/users/me/alert_words ' , data )
self . assert_json_success ( result )
result = self . client . get ( ' /json/users/me/alert_words ' )
self . assert_json_success ( result )
data = ujson . loads ( result . content )
self . assertEqual ( data [ ' alert_words ' ] , [ ' a ' , ' b ' , ' c ' ] )
2013-06-20 18:51:00 +02:00
def full_test_name ( test ) :
test_class = test . __class__ . __name__
test_method = test . _testMethodName
return ' %s / %s ' % ( test_class , test_method )
2013-06-20 19:42:32 +02:00
def get_test_method ( test ) :
return getattr ( test , test . _testMethodName )
2013-06-20 21:17:10 +02:00
def enforce_timely_test_completion ( test_method , test_name , delay ) :
if hasattr ( test_method , ' expected_run_time ' ) :
# Allow for tests to run 50% slower than normal due
# to random variations.
max_delay = 1.5 * test_method . expected_run_time
else :
2013-06-20 21:32:11 +02:00
max_delay = 0.180 # seconds
2013-06-20 21:17:10 +02:00
# Further adjustments for slow laptops:
max_delay = max_delay * 3
if delay > max_delay :
print ' Test is TOO slow: %s ( %.3f s) ' % ( test_name , delay )
2013-06-20 23:27:08 +02:00
def fast_tests_only ( ) :
return os . environ . get ( ' FAST_TESTS_ONLY ' , False )
2013-06-20 18:41:18 +02:00
def run_test ( test ) :
2013-06-20 19:42:32 +02:00
test_method = get_test_method ( test )
2013-06-20 23:27:08 +02:00
if fast_tests_only ( ) and is_known_slow_test ( test_method ) :
return
2013-06-20 18:51:00 +02:00
test_name = full_test_name ( test )
2013-07-02 19:10:50 +02:00
bounce_key_prefix_for_testing ( test_name )
2013-06-20 18:51:00 +02:00
print ' Running %s ' % ( test_name , )
2013-06-20 19:42:32 +02:00
test . _pre_setup ( )
2013-06-20 21:17:10 +02:00
start_time = time . time ( )
2013-06-20 19:42:32 +02:00
test . setUp ( )
test_method ( )
test . tearDown ( )
2013-06-20 21:17:10 +02:00
delay = time . time ( ) - start_time
enforce_timely_test_completion ( test_method , test_name , delay )
2013-06-20 19:42:32 +02:00
test . _post_teardown ( )
2013-06-20 18:41:18 +02:00
2012-11-14 20:50:47 +01:00
class Runner ( DjangoTestSuiteRunner ) :
2013-05-08 05:30:42 +02:00
option_list = ( )
def __init__ ( self , * args , * * kwargs ) :
2012-11-14 20:50:47 +01:00
DjangoTestSuiteRunner . __init__ ( self , * args , * * kwargs )
2013-06-19 20:23:27 +02:00
2013-06-19 20:41:30 +02:00
def run_suite ( self , suite ) :
for test in suite :
2013-06-20 18:41:18 +02:00
run_test ( test )
2013-06-19 20:41:30 +02:00
2013-06-19 20:23:27 +02:00
def run_tests ( self , test_labels , extra_tests = None , * * kwargs ) :
self . setup_test_environment ( )
suite = self . build_suite ( test_labels , extra_tests )
2013-06-19 20:41:30 +02:00
self . run_suite ( suite )
2013-06-19 20:23:27 +02:00
self . teardown_test_environment ( )
2013-06-19 20:41:30 +02:00
print ' DONE! '
print