ext2_filesystem_unittest.cc revision 3f39d5cc753905874d8d93bef94f857b8808f19e
1// 2// Copyright (C) 2015 The Android Open Source Project 3// 4// Licensed under the Apache License, Version 2.0 (the "License"); 5// you may not use this file except in compliance with the License. 6// You may obtain a copy of the License at 7// 8// http://www.apache.org/licenses/LICENSE-2.0 9// 10// Unless required by applicable law or agreed to in writing, software 11// distributed under the License is distributed on an "AS IS" BASIS, 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13// See the License for the specific language governing permissions and 14// limitations under the License. 15// 16 17#include "update_engine/payload_generator/ext2_filesystem.h" 18 19#include <unistd.h> 20 21#include <map> 22#include <set> 23#include <string> 24#include <vector> 25 26#include <base/format_macros.h> 27#include <base/logging.h> 28#include <base/strings/stringprintf.h> 29#include <base/strings/string_number_conversions.h> 30#include <base/strings/string_util.h> 31#include <gtest/gtest.h> 32 33#include "update_engine/payload_generator/extent_utils.h" 34#include "update_engine/test_utils.h" 35#include "update_engine/utils.h" 36 37using chromeos_update_engine::test_utils::System; 38using std::map; 39using std::set; 40using std::string; 41using std::unique_ptr; 42using std::vector; 43 44namespace chromeos_update_engine { 45 46namespace { 47 48uint64_t kDefaultFilesystemSize = 4 * 1024 * 1024; 49size_t kDefaultFilesystemBlockCount = 1024; 50size_t kDefaultFilesystemBlockSize = 4096; 51 52// Checks that all the blocks in |extents| are in the range [0, total_blocks). 53void ExpectBlocksInRange(const vector<Extent>& extents, uint64_t total_blocks) { 54 for (const Extent& extent : extents) { 55 EXPECT_LE(0, extent.start_block()); 56 EXPECT_LE(extent.start_block() + extent.num_blocks(), total_blocks); 57 } 58} 59 60} // namespace 61 62 63class Ext2FilesystemTest : public ::testing::Test { 64 protected: 65 void SetUp() override { 66 ASSERT_TRUE(utils::MakeTempFile("Ext2FilesystemTest-XXXXXX", 67 &fs_filename_, nullptr)); 68 ASSERT_EQ(0, truncate(fs_filename_.c_str(), kDefaultFilesystemSize)); 69 } 70 71 void TearDown() override { 72 unlink(fs_filename_.c_str()); 73 } 74 75 string fs_filename_; 76}; 77 78TEST_F(Ext2FilesystemTest, InvalidFilesystem) { 79 unique_ptr<Ext2Filesystem> fs = Ext2Filesystem::CreateFromFile(fs_filename_); 80 ASSERT_EQ(nullptr, fs.get()); 81 82 fs = Ext2Filesystem::CreateFromFile("/path/to/invalid/file"); 83 ASSERT_EQ(nullptr, fs.get()); 84} 85 86TEST_F(Ext2FilesystemTest, EmptyFilesystem) { 87 EXPECT_EQ(0, System(base::StringPrintf( 88 "/sbin/mkfs.ext2 -q -b %" PRIuS " -F %s", 89 kDefaultFilesystemBlockSize, fs_filename_.c_str()))); 90 unique_ptr<Ext2Filesystem> fs = Ext2Filesystem::CreateFromFile(fs_filename_); 91 92 ASSERT_NE(nullptr, fs.get()); 93 EXPECT_EQ(kDefaultFilesystemBlockCount, fs->GetBlockCount()); 94 EXPECT_EQ(kDefaultFilesystemBlockSize, fs->GetBlockSize()); 95 96 vector<FilesystemInterface::File> files; 97 EXPECT_TRUE(fs->GetFiles(&files)); 98 99 map<string, FilesystemInterface::File> map_files; 100 for (const auto& file : files) { 101 EXPECT_EQ(map_files.end(), map_files.find(file.name)) 102 << "File " << file.name << " repeated in the list."; 103 map_files[file.name] = file; 104 ExpectBlocksInRange(file.extents, fs->GetBlockCount()); 105 } 106 EXPECT_EQ(2, map_files["/"].file_stat.st_ino); 107 EXPECT_FALSE(map_files["<free-space>"].extents.empty()); 108} 109 110// This test parses the sample images generated during build time with the 111// "generate_image.sh" script. The expected conditions of each file in these 112// images is encoded in the file name, as defined in the mentioned script. 113TEST_F(Ext2FilesystemTest, ParseGeneratedImages) { 114 const vector<string> kGeneratedImages = { 115 "disk_ext2_1k.img", 116 "disk_ext2_4k.img" }; 117 base::FilePath build_path = test_utils::GetBuildArtifactsPath().Append("gen"); 118 for (const string& fs_name : kGeneratedImages) { 119 LOG(INFO) << "Testing " << fs_name; 120 unique_ptr<Ext2Filesystem> fs = Ext2Filesystem::CreateFromFile( 121 build_path.Append(fs_name).value()); 122 ASSERT_NE(nullptr, fs.get()); 123 124 vector<FilesystemInterface::File> files; 125 map<string, FilesystemInterface::File> map_files; 126 set<string> filenames; 127 EXPECT_TRUE(fs->GetFiles(&files)); 128 for (const auto& file : files) { 129 // Check no repeated files. We should parse hard-links with two different 130 // names. 131 EXPECT_EQ(map_files.end(), map_files.find(file.name)) 132 << "File " << file.name << " repeated in the list."; 133 map_files[file.name] = file; 134 filenames.insert(file.name); 135 ExpectBlocksInRange(file.extents, fs->GetBlockCount()); 136 } 137 138 // Check that all the files are parsed, and the /removed file should not 139 // be included in the list. 140 set<string> kExpectedFiles = { 141 "/", 142 "/dir1", 143 "/dir1/file", 144 "/dir1/dir2", 145 "/dir1/dir2/file", 146 "/dir1/dir2/dir1", 147 "/empty-file", 148 "/link-hard-regular-16k", 149 "/link-long_symlink", 150 "/link-short_symlink", 151 "/lost+found", 152 "/regular-small", 153 "/regular-16k", 154 "/regular-32k-zeros", 155 "/regular-with_net_cap", 156 "/sparse_empty-10k", 157 "/sparse_empty-2blocks", 158 "/sparse-10000blocks", 159 "/sparse-16k-last_block", 160 "/sparse-16k-first_block", 161 "/sparse-16k-holes", 162 "<inode-blocks>", 163 "<free-space>", 164 "<group-descriptors>", 165 }; 166 EXPECT_EQ(kExpectedFiles, filenames); 167 168 FilesystemInterface::File file; 169 170 // Small symlinks don't actually have data blocks. 171 EXPECT_TRUE(map_files["/link-short_symlink"].extents.empty()); 172 EXPECT_EQ(1, BlocksInExtents(map_files["/link-long_symlink"].extents)); 173 174 // Hard-links report the same list of blocks. 175 EXPECT_EQ(map_files["/link-hard-regular-16k"].extents, 176 map_files["/regular-16k"].extents); 177 EXPECT_FALSE(map_files["/regular-16k"].extents.empty()); 178 179 // The number of blocks in these files doesn't depend on the 180 // block size. 181 EXPECT_TRUE(map_files["/empty-file"].extents.empty()); 182 EXPECT_EQ(1, BlocksInExtents(map_files["/regular-small"].extents)); 183 EXPECT_EQ(1, BlocksInExtents(map_files["/regular-with_net_cap"].extents)); 184 EXPECT_TRUE(map_files["/sparse_empty-10k"].extents.empty()); 185 EXPECT_TRUE(map_files["/sparse_empty-2blocks"].extents.empty()); 186 EXPECT_EQ(1, BlocksInExtents(map_files["/sparse-16k-last_block"].extents)); 187 EXPECT_EQ(1, BlocksInExtents(map_files["/sparse-16k-first_block"].extents)); 188 EXPECT_EQ(2, BlocksInExtents(map_files["/sparse-16k-holes"].extents)); 189 } 190} 191 192TEST_F(Ext2FilesystemTest, LoadSettingsFailsTest) { 193 base::FilePath path = test_utils::GetBuildArtifactsPath().Append( 194 "gen/disk_ext2_1k.img"); 195 unique_ptr<Ext2Filesystem> fs = Ext2Filesystem::CreateFromFile(path.value()); 196 197 brillo::KeyValueStore store; 198 // disk_ext2_1k.img doesn't have the /etc/update_engine.conf file. 199 EXPECT_FALSE(fs->LoadSettings(&store)); 200} 201 202TEST_F(Ext2FilesystemTest, LoadSettingsWorksTest) { 203 base::FilePath path = test_utils::GetBuildArtifactsPath().Append( 204 "gen/disk_ext2_ue_settings.img"); 205 unique_ptr<Ext2Filesystem> fs = Ext2Filesystem::CreateFromFile(path.value()); 206 207 brillo::KeyValueStore store; 208 EXPECT_TRUE(fs->LoadSettings(&store)); 209 string minor_version; 210 EXPECT_TRUE(store.GetString("PAYLOAD_MINOR_VERSION", &minor_version)); 211 EXPECT_EQ("1234", minor_version); 212} 213 214} // namespace chromeos_update_engine 215