def test_on_response():
    # Create mock Executor so we can verify calls to executor.submit().
    executor = mock.create_autospec(futures.Executor, instance=True)

    callback = mock.Mock(spec=())
    policy = create_and_open_policy(callback, executor=executor)

    # Set up the messages.
    response = types.StreamingPullResponse(received_messages=[
        types.ReceivedMessage(ack_id='fack',
                              message=types.PubsubMessage(data=b'foo',
                                                          message_id='1')),
        types.ReceivedMessage(ack_id='back',
                              message=types.PubsubMessage(data=b'bar',
                                                          message_id='2')),
    ], )

    # Actually run the method and prove that modack and executor.submit
    # are called in the expected way.
    modack_patch = mock.patch.object(policy,
                                     'modify_ack_deadline',
                                     autospec=True)
    with modack_patch as modack:
        policy.on_response(response)

    modack.assert_called_once_with(
        [base.ModAckRequest('fack', 10),
         base.ModAckRequest('back', 10)])

    submit_calls = [m for m in executor.method_calls if m[0] == 'submit']
    assert len(submit_calls) == 2
    for call in submit_calls:
        assert call[1][0] == policy._callback
        assert isinstance(call[1][1], message.Message)
def test_on_response():
    callback = mock.Mock(spec=())

    # Create mock ThreadPoolExecutor, pass into create_policy(), and verify
    # that both executor.submit() and future.add_done_callback are called
    # twice.
    future = mock.Mock()
    attrs = {'submit.return_value': future}
    executor = mock.Mock(**attrs)

    # Set up the policy.
    policy = create_policy(executor=executor)
    policy._callback = callback

    # Set up the messages to send.
    messages = (
        types.PubsubMessage(data=b'foo', message_id='1'),
        types.PubsubMessage(data=b'bar', message_id='2'),
    )

    # Set up a valid response.
    response = types.StreamingPullResponse(received_messages=[
        {
            'ack_id': 'fack',
            'message': messages[0]
        },
        {
            'ack_id': 'back',
            'message': messages[1]
        },
    ], )

    # Actually run the method and prove that modack and executor.submit
    # are called in the expected way.
    modack_patch = mock.patch.object(policy,
                                     'modify_ack_deadline',
                                     autospec=True)
    with modack_patch as modack:
        policy.on_response(response)

    modack.assert_called_once_with(
        [base.ModAckRequest('fack', 10),
         base.ModAckRequest('back', 10)])

    submit_calls = [m for m in executor.method_calls if m[0] == 'submit']
    assert len(submit_calls) == 2
    for call in submit_calls:
        assert call[1][0] == callback
        assert isinstance(call[1][1], message.Message)
def test_modify_ack_deadline():
    msg = create_message(b'foo', ack_id='bogus_ack_id')
    with mock.patch.object(msg._request_queue, 'put') as put:
        msg.modify_ack_deadline(60)
        put.assert_called_once_with(
            base.ModAckRequest(
                ack_id='bogus_ack_id',
                seconds=60,
            ))
        check_call_types(put, base.ModAckRequest)
def test_nack():
    policy = create_policy()
    with mock.patch.object(policy, 'modify_ack_deadline') as mad:
        with mock.patch.object(policy, 'drop') as drop:
            items = [base.NackRequest(ack_id='ack_id_string', byte_size=10)]
            policy.nack(items)
            drop.assert_called_once_with(
                [base.DropRequest(ack_id='ack_id_string', byte_size=10)])
        mad.assert_called_once_with(
            [base.ModAckRequest(ack_id='ack_id_string', seconds=0)])
def test_modify_ack_deadline():
    policy = create_policy()
    with mock.patch.object(policy._consumer, 'send_request') as send_request:
        policy.modify_ack_deadline(
            [base.ModAckRequest(ack_id='ack_id_string', seconds=60)])
        send_request.assert_called_once_with(
            types.StreamingPullRequest(
                modify_deadline_ack_ids=['ack_id_string'],
                modify_deadline_seconds=[60],
            ))
    def modify_ack_deadline(self, seconds):
        """Resets the deadline for acknowledgement.

        New deadline will be the given value of seconds from now.

        The default implementation handles this for you; you should not need
        to manually deal with setting ack deadlines. The exception case is
        if you are implementing your own custom subclass of
        :class:`~.pubsub_v1.subcriber._consumer.Consumer`.

        Args:
            seconds (int): The number of seconds to set the lease deadline
                to. This should be between 0 and 600. Due to network latency,
                values below 10 are advised against.
        """
        self._request_queue.put(
            base_policy.ModAckRequest(ack_id=self._ack_id, seconds=seconds))
    def on_response(self, response):
        """Process all received Pub/Sub messages.

        For each message, send a modified acknowledgement request to the
        server. This prevents expiration of the message due to buffering by
        gRPC or proxy/firewall. This makes the server and client expiration
        timer closer to each other thus preventing the message being
        redelivered multiple times.

        After the messages have all had their ack deadline updated, execute
        the callback for each message using the executor.
        """
        items = [
            base.ModAckRequest(message.ack_id, self.histogram.percentile(99))
            for message in response.received_messages
        ]
        self.modify_ack_deadline(items)
        for msg in response.received_messages:
            _LOGGER.debug('Using %s to process message with ack_id %s.',
                          self._callback, msg.ack_id)
            message = Message(msg.message, msg.ack_id, self._request_queue)
            self._executor.submit(self._callback, message)
def test_open_already_open():
    policy = create_policy()
    policy._future = mock.sentinel.future

    with pytest.raises(ValueError) as exc_info:
        policy.open(None)

    assert exc_info.value.args == ('This policy has already been opened.', )


@pytest.mark.parametrize('item,method',
                         [(base.AckRequest(0, 0, 0), 'ack'),
                          (base.DropRequest(0, 0), 'drop'),
                          (base.LeaseRequest(0, 0), 'lease'),
                          (base.ModAckRequest(0, 0), 'modify_ack_deadline'),
                          (base.NackRequest(0, 0), 'nack')])
def test_dispatch_callback_valid(item, method):
    policy = create_policy()
    with mock.patch.object(policy, method) as mocked:
        items = [item]
        policy.dispatch_callback(items)
        mocked.assert_called_once_with([item])


def test_on_exception_deadline_exceeded():
    policy = create_policy()

    details = 'Bad thing happened. Time out, go sit in the corner.'
    exc = exceptions.DeadlineExceeded(details)