event: add a simple wrapper around sd-event

In order to facilitate stop-conditions on the async::context,
we need to be able to escape the wait on the dbus fd.  sd-event
will allow us to do this and also build other co-routine primitives
in the future (such as `co_await async::delay(1s)` backed by sd-event
timers).  Define a simple wrapper around sd-event here which can
be leveraged by the async framework.

Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: I945416cbce3c98d98135c42cb7ca249a57cb9a60
diff --git a/test/event/event.cpp b/test/event/event.cpp
new file mode 100644
index 0000000..dbe470c
--- /dev/null
+++ b/test/event/event.cpp
@@ -0,0 +1,58 @@
+#include <sdbusplus/event.hpp>
+
+#include <chrono>
+#include <thread>
+
+#include <gtest/gtest.h>
+
+using namespace std::literals::chrono_literals;
+
+struct Event : public testing::Test
+{
+    sdbusplus::event_t ev{};
+};
+
+TEST_F(Event, TimeoutWorks)
+{
+    static constexpr auto timeout = 250ms;
+
+    auto start = std::chrono::steady_clock::now();
+    ev.run_one(timeout);
+    auto stop = std::chrono::steady_clock::now();
+
+    EXPECT_TRUE(stop - start > timeout);
+    EXPECT_TRUE(stop - start < timeout * 2);
+}
+
+TEST_F(Event, Runnable)
+{
+    static constexpr auto timeout = 10s;
+
+    std::jthread j{[&]() { ev.break_run(); }};
+
+    auto start = std::chrono::steady_clock::now();
+    ev.run_one(timeout);
+    auto stop = std::chrono::steady_clock::now();
+
+    EXPECT_TRUE(stop - start < timeout);
+}
+
+TEST_F(Event, ConditionSignals)
+{
+    struct run
+    {
+        static int _(sd_event_source*, int, uint32_t, void* data)
+        {
+            *static_cast<bool*>(data) = true;
+            return 0;
+        }
+    };
+    bool ran = false;
+
+    auto c = ev.add_condition(run::_, &ran);
+    std::jthread j{[&]() { c.signal(); }};
+
+    ev.run_one();
+    EXPECT_TRUE(ran);
+    c.ack();
+}