forked from Kistler-Group/sdbus-cpp
Introduce support for asynchronous server-side methods (#12)
* Add preliminary changes for async server methods * Refactor the Message concept and break it into distinctive types * Continue working on async server methods (high-level API mainly) * Continue developing support for async server * Finishing async server methods * Finishing async server methods (fixing tests & cleaning up) * A little code cleaning * Add unit tests for type traits of free functions * Support for generating async server methods in stub headers * Update ChangeLog for v0.3.0 * Update the tutorial with how to use async server-side methods * Update the TOC in sdbus-c++ tutorial * Update numbering in TOC * Remove unnecessary code * Final cleanups
This commit is contained in:
committed by
Lukáš Ďurfina
parent
b041f76bfc
commit
d8fd053714
@@ -40,9 +40,12 @@
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <tuple>
|
||||
#include <chrono>
|
||||
|
||||
using ::testing::Eq;
|
||||
using ::testing::Gt;
|
||||
using ::testing::ElementsAre;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -67,7 +70,7 @@ private:
|
||||
{
|
||||
m_adaptor = std::make_unique<TestingAdaptor>(m_connection);
|
||||
m_proxy = std::make_unique<TestingProxy>(INTERFACE_NAME, OBJECT_PATH);
|
||||
usleep(50000); // Give time for the proxy to start listening to signals
|
||||
std::this_thread::sleep_for(50ms); // Give time for the proxy to start listening to signals
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
@@ -197,6 +200,31 @@ TEST_F(SdbusTestObject, CallsMethodWithComplexTypeSuccesfully)
|
||||
ASSERT_THAT(resComplex.count(0), Eq(1));
|
||||
}
|
||||
|
||||
TEST_F(SdbusTestObject, DoesServerSideAsynchoronousMethodInParallel)
|
||||
{
|
||||
// Yeah, this is kinda timing-dependent test, but times should be safe...
|
||||
std::mutex mtx;
|
||||
std::vector<uint32_t> results;
|
||||
std::atomic<bool> invoke{};
|
||||
std::atomic<int> startedCount{};
|
||||
auto call = [&](uint32_t param)
|
||||
{
|
||||
TestingProxy proxy{INTERFACE_NAME, OBJECT_PATH};
|
||||
++startedCount;
|
||||
while (!invoke) ;
|
||||
auto result = proxy.doOperationAsync(param);
|
||||
std::lock_guard<std::mutex> guard(mtx);
|
||||
results.push_back(result);
|
||||
};
|
||||
|
||||
std::thread invocations[]{std::thread{call, 1500}, std::thread{call, 1000}, std::thread{call, 500}};
|
||||
while (startedCount != 3) ;
|
||||
invoke = true;
|
||||
std::for_each(std::begin(invocations), std::end(invocations), [](auto& t){ t.join(); });
|
||||
|
||||
ASSERT_THAT(results, ElementsAre(500, 1000, 1500));
|
||||
}
|
||||
|
||||
TEST_F(SdbusTestObject, FailsCallingNonexistentMethod)
|
||||
{
|
||||
ASSERT_THROW(m_proxy->callNonexistentMethod(), sdbus::Error);
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#define SDBUS_CPP_INTEGRATIONTESTS_TESTINGADAPTOR_H_
|
||||
|
||||
#include "adaptor-glue.h"
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
class TestingAdaptor : public sdbus::Interfaces<testing_adaptor>
|
||||
{
|
||||
@@ -97,6 +99,22 @@ protected:
|
||||
return res;
|
||||
}
|
||||
|
||||
uint32_t doOperationSync(uint32_t param)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(param));
|
||||
return param;
|
||||
}
|
||||
|
||||
void doOperationAsync(uint32_t param, sdbus::Result<uint32_t> result)
|
||||
{
|
||||
// The same as doOperationSync, just written as an asynchronous method callback
|
||||
std::thread([param, result = std::move(result)]()
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(param));
|
||||
result.returnResults(param);
|
||||
}).detach();
|
||||
}
|
||||
|
||||
sdbus::Signature getSignature() const { return SIGNATURE_VALUE; }
|
||||
sdbus::ObjectPath getObjectPath() const { return OBJECT_PATH_VALUE; }
|
||||
|
||||
|
||||
@@ -82,6 +82,16 @@ protected:
|
||||
return this->sumVectorItems(a, b);
|
||||
});
|
||||
|
||||
object_.registerMethod("doOperationSync").onInterface(INTERFACE_NAME).implementedAs([this](uint32_t param)
|
||||
{
|
||||
return this->doOperationSync(param);
|
||||
});
|
||||
|
||||
object_.registerMethod("doOperationAsync").onInterface(INTERFACE_NAME).implementedAs([this](sdbus::Result<uint32_t> result, uint32_t param)
|
||||
{
|
||||
this->doOperationAsync(param, std::move(result));
|
||||
});
|
||||
|
||||
object_.registerMethod("getSignature").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getSignature(); });
|
||||
object_.registerMethod("getObjectPath").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getObjectPath(); });
|
||||
|
||||
@@ -139,6 +149,8 @@ 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 void doOperationAsync(uint32_t param, sdbus::Result<uint32_t> result) = 0;
|
||||
virtual sdbus::Signature getSignature() const = 0;
|
||||
virtual sdbus::ObjectPath getObjectPath() const = 0;
|
||||
virtual ComplexType getComplex() const = 0;
|
||||
|
||||
@@ -120,6 +120,20 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t doOperationSync(uint32_t param)
|
||||
{
|
||||
uint32_t result;
|
||||
object_.callMethod("doOperationSync").onInterface(INTERFACE_NAME).withArguments(param).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t doOperationAsync(uint32_t param)
|
||||
{
|
||||
uint32_t result;
|
||||
object_.callMethod("doOperationAsync").onInterface(INTERFACE_NAME).withArguments(param).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
sdbus::Signature getSignature()
|
||||
{
|
||||
sdbus::Signature result;
|
||||
|
||||
Reference in New Issue
Block a user