Refactor to use new version of OEM IPMI Handler

Using the new version of ipmi handler provide a higher level wrapper
over the same functionalities. It helps us parse the input and output to
have more control of the input/output we see.

Changes to note,
- All cmd are removed from the request data. That is automatically
  extracted now.

Tested:
Unit Test Passed.

All IPMI OEM command still works the same as before this change.

```
$ burn_my_bmc -command stage -image /tmp/test.txt -interface ipmipci
Set up ipmi flash updater with /flash/dummy
Received failure on delete: Received IPMI_CC: 255
Sending over the firmware image.
Find [0x1050 0x750]
bar0[0x94000000]
Upload to BMC 100% |Goooooooooooooooooooooooooooooooooooooooooooooooooooooooogle| Time: 00:00:00
Opening the verification file
Committing to /flash/verify to trigger service
Calling stat on /flash/verify session to check status
success
succeeded
```

Also tested gBMC Update workflow which worked fine.

Change-Id: Ib2bfeab0c2ec5aa72ede1ff457ef5f90e488053c
Signed-off-by: Willy Tu <wltu@google.com>
diff --git a/test/helper.cpp b/test/helper.cpp
new file mode 100644
index 0000000..73e19aa
--- /dev/null
+++ b/test/helper.cpp
@@ -0,0 +1,32 @@
+#include "helper.hpp"
+
+#include "ipmi.hpp"
+
+#include <ipmid/api-types.hpp>
+#include <optional>
+#include <span>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+namespace blobs
+{
+std::vector<std::uint8_t>
+    validateReply(ipmi::RspType<std::vector<uint8_t>> reply, bool hasData)
+{
+    // Reply is in the form of
+    // std::tuple<ipmi::Cc, std::optional<std::tuple<RetTypes...>>>
+    EXPECT_EQ(::ipmi::ccSuccess, std::get<0>(reply));
+
+    auto actualReply = std::get<1>(reply);
+    EXPECT_TRUE(actualReply.has_value());
+
+    auto data = std::get<0>(*actualReply);
+    EXPECT_EQ(hasData, !data.empty());
+
+    return hasData ? data : std::vector<uint8_t>{};
+}
+
+} // namespace blobs
diff --git a/test/helper.hpp b/test/helper.hpp
new file mode 100644
index 0000000..8d33f5c
--- /dev/null
+++ b/test/helper.hpp
@@ -0,0 +1,15 @@
+#include <ipmid/api-types.hpp>
+#include <optional>
+#include <span>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+namespace blobs
+{
+std::vector<std::uint8_t>
+    validateReply(ipmi::RspType<std::vector<uint8_t>> reply,
+                  bool hasData = true);
+} // namespace blobs
diff --git a/test/ipmi_close_unittest.cpp b/test/ipmi_close_unittest.cpp
index af2e03e..d4bcb41 100644
--- a/test/ipmi_close_unittest.cpp
+++ b/test/ipmi_close_unittest.cpp
@@ -11,10 +11,6 @@
 
 using ::testing::Return;
 
-// ipmid.hpp isn't installed where we can grab it and this value is per BMC
-// SoC.
-#define MAX_IPMI_BUFFER 64
-
 TEST(BlobCloseTest, ManagerRejectsCloseReturnsFailure)
 {
     // The session manager returned failure to close, which we need to pass on.
@@ -22,21 +18,18 @@
     ManagerMock mgr;
     uint16_t sessionId = 0x54;
     size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
+    std::vector<uint8_t> request;
     struct BmcBlobCloseTx req;
 
-    req.cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobClose);
     req.crc = 0;
     req.sessionId = sessionId;
 
     dataLen = sizeof(req);
-
-    std::memcpy(request, &req, sizeof(req));
+    request.resize(dataLen);
+    std::memcpy(request.data(), &req, dataLen);
 
     EXPECT_CALL(mgr, close(sessionId)).WillOnce(Return(false));
-    EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR,
-              closeBlob(&mgr, request, reply, &dataLen));
+    EXPECT_EQ(ipmi::responseUnspecifiedError(), closeBlob(&mgr, request));
 }
 
 TEST(BlobCloseTest, BlobClosedReturnsSuccess)
@@ -46,19 +39,18 @@
     ManagerMock mgr;
     uint16_t sessionId = 0x54;
     size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
+    std::vector<uint8_t> request;
     struct BmcBlobCloseTx req;
 
-    req.cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobClose);
     req.crc = 0;
     req.sessionId = sessionId;
 
     dataLen = sizeof(req);
-
-    std::memcpy(request, &req, sizeof(req));
+    request.resize(dataLen);
+    std::memcpy(request.data(), &req, dataLen);
 
     EXPECT_CALL(mgr, close(sessionId)).WillOnce(Return(true));
-    EXPECT_EQ(IPMI_CC_OK, closeBlob(&mgr, request, reply, &dataLen));
+    EXPECT_EQ(ipmi::responseSuccess(std::vector<uint8_t>{}),
+              closeBlob(&mgr, request));
 }
 } // namespace blobs
diff --git a/test/ipmi_commit_unittest.cpp b/test/ipmi_commit_unittest.cpp
index d4b9c58..6cc8223 100644
--- a/test/ipmi_commit_unittest.cpp
+++ b/test/ipmi_commit_unittest.cpp
@@ -12,31 +12,22 @@
 using ::testing::ElementsAreArray;
 using ::testing::Return;
 
-// ipmid.hpp isn't installed where we can grab it and this value is per BMC
-// SoC.
-#define MAX_IPMI_BUFFER 64
-
 TEST(BlobCommitTest, InvalidCommitDataLengthReturnsFailure)
 {
     // The commit command supports an optional commit blob.  This test verifies
     // we sanity check the length of that blob.
 
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    auto req = reinterpret_cast<struct BmcBlobCommitTx*>(request);
-
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobCommit);
-    req->crc = 0;
-    req->sessionId = 0x54;
-    req->commitDataLen =
+    std::vector<uint8_t> request;
+    struct BmcBlobCommitTx req;
+    req.crc = 0;
+    req.sessionId = 0x54;
+    req.commitDataLen =
         1; // It's one byte, but that's more than the packet size.
 
-    dataLen = sizeof(struct BmcBlobCommitTx);
-
-    EXPECT_EQ(IPMI_CC_REQ_DATA_LEN_INVALID,
-              commitBlob(&mgr, request, reply, &dataLen));
+    request.resize(sizeof(struct BmcBlobCommitTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobCommitTx));
+    EXPECT_EQ(ipmi::responseReqDataLenInvalid(), commitBlob(&mgr, request));
 }
 
 TEST(BlobCommitTest, ValidCommitNoDataHandlerRejectsReturnsFailure)
@@ -44,22 +35,17 @@
     // The commit packet is valid and the manager's commit call returns failure.
 
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    auto req = reinterpret_cast<struct BmcBlobCommitTx*>(request);
+    std::vector<uint8_t> request;
+    struct BmcBlobCommitTx req;
+    req.crc = 0;
+    req.sessionId = 0x54;
+    req.commitDataLen = 0;
 
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobCommit);
-    req->crc = 0;
-    req->sessionId = 0x54;
-    req->commitDataLen = 0;
+    request.resize(sizeof(struct BmcBlobCommitTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobCommitTx));
 
-    dataLen = sizeof(struct BmcBlobCommitTx);
-
-    EXPECT_CALL(mgr, commit(req->sessionId, _)).WillOnce(Return(false));
-
-    EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR,
-              commitBlob(&mgr, request, reply, &dataLen));
+    EXPECT_CALL(mgr, commit(req.sessionId, _)).WillOnce(Return(false));
+    EXPECT_EQ(ipmi::responseUnspecifiedError(), commitBlob(&mgr, request));
 }
 
 TEST(BlobCommitTest, ValidCommitNoDataHandlerAcceptsReturnsSuccess)
@@ -67,21 +53,18 @@
     // Commit called with no data and everything returns success.
 
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    auto req = reinterpret_cast<struct BmcBlobCommitTx*>(request);
+    std::vector<uint8_t> request;
+    struct BmcBlobCommitTx req;
+    req.crc = 0;
+    req.sessionId = 0x54;
+    req.commitDataLen = 0;
 
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobCommit);
-    req->crc = 0;
-    req->sessionId = 0x54;
-    req->commitDataLen = 0;
+    request.resize(sizeof(struct BmcBlobCommitTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobCommitTx));
+    EXPECT_CALL(mgr, commit(req.sessionId, _)).WillOnce(Return(true));
 
-    dataLen = sizeof(struct BmcBlobCommitTx);
-
-    EXPECT_CALL(mgr, commit(req->sessionId, _)).WillOnce(Return(true));
-
-    EXPECT_EQ(IPMI_CC_OK, commitBlob(&mgr, request, reply, &dataLen));
+    EXPECT_EQ(ipmi::responseSuccess(std::vector<uint8_t>{}),
+              commitBlob(&mgr, request));
 }
 
 TEST(BlobCommitTest, ValidCommitWithDataHandlerAcceptsReturnsSuccess)
@@ -89,26 +72,21 @@
     // Commit called with extra data and everything returns success.
 
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    auto req = reinterpret_cast<struct BmcBlobCommitTx*>(request);
+    std::vector<uint8_t> request;
+    std::array<uint8_t, 4> expectedBlob = {0x25, 0x33, 0x45, 0x67};
+    struct BmcBlobCommitTx req;
+    req.crc = 0;
+    req.sessionId = 0x54;
+    req.commitDataLen = sizeof(expectedBlob);
 
-    uint8_t expectedBlob[4] = {0x25, 0x33, 0x45, 0x67};
+    request.resize(sizeof(struct BmcBlobCommitTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobCommitTx));
+    request.insert(request.end(), expectedBlob.begin(), expectedBlob.end());
 
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobCommit);
-    req->crc = 0;
-    req->sessionId = 0x54;
-    req->commitDataLen = sizeof(expectedBlob);
-    std::memcpy(req + 1, &expectedBlob[0], sizeof(expectedBlob));
-
-    dataLen = sizeof(struct BmcBlobCommitTx) + sizeof(expectedBlob);
-
-    EXPECT_CALL(mgr,
-                commit(req->sessionId,
-                       ElementsAreArray(expectedBlob, sizeof(expectedBlob))))
+    EXPECT_CALL(mgr, commit(req.sessionId, ElementsAreArray(expectedBlob)))
         .WillOnce(Return(true));
 
-    EXPECT_EQ(IPMI_CC_OK, commitBlob(&mgr, request, reply, &dataLen));
+    EXPECT_EQ(ipmi::responseSuccess(std::vector<uint8_t>{}),
+              commitBlob(&mgr, request));
 }
 } // namespace blobs
diff --git a/test/ipmi_delete_unittest.cpp b/test/ipmi_delete_unittest.cpp
index 3336b2d..cb1401a 100644
--- a/test/ipmi_delete_unittest.cpp
+++ b/test/ipmi_delete_unittest.cpp
@@ -12,79 +12,58 @@
 using ::testing::Return;
 using ::testing::StrEq;
 
-// ipmid.hpp isn't installed where we can grab it and this value is per BMC
-// SoC.
-#define MAX_IPMI_BUFFER 64
-
 TEST(BlobDeleteTest, InvalidRequestLengthReturnsFailure)
 {
     // There is a minimum blobId length of one character, this test verifies
     // we check that.
-
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    auto req = reinterpret_cast<struct BmcBlobDeleteTx*>(request);
+    std::vector<uint8_t> request;
+    struct BmcBlobDeleteTx req;
+    req.crc = 0;
     std::string blobId = "abc";
 
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobDelete);
-    req->crc = 0;
-    // length() doesn't include the nul-terminator.
-    std::memcpy(req + 1, blobId.c_str(), blobId.length());
+    request.resize(sizeof(struct BmcBlobDeleteTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobDeleteTx));
+    request.insert(request.end(), blobId.begin(), blobId.end());
 
-    dataLen = sizeof(struct BmcBlobDeleteTx) + blobId.length();
-
-    EXPECT_EQ(IPMI_CC_REQ_DATA_LEN_INVALID,
-              deleteBlob(&mgr, request, reply, &dataLen));
+    EXPECT_EQ(ipmi::responseReqDataLenInvalid(), deleteBlob(&mgr, request));
 }
 
 TEST(BlobDeleteTest, RequestRejectedReturnsFailure)
 {
     // The blobId is rejected for any reason.
-
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    auto req = reinterpret_cast<struct BmcBlobDeleteTx*>(request);
+    std::vector<uint8_t> request;
+    struct BmcBlobDeleteTx req;
+    req.crc = 0;
     std::string blobId = "a";
 
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobDelete);
-    req->crc = 0;
-    // length() doesn't include the nul-terminator, request buff is initialized
-    // to 0s
-    std::memcpy(req + 1, blobId.c_str(), blobId.length());
-
-    dataLen = sizeof(struct BmcBlobDeleteTx) + blobId.length() + 1;
+    request.resize(sizeof(struct BmcBlobDeleteTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobDeleteTx));
+    request.insert(request.end(), blobId.begin(), blobId.end());
+    request.emplace_back('\0');
 
     EXPECT_CALL(mgr, deleteBlob(StrEq(blobId))).WillOnce(Return(false));
-
-    EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR,
-              deleteBlob(&mgr, request, reply, &dataLen));
+    EXPECT_EQ(ipmi::responseUnspecifiedError(), deleteBlob(&mgr, request));
 }
 
 TEST(BlobDeleteTest, BlobDeleteReturnsOk)
 {
     // The boring case where the blobId is deleted.
-
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    auto req = reinterpret_cast<struct BmcBlobDeleteTx*>(request);
+    std::vector<uint8_t> request;
+    struct BmcBlobDeleteTx req;
+    req.crc = 0;
     std::string blobId = "a";
 
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobDelete);
-    req->crc = 0;
-    // length() doesn't include the nul-terminator, request buff is initialized
-    // to 0s
-    std::memcpy(req + 1, blobId.c_str(), blobId.length());
-
-    dataLen = sizeof(struct BmcBlobDeleteTx) + blobId.length() + 1;
+    request.resize(sizeof(struct BmcBlobDeleteTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobDeleteTx));
+    request.insert(request.end(), blobId.begin(), blobId.end());
+    request.emplace_back('\0');
 
     EXPECT_CALL(mgr, deleteBlob(StrEq(blobId))).WillOnce(Return(true));
 
-    EXPECT_EQ(IPMI_CC_OK, deleteBlob(&mgr, request, reply, &dataLen));
+    EXPECT_EQ(ipmi::responseSuccess(std::vector<uint8_t>{}),
+              deleteBlob(&mgr, request));
 }
 } // namespace blobs
diff --git a/test/ipmi_enumerate_unittest.cpp b/test/ipmi_enumerate_unittest.cpp
index edea82b..87752ea 100644
--- a/test/ipmi_enumerate_unittest.cpp
+++ b/test/ipmi_enumerate_unittest.cpp
@@ -1,3 +1,4 @@
+#include "helper.hpp"
 #include "ipmi.hpp"
 #include "manager_mock.hpp"
 
@@ -11,28 +12,21 @@
 
 using ::testing::Return;
 
-// ipmid.hpp isn't installed where we can grab it and this value is per BMC
-// SoC.
-#define MAX_IPMI_BUFFER 64
-
 TEST(BlobEnumerateTest, VerifyIfRequestByIdInvalidReturnsFailure)
 {
     // This tests to verify that if the index is invalid, it'll return failure.
 
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
+    std::vector<uint8_t> request;
     struct BmcBlobEnumerateTx req;
-    uint8_t* request = reinterpret_cast<uint8_t*>(&req);
-
-    req.cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobEnumerate);
     req.blobIdx = 0;
-    dataLen = sizeof(struct BmcBlobEnumerateTx);
+
+    request.resize(sizeof(struct BmcBlobEnumerateTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobEnumerateTx));
 
     EXPECT_CALL(mgr, getBlobId(req.blobIdx)).WillOnce(Return(""));
-
-    EXPECT_EQ(IPMI_CC_INVALID_FIELD_REQUEST,
-              enumerateBlob(&mgr, request, reply, &dataLen));
+    EXPECT_EQ(ipmi::responseInvalidFieldRequest(),
+              enumerateBlob(&mgr, request));
 }
 
 TEST(BlobEnumerateTest, BoringRequestByIdAndReceive)
@@ -41,26 +35,23 @@
     // will return the blobId.
 
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
+    std::vector<uint8_t> request;
     struct BmcBlobEnumerateTx req;
-    struct BmcBlobEnumerateRx* rep;
-    uint8_t* request = reinterpret_cast<uint8_t*>(&req);
+    req.blobIdx = 0;
     std::string blobId = "/asdf";
 
-    req.cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobEnumerate);
-    req.blobIdx = 0;
-    dataLen = sizeof(struct BmcBlobEnumerateTx);
+    request.resize(sizeof(struct BmcBlobEnumerateTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobEnumerateTx));
 
     EXPECT_CALL(mgr, getBlobId(req.blobIdx)).WillOnce(Return(blobId));
 
-    EXPECT_EQ(IPMI_CC_OK, enumerateBlob(&mgr, request, reply, &dataLen));
+    auto result = validateReply(enumerateBlob(&mgr, request));
 
     // We're expecting this as a response.
     // blobId.length + 1 + sizeof(uint16_t);
-    EXPECT_EQ(blobId.length() + 1 + sizeof(uint16_t), dataLen);
-
-    rep = reinterpret_cast<struct BmcBlobEnumerateRx*>(reply);
-    EXPECT_EQ(0, std::memcmp(rep + 1, blobId.c_str(), blobId.length() + 1));
+    EXPECT_EQ(blobId.length() + 1 + sizeof(uint16_t), result.size());
+    EXPECT_EQ(blobId,
+              // Remove crc and nul-terminator.
+              std::string(result.begin() + sizeof(uint16_t), result.end() - 1));
 }
 } // namespace blobs
diff --git a/test/ipmi_getcount_unittest.cpp b/test/ipmi_getcount_unittest.cpp
index 34fc33d..dc1202d 100644
--- a/test/ipmi_getcount_unittest.cpp
+++ b/test/ipmi_getcount_unittest.cpp
@@ -1,3 +1,4 @@
+#include "helper.hpp"
 #include "ipmi.hpp"
 #include "manager_mock.hpp"
 
@@ -11,10 +12,6 @@
 
 using ::testing::Return;
 
-// ipmid.hpp isn't installed where we can grab it and this value is per BMC
-// SoC.
-#define MAX_IPMI_BUFFER 64
-
 // the request here is only the subcommand byte and therefore there's no invalid
 // length check, etc to handle within the method.
 
@@ -24,24 +21,17 @@
     // return that there are 0 blobs.
 
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    struct BmcBlobCountTx req;
     struct BmcBlobCountRx rep;
-    uint8_t* request = reinterpret_cast<uint8_t*>(&req);
-
-    req.cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobGetCount);
-    dataLen = sizeof(req);
 
     rep.crc = 0;
     rep.blobCount = 0;
 
     EXPECT_CALL(mgr, buildBlobList()).WillOnce(Return(0));
 
-    EXPECT_EQ(IPMI_CC_OK, getBlobCount(&mgr, request, reply, &dataLen));
+    auto result = validateReply(getBlobCount(&mgr, {}));
 
-    EXPECT_EQ(sizeof(rep), dataLen);
-    EXPECT_EQ(0, std::memcmp(reply, &rep, sizeof(rep)));
+    EXPECT_EQ(sizeof(rep), result.size());
+    EXPECT_EQ(0, std::memcmp(result.data(), &rep, sizeof(rep)));
 }
 
 TEST(BlobCountTest, ReturnsTwoBlobs)
@@ -50,23 +40,16 @@
     // blobs will return that it found two blobs.
 
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    struct BmcBlobCountTx req;
     struct BmcBlobCountRx rep;
-    uint8_t* request = reinterpret_cast<uint8_t*>(&req);
-
-    req.cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobGetCount);
-    dataLen = sizeof(req);
 
     rep.crc = 0;
     rep.blobCount = 2;
 
     EXPECT_CALL(mgr, buildBlobList()).WillOnce(Return(2));
 
-    EXPECT_EQ(IPMI_CC_OK, getBlobCount(&mgr, request, reply, &dataLen));
+    auto result = validateReply(getBlobCount(&mgr, {}));
 
-    EXPECT_EQ(sizeof(rep), dataLen);
-    EXPECT_EQ(0, std::memcmp(reply, &rep, sizeof(rep)));
+    EXPECT_EQ(sizeof(rep), result.size());
+    EXPECT_EQ(0, std::memcmp(result.data(), &rep, sizeof(rep)));
 }
 } // namespace blobs
diff --git a/test/ipmi_open_unittest.cpp b/test/ipmi_open_unittest.cpp
index 5b18631..b938cbe 100644
--- a/test/ipmi_open_unittest.cpp
+++ b/test/ipmi_open_unittest.cpp
@@ -1,3 +1,4 @@
+#include "helper.hpp"
 #include "ipmi.hpp"
 #include "manager_mock.hpp"
 
@@ -15,59 +16,44 @@
 using ::testing::Return;
 using ::testing::StrEq;
 
-// ipmid.hpp isn't installed where we can grab it and this value is per BMC
-// SoC.
-#define MAX_IPMI_BUFFER 64
-
 TEST(BlobOpenTest, InvalidRequestLengthReturnsFailure)
 {
     // There is a minimum blobId length of one character, this test verifies
     // we check that.
-
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    auto req = reinterpret_cast<struct BmcBlobOpenTx*>(request);
+    std::vector<uint8_t> request;
+    BmcBlobOpenTx req;
     std::string blobId = "abc";
 
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobOpen);
-    req->crc = 0;
-    req->flags = 0;
-    // length() doesn't include the nul-terminator.
-    std::memcpy(req + 1, blobId.c_str(), blobId.length());
+    req.crc = 0;
+    req.flags = 0;
 
-    dataLen = sizeof(struct BmcBlobOpenTx) + blobId.length();
+    // Missintg the nul-terminator.
+    request.resize(sizeof(struct BmcBlobOpenTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobOpenTx));
+    request.insert(request.end(), blobId.begin(), blobId.end());
 
-    EXPECT_EQ(IPMI_CC_REQ_DATA_LEN_INVALID,
-              openBlob(&mgr, request, reply, &dataLen));
+    EXPECT_EQ(ipmi::responseReqDataLenInvalid(), openBlob(&mgr, request));
 }
 
 TEST(BlobOpenTest, RequestRejectedReturnsFailure)
 {
     // The blobId is rejected for any reason.
-
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    auto req = reinterpret_cast<struct BmcBlobOpenTx*>(request);
+    std::vector<uint8_t> request;
+    BmcBlobOpenTx req;
     std::string blobId = "a";
 
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobOpen);
-    req->crc = 0;
-    req->flags = 0;
-    // length() doesn't include the nul-terminator, request buff is initialized
-    // to 0s
-    std::memcpy(req + 1, blobId.c_str(), blobId.length());
+    req.crc = 0;
+    req.flags = 0;
+    request.resize(sizeof(struct BmcBlobOpenTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobOpenTx));
+    request.insert(request.end(), blobId.begin(), blobId.end());
+    request.emplace_back('\0');
 
-    dataLen = sizeof(struct BmcBlobOpenTx) + blobId.length() + 1;
+    EXPECT_CALL(mgr, open(req.flags, StrEq(blobId), _)).WillOnce(Return(false));
 
-    EXPECT_CALL(mgr, open(req->flags, StrEq(blobId), _))
-        .WillOnce(Return(false));
-
-    EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR,
-              openBlob(&mgr, request, reply, &dataLen));
+    EXPECT_EQ(ipmi::responseUnspecifiedError(), openBlob(&mgr, request));
 }
 
 TEST(BlobOpenTest, BlobOpenReturnsOk)
@@ -75,35 +61,32 @@
     // The boring case where the blobId opens.
 
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    auto req = reinterpret_cast<struct BmcBlobOpenTx*>(request);
+    std::vector<uint8_t> request;
+    BmcBlobOpenTx req;
     struct BmcBlobOpenRx rep;
     std::string blobId = "a";
 
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobOpen);
-    req->crc = 0;
-    req->flags = 0;
-    // length() doesn't include the nul-terminator, request buff is initialized
-    // to 0s
-    std::memcpy(req + 1, blobId.c_str(), blobId.length());
+    req.crc = 0;
+    req.flags = 0;
+    request.resize(sizeof(struct BmcBlobOpenTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobOpenTx));
+    request.insert(request.end(), blobId.begin(), blobId.end());
+    request.emplace_back('\0');
 
-    dataLen = sizeof(struct BmcBlobOpenTx) + blobId.length() + 1;
     uint16_t returnedSession = 0x54;
 
-    EXPECT_CALL(mgr, open(req->flags, StrEq(blobId), NotNull()))
+    EXPECT_CALL(mgr, open(req.flags, StrEq(blobId), NotNull()))
         .WillOnce(Invoke([&](uint16_t, const std::string&, uint16_t* session) {
             (*session) = returnedSession;
             return true;
         }));
 
-    EXPECT_EQ(IPMI_CC_OK, openBlob(&mgr, request, reply, &dataLen));
+    auto result = validateReply(openBlob(&mgr, request));
 
     rep.crc = 0;
     rep.sessionId = returnedSession;
 
-    EXPECT_EQ(sizeof(rep), dataLen);
-    EXPECT_EQ(0, std::memcmp(reply, &rep, sizeof(rep)));
+    EXPECT_EQ(sizeof(rep), result.size());
+    EXPECT_EQ(0, std::memcmp(result.data(), &rep, sizeof(rep)));
 }
 } // namespace blobs
diff --git a/test/ipmi_read_unittest.cpp b/test/ipmi_read_unittest.cpp
index 8d1b55f..80e1cbc 100644
--- a/test/ipmi_read_unittest.cpp
+++ b/test/ipmi_read_unittest.cpp
@@ -1,3 +1,4 @@
+#include "helper.hpp"
 #include "ipmi.hpp"
 #include "manager_mock.hpp"
 
@@ -11,64 +12,50 @@
 
 using ::testing::Return;
 
-// ipmid.hpp isn't installed where we can grab it and this value is per BMC
-// SoC.
-#define MAX_IPMI_BUFFER 64
-
 TEST(BlobReadTest, ManagerReturnsNoData)
 {
     // Verify that if no data is returned the IPMI command reply has no
     // payload.  The manager, in all failures, will just return 0 bytes.
-
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    auto req = reinterpret_cast<struct BmcBlobReadTx*>(request);
+    std::vector<uint8_t> request;
+    struct BmcBlobReadTx req;
 
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobRead);
-    req->crc = 0;
-    req->sessionId = 0x54;
-    req->offset = 0x100;
-    req->requestedSize = 0x10;
-
-    dataLen = sizeof(struct BmcBlobReadTx);
-
+    req.crc = 0;
+    req.sessionId = 0x54;
+    req.offset = 0x100;
+    req.requestedSize = 0x10;
+    request.resize(sizeof(struct BmcBlobReadTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobReadTx));
     std::vector<uint8_t> data;
 
-    EXPECT_CALL(mgr, read(req->sessionId, req->offset, req->requestedSize))
+    EXPECT_CALL(mgr, read(req.sessionId, req.offset, req.requestedSize))
         .WillOnce(Return(data));
 
-    EXPECT_EQ(IPMI_CC_OK, readBlob(&mgr, request, reply, &dataLen));
-    EXPECT_EQ(sizeof(struct BmcBlobReadRx), dataLen);
+    auto result = validateReply(readBlob(&mgr, request));
+    EXPECT_EQ(sizeof(struct BmcBlobReadRx), result.size());
 }
 
 TEST(BlobReadTest, ManagerReturnsData)
 {
     // Verify that if data is returned, it's placed in the expected location.
-
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    auto req = reinterpret_cast<struct BmcBlobReadTx*>(request);
+    std::vector<uint8_t> request;
+    struct BmcBlobReadTx req;
 
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobRead);
-    req->crc = 0;
-    req->sessionId = 0x54;
-    req->offset = 0x100;
-    req->requestedSize = 0x10;
-
-    dataLen = sizeof(struct BmcBlobReadTx);
-
+    req.crc = 0;
+    req.sessionId = 0x54;
+    req.offset = 0x100;
+    req.requestedSize = 0x10;
+    request.resize(sizeof(struct BmcBlobReadTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobReadTx));
     std::vector<uint8_t> data = {0x02, 0x03, 0x05, 0x06};
 
-    EXPECT_CALL(mgr, read(req->sessionId, req->offset, req->requestedSize))
+    EXPECT_CALL(mgr, read(req.sessionId, req.offset, req.requestedSize))
         .WillOnce(Return(data));
 
-    EXPECT_EQ(IPMI_CC_OK, readBlob(&mgr, request, reply, &dataLen));
-    EXPECT_EQ(sizeof(struct BmcBlobReadRx) + data.size(), dataLen);
-    EXPECT_EQ(0, std::memcmp(&reply[sizeof(struct BmcBlobReadRx)], data.data(),
+    auto result = validateReply(readBlob(&mgr, request));
+    EXPECT_EQ(sizeof(struct BmcBlobReadRx) + data.size(), result.size());
+    EXPECT_EQ(0, std::memcmp(&result[sizeof(struct BmcBlobReadRx)], data.data(),
                              data.size()));
 }
 
diff --git a/test/ipmi_sessionstat_unittest.cpp b/test/ipmi_sessionstat_unittest.cpp
index 4bf1125..3278f25 100644
--- a/test/ipmi_sessionstat_unittest.cpp
+++ b/test/ipmi_sessionstat_unittest.cpp
@@ -1,3 +1,4 @@
+#include "helper.hpp"
 #include "ipmi.hpp"
 #include "manager_mock.hpp"
 
@@ -23,22 +24,19 @@
     // If the session ID is invalid, the request must fail.
 
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    auto req = reinterpret_cast<struct BmcBlobSessionStatTx*>(request);
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobSessionStat);
-    req->crc = 0;
-    req->sessionId = 0x54;
+    std::vector<uint8_t> request;
+    struct BmcBlobSessionStatTx req;
+    req.crc = 0;
+    req.sessionId = 0x54;
 
-    dataLen = sizeof(struct BmcBlobSessionStatTx);
+    request.resize(sizeof(struct BmcBlobSessionStatTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobSessionStatTx));
 
     EXPECT_CALL(mgr,
-                stat(Matcher<uint16_t>(req->sessionId), Matcher<BlobMeta*>(_)))
+                stat(Matcher<uint16_t>(req.sessionId), Matcher<BlobMeta*>(_)))
         .WillOnce(Return(false));
 
-    EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR,
-              sessionStatBlob(&mgr, request, reply, &dataLen));
+    EXPECT_EQ(ipmi::responseUnspecifiedError(), sessionStatBlob(&mgr, request));
 }
 
 TEST(BlobSessionStatTest, RequestSucceedsNoMetadata)
@@ -46,15 +44,13 @@
     // Stat request succeeeds but there were no metadata bytes.
 
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    auto req = reinterpret_cast<struct BmcBlobSessionStatTx*>(request);
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobSessionStat);
-    req->crc = 0;
-    req->sessionId = 0x54;
+    std::vector<uint8_t> request;
+    struct BmcBlobSessionStatTx req;
+    req.crc = 0;
+    req.sessionId = 0x54;
 
-    dataLen = sizeof(struct BmcBlobSessionStatTx);
+    request.resize(sizeof(struct BmcBlobSessionStatTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobSessionStatTx));
 
     struct BmcBlobStatRx rep;
     rep.crc = 0x00;
@@ -65,7 +61,7 @@
     uint16_t blobState = rep.blobState;
     uint32_t size = rep.size;
 
-    EXPECT_CALL(mgr, stat(Matcher<uint16_t>(req->sessionId),
+    EXPECT_CALL(mgr, stat(Matcher<uint16_t>(req.sessionId),
                           Matcher<BlobMeta*>(NotNull())))
         .WillOnce(Invoke([&](uint16_t, BlobMeta* meta) {
             meta->blobState = blobState;
@@ -73,10 +69,10 @@
             return true;
         }));
 
-    EXPECT_EQ(IPMI_CC_OK, sessionStatBlob(&mgr, request, reply, &dataLen));
+    auto result = validateReply(sessionStatBlob(&mgr, request));
 
-    EXPECT_EQ(sizeof(rep), dataLen);
-    EXPECT_EQ(0, std::memcmp(reply, &rep, sizeof(rep)));
+    EXPECT_EQ(sizeof(rep), result.size());
+    EXPECT_EQ(0, std::memcmp(result.data(), &rep, sizeof(rep)));
 }
 
 TEST(BlobSessionStatTest, RequestSucceedsWithMetadata)
@@ -84,15 +80,13 @@
     // Stat request succeeds and there were metadata bytes.
 
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    auto req = reinterpret_cast<struct BmcBlobSessionStatTx*>(request);
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobSessionStat);
-    req->crc = 0;
-    req->sessionId = 0x54;
+    std::vector<uint8_t> request;
+    struct BmcBlobSessionStatTx req;
+    req.crc = 0;
+    req.sessionId = 0x54;
 
-    dataLen = sizeof(struct BmcBlobSessionStatTx);
+    request.resize(sizeof(struct BmcBlobSessionStatTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobSessionStatTx));
 
     BlobMeta lmeta;
     lmeta.blobState = 0x01;
@@ -108,18 +102,18 @@
     rep.size = lmeta.size;
     rep.metadataLen = lmeta.metadata.size();
 
-    EXPECT_CALL(mgr, stat(Matcher<uint16_t>(req->sessionId),
+    EXPECT_CALL(mgr, stat(Matcher<uint16_t>(req.sessionId),
                           Matcher<BlobMeta*>(NotNull())))
         .WillOnce(Invoke([&](uint16_t, BlobMeta* meta) {
             (*meta) = lmeta;
             return true;
         }));
 
-    EXPECT_EQ(IPMI_CC_OK, sessionStatBlob(&mgr, request, reply, &dataLen));
+    auto result = validateReply(sessionStatBlob(&mgr, request));
 
-    EXPECT_EQ(sizeof(rep) + lmeta.metadata.size(), dataLen);
-    EXPECT_EQ(0, std::memcmp(reply, &rep, sizeof(rep)));
-    EXPECT_EQ(0, std::memcmp(reply + sizeof(rep), lmeta.metadata.data(),
+    EXPECT_EQ(sizeof(rep) + lmeta.metadata.size(), result.size());
+    EXPECT_EQ(0, std::memcmp(result.data(), &rep, sizeof(rep)));
+    EXPECT_EQ(0, std::memcmp(result.data() + sizeof(rep), lmeta.metadata.data(),
                              lmeta.metadata.size()));
 }
 } // namespace blobs
diff --git a/test/ipmi_stat_unittest.cpp b/test/ipmi_stat_unittest.cpp
index 6d4d7b2..ab091ad 100644
--- a/test/ipmi_stat_unittest.cpp
+++ b/test/ipmi_stat_unittest.cpp
@@ -1,3 +1,4 @@
+#include "helper.hpp"
 #include "ipmi.hpp"
 #include "manager_mock.hpp"
 
@@ -24,23 +25,18 @@
 {
     // There is a minimum blobId length of one character, this test verifies
     // we check that.
-
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    auto req = reinterpret_cast<struct BmcBlobStatTx*>(request);
+    std::vector<uint8_t> request;
+    struct BmcBlobStatTx req;
     std::string blobId = "abc";
 
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobStat);
-    req->crc = 0;
-    // length() doesn't include the nul-terminator.
-    std::memcpy(req + 1, blobId.c_str(), blobId.length());
+    req.crc = 0;
+    request.resize(sizeof(struct BmcBlobStatTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobStatTx));
+    // Do not include the nul-terminator
+    request.insert(request.end(), blobId.begin(), blobId.end());
 
-    dataLen = sizeof(struct BmcBlobStatTx) + blobId.length();
-
-    EXPECT_EQ(IPMI_CC_REQ_DATA_LEN_INVALID,
-              statBlob(&mgr, request, reply, &dataLen));
+    EXPECT_EQ(ipmi::responseReqDataLenInvalid(), statBlob(&mgr, request));
 }
 
 TEST(BlobStatTest, RequestRejectedReturnsFailure)
@@ -48,26 +44,21 @@
     // The blobId is rejected for any reason.
 
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    auto req = reinterpret_cast<struct BmcBlobStatTx*>(request);
+    std::vector<uint8_t> request;
+    struct BmcBlobStatTx req;
     std::string blobId = "a";
 
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobStat);
-    req->crc = 0;
-    // length() doesn't include the nul-terminator, request buff is initialized
-    // to 0s
-    std::memcpy(req + 1, blobId.c_str(), blobId.length());
-
-    dataLen = sizeof(struct BmcBlobStatTx) + blobId.length() + 1;
+    req.crc = 0;
+    request.resize(sizeof(struct BmcBlobStatTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobStatTx));
+    request.insert(request.end(), blobId.begin(), blobId.end());
+    request.emplace_back('\0');
 
     EXPECT_CALL(mgr, stat(Matcher<const std::string&>(StrEq(blobId)),
                           Matcher<BlobMeta*>(_)))
         .WillOnce(Return(false));
 
-    EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR,
-              statBlob(&mgr, request, reply, &dataLen));
+    EXPECT_EQ(ipmi::responseUnspecifiedError(), statBlob(&mgr, request));
 }
 
 TEST(BlobStatTest, RequestSucceedsNoMetadata)
@@ -75,19 +66,15 @@
     // Stat request succeeeds but there were no metadata bytes.
 
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    auto req = reinterpret_cast<struct BmcBlobStatTx*>(request);
+    std::vector<uint8_t> request;
+    struct BmcBlobStatTx req;
     std::string blobId = "a";
 
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobStat);
-    req->crc = 0;
-    // length() doesn't include the nul-terminator, request buff is initialized
-    // to 0s
-    std::memcpy(req + 1, blobId.c_str(), blobId.length());
-
-    dataLen = sizeof(struct BmcBlobStatTx) + blobId.length() + 1;
+    req.crc = 0;
+    request.resize(sizeof(struct BmcBlobStatTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobStatTx));
+    request.insert(request.end(), blobId.begin(), blobId.end());
+    request.emplace_back('\0');
 
     struct BmcBlobStatRx rep;
     rep.crc = 0x00;
@@ -106,10 +93,10 @@
             return true;
         }));
 
-    EXPECT_EQ(IPMI_CC_OK, statBlob(&mgr, request, reply, &dataLen));
+    auto result = validateReply(statBlob(&mgr, request));
 
-    EXPECT_EQ(sizeof(rep), dataLen);
-    EXPECT_EQ(0, std::memcmp(reply, &rep, sizeof(rep)));
+    EXPECT_EQ(sizeof(rep), result.size());
+    EXPECT_EQ(0, std::memcmp(result.data(), &rep, sizeof(rep)));
 }
 
 TEST(BlobStatTest, RequestSucceedsWithMetadata)
@@ -117,19 +104,15 @@
     // Stat request succeeds and there were metadata bytes.
 
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    auto req = reinterpret_cast<struct BmcBlobStatTx*>(request);
+    std::vector<uint8_t> request;
+    struct BmcBlobStatTx req;
     std::string blobId = "a";
 
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobStat);
-    req->crc = 0;
-    // length() doesn't include the nul-terminator, request buff is initialized
-    // to 0s
-    std::memcpy(req + 1, blobId.c_str(), blobId.length());
-
-    dataLen = sizeof(struct BmcBlobStatTx) + blobId.length() + 1;
+    req.crc = 0;
+    request.resize(sizeof(struct BmcBlobStatTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobStatTx));
+    request.insert(request.end(), blobId.begin(), blobId.end());
+    request.emplace_back('\0');
 
     BlobMeta lmeta;
     lmeta.blobState = 0x01;
@@ -152,11 +135,11 @@
             return true;
         }));
 
-    EXPECT_EQ(IPMI_CC_OK, statBlob(&mgr, request, reply, &dataLen));
+    auto result = validateReply(statBlob(&mgr, request));
 
-    EXPECT_EQ(sizeof(rep) + lmeta.metadata.size(), dataLen);
-    EXPECT_EQ(0, std::memcmp(reply, &rep, sizeof(rep)));
-    EXPECT_EQ(0, std::memcmp(reply + sizeof(rep), lmeta.metadata.data(),
+    EXPECT_EQ(sizeof(rep) + lmeta.metadata.size(), result.size());
+    EXPECT_EQ(0, std::memcmp(result.data(), &rep, sizeof(rep)));
+    EXPECT_EQ(0, std::memcmp(result.data() + sizeof(rep), lmeta.metadata.data(),
                              lmeta.metadata.size()));
 }
 } // namespace blobs
diff --git a/test/ipmi_unittest.cpp b/test/ipmi_unittest.cpp
index 8f27ed7..ed2f026 100644
--- a/test/ipmi_unittest.cpp
+++ b/test/ipmi_unittest.cpp
@@ -14,47 +14,37 @@
 TEST(StringInputTest, NullPointerInput)
 {
     // The method should verify it did receive a non-null input pointer.
-
-    EXPECT_STREQ("", stringFromBuffer(NULL, 5).c_str());
+    EXPECT_STREQ("", stringFromBuffer({}).c_str());
 }
 
 TEST(StringInputTest, ZeroBytesInput)
 {
     // Verify that if the input length is 0 that it'll return the empty string.
-
-    const char* request = "asdf";
-    EXPECT_STREQ("", stringFromBuffer(request, 0).c_str());
+    const std::string request = "asdf";
+    EXPECT_STREQ("", stringFromBuffer(
+                         std::vector<uint8_t>(request.begin(), request.end()))
+                         .c_str());
 }
 
 TEST(StringInputTest, NulTerminatorNotFound)
 {
     // Verify that if there isn't a nul-terminator found in an otherwise valid
     // string, it'll return the emptry string.
-
-    char request[MAX_IPMI_BUFFER];
-    std::memset(request, 'a', sizeof(request));
-    EXPECT_STREQ("", stringFromBuffer(request, sizeof(request)).c_str());
-}
-
-TEST(StringInputTest, TwoNulsFound)
-{
-    // Verify it makes you use the entire data region for the string.
-    char request[MAX_IPMI_BUFFER];
-    request[0] = 'a';
-    request[1] = 0;
-    std::memset(&request[2], 'b', sizeof(request) - 2);
-    request[MAX_IPMI_BUFFER - 1] = 0;
-
-    // This case has two strings, and the last character is a nul-terminator.
-    EXPECT_STREQ("", stringFromBuffer(request, sizeof(request)).c_str());
+    std::array<char, MAX_IPMI_BUFFER> request;
+    std::memset(request.data(), 'a', sizeof(request));
+    EXPECT_STREQ("", stringFromBuffer(
+                         std::vector<uint8_t>(request.begin(), request.end()))
+                         .c_str());
 }
 
 TEST(StringInputTest, NulTerminatorFound)
 {
     // Verify that if it's provided a valid nul-terminated string, it'll
     // return it.
-
-    const char* request = "asdf";
-    EXPECT_STREQ("asdf", stringFromBuffer(request, 5).c_str());
+    std::string request = "asdf";
+    request.push_back('\0');
+    EXPECT_STREQ("asdf", stringFromBuffer(std::vector<uint8_t>(request.begin(),
+                                                               request.end()))
+                             .c_str());
 }
 } // namespace blobs
diff --git a/test/ipmi_write_unittest.cpp b/test/ipmi_write_unittest.cpp
index 229ebd3..12cf1bc 100644
--- a/test/ipmi_write_unittest.cpp
+++ b/test/ipmi_write_unittest.cpp
@@ -1,47 +1,38 @@
+#include "helper.hpp"
 #include "ipmi.hpp"
 #include "manager_mock.hpp"
 
 #include <cstring>
 
 #include <gtest/gtest.h>
-
 namespace blobs
 {
 
 using ::testing::ElementsAreArray;
 using ::testing::Return;
 
-// ipmid.hpp isn't installed where we can grab it and this value is per BMC
-// SoC.
-#define MAX_IPMI_BUFFER 64
-
 TEST(BlobWriteTest, ManagerReturnsFailureReturnsFailure)
 {
     // This verifies a failure from the manager is passed back.
-
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    auto req = reinterpret_cast<struct BmcBlobWriteTx*>(request);
+    std::vector<uint8_t> request;
+    struct BmcBlobWriteTx req;
 
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite);
-    req->crc = 0;
-    req->sessionId = 0x54;
-    req->offset = 0x100;
+    req.crc = 0;
+    req.sessionId = 0x54;
+    req.offset = 0x100;
 
-    uint8_t expectedBytes[2] = {0x66, 0x67};
-    std::memcpy(req + 1, &expectedBytes[0], sizeof(expectedBytes));
+    request.resize(sizeof(struct BmcBlobWriteTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobWriteTx));
 
-    dataLen = sizeof(struct BmcBlobWriteTx) + sizeof(expectedBytes);
+    std::array<uint8_t, 2> expectedBytes = {0x66, 0x67};
+    request.insert(request.end(), expectedBytes.begin(), expectedBytes.end());
 
-    EXPECT_CALL(mgr,
-                write(req->sessionId, req->offset,
-                      ElementsAreArray(expectedBytes, sizeof(expectedBytes))))
+    EXPECT_CALL(
+        mgr, write(req.sessionId, req.offset, ElementsAreArray(expectedBytes)))
         .WillOnce(Return(false));
 
-    EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR,
-              writeBlob(&mgr, request, reply, &dataLen));
+    EXPECT_EQ(ipmi::responseUnspecifiedError(), writeBlob(&mgr, request));
 }
 
 TEST(BlobWriteTest, ManagerReturnsTrueWriteSucceeds)
@@ -49,26 +40,24 @@
     // The case where everything works.
 
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    auto req = reinterpret_cast<struct BmcBlobWriteTx*>(request);
+    std::vector<uint8_t> request;
+    struct BmcBlobWriteTx req;
 
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite);
-    req->crc = 0;
-    req->sessionId = 0x54;
-    req->offset = 0x100;
+    req.crc = 0;
+    req.sessionId = 0x54;
+    req.offset = 0x100;
 
-    uint8_t expectedBytes[2] = {0x66, 0x67};
-    std::memcpy(req + 1, &expectedBytes[0], sizeof(expectedBytes));
+    request.resize(sizeof(struct BmcBlobWriteTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobWriteTx));
 
-    dataLen = sizeof(struct BmcBlobWriteTx) + sizeof(expectedBytes);
+    std::array<uint8_t, 2> expectedBytes = {0x66, 0x67};
+    request.insert(request.end(), expectedBytes.begin(), expectedBytes.end());
 
-    EXPECT_CALL(mgr,
-                write(req->sessionId, req->offset,
-                      ElementsAreArray(expectedBytes, sizeof(expectedBytes))))
+    EXPECT_CALL(
+        mgr, write(req.sessionId, req.offset, ElementsAreArray(expectedBytes)))
         .WillOnce(Return(true));
 
-    EXPECT_EQ(IPMI_CC_OK, writeBlob(&mgr, request, reply, &dataLen));
+    EXPECT_EQ(ipmi::responseSuccess(std::vector<uint8_t>{}),
+              writeBlob(&mgr, request));
 }
 } // namespace blobs
diff --git a/test/ipmi_writemeta_unittest.cpp b/test/ipmi_writemeta_unittest.cpp
index dd9e742..bc8669d 100644
--- a/test/ipmi_writemeta_unittest.cpp
+++ b/test/ipmi_writemeta_unittest.cpp
@@ -17,57 +17,49 @@
 TEST(BlobWriteMetaTest, ManagerReturnsFailureReturnsFailure)
 {
     // This verifies a failure from the manager is passed back.
-
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    auto req = reinterpret_cast<struct BmcBlobWriteMetaTx*>(request);
+    std::vector<uint8_t> request;
+    struct BmcBlobWriteMetaTx req;
 
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite);
-    req->crc = 0;
-    req->sessionId = 0x54;
-    req->offset = 0x100;
+    req.crc = 0;
+    req.sessionId = 0x54;
+    req.offset = 0x100;
 
-    uint8_t expectedBytes[2] = {0x66, 0x67};
-    std::memcpy(req + 1, &expectedBytes[0], sizeof(expectedBytes));
+    request.resize(sizeof(struct BmcBlobWriteMetaTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobWriteMetaTx));
 
-    dataLen = sizeof(struct BmcBlobWriteMetaTx) + sizeof(expectedBytes);
+    std::array<uint8_t, 2> expectedBytes = {0x66, 0x67};
+    request.insert(request.end(), expectedBytes.begin(), expectedBytes.end());
 
-    EXPECT_CALL(
-        mgr, writeMeta(req->sessionId, req->offset,
-                       ElementsAreArray(expectedBytes, sizeof(expectedBytes))))
+    EXPECT_CALL(mgr, writeMeta(req.sessionId, req.offset,
+                               ElementsAreArray(expectedBytes)))
         .WillOnce(Return(false));
 
-    EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR,
-              writeMeta(&mgr, request, reply, &dataLen));
+    EXPECT_EQ(ipmi::responseUnspecifiedError(), writeMeta(&mgr, request));
 }
 
 TEST(BlobWriteMetaTest, ManagerReturnsTrueWriteSucceeds)
 {
     // The case where everything works.
-
     ManagerMock mgr;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-    auto req = reinterpret_cast<struct BmcBlobWriteMetaTx*>(request);
+    std::vector<uint8_t> request;
+    struct BmcBlobWriteMetaTx req;
 
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite);
-    req->crc = 0;
-    req->sessionId = 0x54;
-    req->offset = 0x100;
+    req.crc = 0;
+    req.sessionId = 0x54;
+    req.offset = 0x100;
 
-    uint8_t expectedBytes[2] = {0x66, 0x67};
-    std::memcpy(req + 1, &expectedBytes[0], sizeof(expectedBytes));
+    request.resize(sizeof(struct BmcBlobWriteMetaTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobWriteMetaTx));
 
-    dataLen = sizeof(struct BmcBlobWriteMetaTx) + sizeof(expectedBytes);
+    std::array<uint8_t, 2> expectedBytes = {0x66, 0x67};
+    request.insert(request.end(), expectedBytes.begin(), expectedBytes.end());
 
-    EXPECT_CALL(
-        mgr, writeMeta(req->sessionId, req->offset,
-                       ElementsAreArray(expectedBytes, sizeof(expectedBytes))))
+    EXPECT_CALL(mgr, writeMeta(req.sessionId, req.offset,
+                               ElementsAreArray(expectedBytes)))
         .WillOnce(Return(true));
 
-    EXPECT_EQ(IPMI_CC_OK, writeMeta(&mgr, request, reply, &dataLen));
+    EXPECT_EQ(ipmi::responseSuccess(std::vector<uint8_t>{}),
+              writeMeta(&mgr, request));
 }
 } // namespace blobs
diff --git a/test/meson.build b/test/meson.build
index db240b3..b5bdd99 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -37,6 +37,7 @@
     executable(
       t.underscorify(),
       t + '.cpp',
+      'helper.cpp',
       implicit_include_directories: false,
       dependencies: [blob_manager_dep, gtest, gmock]))
 endforeach
diff --git a/test/process_unittest.cpp b/test/process_unittest.cpp
index b72fe9a..02014d4 100644
--- a/test/process_unittest.cpp
+++ b/test/process_unittest.cpp
@@ -1,9 +1,11 @@
+#include "helper.hpp"
 #include "ipmi.hpp"
 #include "manager_mock.hpp"
 #include "process.hpp"
 
 #include <cstring>
 #include <ipmiblob/test/crc_mock.hpp>
+#include <span>
 
 #include <gtest/gtest.h>
 
@@ -12,6 +14,7 @@
 #define MAX_IPMI_BUFFER 64
 
 using ::testing::_;
+using ::testing::ElementsAre;
 using ::testing::Eq;
 using ::testing::Return;
 using ::testing::StrictMock;
@@ -36,15 +39,11 @@
     EXPECT_FALSE(lhs == nullptr);
     EXPECT_FALSE(rhs == nullptr);
 
-    ipmi_ret_t (*const* lPtr)(ManagerInterface*, const uint8_t*, uint8_t*,
-                              size_t*) =
-        lhs.target<ipmi_ret_t (*)(ManagerInterface*, const uint8_t*, uint8_t*,
-                                  size_t*)>();
+    Resp (*const* lPtr)(ManagerInterface*, std::span<const uint8_t>) =
+        lhs.target<Resp (*)(ManagerInterface*, std::span<const uint8_t>)>();
 
-    ipmi_ret_t (*const* rPtr)(ManagerInterface*, const uint8_t*, uint8_t*,
-                              size_t*) =
-        rhs.target<ipmi_ret_t (*)(ManagerInterface*, const uint8_t*, uint8_t*,
-                                  size_t*)>();
+    Resp (*const* rPtr)(ManagerInterface*, std::span<const uint8_t>) =
+        rhs.target<Resp (*)(ManagerInterface*, std::span<const uint8_t>)>();
 
     EXPECT_TRUE(lPtr);
     EXPECT_TRUE(rPtr);
@@ -67,34 +66,20 @@
 TEST_F(ValidateBlobCommandTest, InvalidCommandReturnsFailure)
 {
     // Verify we handle an invalid command.
-
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-
-    request[0] = 0xff;         // There is no command 0xff.
-    dataLen = sizeof(uint8_t); // There is no payload for CRC.
-    ipmi_ret_t rc;
-
-    EXPECT_EQ(nullptr, validateBlobCommand(request, reply, &dataLen, &rc));
-    EXPECT_EQ(IPMI_CC_INVALID_FIELD_REQUEST, rc);
+    std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
+    // There is no command 0xff.
+    IpmiBlobHandler handler = validateBlobCommand(0xff, request);
+    EXPECT_EQ(ipmi::responseInvalidFieldRequest(), handler(nullptr, {}));
 }
 
 TEST_F(ValidateBlobCommandTest, ValidCommandWithoutPayload)
 {
     // Verify we handle a valid command that doesn't have a payload.
-
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-
-    request[0] = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobGetCount);
-    dataLen = sizeof(uint8_t); // There is no payload for CRC.
-    ipmi_ret_t rc;
-
-    IpmiBlobHandler res = validateBlobCommand(request, reply, &dataLen, &rc);
-    EXPECT_FALSE(res == nullptr);
-    EqualFunctions(getBlobCount, res);
+    std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
+    IpmiBlobHandler handler = validateBlobCommand(
+        static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobGetCount), request);
+    EXPECT_FALSE(handler == nullptr);
+    EqualFunctions(getBlobCount, handler);
 }
 
 TEST_F(ValidateBlobCommandTest, WithPayloadMinimumLengthIs3VerifyChecks)
@@ -102,76 +87,61 @@
     // Verify that if there's a payload, it's at least one command byte and
     // two bytes for the crc16 and then one data byte.
 
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-
-    request[0] = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobGetCount);
-    dataLen = sizeof(uint8_t) + sizeof(uint16_t);
+    std::vector<uint8_t> request(sizeof(uint16_t));
     // There is a payload, but there are insufficient bytes.
-    ipmi_ret_t rc;
 
-    EXPECT_EQ(nullptr, validateBlobCommand(request, reply, &dataLen, &rc));
-    EXPECT_EQ(IPMI_CC_REQ_DATA_LEN_INVALID, rc);
+    IpmiBlobHandler handler = validateBlobCommand(
+        static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobGetCount), request);
+    EXPECT_EQ(ipmi::responseReqDataLenInvalid(), handler(nullptr, {}));
 }
 
 TEST_F(ValidateBlobCommandTest, WithPayloadAndInvalidCrc)
 {
     // Verify that the CRC is checked, and failure is reported.
+    std::vector<uint8_t> request;
+    BmcBlobWriteTx req;
+    req.crc = 0x34;
+    req.sessionId = 0x54;
+    req.offset = 0x100;
 
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-
-    auto req = reinterpret_cast<struct BmcBlobWriteTx*>(request);
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite);
-    req->crc = 0x34;
-    req->sessionId = 0x54;
-    req->offset = 0x100;
-
-    uint8_t expectedBytes[2] = {0x66, 0x67};
-    std::memcpy(req + 1, &expectedBytes[0], sizeof(expectedBytes));
-
-    dataLen = sizeof(struct BmcBlobWriteTx) + sizeof(expectedBytes);
+    std::array<uint8_t, 2> expectedBytes = {0x66, 0x67};
+    request.resize(sizeof(struct BmcBlobWriteTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobWriteTx));
+    request.insert(request.end(), expectedBytes.begin(), expectedBytes.end());
 
     // skip over cmd and crc.
-    std::vector<std::uint8_t> bytes(&request[3], request + dataLen);
+    std::vector<uint8_t> bytes(request.begin() + sizeof(req.crc),
+                               request.end());
     EXPECT_CALL(crcMock, generateCrc(Eq(bytes))).WillOnce(Return(0x1234));
 
-    ipmi_ret_t rc;
-
-    EXPECT_EQ(nullptr, validateBlobCommand(request, reply, &dataLen, &rc));
-    EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR, rc);
+    IpmiBlobHandler handler = validateBlobCommand(
+        static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite), request);
+    EXPECT_EQ(ipmi::responseUnspecifiedError(), handler(nullptr, {}));
 }
 
 TEST_F(ValidateBlobCommandTest, WithPayloadAndValidCrc)
 {
     // Verify the CRC is checked and if it matches, return the handler.
+    std::vector<uint8_t> request;
+    BmcBlobWriteTx req;
+    req.crc = 0x3412;
+    req.sessionId = 0x54;
+    req.offset = 0x100;
 
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
-
-    auto req = reinterpret_cast<struct BmcBlobWriteTx*>(request);
-    req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite);
-    req->crc = 0x3412;
-    req->sessionId = 0x54;
-    req->offset = 0x100;
-
-    uint8_t expectedBytes[2] = {0x66, 0x67};
-    std::memcpy(req + 1, &expectedBytes[0], sizeof(expectedBytes));
-
-    dataLen = sizeof(struct BmcBlobWriteTx) + sizeof(expectedBytes);
+    std::array<uint8_t, 2> expectedBytes = {0x66, 0x67};
+    request.resize(sizeof(struct BmcBlobWriteTx));
+    std::memcpy(request.data(), &req, sizeof(struct BmcBlobWriteTx));
+    request.insert(request.end(), expectedBytes.begin(), expectedBytes.end());
 
     // skip over cmd and crc.
-    std::vector<std::uint8_t> bytes(&request[3], request + dataLen);
+    std::vector<uint8_t> bytes(request.begin() + sizeof(req.crc),
+                               request.end());
     EXPECT_CALL(crcMock, generateCrc(Eq(bytes))).WillOnce(Return(0x3412));
 
-    ipmi_ret_t rc;
-
-    IpmiBlobHandler res = validateBlobCommand(request, reply, &dataLen, &rc);
-    EXPECT_FALSE(res == nullptr);
-    EqualFunctions(writeBlob, res);
+    IpmiBlobHandler handler = validateBlobCommand(
+        static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite), request);
+    EXPECT_FALSE(handler == nullptr);
+    EqualFunctions(writeBlob, handler);
 }
 
 class ProcessBlobCommandTest : public ::testing::Test
@@ -191,17 +161,14 @@
     // noticed and returned.
 
     StrictMock<ManagerMock> manager;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
+    std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
 
-    IpmiBlobHandler h = [](ManagerInterface*, const uint8_t*, uint8_t*,
-                           size_t*) { return IPMI_CC_INVALID; };
+    IpmiBlobHandler h = [](ManagerInterface*, std::span<const uint8_t>) {
+        return ipmi::responseInvalidCommand();
+    };
 
-    dataLen = sizeof(request);
-
-    EXPECT_EQ(IPMI_CC_INVALID,
-              processBlobCommand(h, &manager, request, reply, &dataLen));
+    EXPECT_EQ(ipmi::responseInvalidCommand(),
+              processBlobCommand(h, &manager, request));
 }
 
 TEST_F(ProcessBlobCommandTest, CommandReturnsOkWithNoPayload)
@@ -210,20 +177,14 @@
     // it doesn't try to compute a CRC.
 
     StrictMock<ManagerMock> manager;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
+    std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
 
-    IpmiBlobHandler h = [](ManagerInterface*, const uint8_t*, uint8_t*,
-                           size_t* dataLen) {
-        (*dataLen) = 0;
-        return IPMI_CC_OK;
+    IpmiBlobHandler h = [](ManagerInterface*, std::span<const uint8_t>) {
+        return ipmi::responseSuccess(std::vector<uint8_t>());
     };
 
-    dataLen = sizeof(request);
-
-    EXPECT_EQ(IPMI_CC_OK,
-              processBlobCommand(h, &manager, request, reply, &dataLen));
+    EXPECT_EQ(ipmi::responseSuccess(std::vector<uint8_t>()),
+              processBlobCommand(h, &manager, request));
 }
 
 TEST_F(ProcessBlobCommandTest, CommandReturnsOkWithInvalidPayloadLength)
@@ -232,20 +193,14 @@
     // read), this returns 1.
 
     StrictMock<ManagerMock> manager;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
+    std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
 
-    IpmiBlobHandler h = [](ManagerInterface*, const uint8_t*, uint8_t*,
-                           size_t* dataLen) {
-        (*dataLen) = sizeof(uint8_t);
-        return IPMI_CC_OK;
+    IpmiBlobHandler h = [](ManagerInterface*, std::span<const uint8_t>) {
+        return ipmi::responseSuccess(std::vector<uint8_t>(1));
     };
 
-    dataLen = sizeof(request);
-
-    EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR,
-              processBlobCommand(h, &manager, request, reply, &dataLen));
+    EXPECT_EQ(ipmi::responseUnspecifiedError(),
+              processBlobCommand(h, &manager, request));
 }
 
 TEST_F(ProcessBlobCommandTest, CommandReturnsOkWithValidPayloadLength)
@@ -254,27 +209,22 @@
     // payload of 3 bytes and the crc code is called to process the payload.
 
     StrictMock<ManagerMock> manager;
-    size_t dataLen;
-    uint8_t request[MAX_IPMI_BUFFER] = {0};
-    uint8_t reply[MAX_IPMI_BUFFER] = {0};
+    std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
     uint32_t payloadLen = sizeof(uint16_t) + sizeof(uint8_t);
 
-    IpmiBlobHandler h = [payloadLen](ManagerInterface*, const uint8_t*,
-                                     uint8_t* replyCmdBuf, size_t* dataLen) {
-        (*dataLen) = payloadLen;
-        replyCmdBuf[2] = 0x56;
-        return IPMI_CC_OK;
+    IpmiBlobHandler h = [payloadLen](ManagerInterface*,
+                                     std::span<const uint8_t>) {
+        std::vector<uint8_t> output(payloadLen, 0);
+        output[2] = 0x56;
+        return ipmi::responseSuccess(output);
     };
 
-    dataLen = sizeof(request);
-
     EXPECT_CALL(crcMock, generateCrc(_)).WillOnce(Return(0x3412));
 
-    EXPECT_EQ(IPMI_CC_OK,
-              processBlobCommand(h, &manager, request, reply, &dataLen));
-    EXPECT_EQ(dataLen, payloadLen);
+    auto result = validateReply(processBlobCommand(h, &manager, request));
 
-    uint8_t expectedBytes[3] = {0x12, 0x34, 0x56};
-    EXPECT_EQ(0, std::memcmp(expectedBytes, reply, sizeof(expectedBytes)));
+    EXPECT_EQ(result.size(), payloadLen);
+    EXPECT_THAT(result, ElementsAre(0x12, 0x34, 0x56));
 }
+
 } // namespace blobs