blob: f9598b74f8d20cccd49988e4e46738e001095838 [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.
#include "hoth_updater_cli.hpp"
#include <stdio.h>
#include <filesystem>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
namespace google::hoth::tools
{
namespace
{
using ::testing::_;
using ::testing::Return;
class HothUpdaterCLIMock : public HothUpdaterCLI
{
public:
MOCK_METHOD(HothVersionStringsRsp, getHothVersion,
(sdbusplus::bus::bus & bus, std::string_view hoth_id));
MOCK_METHOD(HothActivationStatistics, getHothActivationStatistics,
(sdbusplus::bus::bus & bus, std::string_view hoth_id));
MOCK_METHOD(void, spiWrite,
(sdbusplus::bus::bus&, std::string_view,
const std::span<const uint8_t>, std::optional<uint32_t>));
MOCK_METHOD(std::vector<uint8_t>, readFileIntoByteArray,
(std::string_view));
MOCK_METHOD(FirmwareUpdateStatus, getFirmwareUpdateStatus,
(sdbusplus::bus::bus & bus, std::string_view hoth_id));
MOCK_METHOD(std::vector<uint8_t>, sendHostCommand,
(sdbusplus::bus::bus & bus, std::string_view hoth_id,
const std::span<const uint8_t> command));
};
TEST(PayloadUpdateCLITest, splitStringTest)
{
std::vector<std::string> sp = splitString("", ',');
EXPECT_EQ(sp.size(), 0);
sp = splitString("product_3_1", ',');
EXPECT_EQ(sp.size(), 1);
EXPECT_EQ(sp[0], "product_3_1");
sp = splitString("product_3_1,product_3_2", ',');
EXPECT_EQ(sp.size(), 2);
EXPECT_EQ(sp[0], "product_3_1");
EXPECT_EQ(sp[1], "product_3_2");
}
class HothUpdaterCLITest : public ::testing::Test
{
protected:
HothUpdaterCLIMock cli;
};
// Test for making sure doActivationCheck does not error out
TEST_F(HothUpdaterCLITest, doActivationCheckTest)
{
HothVersionStringsRsp rsp = {.header =
{
.struct_version = 0,
.checksum = 0,
.result = 0,
.data_len = 0,
.reserved = 0,
},
.version = {
.version_string_ro = "1.2.345",
.version_string_rw = "2.3.456",
.reserved = "",
.current_image = 0,
}};
Args args;
args.expectedRwVersion = "2.3.456";
sdbusplus::bus::bus bus{nullptr};
EXPECT_CALL(cli, getHothVersion(_, _)).Times(1).WillOnce(Return(rsp));
EXPECT_CALL(cli, getHothActivationStatistics(_, _)).Times(0);
cli.doActivationCheckLogic(bus, args);
}
// Test doActivationCheck when version mismatch.
TEST_F(HothUpdaterCLITest, doActivationCheckWrongVersion)
{
HothVersionStringsRsp rsp = {.header =
{
.struct_version = 0,
.checksum = 0,
.result = 0,
.data_len = 0,
.reserved = 0,
},
.version = {
.version_string_ro = "1.2.345",
.version_string_rw = "2.3.456",
.reserved = "",
.current_image = 0,
}};
HothActivationStatistics stats = {
.rw_failure_code = 1,
.rw_failed_minor = 2,
.ro_failure_code = 0xffff,
.reset_flags = 3,
.uptime_us = 0xdeadbeeffeedbead,
};
Args args;
args.expectedRwVersion = "3.4.567";
sdbusplus::bus::bus bus{nullptr};
EXPECT_CALL(cli, getHothVersion(_, _)).Times(1).WillOnce(Return(rsp));
EXPECT_CALL(cli, getHothActivationStatistics(_, _))
.Times(1)
.WillOnce(Return(stats));
EXPECT_THROW(cli.doActivationCheckLogic(bus, args), std::runtime_error);
}
// Test for making sure the doUpdate loop works correctly
TEST_F(HothUpdaterCLITest, getFirmwareUpdateStatusTest)
{
Args args;
args.updateMethod = "spi";
args.imageFilename = "dummy";
std::vector<uint8_t> dummy_image = {0, 1, 2, 3};
sdbusplus::bus::bus bus{nullptr};
EXPECT_CALL(cli, readFileIntoByteArray(_))
.Times(1)
.WillOnce(Return(dummy_image));
EXPECT_CALL(cli, spiWrite(_, _, _, _)).Times(1);
EXPECT_CALL(cli, getFirmwareUpdateStatus(_, _))
.Times(3)
.WillOnce(Return(FirmwareUpdateStatus::InProgress))
.WillOnce(Return(FirmwareUpdateStatus::InProgress))
.WillOnce(Return(FirmwareUpdateStatus::Done));
cli.doUpdateLogic(bus, args);
}
// Test for enabling secureboot enforcement successfully
TEST_F(HothUpdaterCLITest, EnableSecurebootEnforcementSuccess)
{
Args args;
args.hothId = "inst0";
const std::vector<uint8_t> successResponse = {0x03, 0xfc, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00};
sdbusplus::bus::bus bus{nullptr};
EXPECT_CALL(cli, sendHostCommand(_, args.hothId, _))
.WillOnce(Return(successResponse));
EXPECT_NO_THROW(cli.doEnableSecurebootEnforcementLogic(bus, args));
}
// Test for enabling secureboot enforcement failure
TEST_F(HothUpdaterCLITest, EnableSecurebootEnforcementFailure)
{
Args args;
args.hothId = "inst0";
const std::vector<uint8_t> failureResponse = {0x03, 0xfc, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00};
sdbusplus::bus::bus bus{nullptr};
EXPECT_CALL(cli, sendHostCommand(_, args.hothId, _))
.WillOnce(Return(failureResponse));
EXPECT_THROW(cli.doEnableSecurebootEnforcementLogic(bus, args),
std::runtime_error);
}
} // namespace
} // namespace google::hoth::tools