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 issue_svc module.""" |
| 7 |
| 8 import time |
| 9 import unittest |
| 10 |
| 11 import mox |
| 12 |
| 13 from google.appengine.api import search |
| 14 from google.appengine.ext import testbed |
| 15 |
| 16 import settings |
| 17 from framework import sql |
| 18 from proto import tracker_pb2 |
| 19 from services import issue_svc |
| 20 from services import service_manager |
| 21 from services import spam_svc |
| 22 from services import tracker_fulltext |
| 23 from testing import fake |
| 24 from tracker import tracker_bizobj |
| 25 |
| 26 |
| 27 class MockIndex(object): |
| 28 |
| 29 def delete(self, string_list): |
| 30 pass |
| 31 |
| 32 |
| 33 def MakeIssueService(project_service, config_service, cache_manager, my_mox): |
| 34 issue_service = issue_svc.IssueService( |
| 35 project_service, config_service, cache_manager) |
| 36 for table_var in [ |
| 37 'issue_tbl', 'issuesummary_tbl', 'issue2label_tbl', |
| 38 'issue2component_tbl', 'issue2cc_tbl', 'issue2notify_tbl', |
| 39 'issue2fieldvalue_tbl', 'issuerelation_tbl', 'danglingrelation_tbl', |
| 40 'issueformerlocations_tbl', 'comment_tbl', 'issueupdate_tbl', |
| 41 'attachment_tbl', 'reindexqueue_tbl', 'localidcounter_tbl']: |
| 42 setattr(issue_service, table_var, my_mox.CreateMock(sql.SQLTableManager)) |
| 43 |
| 44 return issue_service |
| 45 |
| 46 |
| 47 class IssueIDTwoLevelCacheTest(unittest.TestCase): |
| 48 |
| 49 def setUp(self): |
| 50 self.mox = mox.Mox() |
| 51 self.cnxn = 'fake connection' |
| 52 self.project_service = fake.ProjectService() |
| 53 self.config_service = fake.ConfigService() |
| 54 self.cache_manager = fake.CacheManager() |
| 55 self.issue_service = MakeIssueService( |
| 56 self.project_service, self.config_service, self.cache_manager, |
| 57 self.mox) |
| 58 self.issue_id_2lc = self.issue_service.issue_id_2lc |
| 59 self.spam_service = fake.SpamService() |
| 60 |
| 61 def tearDown(self): |
| 62 self.mox.UnsetStubs() |
| 63 self.mox.ResetAll() |
| 64 |
| 65 def testDeserializeIssueIDs_Empty(self): |
| 66 issue_id_dict = self.issue_id_2lc._DeserializeIssueIDs([]) |
| 67 self.assertEqual({}, issue_id_dict) |
| 68 |
| 69 def testDeserializeIssueIDs_Normal(self): |
| 70 rows = [(789, 1, 78901), (789, 2, 78902), (789, 3, 78903)] |
| 71 issue_id_dict = self.issue_id_2lc._DeserializeIssueIDs(rows) |
| 72 expected = { |
| 73 (789, 1): 78901, |
| 74 (789, 2): 78902, |
| 75 (789, 3): 78903, |
| 76 } |
| 77 self.assertEqual(expected, issue_id_dict) |
| 78 |
| 79 def SetUpFetchItems(self): |
| 80 where = [ |
| 81 ('(Issue.project_id = %s AND Issue.local_id IN (%s,%s,%s))', |
| 82 [789, 1, 2, 3])] |
| 83 rows = [(789, 1, 78901), (789, 2, 78902), (789, 3, 78903)] |
| 84 self.issue_service.issue_tbl.Select( |
| 85 self.cnxn, cols=['project_id', 'local_id', 'id'], |
| 86 where=where, or_where_conds=True).AndReturn(rows) |
| 87 |
| 88 def testFetchItems(self): |
| 89 project_local_ids_list = [(789, 1), (789, 2), (789, 3)] |
| 90 issue_ids = [78901, 78902, 78903] |
| 91 self.SetUpFetchItems() |
| 92 self.mox.ReplayAll() |
| 93 issue_dict = self.issue_id_2lc.FetchItems( |
| 94 self.cnxn, project_local_ids_list) |
| 95 self.mox.VerifyAll() |
| 96 self.assertItemsEqual(project_local_ids_list, issue_dict.keys()) |
| 97 self.assertItemsEqual(issue_ids, issue_dict.values()) |
| 98 |
| 99 def testKeyToStr(self): |
| 100 self.assertEqual('789,1', self.issue_id_2lc._KeyToStr((789, 1))) |
| 101 |
| 102 def testStrToKey(self): |
| 103 self.assertEqual((789, 1), self.issue_id_2lc._StrToKey('789,1')) |
| 104 |
| 105 |
| 106 class IssueTwoLevelCacheTest(unittest.TestCase): |
| 107 |
| 108 def setUp(self): |
| 109 self.mox = mox.Mox() |
| 110 self.cnxn = 'fake connection' |
| 111 self.project_service = fake.ProjectService() |
| 112 self.config_service = fake.ConfigService() |
| 113 self.cache_manager = fake.CacheManager() |
| 114 self.issue_service = MakeIssueService( |
| 115 self.project_service, self.config_service, self.cache_manager, |
| 116 self.mox) |
| 117 self.issue_2lc = self.issue_service.issue_2lc |
| 118 |
| 119 now = int(time.time()) |
| 120 self.project_service.TestAddProject('proj', project_id=789) |
| 121 self.issue_rows = [ |
| 122 (78901, 789, 1, 1, 111L, 222L, now, now, now, 0, 0, 0, 1, 0, False)] |
| 123 self.summary_rows = [(78901, 'sum')] |
| 124 self.label_rows = [(78901, 1, 0)] |
| 125 self.component_rows = [] |
| 126 self.cc_rows = [(78901, 333L, 0)] |
| 127 self.notify_rows = [] |
| 128 self.fieldvalue_rows = [] |
| 129 self.relation_rows = [ |
| 130 (78901, 78902, 'blockedon'), (78903, 78901, 'blockedon')] |
| 131 self.dangling_relation_rows = [ |
| 132 (78901, 'codesite', 5001, 'blocking'), |
| 133 (78901, 'codesite', 5002, 'blockedon')] |
| 134 |
| 135 def tearDown(self): |
| 136 self.mox.UnsetStubs() |
| 137 self.mox.ResetAll() |
| 138 |
| 139 def testDeserializeIssues_Empty(self): |
| 140 issue_dict = self.issue_2lc._DeserializeIssues( |
| 141 self.cnxn, [], [], [], [], [], [], [], [], []) |
| 142 self.assertEqual({}, issue_dict) |
| 143 |
| 144 def testDeserializeIssues_Normal(self): |
| 145 issue_dict = self.issue_2lc._DeserializeIssues( |
| 146 self.cnxn, self.issue_rows, self.summary_rows, self.label_rows, |
| 147 self.component_rows, self.cc_rows, self.notify_rows, |
| 148 self.fieldvalue_rows, self.relation_rows, self.dangling_relation_rows) |
| 149 self.assertItemsEqual([78901], issue_dict.keys()) |
| 150 |
| 151 def testDeserializeIssues_UnexpectedLabel(self): |
| 152 unexpected_label_rows = [ |
| 153 (78901, 999, 0) |
| 154 ] |
| 155 self.assertRaises( |
| 156 AssertionError, |
| 157 self.issue_2lc._DeserializeIssues, |
| 158 self.cnxn, self.issue_rows, self.summary_rows, unexpected_label_rows, |
| 159 self.component_rows, self.cc_rows, self.notify_rows, |
| 160 self.fieldvalue_rows, self.relation_rows, self.dangling_relation_rows) |
| 161 |
| 162 def testDeserializeIssues_UnexpectedIssueRelation(self): |
| 163 unexpected_relation_rows = [ |
| 164 (78990, 78999, 'blockedon') |
| 165 ] |
| 166 self.assertRaises( |
| 167 AssertionError, |
| 168 self.issue_2lc._DeserializeIssues, |
| 169 self.cnxn, self.issue_rows, self.summary_rows, self.label_rows, |
| 170 self.component_rows, self.cc_rows, self.notify_rows, |
| 171 self.fieldvalue_rows, unexpected_relation_rows, |
| 172 self.dangling_relation_rows) |
| 173 |
| 174 def SetUpFetchItems(self, issue_ids): |
| 175 shard_id = None |
| 176 self.issue_service.issue_tbl.Select( |
| 177 self.cnxn, cols=issue_svc.ISSUE_COLS, id=issue_ids, |
| 178 shard_id=shard_id).AndReturn(self.issue_rows) |
| 179 self.issue_service.issuesummary_tbl.Select( |
| 180 self.cnxn, cols=issue_svc.ISSUESUMMARY_COLS, shard_id=shard_id, |
| 181 issue_id=issue_ids).AndReturn(self.summary_rows) |
| 182 self.issue_service.issue2label_tbl.Select( |
| 183 self.cnxn, cols=issue_svc.ISSUE2LABEL_COLS, shard_id=shard_id, |
| 184 issue_id=issue_ids).AndReturn(self.label_rows) |
| 185 self.issue_service.issue2component_tbl.Select( |
| 186 self.cnxn, cols=issue_svc.ISSUE2COMPONENT_COLS, shard_id=shard_id, |
| 187 issue_id=issue_ids).AndReturn(self.component_rows) |
| 188 self.issue_service.issue2cc_tbl.Select( |
| 189 self.cnxn, cols=issue_svc.ISSUE2CC_COLS, shard_id=shard_id, |
| 190 issue_id=issue_ids).AndReturn(self.cc_rows) |
| 191 self.issue_service.issue2notify_tbl.Select( |
| 192 self.cnxn, cols=issue_svc.ISSUE2NOTIFY_COLS, shard_id=shard_id, |
| 193 issue_id=issue_ids).AndReturn(self.notify_rows) |
| 194 self.issue_service.issue2fieldvalue_tbl.Select( |
| 195 self.cnxn, cols=issue_svc.ISSUE2FIELDVALUE_COLS, shard_id=shard_id, |
| 196 issue_id=issue_ids).AndReturn(self.fieldvalue_rows) |
| 197 self.issue_service.issuerelation_tbl.Select( |
| 198 self.cnxn, cols=issue_svc.ISSUERELATION_COLS, # Note: no shard |
| 199 where=[('(issue_id IN (%s) OR dst_issue_id IN (%s))', |
| 200 issue_ids + issue_ids)]).AndReturn(self.relation_rows) |
| 201 self.issue_service.danglingrelation_tbl.Select( |
| 202 self.cnxn, cols=issue_svc.DANGLINGRELATION_COLS, # Note: no shard |
| 203 issue_id=issue_ids).AndReturn(self.dangling_relation_rows) |
| 204 |
| 205 def testFetchItems(self): |
| 206 issue_ids = [78901] |
| 207 self.SetUpFetchItems(issue_ids) |
| 208 self.mox.ReplayAll() |
| 209 issue_dict = self.issue_2lc.FetchItems(self.cnxn, issue_ids) |
| 210 self.mox.VerifyAll() |
| 211 self.assertItemsEqual(issue_ids, issue_dict.keys()) |
| 212 |
| 213 |
| 214 class IssueServiceTest(unittest.TestCase): |
| 215 |
| 216 def setUp(self): |
| 217 self.testbed = testbed.Testbed() |
| 218 self.testbed.activate() |
| 219 self.testbed.init_memcache_stub() |
| 220 |
| 221 self.mox = mox.Mox() |
| 222 self.cnxn = self.mox.CreateMock(sql.MonorailConnection) |
| 223 self.services = service_manager.Services() |
| 224 self.services.user = fake.UserService() |
| 225 self.services.project = fake.ProjectService() |
| 226 self.services.config = fake.ConfigService() |
| 227 self.services.features = fake.FeaturesService() |
| 228 self.cache_manager = fake.CacheManager() |
| 229 self.services.issue = MakeIssueService( |
| 230 self.services.project, self.services.config, self.cache_manager, |
| 231 self.mox) |
| 232 self.services.spam = self.mox.CreateMock(spam_svc.SpamService) |
| 233 self.now = int(time.time()) |
| 234 self.orig_index_issues = tracker_fulltext.IndexIssues |
| 235 tracker_fulltext.IndexIssues = lambda *args: None |
| 236 |
| 237 def classifierResult(self, label, score): |
| 238 return {'outputLabel': label, |
| 239 'outputMulti': [{'label': label, 'score': score}]} |
| 240 |
| 241 def tearDown(self): |
| 242 self.testbed.deactivate() |
| 243 self.mox.UnsetStubs() |
| 244 self.mox.ResetAll() |
| 245 tracker_fulltext.IndexIssues = self.orig_index_issues |
| 246 |
| 247 ### Issue ID lookups |
| 248 |
| 249 def testLookupIssueIDs_Hit(self): |
| 250 self.services.issue.issue_id_2lc.CacheItem((789, 1), 78901) |
| 251 self.services.issue.issue_id_2lc.CacheItem((789, 2), 78902) |
| 252 actual = self.services.issue.LookupIssueIDs( |
| 253 self.cnxn, [(789, 1), (789, 2)]) |
| 254 self.assertEqual([78901, 78902], actual) |
| 255 |
| 256 def testLookupIssueID(self): |
| 257 self.services.issue.issue_id_2lc.CacheItem((789, 1), 78901) |
| 258 actual = self.services.issue.LookupIssueID(self.cnxn, 789, 1) |
| 259 self.assertEqual(78901, actual) |
| 260 |
| 261 def testResolveIssueRefs(self): |
| 262 self.services.issue.issue_id_2lc.CacheItem((789, 1), 78901) |
| 263 self.services.issue.issue_id_2lc.CacheItem((789, 2), 78902) |
| 264 prefetched_projects = {'proj': fake.Project('proj', project_id=789)} |
| 265 refs = [('proj', 1), (None, 2)] |
| 266 actual = self.services.issue.ResolveIssueRefs( |
| 267 self.cnxn, prefetched_projects, 'proj', refs) |
| 268 self.assertEqual([78901, 78902], actual) |
| 269 |
| 270 ### Issue objects |
| 271 |
| 272 def testCreateIssue(self): |
| 273 settings.classifier_spam_thresh = 0.9 |
| 274 self.SetUpAllocateNextLocalID(789, None, None) |
| 275 self.SetUpInsertIssue() |
| 276 self.SetUpInsertComment(7890101, True) |
| 277 self.services.spam.ClassifyIssue(mox.IgnoreArg(), |
| 278 mox.IgnoreArg()).AndReturn( |
| 279 self.classifierResult('ham', 1.0)) |
| 280 self.services.spam.RecordClassifierIssueVerdict(self.cnxn, |
| 281 mox.IsA(tracker_pb2.Issue), False, 1.0) |
| 282 self.SetUpUpdateIssuesModified(set()) |
| 283 |
| 284 self.mox.ReplayAll() |
| 285 actual_local_id = self.services.issue.CreateIssue( |
| 286 self.cnxn, self.services, 789, 'sum', |
| 287 'New', 111L, [], ['Type-Defect'], [], [], 111L, 'content', |
| 288 index_now=False, timestamp=self.now) |
| 289 self.mox.VerifyAll() |
| 290 self.assertEqual(1, actual_local_id) |
| 291 |
| 292 def testCreateIssue_EmptyStringLabels(self): |
| 293 settings.classifier_spam_thresh = 0.9 |
| 294 self.SetUpAllocateNextLocalID(789, None, None) |
| 295 self.SetUpInsertIssue(label_rows=[]) |
| 296 self.SetUpInsertComment(7890101, True) |
| 297 self.services.spam.ClassifyIssue(mox.IgnoreArg(), |
| 298 mox.IgnoreArg()).AndReturn( |
| 299 self.classifierResult('ham', 1.0)) |
| 300 self.services.spam.RecordClassifierIssueVerdict(self.cnxn, |
| 301 mox.IsA(tracker_pb2.Issue), False, 1.0) |
| 302 self.SetUpUpdateIssuesModified(set(), modified_timestamp=self.now) |
| 303 |
| 304 self.mox.ReplayAll() |
| 305 actual_local_id = self.services.issue.CreateIssue( |
| 306 self.cnxn, self.services, 789, 'sum', |
| 307 'New', 111L, [], [',', '', ' ', ', '], [], [], 111L, 'content', |
| 308 index_now=False, timestamp=self.now) |
| 309 self.mox.VerifyAll() |
| 310 self.assertEqual(1, actual_local_id) |
| 311 |
| 312 def SetUpUpdateIssuesModified(self, iids, modified_timestamp=None): |
| 313 self.services.issue.issue_tbl.Update( |
| 314 self.cnxn, {'modified': modified_timestamp or self.now}, |
| 315 id=iids, commit=False) |
| 316 |
| 317 def testCreateIssue_spam(self): |
| 318 settings.classifier_spam_thresh = 0.9 |
| 319 self.SetUpAllocateNextSpamID(789, None, None) |
| 320 self.SetUpInsertSpamIssue() |
| 321 self.SetUpInsertComment(7890101, True) |
| 322 |
| 323 self.services.spam.ClassifyIssue(mox.IsA(tracker_pb2.Issue), |
| 324 mox.IsA(tracker_pb2.IssueComment)).AndReturn( |
| 325 self.classifierResult('spam', 1.0)) |
| 326 self.services.spam.RecordClassifierIssueVerdict(self.cnxn, |
| 327 mox.IsA(tracker_pb2.Issue), True, 1.0) |
| 328 self.SetUpUpdateIssuesModified(set()) |
| 329 |
| 330 self.mox.ReplayAll() |
| 331 actual_local_id = self.services.issue.CreateIssue( |
| 332 self.cnxn, self.services, 789, 'sum', |
| 333 'New', 111L, [], ['Type-Defect'], [], [], 111L, 'content', |
| 334 index_now=False, timestamp=self.now) |
| 335 self.mox.VerifyAll() |
| 336 self.assertEqual(-1, actual_local_id) |
| 337 |
| 338 def testGetAllIssuesInProject_NoIssues(self): |
| 339 self.SetUpGetHighestLocalID(789, None, None) |
| 340 self.mox.ReplayAll() |
| 341 issues = self.services.issue.GetAllIssuesInProject(self.cnxn, 789) |
| 342 self.mox.VerifyAll() |
| 343 self.assertEqual([], issues) |
| 344 |
| 345 def testGetAnyOnHandIssue(self): |
| 346 issue_ids = [78901, 78902, 78903] |
| 347 self.SetUpGetIssues() |
| 348 issue = self.services.issue.GetAnyOnHandIssue(issue_ids) |
| 349 self.assertEqual(78901, issue.issue_id) |
| 350 |
| 351 def SetUpGetIssues(self): |
| 352 issue_1 = fake.MakeTestIssue( |
| 353 project_id=789, local_id=1, owner_id=111L, summary='sum', |
| 354 status='Live', issue_id=78901) |
| 355 issue_1.project_name = 'proj' |
| 356 issue_2 = fake.MakeTestIssue( |
| 357 project_id=789, local_id=2, owner_id=111L, summary='sum', |
| 358 status='Fixed', issue_id=78902) |
| 359 issue_2.project_name = 'proj' |
| 360 self.services.issue.issue_2lc.CacheItem(78901, issue_1) |
| 361 self.services.issue.issue_2lc.CacheItem(78902, issue_2) |
| 362 return issue_1, issue_2 |
| 363 |
| 364 def testGetIssuesDict(self): |
| 365 issue_ids = [78901, 78902] |
| 366 issue_1, issue_2 = self.SetUpGetIssues() |
| 367 issues_dict = self.services.issue.GetIssuesDict(self.cnxn, issue_ids) |
| 368 self.assertEqual( |
| 369 {78901: issue_1, 78902: issue_2}, |
| 370 issues_dict) |
| 371 |
| 372 def testGetIssues(self): |
| 373 issue_ids = [78901, 78902] |
| 374 issue_1, issue_2 = self.SetUpGetIssues() |
| 375 issues = self.services.issue.GetIssues(self.cnxn, issue_ids) |
| 376 self.assertEqual([issue_1, issue_2], issues) |
| 377 |
| 378 def testGetIssue(self): |
| 379 issue_1, _issue_2 = self.SetUpGetIssues() |
| 380 actual_issue = self.services.issue.GetIssue(self.cnxn, 78901) |
| 381 self.assertEqual(issue_1, actual_issue) |
| 382 |
| 383 def testGetIssuesByLocalIDs(self): |
| 384 issue_1, issue_2 = self.SetUpGetIssues() |
| 385 self.services.issue.issue_id_2lc.CacheItem((789, 1), 78901) |
| 386 self.services.issue.issue_id_2lc.CacheItem((789, 2), 78902) |
| 387 actual_issues = self.services.issue.GetIssuesByLocalIDs( |
| 388 self.cnxn, 789, [1, 2]) |
| 389 self.assertEqual([issue_1, issue_2], actual_issues) |
| 390 |
| 391 def testGetIssueByLocalID(self): |
| 392 issue_1, _issue_2 = self.SetUpGetIssues() |
| 393 self.services.issue.issue_id_2lc.CacheItem((789, 1), 78901) |
| 394 actual_issues = self.services.issue.GetIssueByLocalID(self.cnxn, 789, 1) |
| 395 self.assertEqual(issue_1, actual_issues) |
| 396 |
| 397 def testGetOpenAndClosedIssues(self): |
| 398 issue_1, issue_2 = self.SetUpGetIssues() |
| 399 open_issues, closed_issues = self.services.issue.GetOpenAndClosedIssues( |
| 400 self.cnxn, [78901, 78902]) |
| 401 self.assertEqual([issue_1], open_issues) |
| 402 self.assertEqual([issue_2], closed_issues) |
| 403 |
| 404 def SetUpGetCurrentLocationOfMovedIssue(self, project_id, local_id): |
| 405 issue_id = project_id * 100 + local_id |
| 406 self.services.issue.issueformerlocations_tbl.SelectValue( |
| 407 self.cnxn, 'issue_id', default=0, project_id=project_id, |
| 408 local_id=local_id).AndReturn(issue_id) |
| 409 self.services.issue.issue_tbl.SelectRow( |
| 410 self.cnxn, cols=['project_id', 'local_id'], id=issue_id).AndReturn( |
| 411 (project_id + 1, local_id + 1)) |
| 412 |
| 413 def testGetCurrentLocationOfMovedIssue(self): |
| 414 self.SetUpGetCurrentLocationOfMovedIssue(789, 1) |
| 415 self.mox.ReplayAll() |
| 416 new_project_id, new_local_id = ( |
| 417 self.services.issue.GetCurrentLocationOfMovedIssue(self.cnxn, 789, 1)) |
| 418 self.mox.VerifyAll() |
| 419 self.assertEqual(789 + 1, new_project_id) |
| 420 self.assertEqual(1 + 1, new_local_id) |
| 421 |
| 422 def SetUpGetPreviousLocations(self, issue_id, location_rows): |
| 423 self.services.issue.issueformerlocations_tbl.Select( |
| 424 self.cnxn, cols=['project_id', 'local_id'], |
| 425 issue_id=issue_id).AndReturn(location_rows) |
| 426 |
| 427 def testGetPreviousLocations(self): |
| 428 self.SetUpGetPreviousLocations(78901, [(781, 1), (782, 11), (789, 1)]) |
| 429 self.mox.ReplayAll() |
| 430 issue = fake.MakeTestIssue( |
| 431 project_id=789, local_id=1, owner_id=111L, summary='sum', |
| 432 status='Live', issue_id=78901) |
| 433 locations = self.services.issue.GetPreviousLocations(self.cnxn, issue) |
| 434 self.mox.VerifyAll() |
| 435 self.assertEqual(locations, [(781, 1), (782, 11)]) |
| 436 |
| 437 def SetUpInsertIssue(self, label_rows=None): |
| 438 row = (789, 1, 1, 111L, 111L, self.now, 0, self.now, None, 0, |
| 439 False, 0, 0, False) |
| 440 self.services.issue.issue_tbl.InsertRows( |
| 441 self.cnxn, issue_svc.ISSUE_COLS[1:], [row], |
| 442 commit=False, return_generated_ids=True).AndReturn([78901]) |
| 443 self.cnxn.Commit() |
| 444 self.services.issue.issue_tbl.Update( |
| 445 self.cnxn, {'shard': 78901 % settings.num_logical_shards}, |
| 446 id=78901, commit=False) |
| 447 self.SetUpUpdateIssuesSummary() |
| 448 self.SetUpUpdateIssuesLabels(label_rows=label_rows) |
| 449 self.SetUpUpdateIssuesFields() |
| 450 self.SetUpUpdateIssuesComponents() |
| 451 self.SetUpUpdateIssuesCc() |
| 452 self.SetUpUpdateIssuesNotify() |
| 453 self.SetUpUpdateIssuesRelation() |
| 454 |
| 455 def SetUpInsertSpamIssue(self): |
| 456 row = (789, -1, 1, 111L, 111L, self.now, 0, self.now, None, 0, |
| 457 False, 0, 0, True) |
| 458 self.services.issue.issue_tbl.InsertRows( |
| 459 self.cnxn, issue_svc.ISSUE_COLS[1:], [row], |
| 460 commit=False, return_generated_ids=True).AndReturn([78901]) |
| 461 self.cnxn.Commit() |
| 462 self.services.issue.issue_tbl.Update( |
| 463 self.cnxn, {'shard': 78901 % settings.num_logical_shards}, |
| 464 id=78901, commit=False) |
| 465 self.SetUpUpdateIssuesSummary() |
| 466 self.SetUpUpdateIssuesLabels() |
| 467 self.SetUpUpdateIssuesFields() |
| 468 self.SetUpUpdateIssuesComponents() |
| 469 self.SetUpUpdateIssuesCc() |
| 470 self.SetUpUpdateIssuesNotify() |
| 471 self.SetUpUpdateIssuesRelation() |
| 472 |
| 473 def SetUpUpdateIssuesSummary(self): |
| 474 self.services.issue.issuesummary_tbl.InsertRows( |
| 475 self.cnxn, ['issue_id', 'summary'], |
| 476 [(78901, 'sum')], replace=True, commit=False) |
| 477 |
| 478 def SetUpUpdateIssuesLabels(self, label_rows=None): |
| 479 if label_rows is None: |
| 480 label_rows = [(78901, 1, False, 1)] |
| 481 self.services.issue.issue2label_tbl.Delete( |
| 482 self.cnxn, issue_id=[78901], commit=False) |
| 483 self.services.issue.issue2label_tbl.InsertRows( |
| 484 self.cnxn, ['issue_id', 'label_id', 'derived', 'issue_shard'], |
| 485 label_rows, ignore=True, commit=False) |
| 486 |
| 487 def SetUpUpdateIssuesFields(self, issue2fieldvalue_rows=None): |
| 488 issue2fieldvalue_rows = issue2fieldvalue_rows or [] |
| 489 self.services.issue.issue2fieldvalue_tbl.Delete( |
| 490 self.cnxn, issue_id=[78901], commit=False) |
| 491 self.services.issue.issue2fieldvalue_tbl.InsertRows( |
| 492 self.cnxn, issue_svc.ISSUE2FIELDVALUE_COLS + ['issue_shard'], |
| 493 issue2fieldvalue_rows, commit=False) |
| 494 |
| 495 def SetUpUpdateIssuesComponents(self, issue2component_rows=None): |
| 496 issue2component_rows = issue2component_rows or [] |
| 497 self.services.issue.issue2component_tbl.Delete( |
| 498 self.cnxn, issue_id=[78901], commit=False) |
| 499 self.services.issue.issue2component_tbl.InsertRows( |
| 500 self.cnxn, ['issue_id', 'component_id', 'derived', 'issue_shard'], |
| 501 issue2component_rows, ignore=True, commit=False) |
| 502 |
| 503 def SetUpUpdateIssuesCc(self, issue2cc_rows=None): |
| 504 issue2cc_rows = issue2cc_rows or [] |
| 505 self.services.issue.issue2cc_tbl.Delete( |
| 506 self.cnxn, issue_id=[78901], commit=False) |
| 507 self.services.issue.issue2cc_tbl.InsertRows( |
| 508 self.cnxn, ['issue_id', 'cc_id', 'derived', 'issue_shard'], |
| 509 issue2cc_rows, ignore=True, commit=False) |
| 510 |
| 511 def SetUpUpdateIssuesNotify(self, notify_rows=None): |
| 512 notify_rows = notify_rows or [] |
| 513 self.services.issue.issue2notify_tbl.Delete( |
| 514 self.cnxn, issue_id=[78901], commit=False) |
| 515 self.services.issue.issue2notify_tbl.InsertRows( |
| 516 self.cnxn, issue_svc.ISSUE2NOTIFY_COLS, |
| 517 notify_rows, ignore=True, commit=False) |
| 518 |
| 519 def SetUpUpdateIssuesRelation( |
| 520 self, relation_rows=None, dangling_relation_rows=None): |
| 521 relation_rows = relation_rows or [] |
| 522 dangling_relation_rows = dangling_relation_rows or [] |
| 523 self.services.issue.issuerelation_tbl.Delete( |
| 524 self.cnxn, issue_id=[78901], commit=False) |
| 525 self.services.issue.issuerelation_tbl.Delete( |
| 526 self.cnxn, dst_issue_id=[78901], kind='blockedon', |
| 527 commit=False) |
| 528 self.services.issue.issuerelation_tbl.InsertRows( |
| 529 self.cnxn, issue_svc.ISSUERELATION_COLS, relation_rows, |
| 530 ignore=True, commit=False) |
| 531 self.services.issue.danglingrelation_tbl.Delete( |
| 532 self.cnxn, issue_id=[78901], commit=False) |
| 533 self.services.issue.danglingrelation_tbl.InsertRows( |
| 534 self.cnxn, issue_svc.DANGLINGRELATION_COLS, dangling_relation_rows, |
| 535 ignore=True, commit=False) |
| 536 |
| 537 def testInsertIssue(self): |
| 538 self.SetUpInsertIssue() |
| 539 self.mox.ReplayAll() |
| 540 issue = fake.MakeTestIssue( |
| 541 project_id=789, local_id=1, owner_id=111L, reporter_id=111L, |
| 542 summary='sum', status='New', labels=['Type-Defect'], issue_id=78901, |
| 543 opened_timestamp=self.now, modified_timestamp=self.now) |
| 544 actual_issue_id = self.services.issue.InsertIssue(self.cnxn, issue) |
| 545 self.mox.VerifyAll() |
| 546 self.assertEqual(78901, actual_issue_id) |
| 547 |
| 548 def SetUpUpdateIssues(self, given_delta=None): |
| 549 delta = given_delta or { |
| 550 'project_id': 789, |
| 551 'local_id': 1, |
| 552 'owner_id': 111L, |
| 553 'status_id': 1, |
| 554 'opened': 123456789, |
| 555 'closed': 0, |
| 556 'modified': 123456789, |
| 557 'derived_owner_id': None, |
| 558 'derived_status_id': None, |
| 559 'deleted': False, |
| 560 'star_count': 12, |
| 561 'attachment_count': 0, |
| 562 'is_spam': False, |
| 563 } |
| 564 self.services.issue.issue_tbl.Update( |
| 565 self.cnxn, delta, id=78901, commit=False) |
| 566 if not given_delta: |
| 567 self.SetUpUpdateIssuesLabels() |
| 568 self.SetUpUpdateIssuesCc() |
| 569 self.SetUpUpdateIssuesFields() |
| 570 self.SetUpUpdateIssuesComponents() |
| 571 self.SetUpUpdateIssuesNotify() |
| 572 self.SetUpUpdateIssuesSummary() |
| 573 self.SetUpUpdateIssuesRelation() |
| 574 |
| 575 self.cnxn.Commit() |
| 576 |
| 577 def testUpdateIssues_Empty(self): |
| 578 # Note: no setup because DB should not be called. |
| 579 self.mox.ReplayAll() |
| 580 self.services.issue.UpdateIssues(self.cnxn, []) |
| 581 self.mox.VerifyAll() |
| 582 |
| 583 def testUpdateIssues_Normal(self): |
| 584 issue = fake.MakeTestIssue( |
| 585 project_id=789, local_id=1, owner_id=111L, summary='sum', |
| 586 status='Live', labels=['Type-Defect'], issue_id=78901, |
| 587 opened_timestamp=123456789, modified_timestamp=123456789, |
| 588 star_count=12) |
| 589 self.SetUpUpdateIssues() |
| 590 self.mox.ReplayAll() |
| 591 self.services.issue.UpdateIssues(self.cnxn, [issue]) |
| 592 self.mox.VerifyAll() |
| 593 |
| 594 def testUpdateIssue(self): |
| 595 issue = fake.MakeTestIssue( |
| 596 project_id=789, local_id=1, owner_id=111L, summary='sum', |
| 597 status='Live', labels=['Type-Defect'], issue_id=78901, |
| 598 opened_timestamp=123456789, modified_timestamp=123456789, |
| 599 star_count=12) |
| 600 self.SetUpUpdateIssues() |
| 601 self.mox.ReplayAll() |
| 602 self.services.issue.UpdateIssue(self.cnxn, issue) |
| 603 self.mox.VerifyAll() |
| 604 |
| 605 def testUpdateIssuesSummary(self): |
| 606 issue = fake.MakeTestIssue( |
| 607 local_id=1, issue_id=78901, owner_id=111L, summary='sum', status='New', |
| 608 project_id=789) |
| 609 self.SetUpUpdateIssuesSummary() |
| 610 self.mox.ReplayAll() |
| 611 self.services.issue._UpdateIssuesSummary(self.cnxn, [issue], commit=False) |
| 612 self.mox.VerifyAll() |
| 613 |
| 614 def testUpdateIssuesLabels(self): |
| 615 issue = fake.MakeTestIssue( |
| 616 local_id=1, issue_id=78901, owner_id=111L, summary='sum', status='New', |
| 617 labels=['Type-Defect'], project_id=789) |
| 618 self.SetUpUpdateIssuesLabels() |
| 619 self.mox.ReplayAll() |
| 620 self.services.issue._UpdateIssuesLabels( |
| 621 self.cnxn, [issue], 789, commit=False) |
| 622 self.mox.VerifyAll() |
| 623 |
| 624 def testUpdateIssuesFields_Empty(self): |
| 625 issue = fake.MakeTestIssue( |
| 626 local_id=1, issue_id=78901, owner_id=111L, summary='sum', status='New', |
| 627 project_id=789) |
| 628 self.SetUpUpdateIssuesFields() |
| 629 self.mox.ReplayAll() |
| 630 self.services.issue._UpdateIssuesFields(self.cnxn, [issue], commit=False) |
| 631 self.mox.VerifyAll() |
| 632 |
| 633 def testUpdateIssuesFields_Some(self): |
| 634 issue = fake.MakeTestIssue( |
| 635 local_id=1, issue_id=78901, owner_id=111L, summary='sum', status='New', |
| 636 project_id=789) |
| 637 issue_shard = issue.issue_id % settings.num_logical_shards |
| 638 fv1 = tracker_bizobj.MakeFieldValue(345, 679, '', 0L, False) |
| 639 issue.field_values.append(fv1) |
| 640 fv2 = tracker_bizobj.MakeFieldValue(346, 0, 'Blue', 0L, True) |
| 641 issue.field_values.append(fv2) |
| 642 self.SetUpUpdateIssuesFields(issue2fieldvalue_rows=[ |
| 643 (issue.issue_id, fv1.field_id, fv1.int_value, fv1.str_value, |
| 644 None, fv1.derived, issue_shard), |
| 645 (issue.issue_id, fv2.field_id, fv2.int_value, fv2.str_value, |
| 646 None, fv2.derived, issue_shard), |
| 647 ]) |
| 648 self.mox.ReplayAll() |
| 649 self.services.issue._UpdateIssuesFields(self.cnxn, [issue], commit=False) |
| 650 self.mox.VerifyAll() |
| 651 |
| 652 def testUpdateIssuesComponents_Empty(self): |
| 653 issue = fake.MakeTestIssue( |
| 654 project_id=789, local_id=1, owner_id=111L, summary='sum', |
| 655 status='Live', issue_id=78901) |
| 656 self.SetUpUpdateIssuesComponents() |
| 657 self.mox.ReplayAll() |
| 658 self.services.issue._UpdateIssuesComponents( |
| 659 self.cnxn, [issue], commit=False) |
| 660 self.mox.VerifyAll() |
| 661 |
| 662 def testUpdateIssuesCc_Empty(self): |
| 663 issue = fake.MakeTestIssue( |
| 664 project_id=789, local_id=1, owner_id=111L, summary='sum', |
| 665 status='Live', issue_id=78901) |
| 666 self.SetUpUpdateIssuesCc() |
| 667 self.mox.ReplayAll() |
| 668 self.services.issue._UpdateIssuesCc(self.cnxn, [issue], commit=False) |
| 669 self.mox.VerifyAll() |
| 670 |
| 671 def testUpdateIssuesCc_Some(self): |
| 672 issue = fake.MakeTestIssue( |
| 673 project_id=789, local_id=1, owner_id=111L, summary='sum', |
| 674 status='Live', issue_id=78901) |
| 675 issue.cc_ids = [222L, 333L] |
| 676 issue.derived_cc_ids = [888L] |
| 677 issue_shard = issue.issue_id % settings.num_logical_shards |
| 678 self.SetUpUpdateIssuesCc(issue2cc_rows=[ |
| 679 (issue.issue_id, 222L, False, issue_shard), |
| 680 (issue.issue_id, 333L, False, issue_shard), |
| 681 (issue.issue_id, 888L, True, issue_shard), |
| 682 ]) |
| 683 self.mox.ReplayAll() |
| 684 self.services.issue._UpdateIssuesCc(self.cnxn, [issue], commit=False) |
| 685 self.mox.VerifyAll() |
| 686 |
| 687 def testUpdateIssuesNotify_Empty(self): |
| 688 issue = fake.MakeTestIssue( |
| 689 project_id=789, local_id=1, owner_id=111L, summary='sum', |
| 690 status='Live', issue_id=78901) |
| 691 self.SetUpUpdateIssuesNotify() |
| 692 self.mox.ReplayAll() |
| 693 self.services.issue._UpdateIssuesNotify(self.cnxn, [issue], commit=False) |
| 694 self.mox.VerifyAll() |
| 695 |
| 696 def testUpdateIssuesRelation_Empty(self): |
| 697 issue = fake.MakeTestIssue( |
| 698 project_id=789, local_id=1, owner_id=111L, summary='sum', |
| 699 status='Live', issue_id=78901) |
| 700 self.SetUpUpdateIssuesRelation() |
| 701 self.mox.ReplayAll() |
| 702 self.services.issue._UpdateIssuesRelation(self.cnxn, [issue], commit=False) |
| 703 self.mox.VerifyAll() |
| 704 |
| 705 def testDeltaUpdateIssue(self): |
| 706 pass # TODO(jrobbins): write more tests |
| 707 |
| 708 def testDeltaUpdateIssue_MergedInto(self): |
| 709 commenter_id = 222L |
| 710 issue = fake.MakeTestIssue( |
| 711 project_id=789, local_id=1, owner_id=111L, summary='sum', |
| 712 status='Live', issue_id=78901, project_name='proj') |
| 713 target_issue = fake.MakeTestIssue( |
| 714 project_id=789, local_id=2, owner_id=111L, summary='sum sum', |
| 715 status='Live', issue_id=78902, project_name='proj') |
| 716 config = tracker_bizobj.MakeDefaultProjectIssueConfig(789) |
| 717 |
| 718 self.mox.StubOutWithMock(self.services.issue, 'GetIssue') |
| 719 self.mox.StubOutWithMock(self.services.issue, 'UpdateIssue') |
| 720 self.mox.StubOutWithMock(self.services.issue, 'CreateIssueComment') |
| 721 self.mox.StubOutWithMock(self.services.issue, '_UpdateIssuesModified') |
| 722 |
| 723 self.services.issue.GetIssue( |
| 724 self.cnxn, 0).AndRaise(issue_svc.NoSuchIssueException) |
| 725 self.services.issue.GetIssue( |
| 726 self.cnxn, target_issue.issue_id).AndReturn(target_issue) |
| 727 self.services.issue.UpdateIssue( |
| 728 self.cnxn, issue, commit=False, invalidate=False) |
| 729 amendments = [ |
| 730 tracker_bizobj.MakeMergedIntoAmendment( |
| 731 ('proj', 2), None, default_project_name='proj')] |
| 732 self.services.issue.CreateIssueComment( |
| 733 self.cnxn, 789, 1, commenter_id, 'comment text', |
| 734 amendments=amendments, commit=False) |
| 735 self.services.issue._UpdateIssuesModified( |
| 736 self.cnxn, {issue.issue_id, target_issue.issue_id}, |
| 737 modified_timestamp=self.now, invalidate=True) |
| 738 |
| 739 self.mox.ReplayAll() |
| 740 self.services.issue.DeltaUpdateIssue( |
| 741 self.cnxn, self.services, commenter_id, issue.project_id, config, |
| 742 issue, issue.status, issue.owner_id, |
| 743 [], [], [], [], [], [], [], [], [], |
| 744 merged_into=target_issue.issue_id, comment='comment text', |
| 745 index_now=False, timestamp=self.now) |
| 746 self.mox.VerifyAll() |
| 747 |
| 748 def testApplyIssueComment(self): |
| 749 issue = fake.MakeTestIssue( |
| 750 project_id=789, local_id=1, owner_id=111L, summary='sum', |
| 751 status='Live', issue_id=78901) |
| 752 |
| 753 self.mox.StubOutWithMock(self.services.issue, 'GetIssueByLocalID') |
| 754 self.mox.StubOutWithMock(self.services.issue, 'UpdateIssues') |
| 755 self.mox.StubOutWithMock(self.services.issue, 'GetCommentsForIssue') |
| 756 self.mox.StubOutWithMock(self.services.issue, 'SoftDeleteComment') |
| 757 self.mox.StubOutWithMock(self.services.issue, "CreateIssueComment") |
| 758 self.mox.StubOutWithMock(self.services.issue, "_UpdateIssuesModified") |
| 759 |
| 760 self.services.issue.GetIssueByLocalID(self.cnxn, issue.project_id, |
| 761 issue.local_id).AndReturn(issue) |
| 762 self.services.issue.CreateIssueComment(self.cnxn, issue.project_id, |
| 763 issue.local_id, issue.reporter_id, 'comment text', |
| 764 amendments=[], attachments=None, inbound_message=None, |
| 765 is_spam=False) |
| 766 self.services.issue.UpdateIssues(self.cnxn, [issue], |
| 767 just_derived=False, update_cols=None, commit=True, invalidate=True) |
| 768 self.services.spam.ClassifyComment('comment text').AndReturn( |
| 769 self.classifierResult('ham', 1.0)) |
| 770 self.services.spam.RecordClassifierCommentVerdict(self.cnxn, |
| 771 None, False, 1.0) |
| 772 self.services.issue._UpdateIssuesModified( |
| 773 self.cnxn, set(), modified_timestamp=self.now) |
| 774 |
| 775 self.mox.ReplayAll() |
| 776 self.services.issue.ApplyIssueComment(self.cnxn, self.services, |
| 777 issue.reporter_id, issue.project_id, issue.local_id, issue.summary, |
| 778 issue.status, issue.owner_id, issue.cc_ids, issue.labels, |
| 779 issue.field_values, issue.component_ids, [], |
| 780 [], [], [], issue.merged_into, comment='comment text', |
| 781 timestamp=self.now) |
| 782 self.mox.VerifyAll() |
| 783 |
| 784 def testApplyIssueComment_spam(self): |
| 785 settings.classifier_spam_thresh = 0.5 |
| 786 |
| 787 issue = fake.MakeTestIssue( |
| 788 project_id=789, local_id=1, owner_id=111L, summary='sum', |
| 789 status='Live', issue_id=78901) |
| 790 |
| 791 self.mox.StubOutWithMock(self.services.issue, "GetIssueByLocalID") |
| 792 self.mox.StubOutWithMock(self.services.issue, "UpdateIssues") |
| 793 self.mox.StubOutWithMock(self.services.issue, "GetCommentsForIssue") |
| 794 self.mox.StubOutWithMock(self.services.issue, "CreateIssueComment") |
| 795 self.mox.StubOutWithMock(self.services.issue, "SoftDeleteComment") |
| 796 self.mox.StubOutWithMock(self.services.issue, "_UpdateIssuesModified") |
| 797 |
| 798 self.services.issue.GetIssueByLocalID(self.cnxn, 789, 1).AndReturn(issue) |
| 799 self.services.issue.UpdateIssues(self.cnxn, [issue], |
| 800 just_derived=False, update_cols=None, commit=True, invalidate=True) |
| 801 self.services.issue.GetCommentsForIssue(self.cnxn, |
| 802 issue.issue_id).AndReturn([""]) |
| 803 self.services.issue.SoftDeleteComment(self.cnxn, |
| 804 issue.project_id, issue.local_id, 0, issue.reporter_id, |
| 805 self.services.user, is_spam=True) |
| 806 self.services.spam.ClassifyComment('comment text').AndReturn( |
| 807 self.classifierResult('spam', 1.0)) |
| 808 self.services.spam.RecordClassifierCommentVerdict(self.cnxn, |
| 809 mox.IsA(tracker_pb2.IssueComment), True, 1.0) |
| 810 self.services.issue.CreateIssueComment(self.cnxn, issue.project_id, |
| 811 issue.local_id, issue.reporter_id, 'comment text', |
| 812 amendments=[], attachments=None, inbound_message=None, |
| 813 is_spam=True).AndReturn(tracker_pb2.IssueComment()) |
| 814 self.services.issue._UpdateIssuesModified( |
| 815 self.cnxn, set(), modified_timestamp=self.now) |
| 816 |
| 817 self.mox.ReplayAll() |
| 818 self.services.issue.ApplyIssueComment(self.cnxn, self.services, |
| 819 issue.reporter_id, issue.project_id, issue.local_id, issue.summary, |
| 820 issue.status, issue.owner_id, issue.cc_ids, issue.labels, |
| 821 issue.field_values, issue.component_ids, [], |
| 822 [], [], [], issue.merged_into, comment='comment text', |
| 823 timestamp=self.now) |
| 824 self.mox.VerifyAll() |
| 825 |
| 826 def testApplyIssueComment_blockedon(self): |
| 827 issue = fake.MakeTestIssue( |
| 828 project_id=789, local_id=1, owner_id=111L, summary='sum', |
| 829 status='Live', issue_id=78901) |
| 830 blockedon_issue = fake.MakeTestIssue( |
| 831 project_id=789, local_id=2, owner_id=111L, summary='sum', |
| 832 status='Live', issue_id=78902) |
| 833 |
| 834 self.mox.StubOutWithMock(self.services.issue, "GetIssueByLocalID") |
| 835 self.mox.StubOutWithMock(self.services.issue, "UpdateIssues") |
| 836 self.mox.StubOutWithMock(self.services.issue, "CreateIssueComment") |
| 837 self.mox.StubOutWithMock(self.services.issue, "GetIssues") |
| 838 self.mox.StubOutWithMock(self.services.issue, "_UpdateIssuesModified") |
| 839 # Call to find added blockedon issues. |
| 840 self.services.issue.GetIssues( |
| 841 self.cnxn, [blockedon_issue.issue_id]).AndReturn([blockedon_issue]) |
| 842 # Call to find removed blockedon issues. |
| 843 self.services.issue.GetIssues(self.cnxn, []).AndReturn([]) |
| 844 |
| 845 self.services.issue.GetIssueByLocalID(self.cnxn, 789, 1).AndReturn(issue) |
| 846 self.services.issue.UpdateIssues(self.cnxn, [issue], |
| 847 just_derived=False, update_cols=None, commit=True, invalidate=True) |
| 848 self.services.spam.ClassifyComment('comment text').AndReturn( |
| 849 self.classifierResult('ham', 1.0)) |
| 850 self.services.spam.RecordClassifierCommentVerdict(self.cnxn, |
| 851 mox.IsA(tracker_pb2.IssueComment), False, 1.0) |
| 852 self.services.issue.CreateIssueComment(self.cnxn, issue.project_id, |
| 853 issue.local_id, issue.reporter_id, 'comment text', |
| 854 amendments=[ |
| 855 tracker_bizobj.MakeBlockedOnAmendment( |
| 856 [(blockedon_issue.project_name, blockedon_issue.local_id)], [], |
| 857 default_project_name=blockedon_issue.project_name)], |
| 858 attachments=None, inbound_message=None, |
| 859 is_spam=False).AndReturn(tracker_pb2.IssueComment()) |
| 860 # Add a comment on the blockedon issue. |
| 861 self.services.issue.CreateIssueComment( |
| 862 self.cnxn, blockedon_issue.project_id, blockedon_issue.local_id, |
| 863 blockedon_issue.reporter_id, content='', |
| 864 amendments=[tracker_bizobj.MakeBlockingAmendment( |
| 865 [(issue.project_name, issue.local_id)], [], |
| 866 default_project_name=issue.project_name)]) |
| 867 self.services.issue._UpdateIssuesModified( |
| 868 self.cnxn, {blockedon_issue.issue_id}, modified_timestamp=self.now) |
| 869 |
| 870 self.mox.ReplayAll() |
| 871 self.services.issue.ApplyIssueComment(self.cnxn, self.services, |
| 872 issue.reporter_id, issue.project_id, issue.local_id, issue.summary, |
| 873 issue.status, issue.owner_id, issue.cc_ids, issue.labels, |
| 874 issue.field_values, issue.component_ids, [blockedon_issue.issue_id], |
| 875 [], [], [], issue.merged_into, comment='comment text', |
| 876 timestamp=self.now) |
| 877 self.mox.VerifyAll() |
| 878 |
| 879 def SetUpMoveIssues_NewProject(self): |
| 880 self.services.issue.issueformerlocations_tbl.Select( |
| 881 self.cnxn, cols=issue_svc.ISSUEFORMERLOCATIONS_COLS, project_id=789, |
| 882 issue_id=[78901]).AndReturn([]) |
| 883 self.SetUpAllocateNextLocalID(789, None, None) |
| 884 self.SetUpUpdateIssues() |
| 885 self.services.issue.comment_tbl.Update( |
| 886 self.cnxn, {'project_id': 789}, issue_id=[78901], commit=False) |
| 887 |
| 888 old_location_rows = [(78901, 711, 2)] |
| 889 self.services.issue.issueformerlocations_tbl.InsertRows( |
| 890 self.cnxn, issue_svc.ISSUEFORMERLOCATIONS_COLS, old_location_rows, |
| 891 ignore=True, commit=False) |
| 892 self.cnxn.Commit() |
| 893 |
| 894 def testMoveIssues_NewProject(self): |
| 895 """Move project 711 issue 2 to become project 789 issue 1.""" |
| 896 dest_project = fake.Project(project_id=789) |
| 897 issue = fake.MakeTestIssue( |
| 898 project_id=711, local_id=2, owner_id=111L, summary='sum', |
| 899 status='Live', labels=['Type-Defect'], issue_id=78901, |
| 900 opened_timestamp=123456789, modified_timestamp=123456789, |
| 901 star_count=12) |
| 902 self.SetUpMoveIssues_NewProject() |
| 903 self.mox.ReplayAll() |
| 904 self.services.issue.MoveIssues( |
| 905 self.cnxn, dest_project, [issue], self.services.user) |
| 906 self.mox.VerifyAll() |
| 907 |
| 908 # TODO(jrobbins): case where issue is moved back into former project |
| 909 |
| 910 def testExpungeFormerLocations(self): |
| 911 self.services.issue.issueformerlocations_tbl.Delete( |
| 912 self.cnxn, project_id=789) |
| 913 |
| 914 self.mox.ReplayAll() |
| 915 self.services.issue.ExpungeFormerLocations(self.cnxn, 789) |
| 916 self.mox.VerifyAll() |
| 917 |
| 918 def testExpungeIssues(self): |
| 919 issue_ids = [1, 2] |
| 920 |
| 921 self.mox.StubOutWithMock(search, 'Index') |
| 922 search.Index(name=settings.search_index_name_format % 1).AndReturn( |
| 923 MockIndex()) |
| 924 search.Index(name=settings.search_index_name_format % 2).AndReturn( |
| 925 MockIndex()) |
| 926 |
| 927 self.services.issue.issuesummary_tbl.Delete(self.cnxn, issue_id=[1, 2]) |
| 928 self.services.issue.issue2label_tbl.Delete(self.cnxn, issue_id=[1, 2]) |
| 929 self.services.issue.issue2component_tbl.Delete(self.cnxn, issue_id=[1, 2]) |
| 930 self.services.issue.issue2cc_tbl.Delete(self.cnxn, issue_id=[1, 2]) |
| 931 self.services.issue.issue2notify_tbl.Delete(self.cnxn, issue_id=[1, 2]) |
| 932 self.services.issue.issueupdate_tbl.Delete(self.cnxn, issue_id=[1, 2]) |
| 933 self.services.issue.attachment_tbl.Delete(self.cnxn, issue_id=[1, 2]) |
| 934 self.services.issue.comment_tbl.Delete(self.cnxn, issue_id=[1, 2]) |
| 935 self.services.issue.issuerelation_tbl.Delete(self.cnxn, issue_id=[1, 2]) |
| 936 self.services.issue.issuerelation_tbl.Delete(self.cnxn, dst_issue_id=[1, 2]) |
| 937 self.services.issue.danglingrelation_tbl.Delete(self.cnxn, issue_id=[1, 2]) |
| 938 self.services.issue.issueformerlocations_tbl.Delete( |
| 939 self.cnxn, issue_id=[1, 2]) |
| 940 self.services.issue.reindexqueue_tbl.Delete(self.cnxn, issue_id=[1, 2]) |
| 941 self.services.issue.issue_tbl.Delete(self.cnxn, id=[1, 2]) |
| 942 |
| 943 self.mox.ReplayAll() |
| 944 self.services.issue.ExpungeIssues(self.cnxn, issue_ids) |
| 945 self.mox.VerifyAll() |
| 946 |
| 947 def testSoftDeleteIssue(self): |
| 948 project = fake.Project(project_id=789) |
| 949 issue_1, _issue_2 = self.SetUpGetIssues() |
| 950 self.services.issue.issue_id_2lc.CacheItem((789, 1), 78901) |
| 951 delta = {'deleted': True} |
| 952 self.services.issue.issue_tbl.Update( |
| 953 self.cnxn, delta, id=78901, commit=False) |
| 954 self.cnxn.Commit() |
| 955 self.mox.ReplayAll() |
| 956 self.services.issue.SoftDeleteIssue( |
| 957 self.cnxn, project.project_id, 1, True, self.services.user) |
| 958 self.mox.VerifyAll() |
| 959 self.assertTrue(issue_1.deleted) |
| 960 |
| 961 def SetUpDeleteComponentReferences(self, component_id): |
| 962 self.services.issue.issue2component_tbl.Delete( |
| 963 self.cnxn, component_id=component_id) |
| 964 |
| 965 def testDeleteComponentReferences(self): |
| 966 self.SetUpDeleteComponentReferences(123) |
| 967 self.mox.ReplayAll() |
| 968 self.services.issue.DeleteComponentReferences(self.cnxn, 123) |
| 969 self.mox.VerifyAll() |
| 970 |
| 971 ### Local ID generation |
| 972 |
| 973 def SetUpInitializeLocalID(self, project_id): |
| 974 self.services.issue.localidcounter_tbl.InsertRow( |
| 975 self.cnxn, project_id=project_id, used_local_id=0, used_spam_id=0) |
| 976 |
| 977 def testInitializeLocalID(self): |
| 978 self.SetUpInitializeLocalID(789) |
| 979 self.mox.ReplayAll() |
| 980 self.services.issue.InitializeLocalID(self.cnxn, 789) |
| 981 self.mox.VerifyAll() |
| 982 |
| 983 def SetUpAllocateNextLocalID( |
| 984 self, project_id, highest_in_use, highest_former): |
| 985 highest_either = max(highest_in_use or 0, highest_former or 0) |
| 986 self.services.issue.localidcounter_tbl.IncrementCounterValue( |
| 987 self.cnxn, 'used_local_id', project_id=project_id).AndReturn( |
| 988 highest_either + 1) |
| 989 |
| 990 def SetUpAllocateNextSpamID( |
| 991 self, project_id, highest_in_use, highest_former): |
| 992 highest_either = max(highest_in_use or 0, highest_former or 0) |
| 993 self.services.issue.localidcounter_tbl.IncrementCounterValue( |
| 994 self.cnxn, 'used_spam_id', project_id=project_id).AndReturn( |
| 995 highest_either + 1) |
| 996 |
| 997 def testAllocateNextLocalID_NewProject(self): |
| 998 self.SetUpAllocateNextLocalID(789, None, None) |
| 999 self.mox.ReplayAll() |
| 1000 next_local_id = self.services.issue.AllocateNextLocalID(self.cnxn, 789) |
| 1001 self.mox.VerifyAll() |
| 1002 self.assertEqual(1, next_local_id) |
| 1003 |
| 1004 def testAllocateNextLocalID_HighestInUse(self): |
| 1005 self.SetUpAllocateNextLocalID(789, 14, None) |
| 1006 self.mox.ReplayAll() |
| 1007 next_local_id = self.services.issue.AllocateNextLocalID(self.cnxn, 789) |
| 1008 self.mox.VerifyAll() |
| 1009 self.assertEqual(15, next_local_id) |
| 1010 |
| 1011 def testAllocateNextLocalID_HighestWasMoved(self): |
| 1012 self.SetUpAllocateNextLocalID(789, 23, 66) |
| 1013 self.mox.ReplayAll() |
| 1014 next_local_id = self.services.issue.AllocateNextLocalID(self.cnxn, 789) |
| 1015 self.mox.VerifyAll() |
| 1016 self.assertEqual(67, next_local_id) |
| 1017 |
| 1018 def SetUpGetHighestLocalID(self, project_id, highest_in_use, highest_former): |
| 1019 self.services.issue.issue_tbl.SelectValue( |
| 1020 self.cnxn, 'MAX(local_id)', project_id=project_id).AndReturn( |
| 1021 highest_in_use) |
| 1022 self.services.issue.issueformerlocations_tbl.SelectValue( |
| 1023 self.cnxn, 'MAX(local_id)', project_id=project_id).AndReturn( |
| 1024 highest_former) |
| 1025 |
| 1026 def testGetHighestLocalID_OnlyActiveLocalIDs(self): |
| 1027 self.SetUpGetHighestLocalID(789, 14, None) |
| 1028 self.mox.ReplayAll() |
| 1029 highest_id = self.services.issue.GetHighestLocalID(self.cnxn, 789) |
| 1030 self.mox.VerifyAll() |
| 1031 self.assertEqual(14, highest_id) |
| 1032 |
| 1033 def testGetHighestLocalID_OnlyFormerIDs(self): |
| 1034 self.SetUpGetHighestLocalID(789, None, 97) |
| 1035 self.mox.ReplayAll() |
| 1036 highest_id = self.services.issue.GetHighestLocalID(self.cnxn, 789) |
| 1037 self.mox.VerifyAll() |
| 1038 self.assertEqual(97, highest_id) |
| 1039 |
| 1040 def testGetHighestLocalID_BothActiveAndFormer(self): |
| 1041 self.SetUpGetHighestLocalID(789, 345, 97) |
| 1042 self.mox.ReplayAll() |
| 1043 highest_id = self.services.issue.GetHighestLocalID(self.cnxn, 789) |
| 1044 self.mox.VerifyAll() |
| 1045 self.assertEqual(345, highest_id) |
| 1046 |
| 1047 def testGetAllLocalIDsInProject(self): |
| 1048 self.SetUpGetHighestLocalID(789, 14, None) |
| 1049 self.mox.ReplayAll() |
| 1050 local_id_range = self.services.issue.GetAllLocalIDsInProject(self.cnxn, 789) |
| 1051 self.mox.VerifyAll() |
| 1052 self.assertEqual(range(1, 15), local_id_range) |
| 1053 |
| 1054 ### Comments |
| 1055 |
| 1056 def testDeserializeComments_Empty(self): |
| 1057 comments = self.services.issue._DeserializeComments([], [], []) |
| 1058 self.assertEqual([], comments) |
| 1059 |
| 1060 def SetUpCommentRows(self): |
| 1061 comment_rows = [ |
| 1062 (7890101, 78901, self.now, 789, 111L, |
| 1063 'content', None, True, None, False)] |
| 1064 amendment_rows = [ |
| 1065 (1, 78901, 7890101, 'cc', 'old', 'new val', 222, None, None)] |
| 1066 attachment_rows = [] |
| 1067 return comment_rows, amendment_rows, attachment_rows |
| 1068 |
| 1069 def testDeserializeComments(self): |
| 1070 comment_rows, amendment_rows, attachment_rows = self.SetUpCommentRows() |
| 1071 comments = self.services.issue._DeserializeComments( |
| 1072 comment_rows, amendment_rows, attachment_rows) |
| 1073 self.assertEqual(1, len(comments)) |
| 1074 |
| 1075 def SetUpGetComments(self, issue_ids): |
| 1076 # Assumes one comment per issue. |
| 1077 cids = [issue_id + 1000 for issue_id in issue_ids] |
| 1078 self.services.issue.comment_tbl.Select( |
| 1079 self.cnxn, cols=['Comment.id'] + issue_svc.COMMENT_COLS[1:], |
| 1080 where=None, issue_id=issue_ids, order_by=[('created', [])]).AndReturn([ |
| 1081 (issue_id + 1000, issue_id, self.now, 789, 111L, 'content', |
| 1082 None, True, None, False) for issue_id in issue_ids]) |
| 1083 # Assume no amendments or attachment for now. |
| 1084 self.services.issue.issueupdate_tbl.Select( |
| 1085 self.cnxn, cols=issue_svc.ISSUEUPDATE_COLS, |
| 1086 comment_id=cids).AndReturn([]) |
| 1087 if issue_ids: |
| 1088 attachment_rows = [ |
| 1089 (1234, issue_ids[0], cids[0], 'a_filename', 1024, 'text/plain', |
| 1090 False, None)] |
| 1091 else: |
| 1092 attachment_rows = [] |
| 1093 |
| 1094 self.services.issue.attachment_tbl.Select( |
| 1095 self.cnxn, cols=issue_svc.ATTACHMENT_COLS, |
| 1096 comment_id=cids).AndReturn(attachment_rows) |
| 1097 |
| 1098 def testGetComments(self): |
| 1099 self.SetUpGetComments([100001, 100002]) |
| 1100 self.mox.ReplayAll() |
| 1101 comments = self.services.issue.GetComments( |
| 1102 self.cnxn, issue_id=[100001, 100002]) |
| 1103 self.mox.VerifyAll() |
| 1104 self.assertEqual(2, len(comments)) |
| 1105 self.assertEqual('content', comments[0].content) |
| 1106 self.assertEqual('content', comments[1].content) |
| 1107 |
| 1108 def SetUpGetComment_Found(self, comment_id): |
| 1109 # Assumes one comment per issue. |
| 1110 self.services.issue.comment_tbl.Select( |
| 1111 self.cnxn, cols=['Comment.id'] + issue_svc.COMMENT_COLS[1:], |
| 1112 where=None, id=comment_id, order_by=[('created', [])]).AndReturn([ |
| 1113 (comment_id, int(comment_id / 100), self.now, 789, 111L, 'content', |
| 1114 None, True, None, False)]) |
| 1115 # Assume no amendments or attachment for now. |
| 1116 self.services.issue.issueupdate_tbl.Select( |
| 1117 self.cnxn, cols=issue_svc.ISSUEUPDATE_COLS, |
| 1118 comment_id=[comment_id]).AndReturn([]) |
| 1119 self.services.issue.attachment_tbl.Select( |
| 1120 self.cnxn, cols=issue_svc.ATTACHMENT_COLS, |
| 1121 comment_id=[comment_id]).AndReturn([]) |
| 1122 |
| 1123 def testGetComment_Found(self): |
| 1124 self.SetUpGetComment_Found(7890101) |
| 1125 self.mox.ReplayAll() |
| 1126 comment = self.services.issue.GetComment(self.cnxn, 7890101) |
| 1127 self.mox.VerifyAll() |
| 1128 self.assertEqual('content', comment.content) |
| 1129 |
| 1130 def SetUpGetComment_Missing(self, comment_id): |
| 1131 # Assumes one comment per issue. |
| 1132 self.services.issue.comment_tbl.Select( |
| 1133 self.cnxn, cols=['Comment.id'] + issue_svc.COMMENT_COLS[1:], |
| 1134 where=None, id=comment_id, order_by=[('created', [])]).AndReturn([]) |
| 1135 # Assume no amendments or attachment for now. |
| 1136 self.services.issue.issueupdate_tbl.Select( |
| 1137 self.cnxn, cols=issue_svc.ISSUEUPDATE_COLS, |
| 1138 comment_id=[]).AndReturn([]) |
| 1139 self.services.issue.attachment_tbl.Select( |
| 1140 self.cnxn, cols=issue_svc.ATTACHMENT_COLS, comment_id=[]).AndReturn([]) |
| 1141 |
| 1142 def testGetComment_Missing(self): |
| 1143 self.SetUpGetComment_Missing(7890101) |
| 1144 self.mox.ReplayAll() |
| 1145 self.assertRaises( |
| 1146 issue_svc.NoSuchCommentException, |
| 1147 self.services.issue.GetComment, self.cnxn, 7890101) |
| 1148 self.mox.VerifyAll() |
| 1149 |
| 1150 def testGetCommentsForIssue(self): |
| 1151 issue = fake.MakeTestIssue(789, 1, 'Summary', 'New', 111L) |
| 1152 self.SetUpGetComments([issue.issue_id]) |
| 1153 self.mox.ReplayAll() |
| 1154 self.services.issue.GetCommentsForIssue(self.cnxn, issue.issue_id) |
| 1155 self.mox.VerifyAll() |
| 1156 |
| 1157 def testGetCommentsForIssues(self): |
| 1158 self.SetUpGetComments([100001, 100002]) |
| 1159 self.mox.ReplayAll() |
| 1160 self.services.issue.GetCommentsForIssues( |
| 1161 self.cnxn, issue_ids=[100001, 100002]) |
| 1162 self.mox.VerifyAll() |
| 1163 |
| 1164 def SetUpInsertComment(self, comment_id, was_escaped, is_spam=False): |
| 1165 self.services.issue.comment_tbl.InsertRow( |
| 1166 self.cnxn, issue_id=78901, created=self.now, project_id=789, |
| 1167 commenter_id=111L, content='content', inbound_message=None, |
| 1168 was_escaped=was_escaped, deleted_by=None, is_spam=is_spam, |
| 1169 commit=True).AndReturn(comment_id) |
| 1170 |
| 1171 amendment_rows = [] |
| 1172 self.services.issue.issueupdate_tbl.InsertRows( |
| 1173 self.cnxn, issue_svc.ISSUEUPDATE_COLS[1:], amendment_rows, |
| 1174 commit=True) |
| 1175 |
| 1176 attachment_rows = [] |
| 1177 self.services.issue.attachment_tbl.InsertRows( |
| 1178 self.cnxn, issue_svc.ATTACHMENT_COLS[1:], attachment_rows, |
| 1179 commit=True) |
| 1180 |
| 1181 def testInsertComment(self): |
| 1182 self.SetUpInsertComment(7890101, False) |
| 1183 self.mox.ReplayAll() |
| 1184 comment = tracker_pb2.IssueComment( |
| 1185 issue_id=78901, timestamp=self.now, project_id=789, user_id=111L, |
| 1186 content='content', was_escaped=False) |
| 1187 self.services.issue.InsertComment(self.cnxn, comment, commit=True) |
| 1188 self.mox.VerifyAll() |
| 1189 self.assertEqual(7890101, comment.id) |
| 1190 |
| 1191 def SetUpUpdateComment(self, comment_id, delta=None): |
| 1192 delta = delta or { |
| 1193 'commenter_id': 111L, |
| 1194 'content': 'new content', |
| 1195 'deleted_by': 222L, |
| 1196 'is_spam': False, |
| 1197 } |
| 1198 self.services.issue.comment_tbl.Update( |
| 1199 self.cnxn, delta, id=comment_id) |
| 1200 |
| 1201 def testUpdateComment(self): |
| 1202 self.SetUpUpdateComment(7890101) |
| 1203 self.mox.ReplayAll() |
| 1204 comment = tracker_pb2.IssueComment( |
| 1205 id=7890101, issue_id=78901, timestamp=self.now, project_id=789, |
| 1206 user_id=111L, content='new content', was_escaped=True, deleted_by=222L, |
| 1207 is_spam=False) |
| 1208 self.services.issue._UpdateComment(self.cnxn, comment) |
| 1209 self.mox.VerifyAll() |
| 1210 |
| 1211 def testMakeIssueComment(self): |
| 1212 comment = self.services.issue._MakeIssueComment( |
| 1213 789, 111L, 'content', timestamp=self.now) |
| 1214 self.assertEqual('content', comment.content) |
| 1215 self.assertEqual([], comment.amendments) |
| 1216 self.assertEqual([], comment.attachments) |
| 1217 |
| 1218 def testCreateIssueComment(self): |
| 1219 _issue_1, _issue_2 = self.SetUpGetIssues() |
| 1220 self.services.issue.issue_id_2lc.CacheItem((789, 1), 78901) |
| 1221 self.SetUpInsertComment(7890101, False) |
| 1222 self.mox.ReplayAll() |
| 1223 comment = self.services.issue.CreateIssueComment( |
| 1224 self.cnxn, 789, 1, 111L, 'content', timestamp=self.now) |
| 1225 self.mox.VerifyAll() |
| 1226 self.assertEqual('content', comment.content) |
| 1227 |
| 1228 def testCreateIssueComment_spam(self): |
| 1229 _issue_1, _issue_2 = self.SetUpGetIssues() |
| 1230 self.services.issue.issue_id_2lc.CacheItem((789, 1), 78901) |
| 1231 self.SetUpInsertComment(7890101, False, is_spam=True) |
| 1232 self.mox.ReplayAll() |
| 1233 comment = self.services.issue.CreateIssueComment( |
| 1234 self.cnxn, 789, 1, 111L, 'content', timestamp=self.now, is_spam=True) |
| 1235 self.mox.VerifyAll() |
| 1236 self.assertEqual('content', comment.content) |
| 1237 self.assertTrue(comment.is_spam) |
| 1238 |
| 1239 def testSoftDeleteComment(self): |
| 1240 issue_1, _issue_2 = self.SetUpGetIssues() |
| 1241 issue_1.attachment_count = 1 |
| 1242 self.services.issue.issue_id_2lc.CacheItem((789, 1), 78901) |
| 1243 self.SetUpGetComments([78901]) |
| 1244 self.SetUpUpdateComment(79901, delta={'deleted_by': 222L, 'is_spam': False}) |
| 1245 self.SetUpUpdateIssues(given_delta={'attachment_count': 0}) |
| 1246 self.mox.ReplayAll() |
| 1247 self.services.issue.SoftDeleteComment( |
| 1248 self.cnxn, 789, 1, 0, 222L, self.services.user) |
| 1249 self.mox.VerifyAll() |
| 1250 |
| 1251 ### Attachments |
| 1252 |
| 1253 def testGetAttachmentAndContext(self): |
| 1254 # TODO(jrobbins): re-implemnent to use Google Cloud Storage. |
| 1255 pass |
| 1256 |
| 1257 def SetUpUpdateAttachment(self, attachment_id, delta): |
| 1258 self.services.issue.attachment_tbl.Update( |
| 1259 self.cnxn, delta, id=attachment_id) |
| 1260 |
| 1261 def testUpdateAttachment(self): |
| 1262 delta = { |
| 1263 'filename': 'a_filename', |
| 1264 'filesize': 1024, |
| 1265 'mimetype': 'text/plain', |
| 1266 'deleted': False, |
| 1267 } |
| 1268 self.SetUpUpdateAttachment(1234, delta) |
| 1269 self.mox.ReplayAll() |
| 1270 attach = tracker_pb2.Attachment( |
| 1271 attachment_id=1234, filename='a_filename', filesize=1024, |
| 1272 mimetype='text/plain') |
| 1273 self.services.issue._UpdateAttachment(self.cnxn, attach) |
| 1274 self.mox.VerifyAll() |
| 1275 |
| 1276 def testStoreAttachmentBlob(self): |
| 1277 # TODO(jrobbins): re-implemnent to use Google Cloud Storage. |
| 1278 pass |
| 1279 |
| 1280 def testSoftDeleteAttachment(self): |
| 1281 issue_1, _issue_2 = self.SetUpGetIssues() |
| 1282 issue_1.attachment_count = 1 |
| 1283 self.services.issue.issue_id_2lc.CacheItem((789, 1), 78901) |
| 1284 self.SetUpGetComments([78901]) |
| 1285 self.SetUpUpdateAttachment(1234, {'deleted': True}) |
| 1286 self.SetUpUpdateIssues(given_delta={'attachment_count': 0}) |
| 1287 |
| 1288 self.mox.ReplayAll() |
| 1289 self.services.issue.SoftDeleteAttachment( |
| 1290 self.cnxn, 789, 1, 0, 1234, self.services.user) |
| 1291 self.mox.VerifyAll() |
| 1292 |
| 1293 ### Reindex queue |
| 1294 |
| 1295 def SetUpEnqueueIssuesForIndexing(self, issue_ids): |
| 1296 reindex_rows = [(issue_id,) for issue_id in issue_ids] |
| 1297 self.services.issue.reindexqueue_tbl.InsertRows( |
| 1298 self.cnxn, ['issue_id'], reindex_rows, ignore=True) |
| 1299 |
| 1300 def testEnqueueIssuesForIndexing(self): |
| 1301 self.SetUpEnqueueIssuesForIndexing([78901]) |
| 1302 self.mox.ReplayAll() |
| 1303 self.services.issue.EnqueueIssuesForIndexing(self.cnxn, [78901]) |
| 1304 self.mox.VerifyAll() |
| 1305 |
| 1306 def SetUpReindexIssues(self, issue_ids): |
| 1307 self.services.issue.reindexqueue_tbl.Select( |
| 1308 self.cnxn, order_by=[('created', [])], |
| 1309 limit=50).AndReturn([(issue_id,) for issue_id in issue_ids]) |
| 1310 |
| 1311 if issue_ids: |
| 1312 _issue_1, _issue_2 = self.SetUpGetIssues() |
| 1313 self.services.issue.reindexqueue_tbl.Delete( |
| 1314 self.cnxn, issue_id=issue_ids) |
| 1315 |
| 1316 def testReindexIssues_QueueEmpty(self): |
| 1317 self.SetUpReindexIssues([]) |
| 1318 self.mox.ReplayAll() |
| 1319 self.services.issue.ReindexIssues(self.cnxn, 50, self.services.user) |
| 1320 self.mox.VerifyAll() |
| 1321 |
| 1322 def testReindexIssues_QueueHasTwoIssues(self): |
| 1323 self.SetUpReindexIssues([78901, 78902]) |
| 1324 self.mox.ReplayAll() |
| 1325 self.services.issue.ReindexIssues(self.cnxn, 50, self.services.user) |
| 1326 self.mox.VerifyAll() |
| 1327 |
| 1328 ### Search functions |
| 1329 |
| 1330 def SetUpRunIssueQuery( |
| 1331 self, rows, limit=settings.search_limit_per_shard): |
| 1332 self.services.issue.issue_tbl.Select( |
| 1333 self.cnxn, shard_id=1, distinct=True, cols=['Issue.id'], |
| 1334 left_joins=[], where=[('Issue.deleted = %s', [False])], order_by=[], |
| 1335 limit=limit).AndReturn(rows) |
| 1336 |
| 1337 def testRunIssueQuery_NoResults(self): |
| 1338 self.SetUpRunIssueQuery([]) |
| 1339 self.mox.ReplayAll() |
| 1340 result_iids, capped = self.services.issue.RunIssueQuery( |
| 1341 self.cnxn, [], [], [], shard_id=1) |
| 1342 self.mox.VerifyAll() |
| 1343 self.assertEqual([], result_iids) |
| 1344 self.assertFalse(capped) |
| 1345 |
| 1346 def testRunIssueQuery_Normal(self): |
| 1347 self.SetUpRunIssueQuery([(1,), (11,), (21,)]) |
| 1348 self.mox.ReplayAll() |
| 1349 result_iids, capped = self.services.issue.RunIssueQuery( |
| 1350 self.cnxn, [], [], [], shard_id=1) |
| 1351 self.mox.VerifyAll() |
| 1352 self.assertEqual([1, 11, 21], result_iids) |
| 1353 self.assertFalse(capped) |
| 1354 |
| 1355 def testRunIssueQuery_Capped(self): |
| 1356 try: |
| 1357 orig = settings.search_limit_per_shard |
| 1358 settings.search_limit_per_shard = 3 |
| 1359 self.SetUpRunIssueQuery([(1,), (11,), (21,)], limit=3) |
| 1360 self.mox.ReplayAll() |
| 1361 result_iids, capped = self.services.issue.RunIssueQuery( |
| 1362 self.cnxn, [], [], [], shard_id=1) |
| 1363 self.mox.VerifyAll() |
| 1364 self.assertEqual([1, 11, 21], result_iids) |
| 1365 self.assertTrue(capped) |
| 1366 finally: |
| 1367 settings.search_limit_per_shard = orig |
| 1368 |
| 1369 def SetUpGetIIDsByLabelIDs(self): |
| 1370 self.services.issue.issue_tbl.Select( |
| 1371 self.cnxn, shard_id=1, cols=['id'], |
| 1372 left_joins=[('Issue2Label ON Issue.id = Issue2Label.issue_id', [])], |
| 1373 label_id=[123, 456], project_id=789, |
| 1374 where=[('shard = %s', [1])] |
| 1375 ).AndReturn([(1,), (2,), (3,)]) |
| 1376 |
| 1377 def testGetIIDsByLabelIDs(self): |
| 1378 self.SetUpGetIIDsByLabelIDs() |
| 1379 self.mox.ReplayAll() |
| 1380 iids = self.services.issue.GetIIDsByLabelIDs(self.cnxn, [123, 456], 789, 1) |
| 1381 self.mox.VerifyAll() |
| 1382 self.assertEqual([1, 2, 3], iids) |
| 1383 |
| 1384 def SetUpGetIIDsByParticipant(self): |
| 1385 self.services.issue.issue_tbl.Select( |
| 1386 self.cnxn, shard_id=1, cols=['id'], |
| 1387 reporter_id=[111L, 888L], |
| 1388 where=[('shard = %s', [1]), ('Issue.project_id IN (%s)', [789])] |
| 1389 ).AndReturn([(1,)]) |
| 1390 self.services.issue.issue_tbl.Select( |
| 1391 self.cnxn, shard_id=1, cols=['id'], |
| 1392 owner_id=[111L, 888L], |
| 1393 where=[('shard = %s', [1]), ('Issue.project_id IN (%s)', [789])] |
| 1394 ).AndReturn([(2,)]) |
| 1395 self.services.issue.issue_tbl.Select( |
| 1396 self.cnxn, shard_id=1, cols=['id'], |
| 1397 derived_owner_id=[111L, 888L], |
| 1398 where=[('shard = %s', [1]), ('Issue.project_id IN (%s)', [789])] |
| 1399 ).AndReturn([(3,)]) |
| 1400 self.services.issue.issue_tbl.Select( |
| 1401 self.cnxn, shard_id=1, cols=['id'], |
| 1402 left_joins=[('Issue2Cc ON Issue2Cc.issue_id = Issue.id', [])], |
| 1403 cc_id=[111L, 888L], |
| 1404 where=[('shard = %s', [1]), ('Issue.project_id IN (%s)', [789]), |
| 1405 ('cc_id IS NOT NULL', [])] |
| 1406 ).AndReturn([(4,)]) |
| 1407 self.services.issue.issue_tbl.Select( |
| 1408 self.cnxn, shard_id=1, cols=['Issue.id'], |
| 1409 left_joins=[ |
| 1410 ('Issue2FieldValue ON Issue.id = Issue2FieldValue.issue_id', []), |
| 1411 ('FieldDef ON Issue2FieldValue.field_id = FieldDef.id', [])], |
| 1412 user_id=[111L, 888L], grants_perm='View', |
| 1413 where=[('shard = %s', [1]), ('Issue.project_id IN (%s)', [789]), |
| 1414 ('user_id IS NOT NULL', [])] |
| 1415 ).AndReturn([(5,)]) |
| 1416 |
| 1417 def testGetIIDsByParticipant(self): |
| 1418 self.SetUpGetIIDsByParticipant() |
| 1419 self.mox.ReplayAll() |
| 1420 iids = self.services.issue.GetIIDsByParticipant( |
| 1421 self.cnxn, [111L, 888L], [789], 1) |
| 1422 self.mox.VerifyAll() |
| 1423 self.assertEqual([1, 2, 3, 4, 5], iids) |
| 1424 |
| 1425 |
| 1426 class IssueServiceFunctionsTest(unittest.TestCase): |
| 1427 |
| 1428 def testUpdateClosedTimestamp(self): |
| 1429 config = tracker_pb2.ProjectIssueConfig() |
| 1430 config.well_known_statuses.append(tracker_pb2.StatusDef( |
| 1431 status='New', means_open=True)) |
| 1432 config.well_known_statuses.append(tracker_pb2.StatusDef( |
| 1433 status='Accepted', means_open=True)) |
| 1434 config.well_known_statuses.append(tracker_pb2.StatusDef( |
| 1435 status='Old', means_open=False)) |
| 1436 config.well_known_statuses.append(tracker_pb2.StatusDef( |
| 1437 status='Closed', means_open=False)) |
| 1438 |
| 1439 issue = tracker_pb2.Issue() |
| 1440 issue.local_id = 1234 |
| 1441 issue.status = 'New' |
| 1442 |
| 1443 # ensure the default value is undef |
| 1444 self.assert_(not issue.closed_timestamp) |
| 1445 |
| 1446 # ensure transitioning to the same and other open states |
| 1447 # doesn't set the timestamp |
| 1448 issue.status = 'New' |
| 1449 issue_svc._UpdateClosedTimestamp(config, issue, 'New') |
| 1450 self.assert_(not issue.closed_timestamp) |
| 1451 |
| 1452 issue.status = 'Accepted' |
| 1453 issue_svc._UpdateClosedTimestamp(config, issue, 'New') |
| 1454 self.assert_(not issue.closed_timestamp) |
| 1455 |
| 1456 # ensure transitioning from open to closed sets the timestamp |
| 1457 issue.status = 'Closed' |
| 1458 issue_svc._UpdateClosedTimestamp(config, issue, 'Accepted') |
| 1459 self.assert_(issue.closed_timestamp) |
| 1460 |
| 1461 # ensure that the timestamp is cleared when transitioning from |
| 1462 # closed to open |
| 1463 issue.status = 'New' |
| 1464 issue_svc._UpdateClosedTimestamp(config, issue, 'Closed') |
| 1465 self.assert_(not issue.closed_timestamp) |
| 1466 |
| 1467 |
| 1468 if __name__ == '__main__': |
| 1469 unittest.main() |
OLD | NEW |