From bded067496f60426f02e77aaf2278dcb1a462421 Mon Sep 17 00:00:00 2001 From: sangelovic Date: Sat, 18 Jul 2020 20:16:57 +0200 Subject: [PATCH] Fix #43: Clean up integration tests --- tests/CMakeLists.txt | 25 +- .../integrationtests/AdaptorAndProxy_test.cpp | 100 +---- .../DBusAsyncMethodsTests.cpp | 219 +++++++++ ...ction_test.cpp => DBusConnectionTests.cpp} | 8 +- tests/integrationtests/DBusGeneralTests.cpp | 56 +++ tests/integrationtests/DBusMethodsTests.cpp | 253 +++++++++++ .../integrationtests/DBusPropertiesTests.cpp | 74 ++++ tests/integrationtests/DBusSignalsTests.cpp | 94 ++++ .../DBusStandardInterfacesTests.cpp | 259 +++++++++++ tests/integrationtests/{defs.h => Defs.h} | 6 +- tests/integrationtests/TestAdaptor.cpp | 416 ++++++++++++++++++ tests/integrationtests/TestAdaptor.h | 93 ++++ tests/integrationtests/TestFixture.cpp | 33 ++ tests/integrationtests/TestFixture.h | 104 +++++ tests/integrationtests/TestProxy.cpp | 170 +++++++ .../{TestingProxy.h => TestProxy.h} | 114 ++--- tests/integrationtests/TestingAdaptor.h | 246 ----------- tests/integrationtests/adaptor-glue.h | 366 --------------- .../integrationtests-adaptor.h | 109 +++++ .../integrationtests/integrationtests-proxy.h | 204 +++++++++ .../org.sdbuscpp.integrationtests.xml | 105 +++++ tests/integrationtests/proxy-glue.h | 282 ------------ 22 files changed, 2269 insertions(+), 1067 deletions(-) create mode 100644 tests/integrationtests/DBusAsyncMethodsTests.cpp rename tests/integrationtests/{Connection_test.cpp => DBusConnectionTests.cpp} (94%) create mode 100644 tests/integrationtests/DBusGeneralTests.cpp create mode 100644 tests/integrationtests/DBusMethodsTests.cpp create mode 100644 tests/integrationtests/DBusPropertiesTests.cpp create mode 100644 tests/integrationtests/DBusSignalsTests.cpp create mode 100644 tests/integrationtests/DBusStandardInterfacesTests.cpp rename tests/integrationtests/{defs.h => Defs.h} (96%) create mode 100644 tests/integrationtests/TestAdaptor.cpp create mode 100644 tests/integrationtests/TestAdaptor.h create mode 100644 tests/integrationtests/TestFixture.cpp create mode 100644 tests/integrationtests/TestFixture.h create mode 100644 tests/integrationtests/TestProxy.cpp rename tests/integrationtests/{TestingProxy.h => TestProxy.h} (51%) delete mode 100644 tests/integrationtests/TestingAdaptor.h delete mode 100644 tests/integrationtests/adaptor-glue.h create mode 100644 tests/integrationtests/integrationtests-adaptor.h create mode 100644 tests/integrationtests/integrationtests-proxy.h create mode 100644 tests/integrationtests/org.sdbuscpp.integrationtests.xml delete mode 100644 tests/integrationtests/proxy-glue.h diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b226eac..3d3431f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -39,14 +39,23 @@ set(UNITTESTS_SRCS set(INTEGRATIONTESTS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/integrationtests) set(INTEGRATIONTESTS_SRCS - ${INTEGRATIONTESTS_SOURCE_DIR}/AdaptorAndProxy_test.cpp - ${INTEGRATIONTESTS_SOURCE_DIR}/Connection_test.cpp - ${INTEGRATIONTESTS_SOURCE_DIR}/sdbus-c++-integration-tests.cpp - ${INTEGRATIONTESTS_SOURCE_DIR}/adaptor-glue.h - ${INTEGRATIONTESTS_SOURCE_DIR}/defs.h - ${INTEGRATIONTESTS_SOURCE_DIR}/proxy-glue.h - ${INTEGRATIONTESTS_SOURCE_DIR}/TestingAdaptor.h - ${INTEGRATIONTESTS_SOURCE_DIR}/TestingProxy.h) + ${INTEGRATIONTESTS_SOURCE_DIR}/DBusConnectionTests.cpp + ${INTEGRATIONTESTS_SOURCE_DIR}/DBusGeneralTests.cpp + ${INTEGRATIONTESTS_SOURCE_DIR}/DBusMethodsTests.cpp + ${INTEGRATIONTESTS_SOURCE_DIR}/DBusAsyncMethodsTests.cpp + ${INTEGRATIONTESTS_SOURCE_DIR}/DBusSignalsTests.cpp + ${INTEGRATIONTESTS_SOURCE_DIR}/DBusPropertiesTests.cpp + ${INTEGRATIONTESTS_SOURCE_DIR}/DBusStandardInterfacesTests.cpp + ${INTEGRATIONTESTS_SOURCE_DIR}/Defs.h + ${INTEGRATIONTESTS_SOURCE_DIR}/integrationtests-adaptor.h + ${INTEGRATIONTESTS_SOURCE_DIR}/integrationtests-proxy.h + ${INTEGRATIONTESTS_SOURCE_DIR}/TestFixture.h + ${INTEGRATIONTESTS_SOURCE_DIR}/TestFixture.cpp + ${INTEGRATIONTESTS_SOURCE_DIR}/TestAdaptor.h + ${INTEGRATIONTESTS_SOURCE_DIR}/TestAdaptor.cpp + ${INTEGRATIONTESTS_SOURCE_DIR}/TestProxy.h + ${INTEGRATIONTESTS_SOURCE_DIR}/TestProxy.cpp + ${INTEGRATIONTESTS_SOURCE_DIR}/sdbus-c++-integration-tests.cpp) set(PERFTESTS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/perftests) set(STRESSTESTS_CLIENT_SRCS diff --git a/tests/integrationtests/AdaptorAndProxy_test.cpp b/tests/integrationtests/AdaptorAndProxy_test.cpp index 17df3b0..8ee2a44 100644 --- a/tests/integrationtests/AdaptorAndProxy_test.cpp +++ b/tests/integrationtests/AdaptorAndProxy_test.cpp @@ -24,25 +24,19 @@ * along with sdbus-c++. If not, see . */ -// Own -#include "TestingAdaptor.h" -#include "TestingProxy.h" - -// sdbus +#include "TestFixture.h" +#include "TestAdaptor.h" +#include "TestProxy.h" #include "sdbus-c++/sdbus-c++.h" -// gmock #include #include - -// STL #include #include #include #include #include #include - #include using ::testing::Eq; @@ -52,71 +46,9 @@ using ::testing::AnyOf; using ::testing::ElementsAre; using ::testing::SizeIs; using namespace std::chrono_literals; +using namespace sdbus::test; -namespace -{ - -class AdaptorAndProxyFixture : public ::testing::Test -{ -public: - static void SetUpTestCase() - { - s_connection->requestName(INTERFACE_NAME); - s_connection->enterEventLoopAsync(); - } - - static void TearDownTestCase() - { - s_connection->leaveEventLoop(); - s_connection->releaseName(INTERFACE_NAME); - } - - template - static bool waitUntil(_Fnc&& fnc, std::chrono::milliseconds timeout = 5s) - { - std::chrono::milliseconds elapsed{}; - std::chrono::milliseconds step{5ms}; - do { - std::this_thread::sleep_for(step); - elapsed += step; - if (elapsed > timeout) - return false; - } while (!fnc()); - - return true; - } - - static bool waitUntil(std::atomic& flag, std::chrono::milliseconds timeout = 5s) - { - return waitUntil([&flag]() -> bool { return flag; }, timeout); - } - -private: - void SetUp() override - { - m_adaptor = std::make_unique(*s_connection); - m_proxy = std::make_unique(INTERFACE_NAME, OBJECT_PATH); - std::this_thread::sleep_for(50ms); // Give time for the proxy to start listening to signals - } - - void TearDown() override - { - m_proxy.reset(); - m_adaptor.reset(); - } - -public: - static std::unique_ptr s_connection; - - std::unique_ptr m_adaptor; - std::unique_ptr m_proxy; -}; - -std::unique_ptr AdaptorAndProxyFixture::s_connection = sdbus::createSystemBusConnection(); - -} - -using SdbusTestObject = AdaptorAndProxyFixture; +using SdbusTestObject = TestFixture; /*-------------------------------------*/ /* -- TEST CASES -- */ @@ -127,8 +59,8 @@ TEST(AdaptorAndProxy, CanBeConstructedSuccesfully) auto connection = sdbus::createConnection(); connection->requestName(INTERFACE_NAME); - ASSERT_NO_THROW(TestingAdaptor adaptor(*connection)); - ASSERT_NO_THROW(TestingProxy proxy(INTERFACE_NAME, OBJECT_PATH)); + ASSERT_NO_THROW(TestAdaptor adaptor(*connection)); + ASSERT_NO_THROW(TestProxy proxy(INTERFACE_NAME, OBJECT_PATH)); connection->releaseName(INTERFACE_NAME); } @@ -279,7 +211,7 @@ TEST_F(SdbusTestObject, ThrowsTimeoutErrorWhenClientSideAsyncMethodTimesOut) }); m_proxy->doOperationClientSideAsyncWith500msTimeout(1000); // The operation will take 1s, but the timeout is 500ms, so we should time out - future.get(), Eq(100); + future.get(); FAIL() << "Expected sdbus::Error exception"; } @@ -328,7 +260,7 @@ TEST_F(SdbusTestObject, RunsServerSideAsynchoronousMethodAsynchronously) std::atomic startedCount{}; auto call = [&](uint32_t param) { - TestingProxy proxy{INTERFACE_NAME, OBJECT_PATH}; + TestProxy proxy{INTERFACE_NAME, OBJECT_PATH}; ++startedCount; while (!invoke) ; auto result = proxy.doOperationAsync(param); @@ -351,7 +283,7 @@ TEST_F(SdbusTestObject, HandlesCorrectlyABulkOfParallelServerSideAsyncMethods) std::atomic startedCount{}; auto call = [&]() { - TestingProxy proxy{INTERFACE_NAME, OBJECT_PATH}; + TestProxy proxy{INTERFACE_NAME, OBJECT_PATH}; ++startedCount; while (!invoke) ; @@ -465,17 +397,17 @@ TEST_F(SdbusTestObject, FailsCallingMethodOnNonexistentInterface) TEST_F(SdbusTestObject, FailsCallingMethodOnNonexistentDestination) { - TestingProxy proxy("sdbuscpp.destination.that.does.not.exist", OBJECT_PATH); + TestProxy proxy("sdbuscpp.destination.that.does.not.exist", OBJECT_PATH); ASSERT_THROW(proxy.getInt(), sdbus::Error); } TEST_F(SdbusTestObject, FailsCallingMethodOnNonexistentObject) { - TestingProxy proxy(INTERFACE_NAME, "/sdbuscpp/path/that/does/not/exist"); + TestProxy proxy(INTERFACE_NAME, "/sdbuscpp/path/that/does/not/exist"); ASSERT_THROW(proxy.getInt(), sdbus::Error); } -TEST_F(SdbusTestObject, ReceivesTwoSignalsWhileMakingMethodCall) +TEST_F(SdbusTestObject, CanReceiveSignalWhileMakingMethodCall) { m_proxy->emitTwoSimpleSignals(); @@ -508,8 +440,8 @@ TEST_F(SdbusTestObject, EmitsSimpleSignalSuccesfully) TEST_F(SdbusTestObject, EmitsSimpleSignalToMultipleProxiesSuccesfully) { - auto proxy1 = std::make_unique(*s_connection, INTERFACE_NAME, OBJECT_PATH); - auto proxy2 = std::make_unique(*s_connection, INTERFACE_NAME, OBJECT_PATH); + auto proxy1 = std::make_unique(*s_connection, INTERFACE_NAME, OBJECT_PATH); + auto proxy2 = std::make_unique(*s_connection, INTERFACE_NAME, OBJECT_PATH); m_adaptor->emitSimpleSignal(); @@ -553,7 +485,7 @@ TEST_F(SdbusTestObject, ReadsReadOnlyPropertySuccesfully) TEST_F(SdbusTestObject, FailsWritingToReadOnlyProperty) { - ASSERT_THROW(m_proxy->state("new_value"), sdbus::Error); + ASSERT_THROW(m_proxy->setStateProperty("new_value"), sdbus::Error); } TEST_F(SdbusTestObject, WritesAndReadsReadWritePropertySuccesfully) diff --git a/tests/integrationtests/DBusAsyncMethodsTests.cpp b/tests/integrationtests/DBusAsyncMethodsTests.cpp new file mode 100644 index 0000000..7c185f4 --- /dev/null +++ b/tests/integrationtests/DBusAsyncMethodsTests.cpp @@ -0,0 +1,219 @@ +/** + * (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2020 Stanislav Angelovic + * + * @file DBusAsyncMethodsTests.cpp + * + * Created on: Jan 2, 2017 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#include "TestFixture.h" +#include "TestAdaptor.h" +#include "TestProxy.h" +#include "sdbus-c++/sdbus-c++.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using ::testing::Eq; +using ::testing::DoubleEq; +using ::testing::Gt; +using ::testing::AnyOf; +using ::testing::ElementsAre; +using ::testing::SizeIs; +using namespace std::chrono_literals; +using namespace sdbus::test; + +using SdbusTestObject = TestFixture; + +/*-------------------------------------*/ +/* -- TEST CASES -- */ +/*-------------------------------------*/ + +TEST_F(SdbusTestObject, ThrowsTimeoutErrorWhenClientSideAsyncMethodTimesOut) +{ + try + { + std::promise 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->doOperationClientSideAsyncWith500msTimeout(1000); // The operation will take 1s, but the timeout is 500ms, so we should time out + future.get(); + + FAIL() << "Expected sdbus::Error exception"; + } + catch (const sdbus::Error& e) + { + ASSERT_THAT(e.getName(), AnyOf("org.freedesktop.DBus.Error.Timeout", "org.freedesktop.DBus.Error.NoReply")); + ASSERT_THAT(e.getMessage(), AnyOf("Connection timed out", "Method call timed out")); + } + catch(...) + { + FAIL() << "Expected sdbus::Error exception"; + } +} + +TEST_F(SdbusTestObject, RunsServerSideAsynchoronousMethodAsynchronously) +{ + // Yeah, this is kinda timing-dependent test, but times should be safe... + std::mutex mtx; + std::vector results; + std::atomic invoke{}; + std::atomic startedCount{}; + auto call = [&](uint32_t param) + { + TestProxy proxy{INTERFACE_NAME, OBJECT_PATH}; + ++startedCount; + while (!invoke) ; + auto result = proxy.doOperationAsync(param); + std::lock_guard 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, HandlesCorrectlyABulkOfParallelServerSideAsyncMethods) +{ + std::atomic resultCount{}; + std::atomic invoke{}; + std::atomic startedCount{}; + auto call = [&]() + { + TestProxy proxy{INTERFACE_NAME, OBJECT_PATH}; + ++startedCount; + while (!invoke) ; + + size_t localResultCount{}; + for (size_t i = 0; i < 500; ++i) + { + auto result = proxy.doOperationAsync(i % 2); + if (result == (i % 2)) // Correct return value? + localResultCount++; + } + + resultCount += localResultCount; + }; + + std::thread invocations[]{std::thread{call}, std::thread{call}, std::thread{call}}; + while (startedCount != 3) ; + invoke = true; + std::for_each(std::begin(invocations), std::end(invocations), [](auto& t){ t.join(); }); + + ASSERT_THAT(resultCount, Eq(1500)); +} + +TEST_F(SdbusTestObject, InvokesMethodAsynchronouslyOnClientSide) +{ + std::promise 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, AnswersThatAsyncCallIsPendingIfItIsInProgress) +{ + m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){}); + + auto call = m_proxy->doOperationClientSideAsync(100); + + ASSERT_TRUE(call.isPending()); +} + +TEST_F(SdbusTestObject, CancelsPendingAsyncCallOnClientSide) +{ + std::promise promise; + auto future = promise.get_future(); + m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){ promise.set_value(1); }); + auto call = m_proxy->doOperationClientSideAsync(100); + + call.cancel(); + + ASSERT_THAT(future.wait_for(300ms), Eq(std::future_status::timeout)); +} + +TEST_F(SdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenCancelled) +{ + std::promise promise; + auto future = promise.get_future(); + m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){ promise.set_value(1); }); + auto call = m_proxy->doOperationClientSideAsync(100); + + call.cancel(); + + ASSERT_FALSE(call.isPending()); +} + +TEST_F(SdbusTestObject, AnswersThatAsyncCallIsNotPendingAfterItHasBeenCompleted) +{ + std::promise promise; + auto future = promise.get_future(); + m_proxy->installDoOperationClientSideAsyncReplyHandler([&](uint32_t /*res*/, const sdbus::Error* /*err*/){ promise.set_value(1); }); + + auto call = m_proxy->doOperationClientSideAsync(0); + (void) future.get(); // Wait for the call to finish + + ASSERT_TRUE(waitUntil([&call](){ return !call.isPending(); })); +} + +TEST_F(SdbusTestObject, InvokesErroneousMethodAsynchronouslyOnClientSide) +{ + std::promise 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); +} diff --git a/tests/integrationtests/Connection_test.cpp b/tests/integrationtests/DBusConnectionTests.cpp similarity index 94% rename from tests/integrationtests/Connection_test.cpp rename to tests/integrationtests/DBusConnectionTests.cpp index 231aa95..714f6ba 100644 --- a/tests/integrationtests/Connection_test.cpp +++ b/tests/integrationtests/DBusConnectionTests.cpp @@ -1,8 +1,8 @@ /** * (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland - * (C) 2016 - 2019 Stanislav Angelovic + * (C) 2016 - 2020 Stanislav Angelovic * - * @file Connection_test.cpp + * @file DBusConnectionTests.cpp * * Created on: Jan 2, 2017 * Project: sdbus-c++ @@ -25,7 +25,7 @@ */ // Own -#include "defs.h" +#include "Defs.h" // sdbus #include @@ -39,7 +39,7 @@ #include using ::testing::Eq; - +using namespace sdbus::test; /*-------------------------------------*/ /* -- TEST CASES -- */ diff --git a/tests/integrationtests/DBusGeneralTests.cpp b/tests/integrationtests/DBusGeneralTests.cpp new file mode 100644 index 0000000..a0eab34 --- /dev/null +++ b/tests/integrationtests/DBusGeneralTests.cpp @@ -0,0 +1,56 @@ +/** + * (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2020 Stanislav Angelovic + * + * @file DBusGeneralTests.cpp + * + * Created on: Jan 2, 2017 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#include "TestAdaptor.h" +#include "TestProxy.h" +#include "sdbus-c++/sdbus-c++.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace sdbus::test; + +/*-------------------------------------*/ +/* -- TEST CASES -- */ +/*-------------------------------------*/ + +TEST(AdaptorAndProxy, CanBeConstructedSuccesfully) +{ + auto connection = sdbus::createConnection(); + connection->requestName(INTERFACE_NAME); + + ASSERT_NO_THROW(TestAdaptor adaptor(*connection)); + ASSERT_NO_THROW(TestProxy proxy(INTERFACE_NAME, OBJECT_PATH)); + + connection->releaseName(INTERFACE_NAME); +} diff --git a/tests/integrationtests/DBusMethodsTests.cpp b/tests/integrationtests/DBusMethodsTests.cpp new file mode 100644 index 0000000..c1362db --- /dev/null +++ b/tests/integrationtests/DBusMethodsTests.cpp @@ -0,0 +1,253 @@ +/** + * (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2020 Stanislav Angelovic + * + * @file DBusMethodsTests.cpp + * + * Created on: Jan 2, 2017 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#include "TestFixture.h" +#include "TestAdaptor.h" +#include "TestProxy.h" +#include "sdbus-c++/sdbus-c++.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using ::testing::Eq; +using ::testing::DoubleEq; +using ::testing::Gt; +using ::testing::AnyOf; +using ::testing::ElementsAre; +using ::testing::SizeIs; +using namespace std::chrono_literals; +using namespace sdbus::test; + +using SdbusTestObject = TestFixture; + +/*-------------------------------------*/ +/* -- TEST CASES -- */ +/*-------------------------------------*/ + +TEST_F(SdbusTestObject, CallsEmptyMethodSuccesfully) +{ + ASSERT_NO_THROW(m_proxy->noArgNoReturn()); +} + +TEST_F(SdbusTestObject, CallsMethodsWithBaseTypesSuccesfully) +{ + auto resInt = m_proxy->getInt(); + ASSERT_THAT(resInt, Eq(INT32_VALUE)); + + auto multiplyRes = m_proxy->multiply(INT64_VALUE, DOUBLE_VALUE); + ASSERT_THAT(multiplyRes, Eq(INT64_VALUE * DOUBLE_VALUE)); +} + +TEST_F(SdbusTestObject, CallsMethodsWithTuplesSuccesfully) +{ + auto resTuple = m_proxy->getTuple(); + ASSERT_THAT(std::get<0>(resTuple), Eq(UINT32_VALUE)); + ASSERT_THAT(std::get<1>(resTuple), Eq(STRING_VALUE)); +} + +TEST_F(SdbusTestObject, CallsMethodsWithStructSuccesfully) +{ + sdbus::Struct> a{}; + auto vectorRes = m_proxy->getInts16FromStruct(a); + ASSERT_THAT(vectorRes, Eq(std::vector{0})); // because second item is by default initialized to 0 + + + sdbus::Struct> b{ + UINT8_VALUE, INT16_VALUE, DOUBLE_VALUE, STRING_VALUE, {INT16_VALUE, -INT16_VALUE} + }; + vectorRes = m_proxy->getInts16FromStruct(b); + ASSERT_THAT(vectorRes, Eq(std::vector{INT16_VALUE, INT16_VALUE, -INT16_VALUE})); +} + +TEST_F(SdbusTestObject, CallsMethodWithVariantSuccesfully) +{ + sdbus::Variant v{DOUBLE_VALUE}; + auto variantRes = m_proxy->processVariant(v); + ASSERT_THAT(variantRes.get(), Eq(static_cast(DOUBLE_VALUE))); +} + +TEST_F(SdbusTestObject, CallsMethodWithStructVariantsAndGetMapSuccesfully) +{ + std::vector x{-2, 0, 2}; + sdbus::Struct y{false, true}; + auto mapOfVariants = m_proxy->getMapOfVariants(x, y); + decltype(mapOfVariants) res{{-2, false}, {0, false}, {2, true}}; + + ASSERT_THAT(mapOfVariants[-2].get(), Eq(res[-2].get())); + ASSERT_THAT(mapOfVariants[0].get(), Eq(res[0].get())); + ASSERT_THAT(mapOfVariants[2].get(), Eq(res[2].get())); +} + +TEST_F(SdbusTestObject, CallsMethodWithStructInStructSuccesfully) +{ + auto val = m_proxy->getStructInStruct(); + ASSERT_THAT(val.get<0>(), Eq(STRING_VALUE)); + ASSERT_THAT(std::get<0>(std::get<1>(val))[INT32_VALUE], Eq(INT32_VALUE)); +} + +TEST_F(SdbusTestObject, CallsMethodWithTwoStructsSuccesfully) +{ + auto val = m_proxy->sumStructItems({1, 2}, {3, 4}); + ASSERT_THAT(val, Eq(1 + 2 + 3 + 4)); +} + +TEST_F(SdbusTestObject, CallsMethodWithTwoVectorsSuccesfully) +{ + auto val = m_proxy->sumVectorItems({1, 7}, {2, 3}); + ASSERT_THAT(val, Eq(1 + 7 + 2 + 3)); +} + +TEST_F(SdbusTestObject, CallsMethodWithSignatureSuccesfully) +{ + auto resSignature = m_proxy->getSignature(); + ASSERT_THAT(resSignature, Eq(SIGNATURE_VALUE)); +} + +TEST_F(SdbusTestObject, CallsMethodWithObjectPathSuccesfully) +{ + auto resObjectPath = m_proxy->getObjectPath(); + ASSERT_THAT(resObjectPath, Eq(OBJECT_PATH_VALUE)); +} + +TEST_F(SdbusTestObject, CallsMethodWithUnixFdSuccesfully) +{ + auto resUnixFd = m_proxy->getUnixFd(); + ASSERT_THAT(resUnixFd.get(), Gt(UNIX_FD_VALUE)); +} + +TEST_F(SdbusTestObject, CallsMethodWithComplexTypeSuccesfully) +{ + auto resComplex = m_proxy->getComplex(); + ASSERT_THAT(resComplex.count(0), Eq(1)); +} + +TEST_F(SdbusTestObject, CallsMultiplyMethodWithNoReplyFlag) +{ + m_proxy->multiplyWithNoReply(INT64_VALUE, DOUBLE_VALUE); + + ASSERT_TRUE(waitUntil(m_adaptor->m_wasMultiplyCalled)); + ASSERT_THAT(m_adaptor->m_multiplyResult, Eq(INT64_VALUE * DOUBLE_VALUE)); +} + +TEST_F(SdbusTestObject, CallsMethodWithCustomTimeoutSuccessfully) +{ + auto res = m_proxy->doOperationWith500msTimeout(20); // The operation will take 20ms, but the timeout is 500ms, so we are fine + ASSERT_THAT(res, Eq(20)); +} + +TEST_F(SdbusTestObject, ThrowsTimeoutErrorWhenMethodTimesOut) +{ + try + { + m_proxy->doOperationWith500msTimeout(1000); // The operation will take 1s, but the timeout is 500ms, so we should time out + FAIL() << "Expected sdbus::Error exception"; + } + catch (const sdbus::Error& e) + { + ASSERT_THAT(e.getName(), AnyOf("org.freedesktop.DBus.Error.Timeout", "org.freedesktop.DBus.Error.NoReply")); + ASSERT_THAT(e.getMessage(), AnyOf("Connection timed out", "Method call timed out")); + } + catch(...) + { + FAIL() << "Expected sdbus::Error exception"; + } +} + +TEST_F(SdbusTestObject, CallsMethodThatThrowsError) +{ + try + { + m_proxy->throwError(); + FAIL() << "Expected sdbus::Error exception"; + } + catch (const sdbus::Error& e) + { + ASSERT_THAT(e.getName(), Eq("org.freedesktop.DBus.Error.AccessDenied")); + ASSERT_THAT(e.getMessage(), Eq("A test error occurred (Operation not permitted)")); + } + catch(...) + { + FAIL() << "Expected sdbus::Error exception"; + } +} + +TEST_F(SdbusTestObject, CallsErrorThrowingMethodWithDontExpectReplySet) +{ + ASSERT_NO_THROW(m_proxy->throwErrorWithNoReply()); + + ASSERT_TRUE(waitUntil(m_adaptor->m_wasThrowErrorCalled)); +} + +TEST_F(SdbusTestObject, FailsCallingNonexistentMethod) +{ + ASSERT_THROW(m_proxy->callNonexistentMethod(), sdbus::Error); +} + +TEST_F(SdbusTestObject, FailsCallingMethodOnNonexistentInterface) +{ + ASSERT_THROW(m_proxy->callMethodOnNonexistentInterface(), sdbus::Error); +} + +TEST_F(SdbusTestObject, FailsCallingMethodOnNonexistentDestination) +{ + TestProxy proxy("sdbuscpp.destination.that.does.not.exist", OBJECT_PATH); + ASSERT_THROW(proxy.getInt(), sdbus::Error); +} + +TEST_F(SdbusTestObject, FailsCallingMethodOnNonexistentObject) +{ + TestProxy proxy(INTERFACE_NAME, "/sdbuscpp/path/that/does/not/exist"); + ASSERT_THROW(proxy.getInt(), sdbus::Error); +} + +TEST_F(SdbusTestObject, CanReceiveSignalWhileMakingMethodCall) +{ + m_proxy->emitTwoSimpleSignals(); + + ASSERT_TRUE(waitUntil(m_proxy->m_gotSimpleSignal)); + ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithMap)); +} + +#if LIBSYSTEMD_VERSION>=240 +TEST_F(SdbusTestObject, CanSetGeneralMethodTimeoutWithLibsystemdVersionGreaterThan239) +{ + s_connection->setMethodCallTimeout(5000000); + ASSERT_THAT(s_connection->getMethodCallTimeout(), Eq(5000000)); +} +#else +TEST_F(SdbusTestObject, CannotSetGeneralMethodTimeoutWithLibsystemdVersionLessThan240) +{ + ASSERT_THROW(s_connection->setMethodCallTimeout(5000000), sdbus::Error); + ASSERT_THROW(s_connection->getMethodCallTimeout(), sdbus::Error); +} +#endif diff --git a/tests/integrationtests/DBusPropertiesTests.cpp b/tests/integrationtests/DBusPropertiesTests.cpp new file mode 100644 index 0000000..5ab712c --- /dev/null +++ b/tests/integrationtests/DBusPropertiesTests.cpp @@ -0,0 +1,74 @@ +/** + * (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2020 Stanislav Angelovic + * + * @file DBusPropertiesTests.cpp + * + * Created on: Jan 2, 2017 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#include "TestFixture.h" +#include "TestAdaptor.h" +#include "TestProxy.h" +#include "sdbus-c++/sdbus-c++.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using ::testing::Eq; +using ::testing::DoubleEq; +using ::testing::Gt; +using ::testing::AnyOf; +using ::testing::ElementsAre; +using ::testing::SizeIs; +using namespace std::chrono_literals; +using namespace sdbus::test; + +using SdbusTestObject = TestFixture; + +/*-------------------------------------*/ +/* -- TEST CASES -- */ +/*-------------------------------------*/ + +TEST_F(SdbusTestObject, ReadsReadOnlyPropertySuccesfully) +{ + ASSERT_THAT(m_proxy->state(), Eq(DEFAULT_STATE_VALUE)); +} + +TEST_F(SdbusTestObject, FailsWritingToReadOnlyProperty) +{ + ASSERT_THROW(m_proxy->setStateProperty("new_value"), sdbus::Error); +} + +TEST_F(SdbusTestObject, WritesAndReadsReadWritePropertySuccesfully) +{ + uint32_t newActionValue = 5678; + + m_proxy->action(newActionValue); + + ASSERT_THAT(m_proxy->action(), Eq(newActionValue)); +} diff --git a/tests/integrationtests/DBusSignalsTests.cpp b/tests/integrationtests/DBusSignalsTests.cpp new file mode 100644 index 0000000..bbf6b35 --- /dev/null +++ b/tests/integrationtests/DBusSignalsTests.cpp @@ -0,0 +1,94 @@ +/** + * (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2019 Stanislav Angelovic + * + * @file AdaptorAndProxy_test.cpp + * + * Created on: Jan 2, 2017 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#include "TestFixture.h" +#include "TestAdaptor.h" +#include "TestProxy.h" +#include "sdbus-c++/sdbus-c++.h" + +#include +#include +#include + +using ::testing::Eq; +using ::testing::DoubleEq; +using ::testing::Gt; +using ::testing::AnyOf; +using ::testing::ElementsAre; +using ::testing::SizeIs; +using namespace std::chrono_literals; +using namespace sdbus::test; + +using SdbusTestObject = TestFixture; + +/*-------------------------------------*/ +/* -- TEST CASES -- */ +/*-------------------------------------*/ + +TEST_F(SdbusTestObject, EmitsSimpleSignalSuccesfully) +{ + m_adaptor->emitSimpleSignal(); + + ASSERT_TRUE(waitUntil(m_proxy->m_gotSimpleSignal)); +} + +TEST_F(SdbusTestObject, EmitsSimpleSignalToMultipleProxiesSuccesfully) +{ + auto proxy1 = std::make_unique(*s_connection, INTERFACE_NAME, OBJECT_PATH); + auto proxy2 = std::make_unique(*s_connection, INTERFACE_NAME, OBJECT_PATH); + + m_adaptor->emitSimpleSignal(); + + ASSERT_TRUE(waitUntil(m_proxy->m_gotSimpleSignal)); + ASSERT_TRUE(waitUntil(proxy1->m_gotSimpleSignal)); + ASSERT_TRUE(waitUntil(proxy2->m_gotSimpleSignal)); +} + +TEST_F(SdbusTestObject, EmitsSignalWithMapSuccesfully) +{ + m_adaptor->emitSignalWithMap({{0, "zero"}, {1, "one"}}); + + ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithMap)); + ASSERT_THAT(m_proxy->m_mapFromSignal[0], Eq("zero")); + ASSERT_THAT(m_proxy->m_mapFromSignal[1], Eq("one")); +} + +TEST_F(SdbusTestObject, EmitsSignalWithVariantSuccesfully) +{ + double d = 3.14; + m_adaptor->emitSignalWithVariant(d); + + ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithVariant)); + ASSERT_THAT(m_proxy->m_variantFromSignal, DoubleEq(d)); +} + +TEST_F(SdbusTestObject, EmitsSignalWithoutRegistrationSuccesfully) +{ + m_adaptor->emitSignalWithoutRegistration({"platform", {"av"}}); + + ASSERT_TRUE(waitUntil(m_proxy->m_gotSignalWithSignature)); + ASSERT_THAT(m_proxy->m_signatureFromSignal["platform"], Eq("av")); +} diff --git a/tests/integrationtests/DBusStandardInterfacesTests.cpp b/tests/integrationtests/DBusStandardInterfacesTests.cpp new file mode 100644 index 0000000..bef754e --- /dev/null +++ b/tests/integrationtests/DBusStandardInterfacesTests.cpp @@ -0,0 +1,259 @@ +/** + * (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2020 Stanislav Angelovic + * + * @file DBusStandardInterfacesTests.cpp + * + * Created on: Jan 2, 2017 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#include "TestFixture.h" +#include "TestAdaptor.h" +#include "TestProxy.h" +#include "sdbus-c++/sdbus-c++.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using ::testing::Eq; +using ::testing::DoubleEq; +using ::testing::Gt; +using ::testing::AnyOf; +using ::testing::ElementsAre; +using ::testing::SizeIs; +using namespace std::chrono_literals; +using namespace sdbus::test; + +using SdbusTestObject = TestFixture; + +/*-------------------------------------*/ +/* -- TEST CASES -- */ +/*-------------------------------------*/ + +TEST_F(SdbusTestObject, PingsViaPeerInterface) +{ + ASSERT_NO_THROW(m_proxy->Ping()); +} + +TEST_F(SdbusTestObject, AnswersMachineUuidViaPeerInterface) +{ + // If /etc/machine-id does not exist in your system (which is very likely because you have + // a non-systemd Linux), org.freedesktop.DBus.Peer.GetMachineId() will not work. To solve + // this, you can create /etc/machine-id yourself as symlink to /var/lib/dbus/machine-id, + // and then org.freedesktop.DBus.Peer.GetMachineId() will start to work. + if (::access("/etc/machine-id", F_OK) == -1) + GTEST_SKIP() << "/etc/machine-id file does not exist, GetMachineId() will not work"; + + ASSERT_NO_THROW(m_proxy->GetMachineId()); +} + +// TODO: Adjust expected xml and uncomment this test +//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(), 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(), Eq(DEFAULT_STATE_VALUE)); + EXPECT_THAT(properties.at("action").get(), Eq(DEFAULT_ACTION_VALUE)); + EXPECT_THAT(properties.at("blocking").get(), Eq(DEFAULT_BLOCKING_VALUE)); +} + +TEST_F(SdbusTestObject, EmitsPropertyChangedSignalForSelectedProperties) +{ + std::atomic signalReceived{false}; + m_proxy->m_onPropertiesChangedHandler = [&signalReceived]( const std::string& interfaceName + , const std::map& changedProperties + , const std::vector& /*invalidatedProperties*/ ) + { + EXPECT_THAT(interfaceName, Eq(INTERFACE_NAME)); + EXPECT_THAT(changedProperties, SizeIs(1)); + EXPECT_THAT(changedProperties.at("blocking").get(), Eq(!DEFAULT_BLOCKING_VALUE)); + signalReceived = true; + }; + + m_proxy->blocking(!DEFAULT_BLOCKING_VALUE); + m_proxy->action(DEFAULT_ACTION_VALUE*2); + m_adaptor->emitPropertiesChangedSignal(INTERFACE_NAME, {"blocking"}); + + ASSERT_TRUE(waitUntil(signalReceived)); +} + +TEST_F(SdbusTestObject, EmitsPropertyChangedSignalForAllProperties) +{ + std::atomic signalReceived{false}; + m_proxy->m_onPropertiesChangedHandler = [&signalReceived]( const std::string& interfaceName + , const std::map& changedProperties + , const std::vector& invalidatedProperties ) + { + EXPECT_THAT(interfaceName, Eq(INTERFACE_NAME)); + EXPECT_THAT(changedProperties, SizeIs(1)); + EXPECT_THAT(changedProperties.at("blocking").get(), Eq(DEFAULT_BLOCKING_VALUE)); + ASSERT_THAT(invalidatedProperties, SizeIs(1)); + EXPECT_THAT(invalidatedProperties[0], Eq("action")); + signalReceived = true; + }; + + m_adaptor->emitPropertiesChangedSignal(INTERFACE_NAME); + + ASSERT_TRUE(waitUntil(signalReceived)); +} + +TEST_F(SdbusTestObject, GetsZeroManagedObjectsIfHasNoSubPathObjects) +{ + const auto objectsInterfacesAndProperties = m_proxy->GetManagedObjects(); + + ASSERT_THAT(objectsInterfacesAndProperties, SizeIs(0)); +} + +TEST_F(SdbusTestObject, GetsManagedObjectsSuccessfully) +{ + 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(), Eq(123)); + EXPECT_THAT(objectsInterfacesAndProperties.at("/sub/path2").at("org.sdbuscpp.integrationtests.iface2").at("aProperty2").get(), Eq("hi")); +} + +TEST_F(SdbusTestObject, EmitsInterfacesAddedSignalForSelectedObjectInterfaces) +{ + std::atomic signalReceived{false}; + m_proxy->m_onInterfacesAddedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath + , const std::map>& interfacesAndProperties ) + { + EXPECT_THAT(objectPath, Eq(OBJECT_PATH)); + EXPECT_THAT(interfacesAndProperties, SizeIs(1)); + EXPECT_THAT(interfacesAndProperties.count(INTERFACE_NAME), Eq(1)); +#if LIBSYSTEMD_VERSION<=244 + // Up to sd-bus v244, all properties are added to the list, i.e. `state', `action', and `blocking' in this case. + EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(3)); + EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("state")); + EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("action")); + EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("blocking")); +#else + // Since v245 sd-bus does not add to the InterfacesAdded signal message the values of properties marked only + // for invalidation on change, which makes the behavior consistent with the PropertiesChangedSignal. + // So in this specific instance, `action' property is no more added to the list. + EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(2)); + EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("state")); + EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("blocking")); +#endif + signalReceived = true; + }; + + m_adaptor->emitInterfacesAddedSignal({INTERFACE_NAME}); + + ASSERT_TRUE(waitUntil(signalReceived)); +} + +TEST_F(SdbusTestObject, EmitsInterfacesAddedSignalForAllObjectInterfaces) +{ + std::atomic signalReceived{false}; + m_proxy->m_onInterfacesAddedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath + , const std::map>& interfacesAndProperties ) + { + EXPECT_THAT(objectPath, Eq(OBJECT_PATH)); + EXPECT_THAT(interfacesAndProperties, SizeIs(5)); // INTERFACE_NAME + 4 standard interfaces +#if LIBSYSTEMD_VERSION<=244 + // Up to sd-bus v244, all properties are added to the list, i.e. `state', `action', and `blocking' in this case. + EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(3)); + EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("state")); + EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("action")); + EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("blocking")); +#else + // Since v245 sd-bus does not add to the InterfacesAdded signal message the values of properties marked only + // for invalidation on change, which makes the behavior consistent with the PropertiesChangedSignal. + // So in this specific instance, `action' property is no more added to the list. + EXPECT_THAT(interfacesAndProperties.at(INTERFACE_NAME), SizeIs(2)); + EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("state")); + EXPECT_TRUE(interfacesAndProperties.at(INTERFACE_NAME).count("blocking")); +#endif + signalReceived = true; + }; + + m_adaptor->emitInterfacesAddedSignal(); + + ASSERT_TRUE(waitUntil(signalReceived)); +} + +TEST_F(SdbusTestObject, EmitsInterfacesRemovedSignalForSelectedObjectInterfaces) +{ + std::atomic signalReceived{false}; + m_proxy->m_onInterfacesRemovedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath + , const std::vector& interfaces ) + { + EXPECT_THAT(objectPath, Eq(OBJECT_PATH)); + ASSERT_THAT(interfaces, SizeIs(1)); + EXPECT_THAT(interfaces[0], Eq(INTERFACE_NAME)); + signalReceived = true; + }; + + m_adaptor->emitInterfacesRemovedSignal({INTERFACE_NAME}); + + ASSERT_TRUE(waitUntil(signalReceived)); +} + +TEST_F(SdbusTestObject, EmitsInterfacesRemovedSignalForAllObjectInterfaces) +{ + std::atomic signalReceived{false}; + m_proxy->m_onInterfacesRemovedHandler = [&signalReceived]( const sdbus::ObjectPath& objectPath + , const std::vector& interfaces ) + { + EXPECT_THAT(objectPath, Eq(OBJECT_PATH)); + ASSERT_THAT(interfaces, SizeIs(5)); // INTERFACE_NAME + 4 standard interfaces + signalReceived = true; + }; + + m_adaptor->emitInterfacesRemovedSignal(); + + ASSERT_TRUE(waitUntil(signalReceived)); +} diff --git a/tests/integrationtests/defs.h b/tests/integrationtests/Defs.h similarity index 96% rename from tests/integrationtests/defs.h rename to tests/integrationtests/Defs.h index 985d522..7dcc4d9 100644 --- a/tests/integrationtests/defs.h +++ b/tests/integrationtests/Defs.h @@ -2,7 +2,7 @@ * (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland * (C) 2016 - 2019 Stanislav Angelovic * - * @file defs.h + * @file Defs.h * * Created on: Jan 2, 2017 * Project: sdbus-c++ @@ -29,6 +29,8 @@ #include "sdbus-c++/Types.h" +namespace sdbus { namespace test { + const std::string INTERFACE_NAME{"org.sdbuscpp.integrationtests"}; const std::string OBJECT_PATH{"/"}; @@ -49,4 +51,6 @@ const bool DEFAULT_BLOCKING_VALUE{true}; constexpr const double DOUBLE_VALUE{3.24L}; +}} + #endif /* SDBUS_CPP_INTEGRATIONTESTS_DEFS_H_ */ diff --git a/tests/integrationtests/TestAdaptor.cpp b/tests/integrationtests/TestAdaptor.cpp new file mode 100644 index 0000000..b66c963 --- /dev/null +++ b/tests/integrationtests/TestAdaptor.cpp @@ -0,0 +1,416 @@ +/** + * (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2019 Stanislav Angelovic + * + * @file TestAdaptor.cpp + * + * Created on: May 23, 2020 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#include "TestAdaptor.h" +#include +#include +#include + +namespace sdbus { namespace test { + +TestAdaptor::TestAdaptor(sdbus::IConnection& connection) : + AdaptorInterfaces(connection, OBJECT_PATH) +{ + registerAdaptor(); +} + +TestAdaptor::~TestAdaptor() +{ + unregisterAdaptor(); +} + +void TestAdaptor::noArgNoReturn() +{ +} + +int32_t TestAdaptor::getInt() +{ + return INT32_VALUE; +} + +std::tuple TestAdaptor::getTuple() +{ + return std::make_tuple(UINT32_VALUE, STRING_VALUE); +} + +double TestAdaptor::multiply(const int64_t& a, const double& b) +{ + return a * b; +} + +void TestAdaptor::multiplyWithNoReply(const int64_t& a, const double& b) +{ + m_multiplyResult = a * b; + m_wasMultiplyCalled = true; +} + +std::vector TestAdaptor::getInts16FromStruct(const sdbus::Struct>& x) +{ + std::vector res{x.get<1>()}; + auto y = std::get>(x); + res.insert(res.end(), y.begin(), y.end()); + return res; +} + +sdbus::Variant TestAdaptor::processVariant(const sdbus::Variant& v) +{ + sdbus::Variant res = static_cast(v.get()); + return res; +} + +std::map TestAdaptor::getMapOfVariants(const std::vector& x, const sdbus::Struct& y) +{ + std::map res; + for (auto item : x) + { + res[item] = (item <= 0) ? std::get<0>(y) : std::get<1>(y); + } + return res; +} + +sdbus::Struct>> TestAdaptor::getStructInStruct() +{ + return sdbus::make_struct(STRING_VALUE, sdbus::make_struct(std::map{{INT32_VALUE, INT32_VALUE}})); +} + +int32_t TestAdaptor::sumStructItems(const sdbus::Struct& a, const sdbus::Struct& b) +{ + int32_t res{0}; + res += std::get<0>(a) + std::get<1>(a); + res += std::get<0>(b) + std::get<1>(b); + return res; +} + +uint32_t TestAdaptor::sumVectorItems(const std::vector& a, const std::vector& b) +{ + uint32_t res{0}; + for (auto x : a) + { + res += x; + } + for (auto x : b) + { + res += x; + } + return res; +} + +uint32_t TestAdaptor::doOperation(const uint32_t& param) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(param)); + return param; +} + +void TestAdaptor::doOperationAsync(sdbus::Result&& result, uint32_t param) +{ + if (param == 0) + { + // Don't sleep and return the result from this thread + result.returnResults(param); + } + else + { + // Process asynchronously in another thread and return the result from there + std::thread([param, result = std::move(result)]() + { + std::this_thread::sleep_for(std::chrono::milliseconds(param)); + result.returnResults(param); + }).detach(); + } +} + +sdbus::Signature TestAdaptor::getSignature() +{ + return SIGNATURE_VALUE; +} +sdbus::ObjectPath TestAdaptor::getObjectPath() +{ + return OBJECT_PATH_VALUE; +} +sdbus::UnixFd TestAdaptor::getUnixFd() +{ + return sdbus::UnixFd{UNIX_FD_VALUE}; +} + +std::map>>>, sdbus::Signature, std::string>> TestAdaptor::getComplex() +{ + return { // map + { + 0, // uint_64_t + { // struct + { // map + { + 23, // uint8_t + { // vector + { // struct + "/object/path", // object path + false, + Variant{3.14}, + { // map + {0, "zero"} + } + } + } + } + }, + "a{t(a{ya(obva{is})}gs)}", // signature + std::string{} + } + } + }; +} + +void TestAdaptor::throwError() +{ + m_wasThrowErrorCalled = true; + throw sdbus::createError(1, "A test error occurred"); +} + +void TestAdaptor::throwErrorWithNoReply() +{ + TestAdaptor::throwError(); +} + +void TestAdaptor::doPrivilegedStuff() +{ + // Intentionally left blank +} + +void TestAdaptor::emitTwoSimpleSignals() +{ + emitSimpleSignal(); + emitSignalWithMap({}); +} + +std::string TestAdaptor::state() +{ + return m_state; +} + +uint32_t TestAdaptor::action() +{ + return m_action; +} + +void TestAdaptor::action(const uint32_t& value) +{ + m_action = value; +} + +bool TestAdaptor::blocking() +{ + return m_blocking; +} + +void TestAdaptor::blocking(const bool& value) +{ + m_blocking = value; +} + +void TestAdaptor::emitSignalWithoutRegistration(const sdbus::Struct>& s) +{ + getObject().emitSignal("signalWithoutRegistration").onInterface(sdbus::test::INTERFACE_NAME).withArguments(s); +} + +std::string TestAdaptor::getExpectedXmlApiDescription() const +{ + return +R"delimiter( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +)delimiter" +#if LIBSYSTEMD_VERSION>=242 +R"delimiter( +)delimiter" +#else +R"delimiter( +)delimiter" +#endif +R"delimiter( + + + + + +)delimiter" +#if LIBSYSTEMD_VERSION>=242 +R"delimiter( + + +)delimiter" +#else +R"delimiter( + + +)delimiter" +#endif +R"delimiter( + + + + + + + + + + + + + + + + + +)delimiter" +#if LIBSYSTEMD_VERSION>=242 +R"delimiter( + + +)delimiter" +#else +R"delimiter( + + +)delimiter" +#endif +R"delimiter( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +)delimiter"; +} + +}} diff --git a/tests/integrationtests/TestAdaptor.h b/tests/integrationtests/TestAdaptor.h new file mode 100644 index 0000000..89b738b --- /dev/null +++ b/tests/integrationtests/TestAdaptor.h @@ -0,0 +1,93 @@ +/** + * (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2019 Stanislav Angelovic + * + * @file TestAdaptor.h + * + * Created on: Jan 2, 2017 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#ifndef SDBUS_CPP_INTEGRATIONTESTS_TESTADAPTOR_H_ +#define SDBUS_CPP_INTEGRATIONTESTS_TESTADAPTOR_H_ + +#include "integrationtests-adaptor.h" +#include "Defs.h" +#include +#include +#include + +namespace sdbus { namespace test { + +class TestAdaptor final : public sdbus::AdaptorInterfaces< org::sdbuscpp::integrationtests_adaptor + , sdbus::Properties_adaptor + , sdbus::ObjectManager_adaptor > +{ +public: + TestAdaptor(sdbus::IConnection& connection); + ~TestAdaptor(); + +protected: + void noArgNoReturn() override; + int32_t getInt() override; + std::tuple getTuple() override; + double multiply(const int64_t& a, const double& b) override; + void multiplyWithNoReply(const int64_t& a, const double& b) override; + std::vector getInts16FromStruct(const sdbus::Struct>& arg0) override; + sdbus::Variant processVariant(const sdbus::Variant& variant) override; + std::map getMapOfVariants(const std::vector& x, const sdbus::Struct& y) override; + sdbus::Struct>> getStructInStruct() override; + int32_t sumStructItems(const sdbus::Struct& arg0, const sdbus::Struct& arg1) override; + uint32_t sumVectorItems(const std::vector& arg0, const std::vector& arg1) override; + uint32_t doOperation(const uint32_t& arg0) override; + void doOperationAsync(sdbus::Result&& result, uint32_t arg0) override; + sdbus::Signature getSignature() override; + sdbus::ObjectPath getObjectPath() override; + sdbus::UnixFd getUnixFd() override; + std::map>>>, sdbus::Signature, std::string>> getComplex() override; + void throwError() override; + void throwErrorWithNoReply() override; + void doPrivilegedStuff() override; + void emitTwoSimpleSignals() override; + + uint32_t action() override; + void action(const uint32_t& value) override; + bool blocking() override; + void blocking(const bool& value) override; + std::string state() override; + +public: + void emitSignalWithoutRegistration(const sdbus::Struct>& s); + std::string getExpectedXmlApiDescription() const; + +private: + const std::string m_state{DEFAULT_STATE_VALUE}; + uint32_t m_action{DEFAULT_ACTION_VALUE}; + bool m_blocking{DEFAULT_BLOCKING_VALUE}; + +public: // for tests + // For dont-expect-reply method call verifications + mutable std::atomic m_wasMultiplyCalled{false}; + mutable double m_multiplyResult{}; + mutable std::atomic m_wasThrowErrorCalled{false}; +}; + +}} + +#endif /* INTEGRATIONTESTS_TESTADAPTOR_H_ */ diff --git a/tests/integrationtests/TestFixture.cpp b/tests/integrationtests/TestFixture.cpp new file mode 100644 index 0000000..e49b395 --- /dev/null +++ b/tests/integrationtests/TestFixture.cpp @@ -0,0 +1,33 @@ +/** + * (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2019 Stanislav Angelovic + * + * @file TestAdaptor.cpp + * + * Created on: May 23, 2020 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#include "TestFixture.h" + +namespace sdbus { namespace test { + +std::unique_ptr TestFixture::s_connection = sdbus::createSystemBusConnection(); + +}} diff --git a/tests/integrationtests/TestFixture.h b/tests/integrationtests/TestFixture.h new file mode 100644 index 0000000..88cc32f --- /dev/null +++ b/tests/integrationtests/TestFixture.h @@ -0,0 +1,104 @@ +/** + * (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2019 Stanislav Angelovic + * + * @file TestAdaptor.h + * + * Created on: Jan 2, 2017 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#ifndef SDBUS_CPP_INTEGRATIONTESTS_TESTFIXTURE_H_ +#define SDBUS_CPP_INTEGRATIONTESTS_TESTFIXTURE_H_ + +#include "TestAdaptor.h" +#include "TestProxy.h" +#include "Defs.h" + +#include +#include + +#include +#include +#include +#include + +namespace sdbus { namespace test { + +class TestFixture : public ::testing::Test +{ +public: + static void SetUpTestCase() + { + s_connection->requestName(INTERFACE_NAME); + s_connection->enterEventLoopAsync(); + } + + static void TearDownTestCase() + { + s_connection->leaveEventLoop(); + s_connection->releaseName(INTERFACE_NAME); + } + + template + static bool waitUntil(_Fnc&& fnc, std::chrono::milliseconds timeout = std::chrono::seconds(5)) + { + using namespace std::chrono_literals; + + std::chrono::milliseconds elapsed{}; + std::chrono::milliseconds step{5ms}; + do { + std::this_thread::sleep_for(step); + elapsed += step; + if (elapsed > timeout) + return false; + } while (!fnc()); + + return true; + } + + static bool waitUntil(std::atomic& flag, std::chrono::milliseconds timeout = std::chrono::seconds(5)) + { + return waitUntil([&flag]() -> bool { return flag; }, timeout); + } + +private: + void SetUp() override + { + m_adaptor = std::make_unique(*s_connection); + m_proxy = std::make_unique(INTERFACE_NAME, OBJECT_PATH); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); // Give time for the proxy to start listening to signals + } + + void TearDown() override + { + m_proxy.reset(); + m_adaptor.reset(); + } + +public: + static std::unique_ptr s_connection; + + std::unique_ptr m_adaptor; + std::unique_ptr m_proxy; +}; + +}} + +#endif /* SDBUS_CPP_INTEGRATIONTESTS_TESTFIXTURE_H_ */ diff --git a/tests/integrationtests/TestProxy.cpp b/tests/integrationtests/TestProxy.cpp new file mode 100644 index 0000000..91a9cd4 --- /dev/null +++ b/tests/integrationtests/TestProxy.cpp @@ -0,0 +1,170 @@ +/** + * (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland + * (C) 2016 - 2019 Stanislav Angelovic + * + * @file TestAdaptor.cpp + * + * Created on: May 23, 2020 + * Project: sdbus-c++ + * Description: High-level D-Bus IPC C++ library based on sd-bus + * + * This file is part of sdbus-c++. + * + * sdbus-c++ is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * sdbus-c++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with sdbus-c++. If not, see . + */ + +#include "TestProxy.h" +#include +#include +#include + +namespace sdbus { namespace test { + +TestProxy::TestProxy(std::string destination, std::string objectPath) + : ProxyInterfaces(std::move(destination), std::move(objectPath)) +{ + getProxy().uponSignal("signalWithoutRegistration").onInterface(sdbus::test::INTERFACE_NAME).call([this](const sdbus::Struct>& s){ this->onSignalWithoutRegistration(s); }); + + registerProxy(); +} + +TestProxy::TestProxy(sdbus::IConnection& connection, std::string destination, std::string objectPath) + : ProxyInterfaces(connection, std::move(destination), std::move(objectPath)) +{ + getProxy().uponSignal("signalWithoutRegistration").onInterface(sdbus::test::INTERFACE_NAME).call([this](const sdbus::Struct>& s){ this->onSignalWithoutRegistration(s); }); + + registerProxy(); +} + +TestProxy::~TestProxy() +{ + unregisterProxy(); +} + +void TestProxy::onSimpleSignal() +{ + m_gotSimpleSignal = true; +} + +void TestProxy::onSignalWithMap(const std::map& aMap) +{ + m_mapFromSignal = aMap; + m_gotSignalWithMap = true; +} + +void TestProxy::onSignalWithVariant(const sdbus::Variant& aVariant) +{ + m_variantFromSignal = aVariant.get(); + m_gotSignalWithVariant = true; +} + +void TestProxy::onSignalWithoutRegistration(const sdbus::Struct>& s) +{ + m_signatureFromSignal[std::get<0>(s)] = static_cast(std::get<0>(std::get<1>(s))); + m_gotSignalWithSignature = true; +} + +void TestProxy::onDoOperationReply(uint32_t returnValue, const sdbus::Error* error) +{ + if (m_DoOperationClientSideAsyncReplyHandler) + m_DoOperationClientSideAsyncReplyHandler(returnValue, error); +} + +void TestProxy::onPropertiesChanged( const std::string& interfaceName + , const std::map& changedProperties + , const std::vector& invalidatedProperties ) +{ + if (m_onPropertiesChangedHandler) + m_onPropertiesChangedHandler(interfaceName, changedProperties, invalidatedProperties); +} + +void TestProxy::onInterfacesAdded(const sdbus::ObjectPath& objectPath, const std::map>& interfacesAndProperties) +{ + if (m_onInterfacesAddedHandler) + m_onInterfacesAddedHandler(objectPath, interfacesAndProperties); +} + +void TestProxy::onInterfacesRemoved(const sdbus::ObjectPath& objectPath, const std::vector& interfaces) +{ + if (m_onInterfacesRemovedHandler) + m_onInterfacesRemovedHandler(objectPath, interfaces); +} + +void TestProxy::installDoOperationClientSideAsyncReplyHandler(std::function handler) +{ + m_DoOperationClientSideAsyncReplyHandler = std::move(handler); +} + +uint32_t TestProxy::doOperationWith500msTimeout(uint32_t param) +{ + using namespace std::chrono_literals; + uint32_t result; + getProxy().callMethod("doOperation").onInterface(sdbus::test::INTERFACE_NAME).withTimeout(500000us).withArguments(param).storeResultsTo(result); + return result; +} + +sdbus::PendingAsyncCall TestProxy::doOperationClientSideAsync(uint32_t param) +{ + return getProxy().callMethodAsync("doOperation") + .onInterface(sdbus::test::INTERFACE_NAME) + .withArguments(param) + .uponReplyInvoke([this](const sdbus::Error* error, uint32_t returnValue) + { + this->onDoOperationReply(returnValue, error); + }); +} + +void TestProxy::doErroneousOperationClientSideAsync() +{ + getProxy().callMethodAsync("throwError") + .onInterface(sdbus::test::INTERFACE_NAME) + .uponReplyInvoke([this](const sdbus::Error* error) + { + this->onDoOperationReply(0, error); + }); +} + +void TestProxy::doOperationClientSideAsyncWith500msTimeout(uint32_t param) +{ + using namespace std::chrono_literals; + getProxy().callMethodAsync("doOperation") + .onInterface(sdbus::test::INTERFACE_NAME) + .withTimeout(500000us) + .withArguments(param) + .uponReplyInvoke([this](const sdbus::Error* error, uint32_t returnValue) + { + this->onDoOperationReply(returnValue, error); + }); +} + +int32_t TestProxy::callNonexistentMethod() +{ + int32_t result; + getProxy().callMethod("callNonexistentMethod").onInterface(sdbus::test::INTERFACE_NAME).storeResultsTo(result); + return result; +} + +int32_t TestProxy::callMethodOnNonexistentInterface() +{ + int32_t result; + getProxy().callMethod("someMethod").onInterface("sdbuscpp.interface.that.does.not.exist").storeResultsTo(result); + return result; +} + +void TestProxy::setStateProperty(const std::string& value) +{ + getProxy().setProperty("state").onInterface(sdbus::test::INTERFACE_NAME).toValue(value); +} + +}} diff --git a/tests/integrationtests/TestingProxy.h b/tests/integrationtests/TestProxy.h similarity index 51% rename from tests/integrationtests/TestingProxy.h rename to tests/integrationtests/TestProxy.h index c4ea3e0..d152474 100644 --- a/tests/integrationtests/TestingProxy.h +++ b/tests/integrationtests/TestProxy.h @@ -2,7 +2,7 @@ * (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland * (C) 2016 - 2019 Stanislav Angelovic * - * @file TestingProxy.h + * @file TestAdaptor.h * * Created on: Jan 2, 2017 * Project: sdbus-c++ @@ -24,93 +24,53 @@ * along with sdbus-c++. If not, see . */ -#ifndef SDBUS_CPP_INTEGRATIONTESTS_TESTINGPROXY_H_ -#define SDBUS_CPP_INTEGRATIONTESTS_TESTINGPROXY_H_ +#ifndef SDBUS_CPP_INTEGRATIONTESTS_TESTPROXY_H_ +#define SDBUS_CPP_INTEGRATIONTESTS_TESTPROXY_H_ -#include "proxy-glue.h" +#include "integrationtests-proxy.h" +#include "Defs.h" +#include +#include #include -class TestingProxy : public sdbus::ProxyInterfaces< ::testing_proxy - , sdbus::Peer_proxy - , sdbus::Introspectable_proxy - , sdbus::Properties_proxy - , sdbus::ObjectManager_proxy > +namespace sdbus { namespace test { + +class TestProxy final : public sdbus::ProxyInterfaces< org::sdbuscpp::integrationtests_proxy + , sdbus::Peer_proxy + , sdbus::Introspectable_proxy + , sdbus::Properties_proxy + , sdbus::ObjectManager_proxy > { public: - TestingProxy(std::string destination, std::string objectPath) - : ProxyInterfaces(std::move(destination), std::move(objectPath)) - { - registerProxy(); - } - - TestingProxy(sdbus::IConnection& connection, std::string destination, std::string objectPath) - : ProxyInterfaces(connection, std::move(destination), std::move(objectPath)) - { - registerProxy(); - } - - ~TestingProxy() - { - unregisterProxy(); - } - - void installDoOperationClientSideAsyncReplyHandler(std::function handler) - { - m_DoOperationClientSideAsyncReplyHandler = handler; - } + TestProxy(std::string destination, std::string objectPath); + TestProxy(sdbus::IConnection& connection, std::string destination, std::string objectPath); + ~TestProxy(); protected: - void onSimpleSignal() override - { - m_gotSimpleSignal = true; - } + void onSimpleSignal() override; + void onSignalWithMap(const std::map& aMap) override; + void onSignalWithVariant(const sdbus::Variant& aVariant) override; - void onSignalWithMap(const std::map& m) override - { - m_mapFromSignal = m; - m_gotSignalWithMap = true; - } - - void onSignalWithVariant(const sdbus::Variant& v) override - { - m_variantFromSignal = v.get(); - m_gotSignalWithVariant = true; - } - - void onSignalWithoutRegistration(const sdbus::Struct>& s) override - { - m_signatureFromSignal[std::get<0>(s)] = static_cast(std::get<0>(std::get<1>(s))); - m_gotSignalWithSignature = true; - } - - void onDoOperationReply(uint32_t returnValue, const sdbus::Error* error) override - { - if (m_DoOperationClientSideAsyncReplyHandler) - m_DoOperationClientSideAsyncReplyHandler(returnValue, error); - } + void onSignalWithoutRegistration(const sdbus::Struct>& s); + void onDoOperationReply(uint32_t returnValue, const sdbus::Error* error); // Signals of standard D-Bus interfaces - void onPropertiesChanged( const std::string& interfaceName , const std::map& changedProperties - , const std::vector& invalidatedProperties ) override - { - if (m_onPropertiesChangedHandler) - m_onPropertiesChangedHandler(interfaceName, changedProperties, invalidatedProperties); - } - + , const std::vector& invalidatedProperties ) override; void onInterfacesAdded( const sdbus::ObjectPath& objectPath - , const std::map>& interfacesAndProperties) override - { - if (m_onInterfacesAddedHandler) - m_onInterfacesAddedHandler(objectPath, interfacesAndProperties); - } - void onInterfacesRemoved( const sdbus::ObjectPath& objectPath - , const std::vector& interfaces) override - { - if (m_onInterfacesRemovedHandler) - m_onInterfacesRemovedHandler(objectPath, interfaces); - } + , const std::map>& interfacesAndProperties) override; + void onInterfacesRemoved( const sdbus::ObjectPath& objectPath, const std::vector& interfaces) override; + +public: + void installDoOperationClientSideAsyncReplyHandler(std::function handler); + uint32_t doOperationWith500msTimeout(uint32_t param); + sdbus::PendingAsyncCall doOperationClientSideAsync(uint32_t param); + void doErroneousOperationClientSideAsync(); + void doOperationClientSideAsyncWith500msTimeout(uint32_t param); + int32_t callNonexistentMethod(); + int32_t callMethodOnNonexistentInterface(); + void setStateProperty(const std::string& value); //private: public: // for tests @@ -129,4 +89,6 @@ public: // for tests std::function&)> m_onInterfacesRemovedHandler; }; -#endif /* SDBUS_CPP_INTEGRATIONTESTS_TESTINGPROXY_H_ */ +}} + +#endif /* SDBUS_CPP_INTEGRATIONTESTS_TESTPROXY_H_ */ diff --git a/tests/integrationtests/TestingAdaptor.h b/tests/integrationtests/TestingAdaptor.h deleted file mode 100644 index 2793987..0000000 --- a/tests/integrationtests/TestingAdaptor.h +++ /dev/null @@ -1,246 +0,0 @@ -/** - * (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland - * (C) 2016 - 2019 Stanislav Angelovic - * - * @file TestingAdaptor.h - * - * Created on: Jan 2, 2017 - * Project: sdbus-c++ - * Description: High-level D-Bus IPC C++ library based on sd-bus - * - * This file is part of sdbus-c++. - * - * sdbus-c++ is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 of the License, or - * (at your option) any later version. - * - * sdbus-c++ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with sdbus-c++. If not, see . - */ - -#ifndef SDBUS_CPP_INTEGRATIONTESTS_TESTINGADAPTOR_H_ -#define SDBUS_CPP_INTEGRATIONTESTS_TESTINGADAPTOR_H_ - -#include "adaptor-glue.h" -#include -#include -#include - -class TestingAdaptor : public sdbus::AdaptorInterfaces< testing_adaptor - , sdbus::Properties_adaptor - , sdbus::ObjectManager_adaptor > -{ -public: - TestingAdaptor(sdbus::IConnection& connection) : - AdaptorInterfaces(connection, OBJECT_PATH) - { - registerAdaptor(); - } - - ~TestingAdaptor() - { - unregisterAdaptor(); - } - -protected: - - void noArgNoReturn() const override - { - } - - int32_t getInt() const override - { - return INT32_VALUE; - } - - std::tuple getTuple() const override - { - return std::make_tuple(UINT32_VALUE, STRING_VALUE); - } - - double multiply(const int64_t& a, const double& b) const override - { - return a * b; - } - - void multiplyWithNoReply(const int64_t& a, const double& b) const override - { - m_multiplyResult = a * b; - m_wasMultiplyCalled = true; - } - - std::vector getInts16FromStruct(const sdbus::Struct>& x) const override - { - std::vector res{x.get<1>()}; - auto y = std::get>(x); - res.insert(res.end(), y.begin(), y.end()); - return res; - } - - sdbus::Variant processVariant(sdbus::Variant& v) override - { - sdbus::Variant res = static_cast(v.get()); - return res; - } - - std::map getMapOfVariants(const std::vector& x, const sdbus::Struct& y) const override - { - std::map res; - for (auto item : x) - { - res[item] = (item <= 0) ? std::get<0>(y) : std::get<1>(y); - } - return res; - } - - sdbus::Struct>> getStructInStruct() const override - { - return sdbus::make_struct(STRING_VALUE, sdbus::make_struct(std::map{{INT32_VALUE, INT32_VALUE}})); - } - - int32_t sumStructItems(const sdbus::Struct& a, const sdbus::Struct& b) override - { - int32_t res{0}; - res += std::get<0>(a) + std::get<1>(a); - res += std::get<0>(b) + std::get<1>(b); - return res; - } - - uint32_t sumVectorItems(const std::vector& a, const std::vector& b) override - { - uint32_t res{0}; - for (auto x : a) - { - res += x; - } - for (auto x : b) - { - res += x; - } - return res; - } - - uint32_t doOperation(uint32_t param) override - { - std::this_thread::sleep_for(std::chrono::milliseconds(param)); - return param; - } - - void doOperationAsync(uint32_t param, sdbus::Result result) override - { - if (param == 0) - { - // Don't sleep and return the result from this thread - result.returnResults(param); - } - else - { - // Process asynchronously in another thread and return the result from there - std::thread([param, result = std::move(result)]() - { - std::this_thread::sleep_for(std::chrono::milliseconds(param)); - result.returnResults(param); - }).detach(); - } - } - - sdbus::Signature getSignature() const override - { - return SIGNATURE_VALUE; - } - sdbus::ObjectPath getObjPath() const override - { - return OBJECT_PATH_VALUE; - } - sdbus::UnixFd getUnixFd() const override - { - return sdbus::UnixFd{UNIX_FD_VALUE}; - } - - ComplexType getComplex() const override - { - return { // map - { - 0, // uint_64_t - { // struct - { // map - { - 'a', // uint8_t - { // vector - { // struct - "/object/path", // object path - false, - 3.14, - { // map - {0, "zero"} - } - } - } - } - }, - "a{t(a{ya(obva{is})}gs)}", // signature - "" - } - } - }; - } - - void throwError() const override - { - m_wasThrowErrorCalled = true; - throw sdbus::createError(1, "A test error occurred"); - } - - - void emitTwoSimpleSignals() override - { - emitSimpleSignal(); - emitSignalWithMap({}); - } - - std::string state() override - { - return m_state; - } - - uint32_t action() override - { - return m_action; - } - - void action(const uint32_t& value) override - { - m_action = value; - } - - bool blocking() override - { - return m_blocking; - } - - void blocking(const bool& value) override - { - m_blocking = value; - } - -private: - const std::string m_state{DEFAULT_STATE_VALUE}; - uint32_t m_action{DEFAULT_ACTION_VALUE}; - bool m_blocking{DEFAULT_BLOCKING_VALUE}; - -public: // for tests - // For dont-expect-reply method call verifications - mutable std::atomic m_wasMultiplyCalled{false}; - mutable double m_multiplyResult{}; - mutable std::atomic m_wasThrowErrorCalled{false}; -}; - - - -#endif /* INTEGRATIONTESTS_TESTINGADAPTOR_H_ */ diff --git a/tests/integrationtests/adaptor-glue.h b/tests/integrationtests/adaptor-glue.h deleted file mode 100644 index d160e41..0000000 --- a/tests/integrationtests/adaptor-glue.h +++ /dev/null @@ -1,366 +0,0 @@ -/** - * (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland - * (C) 2016 - 2019 Stanislav Angelovic - * - * @file adaptor-glue.h - * - * Created on: Jan 2, 2017 - * Project: sdbus-c++ - * Description: High-level D-Bus IPC C++ library based on sd-bus - * - * This file is part of sdbus-c++. - * - * sdbus-c++ is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 of the License, or - * (at your option) any later version. - * - * sdbus-c++ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with sdbus-c++. If not, see . - */ - -#ifndef SDBUS_CPP_INTEGRATIONTESTS_ADAPTOR_GLUE_H_ -#define SDBUS_CPP_INTEGRATIONTESTS_ADAPTOR_GLUE_H_ - -#include "defs.h" - -// sdbus -#include "sdbus-c++/sdbus-c++.h" - -using ComplexType = std::map< - uint64_t, - sdbus::Struct< - std::map< - uint8_t, - std::vector< - sdbus::Struct< - sdbus::ObjectPath, - bool, - sdbus::Variant, - std::map - > - > - >, - sdbus::Signature, - std::string // char* leads to type and memory issues, std::string is best choice - > - >; - -class testing_adaptor -{ -protected: - testing_adaptor(sdbus::IObject& object) : - object_(object) - { - object_.setInterfaceFlags(INTERFACE_NAME).markAsDeprecated().withPropertyUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL); - - object_.registerMethod("noArgNoReturn").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->noArgNoReturn(); }); - object_.registerMethod("getInt").onInterface(INTERFACE_NAME).withOutputParamNames("anInt").implementedAs([this](){ return this->getInt(); }); - object_.registerMethod("getTuple").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getTuple(); }); - - object_.registerMethod("multiply").onInterface(INTERFACE_NAME).withInputParamNames("a", "b").withOutputParamNames("result").implementedAs([this](const int64_t& a, const double& b){ return this->multiply(a, b); }); - object_.registerMethod("multiplyWithNoReply").onInterface(INTERFACE_NAME).implementedAs([this](const int64_t& a, const double& b){ this->multiplyWithNoReply(a, b); }).markAsDeprecated().withNoReply(); - object_.registerMethod("getInts16FromStruct").onInterface(INTERFACE_NAME).implementedAs([this]( - const sdbus::Struct>& x){ return this->getInts16FromStruct(x); }); - - object_.registerMethod("processVariant").onInterface(INTERFACE_NAME).implementedAs([this](sdbus::Variant& v){ return this->processVariant(v); }); - - object_.registerMethod("getMapOfVariants").onInterface(INTERFACE_NAME) - .withInputParamNames("x", "y").withOutputParamNames("aMapOfVariants").implementedAs([this]( - const std::vector& x, const sdbus::Struct& y){ return this->getMapOfVariants(x ,y); }); - - object_.registerMethod("getStructInStruct").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getStructInStruct(); }); - - object_.registerMethod("sumStructItems").onInterface(INTERFACE_NAME).implementedAs([this]( - const sdbus::Struct& a, const sdbus::Struct& b){ - return this->sumStructItems(a, b); - }); - - object_.registerMethod("sumVectorItems").onInterface(INTERFACE_NAME).implementedAs([this]( - const std::vector& a, const std::vector& b){ - return this->sumVectorItems(a, b); - }); - - object_.registerMethod("doOperation").onInterface(INTERFACE_NAME).implementedAs([this](uint32_t param) - { - return this->doOperation(param); - }); - - object_.registerMethod("doOperationAsync").onInterface(INTERFACE_NAME).implementedAs([this](sdbus::Result result, uint32_t param) - { - this->doOperationAsync(param, std::move(result)); - }); - - object_.registerMethod("getSignature").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getSignature(); }); - object_.registerMethod("getObjPath").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getObjPath(); }); - object_.registerMethod("getUnixFd").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getUnixFd(); }); - - object_.registerMethod("getComplex").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->getComplex(); }).markAsDeprecated(); - - object_.registerMethod("throwError").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->throwError(); }); - object_.registerMethod("throwErrorWithNoReply").onInterface(INTERFACE_NAME).implementedAs([this](){ this->throwError(); }).withNoReply(); - - object_.registerMethod("doPrivilegedStuff").onInterface(INTERFACE_NAME).implementedAs([](){}).markAsPrivileged(); - - object_.registerMethod("emitTwoSimpleSignals").onInterface(INTERFACE_NAME).implementedAs([this](){ this->emitTwoSimpleSignals(); }); - - // registration of signals is optional, it is useful because of introspection - object_.registerSignal("simpleSignal").onInterface(INTERFACE_NAME).markAsDeprecated(); - // Note: sd-bus of libsystemd up to (including) v244 has a bug where it doesn't generate signal parameter names in introspection XML. Signal param names commented temporarily. - object_.registerSignal("signalWithMap").onInterface(INTERFACE_NAME).withParameters>(/*"aMap"*/); - object_.registerSignal("signalWithVariant").onInterface(INTERFACE_NAME).withParameters(/*"aVariant"*/); - - 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_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); }); - } - - ~testing_adaptor() = default; - -public: - void emitSimpleSignal() - { - object_.emitSignal("simpleSignal").onInterface(INTERFACE_NAME); - } - - void emitSignalWithMap(const std::map& map) - { - object_.emitSignal("signalWithMap").onInterface(INTERFACE_NAME).withArguments(map); - } - - void emitSignalWithVariant(const sdbus::Variant& v) - { - object_.emitSignal("signalWithVariant").onInterface(INTERFACE_NAME).withArguments(v); - } - - void emitSignalWithoutRegistration(const sdbus::Struct>& s) - { - object_.emitSignal("signalWithoutRegistration").onInterface(INTERFACE_NAME).withArguments(s); - } - - void emitSignalOnNonexistentInterface() - { - object_.emitSignal("simpleSignal").onInterface("sdbuscpp.interface.that.does.not.exist"); - } - -private: - sdbus::IObject& object_; - -protected: - - virtual void noArgNoReturn() const = 0; - virtual int32_t getInt() const = 0; - virtual std::tuple getTuple() const = 0; - virtual double multiply(const int64_t& a, const double& b) const = 0; - virtual void multiplyWithNoReply(const int64_t& a, const double& b) const = 0; - virtual std::vector getInts16FromStruct(const sdbus::Struct>& x) const = 0; - virtual sdbus::Variant processVariant(sdbus::Variant& v) = 0; - virtual std::map getMapOfVariants(const std::vector& x, const sdbus::Struct& y) const = 0; - virtual sdbus::Struct>> getStructInStruct() const = 0; - virtual int32_t sumStructItems(const sdbus::Struct& a, const sdbus::Struct& b) = 0; - virtual uint32_t sumVectorItems(const std::vector& a, const std::vector& b) = 0; - virtual uint32_t doOperation(uint32_t param) = 0; - virtual void doOperationAsync(uint32_t param, sdbus::Result result) = 0; - virtual sdbus::Signature getSignature() const = 0; - virtual sdbus::ObjectPath getObjPath() const = 0; - virtual sdbus::UnixFd getUnixFd() const = 0; - virtual ComplexType getComplex() const = 0; - virtual void throwError() const = 0; - virtual void emitTwoSimpleSignals() = 0; - - virtual std::string state() = 0; - virtual uint32_t action() = 0; - virtual void action(const uint32_t& value) = 0; - virtual bool blocking() = 0; - virtual void blocking(const bool& value) = 0; - -public: // For testing purposes - std::string getExpectedXmlApiDescription() - { - return -R"delimiter( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - )delimiter" -#if LIBSYSTEMD_VERSION>=242 -R"delimiter( - )delimiter" -#else -R"delimiter( - )delimiter" -#endif -R"delimiter( - - - - - - )delimiter" -#if LIBSYSTEMD_VERSION>=242 -R"delimiter( - - - )delimiter" -#else -R"delimiter( - - - )delimiter" -#endif -R"delimiter( - - - - - - - - - - - - - - - - - - )delimiter" -#if LIBSYSTEMD_VERSION>=242 -R"delimiter( - - - )delimiter" -#else -R"delimiter( - - - )delimiter" -#endif -R"delimiter( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -)delimiter"; - } - -}; - - - -#endif /* SDBUS_CPP_INTEGRATIONTESTS_ADAPTOR_GLUE_H_ */ diff --git a/tests/integrationtests/integrationtests-adaptor.h b/tests/integrationtests/integrationtests-adaptor.h new file mode 100644 index 0000000..ecd13e4 --- /dev/null +++ b/tests/integrationtests/integrationtests-adaptor.h @@ -0,0 +1,109 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__integrationtests_adaptor_h__adaptor__H__ +#define __sdbuscpp__integrationtests_adaptor_h__adaptor__H__ + +#include +#include +#include + +namespace org { +namespace sdbuscpp { + +class integrationtests_adaptor +{ +public: + static constexpr const char* INTERFACE_NAME = "org.sdbuscpp.integrationtests"; + +protected: + integrationtests_adaptor(sdbus::IObject& object) + : object_(object) + { + object_.setInterfaceFlags(INTERFACE_NAME).markAsDeprecated().withPropertyUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL); + object_.registerMethod("noArgNoReturn").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->noArgNoReturn(); }); + object_.registerMethod("getInt").onInterface(INTERFACE_NAME).withOutputParamNames("anInt").implementedAs([this](){ return this->getInt(); }); + object_.registerMethod("getTuple").onInterface(INTERFACE_NAME).withOutputParamNames("arg0", "arg1").implementedAs([this](){ return this->getTuple(); }); + object_.registerMethod("multiply").onInterface(INTERFACE_NAME).withInputParamNames("a", "b").withOutputParamNames("result").implementedAs([this](const int64_t& a, const double& b){ return this->multiply(a, b); }); + object_.registerMethod("multiplyWithNoReply").onInterface(INTERFACE_NAME).withInputParamNames("a", "b").implementedAs([this](const int64_t& a, const double& b){ return this->multiplyWithNoReply(a, b); }).markAsDeprecated().withNoReply(); + object_.registerMethod("getInts16FromStruct").onInterface(INTERFACE_NAME).withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](const sdbus::Struct>& arg0){ return this->getInts16FromStruct(arg0); }); + object_.registerMethod("processVariant").onInterface(INTERFACE_NAME).withInputParamNames("variant").withOutputParamNames("result").implementedAs([this](const sdbus::Variant& variant){ return this->processVariant(variant); }); + object_.registerMethod("getMapOfVariants").onInterface(INTERFACE_NAME).withInputParamNames("x", "y").withOutputParamNames("aMapOfVariants").implementedAs([this](const std::vector& x, const sdbus::Struct& y){ return this->getMapOfVariants(x, y); }); + object_.registerMethod("getStructInStruct").onInterface(INTERFACE_NAME).withOutputParamNames("aMapOfVariants").implementedAs([this](){ return this->getStructInStruct(); }); + object_.registerMethod("sumStructItems").onInterface(INTERFACE_NAME).withInputParamNames("arg0", "arg1").withOutputParamNames("arg0").implementedAs([this](const sdbus::Struct& arg0, const sdbus::Struct& arg1){ return this->sumStructItems(arg0, arg1); }); + object_.registerMethod("sumVectorItems").onInterface(INTERFACE_NAME).withInputParamNames("arg0", "arg1").withOutputParamNames("arg0").implementedAs([this](const std::vector& arg0, const std::vector& arg1){ return this->sumVectorItems(arg0, arg1); }); + object_.registerMethod("doOperation").onInterface(INTERFACE_NAME).withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](const uint32_t& arg0){ return this->doOperation(arg0); }); + object_.registerMethod("doOperationAsync").onInterface(INTERFACE_NAME).withInputParamNames("arg0").withOutputParamNames("arg0").implementedAs([this](sdbus::Result&& result, uint32_t arg0){ this->doOperationAsync(std::move(result), std::move(arg0)); }); + object_.registerMethod("getSignature").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getSignature(); }); + object_.registerMethod("getObjectPath").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getObjectPath(); }); + object_.registerMethod("getUnixFd").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getUnixFd(); }); + object_.registerMethod("getComplex").onInterface(INTERFACE_NAME).withOutputParamNames("arg0").implementedAs([this](){ return this->getComplex(); }).markAsDeprecated(); + object_.registerMethod("throwError").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->throwError(); }); + object_.registerMethod("throwErrorWithNoReply").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->throwErrorWithNoReply(); }).withNoReply(); + object_.registerMethod("doPrivilegedStuff").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->doPrivilegedStuff(); }).markAsPrivileged(); + object_.registerMethod("emitTwoSimpleSignals").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->emitTwoSimpleSignals(); }); + object_.registerSignal("simpleSignal").onInterface(INTERFACE_NAME).markAsDeprecated(); + object_.registerSignal("signalWithMap").onInterface(INTERFACE_NAME).withParameters>("aMap"); + object_.registerSignal("signalWithVariant").onInterface(INTERFACE_NAME).withParameters("aVariant"); + 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("state").onInterface(INTERFACE_NAME).withGetter([this](){ return this->state(); }).markAsDeprecated().withUpdateBehavior(sdbus::Flags::CONST_PROPERTY_VALUE); + } + + ~integrationtests_adaptor() = default; + +public: + void emitSimpleSignal() + { + object_.emitSignal("simpleSignal").onInterface(INTERFACE_NAME); + } + + void emitSignalWithMap(const std::map& aMap) + { + object_.emitSignal("signalWithMap").onInterface(INTERFACE_NAME).withArguments(aMap); + } + + void emitSignalWithVariant(const sdbus::Variant& aVariant) + { + object_.emitSignal("signalWithVariant").onInterface(INTERFACE_NAME).withArguments(aVariant); + } + +private: + virtual void noArgNoReturn() = 0; + virtual int32_t getInt() = 0; + virtual std::tuple getTuple() = 0; + virtual double multiply(const int64_t& a, const double& b) = 0; + virtual void multiplyWithNoReply(const int64_t& a, const double& b) = 0; + virtual std::vector getInts16FromStruct(const sdbus::Struct>& arg0) = 0; + virtual sdbus::Variant processVariant(const sdbus::Variant& variant) = 0; + virtual std::map getMapOfVariants(const std::vector& x, const sdbus::Struct& y) = 0; + virtual sdbus::Struct>> getStructInStruct() = 0; + virtual int32_t sumStructItems(const sdbus::Struct& arg0, const sdbus::Struct& arg1) = 0; + virtual uint32_t sumVectorItems(const std::vector& arg0, const std::vector& arg1) = 0; + virtual uint32_t doOperation(const uint32_t& arg0) = 0; + virtual void doOperationAsync(sdbus::Result&& result, uint32_t arg0) = 0; + virtual sdbus::Signature getSignature() = 0; + virtual sdbus::ObjectPath getObjectPath() = 0; + virtual sdbus::UnixFd getUnixFd() = 0; + virtual std::map>>>, sdbus::Signature, std::string>> getComplex() = 0; + virtual void throwError() = 0; + virtual void throwErrorWithNoReply() = 0; + virtual void doPrivilegedStuff() = 0; + virtual void emitTwoSimpleSignals() = 0; + +private: + virtual uint32_t action() = 0; + virtual void action(const uint32_t& value) = 0; + virtual bool blocking() = 0; + virtual void blocking(const bool& value) = 0; + virtual std::string state() = 0; + +private: + sdbus::IObject& object_; +}; + +}} // namespaces + +#endif diff --git a/tests/integrationtests/integrationtests-proxy.h b/tests/integrationtests/integrationtests-proxy.h new file mode 100644 index 0000000..5c98722 --- /dev/null +++ b/tests/integrationtests/integrationtests-proxy.h @@ -0,0 +1,204 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__integrationtests_proxy_h__proxy__H__ +#define __sdbuscpp__integrationtests_proxy_h__proxy__H__ + +#include +#include +#include + +namespace org { +namespace sdbuscpp { + +class integrationtests_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.sdbuscpp.integrationtests"; + +protected: + integrationtests_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + proxy_.uponSignal("simpleSignal").onInterface(INTERFACE_NAME).call([this](){ this->onSimpleSignal(); }); + proxy_.uponSignal("signalWithMap").onInterface(INTERFACE_NAME).call([this](const std::map& aMap){ this->onSignalWithMap(aMap); }); + proxy_.uponSignal("signalWithVariant").onInterface(INTERFACE_NAME).call([this](const sdbus::Variant& aVariant){ this->onSignalWithVariant(aVariant); }); + } + + ~integrationtests_proxy() = default; + + virtual void onSimpleSignal() = 0; + virtual void onSignalWithMap(const std::map& aMap) = 0; + virtual void onSignalWithVariant(const sdbus::Variant& aVariant) = 0; + +public: + void noArgNoReturn() + { + proxy_.callMethod("noArgNoReturn").onInterface(INTERFACE_NAME); + } + + int32_t getInt() + { + int32_t result; + proxy_.callMethod("getInt").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + std::tuple getTuple() + { + std::tuple result; + proxy_.callMethod("getTuple").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + double multiply(const int64_t& a, const double& b) + { + double result; + proxy_.callMethod("multiply").onInterface(INTERFACE_NAME).withArguments(a, b).storeResultsTo(result); + return result; + } + + void multiplyWithNoReply(const int64_t& a, const double& b) + { + proxy_.callMethod("multiplyWithNoReply").onInterface(INTERFACE_NAME).withArguments(a, b).dontExpectReply(); + } + + std::vector getInts16FromStruct(const sdbus::Struct>& arg0) + { + std::vector result; + proxy_.callMethod("getInts16FromStruct").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result); + return result; + } + + sdbus::Variant processVariant(const sdbus::Variant& variant) + { + sdbus::Variant result; + proxy_.callMethod("processVariant").onInterface(INTERFACE_NAME).withArguments(variant).storeResultsTo(result); + return result; + } + + std::map getMapOfVariants(const std::vector& x, const sdbus::Struct& y) + { + std::map result; + proxy_.callMethod("getMapOfVariants").onInterface(INTERFACE_NAME).withArguments(x, y).storeResultsTo(result); + return result; + } + + sdbus::Struct>> getStructInStruct() + { + sdbus::Struct>> result; + proxy_.callMethod("getStructInStruct").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + int32_t sumStructItems(const sdbus::Struct& arg0, const sdbus::Struct& arg1) + { + int32_t result; + proxy_.callMethod("sumStructItems").onInterface(INTERFACE_NAME).withArguments(arg0, arg1).storeResultsTo(result); + return result; + } + + uint32_t sumVectorItems(const std::vector& arg0, const std::vector& arg1) + { + uint32_t result; + proxy_.callMethod("sumVectorItems").onInterface(INTERFACE_NAME).withArguments(arg0, arg1).storeResultsTo(result); + return result; + } + + uint32_t doOperation(const uint32_t& arg0) + { + uint32_t result; + proxy_.callMethod("doOperation").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result); + return result; + } + + uint32_t doOperationAsync(const uint32_t& arg0) + { + uint32_t result; + proxy_.callMethod("doOperationAsync").onInterface(INTERFACE_NAME).withArguments(arg0).storeResultsTo(result); + return result; + } + + sdbus::Signature getSignature() + { + sdbus::Signature result; + proxy_.callMethod("getSignature").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + sdbus::ObjectPath getObjectPath() + { + sdbus::ObjectPath result; + proxy_.callMethod("getObjectPath").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + sdbus::UnixFd getUnixFd() + { + sdbus::UnixFd result; + proxy_.callMethod("getUnixFd").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + std::map>>>, sdbus::Signature, std::string>> getComplex() + { + std::map>>>, sdbus::Signature, std::string>> result; + proxy_.callMethod("getComplex").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + void throwError() + { + proxy_.callMethod("throwError").onInterface(INTERFACE_NAME); + } + + void throwErrorWithNoReply() + { + proxy_.callMethod("throwErrorWithNoReply").onInterface(INTERFACE_NAME).dontExpectReply(); + } + + void doPrivilegedStuff() + { + proxy_.callMethod("doPrivilegedStuff").onInterface(INTERFACE_NAME); + } + + void emitTwoSimpleSignals() + { + proxy_.callMethod("emitTwoSimpleSignals").onInterface(INTERFACE_NAME); + } + +public: + uint32_t action() + { + return proxy_.getProperty("action").onInterface(INTERFACE_NAME); + } + + void action(const uint32_t& value) + { + proxy_.setProperty("action").onInterface(INTERFACE_NAME).toValue(value); + } + + bool blocking() + { + return proxy_.getProperty("blocking").onInterface(INTERFACE_NAME); + } + + void blocking(const bool& value) + { + proxy_.setProperty("blocking").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string state() + { + return proxy_.getProperty("state").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}} // namespaces + +#endif diff --git a/tests/integrationtests/org.sdbuscpp.integrationtests.xml b/tests/integrationtests/org.sdbuscpp.integrationtests.xml new file mode 100644 index 0000000..6b504cb --- /dev/null +++ b/tests/integrationtests/org.sdbuscpp.integrationtests.xml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/integrationtests/proxy-glue.h b/tests/integrationtests/proxy-glue.h deleted file mode 100644 index da49814..0000000 --- a/tests/integrationtests/proxy-glue.h +++ /dev/null @@ -1,282 +0,0 @@ -/** - * (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland - * (C) 2016 - 2019 Stanislav Angelovic - * - * @file proxy-glue.h - * - * Created on: Jan 2, 2017 - * Project: sdbus-c++ - * Description: High-level D-Bus IPC C++ library based on sd-bus - * - * This file is part of sdbus-c++. - * - * sdbus-c++ is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 of the License, or - * (at your option) any later version. - * - * sdbus-c++ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with sdbus-c++. If not, see . - */ - -#ifndef SDBUS_CPP_INTEGRATIONTESTS_PROXY_GLUE_H_ -#define SDBUS_CPP_INTEGRATIONTESTS_PROXY_GLUE_H_ - -#include "defs.h" - -// sdbus -#include "sdbus-c++/sdbus-c++.h" - -class testing_proxy -{ -protected: - testing_proxy(sdbus::IProxy& object) : - object_(object) - { - object_.uponSignal("simpleSignal").onInterface(INTERFACE_NAME).call([this](){ this->onSimpleSignal(); }); - object_.uponSignal("signalWithMap").onInterface(INTERFACE_NAME).call([this](const std::map& map){ this->onSignalWithMap(map); }); - object_.uponSignal("signalWithVariant").onInterface(INTERFACE_NAME).call([this](const sdbus::Variant& v){ this->onSignalWithVariant(v); }); - - object_.uponSignal("signalWithoutRegistration").onInterface(INTERFACE_NAME).call([this](const sdbus::Struct>& s) - { this->onSignalWithoutRegistration(s); }); - } - - ~testing_proxy() = default; - - virtual void onSimpleSignal() = 0; - virtual void onSignalWithMap(const std::map& map) = 0; - virtual void onSignalWithVariant(const sdbus::Variant& v) = 0; - virtual void onSignalWithoutRegistration(const sdbus::Struct>& s) = 0; - - virtual void onDoOperationReply(uint32_t returnValue, const sdbus::Error* error) = 0; - -public: - void emitTwoSimpleSignals() - { - object_.callMethod("emitTwoSimpleSignals").onInterface(INTERFACE_NAME); - } - - void noArgNoReturn() - { - object_.callMethod("noArgNoReturn").onInterface(INTERFACE_NAME); - } - - int32_t getInt() - { - int32_t result; - object_.callMethod("getInt").onInterface(INTERFACE_NAME).storeResultsTo(result); - return result; - } - - std::tuple getTuple() - { - std::tuple result; - object_.callMethod("getTuple").onInterface(INTERFACE_NAME).storeResultsTo(result); - return result; - } - - double multiply(const int64_t& a, const double& b) - { - double result; - object_.callMethod("multiply").onInterface(INTERFACE_NAME).withArguments(a, b).storeResultsTo(result); - return result; - } - - void multiplyWithNoReply(const int64_t& a, const double& b) - { - object_.callMethod("multiplyWithNoReply").onInterface(INTERFACE_NAME).withArguments(a, b).dontExpectReply(); - } - - std::vector getInts16FromStruct(const sdbus::Struct>& x) - { - std::vector result; - object_.callMethod("getInts16FromStruct").onInterface(INTERFACE_NAME).withArguments(x).storeResultsTo(result); - return result; - } - - sdbus::Variant processVariant(const sdbus::Variant& v) - { - sdbus::Variant result; - object_.callMethod("processVariant").onInterface(INTERFACE_NAME).withArguments(v).storeResultsTo(result); - return result; - } - - std::map getMapOfVariants(const std::vector& x, const sdbus::Struct& y) - { - std::map result; - object_.callMethod("getMapOfVariants").onInterface(INTERFACE_NAME).withArguments(x, y).storeResultsTo(result); - return result; - } - - sdbus::Struct>> getStructInStruct() - { - sdbus::Struct>> result; - object_.callMethod("getStructInStruct").onInterface(INTERFACE_NAME).withArguments().storeResultsTo(result); - return result; - } - - int32_t sumStructItems(const sdbus::Struct& a, const sdbus::Struct& b) - { - int32_t result; - object_.callMethod("sumStructItems").onInterface(INTERFACE_NAME).withArguments(a, b).storeResultsTo(result); - return result; - } - - uint32_t sumVectorItems(const std::vector& a, const std::vector& b) - { - uint32_t result; - object_.callMethod("sumVectorItems").onInterface(INTERFACE_NAME).withArguments(a, b).storeResultsTo(result); - return result; - } - - uint32_t doOperation(uint32_t param) - { - uint32_t result; - object_.callMethod("doOperation").onInterface(INTERFACE_NAME).withArguments(param).storeResultsTo(result); - return result; - } - - uint32_t doOperationWith500msTimeout(uint32_t param) - { - using namespace std::chrono_literals; - uint32_t result; - object_.callMethod("doOperation").onInterface(INTERFACE_NAME).withTimeout(500000us).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::PendingAsyncCall doOperationClientSideAsync(uint32_t param) - { - return object_.callMethodAsync("doOperation") - .onInterface(INTERFACE_NAME) - .withArguments(param) - .uponReplyInvoke([this](const sdbus::Error* error, uint32_t returnValue) - { - this->onDoOperationReply(returnValue, error); - }); - } - - void doErroneousOperationClientSideAsync() - { - object_.callMethodAsync("throwError") - .onInterface(INTERFACE_NAME) - .uponReplyInvoke([this](const sdbus::Error* error) - { - this->onDoOperationReply(0, error); - }); - } - - void doOperationClientSideAsyncWith500msTimeout(uint32_t param) - { - using namespace std::chrono_literals; - object_.callMethodAsync("doOperation") - .onInterface(INTERFACE_NAME) - .withTimeout(500000us) - .withArguments(param) - .uponReplyInvoke([this](const sdbus::Error* error, uint32_t returnValue) - { - this->onDoOperationReply(returnValue, error); - }); - } - - sdbus::Signature getSignature() - { - sdbus::Signature result; - object_.callMethod("getSignature").onInterface(INTERFACE_NAME).storeResultsTo(result); - return result; - } - - sdbus::ObjectPath getObjPath() - { - sdbus::ObjectPath result; - object_.callMethod("getObjPath").onInterface(INTERFACE_NAME).storeResultsTo(result); - return result; - } - - sdbus::UnixFd getUnixFd() - { - sdbus::UnixFd result; - object_.callMethod("getUnixFd").onInterface(INTERFACE_NAME).storeResultsTo(result); - return result; - } - - ComplexType getComplex() - { - ComplexType result; - object_.callMethod("getComplex").onInterface(INTERFACE_NAME).storeResultsTo(result); - return result; - } - - void throwError() - { - object_.callMethod("throwError").onInterface(INTERFACE_NAME); - } - - void throwErrorWithNoReply() - { - object_.callMethod("throwErrorWithNoReply").onInterface(INTERFACE_NAME).dontExpectReply(); - } - - int32_t callNonexistentMethod() - { - int32_t result; - object_.callMethod("callNonexistentMethod").onInterface(INTERFACE_NAME).storeResultsTo(result); - return result; - } - - int32_t callMethodOnNonexistentInterface() - { - int32_t result; - object_.callMethod("someMethod").onInterface("sdbuscpp.interface.that.does.not.exist").storeResultsTo(result); - return result; - } - - std::string state() - { - 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); - } - - void action(const uint32_t& value) - { - object_.setProperty("action").onInterface(INTERFACE_NAME).toValue(value); - } - - bool blocking() - { - return object_.getProperty("blocking").onInterface(INTERFACE_NAME); - } - - void blocking(const bool& value) - { - object_.setProperty("blocking").onInterface(INTERFACE_NAME).toValue(value); - } - - -private: - sdbus::IProxy& object_; - -}; - - -#endif /* SDBUS_CPP_INTEGRATIONTESTS_PROXY_GLUE_H_ */