def CancelBuilds(buildbucket_ids, buildbucket_client,
                 debug=True, config=None):
  """Cancel Buildbucket builds in a set.

  Args:
    buildbucket_ids: A list of build_ids (strings).
    buildbucket_client: Instance of buildbucket_lib.buildbucket_client.
    debug: Boolean indicating whether it's a dry run. Default to True.
    config: Instance of config_lib.BuildConfig. Config dict for the master
      build initiating the cancel. Optional.
  """
  if buildbucket_ids:
    logging.info('Canceling buildbucket_ids: %s', buildbucket_ids)
    if (not debug) and config:
      fields = {'build_type': config.build_type,
                'build_name': config.name}
      metrics.Counter(constants.MON_BB_CANCEL_BATCH_BUILDS_COUNT).increment(
          fields=fields)
    cancel_results = buildbucket_client.CancelBatchBuildsRequest(
        buildbucket_ids,
        dryrun=debug)
    result_map = buildbucket_lib.GetResultMap(cancel_results)
    for buildbucket_id, result in result_map.items():
      # Check for error messages
      if buildbucket_lib.GetNestedAttr(result, ['error']):
        # TODO(nxia): Get build url and log url in the warnings.
        logging.warning('Error cancelling build %s with reason: %s. '
                        'Please check the status of the build.',
                        buildbucket_id,
                        buildbucket_lib.GetErrorReason(result))
    def testCancelBatchBuildsRequest(self):
        """Test CancelBatchBuilds."""
        buildbucket_id_1 = 'test_buildbucket_id_1'
        buildbucket_id_2 = 'test_buildbucket_id_2'
        status = 'COMPLETED'
        result = 'CANCELED'
        error_reason = 'BUILD_IS_COMPLETED'
        content = json.dumps({
            'results': [{
                'build_id': buildbucket_id_1,
                'build': {
                    'status': status,
                    'result': result,
                }
            }, {
                'build_id': buildbucket_id_2,
                'error': {
                    'message': 'Cannot cancel a completed build',
                    'reason': error_reason,
                }
            }]
        })
        self.mock_http.request.return_value = (self.success_response, content)
        result_content = self.client.CancelBatchBuildsRequest(
            [buildbucket_id_1, buildbucket_id_2], False)

        result_map = buildbucket_lib.GetResultMap(result_content)
        self.assertIsNotNone(
            buildbucket_lib.GetNestedAttr(result_map[buildbucket_id_1],
                                          ['build']))
        self.assertIsNotNone(
            buildbucket_lib.GetNestedAttr(result_map[buildbucket_id_2],
                                          ['error']))
        self.assertEqual(
            buildbucket_lib.GetBuildStatus(result_map[buildbucket_id_1]),
            status)
        self.assertEqual(
            buildbucket_lib.GetErrorReason(result_map[buildbucket_id_2]),
            error_reason)

        # Test dryrun
        result_content_2 = self.client.CancelBatchBuildsRequest(
            [buildbucket_id_1, buildbucket_id_2], True)
        self.assertIsNone(result_content_2)