Catch2: Problem with event content in tests
When using events in test context the event content (attribute value and quality) is not set properly.
This does not happen when running the server and client outside the test framework, even in -nodb
mode.
Below a test scenario which demonstrates the issue with change events:
Click to expand
#include <tango/tango.h>
#include <memory>
#include "utils/utils.h"
static constexpr double ATTR_INIT_VALUE = 0.0;
static constexpr double ATTR_NEW_VALUE = 1.0;
// Test device class
template <class Base>
class ChangeEventDev : public Base
{
public:
using Base::Base;
~ChangeEventDev() override { }
void init_device() override
{
attr_value = ATTR_INIT_VALUE;
}
void read_attribute(Tango::Attribute &att)
{
att.set_value_date_quality(&attr_value, std::chrono::system_clock::now(), Tango::ATTR_VALID);
}
void write_attribute(Tango::WAttribute &att)
{
att.get_write_value(attr_value);
}
static void attribute_factory(std::vector<Tango::Attr *> &attrs)
{
auto test_attr = new TangoTest::AutoAttr<
&ChangeEventDev::read_attribute,
&ChangeEventDev::write_attribute
>("attr_test", Tango::DEV_DOUBLE);
Tango::UserDefaultAttrProp props;
props.set_event_abs_change("0.0001");
test_attr->set_default_properties(props);
test_attr->set_polling_period(100);
attrs.push_back(test_attr);
}
private:
Tango::DevDouble attr_value;
};
// Test event callback which can test certain things about last received event
class EvCb : public Tango::CallBack
{
public:
EvCb() : event_received(false)
{
}
void push_event(Tango::EventData* ev)
{
event_received = true;
last_event_type = ev->event;
*(ev->attr_value) >> last_event_value;
last_event_quality = ev->attr_value->quality;
std::cout << "push: event_received=" << event_received << "; last_event_type=" << last_event_type <<
"; last_event_value=" << last_event_value << "; last_event_quality=" << last_event_quality << "\n";
}
bool test_last_event(std::string expected_event_type, Tango::DevDouble expected_value, Tango::AttrQuality expected_quality)
{
std::cout << "test: event_received=" << event_received << "; last_event_type=" << last_event_type <<
"; last_event_value=" << last_event_value << "; last_event_quality=" << last_event_quality << "\n";
if(event_received)
{
if(
last_event_type == expected_event_type &&
last_event_value == expected_value &&
last_event_quality == expected_quality
)
{
event_received = false;
return true;
}
}
return false;
}
private:
bool event_received;
std::string last_event_type;
Tango::DevDouble last_event_value;
Tango::AttrQuality last_event_quality;
};
TANGO_TEST_AUTO_DEV_TMPL_INSTANTIATE(ChangeEventDev, 4)
SCENARIO("Change events are sent and received")
{
int idlver = GENERATE(range(4, 7));
GIVEN("a device proxy to a simple IDLv" << idlver << " device")
{
TangoTest::Context ctx{"change_event", "ChangeEventDev", idlver};
INFO(ctx.info());
auto device = ctx.get_proxy();
REQUIRE(idlver == device->get_idl_version());
AND_GIVEN("a polled attribute name")
{
std::string att{"attr_test"};
REQUIRE(device->is_attribute_polled(att) == true);
AND_GIVEN("a change event subscription")
{
EvCb callback;
int evid;
REQUIRE_NOTHROW(evid = device->subscribe_event(att, Tango::CHANGE_EVENT, &callback));
WHEN("we set the new attribute value")
{
Tango::DeviceAttribute v;
v.set_name(att);
v << ATTR_NEW_VALUE;
REQUIRE_NOTHROW(device->write_attribute(v));
THEN("a change event is generated")
{
REQUIRE(callback.test_last_event("change", ATTR_NEW_VALUE, Tango::ATTR_VALID));
}
}
}
}
}
}
I've done tests outside of the test framework using the following client code (you will need to adjust the device path):
Click to expand
#include <iostream>
#include <tango.h>
class EvCb : public Tango::CallBack
{
public:
EvCb() : event_received(false)
{
}
void push_event(Tango::EventData* ev)
{
event_received = true;
last_event_type = ev->event;
*(ev->attr_value) >> last_event_value;
last_event_quality = ev->attr_value->quality;
std::cout << "push_event: event_received=" << event_received << "; last_event_type=" << last_event_type <<
"; last_event_value=" << last_event_value << "; last_event_quality=" << last_event_quality << "\n";
}
bool test_last_event(std::string expected_event_type, Tango::DevDouble expected_value, Tango::AttrQuality expected_quality)
{
std::cout << "test: event_received=" << event_received << "; last_event_type=" << last_event_type <<
"; last_event_value=" << last_event_value << "; last_event_quality=" << last_event_quality << "\n";
if(event_received)
{
if(
last_event_type == expected_event_type &&
last_event_value == expected_value &&
last_event_quality == expected_quality
)
{
event_received = false;
return true;
}
}
return false;
}
private:
bool event_received;
std::string last_event_type;
Tango::DevDouble last_event_value;
Tango::AttrQuality last_event_quality;
};
int main(void)
{
try {
Tango::DeviceProxy dp("tango://vm203-tango-dev:20000/test/ds/123#dbase=no");
EvCb callback;
dp.subscribe_event("MaxSRCurrent", Tango::CHANGE_EVENT, &callback);
char q;
std::cin >> q;
return 0;
} catch(Tango::DevFailed &e) {
std::cout << e;
return 1;
}
}
and this DS from Reynald.