Added end2end test case

Added end2end test case for exercising code from attention event to isolator.

Signed-off-by: Ben Tyner <ben.tyner@ibm.com>
Change-Id: I5bde1c50e4b70e284e99e71bb69d55041310c0d0
diff --git a/analyzer/analyzer_main.cpp b/analyzer/analyzer_main.cpp
index 73e8f51..f697b4b 100644
--- a/analyzer/analyzer_main.cpp
+++ b/analyzer/analyzer_main.cpp
@@ -1,5 +1,3 @@
-#include <stdio.h>
-
 #include <hei_main.hpp>
 
 namespace analyzer
@@ -8,7 +6,7 @@
 /** @brief Analyze and isolate hardware errors */
 void analyzeHardware()
 {
-    printf("analyzeHardware()\n");
+    return;
 }
 
 } // namespace analyzer
diff --git a/analyzer/meson.build b/analyzer/meson.build
index fd0f7da..8f19ecf 100644
--- a/analyzer/meson.build
+++ b/analyzer/meson.build
@@ -2,9 +2,11 @@
 # "fallback" to using the local libhei subproject.
 libhei_dep = dependency('libhei', fallback : ['libhei', 'libhei_dep'])
 
+# gather analyzer sources to be used here and elsewhere if needed
+analyzer_src = files('analyzer_main.cpp', 'user_interface.cpp')
+
 # Create hardware error analyzer library
 analyzer = static_library('analyzer',
-                          'analyzer_main.cpp',
-                          'user_interface.cpp',
+                          analyzer_src,
                           dependencies : libhei_dep,
                           install : true)
diff --git a/attn/attn_handler.cpp b/attn/attn_handler.cpp
index ec600e5..4a5382d 100644
--- a/attn/attn_handler.cpp
+++ b/attn/attn_handler.cpp
@@ -1,12 +1,12 @@
 #include <libpdbg.h>
 
 #include <analyzer/analyzer_main.hpp>
-#include <phosphor-logging/log.hpp>
-#include <sdbusplus/bus.hpp>
+#include <bp_handler.hpp>
+#include <logging.hpp>
+#include <ti_handler.hpp>
 
 #include <iomanip>
-
-using namespace phosphor::logging;
+#include <sstream>
 
 namespace attn
 {
@@ -34,22 +34,6 @@
 int handleSpecial(bool i_breakpoints);
 
 /**
- * @brief Notify Cronus over dbus interface
- *
- * @param i_proc   Processor number with Special attention
- * @param i_core   Core number with special attention
- * @param i_thread Thread number with special attention
- */
-void notifyCronus(uint32_t i_proc, uint32_t i_core, uint32_t i_thread);
-
-/**
- * @brief Start host diagnostic mode
- *
- * Start the host diagnostic mode systemd unit
- */
-void startHostDiagnosticMode();
-
-/**
  * @brief The main attention handler logic
  *
  * @param i_breakpoints true = breakpoint special attn handling enabled
@@ -68,20 +52,20 @@
             proc = pdbg_target_index(target); // get processor number
 
             std::stringstream ss; // log message stream
-            ss << "[ATTN] checking processor " << proc << std::endl;
+            ss << "checking processor " << proc << std::endl;
             log<level::INFO>(ss.str().c_str());
 
             // get active attentions on processor
             if (0 != fsi_read(target, 0x1007, &isr_val))
             {
                 std::stringstream ss; // log message stream
-                ss << "[ATTN] Error! cfam read 0x1007 FAILED" << std::endl;
+                ss << "Error! cfam read 0x1007 FAILED" << std::endl;
                 log<level::INFO>(ss.str().c_str());
             }
             else
             {
                 std::stringstream ss; // log message stream
-                ss << "[ATTN] cfam 0x1007 = 0x";
+                ss << "cfam 0x1007 = 0x";
                 ss << std::hex << std::setw(8) << std::setfill('0');
                 ss << isr_val << std::endl;
                 log<level::INFO>(ss.str().c_str());
@@ -90,13 +74,13 @@
                 if (0 != fsi_read(target, 0x100d, &isr_mask))
                 {
                     std::stringstream ss; // log message stream
-                    ss << "[ATTN] Error! cfam read 0x100d FAILED" << std::endl;
+                    ss << "Error! cfam read 0x100d FAILED" << std::endl;
                     log<level::INFO>(ss.str().c_str());
                 }
                 else
                 {
                     std::stringstream ss; // log message stream
-                    ss << "[ATTN] cfam 0x100d = 0x";
+                    ss << "cfam 0x100d = 0x";
                     ss << std::hex << std::setw(8) << std::setfill('0');
                     ss << isr_mask << std::endl;
                     log<level::INFO>(ss.str().c_str());
@@ -110,7 +94,10 @@
                     // bit 0 on "left": bit 1 = checkstop
                     if (isr_val & isr_mask & 0x40000000)
                     {
-                        handleCheckstop();
+                        if (0 == handleCheckstop())
+                        {
+                            break;
+                        }
                     }
 
                     // bit 0 on "left": bit 2 = special attention
@@ -134,13 +121,13 @@
     int rc = 1; // vital attention handling not yet supported
 
     std::stringstream ss; // log message stream
-    ss << "[ATTN] vital" << std::endl;
+    ss << "vital" << std::endl;
     log<level::INFO>(ss.str().c_str());
 
     if (0 != rc)
     {
         std::stringstream ss; // log message stream
-        ss << "[ATTN] vital NOT handled" << std::endl;
+        ss << "vital NOT handled" << std::endl;
         log<level::INFO>(ss.str().c_str());
     }
 
@@ -152,10 +139,10 @@
  */
 int handleCheckstop()
 {
-    int rc = 1; // checkstop handling not yet supported
+    int rc = 0; // checkstop handling supported
 
     std::stringstream ss; // log message stream
-    ss << "[ATTN] checkstop" << std::endl;
+    ss << "checkstop" << std::endl;
     log<level::INFO>(ss.str().c_str());
 
     analyzer::analyzeHardware();
@@ -176,18 +163,18 @@
 
     std::stringstream ss; // log message stream
 
-    ss << "[ATTN] special" << std::endl;
+    ss << "special" << std::endl;
 
     // Right now we always handle breakpoint special attentions if breakpoint
     // attn handling is enabled. This will eventually check if breakpoint attn
     // handing is enabled AND there is a breakpoint pending.
     if (true == i_breakpoints)
     {
-        ss << "[ATTN] breakpoint" << std::endl;
+        ss << "breakpoint" << std::endl;
         log<level::INFO>(ss.str().c_str());
 
-        // Cronus will determine proc, core and thread so just notify
-        notifyCronus(0, 0, 0); // proc-0, core-0, thread-0
+        // Call the breakpoint special attention handler
+        bpHandler();
     }
     // Right now if breakpoint attn handling is not enabled we will treat the
     // special attention as a TI. This will eventually be changed to check
@@ -195,11 +182,11 @@
     // handling is enbaled or not.
     else
     {
-        ss << "[ATTN] TI (terminate immediately)" << std::endl;
+        ss << "TI (terminate immediately)" << std::endl;
         log<level::INFO>(ss.str().c_str());
 
-        // Start host diagnostic mode
-        startHostDiagnosticMode();
+        // Call TI special attention handler
+        tiHandler();
     }
 
     // TODO recoverable errors?
@@ -207,53 +194,4 @@
     return rc;
 }
 
-/**
- * @brief Notify Cronus over dbus interface
- */
-void notifyCronus(uint32_t i_proc, uint32_t i_core, uint32_t i_thread)
-{
-    std::stringstream ss; // log message stream
-
-    // log status info
-    ss << "[ATTN] notify ";
-    ss << i_proc << ", " << i_core << ", " << i_thread << std::endl;
-    log<level::INFO>(ss.str().c_str());
-
-    // notify Cronus over dbus
-    auto bus = sdbusplus::bus::new_system();
-    auto msg = bus.new_signal("/", "org.openbmc.cronus", "Brkpt");
-
-    std::array<uint32_t, 3> params{i_proc, i_core, i_thread};
-    msg.append(params);
-
-    msg.signal_send();
-
-    return;
-}
-
-/**
- * @brief Start host diagnostic mode
- * */
-void startHostDiagnosticMode()
-{
-    std::stringstream ss; // log message stream
-
-    // log status info
-    ss << "[ATTN] start host diagnostic mode service" << std::endl;
-    log<level::INFO>(ss.str().c_str());
-
-    // Use the systemd service manager object interface to call the start unit
-    // method with the obmc-host-diagnostic-mode target.
-    auto bus    = sdbusplus::bus::new_system();
-    auto method = bus.new_method_call(
-        "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
-        "org.freedesktop.systemd1.Manager", "StartUnit");
-
-    method.append("obmc-host-diagnostic-mode@0.target"); // unit to activate
-    method.append("replace"); // mode = replace conflicting queued jobs
-    bus.call_noreply(method); // start the service
-
-    return;
-}
-
 } // namespace attn
diff --git a/attn/attn_monitor.cpp b/attn/attn_monitor.cpp
index 15c924c..eb46978 100644
--- a/attn/attn_monitor.cpp
+++ b/attn/attn_monitor.cpp
@@ -2,9 +2,7 @@
 
 #include "attn_handler.hpp"
 
-#include <phosphor-logging/log.hpp>
-
-using namespace phosphor::logging;
+#include <logging.hpp>
 
 namespace attn
 {
@@ -12,7 +10,7 @@
 /** @brief Register a callback for gpio event */
 void AttnMonitor::scheduleGPIOEvent()
 {
-    std::string logMessage = "[ATTN] ... waiting for events ...";
+    std::string logMessage = "... waiting for events ...";
     log<level::INFO>(logMessage.c_str());
 
     // Register async callback, note that callback is a
@@ -22,8 +20,8 @@
         [this](const boost::system::error_code& ec) {
             if (ec)
             {
-                std::string logMessage = "[ATTN] ATTN GPIO Async error: " +
-                                         std::string(ec.message());
+                std::string logMessage =
+                    "GPIO Async wait error: " + std::string(ec.message());
                 log<level::INFO>(logMessage.c_str());
             }
             else
@@ -43,7 +41,7 @@
     if (gpiod_line_event_read_fd(iv_gpioEventDescriptor.native_handle(),
                                  &gpioEvent) < 0)
     {
-        logMessage = "[ATTN] ATTN GPIO Failed can't read file descriptor!";
+        logMessage = "GPIO line read failed";
         log<level::INFO>(logMessage.c_str());
     }
     else
@@ -57,13 +55,13 @@
 
             // gpio == 1, GPIO handler should not be executing
             case 1:
-                logMessage = "[ATTN] ATTN GPIO sync!";
+                logMessage = "GPIO handler out of sync";
                 log<level::INFO>(logMessage.c_str());
                 break;
 
             // unexpected value
             default:
-                logMessage = "[ATTN] ATTN GPIO read unexpected valuel!";
+                logMessage = "GPIO line unexpected value";
                 log<level::INFO>(logMessage.c_str());
         }
     }
@@ -75,7 +73,7 @@
 {
     if (0 != gpiod_line_request(iv_gpioLine, &iv_gpioConfig, 0))
     {
-        std::string logMessage = "[ATTN] failed request for GPIO";
+        std::string logMessage = "failed request for GPIO";
         log<level::INFO>(logMessage.c_str());
     }
     else
@@ -85,7 +83,7 @@
         gpioLineFd = gpiod_line_event_get_fd(iv_gpioLine);
         if (gpioLineFd < 0)
         {
-            std::string logMessage = "[ATTN] failed to get file descriptor";
+            std::string logMessage = "failed to get file descriptor";
             log<level::INFO>(logMessage.c_str());
         }
         else
diff --git a/attn/bp_handler.cpp b/attn/bp_handler.cpp
new file mode 100644
index 0000000..7b4744c
--- /dev/null
+++ b/attn/bp_handler.cpp
@@ -0,0 +1,35 @@
+#include <logging.hpp>
+#include <sdbusplus/bus.hpp>
+
+#include <sstream>
+
+namespace attn
+{
+
+/**
+ * @brief Notify Cronus over dbus interface
+ *
+ * When the special attention is due to a breakpoint condition we will notify
+ * Cronus over the dbus interface.
+ */
+void bpHandler()
+{
+    // trace message
+    std::stringstream ss;
+    ss << "Notify Cronus" << std::endl;
+    log<level::INFO>(ss.str().c_str());
+
+    // notify Cronus over dbus
+    auto bus = sdbusplus::bus::new_system();
+    auto msg = bus.new_signal("/", "org.openbmc.cronus", "Brkpt");
+
+    // Cronus will figure out proc, core, thread so just send 0,0,0
+    std::array<uint32_t, 3> params{0, 0, 0};
+    msg.append(params);
+
+    msg.signal_send();
+
+    return;
+}
+
+} // namespace attn
diff --git a/attn/bp_handler.hpp b/attn/bp_handler.hpp
new file mode 100644
index 0000000..4c7dcb0
--- /dev/null
+++ b/attn/bp_handler.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+namespace attn
+{
+
+/**
+ * @brief Breakpoint special attention handler
+ *
+ * Handler for special attention events due to a breakpoint condition.
+ */
+void bpHandler();
+
+} // namespace attn
diff --git a/attn/logging.cpp b/attn/logging.cpp
new file mode 100644
index 0000000..423e9ca
--- /dev/null
+++ b/attn/logging.cpp
@@ -0,0 +1,14 @@
+#include <logging.hpp>
+#include <phosphor-logging/log.hpp>
+
+namespace attn
+{
+
+/** @brief Log message of type INFO using phosphor logging */
+template <>
+void log<INFO>(const char* i_message)
+{
+    phosphor::logging::log<phosphor::logging::level::INFO>(i_message);
+}
+
+} // namespace attn
diff --git a/attn/logging.hpp b/attn/logging.hpp
new file mode 100644
index 0000000..9a4b0dc
--- /dev/null
+++ b/attn/logging.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+namespace attn
+{
+
+/** @brief Logging level types */
+enum level
+{
+    INFO
+};
+
+/**
+ * @brief Log message of different types
+ *
+ * Log messages of different types (level) such as informational, debug,
+ * errors etc.
+ */
+template <level L>
+void log(const char* i_message);
+
+} // namespace attn
diff --git a/attn/meson.build b/attn/meson.build
index dfa1ce9..6a81213 100644
--- a/attn/meson.build
+++ b/attn/meson.build
@@ -6,7 +6,7 @@
               '-DBOOST_ERROR_CODE_HEADER_ONLY',
               '-DBOOST_SYSTEM_NO_DEPRECATED']
 
-# dependency to link dbus support
+# dependency to link sdbusplus support
 sdbusplus = dependency('sdbusplus', version : '>=1.0')
 
 # dependency to link gpiod support
@@ -29,10 +29,23 @@
             'systemdsystemunitdir')
 )
 
+# see if phosphor-logging is available, if not use test case logging code
+h = 'phosphor-logging/log.hpp'
+if cmplr.compiles('#include <@0@>'.format(h), name : '#include <@0@>'.format(h))
+    logging_src = 'logging.cpp'
+else
+    logging_src = '../test/end2end/logging.cpp'
+endif
+
+# gather attention sources to be used here and elsewhere if needed
+attn_src = files('attn_main.cpp', 'attn_handler.cpp', 'attn_monitor.cpp',
+                 'bp_handler.cpp', 'ti_handler.cpp', logging_src)
+
+# Create attention handler library
 attn = static_library('attn_handler',
-           'attn_main.cpp', 'attn_handler.cpp', 'attn_monitor.cpp',
-           include_directories : incdir,
-           dependencies : [whole_archive, libpdbg,
-                           no_whole_archive, sdbusplus, libgpiod],
-           cpp_args : boost_args,
-           install : true)
+                      attn_src,
+                      include_directories : incdir,
+                      dependencies : [whole_archive, libpdbg,
+                                      no_whole_archive, sdbusplus, libgpiod],
+                      cpp_args : boost_args,
+                      install : true)
diff --git a/attn/ti_handler.cpp b/attn/ti_handler.cpp
new file mode 100644
index 0000000..cca2a66
--- /dev/null
+++ b/attn/ti_handler.cpp
@@ -0,0 +1,31 @@
+#include <logging.hpp>
+#include <sdbusplus/bus.hpp>
+
+#include <sstream>
+
+namespace attn
+{
+
+/** @brief Start host diagnostic mode systemd unit */
+void tiHandler()
+{
+    // trace message
+    std::stringstream ss;
+    ss << "start host diagnostic mode service" << std::endl;
+    log<level::INFO>(ss.str().c_str());
+
+    // Use the systemd service manager object interface to call the start unit
+    // method with the obmc-host-diagnostic-mode target.
+    auto bus    = sdbusplus::bus::new_system();
+    auto method = bus.new_method_call(
+        "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
+        "org.freedesktop.systemd1.Manager", "StartUnit");
+
+    method.append("obmc-host-diagnostic-mode@0.target"); // unit to activate
+    method.append("replace"); // mode = replace conflicting queued jobs
+    bus.call_noreply(method); // start the service
+
+    return;
+}
+
+} // namespace attn
diff --git a/attn/ti_handler.hpp b/attn/ti_handler.hpp
new file mode 100644
index 0000000..d3b83cd
--- /dev/null
+++ b/attn/ti_handler.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+/**
+ * @brief TI special attention handler
+ *
+ * Handle special attention due to a terminate immediately (TI) condition.
+ */
+namespace attn
+{
+
+void tiHandler();
+
+} // namespace attn
diff --git a/main.cpp b/main.cpp
index 96c0fa9..f36a3c0 100644
--- a/main.cpp
+++ b/main.cpp
@@ -4,6 +4,7 @@
 #include <attn/attn_main.hpp>
 
 #include <algorithm>
+#include <string>
 
 /*
  * @brief Search the command line arguments for an option
diff --git a/test/end2end/analyzer_main.cpp b/test/end2end/analyzer_main.cpp
new file mode 100644
index 0000000..03d6a8f
--- /dev/null
+++ b/test/end2end/analyzer_main.cpp
@@ -0,0 +1,25 @@
+#include <hei_main.hpp>
+
+namespace analyzer
+{
+
+// Quick test that we can call the core libhei functions. This function
+// is called from the attention handler when a checkstop event is active.
+void analyzeHardware()
+{
+    using namespace libhei;
+
+    // Add some chips for error isolation
+    std::vector<Chip> chipList;
+    chipList.emplace_back(Chip{"proc", static_cast<ChipType_t>(0xdeadbeef)});
+
+    // Isolation data that will be populated by isolator
+    IsolationData isoData{};
+
+    // Isolate active hardware errors in chips
+    initialize(nullptr, 0);
+    isolate(chipList, isoData);
+    uninitialize();
+}
+
+} // namespace analyzer
diff --git a/test/end2end/bp_handler.cpp b/test/end2end/bp_handler.cpp
new file mode 100644
index 0000000..bcb0ac3
--- /dev/null
+++ b/test/end2end/bp_handler.cpp
@@ -0,0 +1,17 @@
+#include <attn/logging.hpp>
+
+#include <sstream>
+
+namespace attn
+{
+
+/** @brief Breakpoint special attention handler */
+void bpHandler()
+{
+    // trace message
+    std::stringstream ss;
+    ss << "breakpoint handler";
+    log<level::INFO>(ss.str().c_str());
+}
+
+} // namespace attn
diff --git a/test/end2end/hei_user_defines.hpp b/test/end2end/hei_user_defines.hpp
new file mode 100644
index 0000000..e45e18d
--- /dev/null
+++ b/test/end2end/hei_user_defines.hpp
@@ -0,0 +1,25 @@
+#pragma once
+
+/**
+ * @file hei_user_defines.hpp
+ * @brief The purpose of this file is to provide defines that are required by
+ *        the hardware error isolator library (libhei)
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdio.h>
+
+#define HEI_INF(...)                                                           \
+    {                                                                          \
+        printf("HWDIAGS I> " __VA_ARGS__);                                     \
+        printf("\n");                                                          \
+    }
+
+#define HEI_ERR(...)                                                           \
+    {                                                                          \
+        printf("HWDIAGS E> " __VA_ARGS__);                                     \
+        printf("\n");                                                          \
+    }
+
+#define HEI_ASSERT(expression) assert(expression);
diff --git a/test/end2end/logging.cpp b/test/end2end/logging.cpp
new file mode 100644
index 0000000..2833766
--- /dev/null
+++ b/test/end2end/logging.cpp
@@ -0,0 +1,15 @@
+#include <attn/logging.hpp>
+
+#include <iostream>
+
+namespace attn
+{
+
+/** @brief Log message of type INFO using stdout */
+template <>
+void log<INFO>(const char* i_message)
+{
+    std::cout << i_message;
+}
+
+} // namespace attn
diff --git a/test/end2end/main.cpp b/test/end2end/main.cpp
new file mode 100644
index 0000000..3540f6d
--- /dev/null
+++ b/test/end2end/main.cpp
@@ -0,0 +1,18 @@
+#include <libpdbg.h>
+
+#include <attn/attn_handler.hpp>
+
+// The attnHandler() function is called when the an attention GPIO event is
+// triggered. We call it here directly to simulatea a GPIO event.
+int main()
+{
+    int rc = 0; // return code
+
+    // initialize pdbg targets
+    pdbg_targets_init(nullptr);
+
+    // exercise attention gpio event path
+    attn::attnHandler(false);
+
+    return rc;
+}
diff --git a/test/end2end/meson.build b/test/end2end/meson.build
new file mode 100644
index 0000000..f2031d6
--- /dev/null
+++ b/test/end2end/meson.build
@@ -0,0 +1,8 @@
+# create openpower-hw-diags executable for local testing
+executable('openpower-hw-diags-test',
+            'main.cpp', 'logging.cpp', 'bp_handler.cpp', 'ti_handler.cpp',
+            'analyzer_main.cpp',
+            link_with : [analyzer, attn],
+            include_directories : incdir,
+            dependencies : libhei_dep,
+            install : false)
diff --git a/test/end2end/ti_handler.cpp b/test/end2end/ti_handler.cpp
new file mode 100644
index 0000000..50cc97b
--- /dev/null
+++ b/test/end2end/ti_handler.cpp
@@ -0,0 +1,17 @@
+#include <attn/logging.hpp>
+
+#include <sstream>
+
+namespace attn
+{
+
+/** @brief Handle TI special attention */
+void tiHandler()
+{
+    // trace message
+    std::stringstream ss;
+    ss << "TI handler" << std::endl;
+    log<level::INFO>(ss.str().c_str());
+}
+
+} // namespace attn
diff --git a/test/meson.build b/test/meson.build
index 76aa354..1704f17 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -1,3 +1,6 @@
+# end2end code exerciser for experiment and testing
+subdir('end2end')
+
 tests = [
   'hello-world',
 ]