treewide: Move timers out of networkd lib scope

Change-Id: I5fd0fc70d007e0851329172b8421846a78016d57
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/ibm/hypervisor-network-mgr-src/hyp_network_manager.cpp b/src/ibm/hypervisor-network-mgr-src/hyp_network_manager.cpp
index 1540e0f..ffacfe5 100644
--- a/src/ibm/hypervisor-network-mgr-src/hyp_network_manager.cpp
+++ b/src/ibm/hypervisor-network-mgr-src/hyp_network_manager.cpp
@@ -1,8 +1,5 @@
 #include "hyp_network_manager.hpp"
 
-#include "types.hpp"
-#include "util.hpp"
-
 #include <phosphor-logging/elog-errors.hpp>
 #include <phosphor-logging/elog.hpp>
 #include <phosphor-logging/log.hpp>
diff --git a/src/ibm/hypervisor-network-mgr-src/hyp_network_manager.hpp b/src/ibm/hypervisor-network-mgr-src/hyp_network_manager.hpp
index ca21ece..5eac26f 100644
--- a/src/ibm/hypervisor-network-mgr-src/hyp_network_manager.hpp
+++ b/src/ibm/hypervisor-network-mgr-src/hyp_network_manager.hpp
@@ -1,12 +1,8 @@
 #pragma once
-
 #include "hyp_sys_config.hpp"
-#include "types.hpp"
-#include "util.hpp"
 
 #include <sdbusplus/bus.hpp>
 #include <sdbusplus/server/object.hpp>
-#include <sdeventplus/source/event.hpp>
 
 namespace phosphor
 {
@@ -65,13 +61,10 @@
 
     /** @brief Constructor to put object onto bus at a dbus path.
      *  @param[in] bus - Bus to attach to.
-     *  @param[in] event - event.
      *  @param[in] path - Path to attach at.
      */
-    HypNetworkMgr(sdbusplus::bus_t& bus, sdeventplus::Event& event,
-                  const char* path) :
-        bus(bus),
-        event(event), objectPath(path){};
+    HypNetworkMgr(sdbusplus::bus_t& bus, const char* path) :
+        bus(bus), objectPath(path){};
 
     /** @brief Get the BaseBiosTable attributes
      *
@@ -143,9 +136,6 @@
     /** @brief sdbusplus DBus bus connection. */
     sdbusplus::bus_t& bus;
 
-    /**  sdevent Event handle. */
-    sdeventplus::Event& event;
-
     /** @brief object path */
     std::string objectPath;
 
diff --git a/src/ibm/hypervisor-network-mgr-src/hyp_network_manager_main.cpp b/src/ibm/hypervisor-network-mgr-src/hyp_network_manager_main.cpp
index d28ca11..55d80c2 100644
--- a/src/ibm/hypervisor-network-mgr-src/hyp_network_manager_main.cpp
+++ b/src/ibm/hypervisor-network-mgr-src/hyp_network_manager_main.cpp
@@ -21,8 +21,7 @@
     bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
 
     // Create hypervisor network manager dbus object
-    phosphor::network::HypNetworkMgr manager(bus, event,
-                                             DEFAULT_HYP_NW_OBJPATH);
+    phosphor::network::HypNetworkMgr manager(bus, DEFAULT_HYP_NW_OBJPATH);
 
     // Create the hypervisor eth interface objects
     manager.createIfObjects();
diff --git a/src/ibm/hypervisor-network-mgr-src/hyp_sys_config.hpp b/src/ibm/hypervisor-network-mgr-src/hyp_sys_config.hpp
index f9f7d74..8c3e423 100644
--- a/src/ibm/hypervisor-network-mgr-src/hyp_sys_config.hpp
+++ b/src/ibm/hypervisor-network-mgr-src/hyp_sys_config.hpp
@@ -1,7 +1,5 @@
 #pragma once
-
 #include "hyp_network_manager.hpp"
-#include "system_configuration.hpp"
 
 #include <sdbusplus/bus.hpp>
 #include <sdbusplus/server/object.hpp>
diff --git a/src/ibm/hypervisor-network-mgr-src/meson.build b/src/ibm/hypervisor-network-mgr-src/meson.build
index becc10c..08cb0ad 100644
--- a/src/ibm/hypervisor-network-mgr-src/meson.build
+++ b/src/ibm/hypervisor-network-mgr-src/meson.build
@@ -17,7 +17,10 @@
   'hyp_network_manager.cpp',
   'hyp_sys_config.cpp',
   implicit_include_directories: false,
-  dependencies: networkd_dep,
+  dependencies: [
+    networkd_dep,
+    dependency('sdeventplus'),
+  ],
   install: true,
   install_dir: get_option('bindir'))
 
diff --git a/src/meson.build b/src/meson.build
index 93cf1f2..e1033e7 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -35,7 +35,6 @@
   dependency('phosphor-logging'),
   networkd_dbus_dep,
   sdbusplus_dep,
-  dependency('sdeventplus'),
   stdplus_dep,
 ]
 
@@ -58,7 +57,6 @@
   'util.cpp',
   'config_parser.cpp',
   'dhcp_configuration.cpp',
-  'rtnetlink_server.cpp',
   'dns_updater.cpp',
   implicit_include_directories: false,
   include_directories: src_includes,
@@ -73,9 +71,13 @@
 executable(
   'phosphor-network-manager',
   'network_manager_main.cpp',
+  'rtnetlink_server.cpp',
   main_srcs,
   implicit_include_directories: false,
-  dependencies: [networkd_dep] + main_deps,
+  dependencies: main_deps + [
+    networkd_dep,
+    dependency('sdeventplus'),
+  ],
   install: true,
   install_dir: get_option('bindir'))
 
diff --git a/src/network_manager.cpp b/src/network_manager.cpp
index 51863a7..557e826 100644
--- a/src/network_manager.cpp
+++ b/src/network_manager.cpp
@@ -29,7 +29,6 @@
 namespace network
 {
 
-extern std::unique_ptr<Timer> reloadTimer;
 using namespace phosphor::logging;
 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
 using Argument = xyz::openbmc_project::Common::InvalidArgument;
@@ -40,10 +39,11 @@
     "link',interface='org.freedesktop.DBus.Properties',member='"
     "PropertiesChanged',arg0='org.freedesktop.network1.Link',";
 
-Manager::Manager(sdbusplus::bus_t& bus, const char* objPath,
+Manager::Manager(sdbusplus::bus_t& bus, DelayedExecutor& reload,
+                 stdplus::zstring_view objPath,
                  const std::filesystem::path& confDir) :
-    ManagerIface(bus, objPath, ManagerIface::action::defer_emit),
-    bus(bus), objPath(std::string(objPath)), confDir(confDir),
+    ManagerIface(bus, objPath.c_str(), ManagerIface::action::defer_emit),
+    reload(reload), bus(bus), objPath(std::string(objPath)), confDir(confDir),
     systemdNetworkdEnabledMatch(
         bus, enabledMatch, [&](sdbusplus::message_t& m) {
             std::string intf;
@@ -76,6 +76,47 @@
             }
         })
 {
+    reload.setCallback([&]() {
+        for (auto& hook : reloadPreHooks)
+        {
+            try
+            {
+                hook();
+            }
+            catch (const std::exception& ex)
+            {
+                log<level::ERR>("Failed executing reload hook, ignoring",
+                                entry("ERR=%s", ex.what()));
+            }
+        }
+        reloadPreHooks.clear();
+        try
+        {
+            auto method = bus.new_method_call(NETWORKD_BUSNAME, NETWORKD_PATH,
+                                              NETWORKD_INTERFACE, "Reload");
+            bus.call_noreply(method);
+            log<level::INFO>("Reloaded systemd-networkd");
+        }
+        catch (const sdbusplus::exception_t& ex)
+        {
+            log<level::ERR>("Failed to reload configuration",
+                            entry("ERR=%s", ex.what()));
+            reloadPostHooks.clear();
+        }
+        for (auto& hook : reloadPostHooks)
+        {
+            try
+            {
+                hook();
+            }
+            catch (const std::exception& ex)
+            {
+                log<level::ERR>("Failed executing reload hook, ignoring",
+                                entry("ERR=%s", ex.what()));
+            }
+        }
+        reloadPostHooks.clear();
+    });
     std::vector<
         std::tuple<int32_t, std::string, sdbusplus::message::object_path>>
         links;
@@ -463,53 +504,6 @@
     }
 }
 
-void Manager::reloadConfigs()
-{
-    reloadTimer->restartOnce(reloadTimeout);
-}
-
-void Manager::doReloadConfigs()
-{
-    for (auto& hook : reloadPreHooks)
-    {
-        try
-        {
-            hook();
-        }
-        catch (const std::exception& ex)
-        {
-            log<level::ERR>("Failed executing reload hook, ignoring",
-                            entry("ERR=%s", ex.what()));
-        }
-    }
-    reloadPreHooks.clear();
-    try
-    {
-        auto method = bus.new_method_call(NETWORKD_BUSNAME, NETWORKD_PATH,
-                                          NETWORKD_INTERFACE, "Reload");
-        bus.call_noreply(method);
-    }
-    catch (const sdbusplus::exception_t& ex)
-    {
-        log<level::ERR>("Failed to reload configuration",
-                        entry("ERR=%s", ex.what()));
-        reloadPostHooks.clear();
-    }
-    for (auto& hook : reloadPostHooks)
-    {
-        try
-        {
-            hook();
-        }
-        catch (const std::exception& ex)
-        {
-            log<level::ERR>("Failed executing reload hook, ignoring",
-                            entry("ERR=%s", ex.what()));
-        }
-    }
-    reloadPostHooks.clear();
-}
-
 void Manager::handleAdminState(std::string_view state, unsigned ifidx)
 {
     if (state == "initialized" || state == "linger")
diff --git a/src/network_manager.hpp b/src/network_manager.hpp
index 5166f7a..890a837 100644
--- a/src/network_manager.hpp
+++ b/src/network_manager.hpp
@@ -11,6 +11,7 @@
 #include <sdbusplus/bus.hpp>
 #include <sdbusplus/bus/match.hpp>
 #include <sdbusplus/message/native_types.hpp>
+#include <stdplus/zstring_view.hpp>
 #include <string>
 #include <string_view>
 #include <vector>
@@ -25,6 +26,15 @@
     sdbusplus::xyz::openbmc_project::Network::VLAN::server::Create,
     sdbusplus::xyz::openbmc_project::Common::server::FactoryReset>;
 
+class DelayedExecutor
+{
+  public:
+    virtual ~DelayedExecutor() = default;
+
+    virtual void schedule() = 0;
+    virtual void setCallback(fu2::unique_function<void()>&& cb) = 0;
+};
+
 /** @class Manager
  *  @brief OpenBMC network manager implementation.
  */
@@ -35,14 +45,15 @@
     Manager& operator=(const Manager&) = delete;
     Manager(Manager&&) = delete;
     Manager& operator=(Manager&&) = delete;
-    virtual ~Manager() = default;
 
     /** @brief Constructor to put object onto bus at a dbus path.
      *  @param[in] bus - Bus to attach to.
+     *  @param[in] reload - The executor for reloading configs
      *  @param[in] objPath - Path to attach at.
      *  @param[in] confDir - Network Configuration directory path.
      */
-    Manager(sdbusplus::bus_t& bus, const char* objPath,
+    Manager(sdbusplus::bus_t& bus, DelayedExecutor& reload,
+            stdplus::zstring_view objPath,
             const std::filesystem::path& confDir);
 
     ObjectPath vlan(std::string interfaceName, uint32_t id) override;
@@ -93,11 +104,10 @@
     /** @brief Arms a timer to tell systemd-network to reload all of the network
      * configurations
      */
-    virtual void reloadConfigs();
-
-    /** @brief Tell systemd-network to reload all of the network configurations
-     */
-    void doReloadConfigs();
+    inline void reloadConfigs()
+    {
+        reload.schedule();
+    }
 
     /** @brief Persistent map of EthernetInterface dbus objects and their names
      */
@@ -119,6 +129,9 @@
     }
 
   protected:
+    /** @brief Handle to the object used to trigger reloads of networkd. */
+    DelayedExecutor& reload;
+
     /** @brief Persistent sdbusplus DBus bus connection. */
     sdbusplus::bus_t& bus;
 
diff --git a/src/network_manager_main.cpp b/src/network_manager_main.cpp
index dc51915..170241d 100644
--- a/src/network_manager_main.cpp
+++ b/src/network_manager_main.cpp
@@ -9,43 +9,49 @@
 
 #include <fmt/format.h>
 
-#include <functional>
-#include <memory>
+#include <chrono>
 #include <phosphor-logging/log.hpp>
 #include <sdbusplus/bus.hpp>
 #include <sdbusplus/server/manager.hpp>
+#include <sdeventplus/clock.hpp>
 #include <sdeventplus/event.hpp>
 #include <sdeventplus/source/signal.hpp>
+#include <sdeventplus/utility/timer.hpp>
 #include <stdplus/signal.hpp>
 
 using phosphor::logging::level;
 using phosphor::logging::log;
 
-constexpr char NETWORK_CONF_DIR[] = "/etc/systemd/network";
 constexpr char DEFAULT_OBJPATH[] = "/xyz/openbmc_project/network";
 
-namespace phosphor
-{
-namespace network
+namespace phosphor::network
 {
 
-std::unique_ptr<Manager> manager = nullptr;
-std::unique_ptr<Timer> reloadTimer = nullptr;
-
-void reloadNetworkd()
+class TimerExecutor : public DelayedExecutor
 {
-    if (manager)
+  private:
+    using Timer = sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>;
+
+  public:
+    TimerExecutor(sdeventplus::Event& event, std::chrono::seconds delay) :
+        delay(delay), timer(event, nullptr)
     {
-        log<level::INFO>("Sending networkd reload");
-        manager->doReloadConfigs();
-        log<level::INFO>("Done networkd reload");
     }
-}
 
-void initializeTimers(sdeventplus::Event& event)
-{
-    reloadTimer = std::make_unique<Timer>(event, std::bind(reloadNetworkd));
-}
+    void schedule() override
+    {
+        timer.restartOnce(delay);
+    }
+
+    void setCallback(fu2::unique_function<void()>&& cb) override
+    {
+        timer.set_callback([cb = std::move(cb)](Timer&) mutable { cb(); });
+    }
+
+  private:
+    std::chrono::seconds delay;
+    Timer timer;
+};
 
 void termCb(sdeventplus::source::Signal& signal, const struct signalfd_siginfo*)
 {
@@ -59,30 +65,23 @@
     stdplus::signal::block(SIGTERM);
     sdeventplus::source::Signal(event, SIGTERM, termCb).set_floating(true);
 
-    initializeTimers(event);
-
     auto bus = sdbusplus::bus::new_default();
-    // Attach the bus to sd_event to service user requests
     bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
-
-    // Add sdbusplus Object Manager for the 'root' path of the network manager.
     sdbusplus::server::manager_t objManager(bus, DEFAULT_OBJPATH);
-    bus.request_name(DEFAULT_BUSNAME);
 
-    manager = std::make_unique<Manager>(bus, DEFAULT_OBJPATH, NETWORK_CONF_DIR);
-
-    // RTNETLINK event handler
-    netlink::Server svr(event, *manager);
+    TimerExecutor reload(event, std::chrono::seconds(3));
+    Manager manager(bus, reload, DEFAULT_OBJPATH, "/etc/systemd/network");
+    netlink::Server svr(event, manager);
 
 #ifdef SYNC_MAC_FROM_INVENTORY
-    auto runtime = inventory::watch(bus, *manager);
+    auto runtime = inventory::watch(bus, manager);
 #endif
 
+    bus.request_name(DEFAULT_BUSNAME);
     return event.loop();
 }
 
-} // namespace network
-} // namespace phosphor
+} // namespace phosphor::network
 
 int main(int /*argc*/, char** /*argv*/)
 {
diff --git a/src/types.hpp b/src/types.hpp
index f426f81..8d1daf4 100644
--- a/src/types.hpp
+++ b/src/types.hpp
@@ -5,10 +5,8 @@
 
 #include <algorithm>
 #include <array>
-#include <chrono>
 #include <numeric>
-#include <sdeventplus/clock.hpp>
-#include <sdeventplus/utility/timer.hpp>
+#include <optional>
 #include <string>
 #include <string_view>
 #include <type_traits>
@@ -37,11 +35,6 @@
 namespace network
 {
 
-using namespace std::chrono_literals;
-
-// wait for three seconds before reloading systemd-networkd
-constexpr auto reloadTimeout = 3s;
-
 // Byte representations for common address types in network byte order
 using InAddrAny = std::variant<in_addr, in6_addr>;
 class IfAddr
@@ -85,8 +78,6 @@
     }
 };
 
-using Timer = sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>;
-
 /** @class InterfaceInfo
  *  @brief Information about interfaces from the kernel
  */
diff --git a/src/util.cpp b/src/util.cpp
index 675409f..14a1cb3 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -14,7 +14,6 @@
 #include <phosphor-logging/log.hpp>
 #include <string>
 #include <string_view>
-#include <variant>
 #include <xyz/openbmc_project/Common/error.hpp>
 
 namespace phosphor
diff --git a/test/global_network_objects.cpp b/test/global_network_objects.cpp
deleted file mode 100644
index 9442546..0000000
--- a/test/global_network_objects.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#include "mock_network_manager.hpp"
-#include "types.hpp"
-
-namespace phosphor
-{
-
-namespace network
-{
-
-std::unique_ptr<MockManager> manager = nullptr;
-std::unique_ptr<Timer> reloadTimer = nullptr;
-
-} // namespace network
-} // namespace phosphor
diff --git a/test/ibm/hypervisor-network-mgr-test/test_hyp_network_manager.cpp b/test/ibm/hypervisor-network-mgr-test/test_hyp_network_manager.cpp
index 08fa317..65914ac 100644
--- a/test/ibm/hypervisor-network-mgr-test/test_hyp_network_manager.cpp
+++ b/test/ibm/hypervisor-network-mgr-test/test_hyp_network_manager.cpp
@@ -17,10 +17,9 @@
   public:
     sdbusplus::bus_t bus;
     HypNetworkMgr manager;
-    sdeventplus::Event event = sdeventplus::Event::get_default();
     TestHypNetworkManager() :
         bus(sdbusplus::bus::new_default()),
-        manager(bus, event, "/xyz/openbmc_test/network/hypervisor")
+        manager(bus, "/xyz/openbmc_test/network/hypervisor")
     {
         // TODO: Once the support for ipv6 has been added, the below
         // method call to set default values in the local copy
diff --git a/test/ibm/hypervisor-network-mgr-test/test_hyp_sys_config.cpp b/test/ibm/hypervisor-network-mgr-test/test_hyp_sys_config.cpp
index 4e4382e..cb75eba 100644
--- a/test/ibm/hypervisor-network-mgr-test/test_hyp_sys_config.cpp
+++ b/test/ibm/hypervisor-network-mgr-test/test_hyp_sys_config.cpp
@@ -18,10 +18,9 @@
     sdbusplus::bus_t bus;
     HypNetworkMgr manager;
     MockHypSysConfig sysConfigObj;
-    sdeventplus::Event event = sdeventplus::Event::get_default();
     TestHypSysConfig() :
         bus(sdbusplus::bus::new_default()),
-        manager(bus, event, "/xyz/openbmc_test/network/hypervisor"),
+        manager(bus, "/xyz/openbmc_test/network/hypervisor"),
         sysConfigObj(bus, "/xyz/openbmc_test/network/hypervisor/config",
                      manager)
     {
diff --git a/test/meson.build b/test/meson.build
index 0e580fd..68eac09 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -33,7 +33,6 @@
 test_lib = static_library(
   'networkd-test',
   'mock_syscall.cpp',
-  'global_network_objects.cpp',
   implicit_include_directories: false,
   include_directories: test_headers,
   dependencies: test_deps)
diff --git a/test/mock_network_manager.hpp b/test/mock_network_manager.hpp
deleted file mode 100644
index 87214d4..0000000
--- a/test/mock_network_manager.hpp
+++ /dev/null
@@ -1,26 +0,0 @@
-#pragma once
-#include "network_manager.hpp"
-
-#include <gmock/gmock.h>
-
-namespace phosphor
-{
-namespace network
-{
-
-class MockManager : public Manager
-{
-  public:
-    MockManager(sdbusplus::bus_t& bus, const char* path,
-                const std::string& dir) :
-        Manager(bus, path, dir)
-    {
-    }
-
-    MOCK_METHOD(void, reloadConfigs, (), (override));
-
-    using Manager::handleAdminState;
-};
-
-} // namespace network
-} // namespace phosphor
diff --git a/test/test_ethernet_interface.cpp b/test/test_ethernet_interface.cpp
index 2b52e4c..e9f3973 100644
--- a/test/test_ethernet_interface.cpp
+++ b/test/test_ethernet_interface.cpp
@@ -1,7 +1,7 @@
 #include "config_parser.hpp"
 #include "ipaddress.hpp"
 #include "mock_ethernet_interface.hpp"
-#include "mock_network_manager.hpp"
+#include "test_network_manager.hpp"
 
 #include <net/if.h>
 
@@ -26,7 +26,7 @@
   public:
     sdbusplus::bus_t bus;
     std::filesystem::path confDir;
-    MockManager manager;
+    TestManager manager;
     MockEthernetInterface interface;
     TestEthernetInterface() :
         bus(sdbusplus::bus::new_default()), confDir(CaseTmpDir()),
@@ -37,7 +37,7 @@
     }
 
     static MockEthernetInterface makeInterface(sdbusplus::bus_t& bus,
-                                               MockManager& manager)
+                                               TestManager& manager)
     {
         AllIntfInfo info{InterfaceInfo{.idx = 1, .flags = 0, .name = "test0"}};
         return {bus, manager, info, "/xyz/openbmc_test/network"sv,
@@ -125,7 +125,7 @@
 TEST_F(TestEthernetInterface, addStaticNameServers)
 {
     ServerList servers = {"9.1.1.1", "9.2.2.2", "9.3.3.3"};
-    EXPECT_CALL(manager, reloadConfigs());
+    EXPECT_CALL(manager.mockReload, schedule());
     interface.staticNameServers(servers);
     config::Parser parser((confDir / "00-bmc-test0.network").native());
     EXPECT_EQ(servers, parser.map.getValueStrings("Network", "DNS"));
@@ -142,7 +142,7 @@
 TEST_F(TestEthernetInterface, addStaticNTPServers)
 {
     ServerList servers = {"10.1.1.1", "10.2.2.2", "10.3.3.3"};
-    EXPECT_CALL(manager, reloadConfigs());
+    EXPECT_CALL(manager.mockReload, schedule());
     interface.staticNTPServers(servers);
     config::Parser parser((confDir / "00-bmc-test0.network").native());
     EXPECT_EQ(servers, parser.map.getValueStrings("Network", "NTP"));
@@ -182,7 +182,8 @@
 
 TEST_F(TestEthernetInterface, DHCPEnabled)
 {
-    EXPECT_CALL(manager, reloadConfigs()).WillRepeatedly(testing::Return());
+    EXPECT_CALL(manager.mockReload, schedule())
+        .WillRepeatedly(testing::Return());
 
     using DHCPConf = EthernetInterfaceIntf::DHCPConf;
     auto test = [&](DHCPConf conf, bool dhcp4, bool dhcp6, bool ra) {
diff --git a/test/test_network_manager.cpp b/test/test_network_manager.cpp
index ffffb44..2e51ac1 100644
--- a/test/test_network_manager.cpp
+++ b/test/test_network_manager.cpp
@@ -1,5 +1,6 @@
+#include "test_network_manager.hpp"
+
 #include "config_parser.hpp"
-#include "mock_network_manager.hpp"
 
 #include <filesystem>
 #include <sdbusplus/bus.hpp>
@@ -19,7 +20,7 @@
 {
   protected:
     sdbusplus::bus_t bus;
-    MockManager manager;
+    TestManager manager;
     TestNetworkManager() :
         bus(sdbusplus::bus::new_default()),
         manager(bus, "/xyz/openbmc_test/abc", CaseTmpDir())
diff --git a/test/test_network_manager.hpp b/test/test_network_manager.hpp
new file mode 100644
index 0000000..eaf853b
--- /dev/null
+++ b/test/test_network_manager.hpp
@@ -0,0 +1,45 @@
+#pragma once
+#include "network_manager.hpp"
+
+#include <gmock/gmock.h>
+
+namespace phosphor
+{
+namespace network
+{
+
+struct MockExecutor : DelayedExecutor
+{
+    MOCK_METHOD((void), schedule, (), (override));
+    MOCK_METHOD((void), setCallback, (fu2::unique_function<void()> &&),
+                (override));
+};
+
+struct TestManagerData
+{
+    MockExecutor mockReload;
+    fu2::unique_function<void()> reloadCb;
+
+    inline MockExecutor& reloadForManager()
+    {
+        EXPECT_CALL(mockReload, setCallback(testing::_))
+            .WillOnce([&](fu2::unique_function<void()>&& cb) {
+                reloadCb = std::move(cb);
+            });
+        return mockReload;
+    }
+};
+
+struct TestManager : TestManagerData, Manager
+{
+    inline TestManager(sdbusplus::bus_t& bus, stdplus::zstring_view path,
+                       const std::filesystem::path& dir) :
+        Manager(bus, reloadForManager(), path, dir)
+    {
+    }
+
+    using Manager::handleAdminState;
+};
+
+} // namespace network
+} // namespace phosphor