OLD | NEW |
(Empty) | |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is govered by a BSD-style |
| 3 # license that can be found in the LICENSE file or at |
| 4 # https://developers.google.com/open-source/licenses/bsd |
| 5 |
| 6 """Unit tests for the framework_helpers module.""" |
| 7 |
| 8 import unittest |
| 9 |
| 10 import mox |
| 11 import time |
| 12 |
| 13 from framework import framework_helpers |
| 14 from framework import framework_views |
| 15 from proto import project_pb2 |
| 16 from services import service_manager |
| 17 from testing import fake |
| 18 from testing import testing_helpers |
| 19 |
| 20 |
| 21 class HelperFunctionsTest(unittest.TestCase): |
| 22 |
| 23 def setUp(self): |
| 24 self.mox = mox.Mox() |
| 25 self.time = self.mox.CreateMock(framework_helpers.time) |
| 26 framework_helpers.time = self.time # Point to a mocked out time module. |
| 27 |
| 28 def tearDown(self): |
| 29 framework_helpers.time = time # Point back to the time module. |
| 30 self.mox.UnsetStubs() |
| 31 self.mox.ResetAll() |
| 32 |
| 33 def testRetryDecorator_ExceedFailures(self): |
| 34 class Tracker(object): |
| 35 func_called = 0 |
| 36 tracker = Tracker() |
| 37 |
| 38 # Use a function that always fails. |
| 39 @framework_helpers.retry(2, delay=1, backoff=2) |
| 40 def testFunc(tracker): |
| 41 tracker.func_called += 1 |
| 42 raise Exception('Failed') |
| 43 |
| 44 self.time.sleep(1).AndReturn(None) |
| 45 self.time.sleep(2).AndReturn(None) |
| 46 self.mox.ReplayAll() |
| 47 with self.assertRaises(Exception): |
| 48 testFunc(tracker) |
| 49 self.mox.VerifyAll() |
| 50 self.assertEquals(3, tracker.func_called) |
| 51 |
| 52 def testRetryDecorator_EventuallySucceed(self): |
| 53 class Tracker(object): |
| 54 func_called = 0 |
| 55 tracker = Tracker() |
| 56 |
| 57 # Use a function that succeeds on the 2nd attempt. |
| 58 @framework_helpers.retry(2, delay=1, backoff=2) |
| 59 def testFunc(tracker): |
| 60 tracker.func_called += 1 |
| 61 if tracker.func_called < 2: |
| 62 raise Exception('Failed') |
| 63 |
| 64 self.time.sleep(1).AndReturn(None) |
| 65 self.mox.ReplayAll() |
| 66 testFunc(tracker) |
| 67 self.mox.VerifyAll() |
| 68 self.assertEquals(2, tracker.func_called) |
| 69 |
| 70 def testGetRoleName(self): |
| 71 proj = project_pb2.Project() |
| 72 proj.owner_ids.append(111L) |
| 73 proj.committer_ids.append(222L) |
| 74 proj.contributor_ids.append(333L) |
| 75 |
| 76 self.assertEquals(None, framework_helpers.GetRoleName(set(), proj)) |
| 77 |
| 78 self.assertEquals( |
| 79 'Owner', framework_helpers.GetRoleName({111L}, proj)) |
| 80 self.assertEquals( |
| 81 'Committer', framework_helpers.GetRoleName({222L}, proj)) |
| 82 self.assertEquals( |
| 83 'Contributor', framework_helpers.GetRoleName({333L}, proj)) |
| 84 |
| 85 self.assertEquals( |
| 86 'Owner', |
| 87 framework_helpers.GetRoleName({111L, 222L, 999L}, proj)) |
| 88 self.assertEquals( |
| 89 'Committer', |
| 90 framework_helpers.GetRoleName({222L, 333L, 999L}, proj)) |
| 91 self.assertEquals( |
| 92 'Contributor', |
| 93 framework_helpers.GetRoleName({333L, 999L}, proj)) |
| 94 |
| 95 |
| 96 class UrlFormattingTest(unittest.TestCase): |
| 97 """Tests for URL formatting.""" |
| 98 |
| 99 def setUp(self): |
| 100 self.services = service_manager.Services(user=fake.UserService()) |
| 101 |
| 102 def testFormatMovedProjectURL(self): |
| 103 """Project foo has been moved to bar. User is visiting /p/foo/...""" |
| 104 mr = testing_helpers.MakeMonorailRequest() |
| 105 mr.current_page_url = '/p/foo/' |
| 106 self.assertEqual( |
| 107 '/p/bar/', |
| 108 framework_helpers.FormatMovedProjectURL(mr, 'bar')) |
| 109 |
| 110 mr.current_page_url = '/p/foo/issues/list' |
| 111 self.assertEqual( |
| 112 '/p/bar/issues/list', |
| 113 framework_helpers.FormatMovedProjectURL(mr, 'bar')) |
| 114 |
| 115 mr.current_page_url = '/p/foo/issues/detail?id=123' |
| 116 self.assertEqual( |
| 117 '/p/bar/issues/detail?id=123', |
| 118 framework_helpers.FormatMovedProjectURL(mr, 'bar')) |
| 119 |
| 120 mr.current_page_url = '/p/foo/issues/detail?id=123#c7' |
| 121 self.assertEqual( |
| 122 '/p/bar/issues/detail?id=123#c7', |
| 123 framework_helpers.FormatMovedProjectURL(mr, 'bar')) |
| 124 |
| 125 def testFormatURL(self): |
| 126 mr = testing_helpers.MakeMonorailRequest() |
| 127 path = '/dude/wheres/my/car' |
| 128 url = framework_helpers.FormatURL(mr, path) |
| 129 self.assertEqual(path, url) |
| 130 |
| 131 def testFormatURLWithRecognizedParams(self): |
| 132 params = {} |
| 133 query = [] |
| 134 for name in framework_helpers.RECOGNIZED_PARAMS: |
| 135 params[name] = name |
| 136 query.append('%s=%s' % (name, name)) |
| 137 path = '/dude/wheres/my/car' |
| 138 expected = '%s?%s' % (path, '&'.join(query)) |
| 139 mr = testing_helpers.MakeMonorailRequest(path=expected) |
| 140 url = framework_helpers.FormatURL(mr, path) # No added params. |
| 141 self.assertEqual(expected, url) |
| 142 |
| 143 def testFormatURLWithKeywordArgs(self): |
| 144 params = {} |
| 145 query_pairs = [] |
| 146 for name in framework_helpers.RECOGNIZED_PARAMS: |
| 147 params[name] = name |
| 148 if name is not 'can' and name is not 'start': |
| 149 query_pairs.append('%s=%s' % (name, name)) |
| 150 path = '/dude/wheres/my/car' |
| 151 mr = testing_helpers.MakeMonorailRequest( |
| 152 path='%s?%s' % (path, '&'.join(query_pairs))) |
| 153 query_pairs.append('can=yep') |
| 154 query_pairs.append('start=486') |
| 155 query_string = '&'.join(query_pairs) |
| 156 expected = '%s?%s' % (path, query_string) |
| 157 url = framework_helpers.FormatURL(mr, path, can='yep', start=486) |
| 158 self.assertEqual(expected, url) |
| 159 |
| 160 def testFormatURLWithKeywordArgsAndID(self): |
| 161 params = {} |
| 162 query_pairs = [] |
| 163 query_pairs.append('id=200') # id should be the first parameter. |
| 164 for name in framework_helpers.RECOGNIZED_PARAMS: |
| 165 params[name] = name |
| 166 if name is not 'can' and name is not 'start': |
| 167 query_pairs.append('%s=%s' % (name, name)) |
| 168 path = '/dude/wheres/my/car' |
| 169 mr = testing_helpers.MakeMonorailRequest( |
| 170 path='%s?%s' % (path, '&'.join(query_pairs))) |
| 171 query_pairs.append('can=yep') |
| 172 query_pairs.append('start=486') |
| 173 query_string = '&'.join(query_pairs) |
| 174 expected = '%s?%s' % (path, query_string) |
| 175 url = framework_helpers.FormatURL(mr, path, can='yep', start=486, id=200) |
| 176 self.assertEqual(expected, url) |
| 177 |
| 178 def testFormatURLWithStrangeParams(self): |
| 179 mr = testing_helpers.MakeMonorailRequest(path='/foo?start=0') |
| 180 url = framework_helpers.FormatURL( |
| 181 mr, '/foo', r=0, path='/foo/bar', sketchy='/foo/ bar baz ') |
| 182 self.assertEqual( |
| 183 '/foo?start=0&path=/foo/bar&r=0&sketchy=/foo/%20bar%20baz%20', |
| 184 url) |
| 185 |
| 186 def testFormatAbsoluteURL(self): |
| 187 _request, mr = testing_helpers.GetRequestObjects( |
| 188 path='/p/proj/some-path', |
| 189 headers={'Host': 'www.test.com'}) |
| 190 self.assertEqual( |
| 191 'http://www.test.com/p/proj/some/path', |
| 192 framework_helpers.FormatAbsoluteURL(mr, '/some/path')) |
| 193 |
| 194 def testFormatAbsoluteURL_CommonRequestParams(self): |
| 195 _request, mr = testing_helpers.GetRequestObjects( |
| 196 path='/p/proj/some-path?foo=bar&can=1', |
| 197 headers={'Host': 'www.test.com'}) |
| 198 self.assertEqual( |
| 199 'http://www.test.com/p/proj/some/path?can=1', |
| 200 framework_helpers.FormatAbsoluteURL(mr, '/some/path')) |
| 201 self.assertEqual( |
| 202 'http://www.test.com/p/proj/some/path', |
| 203 framework_helpers.FormatAbsoluteURL( |
| 204 mr, '/some/path', copy_params=False)) |
| 205 |
| 206 def testFormatAbsoluteURL_NoProject(self): |
| 207 path = '/some/path' |
| 208 _request, mr = testing_helpers.GetRequestObjects( |
| 209 headers={'Host': 'www.test.com'}, path=path) |
| 210 url = framework_helpers.FormatAbsoluteURL(mr, path, include_project=False) |
| 211 self.assertEqual(url, 'http://www.test.com/some/path') |
| 212 |
| 213 |
| 214 class WordWrapSuperLongLinesTest(unittest.TestCase): |
| 215 |
| 216 def testEmptyLogMessage(self): |
| 217 msg = '' |
| 218 wrapped_msg = framework_helpers.WordWrapSuperLongLines(msg) |
| 219 self.assertEqual(wrapped_msg, '') |
| 220 |
| 221 def testShortLines(self): |
| 222 msg = 'one\ntwo\nthree\n' |
| 223 wrapped_msg = framework_helpers.WordWrapSuperLongLines(msg) |
| 224 expected = 'one\ntwo\nthree\n' |
| 225 self.assertEqual(wrapped_msg, expected) |
| 226 |
| 227 def testOneLongLine(self): |
| 228 msg = ('This is a super long line that just goes on and on ' |
| 229 'and it seems like it will never stop because it is ' |
| 230 'super long and it was entered by a user who had no ' |
| 231 'familiarity with the return key.') |
| 232 wrapped_msg = framework_helpers.WordWrapSuperLongLines(msg) |
| 233 expected = ('This is a super long line that just goes on and on and it ' |
| 234 'seems like it will never stop because it\n' |
| 235 'is super long and it was entered by a user who had no ' |
| 236 'familiarity with the return key.') |
| 237 self.assertEqual(wrapped_msg, expected) |
| 238 |
| 239 msg2 = ('This is a super long line that just goes on and on ' |
| 240 'and it seems like it will never stop because it is ' |
| 241 'super long and it was entered by a user who had no ' |
| 242 'familiarity with the return key. ' |
| 243 'This is a super long line that just goes on and on ' |
| 244 'and it seems like it will never stop because it is ' |
| 245 'super long and it was entered by a user who had no ' |
| 246 'familiarity with the return key.') |
| 247 wrapped_msg2 = framework_helpers.WordWrapSuperLongLines(msg2) |
| 248 expected2 = ('This is a super long line that just goes on and on and it ' |
| 249 'seems like it will never stop because it\n' |
| 250 'is super long and it was entered by a user who had no ' |
| 251 'familiarity with the return key. This is a\n' |
| 252 'super long line that just goes on and on and it seems like ' |
| 253 'it will never stop because it is super\n' |
| 254 'long and it was entered by a user who had no familiarity ' |
| 255 'with the return key.') |
| 256 self.assertEqual(wrapped_msg2, expected2) |
| 257 |
| 258 def testMixOfShortAndLong(self): |
| 259 msg = ('[Author: mpcomplete]\n' |
| 260 '\n' |
| 261 # Description on one long line |
| 262 'Fix a memory leak in JsArray and JsObject for the IE and NPAPI ' |
| 263 'ports. Each time you call GetElement* or GetProperty* to ' |
| 264 'retrieve string or object token, the token would be leaked. ' |
| 265 'I added a JsScopedToken to ensure that the right thing is ' |
| 266 'done when the object leaves scope, depending on the platform.\n' |
| 267 '\n' |
| 268 'R=zork\n' |
| 269 'CC=google-gears-eng@googlegroups.com\n' |
| 270 'DELTA=108 (52 added, 36 deleted, 20 changed)\n' |
| 271 'OCL=5932446\n' |
| 272 'SCL=5933728\n') |
| 273 wrapped_msg = framework_helpers.WordWrapSuperLongLines(msg) |
| 274 expected = ( |
| 275 '[Author: mpcomplete]\n' |
| 276 '\n' |
| 277 'Fix a memory leak in JsArray and JsObject for the IE and NPAPI ' |
| 278 'ports. Each time you call\n' |
| 279 'GetElement* or GetProperty* to retrieve string or object token, the ' |
| 280 'token would be leaked. I added\n' |
| 281 'a JsScopedToken to ensure that the right thing is done when the ' |
| 282 'object leaves scope, depending on\n' |
| 283 'the platform.\n' |
| 284 '\n' |
| 285 'R=zork\n' |
| 286 'CC=google-gears-eng@googlegroups.com\n' |
| 287 'DELTA=108 (52 added, 36 deleted, 20 changed)\n' |
| 288 'OCL=5932446\n' |
| 289 'SCL=5933728\n') |
| 290 self.assertEqual(wrapped_msg, expected) |
| 291 |
| 292 |
| 293 class ComputeListDeltasTest(unittest.TestCase): |
| 294 |
| 295 def DoOne(self, old=None, new=None, added=None, removed=None): |
| 296 """Run one call to the target method and check expected results.""" |
| 297 actual_added, actual_removed = framework_helpers.ComputeListDeltas( |
| 298 old, new) |
| 299 self.assertItemsEqual(added, actual_added) |
| 300 self.assertItemsEqual(removed, actual_removed) |
| 301 |
| 302 def testEmptyLists(self): |
| 303 self.DoOne(old=[], new=[], added=[], removed=[]) |
| 304 self.DoOne(old=[1, 2], new=[], added=[], removed=[1, 2]) |
| 305 self.DoOne(old=[], new=[1, 2], added=[1, 2], removed=[]) |
| 306 |
| 307 def testUnchanged(self): |
| 308 self.DoOne(old=[1], new=[1], added=[], removed=[]) |
| 309 self.DoOne(old=[1, 2], new=[1, 2], added=[], removed=[]) |
| 310 self.DoOne(old=[1, 2], new=[2, 1], added=[], removed=[]) |
| 311 |
| 312 def testCompleteChange(self): |
| 313 self.DoOne(old=[1, 2], new=[3, 4], added=[3, 4], removed=[1, 2]) |
| 314 |
| 315 def testGeneralChange(self): |
| 316 self.DoOne(old=[1, 2], new=[2], added=[], removed=[1]) |
| 317 self.DoOne(old=[1], new=[1, 2], added=[2], removed=[]) |
| 318 self.DoOne(old=[1, 2], new=[2, 3], added=[3], removed=[1]) |
| 319 |
| 320 |
| 321 class UserSettingsTest(unittest.TestCase): |
| 322 |
| 323 def testGatherUnifiedSettingsPageData(self): |
| 324 email_options = [] |
| 325 |
| 326 class UserSettingsStub(framework_helpers.UserSettings): |
| 327 |
| 328 # pylint: disable=unused-argument |
| 329 @classmethod |
| 330 def _GetEmailOptions(cls, user_view, conn_pool): |
| 331 return email_options |
| 332 |
| 333 mr = testing_helpers.MakeMonorailRequest() |
| 334 mr.auth.user_view = framework_views.UserView(100, 'user@invalid', True) |
| 335 mr.auth.user_view.profile_url = '/u/profile/url' |
| 336 page_data = UserSettingsStub.GatherUnifiedSettingsPageData( |
| 337 mr.auth.user_id, mr.auth.user_view, mr.auth.user_pb) |
| 338 |
| 339 expected_keys = [ |
| 340 'api_request_reset', |
| 341 'api_request_lifetime_limit', |
| 342 'api_request_hard_limit', |
| 343 'api_request_soft_limit', |
| 344 'settings_user', |
| 345 'settings_user_pb', |
| 346 'settings_user_is_banned', |
| 347 'settings_user_ignore_action_limits', |
| 348 'self', |
| 349 'project_creation_reset', |
| 350 'issue_comment_reset', |
| 351 'issue_attachment_reset', |
| 352 'issue_bulk_edit_reset', |
| 353 'project_creation_lifetime_limit', |
| 354 'project_creation_soft_limit', |
| 355 'project_creation_hard_limit', |
| 356 'issue_comment_lifetime_limit', |
| 357 'issue_comment_soft_limit', |
| 358 'issue_comment_hard_limit', |
| 359 'issue_attachment_lifetime_limit', |
| 360 'issue_attachment_soft_limit', |
| 361 'issue_attachment_hard_limit', |
| 362 'issue_bulk_edit_lifetime_limit', |
| 363 'issue_bulk_edit_hard_limit', |
| 364 'issue_bulk_edit_soft_limit', |
| 365 'profile_url_fragment', |
| 366 'preview_on_hover', |
| 367 ] |
| 368 self.assertItemsEqual(expected_keys, page_data.keys()) |
| 369 |
| 370 self.assertEqual('profile/url', page_data['profile_url_fragment']) |
| 371 # TODO(jrobbins): Test action limit support |
| 372 |
| 373 # TODO(jrobbins): Test ProcessForm. |
| 374 |
| 375 |
| 376 class MurmurHash3Test(unittest.TestCase): |
| 377 |
| 378 def testMurmurHash(self): |
| 379 test_data = [ |
| 380 ('', 0), |
| 381 ('agable@chromium.org', 4092810879), |
| 382 (u'jrobbins@chromium.org', 904770043), |
| 383 ('seanmccullough%google.com@gtempaccount.com', 1301269279), |
| 384 ('rmistry+monorail@chromium.org', 4186878788), |
| 385 ('jparent+foo@', 2923900874), |
| 386 ('@example.com', 3043483168), |
| 387 ] |
| 388 hashes = [framework_helpers.MurmurHash3_x86_32(x) |
| 389 for (x, _) in test_data] |
| 390 self.assertListEqual(hashes, [e for (_, e) in test_data]) |
| 391 |
| 392 def testMurmurHashWithSeed(self): |
| 393 test_data = [ |
| 394 ('', 1113155926, 2270882445), |
| 395 ('agable@chromium.org', 772936925, 3995066671), |
| 396 (u'jrobbins@chromium.org', 1519359761, 1273489513), |
| 397 ('seanmccullough%google.com@gtempaccount.com', 49913829, 1202521153), |
| 398 ('rmistry+monorail@chromium.org', 314860298, 3636123309), |
| 399 ('jparent+foo@', 195791379, 332453977), |
| 400 ('@example.com', 521490555, 257496459), |
| 401 ] |
| 402 hashes = [framework_helpers.MurmurHash3_x86_32(x, s) |
| 403 for (x, s, _) in test_data] |
| 404 self.assertListEqual(hashes, [e for (_, _, e) in test_data]) |
| 405 |
| 406 |
| 407 class MakeRandomKeyTest(unittest.TestCase): |
| 408 |
| 409 def testMakeRandomKey_Normal(self): |
| 410 key1 = framework_helpers.MakeRandomKey() |
| 411 key2 = framework_helpers.MakeRandomKey() |
| 412 self.assertEqual(128, len(key1)) |
| 413 self.assertEqual(128, len(key2)) |
| 414 self.assertNotEqual(key1, key2) |
| 415 |
| 416 def testMakeRandomKey_Length(self): |
| 417 key = framework_helpers.MakeRandomKey() |
| 418 self.assertEqual(128, len(key)) |
| 419 key16 = framework_helpers.MakeRandomKey(length=16) |
| 420 self.assertEqual(16, len(key16)) |
| 421 |
| 422 def testMakeRandomKey_Chars(self): |
| 423 key = framework_helpers.MakeRandomKey(chars='a', length=4) |
| 424 self.assertEqual('aaaa', key) |
| 425 |
| 426 |
| 427 class IsServiceAccountTest(unittest.TestCase): |
| 428 |
| 429 def testIsServiceAccount(self): |
| 430 appspot = 'abc@appspot.gserviceaccount.com' |
| 431 developer = '@developer.gserviceaccount.com' |
| 432 bugdroid = 'bugdroid1@chromium.org' |
| 433 user = 'test@example.com' |
| 434 |
| 435 self.assertTrue(framework_helpers.IsServiceAccount(appspot)) |
| 436 self.assertTrue(framework_helpers.IsServiceAccount(developer)) |
| 437 self.assertTrue(framework_helpers.IsServiceAccount(bugdroid)) |
| 438 self.assertFalse(framework_helpers.IsServiceAccount(user)) |
| 439 |
| 440 |
| 441 if __name__ == '__main__': |
| 442 unittest.main() |
OLD | NEW |