/** * (C) 2016 - 2021 KISTLER INSTRUMENTE AG, Winterthur, Switzerland * (C) 2016 - 2022 Stanislav Angelovic * * @file TestFixture.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 #include #include namespace sdbus { namespace test { class BaseTestFixture : public ::testing::Test { public: static void SetUpTestCase() { s_adaptorConnection->requestName(BUS_NAME); } static void TearDownTestCase() { s_adaptorConnection->releaseName(BUS_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_objectManagerProxy = std::make_unique(*s_proxyConnection, BUS_NAME, MANAGER_PATH); m_proxy = std::make_unique(*s_proxyConnection, BUS_NAME, OBJECT_PATH); m_objectManagerAdaptor = std::make_unique(*s_adaptorConnection, MANAGER_PATH); m_adaptor = std::make_unique(*s_adaptorConnection, OBJECT_PATH); } void TearDown() override { m_proxy.reset(); m_adaptor.reset(); } public: static std::unique_ptr s_adaptorConnection; static std::unique_ptr s_proxyConnection; std::unique_ptr m_objectManagerAdaptor; std::unique_ptr m_objectManagerProxy; std::unique_ptr m_adaptor; std::unique_ptr m_proxy; }; struct SdBusCppLoop{}; struct SdEventLoop{}; template class TestFixture : public BaseTestFixture{}; // Fixture working upon internal sdbus-c++ event loop template <> class TestFixture : public BaseTestFixture { public: static void SetUpTestCase() { BaseTestFixture::SetUpTestCase(); s_proxyConnection->enterEventLoopAsync(); s_adaptorConnection->enterEventLoopAsync(); std::this_thread::sleep_for(std::chrono::milliseconds(50)); // Give time for the proxy connection to start listening to signals } static void TearDownTestCase() { BaseTestFixture::TearDownTestCase(); s_adaptorConnection->leaveEventLoop(); s_proxyConnection->leaveEventLoop(); } }; // Fixture working upon attached external sd-event loop template <> class TestFixture : public BaseTestFixture { public: static void SetUpTestCase() { sd_event_new(&s_adaptorSdEvent); sd_event_new(&s_proxySdEvent); s_adaptorConnection->attachSdEventLoop(s_adaptorSdEvent); s_proxyConnection->attachSdEventLoop(s_proxySdEvent); s_eventExitFd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); // No callback means that the event loop will exit when this event source triggers sd_event_add_io(s_adaptorSdEvent, nullptr, s_eventExitFd, EPOLLIN, nullptr, NULL); sd_event_add_io(s_proxySdEvent, nullptr, s_eventExitFd, EPOLLIN, nullptr, NULL); s_adaptorEventLoopThread = std::thread([]() { sd_event_loop(s_adaptorSdEvent); }); s_proxyEventLoopThread = std::thread([]() { sd_event_loop(s_proxySdEvent); }); BaseTestFixture::SetUpTestCase(); std::this_thread::sleep_for(std::chrono::milliseconds(50)); // Give time for the proxy connection to start listening to signals } static void TearDownTestCase() { uint64_t value = 1; write(s_eventExitFd, &value, sizeof(value)); s_adaptorEventLoopThread.join(); s_proxyEventLoopThread.join(); sd_event_unref(s_adaptorSdEvent); sd_event_unref(s_proxySdEvent); close(s_eventExitFd); BaseTestFixture::TearDownTestCase(); } private: static std::thread s_adaptorEventLoopThread; static std::thread s_proxyEventLoopThread; static sd_event *s_adaptorSdEvent; static sd_event *s_proxySdEvent; static int s_eventExitFd; }; typedef ::testing::Types EventLoopTags; TYPED_TEST_SUITE(TestFixture, EventLoopTags); template using SdbusTestObject = TestFixture<_EventLoop>; TYPED_TEST_SUITE(SdbusTestObject, EventLoopTags); template using AsyncSdbusTestObject = TestFixture<_EventLoop>; TYPED_TEST_SUITE(AsyncSdbusTestObject, EventLoopTags); template using AConnection = TestFixture<_EventLoop>; TYPED_TEST_SUITE(AConnection, EventLoopTags); }} #endif /* SDBUS_CPP_INTEGRATIONTESTS_TESTFIXTURE_H_ */