blob: 26a80c1adfde4ac1144a4a20ff39ee2730c51a9f [file] [log] [blame]
// Copyright 2019 The Fuchsia 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 <lib/fdio/namespace.h>
#include <string>
#include <string_view>
#include "paver-test-common.h"
namespace {
constexpr char kFakeData[] = "lalala";
// Returns a full firmware filename for the given type (no type by default).
std::string FirmwareFilename(const std::string& type = "") {
return NB_FIRMWARE_FILENAME_PREFIX + type;
}
TEST(PaverTest, Constructor) { netsvc::Paver paver({}, {}); }
TEST(PaverTest, GetSingleton) {
int fd = open("/svc", O_DIRECTORY | O_RDWR);
ASSERT_GE(fd, 0);
fdio_ns_t* ns;
ASSERT_OK(fdio_ns_get_installed(&ns));
ASSERT_OK(fdio_ns_bind_fd(ns, "/dev", fd));
ASSERT_NOT_NULL(netsvc::Paver::Get());
ASSERT_OK(fdio_ns_unbind(ns, "/dev"));
}
TEST(PaverTest, InitialInProgressFalse) {
zx::channel chan;
fbl::unique_fd fd;
netsvc::Paver paver_(std::move(chan), std::move(fd));
ASSERT_FALSE(paver_.InProgress());
}
TEST(PaverTest, InitialExitCodeValid) {
zx::channel chan;
fbl::unique_fd fd;
netsvc::Paver paver_(std::move(chan), std::move(fd));
ASSERT_OK(paver_.exit_code());
}
TEST_F(PaverTest, OpenWriteInvalidFile) {
char invalid_file_name[32] = {};
ASSERT_NE(paver_.OpenWrite(invalid_file_name, 0), TFTP_NO_ERROR);
paver_.Close();
}
TEST_F(PaverTest, OpenWriteInvalidSize) {
ASSERT_NE(paver_.OpenWrite(FirmwareFilename(), 0), TFTP_NO_ERROR);
}
TEST_F(PaverTest, OpenWriteValidFile) {
ASSERT_EQ(paver_.OpenWrite(FirmwareFilename(), 1024), TFTP_NO_ERROR);
paver_.Close();
}
TEST_F(PaverTest, OpenTwice) {
ASSERT_EQ(paver_.OpenWrite(FirmwareFilename(), 1024), TFTP_NO_ERROR);
ASSERT_NE(paver_.OpenWrite(FirmwareFilename(), 1024), TFTP_NO_ERROR);
paver_.Close();
}
TEST_F(PaverTest, WriteWithoutOpen) {
size_t size = sizeof(kFakeData);
ASSERT_NE(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
}
TEST_F(PaverTest, WriteAfterClose) {
size_t size = sizeof(kFakeData);
ASSERT_EQ(paver_.OpenWrite(FirmwareFilename(), 1024), TFTP_NO_ERROR);
paver_.Close();
// TODO(surajmalhotra): Should we ensure this fails?
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
}
TEST_F(PaverTest, TimeoutNoWrites) {
ASSERT_EQ(paver_.OpenWrite(FirmwareFilename(), 1024), TFTP_NO_ERROR);
paver_.Close();
Wait();
ASSERT_NE(paver_.exit_code(), ZX_OK);
}
TEST_F(PaverTest, TimeoutPartialWrite) {
size_t size = sizeof(kFakeData);
ASSERT_EQ(paver_.OpenWrite(FirmwareFilename(), 1024), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
paver_.Close();
Wait();
ASSERT_NE(paver_.exit_code(), ZX_OK);
}
void ValidateCommandTrace(const std::vector<Command>& actual,
const std::vector<Command>& expected) {
ASSERT_EQ(actual.size(), expected.size());
for (size_t i = 0; i < actual.size(); i++) {
EXPECT_EQ(actual[i], expected[i], "Command #%zu different from expected", i);
}
}
void ValidateLastCommandTrace(const std::vector<Command>& actual,
const std::vector<Command>& expected) {
ASSERT_GE(actual.size(), expected.size());
for (size_t i = 0; i < expected.size(); i++) {
EXPECT_EQ(actual[actual.size() - expected.size() + i], expected[i],
"Command #%zu different from expected", i);
}
}
TEST_F(PaverTest, WriteCompleteSingle) {
size_t size = sizeof(kFakeData);
fake_svc_.fake_paver().set_expected_payload_size(size);
ASSERT_EQ(paver_.OpenWrite(FirmwareFilename(), size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
paver_.Close();
Wait();
ASSERT_OK(paver_.exit_code());
ValidateCommandTrace(fake_svc_.fake_paver().GetCommandTrace(),
{Command::kInitializeAbr, Command::kWriteFirmware});
}
TEST_F(PaverTest, WriteCompleteManySmallWrites) {
size_t size = sizeof(kFakeData);
fake_svc_.fake_paver().set_expected_payload_size(1024);
ASSERT_EQ(paver_.OpenWrite(FirmwareFilename(), 1024), TFTP_NO_ERROR);
for (size_t offset = 0; offset < 1024; offset += sizeof(kFakeData)) {
size = std::min(sizeof(kFakeData), 1024 - offset);
ASSERT_EQ(paver_.Write(kFakeData, &size, offset), TFTP_NO_ERROR);
ASSERT_EQ(size, std::min(sizeof(kFakeData), 1024 - offset));
}
paver_.Close();
Wait();
ASSERT_OK(paver_.exit_code());
}
TEST_F(PaverTest, Overwrite) {
size_t size = sizeof(kFakeData);
ASSERT_EQ(paver_.OpenWrite(FirmwareFilename(), 2), TFTP_NO_ERROR);
ASSERT_NE(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
paver_.Close();
Wait();
ASSERT_NE(paver_.exit_code(), ZX_OK);
}
TEST_F(PaverTest, CloseChannelBetweenWrites) {
size_t size = sizeof(kFakeData);
fake_svc_.fake_paver().set_expected_payload_size(2 * size);
ASSERT_EQ(paver_.OpenWrite(FirmwareFilename(), 2 * size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
loop_.Shutdown();
ASSERT_EQ(paver_.Write(kFakeData, &size, size), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
paver_.Close();
Wait();
ASSERT_EQ(paver_.exit_code(), ZX_ERR_PEER_CLOSED);
}
TEST_F(PaverTest, WriteFirmwareA) {
size_t size = sizeof(kFakeData);
const char* file_name = NB_IMAGE_PREFIX NB_FIRMWAREA_HOST_FILENAME_PREFIX "tpl";
fake_svc_.fake_paver().set_expected_payload_size(size);
ASSERT_EQ(paver_.OpenWrite(file_name, size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
paver_.Close();
Wait();
ASSERT_OK(paver_.exit_code());
ValidateCommandTrace(fake_svc_.fake_paver().GetCommandTrace(),
{Command::kInitializeAbr, Command::kWriteFirmware});
}
TEST_F(PaverTest, WriteZirconA) {
size_t size = sizeof(kFakeData);
fake_svc_.fake_paver().set_expected_payload_size(size);
ASSERT_EQ(paver_.OpenWrite(NB_ZIRCONA_FILENAME, size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
paver_.Close();
Wait();
ASSERT_OK(paver_.exit_code());
ValidateCommandTrace(fake_svc_.fake_paver().GetCommandTrace(),
{Command::kInitializeAbr, Command::kWriteAsset});
}
TEST_F(PaverTest, WriteVbMetaA) {
size_t size = sizeof(kFakeData);
fake_svc_.fake_paver().set_expected_payload_size(size);
ASSERT_EQ(paver_.OpenWrite(NB_VBMETAA_FILENAME, size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
paver_.Close();
Wait();
ASSERT_OK(paver_.exit_code());
ValidateCommandTrace(fake_svc_.fake_paver().GetCommandTrace(),
{Command::kInitializeAbr, Command::kWriteAsset});
}
TEST_F(PaverTest, WriteFirmwareABWithABRSupported) {
fake_svc_.fake_paver().set_supported_firmware_type("tpl");
const char* file_names[] = {
NB_IMAGE_PREFIX NB_FIRMWAREA_HOST_FILENAME_PREFIX "tpl",
NB_IMAGE_PREFIX NB_FIRMWAREB_HOST_FILENAME_PREFIX "tpl",
};
size_t size = sizeof(kFakeData);
for (auto file_name : file_names) {
fake_svc_.fake_paver().set_abr_supported(true);
fake_svc_.fake_paver().set_expected_payload_size(size);
ASSERT_EQ(paver_.OpenWrite(file_name, size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
paver_.Close();
Wait();
ASSERT_OK(paver_.exit_code());
ValidateLastCommandTrace(fake_svc_.fake_paver().GetCommandTrace(),
{
Command::kInitializeAbr,
Command::kQueryActiveConfiguration,
Command::kSetConfigurationUnbootable,
Command::kWriteFirmware,
Command::kBootManagerFlush,
});
}
}
TEST_F(PaverTest, WriteFirmwareRWithABRSupported) {
fake_svc_.fake_paver().set_supported_firmware_type("tpl");
const char* file_name = NB_IMAGE_PREFIX NB_FIRMWARER_HOST_FILENAME_PREFIX "tpl";
size_t size = sizeof(kFakeData);
fake_svc_.fake_paver().set_abr_supported(true);
fake_svc_.fake_paver().set_expected_payload_size(size);
ASSERT_EQ(paver_.OpenWrite(file_name, size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
paver_.Close();
Wait();
ASSERT_OK(paver_.exit_code());
ValidateLastCommandTrace(fake_svc_.fake_paver().GetCommandTrace(),
{
Command::kInitializeAbr,
Command::kQueryActiveConfiguration,
Command::kWriteFirmware,
Command::kBootManagerFlush,
});
}
TEST_F(PaverTest, WriteZirconAWithABRSupported) {
size_t size = sizeof(kFakeData);
fake_svc_.fake_paver().set_abr_supported(true);
fake_svc_.fake_paver().set_expected_payload_size(size);
ASSERT_EQ(paver_.OpenWrite(NB_ZIRCONA_FILENAME, size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
paver_.Close();
Wait();
ASSERT_OK(paver_.exit_code());
ValidateCommandTrace(fake_svc_.fake_paver().GetCommandTrace(),
{
Command::kInitializeAbr,
Command::kQueryActiveConfiguration,
Command::kSetConfigurationUnbootable,
Command::kWriteAsset,
Command::kBootManagerFlush,
});
}
TEST_F(PaverTest, WriteZirconBWithABRSupported) {
size_t size = sizeof(kFakeData);
fake_svc_.fake_paver().set_abr_supported(true);
fake_svc_.fake_paver().set_expected_payload_size(size);
ASSERT_EQ(paver_.OpenWrite(NB_ZIRCONB_FILENAME, size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
paver_.Close();
Wait();
ASSERT_OK(paver_.exit_code());
ValidateCommandTrace(fake_svc_.fake_paver().GetCommandTrace(),
{
Command::kInitializeAbr,
Command::kQueryActiveConfiguration,
Command::kSetConfigurationUnbootable,
Command::kWriteAsset,
Command::kBootManagerFlush,
});
}
TEST_F(PaverTest, WriteZirconRWithABRSupported) {
size_t size = sizeof(kFakeData);
fake_svc_.fake_paver().set_abr_supported(true);
fake_svc_.fake_paver().set_expected_payload_size(size);
ASSERT_EQ(paver_.OpenWrite(NB_ZIRCONR_FILENAME, size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
paver_.Close();
Wait();
ASSERT_OK(paver_.exit_code());
ValidateCommandTrace(fake_svc_.fake_paver().GetCommandTrace(),
{
Command::kInitializeAbr,
Command::kQueryActiveConfiguration,
Command::kWriteAsset,
Command::kBootManagerFlush,
});
}
TEST_F(PaverTest, WriteVbMetaAWithABRSupported) {
size_t size = sizeof(kFakeData);
fake_svc_.fake_paver().set_abr_supported(true);
fake_svc_.fake_paver().set_expected_payload_size(size);
ASSERT_EQ(paver_.OpenWrite(NB_VBMETAA_FILENAME, size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
paver_.Close();
Wait();
ASSERT_OK(paver_.exit_code());
ValidateCommandTrace(fake_svc_.fake_paver().GetCommandTrace(),
{
Command::kInitializeAbr,
Command::kQueryActiveConfiguration,
Command::kSetConfigurationUnbootable,
Command::kWriteAsset,
Command::kSetConfigurationActive,
Command::kSetConfigurationUnbootable,
Command::kDataSinkFlush,
Command::kBootManagerFlush,
});
ASSERT_FALSE(fake_svc_.fake_paver().abr_data().slot_a.unbootable);
ASSERT_TRUE(fake_svc_.fake_paver().abr_data().slot_a.active);
ASSERT_TRUE(fake_svc_.fake_paver().abr_data().slot_b.unbootable);
}
TEST_F(PaverTest, WriteVbMetaBWithABRSupported) {
size_t size = sizeof(kFakeData);
fake_svc_.fake_paver().set_abr_supported(true);
fake_svc_.fake_paver().set_expected_payload_size(size);
ASSERT_EQ(paver_.OpenWrite(NB_VBMETAB_FILENAME, size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
paver_.Close();
Wait();
ASSERT_OK(paver_.exit_code());
ValidateCommandTrace(fake_svc_.fake_paver().GetCommandTrace(),
{
Command::kInitializeAbr,
Command::kQueryActiveConfiguration,
Command::kSetConfigurationUnbootable,
Command::kWriteAsset,
Command::kSetConfigurationActive,
Command::kSetConfigurationUnbootable,
Command::kDataSinkFlush,
Command::kBootManagerFlush,
});
ASSERT_FALSE(fake_svc_.fake_paver().abr_data().slot_b.unbootable);
ASSERT_TRUE(fake_svc_.fake_paver().abr_data().slot_b.active);
ASSERT_TRUE(fake_svc_.fake_paver().abr_data().slot_a.unbootable);
}
TEST_F(PaverTest, WriteVbMetaRWithABRSupported) {
size_t size = sizeof(kFakeData);
fake_svc_.fake_paver().set_abr_supported(true);
fake_svc_.fake_paver().set_expected_payload_size(size);
ASSERT_EQ(paver_.OpenWrite(NB_VBMETAR_FILENAME, size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
paver_.Close();
Wait();
ASSERT_OK(paver_.exit_code());
ValidateCommandTrace(fake_svc_.fake_paver().GetCommandTrace(),
{
Command::kInitializeAbr,
Command::kQueryActiveConfiguration,
Command::kWriteAsset,
Command::kBootManagerFlush,
});
}
TEST_F(PaverTest, WriteZirconAWithABRSupportedTwice) {
size_t size = sizeof(kFakeData);
fake_svc_.fake_paver().set_abr_supported(true);
fake_svc_.fake_paver().set_expected_payload_size(size);
std::vector<Command> expected_per_time = {
Command::kInitializeAbr,
Command::kQueryActiveConfiguration,
Command::kSetConfigurationUnbootable,
Command::kWriteAsset,
Command::kBootManagerFlush,
};
std::vector<Command> expected_accumulative;
for (int i = 0; i < 2; i++) {
ASSERT_EQ(paver_.OpenWrite(NB_ZIRCONA_FILENAME, size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
paver_.Close();
Wait();
ASSERT_OK(paver_.exit_code());
expected_accumulative.insert(expected_accumulative.end(), expected_per_time.begin(),
expected_per_time.end());
ValidateCommandTrace(fake_svc_.fake_paver().GetCommandTrace(), expected_accumulative);
}
}
TEST_F(PaverTest, WriteSshAuth) {
size_t size = sizeof(kFakeData);
fake_svc_.fake_paver().set_expected_payload_size(size);
ASSERT_EQ(paver_.OpenWrite(NB_SSHAUTH_FILENAME, size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
paver_.Close();
Wait();
ASSERT_OK(paver_.exit_code());
ValidateCommandTrace(fake_svc_.fake_paver().GetCommandTrace(), {Command::kWriteDataFile});
}
TEST_F(PaverTest, WriteFvm) {
size_t size = sizeof(kFakeData);
fake_svc_.fake_paver().set_expected_payload_size(size);
ASSERT_EQ(paver_.OpenWrite(NB_FVM_FILENAME, size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
paver_.Close();
Wait();
ASSERT_OK(paver_.exit_code());
ValidateCommandTrace(fake_svc_.fake_paver().GetCommandTrace(), {Command::kWriteVolumes});
}
TEST_F(PaverTest, WriteFvmManySmallWrites) {
size_t size = sizeof(kFakeData);
fake_svc_.fake_paver().set_expected_payload_size(1024);
ASSERT_EQ(paver_.OpenWrite(NB_FVM_FILENAME, 1024), TFTP_NO_ERROR);
for (size_t offset = 0; offset < 1024; offset += sizeof(kFakeData)) {
size = std::min(sizeof(kFakeData), 1024 - offset);
ASSERT_EQ(paver_.Write(kFakeData, &size, offset), TFTP_NO_ERROR);
ASSERT_EQ(size, std::min(sizeof(kFakeData), 1024 - offset));
}
paver_.Close();
Wait();
ASSERT_OK(paver_.exit_code());
ValidateCommandTrace(fake_svc_.fake_paver().GetCommandTrace(), {Command::kWriteVolumes});
}
TEST_F(PaverTest, InitializePartitionTables) {
ASSERT_NO_FAILURES(SpawnBlockDevice());
modify_partition_table_info partition_info = {};
strcpy(partition_info.block_device_path, "/dev/");
strcat(partition_info.block_device_path, ramdisk_get_path(ramdisk_));
size_t size = sizeof(partition_info);
ASSERT_EQ(paver_.OpenWrite(NB_INIT_PARTITION_TABLES_FILENAME, size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(&partition_info, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(partition_info));
paver_.Close();
Wait();
ASSERT_OK(paver_.exit_code());
ValidateCommandTrace(fake_svc_.fake_paver().GetCommandTrace(), {Command::kInitPartitionTables});
}
TEST_F(PaverTest, WipePartitionTables) {
ASSERT_NO_FAILURES(SpawnBlockDevice());
modify_partition_table_info partition_info = {};
strcpy(partition_info.block_device_path, "/dev/");
strcat(partition_info.block_device_path, ramdisk_get_path(ramdisk_));
size_t size = sizeof(partition_info);
ASSERT_EQ(paver_.OpenWrite(NB_WIPE_PARTITION_TABLES_FILENAME, size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(&partition_info, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(partition_info));
paver_.Close();
Wait();
ASSERT_OK(paver_.exit_code());
ValidateCommandTrace(fake_svc_.fake_paver().GetCommandTrace(), {Command::kWipePartitionTables});
}
TEST_F(PaverTest, WriteFirmwareNoType) {
size_t size = sizeof(kFakeData);
fake_svc_.fake_paver().set_expected_payload_size(size);
ASSERT_EQ(paver_.OpenWrite(FirmwareFilename(), size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
paver_.Close();
Wait();
ASSERT_OK(paver_.exit_code());
ValidateCommandTrace(fake_svc_.fake_paver().GetCommandTrace(),
{Command::kInitializeAbr, Command::kWriteFirmware});
EXPECT_EQ(fake_svc_.fake_paver().last_firmware_type(), "");
}
TEST_F(PaverTest, WriteFirmwareSupportedType) {
size_t size = sizeof(kFakeData);
fake_svc_.fake_paver().set_expected_payload_size(size);
fake_svc_.fake_paver().set_supported_firmware_type("foo");
ASSERT_EQ(paver_.OpenWrite(FirmwareFilename("foo"), size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
paver_.Close();
Wait();
ASSERT_OK(paver_.exit_code());
ValidateCommandTrace(fake_svc_.fake_paver().GetCommandTrace(),
{Command::kInitializeAbr, Command::kWriteFirmware});
EXPECT_EQ(fake_svc_.fake_paver().last_firmware_type(), "foo");
}
TEST_F(PaverTest, WriteFirmwareUnsupportedType) {
size_t size = sizeof(kFakeData);
fake_svc_.fake_paver().set_expected_payload_size(size);
fake_svc_.fake_paver().set_supported_firmware_type("foo");
ASSERT_EQ(paver_.OpenWrite(FirmwareFilename("bar"), size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
paver_.Close();
Wait();
// This should still return OK so that we just skip unknown firmware types.
ASSERT_OK(paver_.exit_code());
ValidateCommandTrace(fake_svc_.fake_paver().GetCommandTrace(),
{Command::kInitializeAbr, Command::kWriteFirmware});
EXPECT_EQ(fake_svc_.fake_paver().last_firmware_type(), "bar");
}
TEST_F(PaverTest, WriteFirmwareFailure) {
// Trigger an error by not writing enough data.
size_t size = sizeof(kFakeData);
fake_svc_.fake_paver().set_expected_payload_size(size + 1);
ASSERT_EQ(paver_.OpenWrite(FirmwareFilename(), size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
paver_.Close();
Wait();
// This should not return OK since an actual error occurred.
ASSERT_NOT_OK(paver_.exit_code());
ValidateCommandTrace(fake_svc_.fake_paver().GetCommandTrace(),
{Command::kInitializeAbr, Command::kWriteFirmware});
}
TEST_F(PaverTest, WriteFirmwareTypeMaxLength) {
const std::string type(NB_FIRMWARE_TYPE_MAX_LENGTH, 'a');
size_t size = sizeof(kFakeData);
fake_svc_.fake_paver().set_expected_payload_size(size);
fake_svc_.fake_paver().set_supported_firmware_type(type);
ASSERT_EQ(paver_.OpenWrite(FirmwareFilename(type), size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
paver_.Close();
Wait();
ASSERT_OK(paver_.exit_code());
ValidateCommandTrace(fake_svc_.fake_paver().GetCommandTrace(),
{Command::kInitializeAbr, Command::kWriteFirmware});
EXPECT_EQ(fake_svc_.fake_paver().last_firmware_type(), type);
}
TEST_F(PaverTest, WriteFirmwareTypeTooLong) {
const std::string type(NB_FIRMWARE_TYPE_MAX_LENGTH + 1, 'a');
size_t size = sizeof(kFakeData);
fake_svc_.fake_paver().set_expected_payload_size(size);
EXPECT_EQ(paver_.OpenWrite(FirmwareFilename(type), size), TFTP_ERR_INVALID_ARGS);
EXPECT_NE(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
paver_.Close();
Wait();
// Make sure the WriteFirmware() call was never made.
ValidateCommandTrace(fake_svc_.fake_paver().GetCommandTrace(), {});
}
TEST_F(PaverTest, BootloaderUsesWriteFirmware) {
size_t size = sizeof(kFakeData);
fake_svc_.fake_paver().set_expected_payload_size(size);
ASSERT_EQ(paver_.OpenWrite(NB_BOOTLOADER_FILENAME, size), TFTP_NO_ERROR);
ASSERT_EQ(paver_.Write(kFakeData, &size, 0), TFTP_NO_ERROR);
ASSERT_EQ(size, sizeof(kFakeData));
paver_.Close();
Wait();
ASSERT_OK(paver_.exit_code());
// Legacy BOOTLOADER file should use WriteFirmare() FIDL with empty type.
ValidateCommandTrace(fake_svc_.fake_paver().GetCommandTrace(),
{Command::kInitializeAbr, Command::kWriteFirmware});
EXPECT_EQ(fake_svc_.fake_paver().last_firmware_type(), "");
}
} // namespace