| // Copyright 2024 Google LLC |
| // |
| // 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. |
| |
| #include "message_util.hpp" |
| |
| #include <stdplus/raw.hpp> |
| #include <xyz/openbmc_project/Control/Hoth/error.hpp> |
| |
| #include <algorithm> |
| #include <cstring> |
| #include <numeric> |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| using google::hoth::internal::calculateChecksum; |
| using google::hoth::internal::populateReqHeader; |
| using google::hoth::internal::ReqHeader; |
| using google::hoth::internal::reqLen; |
| using google::hoth::internal::RspHeader; |
| using google::hoth::internal::rspLen; |
| using google::hoth::internal::SUPPORTED_STRUCT_VERSION; |
| using sdbusplus::error::xyz::openbmc_project::control::hoth::CommandFailure; |
| using sdbusplus::error::xyz::openbmc_project::control::hoth::ResponseFailure; |
| |
| namespace |
| { |
| |
| void convertReq(std::vector<uint8_t>& req, const struct ReqHeader& hdr) |
| { |
| req.resize(sizeof(hdr)); |
| std::memcpy(req.data(), &hdr, req.size()); |
| } |
| |
| void convertRsp(std::vector<uint8_t>& rsp, const struct RspHeader& hdr) |
| { |
| rsp.resize(sizeof(hdr)); |
| std::memcpy(rsp.data(), &hdr, rsp.size()); |
| } |
| |
| } // namespace |
| |
| TEST(ReqLen, empty) |
| { |
| std::vector<uint8_t> req; |
| |
| EXPECT_THROW(reqLen(req), CommandFailure); |
| } |
| |
| TEST(ReqLen, wrongStructVersion) |
| { |
| std::vector<uint8_t> req; |
| struct ReqHeader hdr = {}; |
| hdr.struct_version = 42; |
| |
| convertReq(req, hdr); |
| |
| EXPECT_THROW(reqLen(req), CommandFailure); |
| } |
| |
| TEST(ReqLen, lenZero) |
| { |
| std::vector<uint8_t> req; |
| struct ReqHeader hdr = {}; |
| hdr.struct_version = SUPPORTED_STRUCT_VERSION; |
| |
| convertReq(req, hdr); |
| |
| EXPECT_EQ(sizeof(hdr), reqLen(req)); |
| } |
| |
| TEST(ReqLen, lenZeroTrailing) |
| { |
| std::vector<uint8_t> req; |
| struct ReqHeader hdr = {}; |
| hdr.struct_version = SUPPORTED_STRUCT_VERSION; |
| |
| convertReq(req, hdr); |
| req.resize(req.size() + 5, 42); |
| |
| EXPECT_EQ(sizeof(hdr), reqLen(req)); |
| } |
| |
| TEST(ReqLen, lenOne) |
| { |
| std::vector<uint8_t> req; |
| struct ReqHeader hdr = {}; |
| hdr.struct_version = SUPPORTED_STRUCT_VERSION; |
| constexpr uint16_t size = 1; |
| |
| hdr.data_len = size; |
| convertReq(req, hdr); |
| |
| EXPECT_EQ(sizeof(hdr) + size, reqLen(req)); |
| } |
| |
| TEST(ReqLen, lenBig) |
| { |
| std::vector<uint8_t> req; |
| struct ReqHeader hdr = {}; |
| hdr.struct_version = SUPPORTED_STRUCT_VERSION; |
| constexpr uint16_t size = UINT8_MAX + 9001; |
| |
| hdr.data_len = size; |
| convertReq(req, hdr); |
| |
| EXPECT_EQ(sizeof(hdr) + size, reqLen(req)); |
| } |
| |
| TEST(ReqLen, lenMax) |
| { |
| std::vector<uint8_t> req; |
| struct ReqHeader hdr = {}; |
| hdr.struct_version = SUPPORTED_STRUCT_VERSION; |
| constexpr uint16_t size = UINT16_MAX - sizeof(hdr); |
| |
| hdr.data_len = size; |
| convertReq(req, hdr); |
| |
| EXPECT_EQ(sizeof(hdr) + size, reqLen(req)); |
| } |
| |
| TEST(RspLen, empty) |
| { |
| std::vector<uint8_t> rsp; |
| |
| EXPECT_THROW(rspLen(rsp), ResponseFailure); |
| } |
| |
| TEST(RspLen, wrongStructVersion) |
| { |
| std::vector<uint8_t> rsp; |
| struct RspHeader hdr = {}; |
| hdr.struct_version = 42; |
| |
| convertRsp(rsp, hdr); |
| |
| EXPECT_THROW(rspLen(rsp), ResponseFailure); |
| } |
| |
| TEST(RspLen, lenZero) |
| { |
| std::vector<uint8_t> rsp; |
| struct RspHeader hdr = {}; |
| hdr.struct_version = SUPPORTED_STRUCT_VERSION; |
| |
| convertRsp(rsp, hdr); |
| |
| EXPECT_EQ(sizeof(hdr), rspLen(rsp)); |
| } |
| |
| TEST(RspLen, lenZeroTrailing) |
| { |
| std::vector<uint8_t> rsp; |
| struct RspHeader hdr = {}; |
| hdr.struct_version = SUPPORTED_STRUCT_VERSION; |
| |
| convertRsp(rsp, hdr); |
| rsp.resize(rsp.size() + 5, 42); |
| |
| EXPECT_EQ(sizeof(hdr), rspLen(rsp)); |
| } |
| |
| TEST(RspLen, lenOne) |
| { |
| std::vector<uint8_t> rsp; |
| struct RspHeader hdr = {}; |
| hdr.struct_version = SUPPORTED_STRUCT_VERSION; |
| constexpr uint16_t size = 1; |
| |
| hdr.data_len = size; |
| convertRsp(rsp, hdr); |
| |
| EXPECT_EQ(sizeof(hdr) + size, rspLen(rsp)); |
| } |
| |
| TEST(RspLen, lenBig) |
| { |
| std::vector<uint8_t> rsp; |
| struct RspHeader hdr = {}; |
| hdr.struct_version = SUPPORTED_STRUCT_VERSION; |
| constexpr uint16_t size = UINT8_MAX + 9001; |
| |
| hdr.data_len = size; |
| convertRsp(rsp, hdr); |
| |
| EXPECT_EQ(sizeof(hdr) + size, rspLen(rsp)); |
| } |
| |
| TEST(RspLen, lenMax) |
| { |
| std::vector<uint8_t> rsp; |
| struct RspHeader hdr = {}; |
| hdr.struct_version = SUPPORTED_STRUCT_VERSION; |
| constexpr uint16_t size = UINT16_MAX - sizeof(hdr); |
| |
| hdr.data_len = size; |
| convertRsp(rsp, hdr); |
| |
| EXPECT_EQ(sizeof(hdr) + size, rspLen(rsp)); |
| } |
| |
| TEST(CalculateChecksum, calculateChecksumSuccess) |
| { |
| // Tests to ensure the checksummer is running correctly. |
| |
| uint8_t header[] = {1, 3, 5, 7}; |
| uint8_t body[] = {2, 4, 6, 8}; |
| |
| // (1 + 3 + 5 + 7) + (2 + 4 + 6 + 8) = 36 |
| EXPECT_EQ(36, calculateChecksum(header, body)); |
| |
| // Now test what happens if the sum exceeds 256. |
| body[0] = 200; |
| body[1] = 202; |
| |
| // (1 + 3 + 5 + 7) + (200 + 202 + 6 + 8) = 432 |
| // 432 % 256 = 176 |
| EXPECT_EQ(176, calculateChecksum(header, body)); |
| } |
| |
| TEST(PopulateReqHeader, populateReqHeaderSuccess) |
| { |
| ASSERT_THROW(populateReqHeader(0, 0, nullptr, 0, nullptr), CommandFailure); |
| |
| // NOLINTNEXTLINE(cert-msc30-c, cert-msc50-cpp) |
| uint16_t command = std::rand() % UINT16_MAX; |
| // NOLINTNEXTLINE(cert-msc30-c, cert-msc50-cpp) |
| uint8_t command_version = std::rand() % UINT8_MAX; |
| |
| constexpr size_t kRequestSize = 15; |
| |
| std::vector<uint8_t> request(kRequestSize); |
| std::generate(request.begin(), request.end(), std::rand); |
| |
| ReqHeader request_header; |
| |
| ASSERT_NO_THROW(populateReqHeader(command, command_version, request.data(), |
| request.size(), &request_header)); |
| |
| EXPECT_EQ(request_header.struct_version, SUPPORTED_STRUCT_VERSION); |
| EXPECT_EQ(request_header.command, command); |
| EXPECT_EQ(request_header.command_version, command_version); |
| EXPECT_EQ(request_header.reserved, 0); |
| EXPECT_EQ(request_header.data_len, request.size()); |
| |
| EXPECT_EQ(0, calculateChecksum( |
| stdplus::raw::asSpan<uint8_t>(request_header), request)); |
| } |
| |
| TEST(PopulateReqHeader, PopulateRequestHeaderWithNullRequestData) |
| { |
| ReqHeader request_header; |
| |
| ASSERT_NO_THROW(populateReqHeader(0xa5, 12, nullptr, 0, &request_header)); |
| EXPECT_EQ(0, |
| calculateChecksum(stdplus::raw::asSpan<uint8_t>(request_header))); |
| } |