def test_connect_success(monkeypatch): # Test if connect reports connection success mock_connection(monkeypatch, connection_success=True) connection = AsyncConnection(connection_params) assert (connection.connect() is True) connection.disconnect()
def test_publish_failure(monkeypatch): # Test publish failure mock_connection(monkeypatch, connection_success=True) connection = AsyncConnection(connection_params) queue = {"name": "name", "key": "key"} with pytest.raises(Exception): connection.publish(queue, "key", "message")
def test_connect_callback_failure(monkeypatch): # Test if connect does not call callback on failure mock_connection(monkeypatch, connection_success=False) global on_connect_called connection = AsyncConnection(connection_params) assert (not on_connect_called) connection.connect(on_connect) assert (not on_connect_called)
def test_on_message(self): global return_message # setup mocks and fixtures mocked_handler = mock.Mock(wraps=handler) service = fixtures.get_service_fixture(mocked_handler) single_service = [v for v in service.values()][0] message = {} queue = {'name': single_service['queue']} key = {'name': single_service['key']} connection = AsyncConnection({}) # setup expectations return_message = fixtures.random_string() return_queue = single_service['report'] with mock.patch.object(connection, "publish") as mocked_publish: # on_message = messagedriven_service._get_on_message(single_service) result = messagedriven_service._on_message(connection, single_service, message) # The result should be True self.assertTrue(result) # The message handler should be called with the message mocked_handler.assert_called_with(message) # The return message should be published on the return queue mocked_publish.assert_called_with(return_queue, return_queue['key'], return_message)
def test_publish(monkeypatch): # Test publish message mock_connection(monkeypatch, connection_success=True) connection = AsyncConnection(connection_params) connection.connect() queue = {"exchange": "exchange", "name": "name", "key": "key"} connection.publish(queue, "key", "message") assert (published_message == json.dumps("message")) connection.disconnect()
def test_connect_context_manager(monkeypatch): # Test if context manager calls disconnect on exit with statement mock_connection(monkeypatch, connection_success=True) org_connection = None with patch.object(AsyncConnection, 'disconnect') as mocked_disconnect: with AsyncConnection(connection_params) as connection: org_connection = connection # save to call the real disconnect afterwards pass assert (mocked_disconnect.called) org_connection.disconnect() # Call the real disconnect
def _listen(self, queues: list): with AsyncConnection(CONNECTION_PARAMS, self.params) as connection: # Subscribe to the queues, handle messages in the on_message function (runs in another thread) connection.subscribe(queues, self._on_message) id = ', '.join([queue for queue in queues]) # Repeat forever while self.keep_running and connection.is_alive(): time.sleep(self.check_connection) print(f"Queue connection for {id} stopped.")
def test_connect_callback_success(monkeypatch): # Test if connect calls callback on success mock_connection(monkeypatch, connection_success=True) global on_connect_called assert (not on_connect_called) connection = AsyncConnection(connection_params) connection.connect(on_connect) assert (on_connect_called) connection.disconnect()
def _heartbeat_loop(self): with AsyncConnection(CONNECTION_PARAMS, self.params) as connection: heartbeat = Heartbeat(connection, self.name) n = 0 while self.keep_running and connection.is_alive(): time.sleep(self.check_connection) for thread in self.threads: if not thread['thread'].is_alive(): print("ERROR: died thread found") # Create new thread thread['thread'] = self._start_thread(thread['queues']) n += self.check_connection if n >= self.heartbeat_interval and all([t['thread'].is_alive() for t in self.threads]): heartbeat.send() n = 0
def test_disconnect(): # Test if a disconnect can be called without an earlier connect connection = AsyncConnection('') assert (connection.disconnect() is None)
def publish(exchange, key, msg): with AsyncConnection(CONNECTION_PARAMS) as connection: connection.publish(exchange, key, msg)
def test_connect_failure(monkeypatch): # Test if connect reports failure to connect mock_connection(monkeypatch, connection_success=False) connection = AsyncConnection(connection_params) assert (connection.connect() is False)
def test_subscribe(monkeypatch): # Test subscription and message receipt mock_connection(monkeypatch, connection_success=True) # connection, exchange, queue, key, msg def on_message(self, exchange, queue, key, body): assert (key == "mykey") assert (body == "mybody") connection = AsyncConnection(connection_params) connection.connect() queue = {"exchange": "exchange", "name": "name", "key": "key"} connection.subscribe([queue, queue], on_message) connection.publish(queue, "key", "mybody") assert (consumed_message == "mybody") # connection, exchange, queue, key, msg def on_message_fail(self, exchange, queue, key, body): raise Exception connection.subscribe([queue, queue], on_message_fail) connection.publish(queue, "key", "mybody") assert (consumed_message == "mybody") connection.disconnect()
def test_connection_constructor(): # Test if a connection can be initialized connection = AsyncConnection(connection_params) assert (connection is not None) assert (connection._connection_params == connection_params)
def setUp(self) -> None: self.connection_params = {'connection': 'params'} self.params = {'other': 'params'} self.async_connection = AsyncConnection(self.connection_params, self.params)
class TestAsyncConnection(TestCase): def setUp(self) -> None: self.connection_params = {'connection': 'params'} self.params = {'other': 'params'} self.async_connection = AsyncConnection(self.connection_params, self.params) def test_init(self): self.assertEqual( { 'load_message': True, 'stream_contents': False, 'other': 'params', 'prefetch_count': 1, }, self.async_connection._params) self.assertEqual(self.connection_params, self.async_connection._connection_params) self.assertFalse(self.async_connection._eventloop_failed) def test_enter(self): self.async_connection.connect = MagicMock() self.assertEqual(self.async_connection, self.async_connection.__enter__()) self.async_connection.connect.assert_called_once() def test_exit(self): self.async_connection.disconnect = MagicMock() self.async_connection.__exit__() self.async_connection.disconnect.assert_called_once() def test_is_alive(self): self.assertTrue(self.async_connection.is_alive()) self.async_connection._eventloop_failed = True self.assertFalse(self.async_connection.is_alive()) @patch('builtins.print') @patch("gobcore.message_broker.async_message_broker.threading.Thread") @patch("gobcore.message_broker.async_message_broker.os._exit") def test_on_message_redeliver(self, mock_os_exit, mock_thread, mock_print): msg = {'some': 'message'} message_handler = MagicMock() message_handler.side_effect = Exception on_message = self.async_connection.on_message('some queue', message_handler) channel = MagicMock() basic_deliver = MagicMock() properties = {} basic_deliver.redelivered = False on_message(channel, basic_deliver, properties, json.dumps(msg)) thread_target = mock_thread.call_args[1]['target'] thread_target() mock_os_exit.assert_called_with(os.EX_TEMPFAIL) print_msg = mock_print.call_args[0][0] self.assertEqual(print_msg, 'Message handling has failed, terminating program') basic_deliver.redelivered = True on_message(channel, basic_deliver, properties, json.dumps(msg)) thread_target = mock_thread.call_args[1]['target'] thread_target() print_msg = mock_print.call_args[0][0] self.assertTrue( print_msg.startswith('Message handling has failed on second try')) @patch('builtins.print') @patch("gobcore.message_broker.async_message_broker.threading.Thread") def test_on_message_nack(self, mock_thread, mock_print): msg = {'some': 'message'} message_handler = MagicMock(return_value=False) on_message = self.async_connection.on_message('some queue', message_handler) channel = MagicMock() basic_deliver = MagicMock() on_message(channel, basic_deliver, {}, json.dumps(msg)) thread_target = mock_thread.call_args[1]['target'] thread_target() print_msg = mock_print.call_args[0][0] self.assertEqual(print_msg, "Message not acknowlegded, discarding message")
def publish(queue_name, key, msg): with AsyncConnection(CONNECTION_PARAMS) as connection: connection.publish(get_queue(queue_name), key, msg)
def test_idempotent_disconnect(): # Test disconnect repeated execution connection = AsyncConnection('') assert (connection.disconnect() is None) assert (connection.disconnect() is None)
def messagedriven_service(services, name, params={}): """Start a connection with a the message broker and the given definition servicedefenition is a dict of dicts: ``` SERVICEDEFINITION = { 'unique_key': { 'exchange': 'name_of_the_exchange_to_listen_to', 'queue': 'name_of_the_queue_to_listen_to', 'key': 'name_of_the_key_to_listen_to' 'handler': 'method_to_invoke_on_message', # optional report functionality 'report': { 'exchange': 'name_of_the_exchange_to_report_to', 'queue': 'name_of_the_queue_to_report_to', 'key': 'name_of_the_key_to_report_to' } } } ``` start the service with: ``` from gobcore.message_broker.messagedriven_service import messagedriven_service messagedriven_services(SERVICEDEFINITION) """ heartbeat = None def on_message(connection, exchange, queue, key, msg): """Called on every message receipt :param connection: the connection with the message broker :param exchange: the message broker exchange :param queue: the message broker queue :param key: the identification of the message (e.g. fullimport.proposal) :param msg: the contents of the message :return: """ print(f"{key} accepted from {queue}, start handling") service = _get_service(services, exchange, queue, key) result = _on_message(connection, service, msg) return result # Start by initializing the message broker (idempotent) _init() with AsyncConnection(CONNECTION_PARAMS, params) as connection: # Subscribe to the queues, handle messages in the on_message function (runs in another thread) queues = [] for key, service in services.items(): queues.append({ "exchange": service['exchange'], "name": service['queue'], "key": service['key'] }) print(f"Listening to messages {service['key']} on queue {service['queue']}") heartbeat = Heartbeat(connection, name) connection.subscribe(queues, on_message) # Repeat forever print("Queue connection for servicedefinition started") n = 0 while keep_running and connection.is_alive(): time.sleep(CHECK_CONNECTION) n += CHECK_CONNECTION if n >= HEARTBEAT_INTERVAL: heartbeat.send() n = 0 print("Queue connection for servicedefinition has stopped")