def testGetIntListParam_MultiValue(self): mr = monorailrequest.MonorailRequest() mr.ParseRequest(webapp2.Request.blank('servlet?ids=21,22,23'), self.services, self.profiler) self.assertEquals(mr.GetIntListParam('ids'), [21, 22, 23]) self.assertEquals(mr.GetIntListParam('ids', default_value=['test']), [21, 22, 23])
def testIssueListURL_NotCustomized(self): mr = monorailrequest.MonorailRequest() mr.query = None mr.can = 2 mr.project = self.project mr.config = self.config self.assertEqual('', mr._CalcDefaultQuery())
def testGetIntListParam_NoParam(self): mr = monorailrequest.MonorailRequest() mr.ParseRequest(webapp2.Request.blank('servlet'), self.services, self.profiler) self.assertEquals(mr.GetIntListParam('ids'), None) self.assertEquals(mr.GetIntListParam('ids', default_value=['test']), ['test'])
def testDefaultValuesNoUrl(self): """If request has no param, default param values should be used.""" mr = monorailrequest.MonorailRequest(self.services) mr.ParseRequest(webapp2.Request.blank('servlet'), self.services) self.assertEqual(mr.GetParam('r', 3), 3) self.assertEqual(mr.GetIntParam('r', 3), 3) self.assertEqual(mr.GetPositiveIntParam('r', 3), 3) self.assertEqual(mr.GetIntListParam('r', [3, 4]), [3, 4])
def testIssueListURL_Customized_Member(self): mr = monorailrequest.MonorailRequest() mr.query = None mr.can = 2 mr.project = self.project mr.config = self.config mr.config.member_default_query = 'owner:me' mr.auth = testing_helpers.Blank(effective_ids={111L}) self.assertEqual('owner:me', mr._CalcDefaultQuery())
def setUp(self): project = project_pb2.Project() project.owner_ids.append(111) project.committer_ids.append(222) project.contributor_ids.append(333) project.contributor_ids.append(888) user = user_pb2.User() user.is_site_admin = False self.mr = monorailrequest.MonorailRequest(None) self.mr.project = project self.mr.auth.user_pb = user
def MakeRequestAsUser(self, project_name, email): self.mox.StubOutWithMock(users, 'get_current_user') users.get_current_user().AndReturn( testing_helpers.Blank(email=lambda: email)) self.mox.ReplayAll() request = webapp2.Request.blank('/p/' + project_name) mr = monorailrequest.MonorailRequest() prof = profiler.Profiler() with prof.Phase('parse user info'): mr.ParseRequest(request, self.services, prof) return mr
def testAssertBasePermission(self): """Only permit site admins and users viewing themselves.""" mr = monorailrequest.MonorailRequest() mr.viewed_user_auth.user_id = 111L mr.auth.user_id = 222L self.assertRaises(permissions.PermissionException, self.servlet.AssertBasePermission, mr) mr.auth.user_id = 111L self.servlet.AssertBasePermission(mr) mr.auth.user_id = 222L mr.auth.user_pb.is_site_admin = True self.servlet.AssertBasePermission(mr)
def testAssertBasePermission(self): servlet = banned.Banned('request', 'response', services=self.services) mr = monorailrequest.MonorailRequest(self.services) mr.auth.user_id = 0 # Anon user cannot see banned page. with self.assertRaises(webapp2.HTTPException) as cm: servlet.AssertBasePermission(mr) self.assertEquals(404, cm.exception.code) mr.auth.user_id = 111 # User who is not banned cannot view banned page. with self.assertRaises(webapp2.HTTPException) as cm: servlet.AssertBasePermission(mr) self.assertEquals(404, cm.exception.code) # This should not throw exception. mr.auth.user_pb.banned = 'spammer' servlet.AssertBasePermission(mr)
def _MakeEmailTasks( self, cnxn, project, issue, config, old_owner_id, users_by_id, all_comments, comment, starrer_ids, contributor_could_view, hostport, omit_ids, perms): """Formulate emails to be sent.""" detail_url = framework_helpers.IssueCommentURL( hostport, project, issue.local_id, seq_num=comment.sequence) # TODO(jrobbins): avoid the need to make a MonorailRequest object. mr = monorailrequest.MonorailRequest(self.services) mr.project_name = project.project_name mr.project = project mr.perms = perms # We do not autolink in the emails, so just use an empty # registry of autolink rules. # TODO(jrobbins): offer users an HTML email option w/ autolinks. autolinker = autolink.Autolink() was_created = ezt.boolean(comment.sequence == 0) email_data = { # Pass open_related and closed_related into this method and to # the issue view so that we can show it on new issue email. 'issue': tracker_views.IssueView(issue, users_by_id, config), 'summary': issue.summary, 'comment': tracker_views.IssueCommentView( project.project_name, comment, users_by_id, autolinker, {}, mr, issue), 'comment_text': comment.content, 'detail_url': detail_url, 'was_created': was_created, } # Generate three versions of email body: link-only is just the link, # non-members see some obscured email addresses, and members version has # all full email addresses exposed. body_link_only = self.link_only_email_template.GetResponse( {'detail_url': detail_url, 'was_created': was_created}) body_for_non_members = self.email_template.GetResponse(email_data) framework_views.RevealAllEmails(users_by_id) email_data['comment'] = tracker_views.IssueCommentView( project.project_name, comment, users_by_id, autolinker, {}, mr, issue) body_for_members = self.email_template.GetResponse(email_data) logging.info('link-only body is:\n%r' % body_link_only) logging.info('body for non-members is:\n%r' % body_for_non_members) logging.info('body for members is:\n%r' % body_for_members) commenter_email = users_by_id[comment.user_id].email omit_addrs = set([commenter_email] + [users_by_id[omit_id].email for omit_id in omit_ids]) auth = authdata.AuthData.FromUserID( cnxn, comment.user_id, self.services) commenter_in_project = framework_bizobj.UserIsInProject( project, auth.effective_ids) noisy = tracker_helpers.IsNoisy(len(all_comments) - 1, len(starrer_ids)) # Give each user a bullet-list of all the reasons that apply for that user. group_reason_list = notify_reasons.ComputeGroupReasonList( cnxn, self.services, project, issue, config, users_by_id, omit_addrs, contributor_could_view, noisy=noisy, starrer_ids=starrer_ids, old_owner_id=old_owner_id, commenter_in_project=commenter_in_project) commenter_view = users_by_id[comment.user_id] detail_url = framework_helpers.FormatAbsoluteURLForDomain( hostport, issue.project_name, urls.ISSUE_DETAIL, id=issue.local_id) email_tasks = notify_helpers.MakeBulletedEmailWorkItems( group_reason_list, issue, body_link_only, body_for_non_members, body_for_members, project, hostport, commenter_view, detail_url, seq_num=comment.sequence) return email_tasks
def testIssueListURL_NoProject(self): mr = monorailrequest.MonorailRequest() mr.query = None mr.can = 2 self.assertEqual('', mr._CalcDefaultQuery())
def _MRWithMockRequest(self, path, headers=None, *mr_args, **mr_kwargs): request = webapp2.Request.blank(path, headers=headers) mr = monorailrequest.MonorailRequest(*mr_args, **mr_kwargs) mr.ParseRequest(request, self.services, self.profiler) return mr
def testGetIntListParam_Malformed(self): mr = monorailrequest.MonorailRequest() with self.assertRaises(monorailrequest.InputException): mr.ParseRequest(webapp2.Request.blank('servlet?ids=31,32,,'), self.services, self.profiler)
def testGetIntListParam_BogusValue(self): mr = monorailrequest.MonorailRequest() with self.assertRaises(monorailrequest.InputException): mr.ParseRequest(webapp2.Request.blank('servlet?ids=not_an_int'), self.services, self.profiler)
def _MakeApprovalEmailTasks( self, hostport, issue, project, approval_value, approval_name, comment, users_by_id, user_ids_from_fields, perms): """Formulate emails to be sent.""" # TODO(jojwang): avoid need to make MonorailRequest and autolinker # for comment_view OR make make tracker_views._ParseTextRuns public # and only pass text_runs to email_data. mr = monorailrequest.MonorailRequest(self.services) mr.project_name = project.project_name mr.project = project mr.perms = perms autolinker = autolink.Autolink() approval_url = framework_helpers.IssueCommentURL( hostport, project, issue.local_id, seq_num=comment.sequence) comment_view = tracker_views.IssueCommentView( project.project_name, comment, users_by_id, autolinker, {}, mr, issue) domain_url = framework_helpers.FormatAbsoluteURLForDomain( hostport, project.project_name, '/issues/') commenter_view = users_by_id[comment.user_id] email_data = { 'domain_url': domain_url, 'approval_url': approval_url, 'comment': comment_view, 'issue_local_id': issue.local_id, 'summary': issue.summary, } subject = '%s Approval: %s (Issue %s)' % ( approval_name, issue.summary, issue.local_id) email_body = self.email_template.GetResponse(email_data) body = notify_helpers._TruncateBody(email_body) recipient_ids = self._GetApprovalEmailRecipients( approval_value, comment, issue, user_ids_from_fields, omit_ids=[comment.user_id]) direct, indirect = self.services.usergroup.ExpandAnyGroupEmailRecipients( mr.cnxn, recipient_ids) # group ids were found in recipient_ids. # Re-set recipient_ids to remove group_ids if indirect: recipient_ids = set(direct + indirect) users_by_id.update(framework_views.MakeAllUserViews( mr.cnxn, self.services.user, indirect)) # already contains direct # TODO(jojwang): monorail:3588, refine email contents based on direct # and indirect user_ids returned. email_tasks = [] for rid in recipient_ids: # TODO(jojwang): monorail:3588, add reveal_addr based on # recipient member status from_addr = emailfmt.FormatFromAddr( project, commenter_view=commenter_view, can_reply_to=False) dest_email = users_by_id[rid].email email_tasks.append( dict(from_addr=from_addr, to=dest_email, subject=subject, body=body) ) return email_tasks
def testIssueListURL_NoConfig(self): mr = monorailrequest.MonorailRequest(None) mr.query = None mr.can = 2 mr.project = self.project self.assertEqual('', mr._CalcDefaultQuery())
def testIssueListURL_NotDefaultCan(self): mr = monorailrequest.MonorailRequest(None) mr.query = None mr.can = 1 self.assertEqual('', mr._CalcDefaultQuery())
def testGetIntListParam_OneValue(self): mr = monorailrequest.MonorailRequest(self.services) mr.ParseRequest(webapp2.Request.blank('servlet?ids=11'), self.services) self.assertEqual(mr.GetIntListParam('ids'), [11]) self.assertEqual(mr.GetIntListParam('ids', default_value=['test']), [11])
def dispatch(self): """Do common stuff then dispatch the request to get() or put() methods.""" handler_start_time = time.time() logging.info('\n\n\nRequest handler: %r', self) count0, count1, count2 = gc.get_count() logging.info('gc counts: %d %d %d', count0, count1, count2) GC_COUNT.add(count0, {'generation': 0}) GC_COUNT.add(count1, {'generation': 1}) GC_COUNT.add(count2, {'generation': 2}) self.mr = monorailrequest.MonorailRequest(self.services) self.ratelimiter.CheckStart(self.request) self.response.headers.add('Strict-Transport-Security', 'max-age=31536000; includeSubDomains') if 'X-Cloud-Trace-Context' in self.request.headers: self.mr.profiler.trace_context = ( self.request.headers.get('X-Cloud-Trace-Context')) if trace_service is not None: self.mr.profiler.trace_service = trace_service if self.services.cache_manager: # TODO(jrobbins): don't do this step if invalidation_timestep was # passed via the request and matches our last timestep try: with self.mr.profiler.Phase('distributed invalidation'): self.services.cache_manager.DoDistributedInvalidation( self.mr.cnxn) except MySQLdb.OperationalError as e: logging.exception(e) page_data = { 'http_response_code': httplib.SERVICE_UNAVAILABLE, 'requested_url': self.request.url, } self.template = template_helpers.GetTemplate( 'templates/framework/database-maintenance.ezt', eliminate_blank_lines=self._ELIMINATE_BLANK_LINES) self.template.WriteResponse(self.response, page_data, content_type='text/html') return try: with self.mr.profiler.Phase('parsing request and doing lookups'): self.mr.ParseRequest(self.request, self.services) self.response.headers['X-Frame-Options'] = 'SAMEORIGIN' webapp2.RequestHandler.dispatch(self) except exceptions.NoSuchUserException as e: logging.warning('Trapped NoSuchUserException %s', e) self.abort(404, 'user not found') except exceptions.NoSuchGroupException as e: logging.warning('Trapped NoSuchGroupException %s', e) self.abort(404, 'user group not found') except exceptions.InputException as e: logging.info('Rejecting invalid input: %r', e) self.response.status = httplib.BAD_REQUEST except exceptions.NoSuchProjectException as e: logging.info('Rejecting invalid request: %r', e) self.response.status = httplib.NOT_FOUND except xsrf.TokenIncorrect as e: logging.info('Bad XSRF token: %r', e.message) self.response.status = httplib.BAD_REQUEST except permissions.BannedUserException as e: logging.warning('The user has been banned') url = framework_helpers.FormatAbsoluteURL(self.mr, urls.BANNED, include_project=False, copy_params=False) self.redirect(url, abort=True) except ratelimiter.RateLimitExceeded as e: logging.info('RateLimitExceeded Exception %s', e) self.response.status = httplib.BAD_REQUEST self.response.body = 'Slow your roll.' finally: self.mr.CleanUp() self.ratelimiter.CheckEnd(self.request, time.time(), handler_start_time) total_processing_time = time.time() - handler_start_time logging.warn('Processed request in %d ms', int(total_processing_time * 1000)) end_count0, end_count1, end_count2 = gc.get_count() logging.info('gc counts: %d %d %d', end_count0, end_count1, end_count2) if (end_count0 < count0) or (end_count1 < count1) or (end_count2 < count2): GC_EVENT_REQUEST.increment() if settings.enable_profiler_logging: self.mr.profiler.LogStats() if (self.mr.profiler.trace_context is not None and random.random() < settings.trace_fraction): self.mr.profiler.ReportTrace()
def dispatch(self): """Do common stuff then dispatch the request to get() or put() methods.""" handler_start_time = time.time() logging.info('\n\n\nRequest handler: %r', self) self.mr = monorailrequest.MonorailRequest() self.ratelimiter.CheckStart(self.request) self.response.headers.add('Strict-Transport-Security', 'max-age=31536000; includeSubDomains') if self.services.cache_manager: # TODO(jrobbins): don't do this step if invalidation_timestep was # passed via the request and matches our last timestep try: with self.profiler.Phase('distributed invalidation'): self.services.cache_manager.DoDistributedInvalidation( self.mr.cnxn) except MySQLdb.OperationalError as e: logging.exception(e) page_data = { 'http_response_code': httplib.SERVICE_UNAVAILABLE, 'requested_url': self.request.url, } self.template = template_helpers.GetTemplate( 'templates/framework/database-maintenance.ezt', eliminate_blank_lines=self._ELIMINATE_BLANK_LINES) self.template.WriteResponse(self.response, page_data, content_type='text/html') return try: with self.profiler.Phase('parsing request and doing lookups'): self.mr.ParseRequest(self.request, self.services, self.profiler) self.response.headers['X-Frame-Options'] = 'SAMEORIGIN' webapp2.RequestHandler.dispatch(self) except user_svc.NoSuchUserException as e: logging.warning('Trapped NoSuchUserException %s', e) self.abort(404, 'user not found') except usergroup_svc.NoSuchGroupException as e: logging.warning('Trapped NoSuchGroupException %s', e) self.abort(404, 'user group not found') except monorailrequest.InputException as e: logging.info('Rejecting invalid input: %r', e) self.response.status = httplib.BAD_REQUEST except project_svc.NoSuchProjectException as e: logging.info('Rejecting invalid request: %r', e) self.response.status = httplib.BAD_REQUEST except xsrf.TokenIncorrect as e: logging.info('Bad XSRF token: %r', e.message) self.response.status = httplib.BAD_REQUEST except AlreadySentResponseException: # If servlet already sent response, then do nothing more. E.g., # when serving attachment content, we do not use templates. pass except permissions.BannedUserException as e: logging.warning('The user has been banned') url = framework_helpers.FormatAbsoluteURL(self.mr, urls.BANNED, include_project=False, copy_params=False) self.redirect(url, abort=True) except actionlimit.ExcessiveActivityException: logging.info('Excessive Activity Exception %r', self.mr.auth.user_id) url = framework_helpers.FormatAbsoluteURL(self.mr, urls.EXCESSIVE_ACTIVITY, include_project=False, copy_params=False) self.redirect(url, abort=True) except ratelimiter.RateLimitExceeded as e: logging.info('RateLimitExceeded Exception %s', e) self.response.status = httplib.BAD_REQUEST self.response.body = 'Slow your roll.' finally: self.mr.CleanUp() self.ratelimiter.CheckEnd(self.request, time.time(), handler_start_time) total_processing_time = time.time() - handler_start_time logging.warn('Processed request in %d ms', int(total_processing_time * 1000)) if settings.enable_profiler_logging: self.profiler.LogStats()