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 """Unittests for monorail.tracker.issuebulkedit.""" |
| 7 |
| 8 import os |
| 9 import unittest |
| 10 import webapp2 |
| 11 |
| 12 from google.appengine.api import memcache |
| 13 from google.appengine.api import taskqueue |
| 14 from google.appengine.ext import testbed |
| 15 |
| 16 from framework import monorailrequest |
| 17 from framework import permissions |
| 18 from proto import tracker_pb2 |
| 19 from services import service_manager |
| 20 from services import tracker_fulltext |
| 21 from testing import fake |
| 22 from testing import testing_helpers |
| 23 from tracker import issuebulkedit |
| 24 from tracker import tracker_bizobj |
| 25 |
| 26 |
| 27 class Response(object): |
| 28 |
| 29 def __init__(self): |
| 30 self.status = None |
| 31 |
| 32 |
| 33 class IssueBulkEditTest(unittest.TestCase): |
| 34 |
| 35 def setUp(self): |
| 36 self.services = service_manager.Services( |
| 37 features=fake.FeaturesService(), |
| 38 project=fake.ProjectService(), |
| 39 config=fake.ConfigService(), |
| 40 issue=fake.IssueService(), |
| 41 issue_star=fake.IssueStarService(), |
| 42 user=fake.UserService(), |
| 43 usergroup=fake.UserGroupService()) |
| 44 self.servlet = issuebulkedit.IssueBulkEdit( |
| 45 'req', 'res', services=self.services) |
| 46 self.mr = testing_helpers.MakeMonorailRequest( |
| 47 perms=permissions.OWNER_ACTIVE_PERMISSIONSET) |
| 48 self.project = self.services.project.TestAddProject( |
| 49 name='proj', project_id=789, owner_ids=[111]) |
| 50 self.cnxn = 'fake connection' |
| 51 self.config = self.services.config.GetProjectConfig( |
| 52 self.cnxn, self.project.project_id) |
| 53 self.services.config.StoreConfig(self.cnxn, self.config) |
| 54 self.owner = self.services.user.TestAddUser('owner@example.com', 111) |
| 55 |
| 56 self.testbed = testbed.Testbed() |
| 57 self.testbed.activate() |
| 58 self.testbed.init_taskqueue_stub() |
| 59 self.testbed.init_memcache_stub() |
| 60 self.testbed.init_datastore_v3_stub() |
| 61 self.taskqueue_stub = self.testbed.get_stub(testbed.TASKQUEUE_SERVICE_NAME) |
| 62 self.taskqueue_stub._root_path = os.path.dirname( |
| 63 os.path.dirname(os.path.dirname( __file__ ))) |
| 64 |
| 65 self.mocked_methods = {} |
| 66 |
| 67 def tearDown(self): |
| 68 """Restore mocked objects of other modules.""" |
| 69 for obj, items in self.mocked_methods.iteritems(): |
| 70 for member, previous_value in items.iteritems(): |
| 71 setattr(obj, member, previous_value) |
| 72 |
| 73 def testAssertBasePermission(self): |
| 74 """Permit users with EDIT_ISSUE and ADD_ISSUE_COMMENT permissions.""" |
| 75 mr = testing_helpers.MakeMonorailRequest( |
| 76 perms=permissions.CONTRIBUTOR_ACTIVE_PERMISSIONSET) |
| 77 self.assertRaises(permissions.PermissionException, |
| 78 self.servlet.AssertBasePermission, mr) |
| 79 |
| 80 self.servlet.AssertBasePermission(self.mr) |
| 81 |
| 82 def testGatherPageData(self): |
| 83 """Test GPD works in a normal no-corner-cases case.""" |
| 84 local_id_1 = self.services.issue.CreateIssue( |
| 85 self.cnxn, self.services, 789, 'issue summary', 'New', None, |
| 86 [], [], [], [], 111L, 'test issue') |
| 87 mr = testing_helpers.MakeMonorailRequest( |
| 88 project=self.project) |
| 89 mr.local_id_list = [local_id_1] |
| 90 |
| 91 page_data = self.servlet.GatherPageData(mr) |
| 92 self.assertEqual(1, page_data['num_issues']) |
| 93 |
| 94 def testGatherPageData_NoIssues(self): |
| 95 """Test GPD when no issues are specified in the mr.""" |
| 96 mr = testing_helpers.MakeMonorailRequest( |
| 97 project=self.project) |
| 98 self.assertRaises(monorailrequest.InputException, |
| 99 self.servlet.GatherPageData, mr) |
| 100 |
| 101 def testGatherPageData_FilteredIssues(self): |
| 102 """Test GPD when all specified issues get filtered out.""" |
| 103 local_id_1 = self.services.issue.CreateIssue( |
| 104 self.cnxn, self.services, 789, 'issue summary', 'New', None, [], |
| 105 ['restrict-view-Googler'], [], [], |
| 106 111L, 'test issue') |
| 107 mr = testing_helpers.MakeMonorailRequest( |
| 108 project=self.project) |
| 109 mr.local_id_list = [local_id_1] |
| 110 |
| 111 self.assertRaises(webapp2.HTTPException, |
| 112 self.servlet.GatherPageData, mr) |
| 113 |
| 114 def testGatherPageData_TypeLabels(self): |
| 115 """Test that GPD displays a custom field for appropriate issues.""" |
| 116 local_id_1 = self.services.issue.CreateIssue( |
| 117 self.cnxn, self.services, 789, 'issue summary', 'New', None, [], |
| 118 ['type-customlabels'], [], [], |
| 119 111L, 'test issue') |
| 120 mr = testing_helpers.MakeMonorailRequest( |
| 121 project=self.project) |
| 122 mr.local_id_list = [local_id_1] |
| 123 |
| 124 fd = tracker_bizobj.MakeFieldDef( |
| 125 123, 789, 'CPU', tracker_pb2.FieldTypes.INT_TYPE, None, |
| 126 '', False, False, None, None, '', False, '', '', |
| 127 tracker_pb2.NotifyTriggers.NEVER, 'doc', False) |
| 128 self.config.field_defs.append(fd) |
| 129 |
| 130 page_data = self.servlet.GatherPageData(mr) |
| 131 self.assertEqual(1, len(page_data['fields'])) |
| 132 |
| 133 def testProcessFormData(self): |
| 134 """Test that PFD works in a normal no-corner-cases case.""" |
| 135 local_id_1 = self.services.issue.CreateIssue( |
| 136 self.cnxn, self.services, 789, 'issue summary', 'New', 111L, |
| 137 [], [], [], [], 111L, 'test issue') |
| 138 mr = testing_helpers.MakeMonorailRequest( |
| 139 project=self.project, |
| 140 perms=permissions.OWNER_ACTIVE_PERMISSIONSET, |
| 141 user_info={'user_id': 111}) |
| 142 mr.local_id_list = [local_id_1] |
| 143 |
| 144 post_data = fake.PostData( |
| 145 owner=['owner@example.com'], can=[1], |
| 146 q=[''], colspec=[''], sort=[''], groupby=[''], start=[0], num=[100]) |
| 147 self._MockMethods() |
| 148 url = self.servlet.ProcessFormData(mr, post_data) |
| 149 self.assertTrue('list?can=1&saved=1' in url) |
| 150 |
| 151 def testProcessFormData_NoIssues(self): |
| 152 """Test PFD when no issues are specified.""" |
| 153 mr = testing_helpers.MakeMonorailRequest( |
| 154 project=self.project, |
| 155 perms=permissions.OWNER_ACTIVE_PERMISSIONSET, |
| 156 user_info={'user_id': 111}) |
| 157 post_data = fake.PostData() |
| 158 self.servlet.response = Response() |
| 159 self.servlet.ProcessFormData(mr, post_data) |
| 160 # 400 == bad request |
| 161 self.assertEqual(400, self.servlet.response.status) |
| 162 |
| 163 def testProcessFormData_NoUser(self): |
| 164 """Test PDF when the user is not logged in.""" |
| 165 mr = testing_helpers.MakeMonorailRequest( |
| 166 project=self.project) |
| 167 mr.local_id_list = [99999] |
| 168 post_data = fake.PostData() |
| 169 self.servlet.response = Response() |
| 170 self.servlet.ProcessFormData(mr, post_data) |
| 171 # 400 == bad request |
| 172 self.assertEqual(400, self.servlet.response.status) |
| 173 |
| 174 def testProcessFormData_CantComment(self): |
| 175 """Test PFD when the user can't comment on any of the issues.""" |
| 176 mr = testing_helpers.MakeMonorailRequest( |
| 177 project=self.project, |
| 178 perms=permissions.EMPTY_PERMISSIONSET, |
| 179 user_info={'user_id': 111}) |
| 180 mr.local_id_list = [99999] |
| 181 post_data = fake.PostData() |
| 182 self.servlet.response = Response() |
| 183 self.servlet.ProcessFormData(mr, post_data) |
| 184 # 400 == bad request |
| 185 self.assertEqual(400, self.servlet.response.status) |
| 186 |
| 187 def testProcessFormData_CantEdit(self): |
| 188 """Test PFD when the user can't edit any issue metadata.""" |
| 189 mr = testing_helpers.MakeMonorailRequest( |
| 190 project=self.project, |
| 191 perms=permissions.CONTRIBUTOR_ACTIVE_PERMISSIONSET, |
| 192 user_info={'user_id': 111}) |
| 193 mr.local_id_list = [99999] |
| 194 post_data = fake.PostData() |
| 195 self.servlet.response = Response() |
| 196 self.servlet.ProcessFormData(mr, post_data) |
| 197 # 400 == bad request |
| 198 self.assertEqual(400, self.servlet.response.status) |
| 199 |
| 200 def testProcessFormData_CantMove(self): |
| 201 """Test PFD when the user can't move issues.""" |
| 202 mr = testing_helpers.MakeMonorailRequest( |
| 203 project=self.project, |
| 204 perms=permissions.COMMITTER_ACTIVE_PERMISSIONSET, |
| 205 user_info={'user_id': 111}) |
| 206 mr.local_id_list = [99999] |
| 207 post_data = fake.PostData(move_to=['proj']) |
| 208 self.servlet.response = Response() |
| 209 self.servlet.ProcessFormData(mr, post_data) |
| 210 # 400 == bad request |
| 211 self.assertEqual(400, self.servlet.response.status) |
| 212 |
| 213 local_id_1 = self.services.issue.CreateIssue( |
| 214 self.cnxn, self.services, 789, 'issue summary', 'New', 111L, |
| 215 [], [], [], [], 111L, 'test issue') |
| 216 mr.perms = permissions.OWNER_ACTIVE_PERMISSIONSET |
| 217 mr.local_id_list = [local_id_1] |
| 218 mr.project_name = 'proj' |
| 219 self._MockMethods() |
| 220 self.servlet.ProcessFormData(mr, post_data) |
| 221 self.assertEqual( |
| 222 'The issues are already in project proj', mr.errors.move_to) |
| 223 |
| 224 post_data = fake.PostData(move_to=['notexist']) |
| 225 self.servlet.ProcessFormData(mr, post_data) |
| 226 self.assertEqual('No such project: notexist', mr.errors.move_to) |
| 227 |
| 228 def _MockMethods(self): |
| 229 # Mock methods of other modules to avoid unnecessary testing |
| 230 self.mocked_methods[tracker_fulltext] = { |
| 231 'IndexIssues': tracker_fulltext.IndexIssues, |
| 232 'UnindexIssues': tracker_fulltext.UnindexIssues} |
| 233 def DoNothing(*_args, **_kwargs): |
| 234 pass |
| 235 self.servlet.PleaseCorrect = DoNothing |
| 236 tracker_fulltext.IndexIssues = DoNothing |
| 237 tracker_fulltext.UnindexIssues = DoNothing |
| 238 |
| 239 def VerifyIssueUpdated(self, project_id, local_id): |
| 240 issue = self.services.issue.GetIssueByLocalID( |
| 241 self.cnxn, project_id, local_id) |
| 242 issue_id = issue.issue_id |
| 243 comments = self.services.issue.GetCommentsForIssue(self.cnxn, issue_id) |
| 244 last_comment = comments[-1] |
| 245 if last_comment.amendments[0].newvalue == 'Updated': |
| 246 return True |
| 247 else: |
| 248 return False |
| 249 |
| 250 def testProcessFormData_CustomFields(self): |
| 251 """Test PFD processes edits to custom fields.""" |
| 252 local_id_1 = self.services.issue.CreateIssue( |
| 253 self.cnxn, self.services, 789, 'issue summary', 'New', 111L, |
| 254 [], [], [], [], 111L, 'test issue') |
| 255 mr = testing_helpers.MakeMonorailRequest( |
| 256 project=self.project, |
| 257 perms=permissions.OWNER_ACTIVE_PERMISSIONSET, |
| 258 user_info={'user_id': 111}) |
| 259 mr.local_id_list = [local_id_1] |
| 260 |
| 261 fd = tracker_bizobj.MakeFieldDef( |
| 262 12345, 789, 'CPU', tracker_pb2.FieldTypes.INT_TYPE, None, |
| 263 '', False, False, None, None, '', False, '', '', |
| 264 tracker_pb2.NotifyTriggers.NEVER, 'doc', False) |
| 265 self.config.field_defs.append(fd) |
| 266 |
| 267 post_data = fake.PostData( |
| 268 custom_12345=['111'], owner=['owner@example.com'], can=[1], |
| 269 q=[''], colspec=[''], sort=[''], groupby=[''], start=[0], num=[100]) |
| 270 self._MockMethods() |
| 271 self.servlet.ProcessFormData(mr, post_data) |
| 272 self.assertTrue(self.VerifyIssueUpdated(789, local_id_1)) |
| 273 |
| 274 def testProcessFormData_DuplicateStatus_MergeSameIssue(self): |
| 275 """Test PFD processes null/cleared status values.""" |
| 276 local_id_1 = self.services.issue.CreateIssue( |
| 277 self.cnxn, self.services, self.project.project_id, 'issue summary', |
| 278 'New', 111L, [], [], [], [], 111L, 'test issue') |
| 279 merge_into_local_id_2 = self.services.issue.CreateIssue( |
| 280 self.cnxn, self.services, self.project.project_id, 'issue summary2', |
| 281 'New', 112L, [], [], [], [], 112L, 'test issue2') |
| 282 |
| 283 mr = testing_helpers.MakeMonorailRequest( |
| 284 project=self.project, |
| 285 perms=permissions.OWNER_ACTIVE_PERMISSIONSET, |
| 286 user_info={'user_id': 111}) |
| 287 mr.local_id_list = [local_id_1, merge_into_local_id_2] |
| 288 mr.project_name = 'proj' |
| 289 |
| 290 # Add required project_name to merge_into_issue. |
| 291 merge_into_issue = self.services.issue.GetIssueByLocalID( |
| 292 mr.cnxn, self.project.project_id, merge_into_local_id_2) |
| 293 merge_into_issue.project_name = 'proj' |
| 294 |
| 295 post_data = fake.PostData(status=['Duplicate'], |
| 296 merge_into=[str(merge_into_local_id_2)], owner=['owner@example.com'], |
| 297 can=[1], q=[''], colspec=[''], sort=[''], groupby=[''], start=[0], |
| 298 num=[100]) |
| 299 self._MockMethods() |
| 300 self.servlet.ProcessFormData(mr, post_data) |
| 301 self.assertEquals('Cannot merge issue into itself', mr.errors.merge_into_id) |
| 302 |
| 303 def testProcessFormData_DuplicateStatus_MergeMissingIssue(self): |
| 304 """Test PFD processes null/cleared status values.""" |
| 305 local_id_1 = self.services.issue.CreateIssue( |
| 306 self.cnxn, self.services, self.project.project_id, 'issue summary', |
| 307 'New', 111L, [], [], [], [], 111L, 'test issue') |
| 308 local_id_2 = self.services.issue.CreateIssue( |
| 309 self.cnxn, self.services, self.project.project_id, 'issue summary2', |
| 310 'New', 112L, [], [], [], [], 112L, 'test issue2') |
| 311 mr = testing_helpers.MakeMonorailRequest( |
| 312 project=self.project, |
| 313 perms=permissions.OWNER_ACTIVE_PERMISSIONSET, |
| 314 user_info={'user_id': 111}) |
| 315 mr.local_id_list = [local_id_1, local_id_2] |
| 316 mr.project_name = 'proj' |
| 317 |
| 318 post_data = fake.PostData(status=['Duplicate'], |
| 319 merge_into=['non existant id'], owner=['owner@example.com'], |
| 320 can=[1], q=[''], colspec=[''], sort=[''], groupby=[''], start=[0], |
| 321 num=[100]) |
| 322 self._MockMethods() |
| 323 self.servlet.ProcessFormData(mr, post_data) |
| 324 self.assertEquals('Please enter an issue ID', |
| 325 mr.errors.merge_into_id) |
| 326 |
| 327 def testProcessFormData_DuplicateStatus_Success(self): |
| 328 """Test PFD processes null/cleared status values.""" |
| 329 local_id_1 = self.services.issue.CreateIssue( |
| 330 self.cnxn, self.services, self.project.project_id, 'issue summary', |
| 331 'New', 111L, [], [], [], [], 111L, 'test issue') |
| 332 local_id_2 = self.services.issue.CreateIssue( |
| 333 self.cnxn, self.services, self.project.project_id, 'issue summary2', |
| 334 'New', 111L, [], [], [], [], 111L, 'test issue2') |
| 335 merge_into_local_id_3 = self.services.issue.CreateIssue( |
| 336 self.cnxn, self.services, self.project.project_id, 'issue summary3', |
| 337 'New', 112L, [], [], [], [], 112L, 'test issue3') |
| 338 mr = testing_helpers.MakeMonorailRequest( |
| 339 project=self.project, |
| 340 perms=permissions.OWNER_ACTIVE_PERMISSIONSET, |
| 341 user_info={'user_id': 111}) |
| 342 mr.local_id_list = [local_id_1, local_id_2] |
| 343 mr.project_name = 'proj' |
| 344 |
| 345 post_data = fake.PostData(status=['Duplicate'], |
| 346 merge_into=[str(merge_into_local_id_3)], owner=['owner@example.com'], |
| 347 can=[1], q=[''], colspec=[''], sort=[''], groupby=[''], start=[0], |
| 348 num=[100]) |
| 349 self._MockMethods() |
| 350 |
| 351 # Add project_name, CCs and starrers to the merge_into_issue. |
| 352 merge_into_issue = self.services.issue.GetIssueByLocalID( |
| 353 mr.cnxn, self.project.project_id, merge_into_local_id_3) |
| 354 merge_into_issue.project_name = 'proj' |
| 355 merge_into_issue.cc_ids = [113L, 120L] |
| 356 self.services.issue_star.SetStar( |
| 357 mr.cnxn, None, None, merge_into_issue.issue_id, 120L, True) |
| 358 |
| 359 # Add project_name, CCs and starrers to the source issues. |
| 360 # Issue 1 |
| 361 issue_1 = self.services.issue.GetIssueByLocalID( |
| 362 mr.cnxn, self.project.project_id, local_id_1) |
| 363 issue_1.project_name = 'proj' |
| 364 issue_1.cc_ids = [113L, 114L] |
| 365 self.services.issue_star.SetStar( |
| 366 mr.cnxn, None, None, issue_1.issue_id, 113L, True) |
| 367 # Issue 2 |
| 368 issue_2 = self.services.issue.GetIssueByLocalID( |
| 369 mr.cnxn, self.project.project_id, local_id_2) |
| 370 issue_2.project_name = 'proj' |
| 371 issue_2.cc_ids = [113L, 115L, 118L] |
| 372 self.services.issue_star.SetStar( |
| 373 mr.cnxn, None, None, issue_2.issue_id, 114L, True) |
| 374 self.services.issue_star.SetStar( |
| 375 mr.cnxn, None, None, issue_2.issue_id, 115L, True) |
| 376 |
| 377 self.servlet.ProcessFormData(mr, post_data) |
| 378 |
| 379 # Verify both source issues were updated. |
| 380 self.assertTrue( |
| 381 self.VerifyIssueUpdated(self.project.project_id, local_id_1)) |
| 382 self.assertTrue( |
| 383 self.VerifyIssueUpdated(self.project.project_id, local_id_2)) |
| 384 |
| 385 # Verify that the merge into issue was updated with a comment. |
| 386 comments = self.services.issue.GetCommentsForIssue( |
| 387 self.cnxn, merge_into_issue.issue_id) |
| 388 self.assertEquals( |
| 389 'Issue 1 has been merged into this issue.\n' |
| 390 'Issue 2 has been merged into this issue.', comments[-1].content) |
| 391 |
| 392 # Verify CC lists and owner were merged to the merge_into issue. |
| 393 self.assertEquals( |
| 394 [113L, 120L, 114L, 115L, 118L, 111L], merge_into_issue.cc_ids) |
| 395 # Verify new starrers were added to the merge_into issue. |
| 396 self.assertEquals(4, |
| 397 self.services.issue_star.CountItemStars( |
| 398 self.cnxn, merge_into_issue.issue_id)) |
| 399 self.assertEquals([120L, 113L, 114L, 115L], |
| 400 self.services.issue_star.LookupItemStarrers( |
| 401 self.cnxn, merge_into_issue.issue_id)) |
| 402 |
| 403 def testProcessFormData_ClearStatus(self): |
| 404 """Test PFD processes null/cleared status values.""" |
| 405 local_id_1 = self.services.issue.CreateIssue( |
| 406 self.cnxn, self.services, 789, 'issue summary', 'New', 111L, |
| 407 [], [], [], [], 111L, 'test issue') |
| 408 mr = testing_helpers.MakeMonorailRequest( |
| 409 project=self.project, |
| 410 perms=permissions.OWNER_ACTIVE_PERMISSIONSET, |
| 411 user_info={'user_id': 111}) |
| 412 mr.local_id_list = [local_id_1] |
| 413 |
| 414 post_data = fake.PostData( |
| 415 op_statusenter=['clear'], owner=['owner@example.com'], can=[1], |
| 416 q=[''], colspec=[''], sort=[''], groupby=[''], start=[0], num=[100]) |
| 417 self._MockMethods() |
| 418 self.servlet.ProcessFormData(mr, post_data) |
| 419 self.assertTrue(self.VerifyIssueUpdated(789, local_id_1)) |
| 420 |
| 421 def testProcessFormData_InvalidOwner(self): |
| 422 """Test PFD rejects invalid owner emails.""" |
| 423 local_id_1 = self.services.issue.CreateIssue( |
| 424 self.cnxn, self.services, 789, 'issue summary', 'New', None, |
| 425 [], [], [], [], 111L, 'test issue') |
| 426 mr = testing_helpers.MakeMonorailRequest( |
| 427 project=self.project, |
| 428 perms=permissions.OWNER_ACTIVE_PERMISSIONSET, |
| 429 user_info={'user_id': 111}) |
| 430 mr.local_id_list = [local_id_1] |
| 431 post_data = fake.PostData( |
| 432 owner=['invalid']) |
| 433 self.servlet.response = Response() |
| 434 self._MockMethods() |
| 435 self.servlet.ProcessFormData(mr, post_data) |
| 436 self.assertTrue(mr.errors.AnyErrors()) |
| 437 |
| 438 def testProcessFormData_MoveTo(self): |
| 439 """Test PFD processes move_to values.""" |
| 440 local_id_1 = self.services.issue.CreateIssue( |
| 441 self.cnxn, self.services, 789, 'issue to move', 'New', 111L, |
| 442 [], [], [], [], 111L, 'test issue') |
| 443 move_to_project = self.services.project.TestAddProject( |
| 444 name='proj2', project_id=790, owner_ids=[111]) |
| 445 |
| 446 mr = testing_helpers.MakeMonorailRequest( |
| 447 project=self.project, |
| 448 perms=permissions.OWNER_ACTIVE_PERMISSIONSET, |
| 449 user_info={'user_id': 111}) |
| 450 mr.project_name = 'proj' |
| 451 mr.local_id_list = [local_id_1] |
| 452 |
| 453 self._MockMethods() |
| 454 post_data = fake.PostData( |
| 455 move_to=['proj2'], can=[1], q=[''], |
| 456 colspec=[''], sort=[''], groupby=[''], start=[0], num=[100]) |
| 457 self.servlet.response = Response() |
| 458 self.servlet.ProcessFormData(mr, post_data) |
| 459 |
| 460 issue = self.services.issue.GetIssueByLocalID( |
| 461 self.cnxn, move_to_project.project_id, local_id_1) |
| 462 self.assertIsNotNone(issue) |
OLD | NEW |