blob: db603194009ecb7d73e99e66df0b0369f067a8cf [file] [log] [blame] [edit]
#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