Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1132)

Side by Side Diff: appengine/monorail/framework/test/monorailrequest_test.py

Issue 1868553004: Open Source Monorail (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Rebase Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 monorailrequest module."""
7
8 import re
9 import unittest
10
11 import mox
12
13 from google.appengine.api import users
14
15 import webapp2
16
17 from framework import monorailrequest
18 from framework import permissions
19 from framework import profiler
20 from proto import project_pb2
21 from proto import tracker_pb2
22 from services import service_manager
23 from testing import fake
24 from testing import testing_helpers
25 from tracker import tracker_constants
26
27
28 class HostportReTest(unittest.TestCase):
29
30 def testGood(self):
31 test_data = [
32 'localhost:8080',
33 'app.appspot.com',
34 'bugs-staging.chromium.org',
35 'vers10n-h3x-dot-app-id.appspot.com',
36 ]
37 for hostport in test_data:
38 self.assertTrue(monorailrequest._HOSTPORT_RE.match(hostport),
39 msg='Incorrectly rejected %r' % hostport)
40
41 def testBad(self):
42 test_data = [
43 '',
44 ' ',
45 '\t',
46 '\n',
47 '\'',
48 '"',
49 'version"cruft-dot-app-id.appspot.com',
50 '\nother header',
51 'version&cruft-dot-app-id.appspot.com',
52 ]
53 for hostport in test_data:
54 self.assertFalse(monorailrequest._HOSTPORT_RE.match(hostport),
55 msg='Incorrectly accepted %r' % hostport)
56
57 class AuthDataTest(unittest.TestCase):
58
59 def setUp(self):
60 self.mox = mox.Mox()
61
62 def tearDown(self):
63 self.mox.UnsetStubs()
64
65 def testGetUserID(self):
66 pass # TODO(jrobbins): re-impement
67
68 def testExamineRequestUserID(self):
69 pass # TODO(jrobbins): re-implement
70
71
72 class MonorailRequestUnitTest(unittest.TestCase):
73
74 def setUp(self):
75 self.services = service_manager.Services(
76 project=fake.ProjectService(),
77 user=fake.UserService(),
78 usergroup=fake.UserGroupService())
79 self.project = self.services.project.TestAddProject('proj')
80 self.services.user.TestAddUser('jrobbins@example.com', 111)
81
82 self.profiler = profiler.Profiler()
83 self.mox = mox.Mox()
84 self.mox.StubOutWithMock(users, 'get_current_user')
85 users.get_current_user().AndReturn(None)
86 self.mox.ReplayAll()
87
88 def tearDown(self):
89 self.mox.UnsetStubs()
90
91 def testGetIntParamConvertsQueryParamToInt(self):
92 notice_id = 12345
93 mr = testing_helpers.MakeMonorailRequest(
94 path='/foo?notice=%s' % notice_id)
95
96 value = mr.GetIntParam('notice')
97 self.assert_(isinstance(value, int))
98 self.assertEqual(notice_id, value)
99
100 def testGetIntParamConvertsQueryParamToLong(self):
101 notice_id = 12345678901234567890
102 mr = testing_helpers.MakeMonorailRequest(
103 path='/foo?notice=%s' % notice_id)
104
105 value = mr.GetIntParam('notice')
106 self.assertTrue(isinstance(value, long))
107 self.assertEqual(notice_id, value)
108
109 def testGetIntListParamNoParam(self):
110 mr = monorailrequest.MonorailRequest()
111 mr.ParseRequest(
112 webapp2.Request.blank('servlet'), self.services, self.profiler)
113 self.assertEquals(mr.GetIntListParam('ids'), None)
114 self.assertEquals(mr.GetIntListParam('ids', default_value=['test']),
115 ['test'])
116
117 def testGetIntListParamOneValue(self):
118 mr = monorailrequest.MonorailRequest()
119 mr.ParseRequest(
120 webapp2.Request.blank('servlet?ids=11'), self.services, self.profiler)
121 self.assertEquals(mr.GetIntListParam('ids'), [11])
122 self.assertEquals(mr.GetIntListParam('ids', default_value=['test']),
123 [11])
124
125 def testGetIntListParamMultiValue(self):
126 mr = monorailrequest.MonorailRequest()
127 mr.ParseRequest(
128 webapp2.Request.blank('servlet?ids=21,22,23'), self.services,
129 self.profiler)
130 self.assertEquals(mr.GetIntListParam('ids'), [21, 22, 23])
131 self.assertEquals(mr.GetIntListParam('ids', default_value=['test']),
132 [21, 22, 23])
133
134 def testGetIntListParamBogusValue(self):
135 mr = monorailrequest.MonorailRequest()
136 mr.ParseRequest(
137 webapp2.Request.blank('servlet?ids=not_an_int'), self.services,
138 self.profiler)
139 self.assertEquals(mr.GetIntListParam('ids'), None)
140 self.assertEquals(mr.GetIntListParam('ids', default_value=['test']),
141 ['test'])
142
143 def testGetIntListParamMalformed(self):
144 mr = monorailrequest.MonorailRequest()
145 mr.ParseRequest(
146 webapp2.Request.blank('servlet?ids=31,32,,'), self.services,
147 self.profiler)
148 self.assertEquals(mr.GetIntListParam('ids'), None)
149 self.assertEquals(mr.GetIntListParam('ids', default_value=['test']),
150 ['test'])
151
152 def testDefaultValuesNoUrl(self):
153 """If request has no param, default param values should be used."""
154 mr = monorailrequest.MonorailRequest()
155 mr.ParseRequest(
156 webapp2.Request.blank('servlet'), self.services, self.profiler)
157 self.assertEquals(mr.GetParam('r', 3), 3)
158 self.assertEquals(mr.GetIntParam('r', 3), 3)
159 self.assertEquals(mr.GetPositiveIntParam('r', 3), 3)
160 self.assertEquals(mr.GetIntListParam('r', [3, 4]), [3, 4])
161
162 def _MRWithMockRequest(
163 self, path, headers=None, *mr_args, **mr_kwargs):
164 request = webapp2.Request.blank(path, headers=headers)
165 mr = monorailrequest.MonorailRequest(*mr_args, **mr_kwargs)
166 mr.ParseRequest(request, self.services, self.profiler)
167 return mr
168
169 def testParseQueryParameters(self):
170 mr = self._MRWithMockRequest(
171 '/p/proj/issues/list?q=foo+OR+bar&num=50')
172 self.assertEquals('foo OR bar', mr.query)
173 self.assertEquals(50, mr.num)
174
175 def testParseRequest_Scheme(self):
176 mr = self._MRWithMockRequest('/p/proj/')
177 self.assertEquals('http', mr.request.scheme)
178
179 def testParseRequest_HostportAndCurrentPageURL(self):
180 mr = self._MRWithMockRequest('/p/proj/', headers={
181 'Host': 'example.com',
182 'Cookie': 'asdf',
183 })
184 self.assertEquals('http', mr.request.scheme)
185 self.assertEquals('example.com', mr.request.host)
186 self.assertEquals('http://example.com/p/proj/', mr.current_page_url)
187
188 def testViewedUser_WithEmail(self):
189 mr = self._MRWithMockRequest('/u/jrobbins@example.com/')
190 self.assertEquals('jrobbins@example.com', mr.viewed_username)
191 self.assertEquals(111, mr.viewed_user_auth.user_id)
192 self.assertEquals(
193 self.services.user.GetUser('fake cnxn', 111),
194 mr.viewed_user_auth.user_pb)
195
196 def testViewedUser_WithUserID(self):
197 mr = self._MRWithMockRequest('/u/111/')
198 self.assertEquals('jrobbins@example.com', mr.viewed_username)
199 self.assertEquals(111, mr.viewed_user_auth.user_id)
200 self.assertEquals(
201 self.services.user.GetUser('fake cnxn', 111),
202 mr.viewed_user_auth.user_pb)
203
204 def testViewedUser_NoSuchEmail(self):
205 try:
206 self._MRWithMockRequest('/u/unknownuser@example.com/')
207 self.fail()
208 except webapp2.HTTPException as e:
209 self.assertEquals(404, e.code)
210
211 def testViewedUser_NoSuchUserID(self):
212 with self.assertRaises(webapp2.HTTPException) as e:
213 self._MRWithMockRequest('/u/234521111/')
214 self.assertEquals(404, e.code)
215
216 def testGetParam(self):
217 mr = testing_helpers.MakeMonorailRequest(
218 path='/foo?syn=error!&a=a&empty=',
219 params=dict(over1='over_value1', over2='over_value2'))
220
221 # test tampering
222 self.assertRaises(monorailrequest.InputException, mr.GetParam, 'a',
223 antitamper_re=re.compile(r'^$'))
224 self.assertRaises(monorailrequest.InputException, mr.GetParam,
225 'undefined', default_value='default',
226 antitamper_re=re.compile(r'^$'))
227
228 # test empty value
229 self.assertEquals('', mr.GetParam(
230 'empty', default_value='default', antitamper_re=re.compile(r'^$')))
231
232 # test default
233 self.assertEquals('default', mr.GetParam(
234 'undefined', default_value='default'))
235
236 def testComputeColSpec(self):
237 # No config passed, and nothing in URL
238 mr = testing_helpers.MakeMonorailRequest(
239 path='/p/proj/issues/detail?id=123')
240 mr.ComputeColSpec(None)
241 self.assertEquals(tracker_constants.DEFAULT_COL_SPEC, mr.col_spec)
242
243 # No config passed, but set in URL
244 mr = testing_helpers.MakeMonorailRequest(
245 path='/p/proj/issues/detail?id=123&colspec=a b C')
246 mr.ComputeColSpec(None)
247 self.assertEquals('a b C', mr.col_spec)
248
249 config = tracker_pb2.ProjectIssueConfig()
250
251 # No default in the config, and nothing in URL
252 mr = testing_helpers.MakeMonorailRequest(
253 path='/p/proj/issues/detail?id=123')
254 mr.ComputeColSpec(config)
255 self.assertEquals(tracker_constants.DEFAULT_COL_SPEC, mr.col_spec)
256
257 # No default in the config, but set in URL
258 mr = testing_helpers.MakeMonorailRequest(
259 path='/p/proj/issues/detail?id=123&colspec=a b C')
260 mr.ComputeColSpec(config)
261 self.assertEquals('a b C', mr.col_spec)
262
263 config.default_col_spec = 'd e f'
264
265 # Default in the config, and nothing in URL
266 mr = testing_helpers.MakeMonorailRequest(
267 path='/p/proj/issues/detail?id=123')
268 mr.ComputeColSpec(config)
269 self.assertEquals('d e f', mr.col_spec)
270
271 # Default in the config, but overrided via URL
272 mr = testing_helpers.MakeMonorailRequest(
273 path='/p/proj/issues/detail?id=123&colspec=a b C')
274 mr.ComputeColSpec(config)
275 self.assertEquals('a b C', mr.col_spec)
276
277 def testComputeColSpec_XSS(self):
278 config_1 = tracker_pb2.ProjectIssueConfig()
279 config_2 = tracker_pb2.ProjectIssueConfig()
280 config_2.default_col_spec = "id '+alert(1)+'"
281 mr_1 = testing_helpers.MakeMonorailRequest(
282 path='/p/proj/issues/detail?id=123')
283 mr_2 = testing_helpers.MakeMonorailRequest(
284 path="/p/proj/issues/detail?id=123&colspec=id '+alert(1)+'")
285
286 # Normal colspec in config but malicious request
287 self.assertRaises(
288 monorailrequest.InputException,
289 mr_2.ComputeColSpec, config_1)
290
291 # Malicious colspec in config but normal request
292 self.assertRaises(
293 monorailrequest.InputException,
294 mr_1.ComputeColSpec, config_2)
295
296 # Malicious colspec in config and malicious request
297 self.assertRaises(
298 monorailrequest.InputException,
299 mr_2.ComputeColSpec, config_2)
300
301
302 class TestMonorailRequestFunctions(unittest.TestCase):
303
304 def testExtractPathIdenifiers_ProjectOnly(self):
305 username, project_name = monorailrequest._ParsePathIdentifiers(
306 '/p/proj/issues/list?q=foo+OR+bar&ts=1234')
307 self.assertIsNone(username)
308 self.assertEquals('proj', project_name)
309
310 def testExtractPathIdenifiers_ViewedUserOnly(self):
311 username, project_name = monorailrequest._ParsePathIdentifiers(
312 '/u/jrobbins@example.com/')
313 self.assertEquals('jrobbins@example.com', username)
314 self.assertIsNone(project_name)
315
316 def testExtractPathIdenifiers_ViewedUserURLSpace(self):
317 username, project_name = monorailrequest._ParsePathIdentifiers(
318 '/u/jrobbins@example.com/updates')
319 self.assertEquals('jrobbins@example.com', username)
320 self.assertIsNone(project_name)
321
322 def testExtractPathIdenifiers_ViewedGroupURLSpace(self):
323 username, project_name = monorailrequest._ParsePathIdentifiers(
324 '/g/user-group@example.com/updates')
325 self.assertEquals('user-group@example.com', username)
326 self.assertIsNone(project_name)
327
328 def testParseColSpec(self):
329 parse = monorailrequest.ParseColSpec
330 self.assertEqual(['PageName', 'Summary', 'Changed', 'ChangedBy'],
331 parse(u'PageName Summary Changed ChangedBy'))
332 self.assertEqual(['Foo-Bar', 'Foo-Bar-Baz', 'Release-1.2', 'Hey', 'There'],
333 parse('Foo-Bar Foo-Bar-Baz Release-1.2 Hey!There'))
334 self.assertEqual(
335 ['\xe7\xaa\xbf\xe8\x8b\xa5\xe7\xb9\xb9'.decode('utf-8'),
336 '\xe5\x9f\xba\xe5\x9c\xb0\xe3\x81\xaf'.decode('utf-8')],
337 parse('\xe7\xaa\xbf\xe8\x8b\xa5\xe7\xb9\xb9 '
338 '\xe5\x9f\xba\xe5\x9c\xb0\xe3\x81\xaf'.decode('utf-8')))
339
340
341 class TestPermissionLookup(unittest.TestCase):
342 OWNER_ID = 1
343 OTHER_USER_ID = 2
344
345 def setUp(self):
346 self.services = service_manager.Services(
347 project=fake.ProjectService(),
348 user=fake.UserService(),
349 usergroup=fake.UserGroupService())
350 self.services.user.TestAddUser('owner@gmail.com', self.OWNER_ID)
351 self.services.user.TestAddUser('user@gmail.com', self.OTHER_USER_ID)
352 self.live_project = self.services.project.TestAddProject(
353 'live', owner_ids=[self.OWNER_ID])
354 self.archived_project = self.services.project.TestAddProject(
355 'archived', owner_ids=[self.OWNER_ID],
356 state=project_pb2.ProjectState.ARCHIVED)
357 self.members_only_project = self.services.project.TestAddProject(
358 'members-only', owner_ids=[self.OWNER_ID],
359 access=project_pb2.ProjectAccess.MEMBERS_ONLY)
360
361 self.mox = mox.Mox()
362
363 def tearDown(self):
364 self.mox.UnsetStubs()
365
366 def CheckPermissions(self, perms, expect_view, expect_commit, expect_edit):
367 may_view = perms.HasPerm(permissions.VIEW, None, None)
368 self.assertEqual(expect_view, may_view)
369 may_commit = perms.HasPerm(permissions.COMMIT, None, None)
370 self.assertEqual(expect_commit, may_commit)
371 may_edit = perms.HasPerm(permissions.EDIT_PROJECT, None, None)
372 self.assertEqual(expect_edit, may_edit)
373
374 def MakeRequestAsUser(self, project_name, email):
375 self.mox.StubOutWithMock(users, 'get_current_user')
376 users.get_current_user().AndReturn(testing_helpers.Blank(
377 email=lambda: email))
378 self.mox.ReplayAll()
379
380 request = webapp2.Request.blank('/p/' + project_name)
381 mr = monorailrequest.MonorailRequest()
382 prof = profiler.Profiler()
383 with prof.Phase('parse user info'):
384 mr.ParseRequest(request, self.services, prof)
385 return mr
386
387 def testOwnerPermissions_Live(self):
388 mr = self.MakeRequestAsUser('live', 'owner@gmail.com')
389 self.CheckPermissions(mr.perms, True, True, True)
390
391 def testOwnerPermissions_Archived(self):
392 mr = self.MakeRequestAsUser('archived', 'owner@gmail.com')
393 self.CheckPermissions(mr.perms, True, False, True)
394
395 def testOwnerPermissions_MembersOnly(self):
396 mr = self.MakeRequestAsUser('members-only', 'owner@gmail.com')
397 self.CheckPermissions(mr.perms, True, True, True)
398
399 def testExternalUserPermissions_Live(self):
400 mr = self.MakeRequestAsUser('live', 'user@gmail.com')
401 self.CheckPermissions(mr.perms, True, False, False)
402
403 def testExternalUserPermissions_Archived(self):
404 mr = self.MakeRequestAsUser('archived', 'user@gmail.com')
405 self.CheckPermissions(mr.perms, False, False, False)
406
407 def testExternalUserPermissions_MembersOnly(self):
408 mr = self.MakeRequestAsUser('members-only', 'user@gmail.com')
409 self.CheckPermissions(mr.perms, False, False, False)
410
411
412 if __name__ == '__main__':
413 unittest.main()
OLDNEW
« no previous file with comments | « appengine/monorail/framework/test/jsonfeed_test.py ('k') | appengine/monorail/framework/test/paginate_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698