pseq: Add Services class for automated testing

Add a Services class hierarchy to enable mocking and automated testing.
The class methods provide a high level abstraction for system services
like error logging and presence detection.

* Services: Abstract base class
* BMCServices: Sub-class with real implementation using BMC services
* MockServices: Sub-class with mock implementation for automated testing

* Tested:
  * Tested all methods in BMCServices class
    * When method succeeds
    * When method fails; verify all error paths
  * The detailed test plan is available in a gist:
    * https://gist.github.com/smccarney/e7a250011133c7e3040a8bce240705c5

Change-Id: If17ef8c4540b3ee07cced947bc49a950141b38ae
Signed-off-by: Shawn McCarney <shawnmm@us.ibm.com>
diff --git a/phosphor-power-sequencer/test/mock_pmbus.hpp b/phosphor-power-sequencer/test/mock_pmbus.hpp
new file mode 100644
index 0000000..587e08b
--- /dev/null
+++ b/phosphor-power-sequencer/test/mock_pmbus.hpp
@@ -0,0 +1,58 @@
+/**
+ * Copyright © 2024 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "pmbus.hpp"
+
+#include <gmock/gmock.h>
+
+namespace phosphor::pmbus
+{
+
+/**
+ * @class MockPMBus
+ *
+ * Mock implementation of the PMBusBase interface.
+ */
+class MockPMBus : public PMBusBase
+{
+  public:
+    // Specify which compiler-generated methods we want
+    MockPMBus() = default;
+    MockPMBus(const MockPMBus&) = delete;
+    MockPMBus(MockPMBus&&) = delete;
+    MockPMBus& operator=(const MockPMBus&) = delete;
+    MockPMBus& operator=(MockPMBus&&) = delete;
+    virtual ~MockPMBus() = default;
+
+    MOCK_METHOD(uint64_t, read,
+                (const std::string& name, Type type, bool errTrace),
+                (override));
+    MOCK_METHOD(std::string, readString, (const std::string& name, Type type),
+                (override));
+    MOCK_METHOD(std::vector<uint8_t>, readBinary,
+                (const std::string& name, Type type, size_t length),
+                (override));
+    MOCK_METHOD(void, writeBinary,
+                (const std::string& name, std::vector<uint8_t> data, Type type),
+                (override));
+    MOCK_METHOD(void, findHwmonDir, (), (override));
+    MOCK_METHOD(const fs::path&, path, (), (const, override));
+    MOCK_METHOD(std::string, insertPageNum,
+                (const std::string& templateName, size_t page), (override));
+};
+
+} // namespace phosphor::pmbus
diff --git a/phosphor-power-sequencer/test/mock_services.hpp b/phosphor-power-sequencer/test/mock_services.hpp
new file mode 100644
index 0000000..78ccbc2
--- /dev/null
+++ b/phosphor-power-sequencer/test/mock_services.hpp
@@ -0,0 +1,63 @@
+/**
+ * Copyright © 2024 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "mock_pmbus.hpp"
+#include "services.hpp"
+
+#include <gmock/gmock.h>
+
+namespace phosphor::power::sequencer
+{
+
+/**
+ * @class MockServices
+ *
+ * Mock implementation of the Services interface.
+ */
+class MockServices : public Services
+{
+  public:
+    // Specify which compiler-generated methods we want
+    MockServices() = default;
+    MockServices(const MockServices&) = delete;
+    MockServices(MockServices&&) = delete;
+    MockServices& operator=(const MockServices&) = delete;
+    MockServices& operator=(MockServices&&) = delete;
+    virtual ~MockServices() = default;
+
+    MOCK_METHOD(sdbusplus::bus_t&, getBus, (), (override));
+    MOCK_METHOD(void, logErrorMsg, (const std::string& message), (override));
+    MOCK_METHOD(void, logInfoMsg, (const std::string& message), (override));
+    MOCK_METHOD(void, logError,
+                (const std::string& message, Entry::Level severity,
+                 std::map<std::string, std::string>& additionalData),
+                (override));
+    MOCK_METHOD(bool, isPresent, (const std::string& inventoryPath),
+                (override));
+    MOCK_METHOD(std::vector<int>, getGPIOValues, (const std::string& chipLabel),
+                (override));
+
+    virtual std::unique_ptr<PMBusBase>
+        createPMBus(uint8_t bus, uint16_t address,
+                    const std::string& driverName = "",
+                    size_t instance = 0) override
+    {
+        return std::make_unique<MockPMBus>();
+    }
+};
+
+} // namespace phosphor::power::sequencer