Merge branch 'main' into avm99963-monorail

Merged commit 34d8229ae2b51fb1a15bd208e6fe6185c94f6266

GitOrigin-RevId: 7ee0917f93a577e475f8e09526dd144d245593f4
diff --git a/testing/fake.py b/testing/fake.py
index f484b12..c503fa0 100644
--- a/testing/fake.py
+++ b/testing/fake.py
@@ -1,7 +1,6 @@
-# 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.
 
 """Fake object classes that are useful for unit tests."""
 from __future__ import print_function
@@ -27,11 +26,11 @@
 from framework import permissions
 from framework import profiler
 from framework import validate
-from proto import features_pb2
-from proto import project_pb2
-from proto import tracker_pb2
-from proto import user_pb2
-from proto import usergroup_pb2
+from mrproto import features_pb2
+from mrproto import project_pb2
+from mrproto import tracker_pb2
+from mrproto import user_pb2
+from mrproto import usergroup_pb2
 from services import caches
 from services import config_svc
 from services import features_svc
@@ -145,13 +144,35 @@
 
 
 def MakeTestIssue(
-    project_id, local_id, summary, status, owner_id, labels=None,
-    derived_labels=None, derived_status=None, merged_into=0, star_count=0,
-    derived_owner_id=0, issue_id=None, reporter_id=None, opened_timestamp=None,
-    closed_timestamp=None, modified_timestamp=None, is_spam=False,
-    component_ids=None, project_name=None, field_values=None, cc_ids=None,
-    derived_cc_ids=None, assume_stale=True, phases=None, approval_values=None,
-    merged_into_external=None, attachment_count=0, derived_component_ids=None):
+    project_id,
+    local_id,
+    summary,
+    status,
+    owner_id,
+    labels=None,
+    derived_labels=None,
+    derived_status=None,
+    merged_into=0,
+    star_count=0,
+    derived_owner_id=0,
+    issue_id=None,
+    reporter_id=None,
+    opened_timestamp=None,
+    closed_timestamp=None,
+    modified_timestamp=None,
+    migration_modified_timestamp=None,
+    is_spam=False,
+    component_ids=None,
+    project_name=None,
+    field_values=None,
+    cc_ids=None,
+    derived_cc_ids=None,
+    assume_stale=True,
+    phases=None,
+    approval_values=None,
+    merged_into_external=None,
+    attachment_count=0,
+    derived_component_ids=None):
   """Easily make an Issue for testing."""
   issue = tracker_pb2.Issue()
   issue.project_id = project_id
@@ -180,6 +201,11 @@
     issue.component_modified_timestamp = opened_timestamp
   if modified_timestamp:
     issue.modified_timestamp = modified_timestamp
+    # By default, make migration_modified_timestamp the same as
+    # modified_timestamp
+    issue.migration_modified_timestamp = modified_timestamp
+  if migration_modified_timestamp:
+    issue.migration_modified_timestamp = migration_modified_timestamp
   if closed_timestamp:
     issue.closed_timestamp = closed_timestamp
   if labels is not None:
@@ -1041,9 +1067,9 @@
     return [project_dict[pid] for pid in project_id_list
             if pid in project_dict]
 
-  def GetVisibleLiveProjects(
+  def GetVisibleProjects(
       self, _cnxn, logged_in_user, effective_ids, domain=None, use_cache=True):
-    project_ids = list(self.projects_by_id.keys())
+    project_ids = sorted(self.projects_by_id.keys())
     visible_project_ids = []
     for pid in project_ids:
       can_view = permissions.UserCanViewProject(
@@ -1245,17 +1271,23 @@
       return None
     return 'label_%d_%d' % (project_id, label_id)
 
-  def LookupLabelID(self, cnxn, project_id, label, autocreate=True):
+  def LookupLabelID(
+      self, cnxn, project_id, label, autocreate=True, case_sensitive=False):
     if label in self.label_to_id:
       return self.label_to_id[label]
+    # TODO: The condition here is specifically added to return 'None' and
+    # allow testing for label freezing. This can be removed after refactoring
+    # other dependent tests to not fail for returning 'None' instead of '1'
+    # when label is not found in 'label_to_id' dict.
+    if label == 'freeze_new_label':
+      return None
     return 1
 
   def LookupLabelIDs(self, cnxn, project_id, labels, autocreate=False):
     ids = []
     next_label_id = 0
     if self.id_to_label.keys():
-      existing_ids = self.id_to_label.keys()
-      existing_ids.sort()
+      existing_ids = sorted(self.id_to_label.keys())
       next_label_id = existing_ids[-1] + 1
     for label in labels:
       if self.label_to_id.get(label) is not None:
@@ -1550,6 +1582,17 @@
     # The next id to return if it is > 0.
     self.next_id = -1
 
+  def UpdateIssue(
+      self,
+      cnxn,
+      issue,
+      update_cols=None,
+      just_derived=False,
+      commit=True,
+      invalidate=True):
+    self.UpdateIssues(
+        cnxn, [issue], update_cols, just_derived, commit, invalidate)
+
   def UpdateIssues(
       self, cnxn, issues, update_cols=None, just_derived=False,
       commit=True, invalidate=True):
@@ -1971,6 +2014,7 @@
       timestamp = int(time.time())
       new_issue.opened_timestamp = timestamp
       new_issue.modified_timestamp = timestamp
+      new_issue.migration_modified_timestamp = timestamp
 
       target_comments = self.GetCommentsForIssue(cnxn, target_issue.issue_id)
       initial_summary_comment = target_comments[0]
@@ -2659,8 +2703,9 @@
         hotlist = self.test_hotlists.get((name, owner_id))
         if hotlist:
           if not hotlist.owner_ids:  # Should never happen.
-            logging.warn('Unowned Hotlist: id:%r, name:%r',
-                         hotlist.hotlist_id, hotlist.name)
+            logging.warning(
+                'Unowned Hotlist: id:%r, name:%r', hotlist.hotlist_id,
+                hotlist.name)
             continue
           id_dict[(name.lower(), owner_id)] = hotlist.hotlist_id
     return id_dict
@@ -2790,7 +2835,7 @@
     emails = user_ids_by_email.keys()
     user_ids = user_ids_by_email.values()
     project_rules_dict = collections.defaultdict(list)
-    for project_id, rules in self.test_rules.iteritems():
+    for project_id, rules in self.test_rules.items():
       for rule in rules:
         if rule.default_owner_id in user_ids:
           project_rules_dict[project_id].append(rule)