blob: 097320563a4881e2c0aa93970a2138c82cbc8d70 [file] [log] [blame]
// 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.
#pragma once
#include "command/test/dbus_command_mock.hpp"
#include "hoth_skmhss.hpp"
#include "hoth_util_mock.hpp"
#include <sdbusplus/exception.hpp>
#include <sdbusplus/test/sdbus_mock.hpp>
#include <xyz/openbmc_project/Control/Hoth/error.hpp>
#include <array>
#include <cstdint>
#include <memory>
#include <span>
#include <string>
#include <string_view>
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using ipmi_hoth::internal::DbusCommand;
using ::testing::_;
using ::testing::NotNull;
using ::testing::Return;
using ResponseFailure =
sdbusplus::xyz::openbmc_project::Control::Hoth::Error::ResponseFailure;
namespace ipmi_hoth
{
struct MockCancel : public stdplus::Cancelable
{
MOCK_METHOD(void, cancel, (), (noexcept, override));
};
class HothSKMHSSTest : public ::testing::Test
{
public:
void expectCmd(uint8_t i, fu2::unique_function<void()>& cb,
MockCancel& cancel, std::span<const uint8_t> data)
{
bool has_data = data.data() != nullptr;
EXPECT_CALL(dbus,
SendHostCommand(
"", testing::ElementsAre(static_cast<uint8_t>(10 + i)),
_))
.WillOnce([&cb, &cancel, i,
has_data](std::string_view, const std::vector<uint8_t>&,
DbusCommand::Cb&& icb) {
if (has_data)
{
cb = [icb = std::move(icb), i]() mutable {
icb(std::vector<uint8_t>{static_cast<uint8_t>(20 + i)});
};
}
else
{
cb = [icb = std::move(icb)]() mutable {
icb(std::nullopt);
};
}
return stdplus::Cancel(&cancel);
});
if (has_data)
{
EXPECT_CALL(hvnutil, payloadECResponse(testing::ElementsAre(
static_cast<uint8_t>(20 + i))))
.WillOnce(Return(data));
}
EXPECT_CALL(cancel, cancel()).WillOnce(Return());
}
void expectRead(uint8_t i, fu2::unique_function<void()>& cb,
MockCancel& cancel, std::span<const uint8_t> data)
{
EXPECT_CALL(hvnutil, readSKMHSS(i))
.WillOnce(
Return(std::vector<uint8_t>{static_cast<uint8_t>(10 + i)}));
expectCmd(i, cb, cancel, data);
}
std::unique_ptr<HothSKMHSSBlobHandler>
createHandler(const std::vector<uint8_t>& data)
{
std::array<fu2::unique_function<void()>, 4> cbs;
std::array<testing::StrictMock<MockCancel>, 4> cancels;
for (uint8_t i = 0; i < 4; ++i)
{
expectRead(i, cbs[i], cancels[i], data);
}
auto ret = std::make_unique<HothSKMHSSBlobHandler>(&dbus, &hvnutil);
for (uint8_t i = 0; i < 4; ++i)
{
cbs[i]();
}
testing::Mock::VerifyAndClearExpectations(&hvnutil);
testing::Mock::VerifyAndClearExpectations(&dbus);
return ret;
}
// Create a handler with empty HSS cache.
std::unique_ptr<HothSKMHSSBlobHandler> createHandlerWithEmptyCache()
{
return createHandler({});
}
// Create a handler with test HSS cache.
std::unique_ptr<HothSKMHSSBlobHandler> createHandlerWithTestCache()
{
return createHandler(testHSSBytes);
}
protected:
// dbus mock object
testing::StrictMock<internal::DbusCommandMock> dbus;
// Hoth utility mock object
testing::StrictMock<internal::HothUtilMock> hvnutil;
const uint16_t session = 0;
const std::vector<std::string> legacyPath = {
"/skm/hss-backup/0",
"/skm/hss-backup/1",
"/skm/hss-backup/2",
"/skm/hss-backup/3",
};
const std::vector<uint8_t> testHSSBytes = std::vector<uint8_t>(64, 0x0b);
};
class HothSKMHSSBasicTest : public HothSKMHSSTest
{
public:
HothSKMHSSBasicTest() :
hvn(HothSKMHSSBasicTest::createHandlerWithTestCache())
{}
std::unique_ptr<HothSKMHSSBlobHandler> hvn;
};
} // namespace ipmi_hoth