input: DBus semaphore listener

Adds an input source responsible for listening to changes that happens
on specified dbus object which provides a semaphore-status health.
We will use this for monitoring cla-sysrepod health status.

Change-Id: Ib1b82efa181d445ad779f2b181146c9d5ab7722a
Depends-on: https://cesnet-gerrit-public/c/CzechLight/dependencies/+/2778
Depends-on: https://gerrit.cesnet.cz/c/CzechLight/dependencies/+/2778
diff --git a/tests/dbus-helpers/dbus_semaphore_server.cpp b/tests/dbus-helpers/dbus_semaphore_server.cpp
new file mode 100644
index 0000000..35eb45f
--- /dev/null
+++ b/tests/dbus-helpers/dbus_semaphore_server.cpp
@@ -0,0 +1,38 @@
+#include <sdbus-c++/sdbus-c++.h>
+#include <thread>
+#include "dbus_semaphore_server.h"
+#include "utils/log-init.h"
+
+/* Ask for current value:
+ * dbus-send --print-reply --system --dest=<bus> /cz/cesnet/led org.freedesktop.DBus.Properties.Get string:cz.cesnet.Led string:semaphore
+ */
+
+DbusSemaphoreServer::DbusSemaphoreServer(sdbus::IConnection& connection, const std::string& objectPath, const std::string& propertyName, const std::string& propertyInterface, const std::string& state)
+    : m_object(sdbus::createObject(connection, objectPath))
+    , m_propertyName(propertyName)
+    , m_propertyInterface(propertyInterface)
+    , m_semaphoreState(state)
+{
+    // Register D-Bus methods and signals on the object, and exports the object.
+    m_object->registerProperty(m_propertyName).onInterface(m_propertyInterface).withGetter([&]() {
+        std::lock_guard<std::mutex> lock(m_semaphoreStateMtx);
+        return m_semaphoreState;
+    });
+    m_object->finishRegistration();
+}
+
+void DbusSemaphoreServer::runStateChanges(const std::vector<std::pair<std::string, std::chrono::milliseconds>>& sequence)
+{
+    std::thread serverThr([&]() {
+        for (const auto& [state, sleepTime] : sequence) {
+            {
+                std::lock_guard<std::mutex> lock(m_semaphoreStateMtx);
+                m_semaphoreState = state;
+            }
+            m_object->emitPropertiesChangedSignal(m_propertyInterface, {m_propertyName});
+            std::this_thread::sleep_for(sleepTime);
+        }
+    });
+
+    serverThr.join();
+}
\ No newline at end of file
diff --git a/tests/dbus-helpers/dbus_semaphore_server.h b/tests/dbus-helpers/dbus_semaphore_server.h
new file mode 100644
index 0000000..1a57c1b
--- /dev/null
+++ b/tests/dbus-helpers/dbus_semaphore_server.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <memory>
+#include <mutex>
+#include <sdbus-c++/sdbus-c++.h>
+#include <string>
+
+class DbusSemaphoreServer {
+public:
+    DbusSemaphoreServer(sdbus::IConnection& connection, const std::string& objectPath, const std::string& propertyName, const std::string& propertyInterface, const std::string& state);
+    void runStateChanges(const std::vector<std::pair<std::string, std::chrono::milliseconds>>& sequence);
+
+private:
+    std::unique_ptr<sdbus::IObject> m_object;
+    std::string m_propertyName;
+    std::string m_propertyInterface;
+    std::string m_semaphoreState;
+    std::mutex m_semaphoreStateMtx;
+};
\ No newline at end of file