Home | History | Annotate | Download | only in payload_consumer
      1 //
      2 // Copyright (C) 2009 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_consumer/extent_writer.h"
     18 
     19 #include <fcntl.h>
     20 
     21 #include <algorithm>
     22 #include <string>
     23 #include <vector>
     24 
     25 #include <brillo/make_unique_ptr.h>
     26 #include <brillo/secure_blob.h>
     27 #include <gtest/gtest.h>
     28 
     29 #include "update_engine/common/test_utils.h"
     30 #include "update_engine/common/utils.h"
     31 #include "update_engine/payload_consumer/payload_constants.h"
     32 
     33 using chromeos_update_engine::test_utils::ExpectVectorsEq;
     34 using std::min;
     35 using std::string;
     36 using std::vector;
     37 
     38 namespace chromeos_update_engine {
     39 
     40 static_assert(sizeof(off_t) == 8, "off_t not 64 bit");
     41 
     42 namespace {
     43 const size_t kBlockSize = 4096;
     44 }
     45 
     46 class ExtentWriterTest : public ::testing::Test {
     47  protected:
     48   void SetUp() override {
     49     fd_.reset(new EintrSafeFileDescriptor);
     50     ASSERT_TRUE(fd_->Open(temp_file_.path().c_str(), O_RDWR, 0600));
     51   }
     52   void TearDown() override {
     53     fd_->Close();
     54   }
     55 
     56   // Writes data to an extent writer in 'chunk_size' chunks with
     57   // the first chunk of size first_chunk_size. It calculates what the
     58   // resultant file should look like and ensure that the extent writer
     59   // wrote the file correctly.
     60   void WriteAlignedExtents(size_t chunk_size, size_t first_chunk_size);
     61   void TestZeroPad(bool aligned_size);
     62 
     63   FileDescriptorPtr fd_;
     64   test_utils::ScopedTempFile temp_file_{"ExtentWriterTest-file.XXXXXX"};
     65 };
     66 
     67 TEST_F(ExtentWriterTest, SimpleTest) {
     68   vector<Extent> extents;
     69   Extent extent;
     70   extent.set_start_block(1);
     71   extent.set_num_blocks(1);
     72   extents.push_back(extent);
     73 
     74   const string bytes = "1234";
     75 
     76   DirectExtentWriter direct_writer;
     77   EXPECT_TRUE(direct_writer.Init(fd_, extents, kBlockSize));
     78   EXPECT_TRUE(direct_writer.Write(bytes.data(), bytes.size()));
     79   EXPECT_TRUE(direct_writer.End());
     80 
     81   EXPECT_EQ(static_cast<off_t>(kBlockSize + bytes.size()),
     82             utils::FileSize(temp_file_.path()));
     83 
     84   brillo::Blob result_file;
     85   EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &result_file));
     86 
     87   brillo::Blob expected_file(kBlockSize);
     88   expected_file.insert(expected_file.end(),
     89                        bytes.data(), bytes.data() + bytes.size());
     90   ExpectVectorsEq(expected_file, result_file);
     91 }
     92 
     93 TEST_F(ExtentWriterTest, ZeroLengthTest) {
     94   vector<Extent> extents;
     95   Extent extent;
     96   extent.set_start_block(1);
     97   extent.set_num_blocks(1);
     98   extents.push_back(extent);
     99 
    100   DirectExtentWriter direct_writer;
    101   EXPECT_TRUE(direct_writer.Init(fd_, extents, kBlockSize));
    102   EXPECT_TRUE(direct_writer.Write(nullptr, 0));
    103   EXPECT_TRUE(direct_writer.End());
    104 }
    105 
    106 TEST_F(ExtentWriterTest, OverflowExtentTest) {
    107   WriteAlignedExtents(kBlockSize * 3, kBlockSize * 3);
    108 }
    109 
    110 TEST_F(ExtentWriterTest, UnalignedWriteTest) {
    111   WriteAlignedExtents(7, 7);
    112 }
    113 
    114 TEST_F(ExtentWriterTest, LargeUnalignedWriteTest) {
    115   WriteAlignedExtents(kBlockSize * 2, kBlockSize / 2);
    116 }
    117 
    118 void ExtentWriterTest::WriteAlignedExtents(size_t chunk_size,
    119                                            size_t first_chunk_size) {
    120   vector<Extent> extents;
    121   Extent extent;
    122   extent.set_start_block(1);
    123   extent.set_num_blocks(1);
    124   extents.push_back(extent);
    125   extent.set_start_block(0);
    126   extent.set_num_blocks(1);
    127   extents.push_back(extent);
    128   extent.set_start_block(2);
    129   extent.set_num_blocks(1);
    130   extents.push_back(extent);
    131 
    132   brillo::Blob data(kBlockSize * 3);
    133   test_utils::FillWithData(&data);
    134 
    135   DirectExtentWriter direct_writer;
    136   EXPECT_TRUE(direct_writer.Init(fd_, extents, kBlockSize));
    137 
    138   size_t bytes_written = 0;
    139   while (bytes_written < data.size()) {
    140     size_t bytes_to_write = min(data.size() - bytes_written, chunk_size);
    141     if (bytes_written == 0) {
    142       bytes_to_write = min(data.size() - bytes_written, first_chunk_size);
    143     }
    144     EXPECT_TRUE(direct_writer.Write(&data[bytes_written], bytes_to_write));
    145     bytes_written += bytes_to_write;
    146   }
    147   EXPECT_TRUE(direct_writer.End());
    148 
    149   EXPECT_EQ(static_cast<off_t>(data.size()),
    150             utils::FileSize(temp_file_.path()));
    151 
    152   brillo::Blob result_file;
    153   EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &result_file));
    154 
    155   brillo::Blob expected_file;
    156   expected_file.insert(expected_file.end(),
    157                        data.begin() + kBlockSize,
    158                        data.begin() + kBlockSize * 2);
    159   expected_file.insert(expected_file.end(),
    160                        data.begin(), data.begin() + kBlockSize);
    161   expected_file.insert(expected_file.end(),
    162                        data.begin() + kBlockSize * 2, data.end());
    163   ExpectVectorsEq(expected_file, result_file);
    164 }
    165 
    166 TEST_F(ExtentWriterTest, ZeroPadNullTest) {
    167   TestZeroPad(true);
    168 }
    169 
    170 TEST_F(ExtentWriterTest, ZeroPadFillTest) {
    171   TestZeroPad(false);
    172 }
    173 
    174 void ExtentWriterTest::TestZeroPad(bool aligned_size) {
    175   vector<Extent> extents;
    176   Extent extent;
    177   extent.set_start_block(1);
    178   extent.set_num_blocks(1);
    179   extents.push_back(extent);
    180   extent.set_start_block(0);
    181   extent.set_num_blocks(1);
    182   extents.push_back(extent);
    183 
    184   brillo::Blob data(kBlockSize * 2);
    185   test_utils::FillWithData(&data);
    186 
    187   ZeroPadExtentWriter zero_pad_writer(
    188       brillo::make_unique_ptr(new DirectExtentWriter()));
    189 
    190   EXPECT_TRUE(zero_pad_writer.Init(fd_, extents, kBlockSize));
    191   size_t bytes_to_write = data.size();
    192   const size_t missing_bytes = (aligned_size ? 0 : 9);
    193   bytes_to_write -= missing_bytes;
    194   fd_->Seek(kBlockSize - missing_bytes, SEEK_SET);
    195   EXPECT_EQ(3, fd_->Write("xxx", 3));
    196   ASSERT_TRUE(zero_pad_writer.Write(data.data(), bytes_to_write));
    197   EXPECT_TRUE(zero_pad_writer.End());
    198 
    199   EXPECT_EQ(static_cast<off_t>(data.size()),
    200             utils::FileSize(temp_file_.path()));
    201 
    202   brillo::Blob result_file;
    203   EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &result_file));
    204 
    205   brillo::Blob expected_file;
    206   expected_file.insert(expected_file.end(),
    207                        data.begin() + kBlockSize,
    208                        data.begin() + kBlockSize * 2);
    209   expected_file.insert(expected_file.end(),
    210                        data.begin(), data.begin() + kBlockSize);
    211   if (missing_bytes) {
    212     memset(&expected_file[kBlockSize - missing_bytes], 0, missing_bytes);
    213   }
    214 
    215   ExpectVectorsEq(expected_file, result_file);
    216 }
    217 
    218 TEST_F(ExtentWriterTest, SparseFileTest) {
    219   vector<Extent> extents;
    220   Extent extent;
    221   extent.set_start_block(1);
    222   extent.set_num_blocks(1);
    223   extents.push_back(extent);
    224   extent.set_start_block(kSparseHole);
    225   extent.set_num_blocks(2);
    226   extents.push_back(extent);
    227   extent.set_start_block(0);
    228   extent.set_num_blocks(1);
    229   extents.push_back(extent);
    230   const int block_count = 4;
    231   const int on_disk_count = 2;
    232 
    233   brillo::Blob data(17);
    234   test_utils::FillWithData(&data);
    235 
    236   DirectExtentWriter direct_writer;
    237   EXPECT_TRUE(direct_writer.Init(fd_, extents, kBlockSize));
    238 
    239   size_t bytes_written = 0;
    240   while (bytes_written < (block_count * kBlockSize)) {
    241     size_t bytes_to_write = min(block_count * kBlockSize - bytes_written,
    242                                 data.size());
    243     EXPECT_TRUE(direct_writer.Write(data.data(), bytes_to_write));
    244     bytes_written += bytes_to_write;
    245   }
    246   EXPECT_TRUE(direct_writer.End());
    247 
    248   // check file size, then data inside
    249   ASSERT_EQ(static_cast<off_t>(2 * kBlockSize),
    250             utils::FileSize(temp_file_.path()));
    251 
    252   brillo::Blob resultant_data;
    253   EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &resultant_data));
    254 
    255   // Create expected data
    256   brillo::Blob expected_data(on_disk_count * kBlockSize);
    257   brillo::Blob big(block_count * kBlockSize);
    258   for (brillo::Blob::size_type i = 0; i < big.size(); i++) {
    259     big[i] = data[i % data.size()];
    260   }
    261   memcpy(&expected_data[kBlockSize], &big[0], kBlockSize);
    262   memcpy(&expected_data[0], &big[3 * kBlockSize], kBlockSize);
    263   ExpectVectorsEq(expected_data, resultant_data);
    264 }
    265 
    266 }  // namespace chromeos_update_engine
    267