blob: fb8810b0ef7191cf4b8d350f721d7dca24cbe1b7 [file] [log] [blame]
# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file or at
# https://developers.google.com/open-source/licenses/bsd
"""Unit tests for the framework_helpers module."""
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
import mock
import unittest
try:
from mox3 import mox
except ImportError:
import mox
import time
from businesslogic import work_env
from framework import framework_helpers
from framework import framework_views
from proto import features_pb2
from proto import project_pb2
from proto import user_pb2
from services import service_manager
from testing import fake
from testing import testing_helpers
class HelperFunctionsTest(unittest.TestCase):
def setUp(self):
self.mox = mox.Mox()
self.time = self.mox.CreateMock(framework_helpers.time)
framework_helpers.time = self.time # Point to a mocked out time module.
def tearDown(self):
framework_helpers.time = time # Point back to the time module.
self.mox.UnsetStubs()
self.mox.ResetAll()
def testRetryDecorator_ExceedFailures(self):
class Tracker(object):
func_called = 0
tracker = Tracker()
# Use a function that always fails.
@framework_helpers.retry(2, delay=1, backoff=2)
def testFunc(tracker):
tracker.func_called += 1
raise Exception('Failed')
self.time.sleep(1).AndReturn(None)
self.time.sleep(2).AndReturn(None)
self.mox.ReplayAll()
with self.assertRaises(Exception):
testFunc(tracker)
self.mox.VerifyAll()
self.assertEqual(3, tracker.func_called)
def testRetryDecorator_EventuallySucceed(self):
class Tracker(object):
func_called = 0
tracker = Tracker()
# Use a function that succeeds on the 2nd attempt.
@framework_helpers.retry(2, delay=1, backoff=2)
def testFunc(tracker):
tracker.func_called += 1
if tracker.func_called < 2:
raise Exception('Failed')
self.time.sleep(1).AndReturn(None)
self.mox.ReplayAll()
testFunc(tracker)
self.mox.VerifyAll()
self.assertEqual(2, tracker.func_called)
def testGetRoleName(self):
proj = project_pb2.Project()
proj.owner_ids.append(111)
proj.committer_ids.append(222)
proj.contributor_ids.append(333)
self.assertEqual(None, framework_helpers.GetRoleName(set(), proj))
self.assertEqual('Owner', framework_helpers.GetRoleName({111}, proj))
self.assertEqual('Committer', framework_helpers.GetRoleName({222}, proj))
self.assertEqual('Contributor', framework_helpers.GetRoleName({333}, proj))
self.assertEqual(
'Owner', framework_helpers.GetRoleName({111, 222, 999}, proj))
self.assertEqual(
'Committer', framework_helpers.GetRoleName({222, 333, 999}, proj))
self.assertEqual(
'Contributor', framework_helpers.GetRoleName({333, 999}, proj))
def testGetHotlistRoleName(self):
hotlist = features_pb2.Hotlist()
hotlist.owner_ids.append(111)
hotlist.editor_ids.append(222)
hotlist.follower_ids.append(333)
self.assertEqual(None, framework_helpers.GetHotlistRoleName(set(), hotlist))
self.assertEqual(
'Owner', framework_helpers.GetHotlistRoleName({111}, hotlist))
self.assertEqual(
'Editor', framework_helpers.GetHotlistRoleName({222}, hotlist))
self.assertEqual(
'Follower', framework_helpers.GetHotlistRoleName({333}, hotlist))
self.assertEqual(
'Owner', framework_helpers.GetHotlistRoleName({111, 222, 999}, hotlist))
self.assertEqual(
'Editor', framework_helpers.GetHotlistRoleName(
{222, 333, 999}, hotlist))
self.assertEqual(
'Follower', framework_helpers.GetHotlistRoleName({333, 999}, hotlist))
class UrlFormattingTest(unittest.TestCase):
"""Tests for URL formatting."""
def setUp(self):
self.services = service_manager.Services(user=fake.UserService())
def testFormatMovedProjectURL(self):
"""Project foo has been moved to bar. User is visiting /p/foo/..."""
mr = testing_helpers.MakeMonorailRequest()
mr.current_page_url = '/p/foo/'
self.assertEqual(
'/p/bar/',
framework_helpers.FormatMovedProjectURL(mr, 'bar'))
mr.current_page_url = '/p/foo/issues/list'
self.assertEqual(
'/p/bar/issues/list',
framework_helpers.FormatMovedProjectURL(mr, 'bar'))
mr.current_page_url = '/p/foo/issues/detail?id=123'
self.assertEqual(
'/p/bar/issues/detail?id=123',
framework_helpers.FormatMovedProjectURL(mr, 'bar'))
mr.current_page_url = '/p/foo/issues/detail?id=123#c7'
self.assertEqual(
'/p/bar/issues/detail?id=123#c7',
framework_helpers.FormatMovedProjectURL(mr, 'bar'))
def testFormatURL(self):
mr = testing_helpers.MakeMonorailRequest()
path = '/dude/wheres/my/car'
recognized_params = [(name, mr.GetParam(name)) for name in
framework_helpers.RECOGNIZED_PARAMS]
url = framework_helpers.FormatURL(recognized_params, path)
self.assertEqual(path, url)
def testFormatURLWithRecognizedParams(self):
params = {}
query = []
for name in framework_helpers.RECOGNIZED_PARAMS:
params[name] = name
query.append('%s=%s' % (name, 123))
path = '/dude/wheres/my/car'
expected = '%s?%s' % (path, '&'.join(query))
mr = testing_helpers.MakeMonorailRequest(path=expected)
recognized_params = [(name, mr.GetParam(name)) for name in
framework_helpers.RECOGNIZED_PARAMS]
# No added params.
url = framework_helpers.FormatURL(recognized_params, path)
self.assertEqual(expected, url)
def testFormatURLWithKeywordArgs(self):
params = {}
query_pairs = []
for name in framework_helpers.RECOGNIZED_PARAMS:
params[name] = name
if name != 'can' and name != 'start':
query_pairs.append('%s=%s' % (name, 123))
path = '/dude/wheres/my/car'
mr = testing_helpers.MakeMonorailRequest(
path='%s?%s' % (path, '&'.join(query_pairs)))
query_pairs.append('can=yep')
query_pairs.append('start=486')
query_string = '&'.join(query_pairs)
expected = '%s?%s' % (path, query_string)
recognized_params = [(name, mr.GetParam(name)) for name in
framework_helpers.RECOGNIZED_PARAMS]
url = framework_helpers.FormatURL(
recognized_params, path, can='yep', start=486)
self.assertEqual(expected, url)
def testFormatURLWithKeywordArgsAndID(self):
params = {}
query_pairs = []
query_pairs.append('id=200') # id should be the first parameter.
for name in framework_helpers.RECOGNIZED_PARAMS:
params[name] = name
if name != 'can' and name != 'start':
query_pairs.append('%s=%s' % (name, 123))
path = '/dude/wheres/my/car'
mr = testing_helpers.MakeMonorailRequest(
path='%s?%s' % (path, '&'.join(query_pairs)))
query_pairs.append('can=yep')
query_pairs.append('start=486')
query_string = '&'.join(query_pairs)
expected = '%s?%s' % (path, query_string)
recognized_params = [(name, mr.GetParam(name)) for name in
framework_helpers.RECOGNIZED_PARAMS]
url = framework_helpers.FormatURL(
recognized_params, path, can='yep', start=486, id=200)
self.assertEqual(expected, url)
def testFormatURLWithStrangeParams(self):
mr = testing_helpers.MakeMonorailRequest(path='/foo?start=0')
recognized_params = [(name, mr.GetParam(name)) for name in
framework_helpers.RECOGNIZED_PARAMS]
url = framework_helpers.FormatURL(
recognized_params, '/foo',
r=0, path='/foo/bar', sketchy='/foo/ bar baz ')
self.assertEqual(
'/foo?start=0&path=/foo/bar&r=0&sketchy=/foo/%20bar%20baz%20',
url)
def testFormatAbsoluteURL(self):
_request, mr = testing_helpers.GetRequestObjects(
path='/p/proj/some-path',
headers={'Host': 'www.test.com'})
self.assertEqual(
'http://www.test.com/p/proj/some/path',
framework_helpers.FormatAbsoluteURL(mr, '/some/path'))
def testFormatAbsoluteURL_CommonRequestParams(self):
_request, mr = testing_helpers.GetRequestObjects(
path='/p/proj/some-path?foo=bar&can=1',
headers={'Host': 'www.test.com'})
self.assertEqual(
'http://www.test.com/p/proj/some/path?can=1',
framework_helpers.FormatAbsoluteURL(mr, '/some/path'))
self.assertEqual(
'http://www.test.com/p/proj/some/path',
framework_helpers.FormatAbsoluteURL(
mr, '/some/path', copy_params=False))
def testFormatAbsoluteURL_NoProject(self):
path = '/some/path'
_request, mr = testing_helpers.GetRequestObjects(
headers={'Host': 'www.test.com'}, path=path)
url = framework_helpers.FormatAbsoluteURL(mr, path, include_project=False)
self.assertEqual(url, 'http://www.test.com/some/path')
def testGetHostPort_Local(self):
"""We use testing-app.appspot.com when running locally."""
self.assertEqual('testing-app.appspot.com',
framework_helpers.GetHostPort())
self.assertEqual('testing-app.appspot.com',
framework_helpers.GetHostPort(project_name='proj'))
@mock.patch('settings.preferred_domains',
{'testing-app.appspot.com': 'example.com'})
def testGetHostPort_PreferredDomain(self):
"""A prod server can have a preferred domain."""
self.assertEqual('example.com',
framework_helpers.GetHostPort())
self.assertEqual('example.com',
framework_helpers.GetHostPort(project_name='proj'))
@mock.patch('settings.branded_domains',
{'proj': 'branded.com', '*': 'unbranded.com'})
@mock.patch('settings.preferred_domains',
{'testing-app.appspot.com': 'example.com'})
def testGetHostPort_BrandedDomain(self):
"""A prod server can have a preferred domain."""
self.assertEqual('example.com',
framework_helpers.GetHostPort())
self.assertEqual('branded.com',
framework_helpers.GetHostPort(project_name='proj'))
self.assertEqual('unbranded.com',
framework_helpers.GetHostPort(project_name='other-proj'))
def testIssueCommentURL(self):
hostport = 'port.someplex.com'
proj = project_pb2.Project()
proj.project_name = 'proj'
url = 'https://port.someplex.com/p/proj/issues/detail?id=2'
actual_url = framework_helpers.IssueCommentURL(
hostport, proj, 2)
self.assertEqual(actual_url, url)
url = 'https://port.someplex.com/p/proj/issues/detail?id=2#c2'
actual_url = framework_helpers.IssueCommentURL(
hostport, proj, 2, seq_num=2)
self.assertEqual(actual_url, url)
class WordWrapSuperLongLinesTest(unittest.TestCase):
def testEmptyLogMessage(self):
msg = ''
wrapped_msg = framework_helpers.WordWrapSuperLongLines(msg)
self.assertEqual(wrapped_msg, '')
def testShortLines(self):
msg = 'one\ntwo\nthree\n'
wrapped_msg = framework_helpers.WordWrapSuperLongLines(msg)
expected = 'one\ntwo\nthree\n'
self.assertEqual(wrapped_msg, expected)
def testOneLongLine(self):
msg = ('This is a super long line that just goes on and on '
'and it seems like it will never stop because it is '
'super long and it was entered by a user who had no '
'familiarity with the return key.')
wrapped_msg = framework_helpers.WordWrapSuperLongLines(msg)
expected = ('This is a super long line that just goes on and on and it '
'seems like it will never stop because it\n'
'is super long and it was entered by a user who had no '
'familiarity with the return key.')
self.assertEqual(wrapped_msg, expected)
msg2 = ('This is a super long line that just goes on and on '
'and it seems like it will never stop because it is '
'super long and it was entered by a user who had no '
'familiarity with the return key. '
'This is a super long line that just goes on and on '
'and it seems like it will never stop because it is '
'super long and it was entered by a user who had no '
'familiarity with the return key.')
wrapped_msg2 = framework_helpers.WordWrapSuperLongLines(msg2)
expected2 = ('This is a super long line that just goes on and on and it '
'seems like it will never stop because it\n'
'is super long and it was entered by a user who had no '
'familiarity with the return key. This is a\n'
'super long line that just goes on and on and it seems like '
'it will never stop because it is super\n'
'long and it was entered by a user who had no familiarity '
'with the return key.')
self.assertEqual(wrapped_msg2, expected2)
def testMixOfShortAndLong(self):
msg = ('[Author: mpcomplete]\n'
'\n'
# Description on one long line
'Fix a memory leak in JsArray and JsObject for the IE and NPAPI '
'ports. Each time you call GetElement* or GetProperty* to '
'retrieve string or object token, the token would be leaked. '
'I added a JsScopedToken to ensure that the right thing is '
'done when the object leaves scope, depending on the platform.\n'
'\n'
'R=zork\n'
'CC=google-gears-eng@googlegroups.com\n'
'DELTA=108 (52 added, 36 deleted, 20 changed)\n'
'OCL=5932446\n'
'SCL=5933728\n')
wrapped_msg = framework_helpers.WordWrapSuperLongLines(msg)
expected = (
'[Author: mpcomplete]\n'
'\n'
'Fix a memory leak in JsArray and JsObject for the IE and NPAPI '
'ports. Each time you call\n'
'GetElement* or GetProperty* to retrieve string or object token, the '
'token would be leaked. I added\n'
'a JsScopedToken to ensure that the right thing is done when the '
'object leaves scope, depending on\n'
'the platform.\n'
'\n'
'R=zork\n'
'CC=google-gears-eng@googlegroups.com\n'
'DELTA=108 (52 added, 36 deleted, 20 changed)\n'
'OCL=5932446\n'
'SCL=5933728\n')
self.assertEqual(wrapped_msg, expected)
class ComputeListDeltasTest(unittest.TestCase):
def DoOne(self, old=None, new=None, added=None, removed=None):
"""Run one call to the target method and check expected results."""
actual_added, actual_removed = framework_helpers.ComputeListDeltas(
old, new)
self.assertItemsEqual(added, actual_added)
self.assertItemsEqual(removed, actual_removed)
def testEmptyLists(self):
self.DoOne(old=[], new=[], added=[], removed=[])
self.DoOne(old=[1, 2], new=[], added=[], removed=[1, 2])
self.DoOne(old=[], new=[1, 2], added=[1, 2], removed=[])
def testUnchanged(self):
self.DoOne(old=[1], new=[1], added=[], removed=[])
self.DoOne(old=[1, 2], new=[1, 2], added=[], removed=[])
self.DoOne(old=[1, 2], new=[2, 1], added=[], removed=[])
def testCompleteChange(self):
self.DoOne(old=[1, 2], new=[3, 4], added=[3, 4], removed=[1, 2])
def testGeneralChange(self):
self.DoOne(old=[1, 2], new=[2], added=[], removed=[1])
self.DoOne(old=[1], new=[1, 2], added=[2], removed=[])
self.DoOne(old=[1, 2], new=[2, 3], added=[3], removed=[1])
class UserSettingsTest(unittest.TestCase):
def setUp(self):
self.mr = testing_helpers.MakeMonorailRequest()
self.cnxn = 'cnxn'
self.services = service_manager.Services(
user=fake.UserService(),
usergroup=fake.UserGroupService())
def testGatherUnifiedSettingsPageData(self):
mr = self.mr
mr.auth.user_view = framework_views.StuffUserView(100, 'user@invalid', True)
mr.auth.user_view.profile_url = '/u/profile/url'
userprefs = user_pb2.UserPrefs(
prefs=[user_pb2.UserPrefValue(name='public_issue_notice', value='true')])
page_data = framework_helpers.UserSettings.GatherUnifiedSettingsPageData(
mr.auth.user_id, mr.auth.user_view, mr.auth.user_pb, userprefs)
expected_keys = [
'settings_user',
'settings_user_pb',
'settings_user_is_banned',
'self',
'profile_url_fragment',
'preview_on_hover',
'settings_user_prefs',
]
self.assertItemsEqual(expected_keys, list(page_data.keys()))
self.assertEqual('profile/url', page_data['profile_url_fragment'])
self.assertTrue(page_data['settings_user_prefs'].public_issue_notice)
self.assertFalse(page_data['settings_user_prefs'].restrict_new_issues)
def testGatherUnifiedSettingsPageData_NoUserPrefs(self):
"""If UserPrefs were not loaded, consider them all false."""
mr = self.mr
mr.auth.user_view = framework_views.StuffUserView(100, 'user@invalid', True)
userprefs = None
page_data = framework_helpers.UserSettings.GatherUnifiedSettingsPageData(
mr.auth.user_id, mr.auth.user_view, mr.auth.user_pb, userprefs)
self.assertFalse(page_data['settings_user_prefs'].public_issue_notice)
self.assertFalse(page_data['settings_user_prefs'].restrict_new_issues)
def testProcessBanForm(self):
"""We can ban and unban users."""
user = self.services.user.TestAddUser('one@example.com', 111)
post_data = {'banned': 1, 'banned_reason': 'rude'}
framework_helpers.UserSettings.ProcessBanForm(
self.cnxn, self.services.user, post_data, 111, user)
self.assertEqual('rude', user.banned)
post_data = {} # not banned
framework_helpers.UserSettings.ProcessBanForm(
self.cnxn, self.services.user, post_data, 111, user)
self.assertEqual('', user.banned)
def testProcessSettingsForm_OldStylePrefs(self):
"""We can set prefs that are stored in the User PB."""
user = self.services.user.TestAddUser('one@example.com', 111)
post_data = {'obscure_email': 1, 'notify': 1}
with work_env.WorkEnv(self.mr, self.services) as we:
framework_helpers.UserSettings.ProcessSettingsForm(
we, post_data, user)
self.assertTrue(user.obscure_email)
self.assertTrue(user.notify_issue_change)
self.assertFalse(user.notify_starred_ping)
def testProcessSettingsForm_NewStylePrefs(self):
"""We can set prefs that are stored in the UserPrefs PB."""
user = self.services.user.TestAddUser('one@example.com', 111)
post_data = {'restrict_new_issues': 1}
with work_env.WorkEnv(self.mr, self.services) as we:
framework_helpers.UserSettings.ProcessSettingsForm(
we, post_data, user)
userprefs = we.GetUserPrefs(111)
actual = {upv.name: upv.value
for upv in userprefs.prefs}
expected = {
'restrict_new_issues': 'true',
'public_issue_notice': 'false',
}
self.assertEqual(expected, actual)
class MurmurHash3Test(unittest.TestCase):
def testMurmurHash(self):
test_data = [
('', 0),
('agable@chromium.org', 4092810879),
(u'jrobbins@chromium.org', 904770043),
('seanmccullough%google.com@gtempaccount.com', 1301269279),
('rmistry+monorail@chromium.org', 4186878788),
('jparent+foo@', 2923900874),
('@example.com', 3043483168),
]
hashes = [framework_helpers.MurmurHash3_x86_32(x)
for (x, _) in test_data]
self.assertListEqual(hashes, [e for (_, e) in test_data])
def testMurmurHashWithSeed(self):
test_data = [
('', 1113155926, 2270882445),
('agable@chromium.org', 772936925, 3995066671),
(u'jrobbins@chromium.org', 1519359761, 1273489513),
('seanmccullough%google.com@gtempaccount.com', 49913829, 1202521153),
('rmistry+monorail@chromium.org', 314860298, 3636123309),
('jparent+foo@', 195791379, 332453977),
('@example.com', 521490555, 257496459),
]
hashes = [framework_helpers.MurmurHash3_x86_32(x, s)
for (x, s, _) in test_data]
self.assertListEqual(hashes, [e for (_, _, e) in test_data])
class MakeRandomKeyTest(unittest.TestCase):
def testMakeRandomKey_Normal(self):
key1 = framework_helpers.MakeRandomKey()
key2 = framework_helpers.MakeRandomKey()
self.assertEqual(128, len(key1))
self.assertEqual(128, len(key2))
self.assertNotEqual(key1, key2)
def testMakeRandomKey_Length(self):
key = framework_helpers.MakeRandomKey()
self.assertEqual(128, len(key))
key16 = framework_helpers.MakeRandomKey(length=16)
self.assertEqual(16, len(key16))
def testMakeRandomKey_Chars(self):
key = framework_helpers.MakeRandomKey(chars='a', length=4)
self.assertEqual('aaaa', key)
class IsServiceAccountTest(unittest.TestCase):
def testIsServiceAccount(self):
appspot = 'abc@appspot.gserviceaccount.com'
developer = '@developer.gserviceaccount.com'
bugdroid = 'bugdroid1@chromium.org'
user = 'test@example.com'
self.assertTrue(framework_helpers.IsServiceAccount(appspot))
self.assertTrue(framework_helpers.IsServiceAccount(developer))
self.assertTrue(framework_helpers.IsServiceAccount(bugdroid))
self.assertFalse(framework_helpers.IsServiceAccount(user))
client_emails = set([appspot, developer, bugdroid])
self.assertTrue(framework_helpers.IsServiceAccount(
appspot, client_emails=client_emails))
self.assertTrue(framework_helpers.IsServiceAccount(
developer, client_emails=client_emails))
self.assertTrue(framework_helpers.IsServiceAccount(
bugdroid, client_emails=client_emails))
self.assertFalse(framework_helpers.IsServiceAccount(
user, client_emails=client_emails))