I am trying to test a consumer that consumes messages of a queue and creates the corresponding object in salesforce.
To test the consumer I have to start it in a new thread because, it is an infinite loop and otherwise my test would not continue after starting the consumer.
test_consumer.py
class TestRabbitMQ(unittest.TestCase): @patch('src.consumer.add_service_id') @patch('src.xml_parser.get_service_id') def test_rabbitmq_messages(self, add_service_id_mock, get_service_id_mock): with RabbitMqContainer("rabbitmq:3-management", None, secrets.RABBITMQ_USER, secrets.RABBITMQ_PASSWORD) as rabbitmq: get_service_id_mock.return_value = {"crm": "1234" } add_service_id_mock.return_value = {"success": True,"message": "Service ID successfully added." } channel: BlockingChannel = configure_rabbitMQ(rabbitmq) consumer_thread = threading.Thread(target=consumer.main) consumer_thread.daemon = True consumer_thread.start() time.sleep(5) with open('tests/resources/dummy_user.xml', 'r') as file: test_message = file.read() channel.basic_publish(exchange='amq.topic', routing_key='user.frontend', body=test_message) channel.basic_consume(queue='crm', on_message_callback=callback, auto_ack=False) self.assertTrue(channel._consumer_infos) # If consumer_infos is not empty, message was received consumer_thread.join()if __name__ == "__main__": unittest.main()consumer.py
def main(): TEAM = 'crm' # Connect to RabbitMQ credentials = pika.PlainCredentials(secrets.RABBITMQ_USER, secrets.RABBITMQ_PASSWORD) try: connection = pika.BlockingConnection(pika.ConnectionParameters(host=secrets.HOST, port=secrets.PORT, credentials=credentials)) except Exception as e: logger.error(f"Failed to connect to RabbitMQ: {e}") sys.exit(1) channel = connection.channel() channel.queue_declare(queue=TEAM, durable=True) def callback(ch, method, properties, body): xml_string = body xml_string = xml_string.decode().strip() root = ET.fromstring(xml_string) crud_operation = root.find('crud_operation').text logger.info(f"Received a {crud_operation} request for {root.tag}") logger.debug(f"Message: {xml_string}") try: variables = {} match root.tag, crud_operation: case 'user', 'create': read_xml_user(variables, root) payload = write_xml_user(**variables) service_id = add_user(payload) add_service_id(root.find('id').text, service_id, TEAM) ch.basic_ack(delivery_tag=method.delivery_tag) logger.info(f'Processed {crud_operation} request for {root.tag}') log(logger, f"CONSUMER: {root.tag}.{crud_operation}", f"Processed {crud_operation} request for {root.tag}") except Exception as e: ch.basic_nack(delivery_tag=method.delivery_tag, requeue=False) logger.error(f'Failed to process {crud_operation} request for {root.tag}: {e}') log(logger, f"CONSUMER: {root.tag}.{crud_operation}", f"Failed to process {crud_operation} request for {root.tag}: {e}", error='true') channel.basic_consume(queue=TEAM, on_message_callback=callback, auto_ack=False) logger.info("Waiting for messages to receive. To exit press CTRL+C") channel.start_consuming()if __name__ == '__main__': logger = init_logger("__consumer__") try: authenticate() main() except Exception as e: logger.error(f"Failed to start consumer: {e}") sys.exit(1)When I run the test, the code fails when it goes into:
read_xml_user(variables, root)it logs an error stating:
2024-05-16 16:48:00:ERROR:__API__:Failed to process create request for user: HTTPConnectionPool(host='localhost', port=6000): Max retries exceeded with url: /getServiceId (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x000002383E3983B0>: Failed to establish a new connection: [WinError 10061] No connection could be made because the target machine actively refused it'))So it still tries to execute the get_service_id() which is called in xml_parser.py.
which confused me because I specifically patched this function in the test.
xml_parser.py
def read_xml_user(variables, root): for child in root: if child.tag == "routing_key" or child.tag == "crud_operation": continue elif child.tag == "address": for address_field in child: variables[address_field.tag] = address_field.text elif child.tag == "id" or child.tag == "company_id": if (child.text is not None): variables[child.tag] = get_service_id(child.text, TEAM) else: variables[child.tag] = None else: variables[child.tag] = child.textMy theory is that the consumer is being run in a new thread making it so the patches are not applied to the fucntions inside that thread.
As for my question: I can't figure out how to apply the patches to the consumer_thread.