Add callback support to triggerable actions

Change-Id: Icc27fbe9403eda418f41e12c76af7f3216f4b72a
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/bmc/firmware-handler/test/firmware_skip_unittest.cpp b/bmc/firmware-handler/test/firmware_skip_unittest.cpp
index a549582..243380d 100644
--- a/bmc/firmware-handler/test/firmware_skip_unittest.cpp
+++ b/bmc/firmware-handler/test/firmware_skip_unittest.cpp
@@ -13,7 +13,12 @@
 {
     SkipAction skip;
     EXPECT_TRUE(skip.trigger());
+    size_t i = 0;
+    skip.setCallback([&](TriggerableActionInterface&) { i++; });
     EXPECT_TRUE(skip.trigger());
+    EXPECT_EQ(1, i);
+    EXPECT_TRUE(skip.trigger());
+    EXPECT_EQ(2, i);
 }
 
 TEST(SkipActionTest, ValidateStatusAlwaysSuccess)
diff --git a/bmc/general_systemd.cpp b/bmc/general_systemd.cpp
index 3c59c11..ecd15d4 100644
--- a/bmc/general_systemd.cpp
+++ b/bmc/general_systemd.cpp
@@ -144,6 +144,11 @@
     job = std::nullopt;
     currentStatus =
         result == "done" ? ActionStatus::success : ActionStatus::failed;
+
+    if (cb)
+    {
+        cb(*this);
+    }
 }
 
 std::unique_ptr<TriggerableActionInterface>
diff --git a/bmc/skip_action.cpp b/bmc/skip_action.cpp
index 4392e97..f1a67e0 100644
--- a/bmc/skip_action.cpp
+++ b/bmc/skip_action.cpp
@@ -26,4 +26,21 @@
     return std::make_unique<SkipAction>();
 }
 
+bool SkipAction::trigger()
+{
+    if (cb)
+    {
+        cb(*this);
+    }
+    return true;
+}
+
+void SkipAction::abort()
+{}
+
+ActionStatus SkipAction::status()
+{
+    return ActionStatus::success;
+}
+
 } // namespace ipmi_flash
diff --git a/bmc/skip_action.hpp b/bmc/skip_action.hpp
index 65fcfc8..4fc9462 100644
--- a/bmc/skip_action.hpp
+++ b/bmc/skip_action.hpp
@@ -23,16 +23,9 @@
     SkipAction(SkipAction&&) = default;
     SkipAction& operator=(SkipAction&&) = default;
 
-    bool trigger() override
-    {
-        return true;
-    }
-    void abort() override
-    {}
-    ActionStatus status() override
-    {
-        return ActionStatus::success;
-    }
+    bool trigger() override;
+    void abort() override;
+    ActionStatus status() override;
 };
 
 } // namespace ipmi_flash
diff --git a/bmc/test/triggerable_mock.hpp b/bmc/test/triggerable_mock.hpp
index 9a63dcb..de2b025 100644
--- a/bmc/test/triggerable_mock.hpp
+++ b/bmc/test/triggerable_mock.hpp
@@ -18,6 +18,7 @@
     MOCK_METHOD0(trigger, bool());
     MOCK_METHOD0(abort, void());
     MOCK_METHOD0(status, ActionStatus());
+    using TriggerableActionInterface::cb;
 };
 
 std::unique_ptr<TriggerableActionInterface> CreateTriggerMock()
diff --git a/configure.ac b/configure.ac
index 7195890..16d95e8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -84,6 +84,12 @@
     )
 
     AC_CHECK_HEADER(
+        [function2/function2.hpp],
+        [],
+        [AC_MSG_ERROR([Could not find function2/function2.hpp])]
+    )
+
+    AC_CHECK_HEADER(
         [nlohmann/json.hpp],
         [],
         [AC_MSG_ERROR([Could not find nlohmann/json.hpp])]
diff --git a/status.hpp b/status.hpp
index 869fe89..e3342d2 100644
--- a/status.hpp
+++ b/status.hpp
@@ -1,5 +1,7 @@
 #pragma once
 
+#include <function2/function2.hpp>
+
 #include <cstdint>
 
 namespace ipmi_flash
@@ -17,6 +19,8 @@
 class TriggerableActionInterface
 {
   public:
+    using Callback = fu2::unique_function<void(TriggerableActionInterface&)>;
+
     virtual ~TriggerableActionInterface() = default;
 
     /**
@@ -31,6 +35,15 @@
 
     /** Check the current state of the action. */
     virtual ActionStatus status() = 0;
+
+    /** Sets the callback that is executed on completion of the trigger. */
+    void setCallback(Callback&& cb)
+    {
+        this->cb = std::move(cb);
+    }
+
+  protected:
+    Callback cb;
 };
 
 } // namespace ipmi_flash