Merge branch 'main' into avm99963-monorail

Merged commit 34d8229ae2b51fb1a15bd208e6fe6185c94f6266

GitOrigin-RevId: 7ee0917f93a577e475f8e09526dd144d245593f4
diff --git a/api/test/converters_test.py b/api/test/converters_test.py
index e193423..ee060bd 100644
--- a/api/test/converters_test.py
+++ b/api/test/converters_test.py
@@ -1,17 +1,18 @@
-# Copyright 2018 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 2018 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Tests for converting internal protorpc to external protoc."""
 from __future__ import print_function
 from __future__ import division
 from __future__ import absolute_import
 
-from mock import Mock, patch
+from mock import patch
+import six
 import unittest
 
 from google.protobuf import wrappers_pb2
+import pytest
 
 import settings
 from api import converters
@@ -22,8 +23,8 @@
 from api.api_proto import user_objects_pb2
 from framework import exceptions
 from framework import permissions
-from proto import tracker_pb2
-from proto import user_pb2
+from mrproto import tracker_pb2
+from mrproto import user_pb2
 from testing import fake
 from testing import testing_helpers
 from tracker import tracker_bizobj
@@ -284,28 +285,27 @@
 
     actual = converters.ConvertUsers(
         [user1, user2, user3, user4], users_by_id)
-    self.assertItemsEqual(
-        actual,
-        [user_objects_pb2.User(
-            user_id=1,
-            display_name='user1@example.com'),
-         user_objects_pb2.User(
-            user_id=2,
-            display_name='user2@example.com',
-            is_site_admin=True),
-         user_objects_pb2.User(
-            user_id=3,
-            display_name='user3@example.com',
-            availability='User never visited',
-            linked_child_refs=[common_pb2.UserRef(
-              user_id=4, display_name='user4@example.com')]),
-         user_objects_pb2.User(
-            user_id=4,
-            display_name='user4@example.com',
-            availability='Last visit > 30 days ago',
-            linked_parent_ref=common_pb2.UserRef(
-              user_id=3, display_name='user3@example.com')),
-         ])
+    six.assertCountEqual(
+        self, actual, [
+            user_objects_pb2.User(user_id=1, display_name='user1@example.com'),
+            user_objects_pb2.User(
+                user_id=2, display_name='user2@example.com',
+                is_site_admin=True),
+            user_objects_pb2.User(
+                user_id=3,
+                display_name='user3@example.com',
+                availability='User never visited',
+                linked_child_refs=[
+                    common_pb2.UserRef(
+                        user_id=4, display_name='user4@example.com')
+                ]),
+            user_objects_pb2.User(
+                user_id=4,
+                display_name='user4@example.com',
+                availability='Last visit > 30 days ago',
+                linked_parent_ref=common_pb2.UserRef(
+                    user_id=3, display_name='user3@example.com')),
+        ])
 
   def testConvetPrefValues(self):
     """We can convert a list of UserPrefValues from protorpc to protoc."""
@@ -506,7 +506,7 @@
               field_id=5, field_name='Pre', type=common_pb2.ENUM_TYPE),
           value='label2', is_derived=True),
       ]
-    self.assertItemsEqual(expected, actual)
+    six.assertCountEqual(self, expected, actual)
 
   def testConvertIssue(self):
     """We can convert a protorpc Issue to a protoc Issue."""
@@ -584,6 +584,83 @@
               rank=2)])
     self.assertEqual(expected, actual)
 
+  def testConvertIssue_WithMigratedID(self):
+    """We can convert a protorpc Issue to a protoc Issue."""
+    related_refs_dict = {
+        78901: ('proj', 1),
+        78902: ('proj', 2),
+        }
+    now = 12345678
+    self.config.component_defs = [
+      tracker_pb2.ComponentDef(component_id=1, path='UI'),
+      tracker_pb2.ComponentDef(component_id=2, path='DB'),
+      ]
+    issue = fake.MakeTestIssue(
+      789, 3, 'sum', 'New', 111, labels=['Hot'],
+      derived_labels=['Scalability'], star_count=12, reporter_id=222,
+      opened_timestamp=now, component_ids=[1], project_name='proj',
+      cc_ids=[111], derived_cc_ids=[222])
+    issue.phases = [
+        tracker_pb2.Phase(phase_id=1, name='Dev', rank=1),
+        tracker_pb2.Phase(phase_id=2, name='Beta', rank=2),
+        ]
+    issue.dangling_blocked_on_refs = [
+        tracker_pb2.DanglingIssueRef(project='dangling_proj', issue_id=1234)]
+    issue.dangling_blocking_refs = [
+        tracker_pb2.DanglingIssueRef(project='dangling_proj', issue_id=5678)]
+
+    actual = converters.ConvertIssue(
+        issue, self.users_by_id, related_refs_dict, self.config, '123')
+
+    expected = issue_objects_pb2.Issue(
+        project_name='proj',
+        local_id=3,
+        summary='sum',
+        status_ref=common_pb2.StatusRef(
+            status='New',
+            is_derived=False,
+            means_open=True),
+        owner_ref=common_pb2.UserRef(
+            user_id=111,
+            display_name='one@example.com',
+            is_derived=False),
+        cc_refs=[
+            common_pb2.UserRef(
+                user_id=111,
+                display_name='one@example.com',
+                is_derived=False),
+            common_pb2.UserRef(
+                user_id=222,
+                display_name='two@example.com',
+                is_derived=True)],
+        label_refs=[
+            common_pb2.LabelRef(label='Hot', is_derived=False),
+            common_pb2.LabelRef(label='Scalability', is_derived=True)],
+        component_refs=[common_pb2.ComponentRef(path='UI', is_derived=False)],
+        is_deleted=False,
+        reporter_ref=common_pb2.UserRef(
+            user_id=222, display_name='two@example.com', is_derived=False),
+        opened_timestamp=now,
+        component_modified_timestamp=now,
+        status_modified_timestamp=now,
+        owner_modified_timestamp=now,
+        star_count=12,
+        is_spam=False,
+        attachment_count=0,
+        dangling_blocked_on_refs=[
+            common_pb2.IssueRef(project_name='dangling_proj', local_id=1234)],
+        dangling_blocking_refs=[
+            common_pb2.IssueRef(project_name='dangling_proj', local_id=5678)],
+        phases=[
+            issue_objects_pb2.PhaseDef(
+              phase_ref=issue_objects_pb2.PhaseRef(phase_name='Dev'),
+              rank=1),
+            issue_objects_pb2.PhaseDef(
+              phase_ref=issue_objects_pb2.PhaseRef(phase_name='Beta'),
+              rank=2)],
+        migrated_id='123',)
+    self.assertEqual(expected, actual)
+
   def testConvertIssue_NegativeAttachmentCount(self):
     """We can convert a protorpc Issue to a protoc Issue."""
     related_refs_dict = {
@@ -1423,21 +1500,22 @@
     """Uploading files results in a list of attachments."""
     uploads = [
         issue_objects_pb2.AttachmentUpload(
-            filename='hello.c', content='int main() {}'),
+            filename='hello.c', content=b'int main() {}'),
         issue_objects_pb2.AttachmentUpload(
-            filename='README.md', content='readme content'),
-        ]
+            filename='README.md', content=b'readme content'),
+    ]
     actual = converters.IngestAttachmentUploads(uploads)
     self.assertEqual(
-      [('hello.c', 'int main() {}', 'text/plain'),
-       ('README.md', 'readme content', 'text/plain')],
-      actual)
+        [
+            ('hello.c', b'int main() {}', 'text/plain'),
+            ('README.md', b'readme content', 'text/plain')
+        ], actual)
 
   def testIngestAttachmentUploads_Invalid(self):
     """We reject uploaded files that lack a name or content."""
     with self.assertRaises(exceptions.InputException):
-      converters.IngestAttachmentUploads([
-          issue_objects_pb2.AttachmentUpload(content='name is mssing')])
+      converters.IngestAttachmentUploads(
+          [issue_objects_pb2.AttachmentUpload(content=b'name is mssing')])
 
     with self.assertRaises(exceptions.InputException):
       converters.IngestAttachmentUploads([
@@ -1607,9 +1685,7 @@
       converters.IngestFieldValues(
           self.cnxn, self.services.user, field_values, self.config, [])
 
-    self.assertEqual(
-        'Unparsable value for field SecField',
-        cm.exception.message)
+    self.assertEqual('Unparsable value for field SecField', str(cm.exception))
 
   def testIngestSavedQueries(self):
     self.services.project.TestAddProject('chromium', project_id=1)
@@ -1656,6 +1732,7 @@
         self.cnxn, self.services.user, self.services.features, hotlist_ref)
     self.assertEqual(actual_hotlist_id, hotlist.hotlist_id)
 
+  @pytest.mark.skip(reason='Test is flaky (https://crbug.com/monorail/12052)')
   def testIngestHotlistRef_HotlistID(self):
     self.services.user.TestAddUser('user1@example.com', 111)
     hotlist = self.services.features.CreateHotlist(
@@ -1674,6 +1751,7 @@
       converters.IngestHotlistRef(
           self.cnxn, self.services.user, self.services.features, hotlist_ref)
 
+  @pytest.mark.skip(reason='Test is flaky (https://crbug.com/monorail/12052)')
   def testIngestHotlistRef_InconsistentRequest(self):
     self.services.user.TestAddUser('user1@example.com', 111)
     hotlist1 = self.services.features.CreateHotlist(