blob: aba3f3495ca191144235dca7ba96c53c6310f817 [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "trunks/csme/mei_client_char_device.h"
#include <string>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <base/logging.h>
#include <libhwsec-foundation/syscaller/mock_syscaller.h>
namespace trunks {
namespace csme {
namespace {
constexpr char kFakeMeiPath[] = "mei path";
constexpr uuid_le kFakeGuid = UUID_LE(
0x88888888, 0x8888, 0x8888, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88);
constexpr int kFakeFd = 0xfd;
constexpr int kFakeMaxMsgLength = 5120;
constexpr char kFakeMessage[] = "fake message";
constexpr int kFakeMessageLength = sizeof(kFakeMessage) - 1;
using testing::_;
using testing::AtMost;
using testing::DoAll;
using testing::Return;
using testing::StrictMock;
using testing::WithArg;
} // namespace
class MeiClientCharDeviceTest : public testing::Test {
public:
MeiClientCharDeviceTest() {
EXPECT_CALL(mock_syscaller_, Close(kFakeFd))
.Times(AtMost(1))
.WillRepeatedly(Return(0));
}
~MeiClientCharDeviceTest() override = default;
protected:
void InitializeMeiClient() {
EXPECT_CALL(mock_syscaller_, Open(_, _)).WillOnce(Return(kFakeFd));
EXPECT_CALL(mock_syscaller_, Ioctl(kFakeFd, IOCTL_MEI_CONNECT_CLIENT, _))
.WillOnce(DoAll(WithArg<2>([](struct mei_connect_client_data* data) {
data->out_client_properties.max_msg_length =
kFakeMaxMsgLength;
}),
Return(0)));
ASSERT_TRUE(client_.Initialize());
}
StrictMock<hwsec_foundation::MockSyscaller> mock_syscaller_;
MeiClientCharDevice client_{kFakeMeiPath, kFakeGuid, &mock_syscaller_};
};
TEST_F(MeiClientCharDeviceTest, InitializeSuccess) {
EXPECT_CALL(mock_syscaller_, Open(_, _)).WillOnce(Return(kFakeFd));
EXPECT_CALL(mock_syscaller_, Ioctl(kFakeFd, IOCTL_MEI_CONNECT_CLIENT, _))
.WillOnce(DoAll(WithArg<2>([](struct mei_connect_client_data* data) {
data->out_client_properties.max_msg_length =
kFakeMaxMsgLength;
}),
Return(0)));
EXPECT_TRUE(client_.Initialize());
}
TEST_F(MeiClientCharDeviceTest, InitializeOpenFailure) {
EXPECT_CALL(mock_syscaller_, Open(_, _)).WillOnce(Return(-1));
EXPECT_FALSE(client_.Initialize());
}
TEST_F(MeiClientCharDeviceTest, InitializeIoctlFailure) {
EXPECT_CALL(mock_syscaller_, Open(_, _)).WillOnce(Return(kFakeFd));
EXPECT_CALL(mock_syscaller_, Ioctl(kFakeFd, IOCTL_MEI_CONNECT_CLIENT, _))
.WillOnce(Return(-1));
// In this case, the fd is opened, and in turn expected to be close.
EXPECT_CALL(mock_syscaller_, Close(kFakeFd));
EXPECT_FALSE(client_.Initialize());
}
TEST_F(MeiClientCharDeviceTest, ReceiveInitializeFailure) {
std::string data;
EXPECT_CALL(mock_syscaller_, Open(_, _)).WillOnce(Return(-1));
EXPECT_FALSE(client_.Receive(&data));
}
TEST_F(MeiClientCharDeviceTest, SendInitializeFailure) {
std::string data;
EXPECT_CALL(mock_syscaller_, Open(_, _)).WillOnce(Return(-1));
EXPECT_FALSE(client_.Send(data, /*wait_for_response_ready=*/true));
}
TEST_F(MeiClientCharDeviceTest, ReceiveSuccess) {
std::string data;
InitializeMeiClient();
EXPECT_CALL(mock_syscaller_, Read(kFakeFd, _, kFakeMaxMsgLength))
.WillOnce(DoAll(WithArg<1>([](void* p) {
memcpy(p, kFakeMessage, kFakeMessageLength);
}),
Return(kFakeMessageLength)));
EXPECT_TRUE(client_.Receive(&data));
EXPECT_EQ(data, std::string(kFakeMessage));
}
TEST_F(MeiClientCharDeviceTest, ReceiveReadFailure) {
std::string data;
InitializeMeiClient();
EXPECT_CALL(mock_syscaller_, Read(kFakeFd, _, kFakeMaxMsgLength))
.WillOnce(Return(-1));
EXPECT_FALSE(client_.Receive(&data));
}
TEST_F(MeiClientCharDeviceTest, SendSuccess) {
InitializeMeiClient();
EXPECT_CALL(mock_syscaller_, Write(kFakeFd, _, kFakeMessageLength))
.WillOnce(Return(kFakeMessageLength));
EXPECT_CALL(mock_syscaller_, Select(kFakeFd + 1, _, nullptr, nullptr, _))
.WillOnce(Return(1));
EXPECT_TRUE(client_.Send(kFakeMessage, /*wait_for_response_ready=*/true));
}
TEST_F(MeiClientCharDeviceTest, SendSuccessNoWaitForResponseReady) {
InitializeMeiClient();
EXPECT_CALL(mock_syscaller_, Write(kFakeFd, _, kFakeMessageLength))
.WillOnce(Return(kFakeMessageLength));
// `Select()` shouldn't be called; `StrictMock` will verify it.
EXPECT_TRUE(client_.Send(kFakeMessage, /*wait_for_response_ready=*/false));
}
TEST_F(MeiClientCharDeviceTest, SendBadWriteSize) {
InitializeMeiClient();
// Either the value greater or less than than the expected written size should
// fail the operation.
EXPECT_CALL(mock_syscaller_, Write(kFakeFd, _, kFakeMessageLength))
.WillOnce(Return(kFakeMessageLength + 1))
.WillOnce(Return(kFakeMessageLength - 1));
EXPECT_FALSE(client_.Send(kFakeMessage, /*wait_for_response_ready=*/true));
EXPECT_FALSE(client_.Send(kFakeMessage, /*wait_for_response_ready=*/true));
}
TEST_F(MeiClientCharDeviceTest, SendSelectTimeout) {
InitializeMeiClient();
EXPECT_CALL(mock_syscaller_, Write(kFakeFd, _, kFakeMessageLength))
.WillOnce(Return(kFakeMessageLength));
EXPECT_CALL(mock_syscaller_, Select(kFakeFd + 1, _, nullptr, nullptr, _))
.WillOnce(Return(0));
EXPECT_FALSE(client_.Send(kFakeMessage, /*wait_for_response_ready=*/true));
}
TEST_F(MeiClientCharDeviceTest, SendSelectError) {
InitializeMeiClient();
EXPECT_CALL(mock_syscaller_, Write(kFakeFd, _, kFakeMessageLength))
.WillOnce(Return(kFakeMessageLength));
EXPECT_CALL(mock_syscaller_, Select(kFakeFd + 1, _, nullptr, nullptr, _))
.WillOnce(Return(-1));
EXPECT_FALSE(client_.Send(kFakeMessage, /*wait_for_response_ready=*/true));
}
} // namespace csme
} // namespace trunks