Esempio n. 1
0
 def _create_channel(self):
     """
     Test helper method, creates mocked up broker interaction.
     """
     ch = RecvChannel()
     ch._declare_exchange = Mock()
     ch._declare_queue = Mock()
     ch._declare_queue.return_value = sentinel.anon_queue
     ch._bind = Mock()
     return ch
Esempio n. 2
0
 def _create_channel(self):
     """
     Test helper method, creates mocked up broker interaction.
     """
     ch = RecvChannel()
     ch._declare_exchange = Mock()
     ch._declare_queue = Mock()
     ch._declare_queue.return_value = sentinel.anon_queue
     ch._bind = Mock()
     return ch
Esempio n. 3
0
 def create_channel():
     ch = RecvChannel()
     ch._declare_exchange = mxp
     ch._declare_queue = mdq
     ch._bind = mb
     return ch
Esempio n. 4
0
 def setUp(self):
     self.ch = RecvChannel()
Esempio n. 5
0
class TestRecvChannel(PyonTestCase):
    def setUp(self):
        self.ch = RecvChannel()

    def _create_channel(self):
        """
        Test helper method, creates mocked up broker interaction.
        """
        ch = RecvChannel()
        ch._declare_exchange = Mock()
        ch._declare_queue = Mock()
        ch._declare_queue.return_value = sentinel.anon_queue
        ch._bind = Mock()
        return ch

    def test_setup_listener(self):
        # sub in mocks for _declare_exchange, _declare_queue, _bind
        mxp = Mock()
        mdq = Mock()
        mdq.return_value = sentinel.anon_queue
        mb = Mock()

        def create_channel():
            ch = RecvChannel()
            ch._declare_exchange = mxp
            ch._declare_queue = mdq
            ch._bind = mb
            return ch

        ch = create_channel()

        self.assertFalse(ch._setup_listener_called)

        # call setup listener, defining xp, queue, binding
        ch.setup_listener(
            NameTrio(sentinel.xp, sentinel.queue, sentinel.binding))

        self.assertTrue(hasattr(ch, '_recv_name'))
        self.assertTrue(hasattr(ch._recv_name, 'exchange'))
        self.assertTrue(hasattr(ch._recv_name, 'queue'))
        self.assertEquals(ch._recv_name.exchange, sentinel.xp)
        self.assertEquals(ch._recv_name.queue, sentinel.queue)

        mxp.assert_called_once_with(sentinel.xp)
        mdq.assert_called_once_with(sentinel.queue)
        mb.assert_called_once_with(sentinel.binding)

        # you can only call setup_listener once
        self.assertTrue(ch._setup_listener_called)

        # calling it again does nothing, does not touch anything
        ch.setup_listener(NameTrio(sentinel.xp2, sentinel.queue2))

        self.assertTrue(hasattr(ch._recv_name, 'exchange'))
        self.assertTrue(hasattr(ch._recv_name, 'queue'))
        self.assertEquals(ch._recv_name.exchange, sentinel.xp)
        self.assertEquals(ch._recv_name.queue, sentinel.queue)
        mxp.assert_called_once_with(sentinel.xp)
        mdq.assert_called_once_with(sentinel.queue)
        mb.assert_called_once_with(sentinel.binding)

        # call setup listener, passing a custom bind this time
        ch = create_channel()
        ch.setup_listener(NameTrio(sentinel.xp2, sentinel.queue2),
                          binding=sentinel.binding)

        mxp.assert_called_with(sentinel.xp2)
        mdq.assert_called_with(sentinel.queue2)
        mb.assert_called_with(sentinel.binding)

        # call setup_listener, use anonymous queue name and no binding (will get return value we set above)
        ch = create_channel()
        ch.setup_listener(NameTrio(sentinel.xp3))

        mxp.assert_called_with(sentinel.xp3)
        mdq.assert_called_with(None)
        mb.assert_called_with(sentinel.anon_queue)

        # call setup_listener with anon queue name but with binding
        ch = create_channel()
        ch.setup_listener(NameTrio(sentinel.xp4), binding=sentinel.binding2)

        mxp.assert_called_with(sentinel.xp4)
        mdq.assert_called_with(None)
        mb.assert_called_with(sentinel.binding2)

    def test_setup_listener_existing_recv_name(self):
        ch = self._create_channel()

        recv_name = NameTrio(sentinel.xp, sentinel.queue, sentinel.binding)
        ch._recv_name = recv_name

        ch.setup_listener()
        self.assertEquals(ch._recv_name, recv_name)

    def test_setup_listener_existing_recv_name_with_differing_name(self):
        ch = self._create_channel()

        recv_name = NameTrio(sentinel.xp, sentinel.queue, sentinel.binding)
        ch._recv_name = recv_name

        ch.setup_listener(
            name=NameTrio(sentinel.xp, sentinel.queue, sentinel.notbinding))
        self.assertNotEquals(ch._recv_name, recv_name)

        self.assertEquals(ch._recv_name.exchange, sentinel.xp)
        self.assertEquals(ch._recv_name.queue, sentinel.queue)
        self.assertEquals(ch._recv_name.binding, sentinel.notbinding)

    def test__destroy_queue_no_recv_name(self):
        self.assertRaises(AssertionError, self.ch.destroy_listener)

    def test__destroy_queue(self):
        self.ch._recv_name = NameTrio(sentinel.xp, sentinel.queue)

        self.ch._transport = Mock(BaseTransport)
        self.ch._amq_chan = sentinel.amq_chan

        self.ch.destroy_listener()

        self.assertTrue(self.ch._transport.delete_queue_impl.called)
        self.assertIn('queue',
                      self.ch._transport.delete_queue_impl.call_args[1])
        self.assertIn(
            sentinel.queue,
            self.ch._transport.delete_queue_impl.call_args[1].itervalues())

    def test_destroy_listener(self):
        m = Mock()
        self.ch._destroy_queue = m

        self.ch.destroy_listener()
        m.assert_called_once_with()

    def test__destroy_binding_no_recv_name_or_binding(self):
        self.assertRaises(AssertionError, self.ch._destroy_binding)

    def test__destroy_binding(self):
        self.ch._recv_name = NameTrio(sentinel.xp, sentinel.queue)
        self.ch._recv_binding = sentinel.binding

        self.ch._transport = Mock(BaseTransport)
        self.ch._amq_chan = sentinel.amq_chan

        self.ch._destroy_binding()

        self.assertTrue(self.ch._transport.unbind_impl.called)
        self.assertIn('queue', self.ch._transport.unbind_impl.call_args[1])
        self.assertIn('exchange', self.ch._transport.unbind_impl.call_args[1])
        self.assertIn('binding', self.ch._transport.unbind_impl.call_args[1])

        self.assertIn(sentinel.queue,
                      self.ch._transport.unbind_impl.call_args[1].itervalues())
        self.assertIn(sentinel.xp,
                      self.ch._transport.unbind_impl.call_args[1].itervalues())
        self.assertIn(sentinel.binding,
                      self.ch._transport.unbind_impl.call_args[1].itervalues())

    def test_start_consume(self):
        ac = Mock(pchannel.Channel)
        self.ch._amq_chan = ac
        self.ch._fsm.current_state = self.ch.S_ACTIVE

        ac.basic_consume.return_value = sentinel.consumer_tag

        # set up recv name for queue
        self.ch._recv_name = NameTrio(sentinel.xp, sentinel.queue)

        self.ch.start_consume()

        self.assertEquals(self.ch._fsm.current_state, self.ch.S_CONSUMING)
        self.assertEquals(self.ch._consumer_tag, sentinel.consumer_tag)

        ac.basic_consume.assert_called_once_with(
            self.ch._on_deliver,
            queue=sentinel.queue,
            no_ack=self.ch._consumer_no_ack,
            exclusive=self.ch._consumer_exclusive)

    def test_start_consume_already_started(self):
        self.ch._fsm.current_state = self.ch.S_CONSUMING
        self.assertRaises(ExceptionFSM, self.ch.start_consume)

    @patch('pyon.net.channel.log')
    def test_start_consume_with_consumer_tag_and_auto_delete(self, mocklog):
        ac = Mock(pchannel.Channel)
        self.ch._amq_chan = ac
        self.ch._fsm.current_state = self.ch.S_ACTIVE

        # set up recv name for queue
        self.ch._recv_name = NameTrio(sentinel.xp, sentinel.queue)

        self.ch._consumer_tag = sentinel.consumer_tag
        self.ch._queue_auto_delete = True

        self.ch.start_consume()
        self.assertTrue(mocklog.warn.called)

    def test_stop_consume(self):
        ac = Mock(pchannel.Channel)
        self.ch._amq_chan = ac

        # pretend we're consuming
        self.ch._fsm.current_state = self.ch.S_CONSUMING

        # callback sideffect!
        def basic_cancel_side(*args, **kwargs):
            cbparam = kwargs.get('callback')
            cbparam()

        ac.basic_cancel.side_effect = basic_cancel_side

        # set a sentinel as our consumer tag
        self.ch._consumer_tag = sentinel.consumer_tag

        # now make the call
        self.ch.stop_consume()

        self.assertEquals(self.ch._fsm.current_state, self.ch.S_ACTIVE)
        self.assertTrue(ac.basic_cancel.called)
        self.assertIn(sentinel.consumer_tag, ac.basic_cancel.call_args[0])

    def test_stop_consume_havent_started(self):
        # we're not consuming, so this should raise
        self.ch._fsm.current_state = self.ch.S_ACTIVE
        self.assertRaises(ExceptionFSM, self.ch.stop_consume)

    @patch('pyon.net.channel.log')
    def test_stop_consume_raises_warning_with_auto_delete(self, mocklog):
        ac = Mock(pchannel.Channel)
        self.ch._amq_chan = ac
        self.ch._consumer_tag = sentinel.consumer_tag
        self.ch._recv_name = NameTrio(sentinel.ex, sentinel.queue,
                                      sentinel.binding)
        self.ch._fsm.current_state = self.ch.S_CONSUMING

        self.ch._ensure_amq_chan = Mock()
        self.ch._sync_call = Mock()
        self.ch._queue_auto_delete = True

        self.ch.stop_consume()

        self.assertTrue(mocklog.debug.called)
        self.assertIn(sentinel.queue, mocklog.debug.call_args[0])

    def test_recv(self):
        # replace recv_queue with a mock obj
        rqmock = Mock(spec=queue.Queue)
        self.ch._recv_queue = rqmock

        rqmock.get.return_value = sentinel.recv

        m = self.ch.recv()

        self.assertEquals(m, sentinel.recv)

        self.assertTrue(rqmock.get.called)

    def test_recv_shutdown(self):
        # replace recv_queue with a mock obj
        rqmock = Mock(spec=queue.Queue)
        self.ch._recv_queue = rqmock

        rqmock.get.return_value = ChannelShutdownMessage()

        self.assertRaises(ChannelClosedError, self.ch.recv)

    @patch('pyon.net.channel.BaseChannel')
    @patch('pyon.net.channel.ChannelShutdownMessage')
    @patch('pyon.net.channel.log',
           Mock())  # to avoid having to put it in signature
    def test_close_impl(self, mockshutdown, mockbasechannel):

        # no auto stop consuming, no auto delete of queue without recv_name set
        # should have a shutdown message inserted
        mockrq = Mock(spec=queue.Queue)
        self.ch._recv_queue = mockrq

        self.ch.close_impl()

        # odd test quirk: have to assert mockshutdown was called once here (by close_impl),
        # before i can test that put was called with it, becuase i have to call it again just
        # to get the return value of it.
        mockshutdown.assert_called_once_with()
        mockrq.put.assert_called_once_with(mockshutdown())

        mockbasechannel.close_impl.assert_called_once_with(self.ch)

    def test_declare_queue(self):
        self.ch._transport = Mock(BaseTransport)
        self.ch._amq_chan = sentinel.amq_chan

        # needs a recv name
        self.ch._recv_name = (NameTrio(str(sentinel.xp)))

        qd = self.ch._declare_queue(str(
            sentinel.queue))  # can't join a sentinel

        self.assertTrue(self.ch._transport.declare_queue_impl.called)
        self.assertIn('queue',
                      self.ch._transport.declare_queue_impl.call_args[1])
        self.assertIn('auto_delete',
                      self.ch._transport.declare_queue_impl.call_args[1])
        self.assertIn('durable',
                      self.ch._transport.declare_queue_impl.call_args[1])

        composed = ".".join([str(sentinel.xp), str(sentinel.queue)])
        self.assertIn(
            composed,
            self.ch._transport.declare_queue_impl.call_args[1].itervalues())
        self.assertIn(
            self.ch._queue_auto_delete,
            self.ch._transport.declare_queue_impl.call_args[1].itervalues())
        self.assertIn(
            self.ch._queue_durable,
            self.ch._transport.declare_queue_impl.call_args[1].itervalues())

        # should have set recv_name
        self.assertTrue(hasattr(self.ch._recv_name, 'exchange'))
        self.assertTrue(hasattr(self.ch._recv_name, 'queue'))
        self.assertEquals(self.ch._recv_name.exchange,
                          str(sentinel.xp))  # we passed in str() versions
        self.assertEquals(self.ch._recv_name.queue,
                          self.ch._transport.declare_queue_impl())
        self.assertEquals(qd, self.ch._transport.declare_queue_impl())

    def test__bind_no_name(self):
        self.assertRaises(AssertionError, self.ch._bind, sentinel.binding)

    def test__bind(self):
        self.ch._recv_name = NameTrio(sentinel.xp, sentinel.queue)

        self.ch._amq_chan = Mock()
        self.ch._transport = Mock()

        self.ch._bind(sentinel.binding)

        self.assertTrue(self.ch._transport.bind_impl.called)
        self.assertIn('queue', self.ch._transport.bind_impl.call_args[1])
        self.assertIn('exchange', self.ch._transport.bind_impl.call_args[1])
        self.assertIn('binding', self.ch._transport.bind_impl.call_args[1])

        self.assertIn(sentinel.queue,
                      self.ch._transport.bind_impl.call_args[1].itervalues())
        self.assertIn(sentinel.xp,
                      self.ch._transport.bind_impl.call_args[1].itervalues())
        self.assertIn(sentinel.binding,
                      self.ch._transport.bind_impl.call_args[1].itervalues())

    def test__on_deliver(self):
        # mock up the method frame (delivery_tag is really only one we care about)
        m = Mock()
        m.consumer_tag = sentinel.consumer_tag
        m.delivery_tag = sentinel.delivery_tag
        m.redelivered = sentinel.redelivered
        m.exchange = sentinel.exchange
        m.routing_key = sentinel.routing_key

        # mock up the header-frame
        h = Mock()
        h.headers = {'this_exists': sentinel.exists}

        # use a mock for the recv queue
        rqmock = Mock(spec=queue.Queue)
        self.ch._recv_queue = rqmock

        # now we can call!
        self.ch._on_deliver(sentinel.chan, m, h, sentinel.body)

        # assert the call
        rqmock.put.assert_called_once_with(
            (sentinel.body, h.headers, sentinel.delivery_tag))

        # assert the headers look ok
        self.assertIn(sentinel.exists,
                      rqmock.put.call_args[0][0][1].itervalues())

    def test_ack(self):
        ac = Mock(spec=pchannel.Channel)
        self.ch._amq_chan = ac

        self.ch.ack(sentinel.delivery_tag)

        ac.basic_ack.assert_called_once_with(sentinel.delivery_tag)

    def test_reject(self):
        ac = Mock(spec=pchannel.Channel)
        self.ch._amq_chan = ac

        self.ch.reject(sentinel.delivery_tag, requeue=True)

        ac.basic_reject.assert_called_once_with(sentinel.delivery_tag,
                                                requeue=True)

    def test_reset(self):
        self.ch.reset()
        self.assertEquals(self.ch._fsm.current_state, self.ch.S_INIT)

    def test_reset_when_consuming(self):
        # have to setup a lot here, can't just mock
        # _on_stop_consume because the FSM holds onto it
        ac = Mock(pchannel.Channel)
        self.ch._amq_chan = ac

        # pretend we're consuming
        self.ch._fsm.current_state = self.ch.S_CONSUMING

        # callback sideffect!
        def basic_cancel_side(*args, **kwargs):
            cbparam = kwargs.get('callback')
            cbparam()

        ac.basic_cancel.side_effect = basic_cancel_side

        # set a sentinel as our consumer tag
        self.ch._consumer_tag = sentinel.consumer_tag

        self.ch.reset()

        self.assertEquals(self.ch._fsm.current_state, self.ch.S_ACTIVE)
        self.assertTrue(ac.basic_cancel.called)

    def test_get_stats(self):
        self.ch._amq_chan = sentinel.amq_chan
        self.ch._transport = Mock()
        self.ch._recv_name = NameTrio(sentinel.ex, sentinel.queue)

        self.ch.get_stats()

        self.ch._transport.get_stats.assert_called_once_with(
            sentinel.amq_chan, queue=sentinel.queue)
Esempio n. 6
0
 def create_channel():
     ch = RecvChannel()
     ch._declare_exchange = mxp
     ch._declare_queue = mdq
     ch._bind = mb
     return ch
Esempio n. 7
0
 def setUp(self):
     self.ch = RecvChannel()
Esempio n. 8
0
class TestRecvChannel(PyonTestCase):
    def setUp(self):
        self.ch = RecvChannel()

    def _create_channel(self):
        """
        Test helper method, creates mocked up broker interaction.
        """
        ch = RecvChannel()
        ch._declare_exchange = Mock()
        ch._declare_queue = Mock()
        ch._declare_queue.return_value = sentinel.anon_queue
        ch._bind = Mock()
        return ch

    def test_setup_listener(self):
        # sub in mocks for _declare_exchange, _declare_queue, _bind
        mxp = Mock()
        mdq = Mock()
        mdq.return_value = sentinel.anon_queue
        mb = Mock()

        def create_channel():
            ch = RecvChannel()
            ch._declare_exchange = mxp
            ch._declare_queue = mdq
            ch._bind = mb
            return ch
        
        ch = create_channel()

        self.assertFalse(ch._setup_listener_called)

        # call setup listener, defining xp, queue, binding
        ch.setup_listener(NameTrio(sentinel.xp, sentinel.queue, sentinel.binding))

        self.assertTrue(hasattr(ch, '_recv_name'))
        self.assertTrue(hasattr(ch._recv_name, 'exchange'))
        self.assertTrue(hasattr(ch._recv_name, 'queue'))
        self.assertEquals(ch._recv_name.exchange, sentinel.xp)
        self.assertEquals(ch._recv_name.queue, sentinel.queue)

        mxp.assert_called_once_with(sentinel.xp)
        mdq.assert_called_once_with(sentinel.queue)
        mb.assert_called_once_with(sentinel.binding)
        
        # you can only call setup_listener once
        self.assertTrue(ch._setup_listener_called)
        
        # calling it again does nothing, does not touch anything
        ch.setup_listener(NameTrio(sentinel.xp2, sentinel.queue2))

        self.assertTrue(hasattr(ch._recv_name, 'exchange'))
        self.assertTrue(hasattr(ch._recv_name, 'queue'))
        self.assertEquals(ch._recv_name.exchange, sentinel.xp)
        self.assertEquals(ch._recv_name.queue, sentinel.queue)
        mxp.assert_called_once_with(sentinel.xp)
        mdq.assert_called_once_with(sentinel.queue)
        mb.assert_called_once_with(sentinel.binding)

        # call setup listener, passing a custom bind this time
        ch = create_channel()
        ch.setup_listener(NameTrio(sentinel.xp2, sentinel.queue2), binding=sentinel.binding)

        mxp.assert_called_with(sentinel.xp2)
        mdq.assert_called_with(sentinel.queue2)
        mb.assert_called_with(sentinel.binding)

        # call setup_listener, use anonymous queue name and no binding (will get return value we set above)
        ch = create_channel()
        ch.setup_listener(NameTrio(sentinel.xp3))

        mxp.assert_called_with(sentinel.xp3)
        mdq.assert_called_with(None)
        mb.assert_called_with(sentinel.anon_queue)

        # call setup_listener with anon queue name but with binding
        ch = create_channel()
        ch.setup_listener(NameTrio(sentinel.xp4), binding=sentinel.binding2)

        mxp.assert_called_with(sentinel.xp4)
        mdq.assert_called_with(None)
        mb.assert_called_with(sentinel.binding2)

    def test_setup_listener_existing_recv_name(self):
        ch = self._create_channel()

        recv_name = NameTrio(sentinel.xp, sentinel.queue, sentinel.binding)
        ch._recv_name = recv_name

        ch.setup_listener()
        self.assertEquals(ch._recv_name, recv_name)

    def test_setup_listener_existing_recv_name_with_differing_name(self):
        ch = self._create_channel()

        recv_name = NameTrio(sentinel.xp, sentinel.queue, sentinel.binding)
        ch._recv_name = recv_name

        ch.setup_listener(name=NameTrio(sentinel.xp, sentinel.queue, sentinel.notbinding))
        self.assertNotEquals(ch._recv_name, recv_name)

        self.assertEquals(ch._recv_name.exchange, sentinel.xp)
        self.assertEquals(ch._recv_name.queue, sentinel.queue)
        self.assertEquals(ch._recv_name.binding, sentinel.notbinding)

    def test__destroy_queue_no_recv_name(self):
        self.assertRaises(AssertionError, self.ch.destroy_listener)

    def test__destroy_queue(self):
        self.ch._recv_name = NameTrio(sentinel.xp, sentinel.queue)

        self.ch.on_channel_open(Mock(BaseTransport))

        self.ch.destroy_listener()

        self.assertTrue(self.ch._transport.delete_queue_impl.called)
        self.assertIn('queue', self.ch._transport.delete_queue_impl.call_args[1])
        self.assertIn(sentinel.queue, self.ch._transport.delete_queue_impl.call_args[1].itervalues())

    def test_destroy_listener(self):
        m = Mock()
        self.ch._destroy_queue = m

        self.ch.destroy_listener()
        m.assert_called_once_with()

    def test__destroy_binding_no_recv_name_or_binding(self):
        self.assertRaises(AssertionError, self.ch._destroy_binding)

    def test__destroy_binding(self):
        self.ch._recv_name = NameTrio(sentinel.xp, sentinel.queue)
        self.ch._recv_binding = sentinel.binding

        self.ch.on_channel_open(Mock(BaseTransport))

        self.ch._destroy_binding()

        self.assertTrue(self.ch._transport.unbind_impl.called)
        self.assertIn('queue', self.ch._transport.unbind_impl.call_args[1])
        self.assertIn('exchange', self.ch._transport.unbind_impl.call_args[1])
        self.assertIn('binding', self.ch._transport.unbind_impl.call_args[1])

        self.assertIn(sentinel.queue, self.ch._transport.unbind_impl.call_args[1].itervalues())
        self.assertIn(sentinel.xp, self.ch._transport.unbind_impl.call_args[1].itervalues())
        self.assertIn(sentinel.binding, self.ch._transport.unbind_impl.call_args[1].itervalues())

    def test_start_consume(self):
        transport = MagicMock()
        self.ch.on_channel_open(transport)
        self.ch._fsm.current_state = self.ch.S_ACTIVE

        transport.start_consume_impl.return_value = sentinel.consumer_tag

        # set up recv name for queue
        self.ch._recv_name = NameTrio(sentinel.xp, sentinel.queue)

        self.ch.start_consume()

        self.assertTrue(self.ch._consuming)
        self.assertEquals(self.ch._fsm.current_state, self.ch.S_ACTIVE)
        self.assertEquals(self.ch._consumer_tag, sentinel.consumer_tag)

        transport.start_consume_impl.assert_called_once_with(self.ch._on_deliver, queue=sentinel.queue, no_ack=self.ch._consumer_no_ack, exclusive=self.ch._consumer_exclusive)

    def test_start_consume_already_started(self):
        self.ch._on_start_consume = Mock()
        self.ch._consuming = True

        self.ch.start_consume()     # noops due to consuming flag already on

        self.assertFalse(self.ch._on_start_consume.called)

    @patch('pyon.net.channel.log')
    def test_start_consume_with_consumer_tag_and_auto_delete(self, mocklog):
        transport = AMQPTransport(Mock())
        self.ch.on_channel_open(transport)
        self.ch._fsm.current_state = self.ch.S_ACTIVE

        # set up recv name for queue
        self.ch._recv_name = NameTrio(sentinel.xp, sentinel.queue)
        self.ch._consumer_tag = sentinel.consumer_tag
        self.ch._queue_auto_delete = True

        self.ch.start_consume()
        self.assertTrue(mocklog.warn.called)

    def test_stop_consume(self):
        transport = MagicMock()
        self.ch.on_channel_open(transport)

        # pretend we're consuming
        self.ch._fsm.current_state = self.ch.S_ACTIVE
        self.ch._consuming = True

        # set a sentinel as our consumer tag
        self.ch._consumer_tag = sentinel.consumer_tag

        # now make the call
        self.ch.stop_consume()

        self.assertEquals(self.ch._fsm.current_state, self.ch.S_ACTIVE)
        self.assertFalse(self.ch._consuming)
        self.assertTrue(transport.stop_consume_impl.called)
        self.assertIn(sentinel.consumer_tag, transport.stop_consume_impl.call_args[0])

    def test_stop_consume_havent_started(self):
        self.ch._on_stop_consume = Mock()

        self.ch.stop_consume()

        self.assertFalse(self.ch._on_stop_consume.called)

    def test_stop_consume_raises_warning_with_auto_delete(self):
        transport = AMQPTransport(Mock())
        transport.stop_consume_impl = Mock()
        self.ch.on_channel_open(transport)
        #transport.channel_number = sentinel.channel_number

        self.ch._consumer_tag = sentinel.consumer_tag
        self.ch._recv_name = NameTrio(sentinel.ex, sentinel.queue, sentinel.binding)
        self.ch._fsm.current_state = self.ch.S_ACTIVE
        self.ch._consuming = True

        #self.ch._ensure_transport = MagicMock()
        self.ch._queue_auto_delete = True

        self.ch.stop_consume()

        self.assertTrue(self.ch._transport.stop_consume_impl.called)
        self.assertIn(self.ch._consumer_tag, self.ch._transport.stop_consume_impl.call_args[0])

    def test_recv(self):
        # replace recv_queue with a mock obj
        rqmock = Mock(spec=RecvChannel.SizeNotifyQueue)
        self.ch._recv_queue = rqmock

        rqmock.get.return_value = sentinel.recv

        m = self.ch.recv()

        self.assertEquals(m, sentinel.recv)

        self.assertTrue(rqmock.get.called)

    def test_recv_shutdown(self):
        # replace recv_queue with a mock obj
        rqmock = Mock(spec=RecvChannel.SizeNotifyQueue)
        self.ch._recv_queue = rqmock

        rqmock.get.return_value = ChannelShutdownMessage()

        self.assertRaises(ChannelClosedError, self.ch.recv)

    @patch('pyon.net.channel.BaseChannel')
    @patch('pyon.net.channel.ChannelShutdownMessage')
    @patch('pyon.net.channel.log', Mock())  # to avoid having to put it in signature
    def test_close_impl(self, mockshutdown, mockbasechannel):

        # no auto stop consuming, no auto delete of queue without recv_name set
        # should have a shutdown message inserted
        mockrq = Mock(spec=RecvChannel.SizeNotifyQueue)
        self.ch._recv_queue = mockrq

        self.ch.close_impl()

        # odd test quirk: have to assert mockshutdown was called once here (by close_impl),
        # before i can test that put was called with it, becuase i have to call it again just
        # to get the return value of it.
        mockshutdown.assert_called_once_with()
        mockrq.put.assert_called_once_with(mockshutdown())

        mockbasechannel.close_impl.assert_called_once_with(self.ch)

    def test_declare_queue(self):
        self.ch.on_channel_open(Mock(BaseTransport))

        # needs a recv name
        self.ch._recv_name = (NameTrio(str(sentinel.xp)))

        qd = self.ch._declare_queue(str(sentinel.queue))    # can't join a sentinel

        self.assertTrue(self.ch._transport.declare_queue_impl.called)
        self.assertIn('queue', self.ch._transport.declare_queue_impl.call_args[1])
        self.assertIn('auto_delete', self.ch._transport.declare_queue_impl.call_args[1])
        self.assertIn('durable', self.ch._transport.declare_queue_impl.call_args[1])

        composed = ".".join([str(sentinel.xp), str(sentinel.queue)])
        self.assertIn(composed, self.ch._transport.declare_queue_impl.call_args[1].itervalues())
        self.assertIn(self.ch.queue_auto_delete, self.ch._transport.declare_queue_impl.call_args[1].itervalues())
        self.assertIn(self.ch.queue_durable, self.ch._transport.declare_queue_impl.call_args[1].itervalues())

        # should have set recv_name
        self.assertTrue(hasattr(self.ch._recv_name, 'exchange'))
        self.assertTrue(hasattr(self.ch._recv_name, 'queue'))
        self.assertEquals(self.ch._recv_name.exchange, str(sentinel.xp))    # we passed in str() versions
        self.assertEquals(self.ch._recv_name.queue, self.ch._transport.declare_queue_impl())
        self.assertEquals(qd, self.ch._transport.declare_queue_impl())

    def test__bind_no_name(self):
        self.assertRaises(AssertionError, self.ch._bind, sentinel.binding)

    def test__bind(self):
        self.ch._recv_name = NameTrio(sentinel.xp, sentinel.queue)

        self.ch.on_channel_open(Mock())

        self.ch._bind(sentinel.binding)

        self.assertTrue(self.ch._transport.bind_impl.called)
        self.assertIn('queue', self.ch._transport.bind_impl.call_args[1])
        self.assertIn('exchange', self.ch._transport.bind_impl.call_args[1])
        self.assertIn('binding', self.ch._transport.bind_impl.call_args[1])

        self.assertIn(sentinel.queue, self.ch._transport.bind_impl.call_args[1].itervalues())
        self.assertIn(sentinel.xp, self.ch._transport.bind_impl.call_args[1].itervalues())
        self.assertIn(sentinel.binding, self.ch._transport.bind_impl.call_args[1].itervalues())

    def test__on_deliver(self):
        # mock up the method frame (delivery_tag is really only one we care about)
        m = Mock()
        m.consumer_tag  = sentinel.consumer_tag
        m.delivery_tag  = sentinel.delivery_tag
        m.redelivered   = sentinel.redelivered
        m.exchange      = sentinel.exchange
        m.routing_key   = sentinel.routing_key

        # mock up the header-frame
        h = Mock()
        h.headers = { 'this_exists': sentinel.exists }

        # use a mock for the recv queue
        rqmock = Mock(spec=RecvChannel.SizeNotifyQueue)
        self.ch._recv_queue = rqmock

        # now we can call!
        self.ch._on_deliver(sentinel.chan, m, h, sentinel.body)

        # assert the call
        rqmock.put.assert_called_once_with((sentinel.body, h.headers, sentinel.delivery_tag))

        # assert the headers look ok
        self.assertIn(sentinel.exists, rqmock.put.call_args[0][0][1].itervalues())

    def test_ack(self):
        transport = Mock()
        transport.channel_number = sentinel.channel_number
        self.ch.on_channel_open(transport)

        self.ch.ack(sentinel.delivery_tag)

        transport.ack_impl.assert_called_once_with(sentinel.delivery_tag)

    def test_reject(self):
        transport = Mock()
        transport.channel_number = sentinel.channel_number
        self.ch.on_channel_open(transport)

        self.ch.reject(sentinel.delivery_tag, requeue=True)

        transport.reject_impl.assert_called_once_with(sentinel.delivery_tag, requeue=True)

    def test_reset(self):
        self.ch.reset()
        self.assertEquals(self.ch._fsm.current_state, self.ch.S_INIT)

    def test_reset_when_consuming(self):
        # have to setup a lot here, can't just mock
        # _on_stop_consume because the FSM holds onto it
        transport = MagicMock()
        self.ch.on_channel_open(transport)

        # pretend we're consuming
        self.ch._fsm.current_state = self.ch.S_ACTIVE
        self.ch._consuming = True

        # set a sentinel as our consumer tag
        self.ch._consumer_tag = sentinel.consumer_tag

        self.ch.reset()

        self.assertEquals(self.ch._fsm.current_state, self.ch.S_ACTIVE)
        self.assertTrue(transport.stop_consume_impl.called)

    def test_get_stats(self):
        transport = Mock()
        self.ch.on_channel_open(transport)
        self.ch._recv_name = NameTrio(sentinel.ex, sentinel.queue)

        self.ch.get_stats()

        self.ch._transport.get_stats_impl.assert_called_once_with(queue=sentinel.queue)

    def test_purge(self):
        transport = Mock()
        self.ch.on_channel_open(transport)
        self.ch._recv_name = NameTrio(sentinel.ex, sentinel.queue)

        self.ch._purge()

        self.ch._transport.purge_impl.assert_called_once_with(queue=sentinel.queue)
Esempio n. 9
0
class TestRecvChannel(PyonTestCase):
    def setUp(self):
        self.ch = RecvChannel()

    def test_setup_listener(self):
        # sub in mocks for _declare_exchange_point, _declare_queue, _bind
        mxp = Mock()
        mdq = Mock()
        mdq.return_value = sentinel.anon_queue
        mb = Mock()

        def create_channel():
            ch = RecvChannel()
            ch._declare_exchange_point = mxp
            ch._declare_queue = mdq
            ch._bind = mb
            return ch
        
        ch = create_channel()

        self.assertFalse(ch._setup_listener_called)

        # call setup listener, defining xp, queue, default binding (will get our return value above) becuase there's no meat to _declare_queue
        ch.setup_listener((sentinel.xp, sentinel.queue))

        self.assertTrue(hasattr(ch, '_recv_name'))
        self.assertEquals(ch._recv_name, (sentinel.xp, sentinel.queue))

        mxp.assert_called_once_with(sentinel.xp)
        mdq.assert_called_once_with(sentinel.queue)
        mb.assert_called_once_with(sentinel.anon_queue)
        
        # you can only call setup_listener once
        self.assertTrue(ch._setup_listener_called)
        
        # calling it again does nothing, does not touch anything
        ch.setup_listener((sentinel.xp2, sentinel.queue2))

        self.assertEquals(ch._recv_name, (sentinel.xp, sentinel.queue))
        mxp.assert_called_once_with(sentinel.xp)
        mdq.assert_called_once_with(sentinel.queue)
        mb.assert_called_once_with(sentinel.anon_queue)

        # call setup listener, passing a custom bind this time
        ch = create_channel()
        ch.setup_listener((sentinel.xp2, sentinel.queue2), binding=sentinel.binding)

        mxp.assert_called_with(sentinel.xp2)
        mdq.assert_called_with(sentinel.queue2)
        mb.assert_called_with(sentinel.binding)

        # call setup_listener, use anonymous queue name and no binding (will get return value we set above)
        ch = create_channel()
        ch.setup_listener((sentinel.xp3, None))

        mxp.assert_called_with(sentinel.xp3)
        mdq.assert_called_with(None)
        mb.assert_called_with(sentinel.anon_queue)

        # call setup_listener with anon queue name but with binding
        ch = create_channel()
        ch.setup_listener((sentinel.xp4, None), binding=sentinel.binding2)

        mxp.assert_called_with(sentinel.xp4)
        mdq.assert_called_with(None)
        mb.assert_called_with(sentinel.binding2)

    def test__destroy_queue_no_recv_name(self):
        self.assertRaises(AssertionError, self.ch.destroy_listener)

    def test__destroy_queue(self):
        self.ch._recv_name = (sentinel.xp, sentinel.queue)

        def side(*args, **kwargs):
            cb = kwargs.get('callback')
            cb()

        ac = Mock(spec=pchannel.Channel)
        self.ch._amq_chan = ac

        ac.queue_delete.side_effect = side

        self.ch.destroy_listener()

        self.assertTrue(ac.queue_delete.called)
        self.assertIn('queue', ac.queue_delete.call_args[1])
        self.assertIn(sentinel.queue, ac.queue_delete.call_args[1].itervalues())

    def test_destroy_listener(self):
        m = Mock()
        self.ch._destroy_queue = m

        self.ch.destroy_listener()
        m.assert_called_once_with()

    def test__destroy_binding_no_recv_name_or_binding(self):
        self.assertRaises(AssertionError, self.ch._destroy_binding)

    def test__destroy_binding(self):
        self.ch._recv_name = (sentinel.xp, sentinel.queue)
        self.ch._recv_binding = sentinel.binding

        def side(*args, **kwargs):
            cb = kwargs.get('callback')
            cb()

        ac = Mock(spec=pchannel.Channel)
        self.ch._amq_chan = ac

        ac.queue_unbind.side_effect = side

        self.ch._destroy_binding()

        self.assertTrue(ac.queue_unbind.called)
        self.assertIn('queue', ac.queue_unbind.call_args[1])
        self.assertIn('exchange', ac.queue_unbind.call_args[1])
        self.assertIn('routing_key', ac.queue_unbind.call_args[1])

        self.assertIn(sentinel.queue, ac.queue_unbind.call_args[1].itervalues())
        self.assertIn(sentinel.xp, ac.queue_unbind.call_args[1].itervalues())
        self.assertIn(sentinel.binding, ac.queue_unbind.call_args[1].itervalues())

    def test_start_consume(self):
        ac = Mock(pchannel.Channel)
        self.ch._amq_chan = ac

        ac.basic_consume.return_value = sentinel.consumer_tag

        # set up recv name for queue
        self.ch._recv_name = (sentinel.xp, sentinel.queue)

        self.ch.start_consume()

        self.assertTrue(self.ch._consuming)
        self.assertEquals(self.ch._consumer_tag, sentinel.consumer_tag)

        ac.basic_consume.assert_called_once_with(self.ch._on_deliver, queue=sentinel.queue, no_ack=self.ch._consumer_no_ack, exclusive=self.ch._consumer_exclusive)

    def test_start_consume_already_started(self):
        self.ch._consuming = True
        self.assertRaises(ChannelError, self.ch.start_consume)

    @patch('pyon.net.channel.log')
    def test_start_consume_with_consumer_tag_and_auto_delete(self, mocklog):
        ac = Mock(pchannel.Channel)
        self.ch._amq_chan = ac

        # set up recv name for queue
        self.ch._recv_name = (sentinel.xp, sentinel.queue)

        self.ch._consumer_tag = sentinel.consumer_tag
        self.ch._queue_auto_delete = True

        self.ch.start_consume()
        self.assertTrue(mocklog.warn.called)

    def test_stop_consume(self):
        ac = Mock(pchannel.Channel)
        self.ch._amq_chan = ac

        # pretend we're consuming
        self.ch._consuming = True

        # callback sideffect!
        def basic_cancel_side(*args, **kwargs):
            cbparam = kwargs.get('callback')
            cbparam()

        ac.basic_cancel.side_effect = basic_cancel_side

        # set a sentinel as our consumer tag
        self.ch._consumer_tag = sentinel.consumer_tag

        # now make the call
        self.ch.stop_consume()

        self.assertFalse(self.ch._consuming)
        self.assertTrue(ac.basic_cancel.called)
        self.assertIn(sentinel.consumer_tag, ac.basic_cancel.call_args[0])

    def test_stop_consume_havent_started(self):
        # we're not consuming, so this should raise
        self.assertRaises(ChannelError, self.ch.stop_consume)

    def test_recv(self):
        # replace recv_queue with a mock obj
        rqmock = Mock(spec=queue.Queue)
        self.ch._recv_queue = rqmock

        rqmock.get.return_value = sentinel.recv

        m = self.ch.recv()

        self.assertEquals(m, sentinel.recv)

        self.assertTrue(rqmock.get.called)

    def test_recv_shutdown(self):
        # replace recv_queue with a mock obj
        rqmock = Mock(spec=queue.Queue)
        self.ch._recv_queue = rqmock

        rqmock.get.return_value = ChannelShutdownMessage()

        self.assertRaises(ChannelClosedError, self.ch.recv)

    @patch('pyon.net.channel.BaseChannel')
    @patch('pyon.net.channel.ChannelShutdownMessage')
    @patch('pyon.net.channel.log', Mock())  # to avoid having to put it in signature
    def test_close_impl(self, mockshutdown, mockbasechannel):

        # no auto stop consuming, no auto delete of queue without recv_name set
        # should have a shutdown message inserted
        mockrq = Mock(spec=queue.Queue)
        self.ch._recv_queue = mockrq

        self.ch.close_impl()

        # odd test quirk: have to assert mockshutdown was called once here (by close_impl),
        # before i can test that put was called with it, becuase i have to call it again just
        # to get the return value of it.
        mockshutdown.assert_called_once_with()
        mockrq.put.assert_called_once_with(mockshutdown())

        mockbasechannel.close_impl.assert_called_once_with(self.ch)

    @patch('pyon.net.channel.BaseChannel')
    @patch('pyon.net.channel.log', Mock())  # to avoid having to put it in signature
    def test_close_impl_stops_consuming(self, mockbasechannel):
        self.ch._consuming = True
        scmock = Mock()

        self.ch.stop_consume = scmock

        self.ch.close_impl()
        scmock.assert_called_once_with()

    def test_declare_queue(self):
        # sideeffect that passes a result back (important here)
        framemock = Mock()
        framemock.method.queue = sentinel.queue

        def side(*args, **kwargs):
            cb = kwargs.get('callback')
            cb(framemock)

        ac = Mock(spec=pchannel.Channel)
        self.ch._amq_chan = ac

        ac.queue_declare.side_effect = side

        # needs a recv name
        self.ch._recv_name = (str(sentinel.xp), None)

        qd = self.ch._declare_queue(str(sentinel.queue))    # can't join a sentinel

        self.assertTrue(ac.queue_declare.called)
        self.assertIn('queue', ac.queue_declare.call_args[1])
        self.assertIn('auto_delete', ac.queue_declare.call_args[1])
        self.assertIn('durable', ac.queue_declare.call_args[1])

        composed = ".".join([str(sentinel.xp), str(sentinel.queue)])
        self.assertIn(composed, ac.queue_declare.call_args[1].itervalues())
        self.assertIn(self.ch._queue_auto_delete, ac.queue_declare.call_args[1].itervalues())
        self.assertIn(self.ch._queue_durable, ac.queue_declare.call_args[1].itervalues())

        # should have set recv_name
        self.assertEquals(self.ch._recv_name, (str(sentinel.xp), sentinel.queue))
        self.assertEquals(qd, sentinel.queue)

    def test__bind_no_name(self):
        self.assertRaises(AssertionError, self.ch._bind, sentinel.binding)

    def test__bind(self):
        self.ch._recv_name = (sentinel.xp, sentinel.queue)

        def side(*args, **kwargs):
            cb = kwargs.get('callback')
            cb()

        ac = Mock(spec=pchannel.Channel)
        ac.queue_bind.side_effect = side
        self.ch._amq_chan = ac

        self.ch._bind(sentinel.binding)

        self.assertTrue(ac.queue_bind.called)
        self.assertIn('queue', ac.queue_bind.call_args[1])
        self.assertIn('exchange', ac.queue_bind.call_args[1])
        self.assertIn('routing_key', ac.queue_bind.call_args[1])

        self.assertIn(sentinel.queue, ac.queue_bind.call_args[1].itervalues())
        self.assertIn(sentinel.xp, ac.queue_bind.call_args[1].itervalues())
        self.assertIn(sentinel.binding, ac.queue_bind.call_args[1].itervalues())

    def test__on_deliver(self):
        # mock up the method frame (delivery_tag is really only one we care about)
        m = Mock()
        m.consumer_tag  = sentinel.consumer_tag
        m.delivery_tag  = sentinel.delivery_tag
        m.redelivered   = sentinel.redelivered
        m.exchange      = sentinel.exchange
        m.routing_key   = sentinel.routing_key

        # mock up the header-frame
        h = Mock()
        h.headers = { 'this_exists': sentinel.exists }

        # use a mock for the recv queue
        rqmock = Mock(spec=queue.Queue)
        self.ch._recv_queue = rqmock

        # now we can call!
        self.ch._on_deliver(sentinel.chan, m, h, sentinel.body)

        # assert the call
        rqmock.put.assert_called_once_with((sentinel.body, h.headers, sentinel.delivery_tag))

        # assert the headers look ok
        self.assertIn(sentinel.exists, rqmock.put.call_args[0][0][1].itervalues())

    def test_ack(self):
        ac = Mock(spec=pchannel.Channel)
        self.ch._amq_chan = ac

        self.ch.ack(sentinel.delivery_tag)

        ac.basic_ack.assert_called_once_with(sentinel.delivery_tag)

    def test_reject(self):
        ac = Mock(spec=pchannel.Channel)
        self.ch._amq_chan = ac

        def side(*args, **kwargs):
            cb = kwargs.get('callback')
            cb()

        ac.basic_reject.side_effect = side

        self.ch.reject(sentinel.delivery_tag, requeue=True)

        self.assertTrue(ac.basic_reject.called)
        self.assertIn(sentinel.delivery_tag, ac.basic_reject.call_args[0])
        self.assertIn('requeue', ac.basic_reject.call_args[1])
        self.assertIn(True, ac.basic_reject.call_args[1].itervalues())