sdbusplus::bus::bus Add sdbus interface injection

By default it'll use the sdbus singleton that points to the real
library calls, however you can now pass in an interface pointer for
it to use instead.

Change-Id: Ib23f6b01c43937d2cc84ff3afea79dd1ef28f1e5
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/sdbusplus/bus.hpp.in b/sdbusplus/bus.hpp.in
index 4382834..0682d86 100644
--- a/sdbusplus/bus.hpp.in
+++ b/sdbusplus/bus.hpp.in
@@ -8,15 +8,42 @@
 #include <systemd/sd-bus.h>
 #include <systemd/sd-event.h>
 #include <sdbusplus/message.hpp>
+#include <sdbusplus/sdbus.hpp>
+
+extern sdbusplus::SdBusImpl sdbus_impl;
 
 namespace sdbusplus
 {
 
 // Forward declare.
-namespace server { namespace interface { struct interface; } }
-namespace server { namespace manager { struct manager; } }
-namespace server { namespace object { template<class...> struct object; } }
-namespace bus { namespace match { struct match; } }
+namespace server
+{
+namespace interface
+{
+struct interface;
+}
+} // namespace server
+namespace server
+{
+namespace manager
+{
+struct manager;
+}
+} // namespace server
+namespace server
+{
+namespace object
+{
+template <class...> struct object;
+}
+} // namespace server
+namespace bus
+{
+namespace match
+{
+struct match;
+}
+} // namespace bus
 
 namespace bus
 {
@@ -58,9 +85,8 @@
 
         explicit Strv(const std::vector<std::string>& v)
         {
-            std::transform(v.begin(), v.end(),
-                           std::back_inserter(ptrs),
-                           [](const auto& i){ return i.c_str(); });
+            std::transform(v.begin(), v.end(), std::back_inserter(ptrs),
+                           [](const auto& i) { return i.c_str(); });
             ptrs.push_back(nullptr);
         }
 
@@ -70,7 +96,6 @@
         }
 
     private:
-
         std::vector<const char*> ptrs;
 };
 
@@ -84,21 +109,24 @@
  */
 struct bus
 {
-        /* Define all of the basic class operations:
-         *     Not allowed:
-         *         - Default constructor to avoid nullptrs.
-         *         - Copy operations due to internal unique_ptr.
-         *     Allowed:
-         *         - Move operations.
-         *         - Destructor.
-         */
+    /* Define all of the basic class operations:
+     *     Not allowed:
+     *         - Default constructor to avoid nullptrs.
+     *         - Copy operations due to internal unique_ptr.
+     *     Allowed:
+     *         - Move operations.
+     *         - Destructor.
+     */
     bus() = delete;
     bus(const bus&) = delete;
     bus& operator=(const bus&) = delete;
+
     bus(bus&&) = default;
     bus& operator=(bus&&) = default;
     ~bus() = default;
 
+    bus(busp_t b, sdbusplus::SdBusInterface* intf);
+
     /** @brief Conversion constructor from 'busp_t'.
      *
      *  Increments ref-count of the bus-pointer and releases it when done.
@@ -114,7 +142,10 @@
     bus(busp_t b, std::false_type);
 
     /** @brief Release ownership of the stored bus-pointer. */
-    busp_t release() { return _bus.release(); }
+    busp_t release()
+    {
+        return _bus.release();
+    }
 
     /** @brief Wait for new dbus messages or signals.
      *
@@ -122,23 +153,23 @@
      */
     void wait(uint64_t timeout_us = ULLONG_MAX)
     {
-        sd_bus_wait(_bus.get(), timeout_us);
+        _intf->sd_bus_wait(_bus.get(), timeout_us);
     }
 
     /** @brief Process waiting dbus messages or signals. */
     auto process()
     {
         sd_bus_message* m = nullptr;
-        sd_bus_process(_bus.get(), &m);
+        _intf->sd_bus_process(_bus.get(), &m);
 
-        return message::message(m, std::false_type());
+        return message::message(m, _intf, std::false_type());
     }
 
     /** @brief Process waiting dbus messages or signals, discarding unhandled.
      */
     void process_discard()
     {
-        sd_bus_process(_bus.get(), nullptr);
+        _intf->sd_bus_process(_bus.get(), nullptr);
     }
 
     /** @brief Claim a service name on the dbus.
@@ -147,7 +178,7 @@
      */
     void request_name(const char* service)
     {
-        sd_bus_request_name(_bus.get(), service, 0);
+        _intf->sd_bus_request_name(_bus.get(), service, 0);
     }
 
     /** @brief Create a method_call message.
@@ -163,10 +194,10 @@
                          const char* interf, const char* method)
     {
         sd_bus_message* m = nullptr;
-        sd_bus_message_new_method_call(_bus.get(), &m, service, objpath,
-                                       interf, method);
+        _intf->sd_bus_message_new_method_call(_bus.get(), &m, service, objpath,
+                                              interf, method);
 
-        return message::message(m, std::false_type());
+        return message::message(m, _intf, std::false_type());
     }
 
     /** @brief Create a signal message.
@@ -180,9 +211,10 @@
     auto new_signal(const char* objpath, const char* interf, const char* member)
     {
         sd_bus_message* m = nullptr;
-        sd_bus_message_new_signal(_bus.get(), &m, objpath, interf, member);
+        _intf->sd_bus_message_new_signal(_bus.get(), &m, objpath, interf,
+                                         member);
 
-        return message::message(m, std::false_type());
+        return message::message(m, _intf, std::false_type());
     }
 
     /** @brief Perform a message call.
@@ -195,9 +227,9 @@
     auto call(message::message& m, uint64_t timeout_us = 0)
     {
         sd_bus_message* reply = nullptr;
-        sd_bus_call(_bus.get(), m.get(), timeout_us, nullptr, &reply);
+        _intf->sd_bus_call(_bus.get(), m.get(), timeout_us, nullptr, &reply);
 
-        return message::message(reply, std::false_type());
+        return message::message(reply, _intf, std::false_type());
     }
 
     /** @brief Perform a message call, ignoring the reply.
@@ -207,17 +239,17 @@
      */
     void call_noreply(message::message& m, uint64_t timeout_us = 0)
     {
-        sd_bus_call(_bus.get(), m.get(), timeout_us, nullptr, nullptr);
+        _intf->sd_bus_call(_bus.get(), m.get(), timeout_us, nullptr, nullptr);
     }
 
     /** @brief Get the bus unique name. Ex: ":1.11".
-      *
-      * @return The bus unique name.
-      */
+     *
+     * @return The bus unique name.
+     */
     auto get_unique_name()
     {
         const char* unique = nullptr;
-        sd_bus_get_unique_name(_bus.get(), &unique);
+        _intf->sd_bus_get_unique_name(_bus.get(), &unique);
         return std::string(unique);
     }
 
@@ -228,19 +260,19 @@
      */
     void attach_event(sd_event* event, int priority)
     {
-        sd_bus_attach_event(_bus.get(), event, priority);
+        _intf->sd_bus_attach_event(_bus.get(), event, priority);
     }
 
     /** @brief Detach the bus from its sd-event event loop object */
     void detach_event()
     {
-        sd_bus_detach_event(_bus.get());
+        _intf->sd_bus_detach_event(_bus.get());
     }
 
     /** @brief Get the sd-event event loop object of the bus */
     auto get_event()
     {
-        return sd_bus_get_event(_bus.get());
+        return _intf->sd_bus_get_event(_bus.get());
     }
 
     /** @brief Wrapper for sd_bus_emit_interfaces_added_strv
@@ -256,9 +288,8 @@
                                const std::vector<std::string>& ifaces)
     {
         details::Strv s{ifaces};
-        sd_bus_emit_interfaces_added_strv(_bus.get(),
-                                          path,
-                                          static_cast<char**>(s));
+        _intf->sd_bus_emit_interfaces_added_strv(_bus.get(), path,
+                                                 static_cast<char**>(s));
     }
 
     /** @brief Wrapper for sd_bus_emit_interfaces_removed_strv
@@ -274,9 +305,8 @@
                                  const std::vector<std::string>& ifaces)
     {
         details::Strv s{ifaces};
-        sd_bus_emit_interfaces_removed_strv(_bus.get(),
-                                            path,
-                                            static_cast<char**>(s));
+        _intf->sd_bus_emit_interfaces_removed_strv(_bus.get(), path,
+                                                   static_cast<char**>(s));
     }
 
     /** @brief Wrapper for sd_bus_emit_object_added
@@ -289,7 +319,7 @@
      */
     void emit_object_added(const char* path)
     {
-        sd_bus_emit_object_added(_bus.get(), path);
+        _intf->sd_bus_emit_object_added(_bus.get(), path);
     }
 
     /** @brief Wrapper for sd_bus_emit_object_removed
@@ -302,7 +332,7 @@
      */
     void emit_object_removed(const char* path)
     {
-        sd_bus_emit_object_removed(_bus.get(), path);
+        _intf->sd_bus_emit_object_removed(_bus.get(), path);
     }
 
     /** @brief Wrapper for sd_bus_list_names.
@@ -314,10 +344,10 @@
     {
         char** names = nullptr;
 
-        sd_bus_list_names(_bus.get(), &names, nullptr);
+        _intf->sd_bus_list_names(_bus.get(), &names, nullptr);
 
         std::vector<std::string> result;
-        for(auto ptr = names; ptr && *ptr; ++ptr)
+        for (auto ptr = names; ptr && *ptr; ++ptr)
         {
             result.push_back(*ptr);
             free(*ptr);
@@ -329,16 +359,22 @@
 
     friend struct server::interface::interface;
     friend struct server::manager::manager;
-    template<class... Args> friend struct server::object::object;
+    template <class... Args> friend struct server::object::object;
     friend struct match::match;
 
-    private:
-        busp_t get() { return _bus.get(); }
-        details::bus _bus;
+  private:
+    busp_t get()
+    {
+        return _bus.get();
+    }
+    sdbusplus::SdBusInterface* _intf;
+    details::bus _bus;
 };
 
-inline bus::bus(busp_t b) : _bus(sd_bus_ref(b))
+inline bus::bus(busp_t b, sdbusplus::SdBusInterface* intf) :
+    _intf(intf), _bus(_intf->sd_bus_ref(b))
 {
+    // We can leave this as the real deleter if we just use a null pointer.
     _bus.get_deleter().deleter = sd_bus_unref;
 
 #if @WANT_TRANSACTION@
@@ -354,8 +390,11 @@
 #endif
 }
 
-inline bus::bus(busp_t b, std::false_type) : _bus(b)
+inline bus::bus(busp_t b) : _intf(&sdbus_impl), _bus(_intf->sd_bus_ref(b))
 {
+    // We can leave this as the real deleter if we just use a null pointer.
+    _bus.get_deleter().deleter = sd_bus_unref;
+
 #if @WANT_TRANSACTION@
     // Emitting object added causes a message to get the properties
     // which can trigger a 'transaction' in the server bindings.  If
@@ -369,6 +408,20 @@
 #endif
 }
 
+inline bus::bus(busp_t b, std::false_type) : _intf(&sdbus_impl), _bus(b)
+{
+#if @WANT_TRANSACTION@
+    // Emitting object added causes a message to get the properties
+    // which can trigger a 'transaction' in the server bindings.  If
+    // the bus isn't up far enough, this causes an assert deep in
+    // sd-bus code.  Get the 'unique_name' to ensure the bus is up far
+    // enough to avoid the assert.
+    if (b != nullptr)
+    {
+        get_unique_name();
+    }
+#endif
+}
 
 inline bus new_default()
 {
@@ -401,7 +454,7 @@
 {
     sd_bus* b = nullptr;
     b = _intf->sd_bus_message_get_bus(_msg.get());
-    return bus::bus(b);
+    return bus::bus(b, _intf);
 }
 
 } // namespace sdbusplus
diff --git a/sdbusplus/message.hpp b/sdbusplus/message.hpp
index fe00ee0..6b58099 100644
--- a/sdbusplus/message.hpp
+++ b/sdbusplus/message.hpp
@@ -79,6 +79,11 @@
     {
     }
 
+    message(msgp_t m, sdbusplus::SdBusInterface* intf, std::false_type) :
+        _intf(intf), _msg(m)
+    {
+    }
+
     /** @brief Constructor for 'msgp_t'.
      *
      *  Takes ownership of the msg-pointer and releases it when done.
diff --git a/sdbusplus/sdbus.hpp b/sdbusplus/sdbus.hpp
index f3db3f3..d0c6311 100644
--- a/sdbusplus/sdbus.hpp
+++ b/sdbusplus/sdbus.hpp
@@ -13,9 +13,29 @@
   public:
     virtual ~SdBusInterface() = default;
 
-    // https://github.com/systemd/systemd/blob/master/src/systemd/sd-bus.h
-    virtual sd_bus_message *sd_bus_message_ref(sd_bus_message *m) = 0;
+    virtual int sd_bus_attach_event(sd_bus *bus, sd_event *e, int priority) = 0;
 
+    virtual int sd_bus_call(sd_bus *bus, sd_bus_message *m, uint64_t usec,
+                            sd_bus_error *ret_error,
+                            sd_bus_message **reply) = 0;
+
+    virtual int sd_bus_detach_event(sd_bus *bus) = 0;
+
+    virtual int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path,
+                                                  char **interfaces) = 0;
+    virtual int sd_bus_emit_interfaces_removed_strv(sd_bus *bus,
+                                                    const char *path,
+                                                    char **interfaces) = 0;
+    virtual int sd_bus_emit_object_added(sd_bus *bus, const char *path) = 0;
+    virtual int sd_bus_emit_object_removed(sd_bus *bus, const char *path) = 0;
+
+    virtual sd_event *sd_bus_get_event(sd_bus *bus) = 0;
+    virtual int sd_bus_get_unique_name(sd_bus *bus, const char **unique) = 0;
+
+    virtual int sd_bus_list_names(sd_bus *bus, char ***acquired,
+                                  char ***activatable) = 0;
+
+    // https://github.com/systemd/systemd/blob/master/src/systemd/sd-bus.h
     virtual int sd_bus_message_append_basic(sd_bus_message *message, char type,
                                             const void *value) = 0;
 
@@ -48,22 +68,46 @@
                                          const char *interface,
                                          const char *member) = 0;
 
+    virtual int sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **m,
+                                               const char *destination,
+                                               const char *path,
+                                               const char *interface,
+                                               const char *member) = 0;
+
     virtual int sd_bus_message_new_method_return(sd_bus_message *call,
                                                  sd_bus_message **m) = 0;
 
+    virtual int sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **m,
+                                          const char *path,
+                                          const char *interface,
+                                          const char *member) = 0;
+
+    virtual int sd_bus_message_open_container(sd_bus_message *m, char type,
+                                              const char *contents) = 0;
+
     virtual int sd_bus_message_read_basic(sd_bus_message *m, char type,
                                           void *p) = 0;
 
+    virtual sd_bus_message *sd_bus_message_ref(sd_bus_message *m) = 0;
+
     virtual int sd_bus_message_skip(sd_bus_message *m, const char *types) = 0;
 
     virtual int sd_bus_message_verify_type(sd_bus_message *m, char type,
                                            const char *contents) = 0;
 
+    virtual int sd_bus_process(sd_bus *bus, sd_bus_message **r) = 0;
+
+    virtual sd_bus *sd_bus_ref(sd_bus *bus) = 0;
+
+    virtual int sd_bus_request_name(sd_bus *bus, const char *name,
+                                    uint64_t flags) = 0;
+
     virtual int sd_bus_send(sd_bus *bus, sd_bus_message *m,
                             uint64_t *cookie) = 0;
 
-    virtual int sd_bus_message_open_container(sd_bus_message *m, char type,
-                                              const char *contents) = 0;
+    virtual sd_bus *sd_bus_unref(sd_bus *bus) = 0;
+
+    virtual int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec) = 0;
 };
 
 class SdBusImpl : public SdBusInterface
@@ -76,9 +120,58 @@
     SdBusImpl(SdBusImpl &&) = default;
     SdBusImpl &operator=(SdBusImpl &&) = default;
 
-    sd_bus_message *sd_bus_message_ref(sd_bus_message *m) override
+    int sd_bus_attach_event(sd_bus *bus, sd_event *e, int priority) override
     {
-        return ::sd_bus_message_ref(m);
+        return ::sd_bus_attach_event(bus, e, priority);
+    }
+
+    int sd_bus_call(sd_bus *bus, sd_bus_message *m, uint64_t usec,
+                    sd_bus_error *ret_error, sd_bus_message **reply) override
+    {
+        return ::sd_bus_call(bus, m, usec, ret_error, reply);
+    }
+
+    int sd_bus_detach_event(sd_bus *bus) override
+    {
+        return ::sd_bus_detach_event(bus);
+    }
+
+    int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path,
+                                          char **interfaces) override
+    {
+        return ::sd_bus_emit_interfaces_added_strv(bus, path, interfaces);
+    }
+
+    int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path,
+                                            char **interfaces) override
+    {
+        return ::sd_bus_emit_interfaces_removed_strv(bus, path, interfaces);
+    }
+
+    int sd_bus_emit_object_added(sd_bus *bus, const char *path) override
+    {
+        return ::sd_bus_emit_object_added(bus, path);
+    }
+
+    int sd_bus_emit_object_removed(sd_bus *bus, const char *path) override
+    {
+        return ::sd_bus_emit_object_removed(bus, path);
+    }
+
+    sd_event *sd_bus_get_event(sd_bus *bus) override
+    {
+        return ::sd_bus_get_event(bus);
+    }
+
+    int sd_bus_get_unique_name(sd_bus *bus, const char **unique) override
+    {
+        return ::sd_bus_get_unique_name(bus, unique);
+    }
+
+    int sd_bus_list_names(sd_bus *bus, char ***acquired,
+                          char ***activatable) override
+    {
+        return ::sd_bus_list_names(bus, acquired, activatable);
     }
 
     int sd_bus_message_append_basic(sd_bus_message *message, char type,
@@ -167,18 +260,45 @@
         return ::sd_bus_message_is_signal(m, interface, member);
     }
 
+    int sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **m,
+                                       const char *destination,
+                                       const char *path, const char *interface,
+                                       const char *member) override
+    {
+        return ::sd_bus_message_new_method_call(bus, m, destination, path,
+                                                interface, member);
+    }
+
     int sd_bus_message_new_method_return(sd_bus_message *call,
                                          sd_bus_message **m) override
     {
         return ::sd_bus_message_new_method_return(call, m);
     }
 
+    int sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **m,
+                                  const char *path, const char *interface,
+                                  const char *member) override
+    {
+        return ::sd_bus_message_new_signal(bus, m, path, interface, member);
+    }
+
+    int sd_bus_message_open_container(sd_bus_message *m, char type,
+                                      const char *contents) override
+    {
+        return ::sd_bus_message_open_container(m, type, contents);
+    }
+
     int sd_bus_message_read_basic(sd_bus_message *m, char type,
                                   void *p) override
     {
         return ::sd_bus_message_read_basic(m, type, p);
     }
 
+    sd_bus_message *sd_bus_message_ref(sd_bus_message *m) override
+    {
+        return ::sd_bus_message_ref(m);
+    }
+
     int sd_bus_message_skip(sd_bus_message *m, const char *types) override
     {
         return ::sd_bus_message_skip(m, types);
@@ -190,15 +310,35 @@
         return ::sd_bus_message_verify_type(m, type, contents);
     }
 
+    int sd_bus_process(sd_bus *bus, sd_bus_message **r) override
+    {
+        return ::sd_bus_process(bus, r);
+    }
+
+    sd_bus *sd_bus_ref(sd_bus *bus) override
+    {
+        return ::sd_bus_ref(bus);
+    }
+
+    int sd_bus_request_name(sd_bus *bus, const char *name,
+                            uint64_t flags) override
+    {
+        return ::sd_bus_request_name(bus, name, flags);
+    }
+
     int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie) override
     {
         return ::sd_bus_send(bus, m, cookie);
     }
 
-    int sd_bus_message_open_container(sd_bus_message *m, char type,
-                                      const char *contents) override
+    sd_bus *sd_bus_unref(sd_bus *bus) override
     {
-        return ::sd_bus_message_open_container(m, type, contents);
+        return ::sd_bus_unref(bus);
+    }
+
+    int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec) override
+    {
+        return ::sd_bus_wait(bus, timeout_usec);
     }
 };
 
diff --git a/sdbusplus/test/sdbus_mock.hpp b/sdbusplus/test/sdbus_mock.hpp
index 1c2ae7e..5b47d58 100644
--- a/sdbusplus/test/sdbus_mock.hpp
+++ b/sdbusplus/test/sdbus_mock.hpp
@@ -12,7 +12,23 @@
   public:
     virtual ~SdBusMock(){};
 
-    MOCK_METHOD1(sd_bus_message_ref, sd_bus_message *(sd_bus_message *));
+    MOCK_METHOD3(sd_bus_attach_event, int(sd_bus *, sd_event *, int));
+    MOCK_METHOD5(sd_bus_call, int(sd_bus *, sd_bus_message *, uint64_t,
+                                  sd_bus_error *, sd_bus_message **));
+    MOCK_METHOD1(sd_bus_detach_event, int(sd_bus *));
+
+    MOCK_METHOD3(sd_bus_emit_interfaces_added_strv,
+                 int(sd_bus *, const char *, char **));
+    MOCK_METHOD3(sd_bus_emit_interfaces_removed_strv,
+                 int(sd_bus *, const char *, char **));
+    MOCK_METHOD2(sd_bus_emit_object_added, int(sd_bus *, const char *));
+    MOCK_METHOD2(sd_bus_emit_object_removed, int(sd_bus *, const char *));
+
+    MOCK_METHOD1(sd_bus_get_event, sd_event *(sd_bus *));
+    MOCK_METHOD2(sd_bus_get_unique_name, int(sd_bus *, const char **));
+
+    MOCK_METHOD3(sd_bus_list_names, int(sd_bus *, char ***, char ***));
+
     MOCK_METHOD3(sd_bus_message_append_basic,
                  int(sd_bus_message *, char, const void *));
     MOCK_METHOD2(sd_bus_message_at_end, int(sd_bus_message *, int));
@@ -39,18 +55,34 @@
     MOCK_METHOD3(sd_bus_message_is_signal,
                  int(sd_bus_message *, const char *, const char *));
 
+    MOCK_METHOD6(sd_bus_message_new_method_call,
+                 int(sd_bus *, sd_bus_message **, const char *, const char *,
+                     const char *, const char *));
+
     MOCK_METHOD2(sd_bus_message_new_method_return,
                  int(sd_bus_message *, sd_bus_message **));
+
+    MOCK_METHOD5(sd_bus_message_new_signal,
+                 int(sd_bus *, sd_bus_message **, const char *, const char *,
+                     const char *));
+
+    MOCK_METHOD3(sd_bus_message_open_container,
+                 int(sd_bus_message *, char, const char *));
+
     MOCK_METHOD3(sd_bus_message_read_basic,
                  int(sd_bus_message *, char, void *));
+    MOCK_METHOD1(sd_bus_message_ref, sd_bus_message *(sd_bus_message *));
 
     MOCK_METHOD2(sd_bus_message_skip, int(sd_bus_message *, const char *));
     MOCK_METHOD3(sd_bus_message_verify_type,
                  int(sd_bus_message *, char, const char *));
-    MOCK_METHOD3(sd_bus_send, int(sd_bus *, sd_bus_message *, uint64_t *));
 
-    MOCK_METHOD3(sd_bus_message_open_container,
-                 int(sd_bus_message *, char, const char *));
+    MOCK_METHOD2(sd_bus_process, int(sd_bus *, sd_bus_message **));
+    MOCK_METHOD1(sd_bus_ref, sd_bus *(sd_bus *));
+    MOCK_METHOD3(sd_bus_request_name, int(sd_bus *, const char *, uint64_t));
+    MOCK_METHOD3(sd_bus_send, int(sd_bus *, sd_bus_message *, uint64_t *));
+    MOCK_METHOD1(sd_bus_unref, sd_bus *(sd_bus *));
+    MOCK_METHOD2(sd_bus_wait, int(sd_bus *, uint64_t));
 };
 
 } // namespace sdbusplus