buildbucket_v2: Add batch calls for Get and Cancel of builds.

Add batch calls for batch get and canceling of builds.  Get
and cancel replace existing functionality in the v1 client.

BUG=b:179735986
TEST=`run_tests`

Change-Id: I387c73ae0c905c7b376634ed1fd9cf247f644d5b
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/2688135
Tested-by: Mike Nichols <mikenichols@chromium.org>
Reviewed-by: Dhanya Ganesh <dhanyaganesh@chromium.org>
Commit-Queue: Mike Nichols <mikenichols@chromium.org>
diff --git a/lib/buildbucket_v2.py b/lib/buildbucket_v2.py
index 2b91656..6a0aaf2 100644
--- a/lib/buildbucket_v2.py
+++ b/lib/buildbucket_v2.py
@@ -245,12 +245,61 @@
   @retry_util.WithRetry(max_retry=5, sleep=20.0, exception=socket.error)
   @retry_util.WithRetry(max_retry=5, sleep=20.0,
                         exception=httplib.ResponseNotReady)
-  def CancelBuild(self, buildbucket_id, summary_markdown, properties=None):
+  def BatchCancelBuilds(self, buildbucket_ids, properties=None):
+    """BatchGetBuild repeated GetBuild request with provided ids.
+
+    Args:
+      buildbucket_ids: list of ids of the builds in buildbucket.
+      properties: fields to include in the response.
+
+    Returns:
+      The corresponding BatchResponse message. See here:
+      https://chromium.googlesource.com/infra/luci/luci-go/+/master/buildbucket/proto/builds_service.proto
+    """
+    batch_requests = []
+    for buildbucket_id in buildbucket_ids:
+      batch_requests.append(rpc_pb2.CancelBuildRequest(
+         id=buildbucket_id,
+         fields=(field_mask_pb2.FieldMask(paths=[properties])
+                 if properties else None)
+      ))
+    return self.client.Batch(rpc_pb2.BatchRequest(requests=batch_requests))
+
+  # TODO(crbug/1006818): Need to handle ResponseNotReady given by luci prpc.
+  @retry_util.WithRetry(max_retry=5, sleep=20.0, exception=SSLError)
+  @retry_util.WithRetry(max_retry=5, sleep=20.0, exception=socket.error)
+  @retry_util.WithRetry(max_retry=5, sleep=20.0,
+                        exception=httplib.ResponseNotReady)
+  def BatchGetBuilds(self, buildbucket_ids, properties=None):
+    """BatchGetBuild repeated GetBuild request with provided ids.
+
+    Args:
+      buildbucket_ids: list of ids of the builds in buildbucket.
+      properties: fields to include in the response.
+
+    Returns:
+      The corresponding BatchResponse message. See here:
+      https://chromium.googlesource.com/infra/luci/luci-go/+/master/buildbucket/proto/builds_service.proto
+    """
+    batch_requests = []
+    for buildbucket_id in buildbucket_ids:
+      batch_requests.append(rpc_pb2.GetBuildRequest(
+        id=buildbucket_id,
+        fields=(field_mask_pb2.FieldMask(paths=[properties])
+                if properties else None)
+      ))
+    return self.client.Batch(rpc_pb2.BatchRequest(requests=batch_requests))
+
+  # TODO(crbug/1006818): Need to handle ResponseNotReady given by luci prpc.
+  @retry_util.WithRetry(max_retry=5, sleep=20.0, exception=SSLError)
+  @retry_util.WithRetry(max_retry=5, sleep=20.0, exception=socket.error)
+  @retry_util.WithRetry(max_retry=5, sleep=20.0,
+                        exception=httplib.ResponseNotReady)
+  def CancelBuild(self, buildbucket_id, properties=None):
     """CancelBuild call of a specific build with buildbucket_id.
 
     Args:
       buildbucket_id: id of the build in buildbucket.
-      summary_markdown: Human-readable summary of the build in Markdown format.
       properties: fields to include in the response.
 
     Returns:
@@ -259,7 +308,6 @@
     """
     cancel_build_request = rpc_pb2.CancelBuildRequest(
          id=buildbucket_id,
-         summary_markdown=summary_markdown,
          fields=(field_mask_pb2.FieldMask(paths=[properties])
                  if properties else None)
     )
diff --git a/lib/buildbucket_v2_unittest.py b/lib/buildbucket_v2_unittest.py
index 4d965b7..a631dba 100644
--- a/lib/buildbucket_v2_unittest.py
+++ b/lib/buildbucket_v2_unittest.py
@@ -36,6 +36,52 @@
     ret = buildbucket_v2.BuildbucketV2(test_env=True)
     self.assertIsInstance(ret.client, Client)
 
+  def testBatchCancelBuilds(self):
+    fake_field_mask = field_mask_pb2.FieldMask(paths=['properties'])
+    fake_batch_request = object()
+    bbv2 = buildbucket_v2.BuildbucketV2()
+    client = bbv2.client
+    self.batch_cancel_build_request_fn = self.PatchObject(
+        rpc_pb2, 'BatchRequest', return_value=fake_batch_request)
+    self.batch_cancel_function = self.PatchObject(client, 'Batch')
+    bbv2.BatchCancelBuilds([1234, 1235], 'properties')
+    fake_builds = [
+      rpc_pb2.CancelBuildRequest(
+        id=1234,
+        fields=fake_field_mask
+      ),
+      rpc_pb2.CancelBuildRequest(
+        id=1235,
+        fields=fake_field_mask
+      ),
+    ]
+    self.batch_cancel_build_request_fn.assert_called_with(
+        requests=fake_builds)
+    self.batch_cancel_function.assert_called_with(fake_batch_request)
+
+  def testBatchGetBuilds(self):
+    fake_field_mask = field_mask_pb2.FieldMask(paths=['properties'])
+    fake_batch_request = object()
+    bbv2 = buildbucket_v2.BuildbucketV2()
+    client = bbv2.client
+    self.batch_get_build_request_fn = self.PatchObject(
+        rpc_pb2, 'BatchRequest', return_value=fake_batch_request)
+    self.batch_get_function = self.PatchObject(client, 'Batch')
+    bbv2.BatchGetBuilds([1234, 1235], 'properties')
+    fake_builds = [
+      rpc_pb2.GetBuildRequest(
+        id=1234,
+        fields=fake_field_mask
+      ),
+      rpc_pb2.GetBuildRequest(
+        id=1235,
+        fields=fake_field_mask
+      ),
+    ]
+    self.batch_get_build_request_fn.assert_called_with(
+        requests=fake_builds)
+    self.batch_get_function.assert_called_with(fake_batch_request)
+
   def testCancelBuildWithProperties(self):
     fake_field_mask = field_mask_pb2.FieldMask(paths=['properties'])
     fake_cancel_build_request = object()
@@ -44,9 +90,8 @@
     self.cancel_build_request_fn = self.PatchObject(
         rpc_pb2, 'CancelBuildRequest', return_value=fake_cancel_build_request)
     self.cancel_build_function = self.PatchObject(client, 'CancelBuild')
-    bbv2.CancelBuild('some-id', 'summary_markdown', 'properties')
-    self.cancel_build_request_fn.assert_called_with(id='some-id',
-        summary_markdown='summary_markdown',
+    bbv2.CancelBuild(1234, 'properties')
+    self.cancel_build_request_fn.assert_called_with(id=1234,
         fields=fake_field_mask)
     self.cancel_build_function.assert_called_with(fake_cancel_build_request)
 
@@ -57,10 +102,9 @@
     self.cancel_build_request_fn = self.PatchObject(
         rpc_pb2, 'CancelBuildRequest', return_value=fake_cancel_build_request)
     self.cancel_build_function = self.PatchObject(client, 'CancelBuild')
-    bbv2.CancelBuild('some-id', 'summary_markdown')
+    bbv2.CancelBuild(1234)
     self.cancel_build_request_fn.assert_called_with(
-        id='some-id',
-        summary_markdown='summary_markdown',
+        id=1234,
         fields=None)
     self.cancel_build_function.assert_called_with(fake_cancel_build_request)