Add support for ObjectManager and other standard D-Bus interfaces (#55)

Fixes #50
This commit is contained in:
Stanislav Angelovič
2019-05-29 22:28:15 +02:00
committed by GitHub
parent 4b0c23204d
commit 91fa35140b
36 changed files with 541 additions and 235 deletions
+111 -11
View File
@@ -45,6 +45,7 @@
using ::testing::Eq;
using ::testing::Gt;
using ::testing::ElementsAre;
using ::testing::SizeIs;
using namespace std::chrono_literals;
namespace
@@ -65,6 +66,18 @@ public:
s_connection->releaseName(INTERFACE_NAME);
}
static void waitUntil(std::atomic<bool>& flag, std::chrono::milliseconds timeout = 1s)
{
std::chrono::milliseconds elapsed{};
std::chrono::milliseconds step{5ms};
do {
std::this_thread::sleep_for(step);
elapsed += step;
if (elapsed > timeout)
throw std::runtime_error("Waiting timed out");
} while (!flag);
}
private:
void SetUp() override
{
@@ -396,30 +409,117 @@ TEST_F(SdbusTestObject, EmitsSignalWithoutRegistrationSuccesfully)
// Properties
TEST_F(SdbusTestObject, ReadsReadPropertySuccesfully)
TEST_F(SdbusTestObject, ReadsReadOnlyPropertySuccesfully)
{
ASSERT_THAT(m_proxy->state(), Eq(STRING_VALUE));
ASSERT_THAT(m_proxy->state(), Eq(DEFAULT_STATE_VALUE));
}
TEST_F(SdbusTestObject, FailsWritingToReadOnlyProperty)
{
ASSERT_THROW(m_proxy->state("new_value"), sdbus::Error);
}
TEST_F(SdbusTestObject, WritesAndReadsReadWritePropertySuccesfully)
{
uint32_t x = 42;
ASSERT_NO_THROW(m_proxy->action(x));
ASSERT_THAT(m_proxy->action(), Eq(x));
uint32_t newActionValue = 5678;
m_proxy->action(newActionValue);
ASSERT_THAT(m_proxy->action(), Eq(newActionValue));
}
TEST_F(SdbusTestObject, WritesToWritePropertySuccesfully)
// Standard D-Bus interfaces
TEST_F(SdbusTestObject, PingsViaPeerInterface)
{
auto x = true;
ASSERT_NO_THROW(m_proxy->blocking(x));
ASSERT_NO_THROW(m_proxy->Ping());
}
TEST_F(SdbusTestObject, CannotReadFromWriteProperty)
TEST_F(SdbusTestObject, AnswersMachineUuidViaPeerInterface)
{
ASSERT_THROW(m_proxy->blocking(), sdbus::Error);
ASSERT_NO_THROW(m_proxy->GetMachineId());
}
TEST_F(SdbusTestObject, AnswersXmlApiDescriptionOnIntrospection)
TEST_F(SdbusTestObject, AnswersXmlApiDescriptionViaIntrospectableInterface)
{
ASSERT_THAT(m_proxy->Introspect(), Eq(m_adaptor->getExpectedXmlApiDescription()));
}
TEST_F(SdbusTestObject, GetsPropertyViaPropertiesInterface)
{
ASSERT_THAT(m_proxy->Get(INTERFACE_NAME, "state").get<std::string>(), Eq(DEFAULT_STATE_VALUE));
}
TEST_F(SdbusTestObject, SetsPropertyViaPropertiesInterface)
{
uint32_t newActionValue = 2345;
m_proxy->Set(INTERFACE_NAME, "action", newActionValue);
ASSERT_THAT(m_proxy->action(), Eq(newActionValue));
}
TEST_F(SdbusTestObject, GetsAllPropertiesViaPropertiesInterface)
{
const auto properties = m_proxy->GetAll(INTERFACE_NAME);
ASSERT_THAT(properties, SizeIs(3));
EXPECT_THAT(properties.at("state").get<std::string>(), Eq(DEFAULT_STATE_VALUE));
EXPECT_THAT(properties.at("action").get<uint32_t>(), Eq(DEFAULT_ACTION_VALUE));
EXPECT_THAT(properties.at("blocking").get<bool>(), Eq(DEFAULT_BLOCKING_VALUE));
}
// TODO: Uncomment once we have support for PropertiesChanged signals
//TEST_F(SdbusTestObject, GetsSignalOnChangedPropertiesViaPropertiesInterface)
//{
// std::atomic<bool> signalReceived{false};
// m_proxy->m_onPropertiesChangedHandler = [&signalReceived](const std::string& interfaceName, const std::map<std::string, sdbus::Variant>& changedProperties, const std::vector<std::string>& invalidatedProperties)
// {
// EXPECT_THAT(interfaceName, Eq(INTERFACE_NAME));
// EXPECT_THAT(changedProperties, SizeIs(2));
// EXPECT_THAT(changedProperties.at("blocking").get<bool>(), Eq(false));
// EXPECT_THAT(invalidatedProperties, SizeIs(0));
// signalReceived = true;
// };
//
// m_proxy->blocking(!DEFAULT_BLOCKING_VALUE);
// waitUntil(signalReceived);
//}
TEST_F(SdbusTestObject, DoesNotProvideObjectManagerInterfaceByDefault)
{
ASSERT_THROW(m_proxy->GetManagedObjects(), sdbus::Error);
}
TEST_F(SdbusTestObject, ProvidesObjectManagerInterfaceWhenExplicitlyAdded)
{
m_adaptor->addObjectManager();
ASSERT_NO_THROW(m_proxy->GetManagedObjects());
}
TEST_F(SdbusTestObject, GetsZeroManagedObjectsIfHasNoSubPathObjects)
{
m_adaptor->addObjectManager();
const auto objectsInterfacesAndProperties = m_proxy->GetManagedObjects();
ASSERT_THAT(objectsInterfacesAndProperties, SizeIs(0));
}
TEST_F(SdbusTestObject, GetsManagedObjectsSuccessfully)
{
m_adaptor->addObjectManager();
auto subObject1 = sdbus::createObject(*s_connection, "/sub/path1");
subObject1->registerProperty("aProperty1").onInterface("org.sdbuscpp.integrationtests.iface1").withGetter([]{return uint8_t{123};});
subObject1->finishRegistration();
auto subObject2 = sdbus::createObject(*s_connection, "/sub/path2");
subObject2->registerProperty("aProperty2").onInterface("org.sdbuscpp.integrationtests.iface2").withGetter([]{return "hi";});
subObject2->finishRegistration();
const auto objectsInterfacesAndProperties = m_proxy->GetManagedObjects();
ASSERT_THAT(objectsInterfacesAndProperties, SizeIs(2));
EXPECT_THAT(objectsInterfacesAndProperties.at("/sub/path1").at("org.sdbuscpp.integrationtests.iface1").at("aProperty1").get<uint8_t>(), Eq(123));
EXPECT_THAT(objectsInterfacesAndProperties.at("/sub/path2").at("org.sdbuscpp.integrationtests.iface2").at("aProperty2").get<std::string>(), Eq("hi"));
}
+4 -3
View File
@@ -177,15 +177,16 @@ protected:
throw sdbus::createError(1, "A test error occurred");
}
std::string state() { return STRING_VALUE; }
std::string state() { return m_state; }
uint32_t action() { return m_action; }
void action(const uint32_t& value) { m_action = value; }
bool blocking() { return m_blocking; }
void blocking(const bool& value) { m_blocking = value; }
private:
uint32_t m_action;
bool m_blocking;
const std::string m_state{DEFAULT_STATE_VALUE};
uint32_t m_action{DEFAULT_ACTION_VALUE};
bool m_blocking{DEFAULT_BLOCKING_VALUE};
// For dont-expect-reply method call verifications
mutable std::atomic<bool> m_multiplyCalled{};
+29 -2
View File
@@ -28,7 +28,11 @@
#include "proxy-glue.h"
class TestingProxy : public sdbus::ProxyInterfaces<::testing_proxy, sdbus::introspectable_proxy>
class TestingProxy : public sdbus::ProxyInterfaces< ::testing_proxy
, sdbus::Peer_proxy
, sdbus::Introspectable_proxy
, sdbus::Properties_proxy
, sdbus::ObjectManager_proxy >
{
public:
TestingProxy(std::string destination, std::string objectPath)
@@ -73,13 +77,36 @@ protected:
m_DoOperationClientSideAsyncReplyHandler(returnValue, error);
}
private:
// Signals of standard D-Bus interfaces
void onPropertiesChanged( const std::string& interfaceName
, const std::map<std::string, sdbus::Variant>& changedProperties
, const std::vector<std::string>& invalidatedProperties ) override
{
if (m_onPropertiesChangedHandler)
m_onPropertiesChangedHandler(interfaceName, changedProperties, invalidatedProperties);
}
void onInterfacesAdded( const sdbus::ObjectPath& /*objectPath*/
, const std::map<std::string, std::map<std::string, sdbus::Variant>>& /*interfacesAndProperties*/) override
{
// Intentionally left empty
}
void onInterfacesRemoved( const sdbus::ObjectPath& /*objectPath*/
, const std::vector<std::string>& /*interfaces*/) override
{
// Intentionally left empty
}
//private:
public:
int m_simpleCallCounter{};
std::map<int32_t, std::string> m_map;
double m_variantValue;
std::map<std::string, std::string> m_signature;
std::function<void(uint32_t res, const sdbus::Error* err)> m_DoOperationClientSideAsyncReplyHandler;
std::function<void(const std::string& interfaceName, const std::map<std::string, sdbus::Variant>& changedProperties, const std::vector<std::string>& invalidatedProperties)> m_onPropertiesChangedHandler;
};
+4 -3
View File
@@ -111,8 +111,9 @@ protected:
object_.registerSignal("signalWithVariant").onInterface(INTERFACE_NAME).withParameters<sdbus::Variant>();
object_.registerProperty("state").onInterface(INTERFACE_NAME).withGetter([this](){ return this->state(); }).markAsDeprecated().withUpdateBehavior(sdbus::Flags::CONST_PROPERTY_VALUE);
object_.registerProperty("action").onInterface(INTERFACE_NAME).withGetter([this](){ return this->action(); }).withSetter([this](const uint32_t& value){ this->action(value); }).withUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL);
object_.registerProperty("blocking").onInterface(INTERFACE_NAME)./*withGetter([this](){ return this->blocking(); }).*/withSetter([this](const bool& value){ this->blocking(value); });
object_.registerProperty("action").onInterface(INTERFACE_NAME).withGetter([this](){ return this->action(); }).withSetter([this](const uint32_t& value){ this->action(value); }).withUpdateBehavior(sdbus::Flags::EMITS_INVALIDATION_SIGNAL);
//object_.registerProperty("blocking").onInterface(INTERFACE_NAME)./*withGetter([this](){ return this->blocking(); }).*/withSetter([this](const bool& value){ this->blocking(value); });
object_.registerProperty("blocking").onInterface(INTERFACE_NAME).withGetter([this](){ return this->blocking(); }).withSetter([this](const bool& value){ this->blocking(value); });
}
@@ -294,7 +295,7 @@ R"delimiter(<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspectio
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
</signal>
<property name="action" type="u" access="readwrite">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/>
</property>
<property name="blocking" type="b" access="readwrite">
</property>
+4
View File
@@ -41,6 +41,10 @@ const std::string STRING_VALUE{"sdbus-c++-testing"};
const sdbus::Signature SIGNATURE_VALUE{"a{is}"};
const sdbus::ObjectPath OBJECT_PATH_VALUE{"/"};
const std::string DEFAULT_STATE_VALUE{"default-state-value"};
const uint32_t DEFAULT_ACTION_VALUE{999};
const bool DEFAULT_BLOCKING_VALUE{true};
constexpr const double DOUBLE_VALUE{3.24L};
#endif /* SDBUS_CPP_INTEGRATIONTESTS_DEFS_H_ */
+5
View File
@@ -211,6 +211,11 @@ public:
return object_.getProperty("state").onInterface(INTERFACE_NAME);
}
void state(const std::string& value)
{
object_.setProperty("state").onInterface(INTERFACE_NAME).toValue(value);
}
uint32_t action()
{
return object_.getProperty("action").onInterface(INTERFACE_NAME);