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