blob: 557984e0a2b857b45a80b33127983309d7720106 [file] [log] [blame]
// Copyright 2019 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 "biod/cros_fp_updater.h"
#include <string>
#include <unordered_set>
#include <utility>
#include <vector>
#include <base/files/file.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/files/scoped_temp_dir.h>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <chromeos/ec/ec_commands.h>
#include <cros_config/fake_cros_config.h>
#include "biod/cros_fp_firmware.h"
#include "biod/utils.h"
using ::testing::_;
using ::testing::AtLeast;
using ::testing::DefaultValue;
using ::testing::DoAll;
using ::testing::Eq;
using ::testing::NotNull;
using ::testing::Ref;
using ::testing::Return;
using ::testing::SetArgPointee;
namespace {
constexpr char kTestImageROVersion[] = "nocturne_fp_v2.2.64-58cf5974e";
constexpr char kTestImageRWVersion[] = "nocturne_fp_v2.2.110-b936c0a3c";
constexpr char kTestImageFileName[] = "nocturne_fp_v2.2.110-b936c0a3c.bin";
const base::FilePath kInitFilePath("/UNTOUCHED_PATH");
// (board_name, file_name)
// All |file_name|'s should be unique, so that tests can pull any
// combination of elements to test with.
// All |board_name|'s should be unique, so that tests can check for
// proper firmware name fetching when multiple valid firmwares are present.
// When |board_name| is "", use legacy update path.
const std::vector<std::pair<std::string, std::string>> kValidFirmwareNames = {
std::make_pair("", kTestImageFileName),
std::make_pair("", "unknown_fp_v123.123.123-123456789.bin"),
std::make_pair("", "0_fp_0.bin"),
std::make_pair("", "_fp_.bin"),
std::make_pair("hatch_fp", "hatch_fp_v2.2.110-b936c0a3c.bin"),
std::make_pair("dragonclaw", "dragonclaw_v1.0.4-b936c0a3c.bin"),
std::make_pair("dragonguts", "dragonguts_v1.2.3-d00d8badf00d.bin"),
};
const std::vector<std::string> kInvalidFirmwareNames = {
"nocturne_fp_v2.2.110-b936c0a3c.txt",
"not_fpmcu_firmware.bin",
"not_fpmcu_firmware.txt",
"_fp_.txt",
"file",
};
const std::vector<biod::updater::FindFirmwareFileStatus>
kFindFirmwareFileStatuses = {
biod::updater::FindFirmwareFileStatus::kFoundFile,
biod::updater::FindFirmwareFileStatus::kNoDirectory,
biod::updater::FindFirmwareFileStatus::kFileNotFound,
biod::updater::FindFirmwareFileStatus::kMultipleFiles,
};
const std::vector<enum ec_current_image> kEcCurrentImageEnums = {
EC_IMAGE_UNKNOWN,
EC_IMAGE_RO,
EC_IMAGE_RW,
};
class MockCrosFpDeviceUpdate : public biod::CrosFpDeviceUpdate {
public:
MOCK_METHOD(bool,
GetVersion,
(biod::CrosFpDevice::EcVersion*),
(const, override));
MOCK_METHOD(bool, IsFlashProtectEnabled, (bool*), (const, override));
MOCK_METHOD(bool,
Flash,
(const biod::CrosFpFirmware&, enum ec_current_image),
(const, override));
};
class MockCrosFpBootUpdateCtrl : public biod::CrosFpBootUpdateCtrl {
public:
MOCK_METHOD(bool, TriggerBootUpdateSplash, (), (const, override));
MOCK_METHOD(bool, ScheduleReboot, (), (const, override));
};
class MockCrosFpFirmware : public biod::CrosFpFirmware {
public:
MockCrosFpFirmware() { set_status(biod::CrosFpFirmware::Status::kOk); }
void SetMockFwVersion(const ImageVersion& version) { set_version(version); }
};
} // namespace
namespace biod {
namespace updater {
TEST(CrosFpUpdaterFingerprintUnsupportedTest, FingerprintLocationUnset) {
// Given a device that does not indicate fingerprint sensor location
brillo::FakeCrosConfig cros_config;
// expect FingerprintUnsupported to report false.
EXPECT_FALSE(FingerprintUnsupported(&cros_config));
}
TEST(CrosFpUpdaterFingerprintUnsupportedTest, FingerprintLocationSet) {
brillo::FakeCrosConfig cros_config;
cros_config.SetString(kCrosConfigFPPath, kCrosConfigFPLocation,
"power-button-top-left");
EXPECT_FALSE(FingerprintUnsupported(&cros_config));
}
TEST(CrosFpUpdaterFingerprintUnsupportedTest, FingerprintLocationSetNone) {
brillo::FakeCrosConfig cros_config;
cros_config.SetString(kCrosConfigFPPath, kCrosConfigFPLocation, "none");
EXPECT_TRUE(FingerprintUnsupported(&cros_config));
}
class CrosFpUpdaterFindFirmwareTest : public ::testing::Test {
protected:
void SetUp() override { CHECK(ResetTestTempDir()); }
void TearDown() override { EXPECT_TRUE(temp_dir_.Delete()); }
bool ResetTestTempDir() {
if (temp_dir_.IsValid()) {
if (!temp_dir_.Delete()) {
return false;
}
}
return temp_dir_.CreateUniqueTempDir();
}
const base::FilePath& GetTestTempDir() const { return temp_dir_.GetPath(); }
bool TouchFile(const base::FilePath& abspath) const {
if (!GetTestTempDir().IsParent(abspath)) {
LOG(ERROR) << "Asked to TouchFile outside test environment.";
return false;
}
base::File file(abspath,
base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
EXPECT_TRUE(file.IsValid());
file.Close();
EXPECT_TRUE(base::PathExists(abspath));
return true;
}
bool RemoveFile(const base::FilePath& abspath) const {
return base::DeleteFile(abspath, true);
}
CrosFpUpdaterFindFirmwareTest() = default;
~CrosFpUpdaterFindFirmwareTest() override = default;
base::ScopedTempDir temp_dir_;
private:
DISALLOW_COPY_AND_ASSIGN(CrosFpUpdaterFindFirmwareTest);
};
TEST_F(CrosFpUpdaterFindFirmwareTest, InvalidPathBlank) {
brillo::FakeCrosConfig cros_config;
base::FilePath out_file_path(kInitFilePath);
// Given an empty directory path, searching for a firmware file
auto status =
FindFirmwareFile(base::FilePath(""), &cros_config, &out_file_path);
// fails with a no directory error
EXPECT_EQ(status, FindFirmwareFileStatus::kNoDirectory);
// without modifying the output file path.
EXPECT_EQ(out_file_path, kInitFilePath);
}
TEST_F(CrosFpUpdaterFindFirmwareTest, InvalidPathOddChars) {
brillo::FakeCrosConfig cros_config;
base::FilePath out_file_path(kInitFilePath);
// Given "--" as directory path, searching for a firmware file
auto status =
FindFirmwareFile(base::FilePath("--"), &cros_config, &out_file_path);
// fails with a no directory error
EXPECT_EQ(status, FindFirmwareFileStatus::kNoDirectory);
// without modifying the output file path.
EXPECT_EQ(out_file_path, kInitFilePath);
}
TEST_F(CrosFpUpdaterFindFirmwareTest, DirectoryWithoutFirmware) {
brillo::FakeCrosConfig cros_config;
base::FilePath out_file_path(kInitFilePath);
// Given a directory with no firmware files, searching for a firmware file
auto status =
FindFirmwareFile(GetTestTempDir(), &cros_config, &out_file_path);
// fails with a file not found error
EXPECT_EQ(status, FindFirmwareFileStatus::kFileNotFound);
// without modifying the output file path.
EXPECT_EQ(out_file_path, kInitFilePath);
}
TEST_F(CrosFpUpdaterFindFirmwareTest, OneGoodFirmwareFilePattern) {
for (const auto& good_fw : kValidFirmwareNames) {
brillo::FakeCrosConfig cros_config;
base::FilePath fw_file_path, out_file_path;
CHECK(ResetTestTempDir());
// Given a directory with one correctly named firmware file
fw_file_path = GetTestTempDir().Append(good_fw.second);
EXPECT_TRUE(TouchFile(fw_file_path));
// and a cros-config with an appropriate fingerprint board name,
if (!good_fw.first.empty()) {
cros_config.SetString(kCrosConfigFPPath, kCrosConfigFPBoard,
good_fw.first);
}
// searching for a firmware file
auto status =
FindFirmwareFile(GetTestTempDir(), &cros_config, &out_file_path);
// succeeds
EXPECT_EQ(status, FindFirmwareFileStatus::kFoundFile);
// and returns the path to the original firmware file.
EXPECT_EQ(out_file_path, fw_file_path);
}
}
TEST_F(CrosFpUpdaterFindFirmwareTest, OneBadFirmwareFilePattern) {
for (const auto& bad_fw_name : kInvalidFirmwareNames) {
brillo::FakeCrosConfig cros_config;
base::FilePath fw_file_path, out_file_path(kInitFilePath);
CHECK(ResetTestTempDir());
// Given a directory with one incorrectly named firmware file,
fw_file_path = GetTestTempDir().Append(bad_fw_name);
EXPECT_TRUE(TouchFile(fw_file_path));
// searching for a firmware file
auto status =
FindFirmwareFile(GetTestTempDir(), &cros_config, &out_file_path);
// fails with a file not found error
EXPECT_EQ(status, FindFirmwareFileStatus::kFileNotFound);
// without modifying the output file path.
EXPECT_EQ(out_file_path, kInitFilePath);
}
}
TEST_F(CrosFpUpdaterFindFirmwareTest, MultipleValidFiles) {
// Given a directory with multiple correctly named firmware files
for (const auto& good_fw : kValidFirmwareNames) {
EXPECT_TRUE(TouchFile(GetTestTempDir().Append(good_fw.second)));
}
for (const auto& good_fw : kValidFirmwareNames) {
brillo::FakeCrosConfig cros_config;
base::FilePath fw_file_path, out_file_path;
// and a cros-config fingerprint board name,
if (good_fw.first.empty()) {
continue;
}
cros_config.SetString(kCrosConfigFPPath, kCrosConfigFPBoard, good_fw.first);
// searching for a firmware file
auto status =
FindFirmwareFile(GetTestTempDir(), &cros_config, &out_file_path);
// succeeds
EXPECT_EQ(status, FindFirmwareFileStatus::kFoundFile);
// and returns the path to the corresponding firmware file.
EXPECT_EQ(out_file_path, GetTestTempDir().Append(good_fw.second));
}
}
TEST_F(CrosFpUpdaterFindFirmwareTest, MultipleValidFilesExceptSpecifc) {
// Given a directory with multiple correctly named firmware files and
for (const auto& good_fw : kValidFirmwareNames) {
EXPECT_TRUE(TouchFile(GetTestTempDir().Append(good_fw.second)));
}
for (const auto& good_fw : kValidFirmwareNames) {
brillo::FakeCrosConfig cros_config;
base::FilePath fw_file_path, out_file_path(kInitFilePath);
const auto good_file_path = GetTestTempDir().Append(good_fw.second);
// a cros-config fingerprint board name,
if (good_fw.first.empty()) {
continue;
}
cros_config.SetString(kCrosConfigFPPath, kCrosConfigFPBoard, good_fw.first);
// but missing the board specific firmware file,
EXPECT_TRUE(RemoveFile(good_file_path));
// searching for a firmware file
auto status =
FindFirmwareFile(GetTestTempDir(), &cros_config, &out_file_path);
// fails with a file not found error
EXPECT_EQ(status, FindFirmwareFileStatus::kFileNotFound);
// without modifying the output file path.
EXPECT_EQ(out_file_path, kInitFilePath);
EXPECT_TRUE(TouchFile(good_file_path));
}
}
TEST_F(CrosFpUpdaterFindFirmwareTest, MultipleFilesError) {
brillo::FakeCrosConfig cros_config;
base::FilePath out_file_path(kInitFilePath);
// Given a directory with two correctly named firmware files,
EXPECT_GE(kValidFirmwareNames.size(), 2);
EXPECT_TRUE(
TouchFile(GetTestTempDir().Append(kValidFirmwareNames[0].second)));
EXPECT_TRUE(
TouchFile(GetTestTempDir().Append(kValidFirmwareNames[1].second)));
// searching for a firmware file
auto status =
FindFirmwareFile(GetTestTempDir(), &cros_config, &out_file_path);
// fails with a multiple files error
EXPECT_EQ(status, FindFirmwareFileStatus::kMultipleFiles);
// without modifying the output file path.
EXPECT_EQ(out_file_path, kInitFilePath);
}
TEST_F(CrosFpUpdaterFindFirmwareTest, OneGoodAndOneBadFirmwareFilePattern) {
brillo::FakeCrosConfig cros_config;
base::FilePath out_file_path, good_file_path, bad_file_path;
// Given a directory with one correctly named and one incorrectly named
// firmware file,
good_file_path = GetTestTempDir().Append(kValidFirmwareNames[0].second);
bad_file_path = GetTestTempDir().Append(kInvalidFirmwareNames[0]);
EXPECT_TRUE(TouchFile(good_file_path));
EXPECT_TRUE(TouchFile(bad_file_path));
// searching for a firmware file
auto status =
FindFirmwareFile(GetTestTempDir(), &cros_config, &out_file_path);
// succeeds
EXPECT_EQ(status, FindFirmwareFileStatus::kFoundFile);
// and returns the path to the single correctly named firmware file.
EXPECT_EQ(out_file_path, good_file_path);
}
TEST_F(CrosFpUpdaterFindFirmwareTest, NonblankStatusMessages) {
// Given a FindFirmwareFile status
for (auto status : kFindFirmwareFileStatuses) {
// when we ask for the human readable string
std::string msg = FindFirmwareFileStatusToString(status);
// expect it to not be "".
EXPECT_FALSE(msg.empty()) << "Status " << to_utype(status)
<< " converts to a blank status string.";
}
}
TEST_F(CrosFpUpdaterFindFirmwareTest, UniqueStatusMessages) {
// Given a set of all FindFirmwareFile status messages
std::unordered_set<std::string> status_msgs;
for (auto status : kFindFirmwareFileStatuses) {
status_msgs.insert(FindFirmwareFileStatusToString(status));
}
// expect the set to contain the same number of unique messages
// as there are original statuses.
EXPECT_EQ(status_msgs.size(), kFindFirmwareFileStatuses.size())
<< "There are one or more non-unique status messages.";
}
class CrosFpUpdaterTest : public ::testing::Test {
protected:
void SetUp() override {
DefaultValue<bool>::Set(true);
// Lay down default rules to ensure an error is logged if an interface
// if called without explicitly specifying it.
EXPECT_CALL(dev_update_, GetVersion(_)).Times(0);
EXPECT_CALL(dev_update_, IsFlashProtectEnabled(_)).Times(0);
EXPECT_CALL(dev_update_, Flash(_, _)).Times(0);
EXPECT_CALL(boot_ctrl_, TriggerBootUpdateSplash()).Times(0);
EXPECT_CALL(boot_ctrl_, ScheduleReboot()).Times(0);
}
void TearDown() override { DefaultValue<bool>::Clear(); }
// Setup an environment where a device GetVersion and IsFlashProtected
// always succeed and report preset values corresponding to a preset
// mock firmware.
void SetupEnvironment(bool flash_protect,
bool ro_mismatch,
bool rw_mismatch,
enum ec_current_image ec_image = EC_IMAGE_RW) {
CrosFpFirmware::ImageVersion img_ver = {kTestImageROVersion,
kTestImageRWVersion};
biod::CrosFpDevice::EcVersion ec_ver = {kTestImageROVersion,
kTestImageRWVersion, ec_image};
if (ro_mismatch) {
img_ver.ro_version += "NEW";
}
if (rw_mismatch) {
img_ver.rw_version += "NEW";
}
fw_.SetMockFwVersion(img_ver);
EXPECT_CALL(dev_update_, GetVersion(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(ec_ver), Return(true)));
EXPECT_CALL(dev_update_, IsFlashProtectEnabled(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(flash_protect), Return(true)));
}
UpdateResult RunUpdater() { return DoUpdate(dev_update_, boot_ctrl_, fw_); }
CrosFpUpdaterTest() = default;
~CrosFpUpdaterTest() override = default;
MockCrosFpDeviceUpdate dev_update_;
MockCrosFpBootUpdateCtrl boot_ctrl_;
MockCrosFpFirmware fw_;
private:
DISALLOW_COPY_AND_ASSIGN(CrosFpUpdaterTest);
};
// EcCurrentImageToString Tests
TEST(CrosFpDeviceUpdateTest, NonblankEcCurrentImageString) {
// Given a EC Image enumeration
for (auto image : kEcCurrentImageEnums) {
// when we ask for the human readable string
std::string msg = CrosFpDeviceUpdate::EcCurrentImageToString(image);
// expect it to not be "".
EXPECT_FALSE(msg.empty()) << "Status " << to_utype(image)
<< " converts to a blank status string.";
}
}
TEST(CrosFpDeviceUpdateTest, UniqueEcCurrentImageString) {
// Given a set of EC Image enumeration strings
std::unordered_set<std::string> status_msgs;
for (auto image : kEcCurrentImageEnums) {
status_msgs.insert(CrosFpDeviceUpdate::EcCurrentImageToString(image));
}
// expect the set to contain the same number of unique strings
// as there are original ec image enumerations.
EXPECT_EQ(status_msgs.size(), kEcCurrentImageEnums.size())
<< "There are one or more non-unique ec image strings.";
}
// DoUpdate Tests
// Failure code paths
TEST_F(CrosFpUpdaterTest, GetDeviceVersionFails) {
// Given a device which fails to report its version,
EXPECT_CALL(dev_update_, GetVersion(NotNull())).WillOnce(Return(false));
// expect the updater to report a get version failure with no update reason.
auto result = RunUpdater();
EXPECT_EQ(result.status, UpdateStatus::kUpdateFailedGetVersion);
EXPECT_EQ(result.reason, UpdateReason::kNone);
}
TEST_F(CrosFpUpdaterTest, GetFlashProtectFails) {
// Given a device which reports its version, but fails to
// report its flash protect status,
EXPECT_CALL(dev_update_, GetVersion(NotNull())).WillOnce(Return(true));
EXPECT_CALL(dev_update_, IsFlashProtectEnabled(NotNull()))
.WillOnce(Return(false));
// expect the updater to report a flash protect failure
// with no update reason.
auto result = RunUpdater();
EXPECT_EQ(result.status, UpdateStatus::kUpdateFailedFlashProtect);
EXPECT_EQ(result.reason, UpdateReason::kNone);
}
TEST_F(CrosFpUpdaterTest, FPDisabled_ROMismatch_ROUpdateFail) {
// Given an environment where
SetupEnvironment(
// flash-protect is disabled,
false,
// RO needs to be updated,
true, false);
// and flashing operations fail,
ON_CALL(dev_update_, Flash(_, _)).WillByDefault(Return(false));
// expect the boot splash to be triggered,
EXPECT_CALL(boot_ctrl_, TriggerBootUpdateSplash());
// but no reboot requested (avoid boot loop),
EXPECT_CALL(boot_ctrl_, ScheduleReboot()).Times(0);
// an attempted RO flash,
EXPECT_CALL(dev_update_, Flash(Ref(fw_), EC_IMAGE_RO));
// and the updater to report an RO update failure with
// an RO version mismatch update reason.
auto result = RunUpdater();
EXPECT_EQ(result.status, UpdateStatus::kUpdateFailedRO);
EXPECT_EQ(result.reason, UpdateReason::kMismatchROVersion);
}
TEST_F(CrosFpUpdaterTest, FPDisabled_RORWMismatch_ROUpdateFail) {
// Given an environment where
SetupEnvironment(
// flash-protect is disabled,
false,
// RO needs to be updated,
true,
// RW needs to be updated,
true);
// flashing operations fail,
ON_CALL(dev_update_, Flash(_, _)).WillByDefault(Return(false));
// expect the boot splash to be triggered,
EXPECT_CALL(boot_ctrl_, TriggerBootUpdateSplash());
// but no reboot requested (avoid boot loop),
EXPECT_CALL(boot_ctrl_, ScheduleReboot()).Times(0);
// an attempted RO flash (but no RW flash),
EXPECT_CALL(dev_update_, Flash(Ref(fw_), EC_IMAGE_RO));
EXPECT_CALL(dev_update_, Flash(Ref(fw_), EC_IMAGE_RW)).Times(0);
// and the updater to report an RO update failure with
// an RO version mismatch update reason.
auto result = RunUpdater();
EXPECT_EQ(result.status, UpdateStatus::kUpdateFailedRO);
EXPECT_EQ(result.reason, UpdateReason::kMismatchROVersion);
}
TEST_F(CrosFpUpdaterTest, FPEnabled_RWMismatch_RWUpdateFail) {
// Given an environment where
SetupEnvironment(
// flash-protect is enabled,
true, false,
// RW needs to be updated,
true);
// flashing operations fail,
ON_CALL(dev_update_, Flash(_, _)).WillByDefault(Return(false));
// expect the boot splash to be triggered,
EXPECT_CALL(boot_ctrl_, TriggerBootUpdateSplash());
// but no reboot requested (avoid boot loop),
EXPECT_CALL(boot_ctrl_, ScheduleReboot()).Times(0);
// an attempted RW flash,
EXPECT_CALL(dev_update_, Flash(Ref(fw_), EC_IMAGE_RW));
// and the updater to report an RW update failure with
// an RW version mismatch update reason.
auto result = RunUpdater();
EXPECT_EQ(result.status, UpdateStatus::kUpdateFailedRW);
EXPECT_EQ(result.reason, UpdateReason::kMismatchRWVersion);
}
TEST_F(CrosFpUpdaterTest, FPDisabled_RORWMismatch_BootCtrlsBothFail) {
// Given an environment where
SetupEnvironment(
// flash-protect is disabled,
false,
// RO needs to be updated,
true,
// RW needs to be updated,
true);
// both boot control functions fail,
ON_CALL(boot_ctrl_, TriggerBootUpdateSplash()).WillByDefault(Return(false));
ON_CALL(boot_ctrl_, ScheduleReboot()).WillByDefault(Return(false));
// expect both boot control functions to be attempted,
EXPECT_CALL(boot_ctrl_, TriggerBootUpdateSplash()).Times(AtLeast(1));
EXPECT_CALL(boot_ctrl_, ScheduleReboot()).Times(AtLeast(1));
// both firmware images to be flashed,
EXPECT_CALL(dev_update_, Flash(Ref(fw_), EC_IMAGE_RW));
EXPECT_CALL(dev_update_, Flash(Ref(fw_), EC_IMAGE_RO));
// and the updater to report a success with an
// RO and RW version mismatch update reason.
auto result = RunUpdater();
EXPECT_EQ(result.status, UpdateStatus::kUpdateSucceeded);
EXPECT_EQ(result.reason, UpdateReason::kMismatchROVersion |
UpdateReason::kMismatchRWVersion);
}
// Abnormal code paths
TEST_F(CrosFpUpdaterTest, CurrentROImage_RORWMatch_UpdateRW) {
// Given an environment where
SetupEnvironment(true, false, false,
// the current boot is stuck in RO,
EC_IMAGE_RO);
// expect both boot controls to be triggered,
EXPECT_CALL(boot_ctrl_, TriggerBootUpdateSplash());
EXPECT_CALL(boot_ctrl_, ScheduleReboot());
// an attempted RW flash,
EXPECT_CALL(dev_update_, Flash(Ref(fw_), EC_IMAGE_RW));
// and the updater to report a success with an
// RO active image update reason.
auto result = RunUpdater();
EXPECT_EQ(result.status, UpdateStatus::kUpdateSucceeded);
EXPECT_EQ(result.reason, UpdateReason::kActiveImageRO);
}
// Normal code paths
TEST_F(CrosFpUpdaterTest, FPDisabled_RORWMatch_NoUpdate) {
// Given an environment where no updates are necessary
SetupEnvironment(
// and flash-protect is disabled,
false, false, false);
// expect neither boot control functions to be attempted,
EXPECT_CALL(boot_ctrl_, TriggerBootUpdateSplash()).Times(0);
EXPECT_CALL(boot_ctrl_, ScheduleReboot()).Times(0);
// no firmware images flashed,
EXPECT_CALL(dev_update_, Flash(_, _)).Times(0);
// and the updater to report an update not necessary with
// no update reason.
auto result = RunUpdater();
EXPECT_EQ(result.status, UpdateStatus::kUpdateNotNecessary);
EXPECT_EQ(result.reason, UpdateReason::kNone);
}
TEST_F(CrosFpUpdaterTest, FPEnabled_RORWMatch_NoUpdate) {
// Given an environment where no updates are necessary
SetupEnvironment(
// and flash-protect is enabled,
true, false, false);
// expect neither boot control functions to be attempted,
EXPECT_CALL(boot_ctrl_, TriggerBootUpdateSplash()).Times(0);
EXPECT_CALL(boot_ctrl_, ScheduleReboot()).Times(0);
// no firmware images flashed,
EXPECT_CALL(dev_update_, Flash(_, _)).Times(0);
// and the updater to report an update not necessary with
// no update reason.
auto result = RunUpdater();
EXPECT_EQ(result.status, UpdateStatus::kUpdateNotNecessary);
EXPECT_EQ(result.reason, UpdateReason::kNone);
}
TEST_F(CrosFpUpdaterTest, FPEnabled_ROMismatch_NoUpdate) {
// Given an environment where
SetupEnvironment(
// flash-protect is enabled
true,
// and RO needs to be updated,
true, false);
// expect neither boot control functions to be attempted,
EXPECT_CALL(boot_ctrl_, TriggerBootUpdateSplash()).Times(0);
EXPECT_CALL(boot_ctrl_, ScheduleReboot()).Times(0);
// no firmware images flashed,
EXPECT_CALL(dev_update_, Flash(_, _)).Times(0);
// and the updater to report an update not necessary with
// no update reason.
auto result = RunUpdater();
EXPECT_EQ(result.status, UpdateStatus::kUpdateNotNecessary);
EXPECT_EQ(result.reason, UpdateReason::kNone);
}
TEST_F(CrosFpUpdaterTest, RWMismatch_UpdateRW) {
// Given an environment where
SetupEnvironment(true, false,
// RW needs to be updated,
true);
// expect both boot control functions to be triggered,
EXPECT_CALL(boot_ctrl_, TriggerBootUpdateSplash());
EXPECT_CALL(boot_ctrl_, ScheduleReboot());
// RW to be flashed,
EXPECT_CALL(dev_update_, Flash(Ref(fw_), EC_IMAGE_RW));
// and the updater to report a success with an
// RW version mismatch update reason.
auto result = RunUpdater();
EXPECT_EQ(result.status, UpdateStatus::kUpdateSucceeded);
EXPECT_EQ(result.reason, UpdateReason::kMismatchRWVersion);
}
TEST_F(CrosFpUpdaterTest, FPDisabled_ROMismatch_UpdateRO) {
// Given an environment where
SetupEnvironment(
// flash-protect is disabled
false,
// and RO needs to be updated,
true, false);
// expect both boot control functions to be triggered,
EXPECT_CALL(boot_ctrl_, TriggerBootUpdateSplash());
EXPECT_CALL(boot_ctrl_, ScheduleReboot());
// RO to be flashed,
EXPECT_CALL(dev_update_, Flash(Ref(fw_), EC_IMAGE_RO));
// and the updater to report a success with an
// RO version mismatch update reason.
auto result = RunUpdater();
EXPECT_EQ(result.status, UpdateStatus::kUpdateSucceeded);
EXPECT_EQ(result.reason, UpdateReason::kMismatchROVersion);
}
TEST_F(CrosFpUpdaterTest, FPDisabled_RORWMismatch_UpdateRORW) {
// Given an environment where
SetupEnvironment(
// flash-protect is disabled,
false,
// RO needs to be updated,
true,
// RW needs to be updated,
true);
// expect both boot control functions to be triggered,
EXPECT_CALL(boot_ctrl_, TriggerBootUpdateSplash()).Times(AtLeast(1));
EXPECT_CALL(boot_ctrl_, ScheduleReboot()).Times(AtLeast(1));
// both firmware images to be flashed,
EXPECT_CALL(dev_update_, Flash(Ref(fw_), EC_IMAGE_RO));
EXPECT_CALL(dev_update_, Flash(Ref(fw_), EC_IMAGE_RW));
// and the updater to report a success with an
// RW and RO version mismatch update reason.
auto result = RunUpdater();
EXPECT_EQ(result.status, UpdateStatus::kUpdateSucceeded);
EXPECT_EQ(result.reason, UpdateReason::kMismatchROVersion |
UpdateReason::kMismatchRWVersion);
}
} // namespace updater
} // namespace biod