From a8a8e447fa4f2563870e5a80e0ef45c7e42831fa Mon Sep 17 00:00:00 2001 From: Martin Haefner Date: Sat, 30 Jan 2021 10:13:12 +0100 Subject: [PATCH] Implemented Properties.GetAll support --- CMakeLists.txt | 1 + include/simppl/clientside.h | 4 +- include/simppl/serverside.h | 16 ++- include/simppl/skeletonbase.h | 3 +- include/simppl/stubbase.h | 61 +++++++++- src/clientside.cpp | 10 +- src/holders.cpp | 34 ++++++ src/skeletonbase.cpp | 100 ++++++++++++----- src/stubbase.cpp | 204 ++++++++++++++++++++++------------ tests/properties.cpp | 148 +++++++++++++++++++++++- 10 files changed, 460 insertions(+), 121 deletions(-) create mode 100644 src/holders.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e853cdc..1a603b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,7 @@ add_library(simppl SHARED src/clientside.cpp src/serialization.cpp src/bool.cpp + src/holders.cpp ) # Provide a namespaced alias add_library(Simppl::simppl ALIAS simppl) diff --git a/include/simppl/clientside.h b/include/simppl/clientside.h index b8972e4..00b482c 100644 --- a/include/simppl/clientside.h +++ b/include/simppl/clientside.h @@ -142,8 +142,6 @@ struct ClientPropertyBase StubBase* stub_; eval_type eval_; - - ClientPropertyBase* next_; }; @@ -267,7 +265,7 @@ DataT ClientProperty::get() template ClientProperty& ClientProperty::attach() { - this->stub_->attach_property(*this); + this->stub_->attach_property(this); dbus_pending_call_set_notify(this->stub_->get_property_async(this->name_).pending(), &holder_type::pending_notify, diff --git a/include/simppl/serverside.h b/include/simppl/serverside.h index 9e73778..ea9a220 100644 --- a/include/simppl/serverside.h +++ b/include/simppl/serverside.h @@ -203,14 +203,14 @@ struct ServerMethod : ServerMethodBase struct ServerPropertyBase { - typedef void (*eval_type)(ServerPropertyBase*, DBusMessage*); + typedef void (*eval_type)(ServerPropertyBase*, DBusMessageIter*); typedef void (*eval_set_type)(ServerPropertyBase*, DBusMessageIter&); ServerPropertyBase(const char* name, SkeletonBase* iface, int iface_id); - void eval(DBusMessage* msg) + void eval(DBusMessageIter* iter) { - eval_(this, msg); + return eval_(this, iter); } void evalSet(DBusMessageIter& iter) @@ -258,16 +258,14 @@ struct BaseProperty : ServerPropertyBase } static - void __eval(ServerPropertyBase* obj, DBusMessage* response) + void __eval(ServerPropertyBase* obj, DBusMessageIter* iter) { - DBusMessageIter iter; - dbus_message_iter_init_append(response, &iter); - auto that = ((BaseProperty*)obj); - + // missing initialization? assert(!that->t_.empty()); - detail::PropertyCodec::encode(iter, that->t_.template get() ? (*that->t_.template get())() : *that->t_.template get()); + + detail::PropertyCodec::encode(*iter, that->t_.template get() ? (*that->t_.template get())() : *that->t_.template get()); } void notify(const DataT& data) diff --git a/include/simppl/skeletonbase.h b/include/simppl/skeletonbase.h index 8a059a2..822172f 100644 --- a/include/simppl/skeletonbase.h +++ b/include/simppl/skeletonbase.h @@ -100,10 +100,11 @@ struct SkeletonBase DBusHandlerResult handle_property_set_request(DBusMessage* msg, ServerPropertyBase& property, DBusMessageIter& iter); DBusHandlerResult handle_interface_request(DBusMessage* msg, ServerMethodBase& method); DBusHandlerResult handle_error(DBusMessage* msg, const char* dbus_error); + DBusHandlerResult handle_property_getall_request(DBusMessage* msg, int iface_id); #if SIMPPL_HAVE_INTROSPECTION void introspect_interface(std::ostream& os, size_type index) const; -#endif +#endif bool has_any_properties() const; ServerPropertyBase* find_property(int iface_id, const char* name) const; ServerMethodBase* find_method(int iface_id, const char* name) const; diff --git a/include/simppl/stubbase.h b/include/simppl/stubbase.h index e4bf642..094e876 100644 --- a/include/simppl/stubbase.h +++ b/include/simppl/stubbase.h @@ -10,7 +10,10 @@ #include "simppl/callstate.h" #include "simppl/pendingcall.h" +#include "simppl/variant.h" + #include "simppl/detail/constants.h" +#include "simppl/detail/holders.h" #include "simppl/connectionstate.h" @@ -29,6 +32,8 @@ struct ClientPropertyBase; struct StubBase { + typedef detail::InterimGetAllPropertiesCallbackHolder getall_properties_holder_type; + template friend struct ClientSignal; template friend struct ClientMethod; template friend struct ClientProperty; @@ -36,6 +41,7 @@ struct StubBase friend struct Dispatcher; friend struct ClientPropertyBase; + friend struct detail::GetAllPropertiesHolder; StubBase(const StubBase&) = delete; StubBase& operator=(const StubBase&) = delete; @@ -82,6 +88,30 @@ struct StubBase return busname_; } + /** + * Implementation of org.freedesktop.DBus.Properties.GetAll(). Blocking call. + * + * Before calling this method all Properties callbacks shall be installed. + * The properties callbacks will then be called before this function returns. + * + * Issues a call like this: + * dbus-send --print-reply --dest=test.Properties.s /test/Properties/s org.freedesktop.DBus.Properties.GetAll string:test.Properties + * + * @TODO complete async support + */ + void get_all_properties(); + + /** + * Implementation of org.freedesktop.DBus.Properties.GetAll(). Asynchronous call. + * + * Before calling this method all Properties callbacks shall be installed. You may install + * only some of the property callbacks. If a callback is not registered the property will + * just omitted. + * + * The asynchronous return will arrive as soon as call the property callbacks are evaluated. + */ + getall_properties_holder_type get_all_properties_async(); + protected: @@ -98,8 +128,8 @@ struct StubBase void register_signal(ClientSignalBase& sigbase); void unregister_signal(ClientSignalBase& sigbase); - void attach_property(ClientPropertyBase& prop); - void detach_property(ClientPropertyBase& prop); + void attach_property(ClientPropertyBase* prop); + void detach_property(ClientPropertyBase* prop); /** * Blocking call. @@ -113,8 +143,19 @@ struct StubBase */ void set_property(const char* Name, std::function&& f); + /** + * Just register the property within the stub. + */ + void add_property(ClientPropertyBase* property); + PendingCall set_property_async(const char* Name, std::function&& f); + /** + * Second part of get_all_properties_async. Once the callback arrives + * the property callbacks have to be called. + */ + simppl::dbus::CallState get_all_properties_handle_response(DBusMessage& response); + std::vector ifaces_; char* objectpath_; std::string busname_; @@ -122,8 +163,10 @@ struct StubBase Dispatcher* disp_; - ClientSignalBase* signals_; ///< attached signals - ClientPropertyBase* properties_; ///< attached properties + ClientSignalBase* signals_; ///< attached signals + + std::vector> properties_; ///< all properties TODO maybe take another container... + int attached_properties_; ///< attach counter }; } // namespace dbus @@ -131,4 +174,14 @@ struct StubBase } // namespace simppl +inline +void operator>>(simppl::dbus::detail::InterimGetAllPropertiesCallbackHolder&& r, const std::function& f) +{ + dbus_pending_call_set_notify(r.pc_.pending(), + &simppl::dbus::detail::GetAllPropertiesHolder::pending_notify, + new simppl::dbus::detail::GetAllPropertiesHolder(f, r.stub_), + &simppl::dbus::detail::GetAllPropertiesHolder::_delete); +} + + #endif // SIMPPL_STUBBASE_H diff --git a/src/clientside.cpp b/src/clientside.cpp index 3717745..e04dc02 100644 --- a/src/clientside.cpp +++ b/src/clientside.cpp @@ -3,15 +3,14 @@ namespace simppl { - + namespace dbus { - + ClientSignalBase::ClientSignalBase(const char* name, StubBase* stub, int) : stub_(stub) , name_(name) - , next_(nullptr) { // NOOP } @@ -20,16 +19,15 @@ ClientSignalBase::ClientSignalBase(const char* name, StubBase* stub, int) ClientPropertyBase::ClientPropertyBase(const char* name, StubBase* stub, int) : name_(name) , stub_(stub) - , next_(nullptr) { - // NOOP + stub_->add_property(this); } /// only call this after the server is connected. void ClientPropertyBase::detach() { - stub_->detach_property(*this); + stub_->detach_property(this); } diff --git a/src/holders.cpp b/src/holders.cpp new file mode 100644 index 0000000..db4f8ad --- /dev/null +++ b/src/holders.cpp @@ -0,0 +1,34 @@ +#include "simppl/pendingcall.h" +#include "simppl/variant.h" +#include "simppl/stub.h" + +#include "simppl/detail/holders.h" + + +simppl::dbus::detail::GetAllPropertiesHolder::GetAllPropertiesHolder(std::function f, StubBase& stub) + : f_(f) + , stub_(stub) +{ + // NOOP +} + + +/*static*/ +void simppl::dbus::detail::GetAllPropertiesHolder::_delete(void* p) +{ + auto that = (GetAllPropertiesHolder*)p; + delete that; +} + + +/*static*/ +void simppl::dbus::detail::GetAllPropertiesHolder::pending_notify(DBusPendingCall* pc, void* data) +{ + auto msg = simppl::dbus::make_message(dbus_pending_call_steal_reply(pc)); + + auto that = (GetAllPropertiesHolder*)data; + assert(that->f_); + + auto cs = that->stub_.get_all_properties_handle_response(*msg); + that->f_(cs); +} diff --git a/src/skeletonbase.cpp b/src/skeletonbase.cpp index fa1a56f..279fb2f 100644 --- a/src/skeletonbase.cpp +++ b/src/skeletonbase.cpp @@ -195,27 +195,24 @@ DBusHandlerResult SkeletonBase::handle_request(DBusMessage* msg) #if SIMPPL_HAVE_INTROSPECTION if (!strcmp(interface_name, "org.freedesktop.DBus.Introspectable")) - { return handle_introspect_request(msg); - } #endif if (!strcmp(interface_name, "org.freedesktop.DBus.Properties")) { + if (!has_any_properties()) + return handle_error(msg, DBUS_ERROR_UNKNOWN_INTERFACE); + return handle_property_request(msg); } int iface_id = find_interface(interface_name); if (iface_id == invalid_iface_id) - { return handle_error(msg, DBUS_ERROR_UNKNOWN_INTERFACE); - } ServerMethodBase* method = find_method(iface_id, method_name); if (!method) - { return handle_error(msg, DBUS_ERROR_UNKNOWN_METHOD); - } return handle_interface_request(msg, *method); } @@ -260,6 +257,10 @@ DBusHandlerResult SkeletonBase::handle_introspect_request(DBusMessage* msg) " \n" " \n" " \n" + " \n" + " \n" + " \n" + " \n" " \n" " \n" " \n" @@ -300,46 +301,89 @@ DBusHandlerResult SkeletonBase::handle_introspect_request(DBusMessage* msg) #endif // defined(SIMPPL_HAVE_INTROSPECTION) +DBusHandlerResult SkeletonBase::handle_property_getall_request(DBusMessage* msg, int iface_id) +{ + message_ptr_t response = make_message(dbus_message_new_method_return(msg)); + + DBusMessageIter iter; + DBusMessageIter _iter; + DBusMessageIter __iter; + + dbus_message_iter_init_append(response.get(), &iter); + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &_iter); + + for (auto pp = property_heads_[iface_id]; pp; pp = pp->next_) + { + dbus_message_iter_open_container(&_iter, DBUS_TYPE_DICT_ENTRY, nullptr, &__iter); + + encode(__iter, pp->name_); + pp->eval(&__iter); + + dbus_message_iter_close_container(&_iter, &__iter); + } + + dbus_message_iter_close_container(&iter, &_iter); + + dbus_connection_send(disp_->conn_, response.get(), nullptr); + return DBUS_HANDLER_RESULT_HANDLED; +} + + DBusHandlerResult SkeletonBase::handle_property_request(DBusMessage* msg) { DBusMessageIter iter; std::string interface_name; - std::string property_name; + int iface_id; + + const char* method = dbus_message_get_member(msg); try { dbus_message_iter_init(msg, &iter); - decode(iter, interface_name, property_name); + decode(iter, interface_name); } catch(DecoderError&) { return handle_error(msg, DBUS_ERROR_INVALID_ARGS); } - int iface_id = find_interface(interface_name); + iface_id = find_interface(interface_name); + if (iface_id == invalid_iface_id) - { return handle_error(msg, DBUS_ERROR_UNKNOWN_INTERFACE); - } - - ServerPropertyBase* property = find_property(iface_id, property_name); - if (!property) - { - return handle_error(msg, DBUS_ERROR_UNKNOWN_PROPERTY); - } - const char* method = dbus_message_get_member(msg); - if (!strcmp(method, "Get")) - { - return handle_property_get_request(msg, *property); - } - else if(!strcmp(method, "Set")) + if(!strcmp(method, "GetAll")) { - return handle_property_set_request(msg, *property, iter); + return handle_property_getall_request(msg, iface_id); } else { - return handle_error(msg, DBUS_ERROR_UNKNOWN_METHOD); + std::string property_name; + + try + { + decode(iter, property_name); + } + catch(DecoderError&) + { + return handle_error(msg, DBUS_ERROR_INVALID_ARGS); + } + + ServerPropertyBase* property = find_property(iface_id, property_name); + + if (!property) + return handle_error(msg, DBUS_ERROR_UNKNOWN_PROPERTY); + + if (!strcmp(method, "Get")) + { + return handle_property_get_request(msg, *property); + } + else if(!strcmp(method, "Set")) + { + return handle_property_set_request(msg, *property, iter); + } + else + return handle_error(msg, DBUS_ERROR_UNKNOWN_METHOD); } } @@ -347,7 +391,11 @@ DBusHandlerResult SkeletonBase::handle_property_request(DBusMessage* msg) DBusHandlerResult SkeletonBase::handle_property_get_request(DBusMessage* msg, ServerPropertyBase& property) { message_ptr_t response = make_message(dbus_message_new_method_return(msg)); - property.eval(response.get()); + DBusMessageIter iter; + + dbus_message_iter_init_append(response.get(), &iter); + property.eval(&iter); + dbus_connection_send(disp_->conn_, response.get(), nullptr); return DBUS_HANDLER_RESULT_HANDLED; } diff --git a/src/stubbase.cpp b/src/stubbase.cpp index d61dabb..b15fdc7 100644 --- a/src/stubbase.cpp +++ b/src/stubbase.cpp @@ -1,4 +1,5 @@ #include "simppl/stub.h" +#include #include "simppl/dispatcher.h" #include "simppl/string.h" @@ -25,7 +26,7 @@ StubBase::StubBase() , conn_state_(ConnectionState::Disconnected) , disp_(nullptr) , signals_(nullptr) - , properties_(nullptr) + , attached_properties_(0) { // NOOP } @@ -73,6 +74,12 @@ void StubBase::init(char* iface, const char* role) } +void StubBase::add_property(ClientPropertyBase* property) +{ + properties_.push_back(std::make_pair(property, false)); +} + + DBusConnection* StubBase::conn() { return disp().conn_; @@ -86,6 +93,87 @@ Dispatcher& StubBase::disp() } +void StubBase::get_all_properties() +{ + message_ptr_t msg = make_message(dbus_message_new_method_call(busname().c_str(), objectpath(), "org.freedesktop.DBus.Properties", "GetAll")); + DBusPendingCall* pending = nullptr; + + DBusMessageIter iter; + dbus_message_iter_init_append(msg.get(), &iter); + + encode(iter, iface()); + + // TODO timeout handling here + dbus_connection_send_with_reply(conn(), msg.get(), &pending, DBUS_TIMEOUT_USE_DEFAULT); + + dbus_pending_call_block(pending); + + msg.reset(dbus_pending_call_steal_reply(pending)); + dbus_pending_call_unref(pending); + + auto cs = get_all_properties_handle_response(*msg); + + if (!cs) + cs.throw_exception(); +} + + +simppl::dbus::CallState StubBase::get_all_properties_handle_response(DBusMessage& response) +{ + DBusMessageIter iter; + dbus_message_iter_init(&response, &iter); + + CallState cs(response); + + if (cs) + { + // open array container + DBusMessageIter _iter; + dbus_message_iter_recurse(&iter, &_iter); + + while(dbus_message_iter_get_arg_type(&_iter) != 0) + { + // open dict container + DBusMessageIter __iter; + dbus_message_iter_recurse(&_iter, &__iter); + + std::string propname; + decode(__iter, propname); + + // get property by name + auto propiter = std::find_if(properties_.begin(), properties_.end(), [propname](auto& pair){ return propname == pair.first->name_; }); + + // get value and call + if (propiter != properties_.end()) + propiter->first->eval(__iter); + + dbus_message_iter_next(&_iter); + } + } + + return std::move(cs); +} + + +StubBase::getall_properties_holder_type StubBase::get_all_properties_async() +{ + message_ptr_t msg = make_message(dbus_message_new_method_call(busname().c_str(), objectpath(), "org.freedesktop.DBus.Properties", "GetAll")); + DBusPendingCall* pending = nullptr; + + { + DBusMessageIter iter; + dbus_message_iter_init_append(msg.get(), &iter); + + encode(iter, iface()); + } + + // TODO timeout handling here + dbus_connection_send_with_reply(conn(), msg.get(), &pending, DBUS_TIMEOUT_USE_DEFAULT); + + return getall_properties_holder_type(PendingCall(dbus_message_get_serial(msg.get()), pending), *this); +} + + PendingCall StubBase::send_request(const char* method_name, std::function&& f, bool is_oneway) { message_ptr_t msg = make_message(dbus_message_new_method_call(busname().c_str(), objectpath(), iface(), method_name)); @@ -93,7 +181,7 @@ PendingCall StubBase::send_request(const char* method_name, std::functionnext_; } - + disp_->register_signal(*this, sigbase); sigbase.next_ = signals_; @@ -204,14 +292,14 @@ void StubBase::unregister_signal(ClientSignalBase& sigbase) ClientSignalBase* last = nullptr; auto sig = signals_; - + while(sig) { // found... if (&sigbase == sig) { disp_->unregister_signal(*this, sigbase); - + // remove from list if (last) { @@ -219,70 +307,47 @@ void StubBase::unregister_signal(ClientSignalBase& sigbase) } else signals_ = sig->next_; - + sigbase.next_ = nullptr; break; } - + last = sig; sig = sig->next_; } } -void StubBase::attach_property(ClientPropertyBase& prop) +void StubBase::attach_property(ClientPropertyBase* prop) { assert(disp_); - - if (!properties_) - disp_->register_properties(*this); - auto p = properties_; - while(p) + auto propiter = std::find_if(properties_.begin(), properties_.end(), [prop](auto& pair){ return prop == pair.first; }); + + if (propiter->second == false) { - // already attached? - if (&prop == p) - return; - - p = p->next_; + propiter->second = true; + + if (++attached_properties_ == 1) + disp_->register_properties(*this); } - - prop.next_ = properties_; - properties_ = ∝ } -void StubBase::detach_property(ClientPropertyBase& prop) +void StubBase::detach_property(ClientPropertyBase* prop) { assert(disp_); - ClientPropertyBase* last = nullptr; - auto p = properties_; - - while(p) + + auto propiter = std::find_if(properties_.begin(), properties_.end(), [prop](auto& pair){ return prop == pair.first; }); + + if (propiter->second) { - // found... - if (&prop == p) - { - // remove from list - if (last) - { - last->next_ = p->next_; - } - else - properties_ = p->next_; - - prop.next_ = nullptr; - break; - } - - last = p; - p = p->next_; + propiter->second = false; + + if (--attached_properties_ == 0) + disp_->unregister_properties(*this); } - - // empty? - if (!properties_) - disp_->unregister_properties(*this); } @@ -295,14 +360,14 @@ void StubBase::cleanup() disp_->unregister_signal(*this, *sig); sig = sig->next_; } - + signals_ = nullptr; // cleanup property registration - if (properties_) + if (attached_properties_) disp_->unregister_properties(*this); - properties_ = nullptr; + attached_properties_ = 0; disp_ = nullptr; } @@ -315,9 +380,10 @@ PendingCall StubBase::get_property_async(const char* name) DBusMessageIter iter; dbus_message_iter_init_append(msg.get(), &iter); - + encode(iter, iface(), name); + // TODO timeout handling here dbus_connection_send_with_reply(conn(), msg.get(), &pending, DBUS_TIMEOUT_USE_DEFAULT); return PendingCall(dbus_message_get_serial(msg.get()), pending); @@ -334,6 +400,7 @@ message_ptr_t StubBase::get_property(const char* name) encode(iter, iface(), name); + // TODO timeout handling here dbus_connection_send_with_reply(conn(), msg.get(), &pending, DBUS_TIMEOUT_USE_DEFAULT); dbus_pending_call_block(pending); @@ -351,7 +418,7 @@ void StubBase::set_property(const char* name, std::functionname_) - { - p->eval(item_iterator); - break; - } - - p = p->next_; - } - + auto propiter = std::find_if(properties_.begin(), properties_.end(), [&property_name](auto& pair){ return property_name == pair.first->name_; }); + + if (propiter != properties_.end() && propiter->second) + propiter->first->eval(item_iterator); + // advance to next element dbus_message_iter_next(&iter); } @@ -436,18 +498,18 @@ void StubBase::try_handle_signal(DBusMessage* msg) else { auto sig = signals_; - + while(sig) { if (!strcmp(sig->name_, dbus_message_get_member(msg))) { DBusMessageIter iter; dbus_message_iter_init(msg, &iter); - + sig->eval(iter); break; } - + sig = sig->next_; } } diff --git a/tests/properties.cpp b/tests/properties.cpp index 7e804ac..9ba9ea0 100644 --- a/tests/properties.cpp +++ b/tests/properties.cpp @@ -35,6 +35,7 @@ INTERFACE(Properties) Property data; Property> props; + Property str_prop; Signal mayShutdown; @@ -44,12 +45,26 @@ INTERFACE(Properties) , INIT(shutdown) , INIT(data) , INIT(props) + , INIT(str_prop) , INIT(mayShutdown) { // NOOP } }; + +INTERFACE(NoProperties) +{ + Method shutdown; + + inline + NoProperties() + : INIT(shutdown) + { + // NOOP + } +}; + } using namespace test; @@ -259,12 +274,25 @@ struct Server : simppl::dbus::Skeleton // initialize properties data = 4711; props = { { One, "One" }, { Two, "Two" } }; + str_prop = "Hallo Welt"; } int calls_ = 0; }; +struct NoPropertiesServer : simppl::dbus::Skeleton +{ + NoPropertiesServer(simppl::dbus::Dispatcher& d, const char* rolename) + : simppl::dbus::Skeleton(d, rolename) + { + shutdown >> [this](){ + disp().stop(); + }; + } +}; + + struct InvalidSetterServer : simppl::dbus::Skeleton { InvalidSetterServer(simppl::dbus::Dispatcher& d, const char* rolename) @@ -320,6 +348,48 @@ struct NonCachingTestClient : simppl::dbus::Stub }; +struct GetAllClient : simppl::dbus::Stub +{ + GetAllClient(simppl::dbus::Dispatcher& d) + : simppl::dbus::Stub(d, "s") + { + connected >> [this](simppl::dbus::ConnectionState s){ + EXPECT_EQ(simppl::dbus::ConnectionState::Connected, s); + + // you only get the properties with a callback set + // so first connect the desired properties + data >> [this](simppl::dbus::CallState cs, int i) { + EXPECT_TRUE((bool)cs); + EXPECT_EQ(i, 4711); + + ++count_; + }; + + str_prop >> [this](simppl::dbus::CallState cs, const std::string& str) { + EXPECT_TRUE((bool)cs); + EXPECT_EQ(str, "Hallo Welt"); + + ++count_; + }; + + // now call - callbacks will be called in background just before + // this callback gets called... + get_all_properties_async() >> [this](simppl::dbus::CallState cs){ + EXPECT_TRUE((bool)cs); + + // the other two callbacks are already evaluated... + EXPECT_EQ(2, count_); + + // ok, test finished + disp().stop(); + }; + }; + } + + int count_ = 0; +}; + + struct NonCachingPropertyServer : simppl::dbus::Skeleton { NonCachingPropertyServer(simppl::dbus::Dispatcher& d, const char* rolename) @@ -405,7 +475,7 @@ TEST(Properties, blocking_set) } -TEST(Properties, blocking_get) +TEST(Properties, get_blocking) { simppl::dbus::Dispatcher d("bus:session"); @@ -425,6 +495,82 @@ TEST(Properties, blocking_get) } +TEST(Properties, getall_blocking) +{ + simppl::dbus::Dispatcher d("bus:session"); + + std::thread t(blockrunner); + + // wait for server to get ready + std::this_thread::sleep_for(200ms); + + simppl::dbus::Stub c(d, "s"); + + int ival = 0; + std::map mval; + std::string sval; + + // first connect all properties + c.data >> [&ival](simppl::dbus::CallState, int i) { ival = i; }; + c.props >> [&mval](simppl::dbus::CallState, const std::map& val) { mval = val; }; + c.str_prop >> [&sval](simppl::dbus::CallState, const std::string& str) { sval = str; }; + + // now call - callbacks will be called in background + c.get_all_properties(); + + EXPECT_EQ(ival, 4711); + EXPECT_EQ(sval, "Hallo Welt"); + + c.shutdown(); // stop server + t.join(); +} + + +TEST(Properties, getall_async) +{ + simppl::dbus::Dispatcher d("bus:session"); + + Server s(d, "s"); + GetAllClient c(d); + + d.run(); +} + + +TEST(Properties, getall_no_properties_blocking) +{ + simppl::dbus::Dispatcher d("bus:session"); + + std::thread t([](){ + simppl::dbus::Dispatcher d("bus:session"); + NoPropertiesServer s(d, "s"); + + d.run(); + }); + + // wait for server to get ready + std::this_thread::sleep_for(200ms); + + simppl::dbus::Stub c(d, "s"); + + try + { + // now call - no properties -> exception + c.get_all_properties(); + + // never reached + EXPECT_TRUE(false); + } + catch(simppl::dbus::Error& err) + { + EXPECT_NE(nullptr, strstr(err.what(), "UnknownInterface")); + } + + c.shutdown(); // stop server + t.join(); +} + + TEST(Properties, set) { simppl::dbus::Dispatcher d("bus:session");