blob: 45e9f49ad1b9df53ede7d137deb4bc2bbe5a51ac [file] [log] [blame]
// Copyright 2017 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 "modemfwd/modem_flasher.h"
#include <memory>
#include <utility>
#include <vector>
#include <base/files/file_path.h>
#include <chromeos/switches/modemfwd_switches.h>
#include <gtest/gtest.h>
#include "modemfwd/firmware_directory_stub.h"
#include "modemfwd/mock_journal.h"
#include "modemfwd/mock_modem.h"
using ::testing::_;
using ::testing::AtLeast;
using ::testing::Mock;
using ::testing::Return;
namespace modemfwd {
namespace {
constexpr char kDeviceId1[] = "device:id:1";
constexpr char kEquipmentId1[] = "equipment_id_1";
constexpr char kMainFirmware1Path[] = "main_fw_1.fls";
constexpr char kMainFirmware1Version[] = "versionA";
constexpr char kMainFirmware2Path[] = "main_fw_2.fls";
constexpr char kMainFirmware2Version[] = "versionB";
constexpr char kOemFirmware1Path[] = "oem_cust_1.fls";
constexpr char kOemFirmware1Version[] = "6000.1";
constexpr char kOemFirmware2Path[] = "oem_cust_2.fls";
constexpr char kOemFirmware2Version[] = "6000.2";
constexpr char kCarrier1[] = "uuid_1";
constexpr char kCarrier1Mvno[] = "uuid_1_1";
constexpr char kCarrier1Firmware1Path[] = "carrier_1_fw_1.fls";
constexpr char kCarrier1Firmware1Version[] = "v1.00";
constexpr char kCarrier1Firmware2Path[] = "carrier_1_fw_2.fls";
constexpr char kCarrier1Firmware2Version[] = "v1.10";
constexpr char kCarrier2[] = "uuid_2";
constexpr char kCarrier2Firmware1Path[] = "carrier_2_fw_1.fls";
constexpr char kCarrier2Firmware1Version[] = "4500.15.65";
constexpr char kGenericCarrierFirmware1Path[] = "generic_fw_1.fls";
constexpr char kGenericCarrierFirmware1Version[] = "2017-10-13";
constexpr char kGenericCarrierFirmware2Path[] = "generic_fw_2.fls";
constexpr char kGenericCarrierFirmware2Version[] = "2017-10-14";
} // namespace
class ModemFlasherTest : public ::testing::Test {
public:
ModemFlasherTest() {
auto firmware_directory = std::make_unique<FirmwareDirectoryStub>();
firmware_directory_ = firmware_directory.get();
auto journal = std::make_unique<MockJournal>();
journal_ = journal.get();
modem_flasher_ = std::make_unique<ModemFlasher>(
std::move(firmware_directory), std::move(journal));
only_main_ = {kFwMain};
only_carrier_ = {kFwCarrier};
}
protected:
void AddMainFirmwareFile(const std::string& device_id,
const base::FilePath& firmware_path,
const std::string& version) {
FirmwareFileInfo firmware_info(firmware_path, version);
firmware_directory_->AddMainFirmware(kDeviceId1, firmware_info);
}
void AddMainFirmwareFileForCarrier(const std::string& device_id,
const std::string& carrier_name,
const base::FilePath& firmware_path,
const std::string& version) {
FirmwareFileInfo firmware_info(firmware_path, version);
firmware_directory_->AddMainFirmwareForCarrier(kDeviceId1, carrier_name,
firmware_info);
}
void AddOemFirmwareFile(const std::string& device_id,
const base::FilePath& firmware_path,
const std::string& version) {
FirmwareFileInfo firmware_info(firmware_path, version);
firmware_directory_->AddOemFirmware(kDeviceId1, firmware_info);
}
void AddOemFirmwareFileForCarrier(const std::string& device_id,
const std::string& carrier_name,
const base::FilePath& firmware_path,
const std::string& version) {
FirmwareFileInfo firmware_info(firmware_path, version);
firmware_directory_->AddOemFirmwareForCarrier(kDeviceId1, carrier_name,
firmware_info);
}
void AddCarrierFirmwareFile(const std::string& device_id,
const std::string& carrier_name,
const base::FilePath& firmware_path,
const std::string& version) {
FirmwareFileInfo firmware_info(firmware_path, version);
firmware_directory_->AddCarrierFirmware(kDeviceId1, carrier_name,
firmware_info);
}
std::unique_ptr<MockModem> GetDefaultModem() {
auto modem = std::make_unique<MockModem>();
ON_CALL(*modem, GetDeviceId()).WillByDefault(Return(kDeviceId1));
ON_CALL(*modem, GetEquipmentId()).WillByDefault(Return(kEquipmentId1));
ON_CALL(*modem, GetCarrierId()).WillByDefault(Return(kCarrier1));
ON_CALL(*modem, GetMainFirmwareVersion())
.WillByDefault(Return(kMainFirmware1Version));
ON_CALL(*modem, GetOemFirmwareVersion())
.WillByDefault(Return(kOemFirmware1Version));
ON_CALL(*modem, GetCarrierFirmwareId()).WillByDefault(Return(""));
ON_CALL(*modem, GetCarrierFirmwareVersion()).WillByDefault(Return(""));
// Since the equipment ID is the main identifier we should always expect
// to want to know what it is.
EXPECT_CALL(*modem, GetEquipmentId()).Times(AtLeast(1));
return modem;
}
void SetCarrierFirmwareInfo(MockModem* modem,
const std::string& carrier_id,
const std::string& version) {
ON_CALL(*modem, GetCarrierFirmwareId()).WillByDefault(Return(carrier_id));
ON_CALL(*modem, GetCarrierFirmwareVersion()).WillByDefault(Return(version));
}
MockJournal* journal_;
std::unique_ptr<ModemFlasher> modem_flasher_;
// helpers for the mock_journal calls
std::vector<std::string> only_main_;
std::vector<std::string> only_carrier_;
private:
// We pass this off to |modem_flasher_| but keep a reference to it to ensure
// we can set up the stub outputs.
FirmwareDirectoryStub* firmware_directory_;
};
TEST_F(ModemFlasherTest, NothingToFlash) {
auto modem = GetDefaultModem();
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, FlashFirmwares(_)).Times(0);
modem_flasher_->TryFlash(modem.get());
}
TEST_F(ModemFlasherTest, FlashMainFirmware) {
base::FilePath new_firmware(kMainFirmware2Path);
AddMainFirmwareFile(kDeviceId1, new_firmware, kMainFirmware2Version);
auto modem = GetDefaultModem();
std::vector<FirmwareConfig> main_cfg = {
{kFwMain, new_firmware, kMainFirmware2Version}};
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetMainFirmwareVersion()).Times(AtLeast(1));
EXPECT_CALL(*modem, FlashFirmwares(main_cfg)).WillOnce(Return(true));
modem_flasher_->TryFlash(modem.get());
}
TEST_F(ModemFlasherTest, SkipSameMainVersion) {
base::FilePath firmware(kMainFirmware1Path);
AddMainFirmwareFile(kDeviceId1, firmware, kMainFirmware1Version);
auto modem = GetDefaultModem();
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetMainFirmwareVersion()).Times(AtLeast(1));
EXPECT_CALL(*modem, FlashFirmwares(_)).Times(0);
modem_flasher_->TryFlash(modem.get());
}
TEST_F(ModemFlasherTest, SkipSameOemVersion) {
base::FilePath firmware(kOemFirmware1Path);
AddOemFirmwareFile(kDeviceId1, firmware, kOemFirmware1Version);
auto modem = GetDefaultModem();
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetOemFirmwareVersion()).Times(AtLeast(1));
EXPECT_CALL(*modem, FlashFirmwares(_)).Times(0);
modem_flasher_->TryFlash(modem.get());
}
TEST_F(ModemFlasherTest, UpgradeOemFirmware) {
base::FilePath new_firmware(kOemFirmware2Path);
AddOemFirmwareFile(kDeviceId1, new_firmware, kOemFirmware2Version);
auto modem = GetDefaultModem();
std::vector<FirmwareConfig> oem_cfg = {
{kFwOem, new_firmware, kOemFirmware2Version}};
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetOemFirmwareVersion()).Times(AtLeast(1));
EXPECT_CALL(*modem, FlashFirmwares(oem_cfg)).WillOnce(Return(true));
modem_flasher_->TryFlash(modem.get());
}
TEST_F(ModemFlasherTest, UpgradeCarrierFirmware) {
base::FilePath new_firmware(kCarrier1Firmware2Path);
AddCarrierFirmwareFile(kDeviceId1, kCarrier1, new_firmware,
kCarrier1Firmware2Version);
auto modem = GetDefaultModem();
std::vector<FirmwareConfig> carrier_cfg = {
{kFwCarrier, new_firmware, kCarrier1Firmware2Version}};
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
SetCarrierFirmwareInfo(modem.get(), kCarrier1, kCarrier1Firmware1Version);
EXPECT_CALL(*modem, FlashFirmwares(carrier_cfg)).WillOnce(Return(true));
modem_flasher_->TryFlash(modem.get());
}
TEST_F(ModemFlasherTest, SwitchCarrierFirmwareForSimHotSwap) {
base::FilePath original_firmware(kCarrier1Firmware1Path);
base::FilePath other_firmware(kCarrier2Firmware1Path);
AddCarrierFirmwareFile(kDeviceId1, kCarrier1, original_firmware,
kCarrier1Firmware1Version);
AddCarrierFirmwareFile(kDeviceId1, kCarrier2, other_firmware,
kCarrier2Firmware1Version);
auto modem = GetDefaultModem();
std::vector<FirmwareConfig> carrier_other_cfg = {
{kFwCarrier, other_firmware, kCarrier2Firmware1Version}};
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetCarrierId())
.Times(AtLeast(1))
.WillRepeatedly(Return(kCarrier2));
SetCarrierFirmwareInfo(modem.get(), kCarrier1, kCarrier1Firmware1Version);
EXPECT_CALL(*modem, FlashFirmwares(carrier_other_cfg)).WillOnce(Return(true));
modem_flasher_->TryFlash(modem.get());
// After the modem reboots, the helper hopefully reports the new carrier.
SetCarrierFirmwareInfo(modem.get(), kCarrier2, kCarrier2Firmware1Version);
EXPECT_CALL(*modem, FlashFirmwares(_)).Times(0);
modem_flasher_->TryFlash(modem.get());
// Suppose we swap the SIM back to the first one. Then we should try to
// flash the first firmware again.
modem = GetDefaultModem();
std::vector<FirmwareConfig> carrier_orig_cfg = {
{kFwCarrier, original_firmware, kCarrier1Firmware1Version}};
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetCarrierId()).Times(AtLeast(1));
SetCarrierFirmwareInfo(modem.get(), kCarrier2, kCarrier2Firmware1Version);
EXPECT_CALL(*modem, FlashFirmwares(carrier_orig_cfg)).WillOnce(Return(true));
modem_flasher_->TryFlash(modem.get());
}
TEST_F(ModemFlasherTest, BlockAfterMainFlashFailure) {
base::FilePath new_firmware(kMainFirmware2Path);
AddMainFirmwareFile(kDeviceId1, new_firmware, kMainFirmware2Version);
auto modem = GetDefaultModem();
std::vector<FirmwareConfig> main_cfg = {
{kFwMain, new_firmware, kMainFirmware2Version}};
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetMainFirmwareVersion()).Times(AtLeast(1));
EXPECT_CALL(*modem, FlashFirmwares(main_cfg)).WillRepeatedly(Return(false));
modem_flasher_->TryFlash(modem.get());
// ModemFlasher retries once on a failure, so fail twice.
modem = GetDefaultModem();
modem_flasher_->TryFlash(modem.get());
// Here the modem would reboot, but ModemFlasher should keep track of its
// IMEI and ensure we don't even check the main firmware version or
// carrier.
modem = GetDefaultModem();
EXPECT_CALL(*modem, GetDeviceId()).Times(0);
EXPECT_CALL(*modem, GetMainFirmwareVersion()).Times(0);
EXPECT_CALL(*modem, GetCarrierId()).Times(0);
EXPECT_CALL(*modem, FlashFirmwares(_)).Times(0);
modem_flasher_->TryFlash(modem.get());
}
TEST_F(ModemFlasherTest, BlockAfterCarrierFlashFailure) {
base::FilePath new_firmware(kCarrier1Firmware2Path);
AddCarrierFirmwareFile(kDeviceId1, kCarrier1, new_firmware,
kCarrier1Firmware2Version);
auto modem = GetDefaultModem();
std::vector<FirmwareConfig> carrier_cfg = {
{kFwCarrier, new_firmware, kCarrier1Firmware2Version}};
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
SetCarrierFirmwareInfo(modem.get(), kCarrier1, kCarrier1Firmware1Version);
EXPECT_CALL(*modem, FlashFirmwares(carrier_cfg))
.WillRepeatedly(Return(false));
modem_flasher_->TryFlash(modem.get());
// ModemFlasher retries once on a failure, so fail twice.
modem = GetDefaultModem();
modem_flasher_->TryFlash(modem.get());
modem = GetDefaultModem();
EXPECT_CALL(*modem, GetDeviceId()).Times(0);
EXPECT_CALL(*modem, GetMainFirmwareVersion()).Times(0);
EXPECT_CALL(*modem, GetCarrierId()).Times(0);
EXPECT_CALL(*modem, FlashFirmwares(_)).Times(0);
modem_flasher_->TryFlash(modem.get());
}
TEST_F(ModemFlasherTest, RefuseToFlashMainFirmwareTwice) {
base::FilePath new_firmware(kMainFirmware2Path);
AddMainFirmwareFile(kDeviceId1, new_firmware, kMainFirmware2Version);
auto modem = GetDefaultModem();
std::vector<FirmwareConfig> main_cfg = {
{kFwMain, new_firmware, kMainFirmware2Version}};
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetMainFirmwareVersion()).Times(AtLeast(1));
EXPECT_CALL(*modem, FlashFirmwares(main_cfg)).WillOnce(Return(true));
modem_flasher_->TryFlash(modem.get());
// We've had issues in the past where the firmware version is updated
// but the modem still reports the old version string. Refuse to flash
// the main firmware twice because that should never be correct behavior
// in one session. Otherwise, we might try to flash the main firmware
// over and over.
modem = GetDefaultModem();
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetMainFirmwareVersion()).Times(0);
EXPECT_CALL(*modem, FlashFirmwares(_)).Times(0);
modem_flasher_->TryFlash(modem.get());
}
TEST_F(ModemFlasherTest, RefuseToFlashOemFirmwareTwice) {
base::FilePath new_firmware(kOemFirmware2Path);
AddOemFirmwareFile(kDeviceId1, new_firmware, kOemFirmware2Version);
auto modem = GetDefaultModem();
std::vector<FirmwareConfig> oem_cfg = {
{kFwOem, new_firmware, kOemFirmware2Version}};
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetOemFirmwareVersion()).Times(AtLeast(1));
EXPECT_CALL(*modem, FlashFirmwares(oem_cfg)).WillOnce(Return(true));
modem_flasher_->TryFlash(modem.get());
// Assume that the modem fails to return properly the new version.
modem = GetDefaultModem();
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetOemFirmwareVersion()).Times(0);
EXPECT_CALL(*modem, FlashFirmwares(_)).Times(0);
modem_flasher_->TryFlash(modem.get());
}
TEST_F(ModemFlasherTest, RefuseToFlashCarrierFirmwareTwice) {
base::FilePath new_firmware(kCarrier1Firmware2Path);
AddCarrierFirmwareFile(kDeviceId1, kCarrier1, new_firmware,
kCarrier1Firmware2Version);
auto modem = GetDefaultModem();
std::vector<FirmwareConfig> carrier_cfg = {
{kFwCarrier, new_firmware, kCarrier1Firmware2Version}};
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
SetCarrierFirmwareInfo(modem.get(), kCarrier1, kCarrier1Firmware1Version);
EXPECT_CALL(*modem, FlashFirmwares(carrier_cfg)).WillOnce(Return(true));
modem_flasher_->TryFlash(modem.get());
// Assume the carrier firmware doesn't have an updated version string in it,
// i.e. the modem will return the old version string even if it's been
// updated.
modem = GetDefaultModem();
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
SetCarrierFirmwareInfo(modem.get(), kCarrier1, kCarrier1Firmware1Version);
EXPECT_CALL(*modem, FlashFirmwares(_)).Times(0);
modem_flasher_->TryFlash(modem.get());
}
TEST_F(ModemFlasherTest, RefuseToReflashCarrierAcrossHotSwap) {
// Upgrade carrier firmware.
base::FilePath new_firmware(kCarrier1Firmware2Path);
AddCarrierFirmwareFile(kDeviceId1, kCarrier1, new_firmware,
kCarrier1Firmware2Version);
auto modem = GetDefaultModem();
std::vector<FirmwareConfig> carrier_cfg = {
{kFwCarrier, new_firmware, kCarrier1Firmware2Version}};
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetCarrierId()).Times(AtLeast(1));
SetCarrierFirmwareInfo(modem.get(), kCarrier1, kCarrier1Firmware1Version);
EXPECT_CALL(*modem, FlashFirmwares(carrier_cfg)).WillOnce(Return(true));
modem_flasher_->TryFlash(modem.get());
// Switch carriers, but there won't be firmware for the new one.
modem = GetDefaultModem();
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetCarrierId())
.Times(AtLeast(1))
.WillRepeatedly(Return(kCarrier2));
SetCarrierFirmwareInfo(modem.get(), kCarrier1, kCarrier1Firmware2Version);
EXPECT_CALL(*modem, FlashFirmwares(_)).Times(0);
modem_flasher_->TryFlash(modem.get());
// Suppose we swap the SIM back to the first one. We should not flash
// firmware that we already know we successfully flashed.
modem = GetDefaultModem();
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetCarrierId()).Times(AtLeast(1));
SetCarrierFirmwareInfo(modem.get(), kCarrier1, kCarrier1Firmware2Version);
EXPECT_CALL(*modem, FlashFirmwares(_)).Times(0);
modem_flasher_->TryFlash(modem.get());
}
TEST_F(ModemFlasherTest, UpgradeGenericFirmware) {
base::FilePath new_firmware(kGenericCarrierFirmware2Path);
AddCarrierFirmwareFile(kDeviceId1, FirmwareDirectory::kGenericCarrierId,
new_firmware, kGenericCarrierFirmware2Version);
auto modem = GetDefaultModem();
std::vector<FirmwareConfig> carrier_cfg = {
{kFwCarrier, new_firmware, kGenericCarrierFirmware2Version}};
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetCarrierId()).Times(AtLeast(1));
SetCarrierFirmwareInfo(modem.get(), FirmwareDirectory::kGenericCarrierId,
kGenericCarrierFirmware1Version);
EXPECT_CALL(*modem, FlashFirmwares(carrier_cfg)).WillOnce(Return(true));
modem_flasher_->TryFlash(modem.get());
}
TEST_F(ModemFlasherTest, SkipSameGenericFirmware) {
base::FilePath generic_firmware(kGenericCarrierFirmware1Path);
AddCarrierFirmwareFile(kDeviceId1, FirmwareDirectory::kGenericCarrierId,
generic_firmware, kGenericCarrierFirmware1Version);
auto modem = GetDefaultModem();
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetCarrierId()).Times(AtLeast(1));
SetCarrierFirmwareInfo(modem.get(), FirmwareDirectory::kGenericCarrierId,
kGenericCarrierFirmware1Version);
EXPECT_CALL(*modem, FlashFirmwares(_)).Times(0);
modem_flasher_->TryFlash(modem.get());
}
TEST_F(ModemFlasherTest, TwoCarriersUsingGenericFirmware) {
base::FilePath generic_firmware(kGenericCarrierFirmware1Path);
AddCarrierFirmwareFile(kDeviceId1, FirmwareDirectory::kGenericCarrierId,
generic_firmware, kGenericCarrierFirmware1Version);
auto modem = GetDefaultModem();
std::vector<FirmwareConfig> carrier_cfg = {
{kFwCarrier, generic_firmware, kGenericCarrierFirmware1Version}};
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetCarrierId()).Times(AtLeast(1));
EXPECT_CALL(*modem, FlashFirmwares(carrier_cfg)).WillOnce(Return(true));
modem_flasher_->TryFlash(modem.get());
// When we try to flash again and the modem reports a different carrier,
// we should expect that the ModemFlasher refuses to flash the same firmware,
// since there is generic firmware and no carrier has its own firmware.
modem = GetDefaultModem();
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetCarrierId()).Times(AtLeast(1));
SetCarrierFirmwareInfo(modem.get(), FirmwareDirectory::kGenericCarrierId,
kGenericCarrierFirmware1Version);
EXPECT_CALL(*modem, FlashFirmwares(_)).Times(0);
modem_flasher_->TryFlash(modem.get());
}
TEST_F(ModemFlasherTest, HotSwapWithGenericFirmware) {
base::FilePath original_firmware(kGenericCarrierFirmware1Path);
base::FilePath other_firmware(kCarrier2Firmware1Path);
AddCarrierFirmwareFile(kDeviceId1, FirmwareDirectory::kGenericCarrierId,
original_firmware, kGenericCarrierFirmware1Version);
AddCarrierFirmwareFile(kDeviceId1, kCarrier2, other_firmware,
kCarrier2Firmware1Version);
// Even though there is generic firmware, we should try to use specific
// ones first if they exist.
auto modem = GetDefaultModem();
std::vector<FirmwareConfig> carrier_other_cfg = {
{kFwCarrier, other_firmware, kCarrier2Firmware1Version}};
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetCarrierId())
.Times(AtLeast(1))
.WillRepeatedly(Return(kCarrier2));
SetCarrierFirmwareInfo(modem.get(), FirmwareDirectory::kGenericCarrierId,
kGenericCarrierFirmware1Version);
EXPECT_CALL(*modem, FlashFirmwares(carrier_other_cfg)).WillOnce(Return(true));
modem_flasher_->TryFlash(modem.get());
// Reboot the modem.
SetCarrierFirmwareInfo(modem.get(), kCarrier2, kCarrier2Firmware1Version);
EXPECT_CALL(*modem, FlashFirmwares(_)).Times(0);
modem_flasher_->TryFlash(modem.get());
// Suppose we swap the SIM back to the first one. Then we should try to
// flash the generic firmware again.
modem = GetDefaultModem();
std::vector<FirmwareConfig> carrier_orig_cfg = {
{kFwCarrier, original_firmware, kGenericCarrierFirmware1Version}};
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetCarrierId()).Times(AtLeast(1));
SetCarrierFirmwareInfo(modem.get(), kCarrier2, kCarrier2Firmware1Version);
EXPECT_CALL(*modem, FlashFirmwares(carrier_orig_cfg)).WillOnce(Return(true));
modem_flasher_->TryFlash(modem.get());
}
TEST_F(ModemFlasherTest, WritesToJournal) {
base::FilePath new_firmware(kMainFirmware2Path);
AddMainFirmwareFile(kDeviceId1, new_firmware, kMainFirmware2Version);
auto modem = GetDefaultModem();
std::vector<FirmwareConfig> main_cfg = {
{kFwMain, new_firmware, kMainFirmware2Version}};
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetMainFirmwareVersion()).Times(AtLeast(1));
EXPECT_CALL(*modem, FlashFirmwares(main_cfg)).WillOnce(Return(true));
EXPECT_CALL(*journal_, MarkStartOfFlashingFirmware(only_main_, kDeviceId1, _))
.Times(1);
EXPECT_CALL(*journal_, MarkEndOfFlashingFirmware(kDeviceId1, _)).Times(1);
base::OnceClosure cb = modem_flasher_->TryFlash(modem.get());
// The cleanup callback marks the end of flashing the firmware.
ASSERT_FALSE(cb.is_null());
std::move(cb).Run();
}
TEST_F(ModemFlasherTest, WritesToJournalOnFailure) {
base::FilePath new_firmware(kMainFirmware2Path);
AddMainFirmwareFile(kDeviceId1, new_firmware, kMainFirmware2Version);
auto modem = GetDefaultModem();
std::vector<FirmwareConfig> main_cfg = {
{kFwMain, new_firmware, kMainFirmware2Version}};
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetMainFirmwareVersion()).Times(AtLeast(1));
EXPECT_CALL(*modem, FlashFirmwares(main_cfg)).WillOnce(Return(false));
EXPECT_CALL(*journal_, MarkStartOfFlashingFirmware(only_main_, kDeviceId1, _))
.Times(1);
EXPECT_CALL(*journal_, MarkEndOfFlashingFirmware(kDeviceId1, _)).Times(1);
// There should be no journal cleanup after the flashing fails.
base::OnceClosure cb = modem_flasher_->TryFlash(modem.get());
ASSERT_TRUE(cb.is_null());
}
TEST_F(ModemFlasherTest, WritesCarrierSwitchesToJournal) {
base::FilePath original_firmware(kCarrier1Firmware1Path);
base::FilePath other_firmware(kCarrier2Firmware1Path);
AddCarrierFirmwareFile(kDeviceId1, kCarrier1, original_firmware,
kCarrier1Firmware1Version);
AddCarrierFirmwareFile(kDeviceId1, kCarrier2, other_firmware,
kCarrier2Firmware1Version);
auto modem = GetDefaultModem();
std::vector<FirmwareConfig> carrier_other_cfg = {
{kFwCarrier, other_firmware, kCarrier2Firmware1Version}};
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetCarrierId())
.Times(AtLeast(1))
.WillRepeatedly(Return(kCarrier2));
SetCarrierFirmwareInfo(modem.get(), kCarrier1, kCarrier1Firmware1Version);
EXPECT_CALL(*modem, FlashFirmwares(carrier_other_cfg)).WillOnce(Return(true));
EXPECT_CALL(*journal_,
MarkStartOfFlashingFirmware(only_carrier_, kDeviceId1, kCarrier2))
.Times(1);
EXPECT_CALL(*journal_, MarkEndOfFlashingFirmware(kDeviceId1, kCarrier2))
.Times(1);
base::OnceClosure cb = modem_flasher_->TryFlash(modem.get());
ASSERT_FALSE(cb.is_null());
std::move(cb).Run();
// After the modem reboots, the helper hopefully reports the new carrier.
SetCarrierFirmwareInfo(modem.get(), kCarrier2, kCarrier2Firmware1Version);
EXPECT_CALL(*modem, FlashFirmwares(_)).Times(0);
cb = modem_flasher_->TryFlash(modem.get());
ASSERT_TRUE(cb.is_null());
// Suppose we swap the SIM back to the first one. Then we should try to
// flash the first firmware again.
modem = GetDefaultModem();
std::vector<FirmwareConfig> carrier_orig_cfg = {
{kFwCarrier, original_firmware, kCarrier1Firmware1Version}};
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetCarrierId()).Times(AtLeast(1));
SetCarrierFirmwareInfo(modem.get(), kCarrier2, kCarrier2Firmware1Version);
EXPECT_CALL(*modem, FlashFirmwares(carrier_orig_cfg)).WillOnce(Return(true));
EXPECT_CALL(*journal_,
MarkStartOfFlashingFirmware(only_carrier_, kDeviceId1, kCarrier1))
.Times(1);
EXPECT_CALL(*journal_, MarkEndOfFlashingFirmware(kDeviceId1, kCarrier1))
.Times(1);
cb = modem_flasher_->TryFlash(modem.get());
ASSERT_FALSE(cb.is_null());
std::move(cb).Run();
}
TEST_F(ModemFlasherTest, CarrierSwitchingMainFirmware) {
base::FilePath original_main(kMainFirmware1Path);
AddMainFirmwareFile(kDeviceId1, original_main, kMainFirmware1Version);
base::FilePath other_main(kMainFirmware2Path);
AddMainFirmwareFileForCarrier(kDeviceId1, kCarrier2, other_main,
kMainFirmware2Version);
base::FilePath original_oem(kOemFirmware1Path);
AddOemFirmwareFile(kDeviceId1, original_oem, kOemFirmware1Version);
base::FilePath other_oem(kOemFirmware2Path);
AddOemFirmwareFileForCarrier(kDeviceId1, kCarrier2, other_oem,
kOemFirmware2Version);
base::FilePath original_carrier(kCarrier1Firmware1Path);
base::FilePath other_carrier(kCarrier2Firmware1Path);
AddCarrierFirmwareFile(kDeviceId1, kCarrier1, original_carrier,
kCarrier1Firmware1Version);
AddCarrierFirmwareFile(kDeviceId1, kCarrier2, other_carrier,
kCarrier2Firmware1Version);
auto modem = GetDefaultModem();
std::vector<FirmwareConfig> other_cfg = {
{kFwMain, other_main, kMainFirmware2Version},
{kFwOem, other_oem, kOemFirmware2Version},
{kFwCarrier, other_carrier, kCarrier2Firmware1Version}};
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetCarrierId())
.Times(AtLeast(1))
.WillRepeatedly(Return(kCarrier2));
SetCarrierFirmwareInfo(modem.get(), kCarrier1, kCarrier1Firmware1Version);
EXPECT_CALL(*modem, FlashFirmwares(other_cfg)).WillOnce(Return(true));
modem_flasher_->TryFlash(modem.get());
// Switch the carrier back and make sure we flash all firmware blobs
// again.
modem = GetDefaultModem();
std::vector<FirmwareConfig> orig_cfg = {
{kFwMain, original_main, kMainFirmware1Version},
{kFwOem, original_oem, kOemFirmware1Version},
{kFwCarrier, original_carrier, kCarrier1Firmware1Version}};
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetMainFirmwareVersion())
.Times(AtLeast(1))
.WillRepeatedly(Return(kMainFirmware2Version));
EXPECT_CALL(*modem, GetOemFirmwareVersion())
.Times(AtLeast(1))
.WillRepeatedly(Return(kOemFirmware2Version));
EXPECT_CALL(*modem, GetCarrierId())
.Times(AtLeast(1))
.WillRepeatedly(Return(kCarrier1));
SetCarrierFirmwareInfo(modem.get(), kCarrier2, kCarrier2Firmware1Version);
EXPECT_CALL(*modem, FlashFirmwares(orig_cfg)).WillOnce(Return(true));
modem_flasher_->TryFlash(modem.get());
}
TEST_F(ModemFlasherTest, InhibitDuringMainFirmwareFlash) {
base::FilePath new_firmware(kMainFirmware2Path);
AddMainFirmwareFile(kDeviceId1, new_firmware, kMainFirmware2Version);
auto modem = GetDefaultModem();
std::vector<FirmwareConfig> main_cfg = {
{kFwMain, new_firmware, kMainFirmware2Version}};
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetMainFirmwareVersion()).Times(AtLeast(1));
EXPECT_CALL(*modem, FlashFirmwares(main_cfg)).WillOnce(Return(true));
EXPECT_CALL(*modem, SetInhibited(true)).WillOnce(Return(true));
EXPECT_CALL(*modem, SetInhibited(false)).WillOnce(Return(true));
modem_flasher_->TryFlash(modem.get());
}
TEST_F(ModemFlasherTest, InhibitDuringCarrierFirmwareFlash) {
base::FilePath new_firmware(kCarrier1Firmware2Path);
AddCarrierFirmwareFile(kDeviceId1, kCarrier1, new_firmware,
kCarrier1Firmware2Version);
auto modem = GetDefaultModem();
std::vector<FirmwareConfig> carrier_cfg = {
{kFwCarrier, new_firmware, kCarrier1Firmware2Version}};
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
SetCarrierFirmwareInfo(modem.get(), kCarrier1, kCarrier1Firmware1Version);
EXPECT_CALL(*modem, FlashFirmwares(carrier_cfg)).WillOnce(Return(true));
EXPECT_CALL(*modem, SetInhibited(true)).WillOnce(Return(true));
EXPECT_CALL(*modem, SetInhibited(false)).WillOnce(Return(true));
modem_flasher_->TryFlash(modem.get());
}
TEST_F(ModemFlasherTest, SkipCarrierWithTwoUuidSameFirmware) {
base::FilePath current_firmware(kCarrier1Firmware1Path);
AddCarrierFirmwareFile(kDeviceId1, kCarrier1, current_firmware,
kCarrier1Firmware2Version);
AddCarrierFirmwareFile(kDeviceId1, kCarrier1Mvno, current_firmware,
kCarrier1Firmware2Version);
auto modem = GetDefaultModem();
EXPECT_CALL(*modem, GetDeviceId()).Times(AtLeast(1));
EXPECT_CALL(*modem, GetCarrierFirmwareVersion()).Times(AtLeast(1));
// The modem will say that the currently flashed firmware has the carrier UUID
// KCarrier1Mvno while the current carrier UUID is always returned as
// kCarrier1.
SetCarrierFirmwareInfo(modem.get(), kCarrier1Mvno, kCarrier1Firmware2Version);
EXPECT_CALL(*modem, FlashFirmwares(_)).Times(0);
modem_flasher_->TryFlash(modem.get());
}
} // namespace modemfwd