Merge branch 'main' into avm99963-monorail
Merged commit 34d8229ae2b51fb1a15bd208e6fe6185c94f6266
GitOrigin-RevId: 7ee0917f93a577e475f8e09526dd144d245593f4
diff --git a/services/test/issue_svc_test.py b/services/test/issue_svc_test.py
index fe41aa4..f6b6c29 100644
--- a/services/test/issue_svc_test.py
+++ b/services/test/issue_svc_test.py
@@ -1,8 +1,7 @@
# -*- coding: utf-8 -*-
-# 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
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
"""Unit tests for issue_svc module."""
@@ -11,6 +10,7 @@
from __future__ import absolute_import
import logging
+import six
import time
import unittest
from mock import patch, Mock, ANY
@@ -27,7 +27,7 @@
from framework import exceptions
from framework import framework_constants
from framework import sql
-from proto import tracker_pb2
+from mrproto import tracker_pb2
from services import caches
from services import chart_svc
from services import issue_svc
@@ -63,12 +63,12 @@
return issue_service
-class TestableIssueTwoLevelCache(issue_svc.IssueTwoLevelCache):
+class _TestableIssueTwoLevelCache(issue_svc.IssueTwoLevelCache):
def __init__(self, issue_list):
cache_manager = fake.CacheManager()
- super(TestableIssueTwoLevelCache, self).__init__(
- cache_manager, None, None, None)
+ super(_TestableIssueTwoLevelCache,
+ self).__init__(cache_manager, None, None, None)
self.cache = caches.RamCache(cache_manager, 'issue')
self.memcache_prefix = 'issue:'
self.pb_class = tracker_pb2.Issue
@@ -134,8 +134,8 @@
issue_dict = self.issue_id_2lc.FetchItems(
self.cnxn, project_local_ids_list)
self.mox.VerifyAll()
- self.assertItemsEqual(project_local_ids_list, list(issue_dict.keys()))
- self.assertItemsEqual(issue_ids, list(issue_dict.values()))
+ six.assertCountEqual(self, project_local_ids_list, list(issue_dict.keys()))
+ six.assertCountEqual(self, issue_ids, list(issue_dict.values()))
def testKeyToStr(self):
self.assertEqual('789,1', self.issue_id_2lc._KeyToStr((789, 1)))
@@ -161,9 +161,10 @@
now = int(time.time())
self.project_service.TestAddProject('proj', project_id=789)
self.issue_rows = [
- (78901, 789, 1, 1, 111, 222,
- now, now, now, now, now, now,
- 0, 0, 0, 1, 0, False)]
+ (
+ 78901, 789, 1, 1, 111, 222, now, now, now, now, now, now, now, 0, 0,
+ 0, 1, 0, False)
+ ]
self.summary_rows = [(78901, 'sum')]
self.label_rows = [(78901, 1, 0)]
self.component_rows = []
@@ -224,14 +225,14 @@
self.component_rows, self.cc_rows, self.notify_rows,
self.fieldvalue_rows, self.relation_rows, self.dangling_relation_rows,
self.phase_rows, self.approvalvalue_rows, self.av_approver_rows)
- self.assertItemsEqual([78901], list(issue_dict.keys()))
+ six.assertCountEqual(self, [78901], list(issue_dict.keys()))
issue = issue_dict[78901]
self.assertEqual(len(issue.phases), 2)
self.assertIsNotNone(tracker_bizobj.FindPhaseByID(1, issue.phases))
av_21 = tracker_bizobj.FindApprovalValueByID(
21, issue.approval_values)
self.assertEqual(av_21.phase_id, 1)
- self.assertItemsEqual(av_21.approver_ids, [111, 222, 333])
+ six.assertCountEqual(self, av_21.approver_ids, [111, 222, 333])
self.assertIsNotNone(tracker_bizobj.FindPhaseByID(2, issue.phases))
self.assertEqual(issue.phases,
[tracker_pb2.Phase(rank=1, phase_id=1, name='Canary'),
@@ -356,7 +357,7 @@
self.mox.ReplayAll()
issue_dict = self.issue_2lc.FetchItems(self.cnxn, issue_ids)
self.mox.VerifyAll()
- self.assertItemsEqual(issue_ids, list(issue_dict.keys()))
+ six.assertCountEqual(self, issue_ids, list(issue_dict.keys()))
self.assertEqual(2, len(issue_dict[78901].phases))
def testFetchItemsNoApprovalValues(self):
@@ -365,7 +366,7 @@
self.mox.ReplayAll()
issue_dict = self.issue_2lc.FetchItems(self.cnxn, issue_ids)
self.mox.VerifyAll()
- self.assertItemsEqual(issue_ids, list(issue_dict.keys()))
+ six.assertCountEqual(self, issue_ids, list(issue_dict.keys()))
self.assertEqual([], issue_dict[78901].phases)
@@ -750,7 +751,7 @@
def testGetIssuesDict(self):
issue_ids = [78901, 78902, 78903]
issue_1, issue_2 = self.SetUpGetIssues()
- self.services.issue.issue_2lc = TestableIssueTwoLevelCache(
+ self.services.issue.issue_2lc = _TestableIssueTwoLevelCache(
[issue_1, issue_2])
issues_dict, missed_iids = self.services.issue.GetIssuesDict(
self.cnxn, issue_ids)
@@ -827,10 +828,9 @@
def SetUpInsertIssue(
self, label_rows=None, av_rows=None, approver_rows=None,
dangling_relation_rows=None):
- row = (789, 1, 1, 111, 111,
- self.now, 0, self.now, self.now, self.now, self.now,
- None, 0,
- False, 0, 0, False)
+ row = (
+ 789, 1, 1, 111, 111, self.now, 0, self.now, self.now, self.now,
+ self.now, self.now, None, 0, False, 0, 0, False)
self.services.issue.issue_tbl.InsertRows(
self.cnxn, issue_svc.ISSUE_COLS[1:], [row],
commit=False, return_generated_ids=True).AndReturn([78901])
@@ -852,9 +852,9 @@
commit=False)
def SetUpInsertSpamIssue(self):
- row = (789, 1, 1, 111, 111,
- self.now, 0, self.now, self.now, self.now, self.now,
- None, 0, False, 0, 0, True)
+ row = (
+ 789, 1, 1, 111, 111, self.now, 0, self.now, self.now, self.now,
+ self.now, self.now, None, 0, False, 0, 0, True)
self.services.issue.issue_tbl.InsertRows(
self.cnxn, issue_svc.ISSUE_COLS[1:], [row],
commit=False, return_generated_ids=True).AndReturn([78901])
@@ -972,13 +972,14 @@
'owner_modified': 123456789,
'status_modified': 123456789,
'component_modified': 123456789,
+ 'migration_modified': 123456789,
'derived_owner_id': None,
'derived_status_id': None,
'deleted': False,
'star_count': 12,
'attachment_count': 0,
'is_spam': False,
- }
+ }
self.services.issue.issue_tbl.Update(
self.cnxn, delta, id=78901, commit=False)
if not given_delta:
@@ -1006,9 +1007,15 @@
def testUpdateIssues_Normal(self):
issue = fake.MakeTestIssue(
- project_id=789, local_id=1, owner_id=111, summary='sum',
- status='Live', labels=['Type-Defect'], issue_id=78901,
- opened_timestamp=123456789, modified_timestamp=123456789,
+ project_id=789,
+ local_id=1,
+ owner_id=111,
+ summary='sum',
+ status='Live',
+ labels=['Type-Defect'],
+ issue_id=78901,
+ opened_timestamp=123456789,
+ modified_timestamp=123456789,
star_count=12)
issue.assume_stale = False
self.SetUpUpdateIssues()
@@ -1018,9 +1025,15 @@
def testUpdateIssue_Normal(self):
issue = fake.MakeTestIssue(
- project_id=789, local_id=1, owner_id=111, summary='sum',
- status='Live', labels=['Type-Defect'], issue_id=78901,
- opened_timestamp=123456789, modified_timestamp=123456789,
+ project_id=789,
+ local_id=1,
+ owner_id=111,
+ summary='sum',
+ status='Live',
+ labels=['Type-Defect'],
+ issue_id=78901,
+ opened_timestamp=123456789,
+ modified_timestamp=123456789,
star_count=12)
issue.assume_stale = False
self.SetUpUpdateIssues()
@@ -1030,9 +1043,15 @@
def testUpdateIssue_Stale(self):
issue = fake.MakeTestIssue(
- project_id=789, local_id=1, owner_id=111, summary='sum',
- status='Live', labels=['Type-Defect'], issue_id=78901,
- opened_timestamp=123456789, modified_timestamp=123456789,
+ project_id=789,
+ local_id=1,
+ owner_id=111,
+ summary='sum',
+ status='Live',
+ labels=['Type-Defect'],
+ issue_id=78901,
+ opened_timestamp=123456789,
+ modified_timestamp=123456789,
star_count=12)
# Do not set issue.assume_stale = False
# Do not call self.SetUpUpdateIssues() because nothing should be updated.
@@ -1270,7 +1289,8 @@
7890101, is_description=True, approval_id=7,
content=config.approval_defs[2].survey, commit=False)
amendment_row = (
- 78901, 7890101, 'custom', None, '-Llama Roo', None, None, 'Approvals')
+ 78901, 7890101, 'custom', None, '-Llama Roo', None, None, 'Approvals',
+ None, None)
self.SetUpInsertComment(
7890101, content=comment_content, amendment_rows=[amendment_row],
commit=False)
@@ -1473,8 +1493,10 @@
# Calls in ApplyIssueDelta
# Call to find added blocking issues.
- issue_refs = {blocking_issue: (
- blocking_issue.project_name, blocking_issue.local_id)}
+ issue_refs = {
+ blocking_issue.issue_id:
+ (blocking_issue.project_name, blocking_issue.local_id)
+ }
self.services.issue.LookupIssueRefs(
self.cnxn, [blocking_issue.issue_id]).AndReturn(issue_refs)
# Call to find removed blocking issues.
@@ -1636,10 +1658,10 @@
def testSoftDeleteIssue(self):
project = fake.Project(project_id=789)
issue_1, issue_2 = self.SetUpGetIssues()
- self.services.issue.issue_2lc = TestableIssueTwoLevelCache(
+ self.services.issue.issue_2lc = _TestableIssueTwoLevelCache(
[issue_1, issue_2])
self.services.issue.issue_id_2lc.CacheItem((789, 1), 78901)
- delta = {'deleted': True}
+ delta = {'deleted': True, 'migration_modified': self.now}
self.services.issue.issue_tbl.Update(
self.cnxn, delta, id=78901, commit=False)
@@ -1842,7 +1864,10 @@
commentcontent_rows = [(7890101, 'content', 'msg'),
(7890102, 'content2', 'msg')]
amendment_rows = [
- (1, 78901, 7890101, 'cc', 'old', 'new val', 222, None, None)]
+ (
+ 1, 78901, 7890101, 'cc', 'old', 'new val', 222, None, None, None,
+ None)
+ ]
attachment_rows = []
approval_rows = [(23, 7890102)]
importer_rows = []
@@ -1869,6 +1894,24 @@
self.assertEqual(2, len(comments))
self.assertEqual(222, comments[0].importer_id)
+ def testUpackAmendment(self):
+ amendment_row = (
+ 1, 78901, 7890101, 'cc', 'old', 'new val', 222, None, None, None, None)
+ amendment, comment_id = self.services.issue._UnpackAmendment(amendment_row)
+ self.assertEqual(comment_id, 7890101)
+ self.assertEqual(amendment.field, tracker_pb2.FieldID('CC'))
+ self.assertEqual(amendment.newvalue, 'new val')
+ self.assertEqual(amendment.oldvalue, 'old')
+ self.assertEqual(amendment.added_user_ids, [222])
+
+ def testUpackAmendment_With_Unicode(self):
+ amendment_row = (
+ 1, 78901, 7890102, 'custom', None, None, None, None, None, u'123', None)
+ amendment, comment_id = self.services.issue._UnpackAmendment(amendment_row)
+ self.assertEqual(comment_id, 7890102)
+ self.assertEqual(amendment.field, tracker_pb2.FieldID('CUSTOM'))
+ self.assertEqual(amendment.added_component_ids, [123])
+
def MockTheRestOfGetCommentsByID(self, comment_ids):
self.services.issue.commentcontent_tbl.Select = Mock(
return_value=[
@@ -2117,6 +2160,32 @@
self.mox.VerifyAll()
self.assertEqual(7890101, comment.id)
+ def testInsertComment_WithIssueUpdate(self):
+ amendment = tracker_bizobj.MakeAmendment(
+ tracker_pb2.FieldID.COMPONENTS, 'aaa', [], [], added_component_ids=[1])
+ amendment_rows = [
+ (
+ 78901, 7890101, 'components', None, 'aaa', None, None, None, None,
+ None),
+ (78901, 7890101, 'components', None, None, None, None, None, 1, None)
+ ]
+ comment = tracker_pb2.IssueComment(
+ issue_id=78901,
+ timestamp=self.now,
+ project_id=789,
+ user_id=111,
+ content='content',
+ amendments=[amendment])
+ self.services.issue.commentcontent_tbl.InsertRow = Mock(
+ return_value=78901010)
+ self.services.issue.comment_tbl.InsertRow = Mock(return_value=7890101)
+ self.services.issue.issueupdate_tbl.InsertRows = Mock()
+
+ self.services.issue.InsertComment(self.cnxn, comment, commit=True)
+
+ self.services.issue.issueupdate_tbl.InsertRows.assert_called_once_with(
+ self.cnxn, issue_svc.ISSUEUPDATE_COLS[1:], amendment_rows, commit=False)
+
def SetUpUpdateComment(self, comment_id, delta=None):
delta = delta or {
'commenter_id': 111,
@@ -2189,7 +2258,7 @@
def testSoftDeleteComment(self):
"""Deleting a comment with an attachment marks it and updates count."""
issue_1, issue_2 = self.SetUpGetIssues()
- self.services.issue.issue_2lc = TestableIssueTwoLevelCache(
+ self.services.issue.issue_2lc = _TestableIssueTwoLevelCache(
[issue_1, issue_2])
issue_1.attachment_count = 1
issue_1.assume_stale = False
@@ -2198,7 +2267,11 @@
self.services.issue.issue_id_2lc.CacheItem((789, 1), 78901)
self.SetUpUpdateComment(
comment.id, delta={'deleted_by': 222, 'is_spam': False})
- self.SetUpUpdateIssues(given_delta={'attachment_count': 0})
+ self.SetUpUpdateIssues(
+ given_delta={
+ 'attachment_count': 0,
+ 'migration_modified': self.now
+ })
self.SetUpEnqueueIssuesForIndexing([78901])
self.mox.ReplayAll()
self.services.issue.SoftDeleteComment(
@@ -2418,7 +2491,11 @@
comment.attachments.append(attachment)
self.SetUpUpdateAttachment(179901, 1234, {'deleted': True})
- self.SetUpUpdateIssues(given_delta={'attachment_count': 0})
+ self.SetUpUpdateIssues(
+ given_delta={
+ 'attachment_count': 0,
+ 'migration_modified': self.now
+ })
self.SetUpEnqueueIssuesForIndexing([78901])
self.mox.ReplayAll()
@@ -2626,6 +2703,9 @@
self.services.issue.issueapproval2approver_tbl.Delete = Mock()
self.services.issue.issue2approvalvalue_tbl.Update = Mock()
+ issue_update_id_rows = [(78914,), (78915,)]
+ self.services.issue.issueupdate_tbl.Select = Mock(
+ return_value=issue_update_id_rows)
self.services.issue.issueupdate_tbl.Update = Mock()
self.services.issue.issue2notify_tbl.Delete = Mock()
@@ -2652,18 +2732,19 @@
commit = False
limit = 50
- affected_user_ids = self.services.issue.ExpungeUsersInIssues(
+ affected_issue_ids = self.services.issue.ExpungeUsersInIssues(
self.cnxn, user_ids_by_email, limit=limit)
- self.assertItemsEqual(
- affected_user_ids,
- [78901, 78902, 78903, 78904, 78905, 78906, 78907, 78908, 78909,
- 78910, 78911, 78912, 78913])
+ six.assertCountEqual(
+ self, affected_issue_ids, [
+ 78901, 78902, 78903, 78904, 78905, 78906, 78907, 78908, 78909,
+ 78910, 78911, 78912, 78913, 78914, 78915
+ ])
self.services.issue.comment_tbl.Select.assert_called_once()
_cnxn, kwargs = self.services.issue.comment_tbl.Select.call_args
self.assertEqual(
kwargs['cols'], ['Comment.id', 'Comment.issue_id', 'commentcontent_id'])
- self.assertItemsEqual(kwargs['commenter_id'], user_ids)
+ six.assertCountEqual(self, kwargs['commenter_id'], user_ids)
self.assertEqual(kwargs['limit'], limit)
# since user_ids are passed to ExpungeUsersInIssues via a dictionary,
@@ -2723,9 +2804,6 @@
self.cnxn, {'reporter_id': framework_constants.DELETED_USER_ID},
id=[row[0] for row in reporter_issue_id_rows], commit=commit)
- self.assertEqual(
- 3, len(self.services.issue.issue_tbl.Update.call_args_list))
-
# issue updates
self.services.issue.issueupdate_tbl.Update.assert_any_call(
self.cnxn, {'added_user_id': framework_constants.DELETED_USER_ID},
@@ -2736,11 +2814,19 @@
self.assertEqual(
2, len(self.services.issue.issueupdate_tbl.Update.call_args_list))
+ # check updates across all issues
+ self.services.issue.issue_tbl.Update.assert_any_call(
+ self.cnxn, {'migration_modified': self.now},
+ id=affected_issue_ids,
+ commit=commit)
+ self.assertEqual(
+ 4, len(self.services.issue.issue_tbl.Update.call_args_list))
+
# issue notify
call_args_list = self.services.issue.issue2notify_tbl.Delete.call_args_list
self.assertEqual(1, len(call_args_list))
_cnxn, kwargs = call_args_list[0]
- self.assertItemsEqual(kwargs['email'], emails)
+ six.assertCountEqual(self, kwargs['email'], emails)
self.assertEqual(kwargs['commit'], commit)
# issue snapshots