| # 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 |
| |
| """Unittests for the issueentry servlet.""" |
| from __future__ import print_function |
| from __future__ import division |
| from __future__ import absolute_import |
| |
| try: |
| from mox3 import mox |
| except ImportError: |
| import mox |
| import time |
| import unittest |
| |
| import ezt |
| |
| from google.appengine.ext import testbed |
| from mock import Mock, patch |
| import webapp2 |
| |
| from framework import framework_bizobj |
| from framework import framework_views |
| from framework import permissions |
| from services import service_manager |
| from services import template_svc |
| from testing import fake |
| from testing import testing_helpers |
| from tracker import issueentry |
| from tracker import tracker_bizobj |
| from proto import tracker_pb2 |
| from proto import user_pb2 |
| |
| |
| class IssueEntryTest(unittest.TestCase): |
| def setUp(self): |
| self.testbed = testbed.Testbed() |
| self.testbed.activate() |
| self.testbed.init_memcache_stub() |
| self.testbed.init_datastore_v3_stub() |
| # Load queue.yaml. |
| |
| self.services = service_manager.Services( |
| config=fake.ConfigService(), |
| issue=fake.IssueService(), |
| user=fake.UserService(), |
| usergroup=fake.UserGroupService(), |
| project=fake.ProjectService(), |
| template=Mock(spec=template_svc.TemplateService), |
| features=fake.FeaturesService()) |
| self.project = self.services.project.TestAddProject('proj', project_id=987) |
| request = webapp2.Request.blank('/p/proj/issues/entry') |
| response = webapp2.Response() |
| self.servlet = issueentry.IssueEntry( |
| request, response, services=self.services) |
| self.user = self.services.user.TestAddUser('to_pass_tests', 0) |
| self.services.features.TestAddHotlist( |
| name='dontcare', summary='', owner_ids=[0]) |
| self.template = testing_helpers.DefaultTemplates()[1] |
| self.services.template.GetTemplateByName = Mock(return_value=self.template) |
| self.services.template.GetTemplateSetForProject = Mock( |
| return_value=[(1, 'name', False)]) |
| |
| # Set-up for testing hotlist parsing. |
| # Scenario: |
| # Users: U1, U2, and U3 |
| # Hotlists: |
| # H1: owned by U1 (private) |
| # H2: owned by U2, can be edited by U1 (private) |
| # H2: owned by U3, can be edited by U1 and U2 (public) |
| self.cnxn = fake.MonorailConnection() |
| self.U1 = self.services.user.TestAddUser('U1', 111) |
| self.U2 = self.services.user.TestAddUser('U2', 222) |
| self.U3 = self.services.user.TestAddUser('U3', 333) |
| |
| self.H1 = self.services.features.TestAddHotlist( |
| name='H1', summary='', owner_ids=[111], is_private=True) |
| self.H2 = self.services.features.TestAddHotlist( |
| name='H2', summary='', owner_ids=[222], editor_ids=[111], |
| is_private=True) |
| self.H2_U3 = self.services.features.TestAddHotlist( |
| name='H2', summary='', owner_ids=[333], editor_ids=[111, 222], |
| is_private=False) |
| |
| self.mox = mox.Mox() |
| |
| def tearDown(self): |
| self.testbed.deactivate() |
| self.mox.UnsetStubs() |
| self.mox.ResetAll() |
| |
| def testAssertBasePermission(self): |
| """Permit users with CREATE_ISSUE.""" |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', services=self.services, |
| perms=permissions.EMPTY_PERMISSIONSET) |
| self.assertRaises(permissions.PermissionException, |
| self.servlet.AssertBasePermission, mr) |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', services=self.services, |
| perms=permissions.CONTRIBUTOR_ACTIVE_PERMISSIONSET) |
| self.servlet.AssertBasePermission(mr) |
| |
| def testDiscardUnusedTemplateLabelPrefixes(self): |
| labels = ['pre-val', 'other-value', 'oneword', 'x', '-y', '-w-z', '', '-'] |
| self.assertEqual(labels, |
| issueentry._DiscardUnusedTemplateLabelPrefixes(labels)) |
| |
| labels = ['prefix-value', 'other-?', 'third-', '', '-', '-?'] |
| self.assertEqual(['prefix-value', 'third-', '', '-'], |
| issueentry._DiscardUnusedTemplateLabelPrefixes(labels)) |
| |
| def testGatherPageData(self): |
| user = self.services.user.TestAddUser('user@invalid', 100) |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', services=self.services) |
| mr.perms = permissions.PermissionSet( |
| [permissions.CREATE_ISSUE, permissions.EDIT_ISSUE]) |
| mr.auth.user_view = framework_views.MakeUserView( |
| 'cnxn', self.services.user, 100) |
| mr.auth.effective_ids = {100} |
| mr.template_name = 'rutabaga' |
| |
| self.mox.StubOutWithMock(self.services.user, 'GetUser') |
| self.services.user.GetUser( |
| mox.IgnoreArg(), mox.IgnoreArg()).MultipleTimes().AndReturn(user) |
| self.mox.ReplayAll() |
| config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id) |
| config.field_defs = [ |
| tracker_bizobj.MakeFieldDef( |
| 22, mr.project_id, 'NotEnum', tracker_pb2.FieldTypes.STR_TYPE, None, |
| '', False, False, False, None, None, '', False, '', '', |
| tracker_pb2.NotifyTriggers.NEVER, 'no_action', 'doc', False), |
| tracker_bizobj.MakeFieldDef( |
| 23, mr.project_id, 'Choices', tracker_pb2.FieldTypes.ENUM_TYPE, |
| None, '', False, False, False, None, None, '', False, '', '', |
| tracker_pb2.NotifyTriggers.NEVER, 'no_action', 'doc', False), |
| tracker_bizobj.MakeFieldDef( |
| 24, |
| mr.project_id, |
| 'RestrictedField', |
| tracker_pb2.FieldTypes.STR_TYPE, |
| None, |
| '', |
| False, |
| False, |
| False, |
| None, |
| None, |
| '', |
| False, |
| '', |
| '', |
| tracker_pb2.NotifyTriggers.NEVER, |
| 'no_action', |
| 'doc', |
| False, |
| is_restricted_field=True) |
| ] |
| self.services.config.StoreConfig(mr.cnxn, config) |
| template = tracker_pb2.TemplateDef( |
| labels=['NotEnum-Not-Masked', 'Choices-Masked']) |
| self.services.template.GetTemplateByName.return_value = template |
| |
| page_data = self.servlet.GatherPageData(mr) |
| self.mox.VerifyAll() |
| self.assertEqual(page_data['initial_owner'], 'user@invalid') |
| self.assertEqual(page_data['initial_status'], 'New') |
| self.assertTrue(page_data['clear_summary_on_click']) |
| self.assertTrue(page_data['must_edit_summary']) |
| self.assertEqual(page_data['labels'], ['NotEnum-Not-Masked']) |
| self.assertEqual(page_data['offer_templates'], ezt.boolean(False)) |
| self.assertEqual(page_data['fields'][0].is_editable, ezt.boolean(True)) |
| self.assertEqual(page_data['fields'][1].is_editable, ezt.boolean(True)) |
| self.assertEqual(page_data['fields'][2].is_editable, ezt.boolean(False)) |
| self.assertEqual(page_data['uneditable_fields'], ezt.boolean(True)) |
| |
| def testGatherPageData_Approvals(self): |
| user = self.services.user.TestAddUser('user@invalid', 100) |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', services=self.services) |
| mr.auth.user_view = framework_views.MakeUserView( |
| 'cnxn', self.services.user, 100) |
| mr.template_name = 'rutabaga' |
| |
| self.mox.StubOutWithMock(self.services.user, 'GetUser') |
| self.services.user.GetUser( |
| mox.IgnoreArg(), mox.IgnoreArg()).MultipleTimes().AndReturn(user) |
| self.mox.ReplayAll() |
| config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id) |
| config.field_defs = [ |
| tracker_bizobj.MakeFieldDef( |
| 24, mr.project_id, 'UXReview', |
| tracker_pb2.FieldTypes.APPROVAL_TYPE, None, '', False, False, |
| False, None, None, '', False, '', '', |
| tracker_pb2.NotifyTriggers.NEVER, 'no_action', 'doc', False)] |
| self.services.config.StoreConfig(mr.cnxn, config) |
| template = tracker_pb2.TemplateDef() |
| template.phases = [tracker_pb2.Phase( |
| phase_id=1, rank=4, name='Stable')] |
| template.approval_values = [tracker_pb2.ApprovalValue( |
| approval_id=24, phase_id=1, |
| status=tracker_pb2.ApprovalStatus.NEEDS_REVIEW)] |
| self.services.template.GetTemplateByName.return_value = template |
| |
| page_data = self.servlet.GatherPageData(mr) |
| self.mox.VerifyAll() |
| self.assertEqual(page_data['approvals'][0].field_name, 'UXReview') |
| self.assertEqual(page_data['initial_phases'][0], |
| tracker_pb2.Phase(phase_id=1, name='Stable', rank=4)) |
| self.assertEqual(page_data['prechecked_approvals'], ['24_phase_0']) |
| self.assertEqual(page_data['required_approval_ids'], [24]) |
| |
| # phase fields row shown when config contains phase fields. |
| config.field_defs.append(tracker_bizobj.MakeFieldDef( |
| 26, mr.project_id, 'GateTarget', |
| tracker_pb2.FieldTypes.INT_TYPE, None, '', False, False, False, |
| None, None, '', False, '', '', tracker_pb2.NotifyTriggers.NEVER, |
| 'no_action', 'doc', False, is_phase_field=True)) |
| self.services.config.StoreConfig(mr.cnxn, config) |
| page_data = self.servlet.GatherPageData(mr) |
| self.assertEqual(page_data['issue_phase_names'], ['stable']) |
| |
| # approval subfields in config hidden when chosen template does not contain |
| # its parent approval |
| template = tracker_pb2.TemplateDef() |
| self.services.template.GetTemplateByName.return_value = template |
| page_data = self.servlet.GatherPageData(mr) |
| self.assertEqual(page_data['approvals'], []) |
| # phase fields row hidden when template has no phases |
| self.assertEqual(page_data['issue_phase_names'], []) |
| |
| # TODO(jojwang): monorail:6305, remove this test when Edit perms |
| # for field values are implemented. |
| def testGatherPageData_FLTSpecialFields(self): |
| user = self.services.user.TestAddUser('user@invalid', 100) |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', services=self.services) |
| mr.auth.user_view = framework_views.MakeUserView( |
| 'cnxn', self.services.user, 100) |
| mr.template_name = 'rutabaga' |
| |
| self.mox.StubOutWithMock(self.services.user, 'GetUser') |
| self.services.user.GetUser( |
| mox.IgnoreArg(), mox.IgnoreArg()).MultipleTimes().AndReturn(user) |
| self.mox.ReplayAll() |
| config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id) |
| config.field_defs = [ |
| tracker_bizobj.MakeFieldDef( |
| 25, mr.project_id, 'nOtice', |
| tracker_pb2.FieldTypes.STR_TYPE, None, '', False, False, |
| False, None, None, '', False, '', '', |
| tracker_pb2.NotifyTriggers.NEVER, 'no_action', 'doc', False), |
| tracker_bizobj.MakeFieldDef( |
| 24, mr.project_id, 'M-Target', |
| tracker_pb2.FieldTypes.STR_TYPE, None, '', False, False, |
| False, None, None, '', False, '', '', |
| tracker_pb2.NotifyTriggers.NEVER, 'no_action', 'doc', False), |
| tracker_bizobj.MakeFieldDef( |
| 25, mr.project_id, 'whitepaper', |
| tracker_pb2.FieldTypes.STR_TYPE, None, '', False, False, |
| False, None, None, '', False, '', '', |
| tracker_pb2.NotifyTriggers.NEVER, 'no_action', 'doc', False), |
| tracker_bizobj.MakeFieldDef( |
| 25, mr.project_id, 'm-approved', |
| tracker_pb2.FieldTypes.STR_TYPE, None, '', False, False, |
| False, None, None, '', False, '', '', |
| tracker_pb2.NotifyTriggers.NEVER, 'no_action', 'doc', False), |
| ] |
| |
| self.services.config.StoreConfig(mr.cnxn, config) |
| template = tracker_pb2.TemplateDef() |
| self.services.template.GetTemplateByName.return_value = template |
| |
| page_data = self.servlet.GatherPageData(mr) |
| self.mox.VerifyAll() |
| self.assertEqual(page_data['fields'][0].field_name, 'M-Target') |
| self.assertEqual(len(page_data['fields']), 1) |
| |
| def testGatherPageData_DefaultOwnerAvailability(self): |
| user = self.services.user.TestAddUser('user@invalid', 100) |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', services=self.services) |
| mr.auth.user_view = framework_views.MakeUserView( |
| 'cnxn', self.services.user, 100) |
| mr.template_name = 'rutabaga' |
| |
| self.mox.StubOutWithMock(self.services.user, 'GetUser') |
| self.services.user.GetUser( |
| mox.IgnoreArg(), mox.IgnoreArg()).MultipleTimes().AndReturn(user) |
| self.mox.ReplayAll() |
| |
| page_data = self.servlet.GatherPageData(mr) |
| self.mox.VerifyAll() |
| self.assertEqual(page_data['initial_owner'], 'user@invalid') |
| self.assertEqual(page_data['owner_avail_state'], 'never') |
| self.assertEqual( |
| page_data['owner_avail_message_short'], |
| 'User never visited') |
| |
| user.last_visit_timestamp = int(time.time()) |
| mr.auth.user_view = framework_views.MakeUserView( |
| 'cnxn', self.services.user, 100) |
| page_data = self.servlet.GatherPageData(mr) |
| self.mox.VerifyAll() |
| self.assertEqual(page_data['initial_owner'], 'user@invalid') |
| self.assertEqual(page_data['owner_avail_state'], None) |
| self.assertEqual(page_data['owner_avail_message_short'], '') |
| |
| def testGatherPageData_TemplateAllowsKeepingSummary(self): |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', services=self.services) |
| mr.auth.user_view = framework_views.StuffUserView(100, 'user@invalid', True) |
| mr.template_name = 'rutabaga' |
| user = self.services.user.TestAddUser('user@invalid', 100) |
| |
| self.mox.StubOutWithMock(self.services.user, 'GetUser') |
| self.services.user.GetUser( |
| mox.IgnoreArg(), mox.IgnoreArg()).MultipleTimes().AndReturn(user) |
| self.mox.ReplayAll() |
| config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id) |
| self.services.config.StoreConfig(mr.cnxn, config) |
| self.template.summary_must_be_edited = False |
| |
| page_data = self.servlet.GatherPageData(mr) |
| self.mox.VerifyAll() |
| self.assertEqual(page_data['initial_owner'], 'user@invalid') |
| self.assertEqual(page_data['initial_status'], 'New') |
| self.assertFalse(page_data['clear_summary_on_click']) |
| self.assertFalse(page_data['must_edit_summary']) |
| |
| def testGatherPageData_DeepLinkSetsSummary(self): |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry?summary=foo', services=self.services) |
| mr.auth.user_view = framework_views.StuffUserView(100, 'user@invalid', True) |
| user = self.services.user.TestAddUser('user@invalid', 100) |
| mr.template_name = 'rutabaga' |
| |
| self.mox.StubOutWithMock(self.services.user, 'GetUser') |
| self.services.user.GetUser( |
| mox.IgnoreArg(), mox.IgnoreArg()).MultipleTimes().AndReturn(user) |
| self.mox.ReplayAll() |
| |
| page_data = self.servlet.GatherPageData(mr) |
| self.mox.VerifyAll() |
| self.assertEqual(page_data['initial_owner'], 'user@invalid') |
| self.assertEqual(page_data['initial_status'], 'New') |
| self.assertFalse(page_data['clear_summary_on_click']) |
| self.assertTrue(page_data['must_edit_summary']) |
| |
| @patch('framework.framework_bizobj.UserIsInProject') |
| def testGatherPageData_MembersOnlyTemplatesExcluded(self, |
| mockUserIsInProject): |
| """Templates with members_only=True are excluded from results |
| when the user is not a member of the project.""" |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', services=self.services) |
| mr.auth.user_view = framework_views.StuffUserView(100, 'user@invalid', True) |
| user = self.services.user.TestAddUser('user@invalid', 100) |
| mr.template_name = 'rutabaga' |
| self.services.template.GetTemplateSetForProject = Mock( |
| return_value=[(1, 'one', False), (2, 'two', True)]) |
| mockUserIsInProject.return_value = False |
| |
| self.mox.StubOutWithMock(self.services.user, 'GetUser') |
| self.services.user.GetUser( |
| mox.IgnoreArg(), mox.IgnoreArg()).MultipleTimes().AndReturn(user) |
| self.mox.ReplayAll() |
| |
| page_data = self.servlet.GatherPageData(mr) |
| self.mox.VerifyAll() |
| self.assertEqual(page_data['config'].template_names, ['one']) |
| |
| @patch('framework.framework_bizobj.UserIsInProject') |
| def testGatherPageData_DefaultTemplatesMember(self, mockUserIsInProject): |
| """If no template is specified, the default one is used based on |
| whether the user is a project member.""" |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', services=self.services) |
| mr.auth.user_view = framework_views.StuffUserView(100, 'user@invalid', True) |
| user = self.services.user.TestAddUser('user@invalid', 100) |
| self.services.template.GetTemplateSetForProject = Mock( |
| return_value=[(1, 'one', False), (2, 'two', True)]) |
| config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id) |
| config.default_template_for_users = 456 |
| config.default_template_for_developers = 789 |
| self.services.config.StoreConfig(mr.cnxn, config) |
| |
| mockUserIsInProject.return_value = True |
| self.services.template.GetTemplateById = Mock(return_value=self.template) |
| self.mox.StubOutWithMock(self.services.user, 'GetUser') |
| self.services.user.GetUser( |
| mox.IgnoreArg(), mox.IgnoreArg()).MultipleTimes().AndReturn(user) |
| |
| self.mox.ReplayAll() |
| self.servlet.GatherPageData(mr) |
| self.mox.VerifyAll() |
| |
| call_args = self.services.template.GetTemplateById.call_args[0] |
| self.assertEqual(call_args[1], 789) |
| |
| @patch('framework.framework_bizobj.UserIsInProject') |
| def testGatherPageData_DefaultTemplatesNonMember(self, mockUserIsInProject): |
| """If no template is specified, the default one is used based on |
| whether the user is not a project member.""" |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', services=self.services) |
| mr.auth.user_view = framework_views.StuffUserView(100, 'user@invalid', True) |
| user = self.services.user.TestAddUser('user@invalid', 100) |
| self.services.template.GetTemplateSetForProject = Mock( |
| return_value=[(1, 'one', False), (2, 'two', True)]) |
| config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id) |
| config.default_template_for_users = 456 |
| config.default_template_for_developers = 789 |
| self.services.config.StoreConfig(mr.cnxn, config) |
| |
| mockUserIsInProject.return_value = False |
| self.services.template.GetTemplateById = Mock(return_value=self.template) |
| self.mox.StubOutWithMock(self.services.user, 'GetUser') |
| self.services.user.GetUser( |
| mox.IgnoreArg(), mox.IgnoreArg()).MultipleTimes().AndReturn(user) |
| |
| self.mox.ReplayAll() |
| self.servlet.GatherPageData(mr) |
| self.mox.VerifyAll() |
| |
| call_args = self.services.template.GetTemplateById.call_args[0] |
| self.assertEqual(call_args[1], 456) |
| |
| def testGatherPageData_MissingDefaultTemplates(self): |
| """If the default templates were deleted, pick the first template.""" |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', services=self.services) |
| mr.auth.user_view = framework_views.StuffUserView(100, 'user@invalid', True) |
| user = self.services.user.TestAddUser('user@invalid', 100) |
| self.services.template.GetTemplateSetForProject = Mock( |
| return_value=[(1, 'one', False), (2, 'two', True)]) |
| |
| self.services.template.GetTemplateById.return_value = None |
| self.services.template.GetProjectTemplates.return_value = [ |
| tracker_pb2.TemplateDef(members_only=True), |
| tracker_pb2.TemplateDef(members_only=False)] |
| self.mox.StubOutWithMock(self.services.user, 'GetUser') |
| self.services.user.GetUser( |
| mox.IgnoreArg(), mox.IgnoreArg()).MultipleTimes().AndReturn(user) |
| |
| self.mox.ReplayAll() |
| page_data = self.servlet.GatherPageData(mr) |
| self.mox.VerifyAll() |
| |
| self.assertTrue(self.services.template.GetProjectTemplates.called) |
| self.assertTrue(page_data['config'].template_view.members_only) |
| |
| def testGatherPageData_IncorrectTemplate(self): |
| """The handler shouldn't error out if passed a non-existent template.""" |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', services=self.services) |
| mr.auth.user_view = framework_views.StuffUserView(100, 'user@invalid', True) |
| mr.template_name = 'rutabaga' |
| |
| user = self.services.user.TestAddUser('user@invalid', 100) |
| config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id) |
| config.default_template_for_users = 456 |
| config.default_template_for_developers = 789 |
| self.services.config.StoreConfig(mr.cnxn, config) |
| |
| self.services.template.GetTemplateSetForProject.return_value = [ |
| (1, 'one', False), (2, 'two', True)] |
| self.services.template.GetTemplateByName.return_value = None |
| self.services.template.GetTemplateById.return_value = \ |
| tracker_pb2.TemplateDef(template_id=123, labels=['yo']) |
| self.services.template.GetProjectTemplates.return_value = [ |
| tracker_pb2.TemplateDef(labels=['no']), |
| tracker_pb2.TemplateDef(labels=['maybe'])] |
| self.mox.StubOutWithMock(self.services.user, 'GetUser') |
| self.services.user.GetUser( |
| mox.IgnoreArg(), mox.IgnoreArg()).MultipleTimes().AndReturn(user) |
| |
| self.mox.ReplayAll() |
| page_data = self.servlet.GatherPageData(mr) |
| self.mox.VerifyAll() |
| |
| self.assertTrue(self.services.template.GetTemplateByName.called) |
| self.assertTrue(self.services.template.GetTemplateById.called) |
| self.assertFalse(self.services.template.GetProjectTemplates.called) |
| self.assertEqual(page_data['config'].template_view.label0, 'yo') |
| |
| def testGatherPageData_RestrictNewIssues(self): |
| """Users with this pref set default to reporting issues with R-V-G.""" |
| self.mox.ReplayAll() |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', services=self.services) |
| mr.auth.user_view = framework_views.StuffUserView(100, 'user@invalid', True) |
| user = self.services.user.TestAddUser('user@invalid', 100) |
| self.services.user.GetUser = Mock(return_value=user) |
| self.services.template.GetTemplateById = Mock(return_value=self.template) |
| |
| mr.auth.user_id = 100 |
| page_data = self.servlet.GatherPageData(mr) |
| self.assertNotIn('Restrict-View-Google', page_data['labels']) |
| |
| pref = user_pb2.UserPrefValue(name='restrict_new_issues', value='true') |
| self.services.user.SetUserPrefs(self.cnxn, 100, [pref]) |
| page_data = self.servlet.GatherPageData(mr) |
| self.assertIn('Restrict-View-Google', page_data['labels']) |
| |
| def testGatherHelpData_Anon(self): |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', project=self.project) |
| mr.auth.user_pb = user_pb2.User() |
| mr.auth.user_id = 0 |
| |
| help_data = self.servlet.GatherHelpData(mr, {}) |
| self.assertEqual( |
| {'account_cue': None, |
| 'cue': None, |
| 'is_privileged_domain_user': None}, |
| help_data) |
| |
| def testGatherHelpData_NewUser(self): |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', project=self.project) |
| mr.auth.user_pb = user_pb2.User(user_id=111) |
| mr.auth.user_id = 111 |
| |
| help_data = self.servlet.GatherHelpData(mr, {}) |
| self.assertEqual( |
| {'account_cue': None, |
| 'cue': 'privacy_click_through', |
| 'is_privileged_domain_user': None}, |
| help_data) |
| |
| def testGatherHelpData_AlreadyClickedThroughPrivacy(self): |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', project=self.project) |
| mr.auth.user_pb = user_pb2.User(user_id=111) |
| mr.auth.user_id = 111 |
| self.services.user.SetUserPrefs( |
| self.cnxn, 111, |
| [user_pb2.UserPrefValue(name='privacy_click_through', value='true')]) |
| |
| help_data = self.servlet.GatherHelpData(mr, {}) |
| self.assertEqual( |
| {'account_cue': None, |
| 'cue': 'code_of_conduct', |
| 'is_privileged_domain_user': None}, |
| help_data) |
| |
| def testGatherHelpData_DismissedEverything(self): |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', project=self.project) |
| mr.auth.user_pb = user_pb2.User(user_id=111) |
| mr.auth.user_id = 111 |
| self.services.user.SetUserPrefs( |
| self.cnxn, 111, |
| [user_pb2.UserPrefValue(name='privacy_click_through', value='true'), |
| user_pb2.UserPrefValue(name='code_of_conduct', value='true')]) |
| |
| help_data = self.servlet.GatherHelpData(mr, {}) |
| self.assertEqual( |
| {'account_cue': None, |
| 'cue': None, |
| 'is_privileged_domain_user': None}, |
| help_data) |
| |
| @patch('framework.cloud_tasks_helpers.create_task') |
| def testProcessFormData_RedirectToEnteredIssue(self, _create_task_mock): |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', project=self.project) |
| mr.auth.user_view = framework_views.StuffUserView(100, 'user@invalid', True) |
| mr.template_name = 'rutabaga' |
| mr.auth.effective_ids = set([100]) |
| post_data = fake.PostData( |
| template_name=['rutabaga'], |
| summary=['fake summary'], |
| comment=['fake comment'], |
| status=['New']) |
| |
| self.mox.ReplayAll() |
| url = self.servlet.ProcessFormData(mr, post_data) |
| |
| self.mox.VerifyAll() |
| self.assertTrue('/p/proj/issues/detail?id=' in url) |
| |
| @patch('framework.cloud_tasks_helpers.create_task') |
| def testProcessFormData_AcceptWithFields(self, _create_task_mock): |
| """We can create new issues with custom fields (restricted or not).""" |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', project=self.project) |
| mr.auth.user_view = framework_views.StuffUserView(100, 'admin@test', True) |
| mr.template_name = 'rutabaga' |
| mr.auth.effective_ids = set([100]) |
| config = self.services.config.GetProjectConfig( |
| mr.cnxn, self.project.project_id) |
| config.field_defs = [ |
| tracker_bizobj.MakeFieldDef( |
| 1, 789, 'NonRestrictedField', tracker_pb2.FieldTypes.INT_TYPE, None, |
| '', False, False, False, None, None, '', False, '', '', |
| tracker_pb2.NotifyTriggers.NEVER, 'no_action', 'NonRestrictedField', |
| False), |
| tracker_bizobj.MakeFieldDef( |
| 2, |
| 789, |
| 'RestrictedField', |
| tracker_pb2.FieldTypes.INT_TYPE, |
| None, |
| '', |
| False, |
| False, |
| False, |
| None, |
| None, |
| '', |
| False, |
| '', |
| '', |
| tracker_pb2.NotifyTriggers.NEVER, |
| 'no_action', |
| 'RestrictedField', |
| False, |
| is_restricted_field=True), |
| tracker_bizobj.MakeFieldDef( |
| 3, |
| 789, |
| 'RestrictedEnumField', |
| tracker_pb2.FieldTypes.ENUM_TYPE, |
| None, |
| '', |
| False, |
| False, |
| False, |
| None, |
| None, |
| '', |
| False, |
| '', |
| '', |
| tracker_pb2.NotifyTriggers.NEVER, |
| 'no_action', |
| 'RestrictedEnumField', |
| False, |
| is_restricted_field=True) |
| ] |
| self.services.config.StoreConfig(mr.cnxn, config) |
| post_data = fake.PostData( |
| template_name=['rutabaga'], |
| summary=['fake summary'], |
| comment=['fake comment'], |
| custom_1=['3'], |
| custom_2=['7'], |
| label=['RestrictedEnumField-7'], |
| status=['New']) |
| |
| self.mox.ReplayAll() |
| url = self.servlet.ProcessFormData(mr, post_data) |
| |
| self.mox.VerifyAll() |
| self.assertTrue('/p/proj/issues/detail?id=' in url) |
| field_values = self.services.issue.issues_by_project[987][1].field_values |
| self.assertEqual( |
| self.services.issue.issues_by_project[987][1].labels, |
| ['RestrictedEnumField-7']) |
| self.assertEqual(field_values[0].int_value, 3) |
| self.assertEqual(field_values[1].int_value, 7) |
| |
| @patch('framework.cloud_tasks_helpers.create_task') |
| def testProcessFormData_AcceptEnforceTemplateRestrictedDefaultValues( |
| self, _create_task_mock): |
| """The template applies default vals on fields that the user cannot edit.""" |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', project=self.project) |
| mr.auth.user_view = framework_views.StuffUserView(100, 'admin@test', True) |
| mr.template_name = 'rutabaga' |
| mr.auth.effective_ids = set([100]) |
| mr.perms = permissions.PermissionSet([]) |
| config = self.services.config.GetProjectConfig( |
| mr.cnxn, self.project.project_id) |
| config.field_defs = [ |
| tracker_bizobj.MakeFieldDef( |
| 1, 789, 'NonRestrictedField', tracker_pb2.FieldTypes.INT_TYPE, None, |
| '', False, False, False, None, None, '', False, '', '', |
| tracker_pb2.NotifyTriggers.NEVER, 'no_action', 'NonRestrictedField', |
| False), |
| tracker_bizobj.MakeFieldDef( |
| 2, |
| 789, |
| 'RestrictedField', |
| tracker_pb2.FieldTypes.INT_TYPE, |
| None, |
| '', |
| False, |
| False, |
| False, |
| None, |
| None, |
| '', |
| False, |
| '', |
| '', |
| tracker_pb2.NotifyTriggers.NEVER, |
| 'no_action', |
| 'RestrictedField', |
| False, |
| is_restricted_field=True), |
| tracker_bizobj.MakeFieldDef( |
| 3, |
| 789, |
| 'RestrictedEnumField', |
| tracker_pb2.FieldTypes.ENUM_TYPE, |
| None, |
| '', |
| False, |
| False, |
| False, |
| None, |
| None, |
| '', |
| False, |
| '', |
| '', |
| tracker_pb2.NotifyTriggers.NEVER, |
| 'no_action', |
| 'RestrictedEnumField', |
| False, |
| is_restricted_field=True) |
| ] |
| self.services.config.StoreConfig(mr.cnxn, config) |
| post_data = fake.PostData( |
| template_name=['rutabaga'], |
| summary=['fake summary'], |
| comment=['fake comment'], |
| custom_1=['3'], |
| label=['Hey'], |
| status=['New']) |
| |
| temp_restricted_fv = tracker_bizobj.MakeFieldValue( |
| 2, 3737, None, None, None, None, False) |
| self.template.field_values.append(temp_restricted_fv) |
| self.template.labels.append('RestrictedEnumField-b') |
| |
| self.mox.ReplayAll() |
| url = self.servlet.ProcessFormData(mr, post_data) |
| |
| self.mox.VerifyAll() |
| self.assertTrue('/p/proj/issues/detail?id=' in url) |
| field_values = self.services.issue.issues_by_project[987][1].field_values |
| self.assertEqual( |
| self.services.issue.issues_by_project[987][1].labels, |
| ['Hey', 'RestrictedEnumField-b']) |
| self.assertEqual(field_values[0].int_value, 3) |
| self.assertEqual(field_values[1].int_value, 3737) |
| |
| def testProcessFormData_RejectRestrictedFields(self): |
| """We raise an AssertionError when restricted fields are set w/o perms.""" |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', project=self.project) |
| mr.auth.user_view = framework_views.StuffUserView( |
| 100, 'non-admin@test', True) |
| mr.template_name = 'rutabaga' |
| mr.auth.effective_ids = set([100]) |
| mr.perms = permissions.PermissionSet([]) |
| config = self.services.config.GetProjectConfig( |
| mr.cnxn, self.project.project_id) |
| config.field_defs = [ |
| tracker_bizobj.MakeFieldDef( |
| 1, 789, 'NonRestrictedField', tracker_pb2.FieldTypes.INT_TYPE, None, |
| '', False, False, False, None, None, '', False, '', '', |
| tracker_pb2.NotifyTriggers.NEVER, 'no_action', 'NonRestrictedField', |
| False), |
| tracker_bizobj.MakeFieldDef( |
| 2, |
| 789, |
| 'RestrictedField', |
| tracker_pb2.FieldTypes.INT_TYPE, |
| None, |
| '', |
| False, |
| False, |
| False, |
| None, |
| None, |
| '', |
| False, |
| '', |
| '', |
| tracker_pb2.NotifyTriggers.NEVER, |
| 'no_action', |
| 'RestrictedField', |
| False, |
| is_restricted_field=True), |
| tracker_bizobj.MakeFieldDef( |
| 3, |
| 789, |
| 'RestrictedEnumField', |
| tracker_pb2.FieldTypes.ENUM_TYPE, |
| None, |
| '', |
| False, |
| False, |
| False, |
| None, |
| None, |
| '', |
| False, |
| '', |
| '', |
| tracker_pb2.NotifyTriggers.NEVER, |
| 'no_action', |
| 'RestrictedEnumField', |
| False, |
| is_restricted_field=True) |
| ] |
| self.services.config.StoreConfig(mr.cnxn, config) |
| post_data_add_fv = fake.PostData( |
| template_name=['rutabaga'], |
| summary=['fake summary'], |
| comment=['fake comment'], |
| custom_1=['3'], |
| custom_2=['7'], |
| status=['New']) |
| post_data_label_edits_enum = fake.PostData( |
| template_name=['rutabaga'], |
| summary=['fake summary'], |
| comment=['fake comment'], |
| label=['RestrictedEnumField-7'], |
| status=['New']) |
| |
| self.assertRaises( |
| AssertionError, self.servlet.ProcessFormData, mr, post_data_add_fv) |
| self.assertRaises( |
| AssertionError, self.servlet.ProcessFormData, mr, |
| post_data_label_edits_enum) |
| |
| def testProcessFormData_RejectPlacedholderSummary(self): |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry') |
| mr.auth.user_view = framework_views.StuffUserView(100, 'user@invalid', True) |
| mr.perms = permissions.USER_PERMISSIONSET |
| mr.template_name = 'rutabaga' |
| post_data = fake.PostData( |
| template_name=['rutabaga'], |
| summary=[issueentry.PLACEHOLDER_SUMMARY], |
| comment=['fake comment'], |
| status=['New']) |
| |
| self.mox.StubOutWithMock(self.servlet, 'PleaseCorrect') |
| self.servlet.PleaseCorrect( |
| mr, component_required=None, fields=[], initial_blocked_on='', |
| initial_blocking='', initial_cc='', initial_comment='fake comment', |
| initial_components='', initial_owner='', initial_status='New', |
| initial_summary='Enter one-line summary', initial_hotlists='', |
| labels=[], template_name='rutabaga') |
| self.mox.ReplayAll() |
| |
| url = self.servlet.ProcessFormData(mr, post_data) |
| self.mox.VerifyAll() |
| self.assertEqual('Summary is required', mr.errors.summary) |
| self.assertIsNone(url) |
| |
| def testProcessFormData_RejectUnmodifiedTemplate(self): |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry') |
| mr.perms = permissions.USER_PERMISSIONSET |
| mr.auth.user_view = framework_views.StuffUserView(100, 'user@invalid', True) |
| post_data = fake.PostData( |
| template_name=['rutabaga'], |
| summary=['Nya nya I modified the summary'], |
| comment=[self.template.content], |
| status=['New']) |
| |
| self.mox.StubOutWithMock(self.servlet, 'PleaseCorrect') |
| self.servlet.PleaseCorrect( |
| mr, component_required=None, fields=[], initial_blocked_on='', |
| initial_blocking='', initial_cc='', |
| initial_comment=self.template.content, initial_components='', |
| initial_owner='', initial_status='New', |
| initial_summary='Nya nya I modified the summary', initial_hotlists='', |
| labels=[], template_name='rutabaga') |
| self.mox.ReplayAll() |
| |
| url = self.servlet.ProcessFormData(mr, post_data) |
| self.mox.VerifyAll() |
| self.assertEqual('Template must be filled out.', mr.errors.comment) |
| self.assertIsNone(url) |
| |
| def testProcessFormData_RejectNonexistentHotlist(self): |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', user_info={'user_id': 111}) |
| entered_hotlists = 'H3' |
| post_data = fake.PostData(hotlists=[entered_hotlists], |
| template_name=['rutabaga']) |
| self.mox.StubOutWithMock(self.servlet, 'PleaseCorrect') |
| self.servlet.PleaseCorrect( |
| mr, component_required=None, fields=[], initial_blocked_on='', |
| initial_blocking='', initial_cc='', initial_comment='', |
| initial_components='', initial_owner='', initial_status='', |
| initial_summary='', initial_hotlists=entered_hotlists, labels=[], |
| template_name='rutabaga') |
| self.mox.ReplayAll() |
| url = self.servlet.ProcessFormData(mr, post_data) |
| self.mox.VerifyAll() |
| self.assertEqual('You have no hotlist(s) named: H3', mr.errors.hotlists) |
| self.assertIsNone(url) |
| |
| def testProcessFormData_RejectNonexistentHotlistOwner(self): |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', user_info={'user_id': 111}) |
| entered_hotlists = 'abc:H1' |
| post_data = fake.PostData(hotlists=[entered_hotlists], |
| template_name=['rutabaga']) |
| self.mox.StubOutWithMock(self.servlet, 'PleaseCorrect') |
| self.servlet.PleaseCorrect( |
| mr, component_required=None, fields=[], initial_blocked_on='', |
| initial_blocking='', initial_cc='', initial_comment='', |
| initial_components='', initial_owner='', initial_status='', |
| initial_summary='', initial_hotlists=entered_hotlists, labels=[], |
| template_name='rutabaga') |
| self.mox.ReplayAll() |
| url = self.servlet.ProcessFormData(mr, post_data) |
| self.mox.VerifyAll() |
| self.assertEqual('You have no hotlist(s) owned by: abc', mr.errors.hotlists) |
| self.assertIsNone(url) |
| |
| def testProcessFormData_RejectInvalidHotlistName(self): |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', user_info={'user_id': 111}) |
| entered_hotlists = 'U1:H2' |
| post_data = fake.PostData(hotlists=[entered_hotlists], |
| template_name=['rutabaga']) |
| self.mox.StubOutWithMock(self.servlet, 'PleaseCorrect') |
| self.servlet.PleaseCorrect( |
| mr, component_required=None, fields=[], initial_blocked_on='', |
| initial_blocking='', initial_cc='', initial_comment='', |
| initial_components='', initial_owner='', initial_status='', |
| initial_summary='', initial_hotlists=entered_hotlists, labels=[], |
| template_name='rutabaga') |
| self.mox.ReplayAll() |
| url = self.servlet.ProcessFormData(mr, post_data) |
| self.mox.VerifyAll() |
| self.assertEqual('Not in your hotlist(s): U1:H2', mr.errors.hotlists) |
| self.assertIsNone(url) |
| |
| def testProcessFormData_RejectDeprecatedComponent(self): |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', |
| user_info={'user_id': 111}, |
| project=self.project) |
| config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id) |
| config.component_defs = [ |
| tracker_bizobj.MakeComponentDef( |
| 1, mr.project_id, 'active', '', False, [], [], 0, 0), |
| tracker_bizobj.MakeComponentDef( |
| 2, mr.project_id, 'notactive', '', True, [], [], 0, 0), |
| ] |
| self.services.config.StoreConfig(mr.cnxn, config) |
| print(config) |
| post_data = fake.PostData( |
| template_name=['rutabaga'], |
| summary=['fake summary'], |
| comment=['fake comment'], |
| components=['notactive']) |
| |
| self.mox.StubOutWithMock(self.servlet, 'PleaseCorrect') |
| self.servlet.PleaseCorrect( |
| mr, |
| component_required=None, |
| fields=[], |
| initial_blocked_on='', |
| initial_blocking='', |
| initial_cc='', |
| initial_comment='fake comment', |
| initial_components='notactive', |
| initial_owner='', |
| initial_status='', |
| initial_summary='fake summary', |
| initial_hotlists='', |
| labels=[], |
| template_name='rutabaga') |
| self.mox.ReplayAll() |
| url = self.servlet.ProcessFormData(mr, post_data) |
| self.mox.VerifyAll() |
| self.assertEqual(mr.errors.components, 'Undefined or deprecated component') |
| self.assertIsNone(url) |
| |
| @patch('framework.cloud_tasks_helpers.create_task') |
| def testProcessFormData_TemplateNameMissing(self, _create_task_mock): |
| """POST doesn't fail if no template_name is passed.""" |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', project=self.project) |
| mr.auth.user_view = framework_views.StuffUserView(100, 'user@invalid', True) |
| mr.auth.effective_ids = set([100]) |
| |
| self.services.template.GetTemplateById.return_value = None |
| self.services.template.GetProjectTemplates.return_value = [ |
| tracker_pb2.TemplateDef(members_only=True, content=''), |
| tracker_pb2.TemplateDef(members_only=False, content='')] |
| post_data = fake.PostData( |
| summary=['fake summary'], |
| comment=['fake comment'], |
| status=['New']) |
| |
| self.mox.ReplayAll() |
| url = self.servlet.ProcessFormData(mr, post_data) |
| |
| self.mox.VerifyAll() |
| self.assertTrue('/p/proj/issues/detail?id=' in url) |
| |
| @patch('framework.cloud_tasks_helpers.create_task') |
| def testProcessFormData_AcceptsFederatedReferences(self, _create_task_mock): |
| """ProcessFormData accepts federated references.""" |
| mr = testing_helpers.MakeMonorailRequest( |
| path='/p/proj/issues/entry', project=self.project) |
| mr.auth.user_view = framework_views.StuffUserView(100, 'user@invalid', True) |
| mr.auth.effective_ids = set([100]) |
| |
| post_data = fake.PostData( |
| summary=['fake summary'], |
| comment=['fake comment'], |
| status=['New'], |
| template_name='rutabaga', |
| blocking=['b/123, b/987'], |
| blockedon=['b/456, b/654']) |
| |
| self.mox.ReplayAll() |
| self.servlet.ProcessFormData(mr, post_data) |
| |
| self.mox.VerifyAll() |
| self.assertIsNone(mr.errors.blockedon) |
| self.assertIsNone(mr.errors.blocking) |
| |
| def testAttachDefaultApprovers(self): |
| config = tracker_bizobj.MakeDefaultProjectIssueConfig(789) |
| config.approval_defs = [ |
| tracker_pb2.ApprovalDef( |
| approval_id=23, approver_ids=[222], survey='Question?'), |
| tracker_pb2.ApprovalDef( |
| approval_id=24, approver_ids=[111], survey='Question?')] |
| approval_values = [tracker_pb2.ApprovalValue( |
| approval_id=24, phase_id=1, |
| status=tracker_pb2.ApprovalStatus.NEEDS_REVIEW)] |
| issueentry._AttachDefaultApprovers(config, approval_values) |
| self.assertEqual(approval_values[0].approver_ids, [111]) |
| |
| # TODO(aneeshm): add a test for the ambiguous hotlist name case; it works |
| # correctly when tested locally, but for some reason doesn't in the test |
| # environment. Probably a result of some quirk in fake.py? |