def test_process_frames_drops_non_close_methods_when_emergency_closing( self): c = Channel(mock(), None, self._CLASS_MAP) c._emergency_close_pending = True c._connection = mock() c._connection.logger = mock() f0 = MethodFrame(1, 30, 40) f1 = HeaderFrame(1, 30, 0, 0) f2 = ContentFrame(1, "payload") f3_basic_close = MethodFrame(1, 20, 40) f4_basic_close_ok = MethodFrame(1, 20, 41) f5 = MethodFrame(1, 90, 11) c._frame_buffer = deque( [f0, f1, f2, f3_basic_close, f4_basic_close_ok, f5]) expect(c.dispatch).args(f0).times(0) expect(c.dispatch).args(f1).times(0) expect(c.dispatch).args(f2).times(0) expect(c.dispatch).args(f3_basic_close).times(1) expect(c.dispatch).args(f4_basic_close_ok).times(1) expect(c.dispatch).args(f5).times(0) expect(c.logger.warn).times(4) c.process_frames() assert_equals(0, len(c._frame_buffer))
def test_next_frame_with_a_frame(self): c = Channel(None, None, {}) ch_id, c_id, m_id = 0, 1, 2 f0 = MethodFrame(ch_id, c_id, m_id) f1 = MethodFrame(ch_id, c_id, m_id) c._frame_buffer = deque([f0, f1]) assert_equals(c.next_frame(), f0)
def test_str(self): frame = MethodFrame(42, 5, 6, Reader(bytearray('hello'))) assert_equals( 'MethodFrame[channel: 42, class_id: 5, method_id: 6, args: \\x68\\x65\\x6c\\x6c\\x6f]', str(frame)) frame = MethodFrame(42, 5, 6) assert_equals( 'MethodFrame[channel: 42, class_id: 5, method_id: 6, args: None]', str(frame))
def test_process_frames_stops_when_frameunderflow_raised(self): c = Channel(None, None, {}) f0 = MethodFrame('ch_id', 'c_id', 'm_id') f1 = MethodFrame('ch_id', 'c_id', 'm_id') c._frame_buffer = deque([f0, f1]) expect(c.dispatch).args(f0).raises(ProtocolClass.FrameUnderflow) c.process_frames() assert_equals(f1, c._frame_buffer[0])
def test_process_frames_stops_when_buffer_is_empty(self): c = Channel(None, None, {}) f0 = MethodFrame('ch_id', 'c_id', 'm_id') f1 = MethodFrame('ch_id', 'c_id', 'm_id') c._frame_buffer = deque([f0, f1]) expect(c.dispatch).args(f0) expect(c.dispatch).args(f1) c.process_frames() assert_equals(deque(), c._frame_buffer)
def test_flush_pending_events_flushes_all_leading_frames(self): conn = mock() c = Channel(conn, 42, {}) f1 = MethodFrame(1, 2, 3) f2 = MethodFrame(1, 2, 3) f3 = MethodFrame(1, 2, 3) c._pending_events = deque([f1, f2, 'cb', f3]) expect(conn.send_frame).args(f1) expect(conn.send_frame).args(f2) c._flush_pending_events() assert_equals(deque(['cb', f3]), c._pending_events)
def test_process_frames_when_connectionclosed_on_dispatch(self): c = Channel(None, None, {}) c._connection = mock() c._connection.logger = mock() f0 = MethodFrame(20, 30, 40) f1 = MethodFrame('ch_id', 'c_id', 'm_id') c._frame_buffer = deque([f0, f1]) expect(c.dispatch).args(f0).raises( ConnectionClosed('something darkside')) stub(c.close) # assert not called assert_raises(ConnectionClosed, c.process_frames)
def test_process_frames_logs_and_closes_when_dispatch_error_raised(self): c = Channel(None, None, {}) c._connection = mock() c._connection.logger = mock() f0 = MethodFrame(20, 30, 40) f1 = MethodFrame('ch_id', 'c_id', 'm_id') c._frame_buffer = deque([f0, f1]) expect(c.dispatch).args(f0).raises(RuntimeError("zomg it broked")) expect(c.close).args(500, 'Failed to dispatch %s' % (str(f0))) assert_raises(RuntimeError, c.process_frames) assert_equals(f1, c._frame_buffer[0])
def test_process_frames_logs_and_closes_when_systemexit_raised(self): c = Channel(None, None, {}) c._connection = mock() c._connection.logger = mock() f0 = MethodFrame(20, 30, 40) f1 = MethodFrame('ch_id', 'c_id', 'm_id') c._frame_buffer = deque([f0, f1]) expect(c.dispatch).args(f0).raises(SystemExit()) stub(c.close) assert_raises(SystemExit, c.process_frames) assert_equals(f1, c._frame_buffer[0])
def dispatch(self, frame): ''' Override the default dispatch since we don't need the rest of the stack. ''' if frame.type() == HeartbeatFrame.type(): self.send_heartbeat() elif frame.type() == MethodFrame.type(): if frame.class_id == 10: cb = self._method_map.get(frame.method_id) if cb: method = self.clear_synchronous_cb(cb) method(frame) else: raise Channel.InvalidMethod( "unsupported method %d on channel %d", frame.method_id, self.channel_id) else: raise Channel.InvalidClass( "class %d is not supported on channel %d", frame.class_id, self.channel_id) else: raise Frame.InvalidFrameType( "frame type %d is not supported on channel %d", frame.type(), self.channel_id)
def bind(self, exchange, source, routing_key='', nowait=True, arguments={}, ticket=None, cb=None): ''' Bind an exchange to another. ''' nowait = nowait and self.allow_nowait() and not cb args = Writer() args.write_short(ticket or self.default_ticket).\ write_shortstr(exchange).\ write_shortstr(source).\ write_shortstr(routing_key).\ write_bit(nowait).\ write_table(arguments or {}) self.send_frame(MethodFrame(self.channel_id, 40, 30, args)) if not nowait: self._bind_cb.append(cb) self.channel.add_synchronous_cb(self._recv_bind_ok)
def nack(self, delivery_tag, multiple=False, requeue=False): '''Send a nack to the broker.''' args = Writer() args.write_longlong(delivery_tag).\ write_bits(multiple, requeue) self.send_frame(MethodFrame(self.channel_id, 60, 120, args))
def consume(self, queue, consumer, consumer_tag='', no_local=False, no_ack=True, exclusive=False, nowait=True, ticket=None, cb=None): ''' Start a queue consumer. If `cb` is supplied, will be called when broker confirms that consumer is registered. ''' nowait = nowait and self.allow_nowait() and not cb if nowait and consumer_tag == '': consumer_tag = self._generate_consumer_tag() args = Writer() args.write_short(ticket or self.default_ticket).\ write_shortstr(queue).\ write_shortstr(consumer_tag).\ write_bits(no_local, no_ack, exclusive, nowait).\ write_table({}) # unused according to spec self.send_frame(MethodFrame(self.channel_id, 60, 20, args)) if not nowait: self._pending_consumers.append((consumer, cb)) self.channel.add_synchronous_cb(self._recv_consume_ok) else: self._consumer_cb[consumer_tag] = consumer
def test_process_frames_raises_systemexit_when_close_raises_systemexit(self): c = Channel(mock(), 20, {}) c._connection = mock() c._connection.logger = mock() f0 = MethodFrame(20, 30, 40) f1 = MethodFrame('ch_id', 'c_id', 'm_id') c._frame_buffer = deque([f0, f1]) expect(c.dispatch).args(f0).raises(RuntimeError("zomg it broked")) expect(c.logger.exception).args( 'Closing on failed dispatch of frame %.255s', f0) expect(c.close).raises(SystemExit()) assert_raises(SystemExit, c.process_frames) assert_equals(f1, c._frame_buffer[0])
def declare(self, queue='', passive=False, durable=False, exclusive=False, auto_delete=True, nowait=True, arguments={}, ticket=None, cb=None): ''' Declare a queue. By default is asynchronoous but will be synchronous if nowait=False or a callback is defined. In synchronous mode, returns (message_count, consumer_count) queue - The name of the queue cb - An optional method which will be called with (queue_name, msg_count, consumer_count) if nowait=False ''' nowait = nowait and self.allow_nowait() and not cb args = Writer() args.write_short(ticket or self.default_ticket).\ write_shortstr(queue).\ write_bits(passive, durable, exclusive, auto_delete, nowait).\ write_table(arguments) self.send_frame(MethodFrame(self.channel_id, 50, 10, args)) if not nowait: self._declare_cb.append(cb) return self.channel.add_synchronous_cb(self._recv_declare_ok)
def declare(self, exchange, type, passive=False, durable=False, nowait=True, arguments=None, ticket=None, cb=None): """ Declare the exchange. exchange - The name of the exchange to declare type - One of """ nowait = nowait and self.allow_nowait() and not cb args = Writer() args.write_short(ticket or self.default_ticket).\ write_shortstr(exchange).\ write_shortstr(type).\ write_bits(passive, durable, False, False, nowait).\ write_table(arguments or {}) self.send_frame(MethodFrame(self.channel_id, 40, 10, args)) if not nowait: self._declare_cb.append(cb) self.channel.add_synchronous_cb(self._recv_declare_ok)
def cancel(self, consumer_tag='', nowait=True, consumer=None, cb=None): ''' Cancel a consumer. Can choose to delete based on a consumer tag or the function which is consuming. If deleting by function, take care to only use a consumer once per channel. ''' if consumer: for (tag, func) in self._consumer_cb.iteritems(): if func == consumer: consumer_tag = tag break nowait = nowait and self.allow_nowait() and not cb args = Writer() args.write_shortstr(consumer_tag).\ write_bit(nowait) self.send_frame(MethodFrame(self.channel_id, 60, 30, args)) if not nowait: self._cancel_cb.append(cb) self.channel.add_synchronous_cb(self._recv_cancel_ok) else: try: del self._consumer_cb[consumer_tag] except KeyError: self.logger.warning( 'no callback registered for consumer tag " %s "', consumer_tag)
def open(self): ''' Open the channel for communication. ''' args = Writer() args.write_shortstr('') self.send_frame(MethodFrame(self.channel_id, 20, 10, args)) self.channel.add_synchronous_cb(self._recv_open_ok)
def _send_flow(self, active): ''' Send a flow control command. ''' args = Writer() args.write_bit(active) self.send_frame(MethodFrame(self.channel_id, 20, 20, args)) self.channel.add_synchronous_cb(self._recv_flow_ok)
def test_requeue_frames(self): c = Channel(None, None, {}) ch_id, c_id, m_id = 0, 1, 2 f = [MethodFrame(ch_id, c_id, m_id) for i in xrange(4)] c._frame_buffer = deque(f[:2]) c.requeue_frames(f[2:]) assert_equals(c._frame_buffer, deque([f[i] for i in [3, 2, 0, 1]]))
def _send_open(self): args = Writer() args.write_shortstr(self.connection._vhost) args.write_shortstr('') args.write_bit(True) # insist flag for older amqp, not used in 0.9.1 self.send_frame(MethodFrame(self.channel_id, 10, 40, args)) self.add_synchronous_cb(self._recv_open_ok)
def _send_close(self): args = Writer() args.write_short(self.connection._close_info['reply_code']) args.write_shortstr(self.connection._close_info['reply_text'][:255]) args.write_short(self.connection._close_info['class_id']) args.write_short(self.connection._close_info['method_id']) self.send_frame(MethodFrame(self.channel_id, 10, 50, args)) self.add_synchronous_cb(self._recv_close_ok)
def test_write_frame(self): args = mock() expect(args.buffer).returns('hello') frame = MethodFrame(42, 5, 6, args) buf = bytearray() frame.write_frame(buf) reader = Reader(buf) assert_equals(1, reader.read_octet()) assert_equals(42, reader.read_short()) size = reader.read_long() start_pos = reader.tell() assert_equals(5, reader.read_short()) assert_equals(6, reader.read_short()) args_pos = reader.tell() assert_equals('hello', reader.read(size - (args_pos - start_pos))) assert_equals(0xce, reader.read_octet())
def test_process_frames_logs_and_preserves_original_exception_when_dispatch_and_close_fail(self): # fix it, too. c = Channel(mock(), 20, {}) c._connection = mock() c._connection.logger = mock() f0 = MethodFrame(20, 30, 40) f1 = MethodFrame('ch_id', 'c_id', 'm_id') c._frame_buffer = deque([f0, f1]) expect(c.dispatch).args(f0).raises(RuntimeError("zomg it broked")) expect(c.logger.exception).args( 'Closing on failed dispatch of frame %.255s', f0) expect(c.close).raises(ValueError()) expect(c.logger.exception).args('Channel close failed') assert_raises(RuntimeError, c.process_frames) assert_equals(f1, c._frame_buffer[0])
def reject(self, delivery_tag, requeue=False): ''' Reject a message. ''' args = Writer() args.write_longlong(delivery_tag).\ write_bit(requeue) self.send_frame(MethodFrame(self.channel_id, 60, 90, args))
def test_dispatch_method_frame_raises_invalidclass(self): frame = mock() frame.class_id = 11 frame.method_id = 10 expect(frame.type).returns(MethodFrame.type()) with assert_raises(Channel.InvalidClass): self.ch.dispatch(frame)
def select(self, cb=None): ''' Set this channel to use transactions. ''' if not self._enabled: self._enabled = True self.send_frame(MethodFrame(self.channel_id, 90, 10)) self._select_cb.append(cb) self.channel.add_synchronous_cb(self._recv_select_ok)
def test_parse(self): reader = mock() expect(reader.read_short).returns('class_id') expect(reader.read_short).returns('method_id') frame = MethodFrame.parse(42, reader) assert_equals(42, frame.channel_id) assert_equals('class_id', frame.class_id) assert_equals('method_id', frame.method_id) assert_equals(reader, frame.args)
def test_dispatch_method_frame_class_10(self): frame = mock() frame.class_id = 10 frame.method_id = 10 method = self.ch._method_map[10] = mock() expect(frame.type).returns(MethodFrame.type()) expect(method).args(frame) self.ch.dispatch(frame)
def _send_start_ok(self): '''Send the start_ok message.''' args = Writer() args.write_table(self.connection._properties) args.write_shortstr(self.connection._login_method) args.write_longstr(self.connection._login_response) args.write_shortstr(self.connection._locale) self.send_frame(MethodFrame(self.channel_id, 10, 11, args)) self.add_synchronous_cb(self._recv_tune)
def test_dispatch_runs_callbacks(self): frame = mock() frame.class_id = 10 frame.method_id = 10 method = self.ch._method_map[10] = mock() cb = mock() expect(frame.type).returns(MethodFrame.type()) expect(self.ch.clear_synchronous_cb).args(method).returns(cb) expect(cb).args(frame) self.ch.dispatch(frame)
def test_type(self): assert_equals(1, MethodFrame.type())