blob: 35da0d09a5d8b3b552da5ec9c65dc254e6b1270b [file] [log] [blame]
// Copyright (c) 2012 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.
// Unit tests for CgptManager class.
#include <string>
#include "../cgpt/CgptManager.h"
// We use some specific GUID constants for some of the tests,
// so pulling in cgpt.h. Make sure this is included after
// CgptManager.h so that we can test the actual usage of
// CgptManager.h as the post-install package would use.
// Example: this would catch an incorrect usage of a GUID
// that's defined only in cgpt.h and being accidentally
// used in CgptManager.h (which should not have any cgpt.h
// dependencies).
extern "C" {
#include "../cgpt/cgpt.h"
}
#include <base/logging.h>
#include <gflags/gflags.h>
#include <gtest/gtest.h>
#include <uuid/uuid.h>
using std::string;
static const Guid p2guid = {{{0, 1, 2, 3, 4, {2, 2, 2, 2, 2, 2}}}};
static const Guid p3guid = {{{0, 6, 5, 4, 2, {3, 3, 3, 3, 3, 3}}}};
#define EXPECT_SUCCESS(c) EXPECT_EQ(kCgptSuccess, c)
// The --v flag controls the log verbosity level.
DEFINE_int32(v, 0, 0);
// This class unit tests the CgptManager class.
class CgptManagerUnitTest : public ::testing::Test {
public:
CgptManagerUnitTest() {
// Even though the post-installer doesn't use any methods that require
// uuid_generate, for the unit test we use those methods, so we need to
// set the uuid_generator.
uuid_generator = uuid_generate;
}
void SetUp() {
const string device_name = "/tmp/DummyFileForCgptManagerTests.bin";
CreateDummyDevice(device_name);
LOG(INFO) << "Initializing cgpt with " << device_name;
EXPECT_SUCCESS(cgpt_manager.Initialize(device_name));
EXPECT_SUCCESS(cgpt_manager.ClearAll());
CheckPartitionCount(0);
}
virtual ~CgptManagerUnitTest() { }
protected:
CgptManager cgpt_manager;
void CreateDummyDevice(const string& dummy_device) {
FILE* fp = fopen(dummy_device.c_str(), "w");
ASSERT_TRUE(fp != NULL);
const int kNumSectors = 1000;
const int kSectorSize = 512;
const char kFillChar = '7'; // Some character, value doesn't matter.
for(int i = 0; i < kNumSectors * kSectorSize; i++) {
EXPECT_EQ(kFillChar, fputc(kFillChar, fp));
}
fclose(fp);
}
void CheckEquality(string field,
uint64_t expected,
uint64_t actual) {
VLOG(1) << field << ":"
<< "Expected = " << expected
<< ";Actual = " << actual;
EXPECT_EQ(expected, actual);
}
void CheckGuidEquality(string field,
const Guid& expected_id,
const Guid& actual_id) {
char expected_id_str[GUID_STRLEN];
GuidToStr(&expected_id, expected_id_str, sizeof(expected_id_str));
char actual_id_str[GUID_STRLEN];
GuidToStr(&actual_id, actual_id_str, sizeof(actual_id_str));
VLOG(1) << field << ":"
<< "Expected = " << expected_id_str
<< ";Actual = " << actual_id_str;
EXPECT_TRUE(GuidEqual(&expected_id, &actual_id));
}
// Checks if the current number of partitions in the device matches
// the value of expected_num_partitions.
void CheckPartitionCount(uint8 expected_num_partitions) {
uint8_t actual_num_partitions;
EXPECT_SUCCESS(cgpt_manager.GetNumNonEmptyPartitions(
&actual_num_partitions));
CheckEquality("NumPartitions",
expected_num_partitions,
actual_num_partitions);
}
void SetAndCheckSuccessfulBit(uint32_t partition_number,
bool expected_is_successful) {
EXPECT_SUCCESS(cgpt_manager.SetSuccessful(partition_number,
expected_is_successful));
bool actual_is_successful;
EXPECT_SUCCESS(cgpt_manager.GetSuccessful(partition_number,
&actual_is_successful));
EXPECT_EQ(expected_is_successful, actual_is_successful);
}
void SetAndCheckNumTriesLeft(uint32_t partition_number,
int expected_num_tries) {
EXPECT_SUCCESS(cgpt_manager.SetNumTriesLeft(partition_number,
expected_num_tries));
int actual_num_tries;
EXPECT_SUCCESS(cgpt_manager.GetNumTriesLeft(partition_number,
&actual_num_tries));
CheckEquality("NumTries", expected_num_tries, actual_num_tries);
}
void SetAndCheckPriority(uint32_t partition_number,
uint8_t expected_priority) {
EXPECT_SUCCESS(cgpt_manager.SetPriority(partition_number,
expected_priority));
uint8_t actual_priority;
EXPECT_SUCCESS(cgpt_manager.GetPriority(partition_number,
&actual_priority));
CheckEquality("Priority", expected_priority, actual_priority);
}
void CheckPriority(uint32_t partition_number,
uint8_t expected_priority) {
uint8_t actual_priority;
EXPECT_SUCCESS(cgpt_manager.GetPriority(partition_number,
&actual_priority));
CheckEquality("Priority", expected_priority, actual_priority);
}
void CheckBeginningOffset(uint32_t partition_number,
uint64_t expected_offset) {
uint64_t actual_offset;
EXPECT_SUCCESS(cgpt_manager.GetBeginningOffset(partition_number,
&actual_offset));
CheckEquality("Beginning Offset", expected_offset, actual_offset);
}
void CheckNumSectors(uint32_t partition_number,
uint64_t expected_num_sectors) {
uint64_t actual_num_sectors;
EXPECT_SUCCESS(cgpt_manager.GetNumSectors(partition_number,
&actual_num_sectors));
CheckEquality("Num Sectors", expected_num_sectors, actual_num_sectors);
}
void CheckPartitionTypeId(int partition_number,
const Guid& expected_partition_type_id) {
// Get the partition type id and check if it matches the expected value.
Guid actual_partition_type_id;
EXPECT_SUCCESS(cgpt_manager.GetPartitionTypeId(partition_number,
&actual_partition_type_id));
CheckGuidEquality("PartitionTypeId",
expected_partition_type_id,
actual_partition_type_id);
}
void CheckPartitionUniqueId(int partition_number,
const Guid& expected_partition_unique_id) {
// Get the partition unique id and check if it matches the expected value.
Guid actual_partition_unique_id;
EXPECT_SUCCESS(cgpt_manager.GetPartitionUniqueId(
partition_number,
&actual_partition_unique_id));
CheckGuidEquality("PartitionUniqueId",
expected_partition_unique_id,
actual_partition_unique_id);
}
void CheckPartitionNumberByUniqueId(const Guid& unique_id,
uint32_t expected_partition_number) {
// Get the partition number for the unique id and check
// if it matches the expected value.
uint32_t actual_partition_number;
EXPECT_SUCCESS(cgpt_manager.GetPartitionNumberByUniqueId(
unique_id,
&actual_partition_number));
CheckEquality("PartitionNumberForUniqueId",
expected_partition_number,
actual_partition_number);
}
void CreateBootFile(const string& boot_file_name) {
FILE* fp = fopen(boot_file_name.c_str(), "w");
ASSERT_TRUE(fp != NULL);
const int kNumSectors = 1;
const int kSectorSize = 512;
const char kFillChar = '8'; // Some character, value doesn't matter.
for(int i = 0; i < kNumSectors * kSectorSize; i++) {
EXPECT_EQ(kFillChar, fputc(kFillChar, fp));
}
fclose(fp);
}
private:
DISALLOW_COPY_AND_ASSIGN(CgptManagerUnitTest);
};
TEST_F(CgptManagerUnitTest, AutoPrioritizationTest) {
EXPECT_SUCCESS(cgpt_manager.AddPartition("k1",
guid_chromeos_kernel,
guid_unused,
100,
10));
CheckPartitionCount(1);
EXPECT_SUCCESS(cgpt_manager.AddPartition("k2",
guid_chromeos_kernel,
p2guid,
200,
20));
CheckPartitionCount(2);
EXPECT_SUCCESS(cgpt_manager.AddPartition("k3",
guid_chromeos_kernel,
p3guid,
300,
30));
CheckPartitionCount(3);
uint8_t expectedk1Priority = 1;
uint8_t expectedk2Priority = 2;
uint8_t expectedk3Priority = 0;
// Calling SetAndCheckPriority will do a set and get of the above priorities.
SetAndCheckPriority(1, expectedk1Priority);
SetAndCheckPriority(2, expectedk2Priority);
SetAndCheckPriority(3, expectedk3Priority);
EXPECT_SUCCESS(cgpt_manager.SetHighestPriority(1));
expectedk1Priority = 2;
expectedk2Priority = 1;
CheckPriority(1, expectedk1Priority);
CheckPriority(2, expectedk2Priority);
CheckPriority(3, expectedk3Priority);
}
TEST_F(CgptManagerUnitTest, AddPartitionTest) {
int p2_offset = 200;
int p2_size = 20;
int p3_offset = 300;
int p3_size = 30;
VLOG(1) << "Adding various types of partitions ... ";
EXPECT_SUCCESS(cgpt_manager.AddPartition("data stuff",
guid_linux_data,
guid_unused,
100,
10));
CheckPartitionCount(1);
EXPECT_SUCCESS(cgpt_manager.AddPartition("kernel stuff",
guid_chromeos_kernel,
p2guid,
p2_offset,
p2_size));
CheckPartitionCount(2);
EXPECT_SUCCESS(cgpt_manager.AddPartition("rootfs stuff",
guid_chromeos_rootfs,
p3guid,
p3_offset,
p3_size));
CheckPartitionCount(3);
uint32_t pmbr_boot_partition_number = 4;
EXPECT_SUCCESS(cgpt_manager.AddPartition("ESP stuff",
guid_efi,
guid_unused,
400,
40));
CheckPartitionCount(4);
EXPECT_SUCCESS(cgpt_manager.AddPartition("fture stuff",
guid_chromeos_reserved,
guid_unused,
500,
50));
CheckPartitionCount(5);
Guid guid_random = {{{0x2364a860, 0xbf63, 0x42fb, 0xa8, 0x3d,
{0x9a, 0xd3, 0xe0, 0x57, 0xfc, 0xf5}}}};
EXPECT_SUCCESS(cgpt_manager.AddPartition("random stuff",
guid_random,
guid_unused,
600,
60));
CheckPartitionCount(6);
string boot_file_name = "/tmp/BootFileForCgptManagerTests.bin";
LOG(INFO) << "Adding EFI partition to PMBR with bootfile: "
<< boot_file_name;
CreateBootFile(boot_file_name);
EXPECT_SUCCESS(cgpt_manager.SetPmbr(pmbr_boot_partition_number,
boot_file_name,
true));
VLOG(1) << "Checking if contents of GPT match values set in AddPartition.";
uint32_t actual_boot_partition_number;
EXPECT_SUCCESS(cgpt_manager.GetPmbrBootPartitionNumber(
&actual_boot_partition_number));
EXPECT_EQ(pmbr_boot_partition_number, actual_boot_partition_number);
// Set the successful attribute for some partition to various Values
// and check if the settings are preserved.
SetAndCheckSuccessfulBit(2, true);
SetAndCheckSuccessfulBit(2, false);
// Set the number of tries for some partition to various Values
// and check if the settings are preserved.
SetAndCheckNumTriesLeft(2, 6);
SetAndCheckNumTriesLeft(2, 5);
// Set the priority for some partition to various Values
// and check if the settings are preserved.
SetAndCheckPriority(2, 2);
SetAndCheckPriority(2, 0);
// Check if the beginning offset for some of the partitions
// are the same as what was set in AddPartition.
CheckBeginningOffset(2, p2_offset);
CheckBeginningOffset(3, p3_offset);
// Check if the number of sectors for some of the partitions
// are same as what was set in AddPartition.
CheckNumSectors(2, p2_size);
CheckNumSectors(3, p3_size);
// Check if the partition type IDs for some of the partitions
// are same as what was set in AddPartition.
CheckPartitionTypeId(2, guid_chromeos_kernel);
CheckPartitionTypeId(4, guid_efi);
// Check if the partition unique IDs for some of the partitions
// same as what was set in AddPartition.
CheckPartitionUniqueId(2, p2guid);
CheckPartitionUniqueId(3, p3guid);
// Check if the partition numbers for some of the partitions are
// retrievable by their unique IDs set in AddPartition.
CheckPartitionNumberByUniqueId(p2guid, 2);
CheckPartitionNumberByUniqueId(p3guid, 3);
}
int main(int argc, char **argv) {
google::ParseCommandLineFlags(&argc, &argv, true);
::testing::InitGoogleTest(&argc, argv);
// VLOG(2) logs at level -2. So if user gives --v=2, we should
// set MinLogLevel to -2, so VLOG(2) and VLOG(1) will show up.
logging::SetMinLogLevel(-FLAGS_v);
return RUN_ALL_TESTS();
}