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/wait-a-bit-longer.cpp b/tests/wait-a-bit-longer.cpp
new file mode 100644
index 0000000..fce354d
--- /dev/null
+++ b/tests/wait-a-bit-longer.cpp
@@ -0,0 +1,39 @@
+#include <chrono>
+#include <doctest/doctest.h>
+#include <thread>
+#include <trompeloeil.hpp>
+
+/** @short Wait until a given sequence of expectation is matched, and then a bit more to ensure that there's silence afterwards */
+void waitForCompletionAndBitMore(const trompeloeil::sequence& seq)
+{
+    using namespace std::literals;
+    using clock = std::chrono::steady_clock;
+
+    // We're busy-waiting a bit
+    const auto waitingStep = 30ms;
+    // Timeout after this much
+    const auto completionTimeout = 5000ms;
+    // When checking for silence afterwards, wait at least this long.
+    // We'll also wait as long as it originally took to process everything.
+    const auto minExtraWait = 100ms;
+
+    auto start = clock::now();
+    while (true) {
+        {
+            auto lock = trompeloeil::get_lock();
+            if (seq.is_completed()) {
+                break;
+            }
+        }
+        std::this_thread::sleep_for(waitingStep);
+        if (clock::now() - start > completionTimeout) {
+            break;
+        }
+    }
+    {
+        auto lock = trompeloeil::get_lock();
+        REQUIRE(seq.is_completed());
+    }
+    auto duration = std::chrono::duration<double>(clock::now() - start);
+    std::this_thread::sleep_for(std::max(duration, decltype(duration)(minExtraWait)));
+}