| #include "ethstats.hpp" |
| |
| #include "handler_mock.hpp" |
| |
| #include <cstdint> |
| #include <cstring> |
| #include <string> |
| #include <vector> |
| |
| #include <gtest/gtest.h> |
| |
| #define MAX_IPMI_BUFFER 64 |
| |
| using ::testing::Return; |
| using ::testing::StrEq; |
| using ::testing::StrictMock; |
| |
| namespace ethstats |
| { |
| |
| TEST(EthStatsTest, InvalidStatReturnsFailure) |
| { |
| // Verify that the enum of valid statistic IDs is checked. |
| |
| std::string ifName = "eth0"; |
| struct EthStatRequest requestStruct; |
| requestStruct.statId = EthernetStatisticsIds::TX_WINDOW_ERRORS + 1; |
| requestStruct.if_name_len = ifName.length(); |
| |
| std::vector<std::uint8_t> request(sizeof(requestStruct) + ifName.length()); |
| std::memcpy(request.data(), &requestStruct, sizeof(requestStruct)); |
| std::memcpy(&request[sizeof(requestStruct)], ifName.c_str(), |
| ifName.length()); |
| |
| size_t dataLen = request.size(); |
| std::uint8_t reply[MAX_IPMI_BUFFER]; |
| |
| // Using StrictMock to ensure it isn't called. |
| StrictMock<HandlerMock> hMock; |
| |
| EXPECT_EQ(IPMI_CC_INVALID_FIELD_REQUEST, |
| handleEthStatCommand(request.data(), reply, &dataLen, &hMock)); |
| } |
| |
| TEST(EthStatsTest, InvalidIpmiPacketSize) |
| { |
| // An IPMI packet for this command has a minimum length. |
| |
| std::string ifName = "e"; |
| struct EthStatRequest requestStruct; |
| requestStruct.statId = EthernetStatisticsIds::RX_BYTES; |
| requestStruct.if_name_len = ifName.length(); |
| |
| std::vector<std::uint8_t> request(sizeof(requestStruct) + ifName.length()); |
| std::memcpy(request.data(), &requestStruct, sizeof(requestStruct)); |
| std::memcpy(&request[sizeof(requestStruct)], ifName.c_str(), |
| ifName.length()); |
| |
| // The minimum length is a 1-byte ifname - this gives one, but dataLen is |
| // set to smaller. |
| size_t dataLen = request.size() - 1; |
| std::uint8_t reply[MAX_IPMI_BUFFER]; |
| |
| // Using StrictMock to ensure it isn't called. |
| StrictMock<HandlerMock> hMock; |
| |
| EXPECT_EQ(IPMI_CC_REQ_DATA_LEN_INVALID, |
| handleEthStatCommand(request.data(), reply, &dataLen, &hMock)); |
| } |
| |
| TEST(EthStatsTest, InvalidIpmiPacketContents) |
| { |
| // The packet has a name length and name contents, if the name length is |
| // longer than the packet size, it should fail. |
| |
| std::string ifName = "eth0"; |
| struct EthStatRequest requestStruct; |
| requestStruct.statId = EthernetStatisticsIds::RX_BYTES; |
| requestStruct.if_name_len = ifName.length() + 1; |
| |
| std::vector<std::uint8_t> request(sizeof(requestStruct) + ifName.length()); |
| std::memcpy(request.data(), &requestStruct, sizeof(requestStruct)); |
| std::memcpy(&request[sizeof(requestStruct)], ifName.c_str(), |
| ifName.length()); |
| |
| size_t dataLen = request.size(); |
| std::uint8_t reply[MAX_IPMI_BUFFER]; |
| |
| // Using StrictMock to ensure it isn't called. |
| StrictMock<HandlerMock> hMock; |
| |
| EXPECT_EQ(IPMI_CC_REQ_DATA_LEN_INVALID, |
| handleEthStatCommand(request.data(), reply, &dataLen, &hMock)); |
| } |
| |
| TEST(EthStatsTest, NameHasIllegalCharacters) |
| { |
| // The interface name cannot have slashes. |
| std::string ifName = "et/h0"; |
| struct EthStatRequest requestStruct; |
| requestStruct.statId = EthernetStatisticsIds::RX_BYTES; |
| requestStruct.if_name_len = ifName.length(); |
| |
| std::vector<std::uint8_t> request(sizeof(requestStruct) + ifName.length()); |
| std::memcpy(request.data(), &requestStruct, sizeof(requestStruct)); |
| std::memcpy(&request[sizeof(requestStruct)], ifName.c_str(), |
| ifName.length()); |
| |
| size_t dataLen = request.size(); |
| std::uint8_t reply[MAX_IPMI_BUFFER]; |
| |
| // Using StrictMock to ensure it isn't called. |
| StrictMock<HandlerMock> hMock; |
| |
| EXPECT_EQ(IPMI_CC_INVALID_FIELD_REQUEST, |
| handleEthStatCommand(request.data(), reply, &dataLen, &hMock)); |
| } |
| |
| TEST(EthStatsTest, InvalidNameOrField) |
| { |
| // The handler returns failure on the input validity check. |
| std::string ifName = "eth0"; |
| struct EthStatRequest requestStruct; |
| requestStruct.statId = EthernetStatisticsIds::RX_BYTES; |
| requestStruct.if_name_len = ifName.length(); |
| |
| std::vector<std::uint8_t> request(sizeof(requestStruct) + ifName.length()); |
| std::memcpy(request.data(), &requestStruct, sizeof(requestStruct)); |
| std::memcpy(&request[sizeof(requestStruct)], ifName.c_str(), |
| ifName.length()); |
| |
| size_t dataLen = request.size(); |
| std::uint8_t reply[MAX_IPMI_BUFFER]; |
| |
| std::string expectedPath = buildPath(ifName, "rx_bytes"); |
| |
| HandlerMock hMock; |
| EXPECT_CALL(hMock, validIfNameAndField(StrEq(expectedPath))) |
| .WillOnce(Return(false)); |
| |
| EXPECT_EQ(IPMI_CC_INVALID_FIELD_REQUEST, |
| handleEthStatCommand(request.data(), reply, &dataLen, &hMock)); |
| } |
| |
| TEST(EthStatsTest, EverythingHappy) |
| { |
| std::string ifName = "eth0"; |
| struct EthStatRequest requestStruct; |
| requestStruct.statId = EthernetStatisticsIds::RX_BYTES; |
| requestStruct.if_name_len = ifName.length(); |
| |
| std::vector<std::uint8_t> request(sizeof(requestStruct) + ifName.length()); |
| std::memcpy(request.data(), &requestStruct, sizeof(requestStruct)); |
| std::memcpy(&request[sizeof(requestStruct)], ifName.c_str(), |
| ifName.length()); |
| |
| size_t dataLen = request.size(); |
| std::uint8_t reply[MAX_IPMI_BUFFER]; |
| |
| std::string expectedPath = buildPath(ifName, "rx_bytes"); |
| |
| HandlerMock hMock; |
| EXPECT_CALL(hMock, validIfNameAndField(StrEq(expectedPath))) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(hMock, readStatistic(StrEq(expectedPath))).WillOnce(Return(1)); |
| |
| EXPECT_EQ(IPMI_CC_OK, |
| handleEthStatCommand(request.data(), reply, &dataLen, &hMock)); |
| |
| struct EthStatReply expectedReply, realReply; |
| expectedReply.statId = EthernetStatisticsIds::RX_BYTES; |
| expectedReply.value = 1; |
| |
| std::memcpy(&realReply, reply, sizeof(realReply)); |
| EXPECT_EQ(0, std::memcmp(&expectedReply, &realReply, sizeof(realReply))); |
| } |
| |
| } // namespace ethstats |