add sdjournal interface to inject tests

The goal of the tests is not to test phosphor-logging, but rather allow
code to call through phosphor-logging/log<> during a test.

Change-Id: Id8c84ded473decc7f9f0be268116083093f86e54
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/Makefile.am b/Makefile.am
index 1b13af7..2b49080 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,14 +2,16 @@
 # export these headers
 nobase_include_HEADERS = \
 	phosphor-logging/log.hpp \
-	phosphor-logging/elog.hpp
+	phosphor-logging/elog.hpp \
+	phosphor-logging/sdjournal.hpp \
+	phosphor-logging/test/sdjournal_mock.hpp
 
 nobase_nodist_include_HEADERS = \
 	phosphor-logging/elog-errors.hpp \
 	xyz/openbmc_project/Logging/Internal/Manager/server.hpp
 
 libphosphor_logging_FILES = \
-	elog.cpp elog_meta.cpp
+	elog.cpp elog_meta.cpp sdjournal.cpp
 libphosphor_loggingdir = ${libdir}
 libphosphor_logging_LTLIBRARIES = libphosphor_logging.la
 libphosphor_logging_la_SOURCES = $(libphosphor_logging_FILES)
@@ -37,7 +39,8 @@
 	org.openbmc.Associations.cpp \
 	elog-process-metadata.cpp \
 	elog_meta.cpp \
-	elog_serialize.cpp
+	elog_serialize.cpp \
+	sdjournal.cpp
 
 # Be sure to build needed files before compiling
 BUILT_SOURCES = \
diff --git a/phosphor-logging/log.hpp b/phosphor-logging/log.hpp
index e20605b..673848c 100644
--- a/phosphor-logging/log.hpp
+++ b/phosphor-logging/log.hpp
@@ -18,6 +18,7 @@
 
 #include <systemd/sd-journal.h>
 
+#include <phosphor-logging/sdjournal.hpp>
 #include <sdbusplus/server/transaction.hpp>
 #include <tuple>
 #include <type_traits>
@@ -99,7 +100,7 @@
 void helper_log(T&& e, std::integer_sequence<size_t, I...>)
 {
     // https://www.freedesktop.org/software/systemd/man/sd_journal_print.html
-    sd_journal_send(std::get<I>(std::forward<T>(e))..., NULL);
+    sdjournal_ptr->journal_send(std::get<I>(std::forward<T>(e))..., NULL);
 }
 
 /** @fn details::log()
diff --git a/phosphor-logging/sdjournal.hpp b/phosphor-logging/sdjournal.hpp
new file mode 100644
index 0000000..6aa2394
--- /dev/null
+++ b/phosphor-logging/sdjournal.hpp
@@ -0,0 +1,72 @@
+#pragma once
+
+#include <systemd/sd-journal.h>
+
+#include <cstdarg>
+
+namespace phosphor
+{
+namespace logging
+{
+
+/**
+ * Implementation that calls into real sd_journal methods.
+ */
+class SdJournalHandler
+{
+  public:
+    SdJournalHandler() = default;
+    virtual ~SdJournalHandler() = default;
+    SdJournalHandler(const SdJournalHandler&) = default;
+    SdJournalHandler& operator=(const SdJournalHandler&) = default;
+    SdJournalHandler(SdJournalHandler&&) = default;
+    SdJournalHandler& operator=(SdJournalHandler&&) = default;
+
+    /**
+     * Provide a fake method that's called by the real method so we can catch
+     * the journal_send call in testing.
+     *
+     * @param[in] fmt - the format string passed into journal_send.
+     * @return an int meant to be intepreted by the journal_send caller during
+     * testing.
+     */
+    virtual int journal_send_call(const char* fmt)
+    {
+        return 0;
+    };
+
+    /**
+     * Send the information to sd_journal_send.
+     *
+     * @param[in] fmt - c string format.
+     * @param[in] ... - parameters.
+     * @return value from sd_journal_send
+     *
+     * sentinel default makes sure the last parameter is null.
+     */
+    virtual int journal_send(const char* fmt, ...)
+        __attribute__((format(printf, 2, 0))) __attribute__((sentinel))
+    {
+        va_list args;
+        va_start(args, fmt);
+
+        int rc = ::sd_journal_send(fmt, args, NULL);
+        va_end(args);
+
+        return rc;
+    }
+};
+
+extern SdJournalHandler* sdjournal_ptr;
+
+/**
+ * Swap out the sdjournal_ptr used by log<> such that a test
+ * won't need to hit the real sd_journal and fail.
+ *
+ * @param[in] with - pointer to your sdjournal_mock object.
+ * @return pointer to the previously stored sdjournal_ptr.
+ */
+SdJournalHandler* SwapJouralImpl(SdJournalHandler* with);
+
+} // namespace logging
+} // namespace phosphor
diff --git a/phosphor-logging/test/sdjournal_mock.hpp b/phosphor-logging/test/sdjournal_mock.hpp
new file mode 100644
index 0000000..3290480
--- /dev/null
+++ b/phosphor-logging/test/sdjournal_mock.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <phosphor-logging/sdjournal.hpp>
+
+#include <gmock/gmock.h>
+
+namespace phosphor
+{
+namespace logging
+{
+
+class SdJournalMock : public SdJournalImpl
+{
+  public:
+    virtual ~SdJournalMock() = default;
+
+    /* Set your mock to catch this call. */
+    MOCK_METHOD1(journal_send_call, int(const char*));
+
+    int journal_send(const char* fmt, ...) override
+    {
+        return journal_send_call(fmt);
+    }
+}
+
+} // namespace logging
+} // namespace phosphor
diff --git a/phosphor-rsyslog-config/Makefile.am b/phosphor-rsyslog-config/Makefile.am
index 6aa48a3..806e30b 100644
--- a/phosphor-rsyslog-config/Makefile.am
+++ b/phosphor-rsyslog-config/Makefile.am
@@ -10,6 +10,9 @@
 	main.cpp \
 	server-conf.cpp
 
+phosphor_rsyslog_conf_LDADD = \
+	$(top_builddir)/sdjournal.o
+
 phosphor_rsyslog_conf_LDFLAGS = \
 	$(SDBUSPLUS_LIBS) \
 	$(PHOSPHOR_DBUS_INTERFACES_LIBS)
diff --git a/sdjournal.cpp b/sdjournal.cpp
new file mode 100644
index 0000000..77ced46
--- /dev/null
+++ b/sdjournal.cpp
@@ -0,0 +1,21 @@
+#include "config.h"
+
+#include <phosphor-logging/sdjournal.hpp>
+
+namespace phosphor
+{
+namespace logging
+{
+
+SdJournalHandler sdjournal_impl;
+SdJournalHandler* sdjournal_ptr = &sdjournal_impl;
+
+SdJournalHandler* SwapJouralHandler(SdJournalHandler* with)
+{
+    SdJournalHandler* curr = sdjournal_ptr;
+    sdjournal_ptr = with;
+    return curr;
+}
+
+} // namespace logging
+} // namespace phosphor
diff --git a/test/Makefile.am b/test/Makefile.am
index 092dd02..08a2537 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -36,9 +36,12 @@
 	$(top_builddir)/xyz/openbmc_project/Logging/Internal/Manager/server.o \
 	$(top_builddir)/elog_meta.o \
 	$(top_builddir)/elog-lookup.o \
-	$(top_builddir)/elog-process-metadata.o
+	$(top_builddir)/elog-process-metadata.o \
+	$(top_builddir)/sdjournal.o
 
-remote_logging_test_ldadd = $(top_builddir)/phosphor-rsyslog-config/server-conf.o
+remote_logging_test_ldadd = \
+	$(top_builddir)/phosphor-rsyslog-config/server-conf.o \
+	$(top_builddir)/sdjournal.o
 
 elog_errorwrap_test_CPPFLAGS = $(test_cppflags)
 elog_errorwrap_test_CXXFLAGS = $(test_cxxflags)