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 servlet base class module.""" |
| 7 |
| 8 import time |
| 9 import unittest |
| 10 |
| 11 from google.appengine.ext import testbed |
| 12 |
| 13 import webapp2 |
| 14 |
| 15 from framework import framework_constants |
| 16 from framework import servlet |
| 17 from framework import xsrf |
| 18 from proto import project_pb2 |
| 19 from proto import tracker_pb2 |
| 20 from services import service_manager |
| 21 from testing import fake |
| 22 from testing import testing_helpers |
| 23 |
| 24 |
| 25 class TestableServlet(servlet.Servlet): |
| 26 """A tiny concrete subclass of abstract class Servlet.""" |
| 27 |
| 28 def __init__(self, request, response, services=None, do_post_redirect=True): |
| 29 super(TestableServlet, self).__init__(request, response, services=services) |
| 30 self.do_post_redirect = do_post_redirect |
| 31 self.seen_post_data = None |
| 32 |
| 33 def ProcessFormData(self, _mr, post_data): |
| 34 self.seen_post_data = post_data |
| 35 if self.do_post_redirect: |
| 36 return '/This/Is?The=Next#Page' |
| 37 else: |
| 38 self.response.write('sending raw data to browser') |
| 39 |
| 40 |
| 41 class ServletTest(unittest.TestCase): |
| 42 |
| 43 def setUp(self): |
| 44 services = service_manager.Services(project=fake.ProjectService()) |
| 45 self.page_class = TestableServlet( |
| 46 webapp2.Request.blank('/'), webapp2.Response(), services=services) |
| 47 self.testbed = testbed.Testbed() |
| 48 self.testbed.activate() |
| 49 self.testbed.init_user_stub() |
| 50 self.testbed.init_memcache_stub() |
| 51 self.testbed.init_datastore_v3_stub() |
| 52 |
| 53 def testDefaultValues(self): |
| 54 self.assertEqual(None, self.page_class._MAIN_TAB_MODE) |
| 55 self.assertTrue(self.page_class._TEMPLATE_PATH.endswith('/templates/')) |
| 56 self.assertEqual(None, self.page_class._PAGE_TEMPLATE) |
| 57 |
| 58 def testGatherBaseData(self): |
| 59 project = fake.Project( |
| 60 project_name='testproj', cached_content_timestamp=12345, |
| 61 state=project_pb2.ProjectState.LIVE) |
| 62 |
| 63 (_request, mr) = testing_helpers.GetRequestObjects( |
| 64 path='/p/testproj/feeds', project=project) |
| 65 nonce = '1a2b3c4d5e6f7g' |
| 66 |
| 67 base_data = self.page_class.GatherBaseData(mr, nonce) |
| 68 |
| 69 self.assertEqual(base_data['nonce'], nonce) |
| 70 self.assertEqual(base_data['projectname'], 'testproj') |
| 71 self.assertEqual(base_data['project'].cached_content_timestamp, 12345) |
| 72 self.assertEqual(base_data['project_alert'], None) |
| 73 |
| 74 self.assert_( |
| 75 base_data['currentPageURL'].endswith('/p/testproj/feeds')) |
| 76 self.assert_( |
| 77 base_data['currentPageURLEncoded'].endswith('%2Fp%2Ftestproj%2Ffeeds')) |
| 78 |
| 79 def testFormHandlerURL(self): |
| 80 self.assertEqual('/edit.do', self.page_class._FormHandlerURL('/')) |
| 81 self.assertEqual( |
| 82 '/something/edit.do', |
| 83 self.page_class._FormHandlerURL('/something/')) |
| 84 self.assertEqual( |
| 85 '/something/edit.do', |
| 86 self.page_class._FormHandlerURL('/something/edit.do')) |
| 87 self.assertEqual( |
| 88 '/something/detail.do', |
| 89 self.page_class._FormHandlerURL('/something/detail')) |
| 90 |
| 91 def testProcessForm_NoToken(self): |
| 92 user_id = 111L |
| 93 request, mr = testing_helpers.GetRequestObjects( |
| 94 path='/we/we/we?so=excited', |
| 95 params={'yesterday': 'thursday', 'today': 'friday'}, |
| 96 user_info={'user_id': user_id}, |
| 97 method='POST', |
| 98 ) |
| 99 # Normally, every form needs a security token. |
| 100 self.assertRaises( |
| 101 xsrf.TokenIncorrect, self.page_class._DoFormProcessing, request, mr) |
| 102 self.assertEqual(None, self.page_class.seen_post_data) |
| 103 |
| 104 # We can make an explicit exception to that. |
| 105 self.page_class.CHECK_SECURITY_TOKEN = False |
| 106 try: |
| 107 self.page_class._DoFormProcessing(request, mr) |
| 108 self.fail() |
| 109 except webapp2.HTTPException as e: |
| 110 self.assertEqual(302, e.code) # forms redirect on succcess |
| 111 |
| 112 self.assertDictEqual( |
| 113 {'yesterday': 'thursday', 'today': 'friday'}, |
| 114 dict(self.page_class.seen_post_data)) |
| 115 |
| 116 def testProcessForm_BadToken(self): |
| 117 |
| 118 user_id = 111L |
| 119 token = 'no soup for you' |
| 120 |
| 121 request, mr = testing_helpers.GetRequestObjects( |
| 122 path='/we/we/we?so=excited', |
| 123 params={'yesterday': 'thursday', 'today': 'friday', 'token': token}, |
| 124 user_info={'user_id': user_id}, |
| 125 method='POST', |
| 126 ) |
| 127 self.assertRaises( |
| 128 xsrf.TokenIncorrect, self.page_class._DoFormProcessing, request, mr) |
| 129 self.assertEqual(None, self.page_class.seen_post_data) |
| 130 |
| 131 def testProcessForm_Normal(self): |
| 132 user_id = 111L |
| 133 token = xsrf.GenerateToken(user_id, '/we/we/we') |
| 134 |
| 135 request, mr = testing_helpers.GetRequestObjects( |
| 136 path='/we/we/we?so=excited', |
| 137 params={'yesterday': 'thursday', 'today': 'friday', 'token': token}, |
| 138 user_info={'user_id': user_id}, |
| 139 method='POST', |
| 140 ) |
| 141 try: |
| 142 self.page_class._DoFormProcessing(request, mr) |
| 143 self.fail() |
| 144 except webapp2.HTTPException as e: |
| 145 self.assertEqual(302, e.code) # forms redirect on succcess |
| 146 |
| 147 self.assertDictEqual( |
| 148 {'yesterday': 'thursday', 'today': 'friday', 'token': token}, |
| 149 dict(self.page_class.seen_post_data)) |
| 150 |
| 151 def testCalcProjectAlert(self): |
| 152 project = fake.Project( |
| 153 project_name='alerttest', state=project_pb2.ProjectState.LIVE) |
| 154 |
| 155 project_alert = servlet._CalcProjectAlert(project) |
| 156 self.assertEqual(project_alert, None) |
| 157 |
| 158 project.state = project_pb2.ProjectState.ARCHIVED |
| 159 project_alert = servlet._CalcProjectAlert(project) |
| 160 self.assertEqual( |
| 161 project_alert, |
| 162 'Project is archived: read-only by members only.') |
| 163 |
| 164 delete_time = int(time.time() + framework_constants.SECS_PER_DAY * 1.5) |
| 165 project.delete_time = delete_time |
| 166 project_alert = servlet._CalcProjectAlert(project) |
| 167 self.assertEqual(project_alert, 'Scheduled for deletion in 1 day.') |
| 168 |
| 169 delete_time = int(time.time() + framework_constants.SECS_PER_DAY * 2.5) |
| 170 project.delete_time = delete_time |
| 171 project_alert = servlet._CalcProjectAlert(project) |
| 172 self.assertEqual(project_alert, 'Scheduled for deletion in 2 days.') |
| 173 |
| 174 def testCheckForMovedProject_NoRedirect(self): |
| 175 project = fake.Project( |
| 176 project_name='proj', state=project_pb2.ProjectState.LIVE) |
| 177 request, mr = testing_helpers.GetRequestObjects( |
| 178 path='/p/proj', project=project) |
| 179 self.page_class._CheckForMovedProject(mr, request) |
| 180 |
| 181 request, mr = testing_helpers.GetRequestObjects( |
| 182 path='/p/proj/source/browse/p/adminAdvanced', project=project) |
| 183 self.page_class._CheckForMovedProject(mr, request) |
| 184 |
| 185 def testCheckForMovedProject_Redirect(self): |
| 186 project = fake.Project(project_name='proj', moved_to='http://example.com') |
| 187 request, mr = testing_helpers.GetRequestObjects( |
| 188 path='/p/proj', project=project) |
| 189 try: |
| 190 self.page_class._CheckForMovedProject(mr, request) |
| 191 self.fail() |
| 192 except webapp2.HTTPException as e: |
| 193 self.assertEqual(302, e.code) # redirect because project moved |
| 194 |
| 195 request, mr = testing_helpers.GetRequestObjects( |
| 196 path='/p/proj/source/browse/p/adminAdvanced', project=project) |
| 197 try: |
| 198 self.page_class._CheckForMovedProject(mr, request) |
| 199 self.fail() |
| 200 except webapp2.HTTPException as e: |
| 201 self.assertEqual(302, e.code) # redirect because project moved |
| 202 |
| 203 def testCheckForMovedProject_AdminAdvanced(self): |
| 204 """We do not redirect away from the page that edits project state.""" |
| 205 project = fake.Project(project_name='proj', moved_to='http://example.com') |
| 206 request, mr = testing_helpers.GetRequestObjects( |
| 207 path='/p/proj/adminAdvanced', project=project) |
| 208 self.page_class._CheckForMovedProject(mr, request) |
| 209 |
| 210 request, mr = testing_helpers.GetRequestObjects( |
| 211 path='/p/proj/adminAdvanced?ts=123234', project=project) |
| 212 self.page_class._CheckForMovedProject(mr, request) |
| 213 |
| 214 request, mr = testing_helpers.GetRequestObjects( |
| 215 path='/p/proj/adminAdvanced.do', project=project) |
| 216 self.page_class._CheckForMovedProject(mr, request) |
| 217 |
| 218 def testGatherHelpData(self): |
| 219 help_data = self.page_class.GatherHelpData('fake mr', {}) |
| 220 self.assertEqual(None, help_data['cue']) |
| 221 |
| 222 def testGatherDebugData_Visibility(self): |
| 223 project = fake.Project( |
| 224 project_name='testtest', state=project_pb2.ProjectState.LIVE) |
| 225 _request, mr = testing_helpers.GetRequestObjects( |
| 226 path='/p/foo/servlet_path', project=project) |
| 227 debug_data = self.page_class.GatherDebugData(mr, {}) |
| 228 self.assertEqual('off', debug_data['dbg']) |
| 229 |
| 230 _request, mr = testing_helpers.GetRequestObjects( |
| 231 path='/p/foo/servlet_path?debug=1', project=project) |
| 232 debug_data = self.page_class.GatherDebugData(mr, {}) |
| 233 self.assertEqual('on', debug_data['dbg']) |
| 234 |
| 235 |
| 236 class ProjectIsRestrictedTest(unittest.TestCase): |
| 237 |
| 238 def testNonRestrictedProject(self): |
| 239 proj = project_pb2.Project() |
| 240 mr = testing_helpers.MakeMonorailRequest() |
| 241 mr.project = proj |
| 242 |
| 243 proj.access = project_pb2.ProjectAccess.ANYONE |
| 244 proj.state = project_pb2.ProjectState.LIVE |
| 245 self.assertFalse(servlet._ProjectIsRestricted(mr)) |
| 246 |
| 247 proj.state = project_pb2.ProjectState.ARCHIVED |
| 248 self.assertFalse(servlet._ProjectIsRestricted(mr)) |
| 249 |
| 250 def testRestrictedProject(self): |
| 251 proj = project_pb2.Project() |
| 252 mr = testing_helpers.MakeMonorailRequest() |
| 253 mr.project = proj |
| 254 |
| 255 proj.state = project_pb2.ProjectState.LIVE |
| 256 proj.access = project_pb2.ProjectAccess.MEMBERS_ONLY |
| 257 self.assertTrue(servlet._ProjectIsRestricted(mr)) |
| 258 |
| 259 |
| 260 FORM_URL = 'http://example.com/issues/form.php' |
| 261 |
| 262 |
| 263 class ComputeIssueEntryURLTest(unittest.TestCase): |
| 264 |
| 265 def setUp(self): |
| 266 self.project = project_pb2.Project() |
| 267 self.project.project_name = 'proj' |
| 268 self.config = tracker_pb2.ProjectIssueConfig() |
| 269 self.testbed = testbed.Testbed() |
| 270 self.testbed.activate() |
| 271 self.testbed.init_user_stub() |
| 272 self.testbed.init_memcache_stub() |
| 273 self.testbed.init_datastore_v3_stub() |
| 274 |
| 275 def testComputeIssueEntryURL_Normal(self): |
| 276 _request, mr = testing_helpers.GetRequestObjects( |
| 277 path='/p/proj/issues/detail?id=123&q=term', |
| 278 project=self.project) |
| 279 |
| 280 url = servlet._ComputeIssueEntryURL(mr, self.config) |
| 281 self.assertEqual('entry', url) |
| 282 |
| 283 def testComputeIssueEntryURL_Customized(self): |
| 284 _request, mr = testing_helpers.GetRequestObjects( |
| 285 path='/p/proj/issues/detail?id=123&q=term', |
| 286 project=self.project) |
| 287 mr.auth.user_id = 111L |
| 288 self.config.custom_issue_entry_url = FORM_URL |
| 289 |
| 290 url = servlet._ComputeIssueEntryURL(mr, self.config) |
| 291 self.assertTrue(url.startswith(FORM_URL)) |
| 292 self.assertIn('token=', url) |
| 293 self.assertIn('role=', url) |
| 294 self.assertIn('continue=', url) |
| 295 |
| 296 |
| 297 if __name__ == '__main__': |
| 298 unittest.main() |
OLD | NEW |