blob: 0cdc8e27f32a027b7f6404d581af8281a16ba100 [file] [log] [blame]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "minios/log_store_manifest.h"
#include <cstdint>
#include <optional>
#include <string>
#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 <gmock/gmock.h>
#include <gtest/gtest.h>
using ::testing::Optional;
namespace minios {
const uint64_t kPartitionSize = 262144 * kBlockSize;
class LogStoreManifestTest : public testing::Test {
protected:
void SetUp() override { CHECK(scoped_temp_dir_.CreateUniqueTempDir()); }
// Helper function to create files of required size.
base::FilePath CreateFileOfSize(uint64_t size) {
base::FilePath file_path;
auto file = base::CreateAndOpenTemporaryFileInDir(
scoped_temp_dir_.GetPath(), &file_path);
EXPECT_TRUE(file.IsValid());
file.SetLength(size);
return file_path;
}
base::ScopedTempDir scoped_temp_dir_;
};
TEST_F(LogStoreManifestTest, VerifyGenerate) {
auto log_file = CreateFileOfSize(1025);
const uint64_t kernel_size = 2;
const uint64_t log_store_offset = 5;
auto disk_file = CreateFileOfSize(10 * 1024);
LogStoreManifest manifest_store{log_file, disk_file, kernel_size,
kPartitionSize};
EXPECT_TRUE(manifest_store.Generate(log_store_offset));
auto generated_manifest = manifest_store.manifest_;
ASSERT_TRUE(generated_manifest.has_value());
EXPECT_EQ(generated_manifest->entry().count(), 1025);
EXPECT_EQ(generated_manifest->entry().offset(), log_store_offset);
}
TEST_F(LogStoreManifestTest, DisabledWithInvalidArgs) {
// Manifest helper should be disabled if args are erroneos.
const uint64_t kernel_size = 2;
const auto disk_file = CreateFileOfSize(10 * 1024);
// Error: Empty log archive path.
LogStoreManifest empty_log_archive{base::FilePath{""}, disk_file, kernel_size,
kPartitionSize};
EXPECT_FALSE(empty_log_archive.IsValid());
EXPECT_FALSE(empty_log_archive.Generate(10));
EXPECT_FALSE(empty_log_archive.Write());
EXPECT_EQ(empty_log_archive.Retreive(), std::nullopt);
LogStoreManifest empty_disk_path{base::FilePath{"log"}, base::FilePath{""},
kernel_size, kPartitionSize};
EXPECT_FALSE(empty_disk_path.IsValid());
// Manifest store within kernel block
LogStoreManifest manifest_in_kernel{base::FilePath{"log"}, disk_file,
kBlockSize + 1, 3 * kBlockSize};
EXPECT_FALSE(manifest_in_kernel.IsValid());
// Unaligned partition sizes are not supported.
LogStoreManifest unaligned_partition_size{
base::FilePath{"log"}, disk_file, kBlockSize + 1, (10 * kBlockSize) + 1};
EXPECT_EQ(unaligned_partition_size.IsValid(), false);
LogStoreManifest disk_open_fails{base::FilePath{"log"},
base::FilePath{"unopenable_file"},
kBlockSize, 3 * kBlockSize};
EXPECT_FALSE(disk_open_fails.IsValid());
}
TEST_F(LogStoreManifestTest, WriteFailsWithoutGenerate) {
const uint64_t kernel_size = 2;
auto disk_file = CreateFileOfSize(10 * 1024);
LogStoreManifest manifest_store{base::FilePath{"log_file"}, disk_file,
kernel_size, kPartitionSize};
EXPECT_TRUE(manifest_store.IsValid());
// This method should return false without a Generate() since there's nothing
// to write.
EXPECT_FALSE(manifest_store.Write());
}
TEST_F(LogStoreManifestTest, VerifyWriteAndRetrieve) {
auto log_file = CreateFileOfSize(1025);
// Set sizes and offsets to not be perfectly block aligned to verify block
// math.
const uint64_t kernel_size = (2 * kBlockSize) + 1;
const uint64_t log_store_offset = (5 * kBlockSize) + 256;
const uint64_t partition_size = 100 * kBlockSize;
auto disk_file = CreateFileOfSize(partition_size);
LogStoreManifest manifest_store{log_file, disk_file, kernel_size,
partition_size};
EXPECT_TRUE(manifest_store.Generate(log_store_offset));
auto generated_manifest = manifest_store.manifest_;
// Write the generated manifest to file.
EXPECT_TRUE(manifest_store.Write());
// Expect the same manfiest to be read back from file.
auto retrieved_manifest = manifest_store.Retreive();
ASSERT_TRUE(retrieved_manifest.has_value());
EXPECT_EQ(retrieved_manifest->SerializeAsString(),
generated_manifest->SerializeAsString());
}
TEST_F(LogStoreManifestTest, VerifyClear) {
const uint64_t kernel_size = kBlockSize;
const uint64_t partition_size = 20 * kBlockSize;
auto log_file = CreateFileOfSize(1025);
auto disk_file = CreateFileOfSize(partition_size);
LogStoreManifest manifest_store{log_file, disk_file, kernel_size,
partition_size};
EXPECT_TRUE(manifest_store.Generate(1024));
// Find the manifest magic where we expect to.
EXPECT_TRUE(manifest_store.Write());
EXPECT_THAT(manifest_store.FindManifestMagic(),
Optional(manifest_store.manifest_store_start_));
manifest_store.Clear();
EXPECT_EQ(manifest_store.FindManifestMagic(), std::nullopt);
}
} // namespace minios