Testing TANGO devices using PyTest
I am writing test cases for TANGO devices using Pytest. I have a few queries about the same.
1. Test TANGO clients
I have two TANGO devices, device A (a client) and device B(a server). Command invoked from device A, internally invokes command of device B and as a result some of the attributes of TANGO device B change.
To test the command of device A, I create a proxy of device B (from test function of device A) and assert with changed attributes of device B. For the test to pass successfully, there is a dependency on Device B to be up and running.
Issue: Since the communication between Device A and Device B may take some time, I get Segmentation fault error. One possibility can be that the assert statement is checked while device B takes time to respond to the change. The error is resolved when the test is run again. I have also tried to add time.sleep(3) statement but still no luck.
I need help on how to overcome the Segmentation Fault issue. Also, how shall I test Device A without depending on Device B?
2. Access device properties inside test_context.py
The Tango Device A uses a device property during it's initialization. Hence, there is a need to supply this device property in order to test Device A.
It is observed that __init__ function in test_context.py takes properties as input. However, while trying below solution, properties for the instance (tango_context) of device is not set. Hence, the device A's initialization is getting failed which result in all the test cases to fail unless we define a default value for each property.
3. Defining attribute properties for Forwarded Attributes
Some attributes of Device B are forwarded on Device A. However, it is mandatory to specify __root_attr attribute property to initialze device A successfully. Without this property, device A goes into Alarm state after initialization.
Is there any way to add attribute property and return test_context of Device A? Also, how to set default value for __root_attr in python?
4. Testing events
Comment on test_client.py says that:
Is there any workaround to enable testing of events and device/attribute configuration through properties?
I understand that it is a long post but any inputs on above queries will be helpful.
That is a lot of questions!
1. You will get a segfault if you are trying to use more than one DeviceTestContext instance in the same test. You have to set process=True to launch them in separate subprocesses instead. See the link to the PyTango PR in the code below.
2. If you are overriding init_device, you need to call the super classes' init_device method first. My example uses the context handler to start the device, but calling start() directly also works.
3. Not sure.
4. The PyTango unit tests include testing of events, so it is possible using the DeviceTestContext, although there are some limitations like a port number has to be specified. See https://github.com/tango-controls/pytango/blob/develop/tests/test_event.py. Maybe the comments in test_client.py are just referring the case where an external device server is launched without using the test context?
(Sorry if code below isn't syntax highlighted - it wasn't in the preview. I used a "code=python" tag)
Thank you for the inputs; really helped us a lot. We are now able to provide property values while running the TANGO device server using DeviceTestContext.
I have few more queries related to the testing the events of TANGO devices!
I will take the example of TANGO device A (client) and TANGO device B (server). Command invoked from device A, internally invokes command of device B and as a result some of the attributes of TANGO device B change. Device A has subscribed change event on the related attributes of device B.
We are able to test change events subscribed by device A (running using DeviceTestContext only if device B is running with a database.
We also tried running device B, without a database (using DeviceTestContext). As suggested, we set process=True to use more than one DeviceTestContext instance in the same test. Following are some issues we faced with this approach:
1. We are not able to test change events subscribed by device A. This is because the polling necessary for sending events was not set for Device B running without a database. How can we set the polling for Device B's attributes in order to test change events? Checked the PyTango APIs, but unable to find set_polling_period() API for read-only attributes.
2. Using process=True while creating DeviceTestContexts of device A and device B, decreases the code coverage (measured using Pytest) significantly. The coverage reduced to 40%, which was 70% when process=False. We are unable to identify why the coverage is reduced in this case and what can be done to stop this reduction.
Thanks and Regards,
Glad I could help.
1. I tried doing this, and it seems to be possible. Hopefully I understood your request correctly. The most import thing to note is that the DeviceContext instantiation must be provided with a port number for the zeromq events mechanism to work. You can see this by looking at the PyTango unit tests: https://github.com/tango-controls/pytango/blob/develop/tests/test_event.py
2. Maybe the coverage is lower because the tool that is measuring the coverage is not aware of the additional processes launched? Maybe you can find one that is multi-process aware.