Quantcast
Channel: Active questions tagged python - Stack Overflow
Viewing all articles
Browse latest Browse all 23276

Python unit testing: function patch does not get applied to consumer that runs in a separate thread

$
0
0

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.text

My 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.


Viewing all articles
Browse latest Browse all 23276

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>