Introduce support for asynchronous D-Bus method calls on the client side (#42)

Fixes #32
This commit is contained in:
Stanislav Angelovič
2019-03-25 14:45:48 +01:00
committed by GitHub
parent 004f158817
commit 663df31398
18 changed files with 481 additions and 54 deletions
+36 -1
View File
@@ -43,6 +43,7 @@
#include <tuple>
#include <chrono>
#include <fstream>
#include <future>
using ::testing::Eq;
using ::testing::Gt;
@@ -247,7 +248,7 @@ TEST_F(SdbusTestObject, CallsErrorThrowingMethodWithDontExpectReplySet)
ASSERT_TRUE(m_adaptor->wasThrowErrorCalled());
}
TEST_F(SdbusTestObject, DoesServerSideAsynchoronousMethodInParallel)
TEST_F(SdbusTestObject, RunsServerSideAsynchoronousMethodAsynchronously)
{
// Yeah, this is kinda timing-dependent test, but times should be safe...
std::mutex mtx;
@@ -302,6 +303,40 @@ TEST_F(SdbusTestObject, HandlesCorrectlyABulkOfParallelServerSideAsyncMethods)
ASSERT_THAT(resultCount, Eq(1500));
}
TEST_F(SdbusTestObject, InvokesMethodAsynchronouslyOnClientSide)
{
std::promise<uint32_t> promise;
auto future = promise.get_future();
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t res, const sdbus::Error* err)
{
if (err == nullptr)
promise.set_value(res);
else
promise.set_exception(std::make_exception_ptr(*err));
});
m_proxy->doOperationClientSideAsync(100);
ASSERT_THAT(future.get(), Eq(100));
}
TEST_F(SdbusTestObject, InvokesErroneousMethodAsynchronouslyOnClientSide)
{
std::promise<uint32_t> promise;
auto future = promise.get_future();
m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t res, const sdbus::Error* err)
{
if (err == nullptr)
promise.set_value(res);
else
promise.set_exception(std::make_exception_ptr(*err));
});
m_proxy->doErroneousOperationClientSideAsync();
ASSERT_THROW(future.get(), sdbus::Error);
}
TEST_F(SdbusTestObject, FailsCallingNonexistentMethod)
{
ASSERT_THROW(m_proxy->callNonexistentMethod(), sdbus::Error);
+1 -1
View File
@@ -110,7 +110,7 @@ protected:
return res;
}
uint32_t doOperationSync(uint32_t param)
uint32_t doOperation(uint32_t param)
{
std::this_thread::sleep_for(std::chrono::milliseconds(param));
return param;
+12
View File
@@ -38,6 +38,11 @@ public:
double getVariantValue() const { return m_variantValue; }
std::map<std::string, std::string> getSignatureFromSignal() const { return m_signature; }
void installDoOperationClientSideAsyncReplyHandler(std::function<void(uint32_t res, const sdbus::Error* err)> handler)
{
m_DoOperationClientSideAsyncReplyHandler = handler;
}
protected:
void onSimpleSignal() override { ++m_simpleCallCounter; }
@@ -53,12 +58,19 @@ protected:
m_signature[std::get<0>(s)] = static_cast<std::string>(std::get<0>(std::get<1>(s)));
}
void onDoOperationReply(uint32_t returnValue, const sdbus::Error* error) override
{
if (m_DoOperationClientSideAsyncReplyHandler)
m_DoOperationClientSideAsyncReplyHandler(returnValue, error);
}
private:
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;
};
+5 -5
View File
@@ -85,9 +85,9 @@ protected:
return this->sumVectorItems(a, b);
});
object_.registerMethod("doOperationSync").onInterface(INTERFACE_NAME).implementedAs([this](uint32_t param)
object_.registerMethod("doOperation").onInterface(INTERFACE_NAME).implementedAs([this](uint32_t param)
{
return this->doOperationSync(param);
return this->doOperation(param);
});
object_.registerMethod("doOperationAsync").onInterface(INTERFACE_NAME).implementedAs([this](sdbus::Result<uint32_t> result, uint32_t param)
@@ -158,7 +158,7 @@ protected:
virtual sdbus::Struct<std::string, sdbus::Struct<std::map<int32_t, int32_t>>> getStructInStruct() const = 0;
virtual int32_t sumStructItems(const sdbus::Struct<uint8_t, uint16_t>& a, const sdbus::Struct<int32_t, int64_t>& b) = 0;
virtual uint32_t sumVectorItems(const std::vector<uint16_t>& a, const std::vector<uint64_t>& b) = 0;
virtual uint32_t doOperationSync(uint32_t param) = 0;
virtual uint32_t doOperation(uint32_t param) = 0;
virtual void doOperationAsync(uint32_t param, sdbus::Result<uint32_t> result) = 0;
virtual sdbus::Signature getSignature() const = 0;
virtual sdbus::ObjectPath getObjectPath() const = 0;
@@ -212,11 +212,11 @@ R"delimiter(<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspectio
</interface>
<interface name="com.kistler.testsdbuscpp">
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
<method name="doOperationAsync">
<method name="doOperation">
<arg type="u" direction="in"/>
<arg type="u" direction="out"/>
</method>
<method name="doOperationSync">
<method name="doOperationAsync">
<arg type="u" direction="in"/>
<arg type="u" direction="out"/>
</method>
+23 -2
View File
@@ -50,6 +50,8 @@ protected:
virtual void onSignalWithVariant(const sdbus::Variant& v) = 0;
virtual void onSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& s) = 0;
virtual void onDoOperationReply(uint32_t returnValue, const sdbus::Error* error) = 0;
public:
void noArgNoReturn()
{
@@ -124,10 +126,10 @@ public:
return result;
}
uint32_t doOperationSync(uint32_t param)
uint32_t doOperation(uint32_t param)
{
uint32_t result;
object_.callMethod("doOperationSync").onInterface(INTERFACE_NAME).withArguments(param).storeResultsTo(result);
object_.callMethod("doOperation").onInterface(INTERFACE_NAME).withArguments(param).storeResultsTo(result);
return result;
}
@@ -138,6 +140,25 @@ public:
return result;
}
uint32_t doOperationClientSideAsync(uint32_t param)
{
object_.callMethodAsync("doOperation")
.onInterface(INTERFACE_NAME)
.withArguments(param)
.uponReplyInvoke([this](const sdbus::Error* error, uint32_t returnValue)
{
this->onDoOperationReply(returnValue, error);
});
}
uint32_t doErroneousOperationClientSideAsync()
{
object_.callMethodAsync("throwError").onInterface(INTERFACE_NAME).uponReplyInvoke([this](const sdbus::Error* error)
{
this->onDoOperationReply(0, error);
});
}
sdbus::Signature getSignature()
{
sdbus::Signature result;