Testing communication between devices

Hi,

I'm working on the TangoBox-9.2 virtual machine and I upgraded PyTango to the latest version (9.2.6).
I need to test the code of my devices with nose using DeviceTestContext from the tango.test_context module.
Simplyfing my situation, I have two devices, number 1 and number 2; device 1 has a command "TurnOn" that sets both his and device 2 state on ON. The code is something like this:


class Dev1(Device):

	dev2 = "sim/test/dev2"

	def init_device(self):
		self.set_state(PyTango.DevState.OFF)

	@command
	def TurnOn(self):
		self.set_state(PyTango.DevState.ON)
		proxy_dev2 = PyTango.DeviceProxy(self.dev2)
		proxy_dev2.command_inout('TurnOn')


class Dev2(Device):

	def init_device(self):
		self.set_state(PyTango.DevState.OFF)

	@command
	def TurnOn(self):
		self.set_state(PyTango.DevState.ON)


The test I wrote is this:

from Dev1 import Dev1
from Dev2 import Dev2
from tango.test_context import DeviceTestContext
import PyTango


def test_TurnOn():

	dev2_context = DeviceTestContext(Dev2, host="localhost", process=True)
	with dev2_context as dev2_test:

		class Dev1Test(Dev1):
			#overwrite dev2 to get access to the test device
			dev2 = dev2_context.get_device_access()

		dev1_context = DeviceTestContext(Dev1Test, host="localhost", process=True)
		with dev1_context as dev1_test:
			dev1_test.TurnOn()
			assert dev1_test.State() == PyTango.DevState.ON
			assert dev2_test.State() == PyTango.DevState.ON

If I run nose on this test everything works fine. But I'd like to set the DeviceProxy as global variable on device 1, like this:


class Dev1(Device):

	dev2 = PyTango.DeviceProxy("sim/test/dev2")

	def init_device(self):
		self.set_state(PyTango.DevState.OFF)

	@command
	def TurnOn(self):
		self.set_state(PyTango.DevState.ON)
		self.dev2.command_inout('TurnOn')

so if I need to use the DeviceProxy in another command I didn't have to create another one.
Well, in this case the same test (with the variable dev1 as a DeviceProxy in the Dev1Test class) doesn't work anymore.
It gives me this error if the device "sim/test/dev2" isn't registered: error reg.png

And, if the device is registered, the DeviceTestContext doesn't start: error start.png

The same thing happens using the older tango.test_context module from PyTango 9.2.1.

Is this a normal behaviour or some kind of bug? Am I missing something?
Sorry for the long post but I wanted to try to be as clear as possible.
Thanks to everyone who wants to help me.

Regards

Maurizio

Hi Maurizio,

The error in error_reg.png says:

device sim/test/dev_not_in_db is not registered in the database !

This has nothing to do with the code you shared with us since there no line like:
dev2 = PyTango.DeviceProxy("sim/test/dev_not_in_db")

in the code you provided in your forum post.

It looks like sim/test/dev_not_in_db is not defined in the database and looking at its name, this seems to be the purpose of this test.

dev2 = PyTango.DeviceProxy("sim/test/dev_not_in_db")

will always fail if sim/test/dev_not_in_db is not defined in the database, unless you surround this call with try/catch blocks.
Rosenberg's Law: Software is easy to make, except when you want it to do something new.
Corollary: The only software that's worth making is software that does something new.
Hi Reynald, thank you for your answer.

I actually changed the device name in "sim/test/dev_not_in_db" to obtain that error because "sim/test/dev2" is defined in my database. I just wanted to show what happens when someone is in that situation and the device is not registered yet. I'm sorry, I forgot to state that in my post.

My point is: I override dev2 in my test file (in Dev1Test class) so why does the original dev2 affect the behaviour of the test?
DeviceTestContext creates new devices with new names (and without the database) to test the code so I thought it shouldn't matter if the original device was registered or not yet. Maybe I'm missing something about the way DeviceTestContext works.
Hi Maurizio

The problem with your second example is that the line dev2 = DeviceProxy("sim/test/dev2") is executed when Python parses the file. You have it as a class variable, so it gets executed using the address "sim/test/dev2". That address doesn't have "#dbase=no" in the address, so the DeviceProxy needs to query the TANGO database. The error is occurring before nosetest even gets a chance to execute your test.

Some suggestions:
- Don't instantiate a DeviceProxy as a class variable. The earliest you could do it is in init_device, and even there isn't great, since that is when dev1 is starting up. If the connection to dev2 failed, then dev1 will also fail to start.
- Rather do "lazy loading" - create the DeviceProxy the first time you need it.
- Rather use a property to tell dev1 what dev2's address is, then you can set it in the TANGO DB, or modify it for your tests.
- The package name PyTango is deprecated - rather use tango.

Example code:

import tango
from tango import DeviceProxy
from tango.server import Device
from tango.server import command, device_property
from tango.test_context import DeviceTestContext


class Dev1(Device):

    dev2_address = device_property(dtype='str',
                                   default_value='sim/test/dev2')

    def init_device(self):
        # important to call super class method for
        # properties to work (and just good practice,
        # base class may do other important things)
        super(Dev1, self).init_device()
        self.set_state(tango.DevState.OFF)
        self.dev2 = None

    @command
    def TurnOn(self):
        self.set_state(tango.DevState.ON)
        if not self.dev2:
            self.dev2 = DeviceProxy(self.dev2_address)
        self.dev2.command_inout('TurnOn')


class Dev2(Device):

    def init_device(self):
        super(Dev2, self).init_device()
        self.set_state(tango.DevState.OFF)

    @command
    def TurnOn(self):
        self.set_state(tango.DevState.ON)


def test_TurnOn():

    dev2_context = DeviceTestContext(Dev2, process=True)
    with dev2_context as dev2_test:

        # get address for dev2 (changes for every test run)
        properties = {'dev2_address': dev2_context.get_device_access()}
        dev1_context = DeviceTestContext(Dev1, process=True,
                                         properties=properties)
        with dev1_context as dev1_test:
            dev1_test.TurnOn()
            assert dev1_test.State() == tango.DevState.ON
            assert dev2_test.State() == tango.DevState.ON

Hi Anton, thank you!
I always thought I was missing something basic and it was so. Your answer and your suggestions solved a lot of my problems and doubts, thank you again!
 
Register or login to create to post a reply.