Home | History | Annotate | Download | only in payload_generator
      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/string_number_conversions.h>
     29 #include <base/strings/string_util.h>
     30 #include <base/strings/stringprintf.h>
     31 #include <gtest/gtest.h>
     32 
     33 #include "update_engine/common/test_utils.h"
     34 #include "update_engine/common/utils.h"
     35 #include "update_engine/payload_generator/extent_utils.h"
     36 
     37 using chromeos_update_engine::test_utils::GetBuildArtifactsPath;
     38 using std::map;
     39 using std::set;
     40 using std::string;
     41 using std::unique_ptr;
     42 using std::vector;
     43 
     44 namespace chromeos_update_engine {
     45 
     46 namespace {
     47 
     48 uint64_t kDefaultFilesystemSize = 4 * 1024 * 1024;
     49 size_t kDefaultFilesystemBlockCount = 1024;
     50 size_t kDefaultFilesystemBlockSize = 4096;
     51 
     52 // Checks that all the blocks in |extents| are in the range [0, total_blocks).
     53 void ExpectBlocksInRange(const vector<Extent>& extents, uint64_t total_blocks) {
     54   for (const Extent& extent : extents) {
     55     EXPECT_LE(0U, extent.start_block());
     56     EXPECT_LE(extent.start_block() + extent.num_blocks(), total_blocks);
     57   }
     58 }
     59 
     60 }  // namespace
     61 
     62 class Ext2FilesystemTest : public ::testing::Test {};
     63 
     64 TEST_F(Ext2FilesystemTest, InvalidFilesystem) {
     65   test_utils::ScopedTempFile fs_filename_{"Ext2FilesystemTest-XXXXXX"};
     66   ASSERT_EQ(0, truncate(fs_filename_.path().c_str(), kDefaultFilesystemSize));
     67   unique_ptr<Ext2Filesystem> fs =
     68       Ext2Filesystem::CreateFromFile(fs_filename_.path());
     69   ASSERT_EQ(nullptr, fs.get());
     70 
     71   fs = Ext2Filesystem::CreateFromFile("/path/to/invalid/file");
     72   ASSERT_EQ(nullptr, fs.get());
     73 }
     74 
     75 TEST_F(Ext2FilesystemTest, EmptyFilesystem) {
     76   unique_ptr<Ext2Filesystem> fs = Ext2Filesystem::CreateFromFile(
     77       GetBuildArtifactsPath("gen/disk_ext2_4k_empty.img"));
     78 
     79   ASSERT_NE(nullptr, fs.get());
     80   EXPECT_EQ(kDefaultFilesystemBlockCount, fs->GetBlockCount());
     81   EXPECT_EQ(kDefaultFilesystemBlockSize, fs->GetBlockSize());
     82 
     83   vector<FilesystemInterface::File> files;
     84   EXPECT_TRUE(fs->GetFiles(&files));
     85 
     86   map<string, FilesystemInterface::File> map_files;
     87   for (const auto& file : files) {
     88     EXPECT_EQ(map_files.end(), map_files.find(file.name))
     89         << "File " << file.name << " repeated in the list.";
     90     map_files[file.name] = file;
     91     ExpectBlocksInRange(file.extents, fs->GetBlockCount());
     92   }
     93   EXPECT_EQ(2U, map_files["/"].file_stat.st_ino);
     94   EXPECT_FALSE(map_files["<free-space>"].extents.empty());
     95 }
     96 
     97 // This test parses the sample images generated during build time with the
     98 // "generate_image.sh" script. The expected conditions of each file in these
     99 // images is encoded in the file name, as defined in the mentioned script.
    100 TEST_F(Ext2FilesystemTest, ParseGeneratedImages) {
    101   const vector<string> kGeneratedImages = {
    102       "disk_ext2_1k.img",
    103       "disk_ext2_4k.img" };
    104   base::FilePath build_path = GetBuildArtifactsPath().Append("gen");
    105   for (const string& fs_name : kGeneratedImages) {
    106     LOG(INFO) << "Testing " << fs_name;
    107     unique_ptr<Ext2Filesystem> fs = Ext2Filesystem::CreateFromFile(
    108         build_path.Append(fs_name).value());
    109     ASSERT_NE(nullptr, fs.get());
    110 
    111     vector<FilesystemInterface::File> files;
    112     map<string, FilesystemInterface::File> map_files;
    113     set<string> filenames;
    114     EXPECT_TRUE(fs->GetFiles(&files));
    115     for (const auto& file : files) {
    116       // Check no repeated files. We should parse hard-links with two different
    117       // names.
    118       EXPECT_EQ(map_files.end(), map_files.find(file.name))
    119           << "File " << file.name << " repeated in the list.";
    120       map_files[file.name] = file;
    121       filenames.insert(file.name);
    122       ExpectBlocksInRange(file.extents, fs->GetBlockCount());
    123     }
    124 
    125     // Check that all the files are parsed, and the /removed file should not
    126     // be included in the list.
    127     set<string> kExpectedFiles = {
    128         "/",
    129         "/cdev",
    130         "/dir1",
    131         "/dir1/file",
    132         "/dir1/dir2",
    133         "/dir1/dir2/file",
    134         "/dir1/dir2/dir1",
    135         "/empty-file",
    136         "/fifo",
    137         "/link-hard-regular-16k",
    138         "/link-long_symlink",
    139         "/link-short_symlink",
    140         "/lost+found",
    141         "/regular-small",
    142         "/regular-16k",
    143         "/regular-32k-zeros",
    144         "/regular-with_net_cap",
    145         "/sparse_empty-10k",
    146         "/sparse_empty-2blocks",
    147         "/sparse-10000blocks",
    148         "/sparse-16k-last_block",
    149         "/sparse-16k-first_block",
    150         "/sparse-16k-holes",
    151         "<inode-blocks>",
    152         "<free-space>",
    153         "<group-descriptors>",
    154     };
    155     EXPECT_EQ(kExpectedFiles, filenames);
    156 
    157     FilesystemInterface::File file;
    158 
    159     // Small symlinks don't actually have data blocks.
    160     EXPECT_TRUE(map_files["/link-short_symlink"].extents.empty());
    161     EXPECT_EQ(1U,
    162               utils::BlocksInExtents(map_files["/link-long_symlink"].extents));
    163 
    164     // Hard-links report the same list of blocks.
    165     EXPECT_EQ(map_files["/link-hard-regular-16k"].extents,
    166               map_files["/regular-16k"].extents);
    167     EXPECT_FALSE(map_files["/regular-16k"].extents.empty());
    168 
    169     // The number of blocks in these files doesn't depend on the
    170     // block size.
    171     EXPECT_TRUE(map_files["/empty-file"].extents.empty());
    172     EXPECT_EQ(1U, utils::BlocksInExtents(map_files["/regular-small"].extents));
    173     EXPECT_EQ(
    174         1U, utils::BlocksInExtents(map_files["/regular-with_net_cap"].extents));
    175     EXPECT_TRUE(map_files["/sparse_empty-10k"].extents.empty());
    176     EXPECT_TRUE(map_files["/sparse_empty-2blocks"].extents.empty());
    177     EXPECT_EQ(
    178         1U,
    179         utils::BlocksInExtents(map_files["/sparse-16k-last_block"].extents));
    180     EXPECT_EQ(
    181         1U,
    182         utils::BlocksInExtents(map_files["/sparse-16k-first_block"].extents));
    183     EXPECT_EQ(2U,
    184               utils::BlocksInExtents(map_files["/sparse-16k-holes"].extents));
    185   }
    186 }
    187 
    188 TEST_F(Ext2FilesystemTest, LoadSettingsFailsTest) {
    189   unique_ptr<Ext2Filesystem> fs = Ext2Filesystem::CreateFromFile(
    190       GetBuildArtifactsPath("gen/disk_ext2_1k.img"));
    191   ASSERT_NE(nullptr, fs.get());
    192 
    193   brillo::KeyValueStore store;
    194   // disk_ext2_1k.img doesn't have the /etc/update_engine.conf file.
    195   EXPECT_FALSE(fs->LoadSettings(&store));
    196 }
    197 
    198 TEST_F(Ext2FilesystemTest, LoadSettingsWorksTest) {
    199   unique_ptr<Ext2Filesystem> fs = Ext2Filesystem::CreateFromFile(
    200       GetBuildArtifactsPath("gen/disk_ext2_unittest.img"));
    201   ASSERT_NE(nullptr, fs.get());
    202 
    203   brillo::KeyValueStore store;
    204   EXPECT_TRUE(fs->LoadSettings(&store));
    205   string minor_version;
    206   EXPECT_TRUE(store.GetString("PAYLOAD_MINOR_VERSION", &minor_version));
    207   EXPECT_EQ("1234", minor_version);
    208 }
    209 
    210 }  // namespace chromeos_update_engine
    211