""" Tests for pika.connection.Connection """ # Suppress pylint warnings concerning access to protected member # pylint: disable=W0212 # Suppress pylint messages concerning missing docstrings # pylint: disable=C0111 # Suppress pylint messages concerning invalid method name # pylint: disable=C0103 try: import mock except ImportError: from unittest import mock # pylint: disable=E0611 import random import platform import unittest import mock from pika import connection, channel, credentials, exceptions, frame, spec import pika from pika.compat import xrange def callback_method(): """Callback method to use in tests""" pass class ConnectionTests(unittest.TestCase): # pylint: disable=R0904 def setUp(self): class ChannelTemplate(channel.Channel): channel_number = None with mock.patch('pika.connection.Connection.connect'): self.connection = connection.Connection() self.connection._set_connection_state( connection.Connection.CONNECTION_OPEN) self.channel = mock.Mock(spec=ChannelTemplate) self.channel.channel_number = 1 self.channel.is_open = True self.channel.is_closing = False self.channel.is_closed = False self.connection._channels[self.channel.channel_number] = self.channel def tearDown(self): del self.connection del self.channel @mock.patch('pika.connection.Connection._on_close_ready') def test_close_calls_on_close_ready_when_no_channels( self, on_close_ready_mock): self.connection._channels = dict() self.connection.close() self.assertTrue(on_close_ready_mock.called, 'on_close_ready_mock should have been called') @mock.patch('pika.connection.Connection._on_close_ready') def test_close_closes_open_channels(self, on_close_ready): self.connection.close() self.channel.close.assert_called_once_with(200, 'Normal shutdown') self.assertFalse(on_close_ready.called) @mock.patch('pika.connection.Connection._on_close_ready') def test_close_closes_opening_channels(self, on_close_ready): self.channel.is_open = False self.channel.is_closing = False self.channel.is_closed = False self.connection.close() self.channel.close.assert_called_once_with(200, 'Normal shutdown') self.assertFalse(on_close_ready.called) @mock.patch('pika.connection.Connection._on_close_ready') def test_close_does_not_close_closing_channels(self, on_close_ready): self.channel.is_open = False self.channel.is_closing = True self.channel.is_closed = False self.connection.close() self.assertFalse(self.channel.close.called) self.assertFalse(on_close_ready.called) @mock.patch('pika.connection.Connection._close_channels') def test_close_bails_out_if_already_closed_or_closing( self, close_channels): for closed_state in (self.connection.CONNECTION_CLOSED, self.connection.CONNECTION_CLOSING): self.connection.connection_state = closed_state self.connection.close() self.assertFalse(self.channel.close.called) self.assertEqual(self.connection.connection_state, closed_state) @mock.patch('logging.Logger.critical') def test_deliver_frame_to_channel_with_frame_for_unknown_channel( self, critical_mock): unknown_channel_num = 99 self.assertNotIn(unknown_channel_num, self.connection._channels) unexpected_frame = frame.Method(unknown_channel_num, mock.Mock()) self.connection._deliver_frame_to_channel(unexpected_frame) critical_mock.assert_called_once_with( 'Received %s frame for unregistered channel %i on %s', unexpected_frame.NAME, unknown_channel_num, self.connection) @mock.patch('pika.connection.Connection._on_close_ready') def test_on_channel_cleanup_with_closing_channels(self, on_close_ready): """if connection is closing but closing channels remain, do not call \ _on_close_ready """ self.channel.is_open = False self.channel.is_closing = True self.channel.is_closed = False self.connection.close() self.assertFalse(on_close_ready.called, '_on_close_ready should not have been called') @mock.patch('pika.connection.Connection._on_close_ready') def test_on_channel_cleanup_closing_state_last_channel_calls_on_close_ready( self, on_close_ready_mock): self.connection.connection_state = self.connection.CONNECTION_CLOSING self.connection._on_channel_cleanup(self.channel) self.assertTrue(on_close_ready_mock.called, '_on_close_ready should have been called') @mock.patch('pika.connection.Connection._on_close_ready') def test_on_channel_cleanup_closing_state_more_channels_no_on_close_ready( self, on_close_ready_mock): self.connection.connection_state = self.connection.CONNECTION_CLOSING channel_mock = mock.Mock(channel_number=99, is_closing=True) self.connection._channels[99] = channel_mock self.connection._on_channel_cleanup(self.channel) self.assertFalse(on_close_ready_mock.called, '_on_close_ready should not have been called') @mock.patch('pika.connection.Connection._on_close_ready') def test_on_channel_cleanup_non_closing_state(self, on_close_ready): """if connection isn't closing _on_close_ready should not be called""" self.connection._on_channel_cleanup(mock.Mock()) self.assertFalse(on_close_ready.called, '_on_close_ready should not have been called') def test_on_terminate_cleans_up(self): """_on_terminate cleans up heartbeat, adapter, and channels""" heartbeat = mock.Mock() self.connection.heartbeat = heartbeat self.connection._adapter_disconnect = mock.Mock() self.connection._on_terminate(-1, 'Undefined') heartbeat.stop.assert_called_once_with() self.connection._adapter_disconnect.assert_called_once_with() self.channel._on_close_meta.assert_called_once_with(-1, 'Undefined') self.assertTrue(self.connection.is_closed) def test_on_terminate_invokes_connection_closed_callback(self): """_on_terminate invokes `Connection.ON_CONNECTION_CLOSED` callbacks""" self.connection.callbacks.process = mock.Mock( wraps=self.connection.callbacks.process) self.connection._adapter_disconnect = mock.Mock() self.connection._on_terminate(1, 'error text') self.connection.callbacks.process.assert_called_once_with( 0, self.connection.ON_CONNECTION_CLOSED, self.connection, self.connection, 1, 'error text') with self.assertRaises(AssertionError): self.connection.callbacks.process.assert_any_call( 0, self.connection.ON_CONNECTION_ERROR, self.connection, self.connection, mock.ANY) def test_on_terminate_invokes_protocol_on_connection_error_and_closed( self): """_on_terminate invokes `ON_CONNECTION_ERROR` with \ `IncompatibleProtocolError` and `ON_CONNECTION_CLOSED` callbacks""" with mock.patch.object(self.connection.callbacks, 'process'): self.connection._adapter_disconnect = mock.Mock() self.connection._set_connection_state( self.connection.CONNECTION_PROTOCOL) self.connection._on_terminate(1, 'error text') self.assertEqual(self.connection.callbacks.process.call_count, 2) self.connection.callbacks.process.assert_any_call( 0, self.connection.ON_CONNECTION_ERROR, self.connection, self.connection, mock.ANY) conn_exc = self.connection.callbacks.process.call_args_list[0][0][ 4] self.assertIs(type(conn_exc), exceptions.IncompatibleProtocolError) self.assertSequenceEqual(conn_exc.args, [1, 'error text']) self.connection.callbacks.process.assert_any_call( 0, self.connection.ON_CONNECTION_CLOSED, self.connection, self.connection, 1, 'error text') def test_on_terminate_invokes_auth_on_connection_error_and_closed(self): """_on_terminate invokes `ON_CONNECTION_ERROR` with \ `ProbableAuthenticationError` and `ON_CONNECTION_CLOSED` callbacks""" with mock.patch.object(self.connection.callbacks, 'process'): self.connection._adapter_disconnect = mock.Mock() self.connection._set_connection_state( self.connection.CONNECTION_START) self.connection._on_terminate(1, 'error text') self.assertEqual(self.connection.callbacks.process.call_count, 2) self.connection.callbacks.process.assert_any_call( 0, self.connection.ON_CONNECTION_ERROR, self.connection, self.connection, mock.ANY) conn_exc = self.connection.callbacks.process.call_args_list[0][0][ 4] self.assertIs( type(conn_exc), exceptions.ProbableAuthenticationError) self.assertSequenceEqual(conn_exc.args, [1, 'error text']) self.connection.callbacks.process.assert_any_call( 0, self.connection.ON_CONNECTION_CLOSED, self.connection, self.connection, 1, 'error text') def test_on_terminate_invokes_access_denied_on_connection_error_and_closed( self): """_on_terminate invokes `ON_CONNECTION_ERROR` with \ `ProbableAccessDeniedError` and `ON_CONNECTION_CLOSED` callbacks""" with mock.patch.object(self.connection.callbacks, 'process'): self.connection._adapter_disconnect = mock.Mock() self.connection._set_connection_state( self.connection.CONNECTION_TUNE) self.connection._on_terminate(1, 'error text') self.assertEqual(self.connection.callbacks.process.call_count, 2) self.connection.callbacks.process.assert_any_call( 0, self.connection.ON_CONNECTION_ERROR, self.connection, self.connection, mock.ANY) conn_exc = self.connection.callbacks.process.call_args_list[0][0][ 4] self.assertIs(type(conn_exc), exceptions.ProbableAccessDeniedError) self.assertSequenceEqual(conn_exc.args, [1, 'error text']) self.connection.callbacks.process.assert_any_call( 0, self.connection.ON_CONNECTION_CLOSED, self.connection, self.connection, 1, 'error text') @mock.patch('pika.connection.Connection.connect') def test_new_conn_should_use_first_channel(self, connect): """_next_channel_number in new conn should always be 1""" conn = connection.Connection() self.assertEqual(1, conn._next_channel_number()) def test_next_channel_number_returns_lowest_unused(self): """_next_channel_number must return lowest available channel number""" for channel_num in xrange(1, 50): self.connection._channels[channel_num] = True expectation = random.randint(5, 49) del self.connection._channels[expectation] self.assertEqual(self.connection._next_channel_number(), expectation) def test_add_callbacks(self): """make sure the callback adding works""" self.connection.callbacks = mock.Mock(spec=self.connection.callbacks) for test_method, expected_key in ( (self.connection.add_backpressure_callback, self.connection.ON_CONNECTION_BACKPRESSURE), (self.connection.add_on_open_callback, self.connection.ON_CONNECTION_OPEN), (self.connection.add_on_close_callback, self.connection.ON_CONNECTION_CLOSED)): self.connection.callbacks.reset_mock() test_method(callback_method) self.connection.callbacks.add.assert_called_once_with( 0, expected_key, callback_method, False) def test_add_on_close_callback(self): """make sure the add on close callback is added""" self.connection.callbacks = mock.Mock(spec=self.connection.callbacks) self.connection.add_on_open_callback(callback_method) self.connection.callbacks.add.assert_called_once_with( 0, self.connection.ON_CONNECTION_OPEN, callback_method, False) def test_add_on_open_error_callback(self): """make sure the add on open error callback is added""" self.connection.callbacks = mock.Mock(spec=self.connection.callbacks) #Test with remove default first (also checks default is True) self.connection.add_on_open_error_callback(callback_method) self.connection.callbacks.remove.assert_called_once_with( 0, self.connection.ON_CONNECTION_ERROR, self.connection._on_connection_error) self.connection.callbacks.add.assert_called_once_with( 0, self.connection.ON_CONNECTION_ERROR, callback_method, False) def test_channel(self): """test the channel method""" self.connection._next_channel_number = mock.Mock(return_value=42) test_channel = mock.Mock(spec=channel.Channel) self.connection._create_channel = mock.Mock(return_value=test_channel) self.connection._add_channel_callbacks = mock.Mock() ret_channel = self.connection.channel(callback_method) self.assertEqual(test_channel, ret_channel) self.connection._create_channel.assert_called_once_with( 42, callback_method) self.connection._add_channel_callbacks.assert_called_once_with(42) test_channel.open.assert_called_once_with() def test_channel_on_closed_connection_raises_connection_closed(self): self.connection.connection_state = self.connection.CONNECTION_CLOSED with self.assertRaises(exceptions.ConnectionClosed): self.connection.channel(lambda *args: None) def test_channel_on_closing_connection_raises_connection_closed(self): self.connection.connection_state = self.connection.CONNECTION_CLOSING with self.assertRaises(exceptions.ConnectionClosed): self.connection.channel(lambda *args: None) def test_channel_on_init_connection_raises_connection_closed(self): self.connection.connection_state = self.connection.CONNECTION_INIT with self.assertRaises(exceptions.ConnectionClosed): self.connection.channel(lambda *args: None) def test_channel_on_start_connection_raises_connection_closed(self): self.connection.connection_state = self.connection.CONNECTION_START with self.assertRaises(exceptions.ConnectionClosed): self.connection.channel(lambda *args: None) def test_channel_on_protocol_connection_raises_connection_closed(self): self.connection.connection_state = self.connection.CONNECTION_PROTOCOL with self.assertRaises(exceptions.ConnectionClosed): self.connection.channel(lambda *args: None) def test_channel_on_tune_connection_raises_connection_closed(self): self.connection.connection_state = self.connection.CONNECTION_TUNE with self.assertRaises(exceptions.ConnectionClosed): self.connection.channel(lambda *args: None) def test_connect_no_adapter_connect_from_constructor(self): """check that adapter connection with AMQP is not happening in constructor """ with mock.patch( 'pika.connection.Connection._adapter_connect', return_value=Exception( '_adapter_connect failed')) as adapter_connect_mock: with mock.patch( 'pika.connection.Connection.add_timeout', return_value='timer') as add_timeout_mock: conn = connection.Connection() self.assertFalse(adapter_connect_mock.called) self.assertEqual(conn.connection_state, conn.CONNECTION_INIT) self.assertIsNotNone(conn._connection_attempt_timer) add_timeout_mock.assert_called_once_with( 0, conn._on_connect_timer) def test_client_properties(self): """make sure client properties has some important keys""" client_props = self.connection._client_properties self.assertTrue(isinstance(client_props, dict)) for required_key in ('product', 'platform', 'capabilities', 'information', 'version'): self.assertTrue(required_key in client_props, '%s missing' % required_key) def test_client_properties_default(self): expectation = { 'product': connection.PRODUCT, 'platform': 'Python %s' % platform.python_version(), 'capabilities': { 'authentication_failure_close': True, 'basic.nack': True, 'connection.blocked': True, 'consumer_cancel_notify': True, 'publisher_confirms': True }, 'information': 'See http://pika.rtfd.org', 'version': pika.__version__ } self.assertDictEqual(self.connection._client_properties, expectation) def test_client_properties_override(self): expectation = { 'capabilities': { 'authentication_failure_close': True, 'basic.nack': True, 'connection.blocked': True, 'consumer_cancel_notify': True, 'publisher_confirms': True } } override = { 'product': 'My Product', 'platform': 'Your platform', 'version': '0.1', 'information': 'this is my app' } expectation.update(override) params = connection.ConnectionParameters(client_properties=override) with mock.patch('pika.connection.Connection.connect'): conn = connection.Connection(params) self.assertDictEqual(conn._client_properties, expectation) def test_set_backpressure_multiplier(self): """test setting the backpressure multiplier""" self.connection._backpressure_multiplier = None self.connection.set_backpressure_multiplier(value=5) self.assertEqual(5, self.connection._backpressure_multiplier) def test_close_channels(self): """test closing all channels""" self.connection.connection_state = self.connection.CONNECTION_OPEN self.connection.callbacks = mock.Mock(spec=self.connection.callbacks) opening_channel = mock.Mock( is_open=False, is_closed=False, is_closing=False) open_channel = mock.Mock( is_open=True, is_closed=False, is_closing=False) closing_channel = mock.Mock( is_open=False, is_closed=False, is_closing=True) self.connection._channels = { 'openingc': opening_channel, 'openc': open_channel, 'closingc': closing_channel } self.connection._close_channels(400, 'reply text') opening_channel.close.assert_called_once_with(400, 'reply text') open_channel.close.assert_called_once_with(400, 'reply text') self.assertFalse(closing_channel.close.called) self.assertTrue('openingc' in self.connection._channels) self.assertTrue('openc' in self.connection._channels) self.assertTrue('closingc' in self.connection._channels) self.assertFalse(self.connection.callbacks.cleanup.called) # Test on closed connection self.connection.connection_state = self.connection.CONNECTION_CLOSED with self.assertRaises(AssertionError): self.connection._close_channels(200, 'reply text') @mock.patch('pika.frame.ProtocolHeader') def test_on_connect_timer(self, frame_protocol_header): """make sure the connect method sets the state and sends a frame""" self.connection.connection_state = self.connection.CONNECTION_INIT self.connection._adapter_connect = mock.Mock(return_value=None) self.connection._send_frame = mock.Mock() frame_protocol_header.spec = frame.ProtocolHeader frame_protocol_header.return_value = 'frame object' self.connection._on_connect_timer() self.assertEqual(self.connection.CONNECTION_PROTOCOL, self.connection.connection_state) self.connection._send_frame.assert_called_once_with('frame object') def test_on_connect_timer_reconnect(self): """try the different reconnect logic, check state & other class vars""" self.connection.connection_state = self.connection.CONNECTION_INIT self.connection._adapter_connect = mock.Mock(return_value='error') self.connection.callbacks = mock.Mock(spec=self.connection.callbacks) self.connection.remaining_connection_attempts = 2 self.connection.params.retry_delay = 555 self.connection.params.connection_attempts = 99 self.connection.add_timeout = mock.Mock() #first failure self.connection._on_connect_timer() self.connection.add_timeout.assert_called_once_with( 555, self.connection._on_connect_timer) self.assertEqual(1, self.connection.remaining_connection_attempts) self.assertFalse(self.connection.callbacks.process.called) self.assertEqual(self.connection.CONNECTION_INIT, self.connection.connection_state) #fail with no attempts remaining self.connection.add_timeout.reset_mock() self.connection._on_connect_timer() self.assertFalse(self.connection.add_timeout.called) self.assertEqual(99, self.connection.remaining_connection_attempts) self.connection.callbacks.process.assert_called_once_with( 0, self.connection.ON_CONNECTION_ERROR, self.connection, self.connection, 'error') self.assertEqual(self.connection.CONNECTION_CLOSED, self.connection.connection_state) def test_on_connection_start(self): """make sure starting a connection sets the correct class vars""" method_frame = mock.Mock() method_frame.method = mock.Mock() method_frame.method.mechanisms = str(credentials.PlainCredentials.TYPE) method_frame.method.version_major = 0 method_frame.method.version_minor = 9 #This may be incorrectly mocked, or the code is wrong #TODO: Code does hasattr check, should this be a has_key/in check? method_frame.method.server_properties = { 'capabilities': { 'basic.nack': True, 'consumer_cancel_notify': False, 'exchange_exchange_bindings': False } } #This will be called, but shoudl not be implmented here, just mock it self.connection._flush_outbound = mock.Mock() self.connection._on_connection_start(method_frame) self.assertEqual(True, self.connection.basic_nack) self.assertEqual(False, self.connection.consumer_cancel_notify) self.assertEqual(False, self.connection.exchange_exchange_bindings) self.assertEqual(False, self.connection.publisher_confirms) @mock.patch('pika.heartbeat.HeartbeatChecker') @mock.patch('pika.frame.Method') def test_on_connection_tune(self, method, heartbeat_checker): """make sure on connection tune turns the connection params""" heartbeat_checker.return_value = 'hearbeat obj' self.connection._flush_outbound = mock.Mock() marshal = mock.Mock(return_value='ab') method.return_value = mock.Mock(marshal=marshal) #may be good to test this here, but i don't want to test too much self.connection._rpc = mock.Mock() method_frame = mock.Mock() method_frame.method = mock.Mock() method_frame.method.channel_max = 40 method_frame.method.frame_max = 10000 method_frame.method.heartbeat = 10 self.connection.params.channel_max = 20 self.connection.params.frame_max = 20000 self.connection.params.heartbeat = 20 #Test self.connection._on_connection_tune(method_frame) #verfy self.assertEqual(self.connection.CONNECTION_TUNE, self.connection.connection_state) self.assertEqual(20, self.connection.params.channel_max) self.assertEqual(10000, self.connection.params.frame_max) self.assertEqual(20, self.connection.params.heartbeat) self.assertEqual(9992, self.connection._body_max_length) heartbeat_checker.assert_called_once_with(self.connection, 20) self.assertEqual(['ab'], list(self.connection.outbound_buffer)) self.assertEqual('hearbeat obj', self.connection.heartbeat) # Pika gives precendence to client heartbeat values if set # See pika/pika#965. # Both client and server values set. Pick client value method_frame.method.heartbeat = 60 self.connection.params.heartbeat = 20 #Test self.connection._on_connection_tune(method_frame) #verfy self.assertEqual(20, self.connection.params.heartbeat) # Client value is None, use the server's method_frame.method.heartbeat = 500 self.connection.params.heartbeat = None #Test self.connection._on_connection_tune(method_frame) #verfy self.assertEqual(500, self.connection.params.heartbeat) # Client value is 0, use it method_frame.method.heartbeat = 60 self.connection.params.heartbeat = 0 #Test self.connection._on_connection_tune(method_frame) #verfy self.assertEqual(0, self.connection.params.heartbeat) # Server value is 0, client value is None method_frame.method.heartbeat = 0 self.connection.params.heartbeat = None #Test self.connection._on_connection_tune(method_frame) #verfy self.assertEqual(0, self.connection.params.heartbeat) # Both client and server values are 0 method_frame.method.heartbeat = 0 self.connection.params.heartbeat = 0 #Test self.connection._on_connection_tune(method_frame) #verfy self.assertEqual(0, self.connection.params.heartbeat) # Server value is 0, use the client's method_frame.method.heartbeat = 0 self.connection.params.heartbeat = 60 #Test self.connection._on_connection_tune(method_frame) #verfy self.assertEqual(60, self.connection.params.heartbeat) # Server value is 10, client passes a heartbeat function that # chooses max(servervalue,60). Pick 60 def choose_max(conn, val): self.assertIs(conn, self.connection) self.assertEqual(val, 10) return max(val, 60) method_frame.method.heartbeat = 10 self.connection.params.heartbeat = choose_max #Test self.connection._on_connection_tune(method_frame) #verfy self.assertEqual(60, self.connection.params.heartbeat) def test_on_connection_closed(self): """make sure connection close sends correct frames""" method_frame = mock.Mock() method_frame.method = mock.Mock(spec=spec.Connection.Close) method_frame.method.reply_code = 1 method_frame.method.reply_text = 'hello' self.connection._on_terminate = mock.Mock() self.connection._on_connection_close(method_frame) #Check self.connection._on_terminate.assert_called_once_with(1, 'hello') def test_on_connection_close_ok(self): """make sure _on_connection_close_ok terminates connection""" method_frame = mock.Mock() method_frame.method = mock.Mock(spec=spec.Connection.CloseOk) self.connection.closing = (1, 'bye') self.connection._on_terminate = mock.Mock() self.connection._on_connection_close_ok(method_frame) #Check self.connection._on_terminate.assert_called_once_with(1, 'bye') @mock.patch('pika.frame.decode_frame') def test_on_data_available(self, decode_frame): """test on data available and process frame""" data_in = ['data'] self.connection._frame_buffer = ['old_data'] for frame_type in (frame.Method, spec.Basic.Deliver, frame.Heartbeat): frame_value = mock.Mock(spec=frame_type) frame_value.frame_type = 2 frame_value.method = 2 frame_value.channel_number = 1 self.connection.bytes_received = 0 self.connection.heartbeat = mock.Mock() self.connection.frames_received = 0 decode_frame.return_value = (2, frame_value) self.connection._on_data_available(data_in) #test value self.assertListEqual([], self.connection._frame_buffer) self.assertEqual(2, self.connection.bytes_received) self.assertEqual(1, self.connection.frames_received) if frame_type == frame.Heartbeat: self.assertTrue(self.connection.heartbeat.received.called) @mock.patch.object( connection.Connection, 'connect', spec_set=connection.Connection.connect) @mock.patch.object(connection.Connection, 'add_on_connection_blocked_callback') @mock.patch.object(connection.Connection, 'add_on_connection_unblocked_callback') def test_create_with_blocked_connection_timeout_config( self, add_on_unblocked_callback_mock, add_on_blocked_callback_mock, connect_mock): conn = connection.Connection( parameters=connection.ConnectionParameters( blocked_connection_timeout=60)) # Check conn.add_on_connection_blocked_callback.assert_called_once_with( conn._on_connection_blocked) conn.add_on_connection_unblocked_callback.assert_called_once_with( conn._on_connection_unblocked) @mock.patch.object(connection.Connection, 'add_timeout') @mock.patch.object( connection.Connection, 'connect', spec_set=connection.Connection.connect) def test_connection_blocked_sets_timer(self, connect_mock, add_timeout_mock): conn = connection.Connection( parameters=connection.ConnectionParameters( blocked_connection_timeout=60)) conn._on_connection_blocked( mock.Mock(name='frame.Method(Connection.Blocked)')) # Check conn.add_timeout.assert_called_once_with( 60, conn._on_blocked_connection_timeout) self.assertIsNotNone(conn._blocked_conn_timer) @mock.patch.object(connection.Connection, 'add_timeout') @mock.patch.object( connection.Connection, 'connect', spec_set=connection.Connection.connect) def test_blocked_connection_multiple_blocked_in_a_row_sets_timer_once( self, connect_mock, add_timeout_mock): conn = connection.Connection( parameters=connection.ConnectionParameters( blocked_connection_timeout=60)) # Simulate Connection.Blocked trigger conn._on_connection_blocked( mock.Mock(name='frame.Method(Connection.Blocked)')) # Check conn.add_timeout.assert_called_once_with( 60, conn._on_blocked_connection_timeout) self.assertIsNotNone(conn._blocked_conn_timer) timer = conn._blocked_conn_timer # Simulate Connection.Blocked trigger again conn._on_connection_blocked( mock.Mock(name='frame.Method(Connection.Blocked)')) self.assertEqual(conn.add_timeout.call_count, 1) self.assertIs(conn._blocked_conn_timer, timer) @mock.patch.object(connection.Connection, '_on_terminate') @mock.patch.object( connection.Connection, 'add_timeout', spec_set=connection.Connection.add_timeout) @mock.patch.object( connection.Connection, 'connect', spec_set=connection.Connection.connect) def test_blocked_connection_timeout_teminates_connection( self, connect_mock, add_timeout_mock, on_terminate_mock): conn = connection.Connection( parameters=connection.ConnectionParameters( blocked_connection_timeout=60)) conn._on_connection_blocked( mock.Mock(name='frame.Method(Connection.Blocked)')) conn._on_blocked_connection_timeout() # Check conn._on_terminate.assert_called_once_with( connection.InternalCloseReasons.BLOCKED_CONNECTION_TIMEOUT, 'Blocked connection timeout expired') self.assertIsNone(conn._blocked_conn_timer) @mock.patch.object(connection.Connection, 'remove_timeout') @mock.patch.object( connection.Connection, 'add_timeout', spec_set=connection.Connection.add_timeout) @mock.patch.object( connection.Connection, 'connect', spec_set=connection.Connection.connect) def test_blocked_connection_unblocked_removes_timer( self, connect_mock, add_timeout_mock, remove_timeout_mock): conn = connection.Connection( parameters=connection.ConnectionParameters( blocked_connection_timeout=60)) conn._on_connection_blocked( mock.Mock(name='frame.Method(Connection.Blocked)')) self.assertIsNotNone(conn._blocked_conn_timer) timer = conn._blocked_conn_timer conn._on_connection_unblocked( mock.Mock(name='frame.Method(Connection.Unblocked)')) # Check conn.remove_timeout.assert_called_once_with(timer) self.assertIsNone(conn._blocked_conn_timer) @mock.patch.object(connection.Connection, 'remove_timeout') @mock.patch.object( connection.Connection, 'add_timeout', spec_set=connection.Connection.add_timeout) @mock.patch.object( connection.Connection, 'connect', spec_set=connection.Connection.connect) def test_blocked_connection_multiple_unblocked_in_a_row_removes_timer_once( self, connect_mock, add_timeout_mock, remove_timeout_mock): conn = connection.Connection( parameters=connection.ConnectionParameters( blocked_connection_timeout=60)) # Simulate Connection.Blocked conn._on_connection_blocked( mock.Mock(name='frame.Method(Connection.Blocked)')) self.assertIsNotNone(conn._blocked_conn_timer) timer = conn._blocked_conn_timer # Simulate Connection.Unblocked conn._on_connection_unblocked( mock.Mock(name='frame.Method(Connection.Unblocked)')) # Check conn.remove_timeout.assert_called_once_with(timer) self.assertIsNone(conn._blocked_conn_timer) # Simulate Connection.Unblocked again conn._on_connection_unblocked( mock.Mock(name='frame.Method(Connection.Unblocked)')) self.assertEqual(conn.remove_timeout.call_count, 1) self.assertIsNone(conn._blocked_conn_timer) @mock.patch.object(connection.Connection, 'remove_timeout') @mock.patch.object( connection.Connection, 'add_timeout', spec_set=connection.Connection.add_timeout) @mock.patch.object( connection.Connection, 'connect', spec_set=connection.Connection.connect) @mock.patch.object( connection.Connection, '_adapter_disconnect', spec_set=connection.Connection._adapter_disconnect) def test_blocked_connection_on_terminate_removes_timer( self, adapter_disconnect_mock, connect_mock, add_timeout_mock, remove_timeout_mock): conn = connection.Connection( parameters=connection.ConnectionParameters( blocked_connection_timeout=60)) conn._on_connection_blocked( mock.Mock(name='frame.Method(Connection.Blocked)')) self.assertIsNotNone(conn._blocked_conn_timer) timer = conn._blocked_conn_timer conn._on_terminate(0, 'test_on_terminate_removes_timer') # Check conn.remove_timeout.assert_called_once_with(timer) self.assertIsNone(conn._blocked_conn_timer) def test_send_message_updates_frames_sent_and_bytes_sent(self): self.connection._flush_outbound = mock.Mock() self.connection._body_max_length = 10000 method = spec.Basic.Publish( exchange='my-exchange', routing_key='my-route') props = spec.BasicProperties() body = b'b' * 1000000 self.connection._send_method( channel_number=1, method=method, content=(props, body)) frames_sent = len(self.connection.outbound_buffer) bytes_sent = sum( len(frame) for frame in self.connection.outbound_buffer) self.assertEqual(self.connection.frames_sent, frames_sent) self.assertEqual(self.connection.bytes_sent, bytes_sent) # Make sure _detect_backpressure doesn't throw self.connection._detect_backpressure()