def _AnnotateNoStatBuilders(self, no_stat):
        """Annotate the build statuses fetched from the Buildbucket.

    Some builds may fail to upload statuses to GS. If the builds were
    scheduled by Buildbucket, get the build statuses and annotate the results.

    Args:
      no_stat: Config names of the slave builds with None status.
    """
        buildbucket_info_dict = buildbucket_lib.GetBuildInfoDict(
            self._run.attrs.metadata)

        for config_name in no_stat:
            if config_name in buildbucket_info_dict:
                buildbucket_id = buildbucket_info_dict[
                    config_name].buildbucket_id
                assert buildbucket_id is not None, 'buildbucket_id is None'
                try:
                    content = self.buildbucket_client.GetBuildRequest(
                        buildbucket_id, self._run.options.debug)

                    status = buildbucket_lib.GetBuildStatus(content)
                    result = buildbucket_lib.GetBuildResult(content)

                    text = '%s: [status] %s [result] %s' % (config_name,
                                                            status, result)

                    if result == constants.BUILDBUCKET_BUILDER_RESULT_FAILURE:
                        failure_reason = buildbucket_lib.GetBuildFailureReason(
                            content)
                        if failure_reason:
                            text += ' [failure_reason] %s' % failure_reason
                    elif result == constants.BUILDBUCKET_BUILDER_RESULT_CANCELED:
                        cancel_reason = buildbucket_lib.GetBuildCancelationReason(
                            content)
                        if cancel_reason:
                            text += ' [cancelation_reason] %s' % cancel_reason

                    dashboard_url = buildbucket_lib.GetBuildURL(content)
                    if dashboard_url:
                        logging.PrintBuildbotLink(text, dashboard_url)
                    else:
                        logging.PrintBuildbotStepText(text)
                except buildbucket_lib.BuildbucketResponseException as e:
                    logging.error('Cannot get status for %s: %s', config_name,
                                  e)
                    logging.PrintBuildbotStepText(
                        'No status found for build %s buildbucket_id %s' %
                        (config_name, buildbucket_id))
            else:
                logging.PrintBuildbotStepText(
                    "%s wasn't scheduled by master." % config_name)
    def GetAllSlaveBuildbucketInfo(buildbucket_client,
                                   scheduled_buildbucket_info_dict,
                                   dry_run=True):
        """Get buildbucket info from Buildbucket for all scheduled slave builds.

    For each build in the scheduled builds dict, get build status and build
    result from Buildbucket and return a updated buildbucket_info_dict.

    Args:
      buildbucket_client: Instance of buildbucket_lib.buildbucket_client.
      scheduled_buildbucket_info_dict: A dict mapping scheduled slave build
        config name to its buildbucket information in the format of
        BuildbucketInfo (see buildbucket.GetBuildInfoDict for details).
      dry_run: Boolean indicating whether it's a dry run. Default to True.

    Returns:
      A dict mapping all scheduled slave build config names to their
      BuildbucketInfos (The BuildbucketInfo of the most recently retried one of
      there're multiple retries for a slave build config).
    """
        #TODO(nxia): consider replacing this with a more elaborate fix
        if buildbucket_client is None:
            return {}

        all_buildbucket_info_dict = {}
        for build_config, build_info in scheduled_buildbucket_info_dict.iteritems(
        ):
            buildbucket_id = build_info.buildbucket_id
            retry = build_info.retry
            created_ts = build_info.created_ts
            status = None
            result = None
            url = None

            try:
                content = buildbucket_client.GetBuildRequest(
                    buildbucket_id, dry_run)
                status = buildbucket_lib.GetBuildStatus(content)
                result = buildbucket_lib.GetBuildResult(content)
                url = buildbucket_lib.GetBuildURL(content)
            except buildbucket_lib.BuildbucketResponseException as e:
                # If we have a temporary issue accessing the build status from the
                # Buildbucket, log the error and continue with other builds.
                # SlaveStatus will handle the missing builds in ShouldWait().
                logging.error('Failed to get status for build %s id %s: %s',
                              build_config, buildbucket_id, e)

            all_buildbucket_info_dict[
                build_config] = buildbucket_lib.BuildbucketInfo(
                    buildbucket_id, retry, created_ts, status, result, url)

        return all_buildbucket_info_dict
    def testGetBuildRequest(self):
        """Test GetBuildRequest."""
        buildbucket_id = 'test_buildbucket_id'
        complete_status = 'COMPLETED'
        content = json.dumps(
            {'build': {
                'id': buildbucket_id,
                'status': complete_status
            }})
        self.mock_http.request.return_value = (self.success_response, content)
        result_content = self.client.GetBuildRequest(buildbucket_id, False)
        self.assertEqual(buildbucket_lib.GetBuildStatus(result_content),
                         complete_status)

        # Test dryrun
        result_content_2 = self.client.GetBuildRequest(buildbucket_id, True)
        self.assertIsNone(result_content_2)
    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)