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/ab_generator.h"
     18 
     19 #include <fcntl.h>
     20 #include <sys/stat.h>
     21 #include <sys/types.h>
     22 
     23 #include <random>
     24 #include <string>
     25 #include <vector>
     26 
     27 #include <gtest/gtest.h>
     28 
     29 #include "update_engine/common/hash_calculator.h"
     30 #include "update_engine/common/test_utils.h"
     31 #include "update_engine/common/utils.h"
     32 #include "update_engine/payload_generator/annotated_operation.h"
     33 #include "update_engine/payload_generator/bzip.h"
     34 #include "update_engine/payload_generator/delta_diff_generator.h"
     35 #include "update_engine/payload_generator/extent_ranges.h"
     36 #include "update_engine/payload_generator/extent_utils.h"
     37 
     38 using std::string;
     39 using std::vector;
     40 
     41 namespace chromeos_update_engine {
     42 
     43 namespace {
     44 
     45 bool ExtentEquals(const Extent& ext,
     46                   uint64_t start_block,
     47                   uint64_t num_blocks) {
     48   return ext.start_block() == start_block && ext.num_blocks() == num_blocks;
     49 }
     50 
     51 // Tests splitting of a REPLACE/REPLACE_BZ operation.
     52 void TestSplitReplaceOrReplaceBzOperation(InstallOperation_Type orig_type,
     53                                           bool compressible) {
     54   const size_t op_ex1_start_block = 2;
     55   const size_t op_ex1_num_blocks = 2;
     56   const size_t op_ex2_start_block = 6;
     57   const size_t op_ex2_num_blocks = 1;
     58   const size_t part_num_blocks = 7;
     59 
     60   // Create the target partition data.
     61   string part_path;
     62   EXPECT_TRUE(utils::MakeTempFile(
     63       "SplitReplaceOrReplaceBzTest_part.XXXXXX", &part_path, nullptr));
     64   ScopedPathUnlinker part_path_unlinker(part_path);
     65   const size_t part_size = part_num_blocks * kBlockSize;
     66   brillo::Blob part_data;
     67   if (compressible) {
     68     part_data.resize(part_size);
     69     test_utils::FillWithData(&part_data);
     70   } else {
     71     std::mt19937 gen(12345);
     72     std::uniform_int_distribution<uint8_t> dis(0, 255);
     73     for (uint32_t i = 0; i < part_size; i++)
     74       part_data.push_back(dis(gen));
     75   }
     76   ASSERT_EQ(part_size, part_data.size());
     77   ASSERT_TRUE(utils::WriteFile(part_path.c_str(), part_data.data(), part_size));
     78 
     79   // Create original operation and blob data.
     80   const size_t op_ex1_offset = op_ex1_start_block * kBlockSize;
     81   const size_t op_ex1_size = op_ex1_num_blocks * kBlockSize;
     82   const size_t op_ex2_offset = op_ex2_start_block * kBlockSize;
     83   const size_t op_ex2_size = op_ex2_num_blocks * kBlockSize;
     84   InstallOperation op;
     85   op.set_type(orig_type);
     86   *(op.add_dst_extents()) = ExtentForRange(op_ex1_start_block,
     87                                            op_ex1_num_blocks);
     88   *(op.add_dst_extents()) = ExtentForRange(op_ex2_start_block,
     89                                            op_ex2_num_blocks);
     90 
     91   brillo::Blob op_data;
     92   op_data.insert(op_data.end(),
     93                  part_data.begin() + op_ex1_offset,
     94                  part_data.begin() + op_ex1_offset + op_ex1_size);
     95   op_data.insert(op_data.end(),
     96                  part_data.begin() + op_ex2_offset,
     97                  part_data.begin() + op_ex2_offset + op_ex2_size);
     98   brillo::Blob op_blob;
     99   if (orig_type == InstallOperation::REPLACE) {
    100     op_blob = op_data;
    101   } else {
    102     ASSERT_TRUE(BzipCompress(op_data, &op_blob));
    103   }
    104   op.set_data_offset(0);
    105   op.set_data_length(op_blob.size());
    106 
    107   AnnotatedOperation aop;
    108   aop.op = op;
    109   aop.name = "SplitTestOp";
    110 
    111   // Create the data file.
    112   string data_path;
    113   EXPECT_TRUE(utils::MakeTempFile(
    114       "SplitReplaceOrReplaceBzTest_data.XXXXXX", &data_path, nullptr));
    115   ScopedPathUnlinker data_path_unlinker(data_path);
    116   int data_fd = open(data_path.c_str(), O_RDWR, 000);
    117   EXPECT_GE(data_fd, 0);
    118   ScopedFdCloser data_fd_closer(&data_fd);
    119   EXPECT_TRUE(utils::WriteFile(data_path.c_str(), op_blob.data(),
    120                                op_blob.size()));
    121   off_t data_file_size = op_blob.size();
    122   BlobFileWriter blob_file(data_fd, &data_file_size);
    123 
    124   // Split the operation.
    125   vector<AnnotatedOperation> result_ops;
    126   PayloadVersion version(kChromeOSMajorPayloadVersion,
    127                          kSourceMinorPayloadVersion);
    128   ASSERT_TRUE(ABGenerator::SplitAReplaceOp(
    129       version, aop, part_path, &result_ops, &blob_file));
    130 
    131   // Check the result.
    132   InstallOperation_Type expected_type =
    133       compressible ? InstallOperation::REPLACE_BZ : InstallOperation::REPLACE;
    134 
    135   ASSERT_EQ(2U, result_ops.size());
    136 
    137   EXPECT_EQ("SplitTestOp:0", result_ops[0].name);
    138   InstallOperation first_op = result_ops[0].op;
    139   EXPECT_EQ(expected_type, first_op.type());
    140   EXPECT_FALSE(first_op.has_src_length());
    141   EXPECT_FALSE(first_op.has_dst_length());
    142   EXPECT_EQ(1, first_op.dst_extents().size());
    143   EXPECT_TRUE(ExtentEquals(first_op.dst_extents(0), op_ex1_start_block,
    144                            op_ex1_num_blocks));
    145   // Obtain the expected blob.
    146   brillo::Blob first_expected_data(
    147       part_data.begin() + op_ex1_offset,
    148       part_data.begin() + op_ex1_offset + op_ex1_size);
    149   brillo::Blob first_expected_blob;
    150   if (compressible) {
    151     ASSERT_TRUE(BzipCompress(first_expected_data, &first_expected_blob));
    152   } else {
    153     first_expected_blob = first_expected_data;
    154   }
    155   EXPECT_EQ(first_expected_blob.size(), first_op.data_length());
    156   // Check that the actual blob matches what's expected.
    157   brillo::Blob first_data_blob(first_op.data_length());
    158   ssize_t bytes_read;
    159   ASSERT_TRUE(utils::PReadAll(data_fd,
    160                               first_data_blob.data(),
    161                               first_op.data_length(),
    162                               first_op.data_offset(),
    163                               &bytes_read));
    164   ASSERT_EQ(bytes_read, static_cast<ssize_t>(first_op.data_length()));
    165   EXPECT_EQ(first_expected_blob, first_data_blob);
    166 
    167   EXPECT_EQ("SplitTestOp:1", result_ops[1].name);
    168   InstallOperation second_op = result_ops[1].op;
    169   EXPECT_EQ(expected_type, second_op.type());
    170   EXPECT_FALSE(second_op.has_src_length());
    171   EXPECT_FALSE(second_op.has_dst_length());
    172   EXPECT_EQ(1, second_op.dst_extents().size());
    173   EXPECT_TRUE(ExtentEquals(second_op.dst_extents(0), op_ex2_start_block,
    174                            op_ex2_num_blocks));
    175   // Obtain the expected blob.
    176   brillo::Blob second_expected_data(
    177       part_data.begin() + op_ex2_offset,
    178       part_data.begin() + op_ex2_offset + op_ex2_size);
    179   brillo::Blob second_expected_blob;
    180   if (compressible) {
    181     ASSERT_TRUE(BzipCompress(second_expected_data, &second_expected_blob));
    182   } else {
    183     second_expected_blob = second_expected_data;
    184   }
    185   EXPECT_EQ(second_expected_blob.size(), second_op.data_length());
    186   // Check that the actual blob matches what's expected.
    187   brillo::Blob second_data_blob(second_op.data_length());
    188   ASSERT_TRUE(utils::PReadAll(data_fd,
    189                               second_data_blob.data(),
    190                               second_op.data_length(),
    191                               second_op.data_offset(),
    192                               &bytes_read));
    193   ASSERT_EQ(bytes_read, static_cast<ssize_t>(second_op.data_length()));
    194   EXPECT_EQ(second_expected_blob, second_data_blob);
    195 
    196   // Check relative layout of data blobs.
    197   EXPECT_EQ(first_op.data_offset() + first_op.data_length(),
    198             second_op.data_offset());
    199   EXPECT_EQ(second_op.data_offset() + second_op.data_length(), data_file_size);
    200   // If we split a REPLACE into multiple ones, ensure reuse of preexisting blob.
    201   if (!compressible && orig_type == InstallOperation::REPLACE) {
    202     EXPECT_EQ(0U, first_op.data_offset());
    203   }
    204 }
    205 
    206 // Tests merging of REPLACE/REPLACE_BZ operations.
    207 void TestMergeReplaceOrReplaceBzOperations(InstallOperation_Type orig_type,
    208                                            bool compressible) {
    209   const size_t first_op_num_blocks = 1;
    210   const size_t second_op_num_blocks = 2;
    211   const size_t total_op_num_blocks = first_op_num_blocks + second_op_num_blocks;
    212   const size_t part_num_blocks = total_op_num_blocks + 2;
    213 
    214   // Create the target partition data.
    215   string part_path;
    216   EXPECT_TRUE(utils::MakeTempFile(
    217       "MergeReplaceOrReplaceBzTest_part.XXXXXX", &part_path, nullptr));
    218   ScopedPathUnlinker part_path_unlinker(part_path);
    219   const size_t part_size = part_num_blocks * kBlockSize;
    220   brillo::Blob part_data;
    221   if (compressible) {
    222     part_data.resize(part_size);
    223     test_utils::FillWithData(&part_data);
    224   } else {
    225     std::mt19937 gen(12345);
    226     std::uniform_int_distribution<uint8_t> dis(0, 255);
    227     for (uint32_t i = 0; i < part_size; i++)
    228       part_data.push_back(dis(gen));
    229   }
    230   ASSERT_EQ(part_size, part_data.size());
    231   ASSERT_TRUE(utils::WriteFile(part_path.c_str(), part_data.data(), part_size));
    232 
    233   // Create original operations and blob data.
    234   vector<AnnotatedOperation> aops;
    235   brillo::Blob blob_data;
    236   const size_t total_op_size = total_op_num_blocks * kBlockSize;
    237 
    238   InstallOperation first_op;
    239   first_op.set_type(orig_type);
    240   const size_t first_op_size = first_op_num_blocks * kBlockSize;
    241   *(first_op.add_dst_extents()) = ExtentForRange(0, first_op_num_blocks);
    242   brillo::Blob first_op_data(part_data.begin(),
    243                                part_data.begin() + first_op_size);
    244   brillo::Blob first_op_blob;
    245   if (orig_type == InstallOperation::REPLACE) {
    246     first_op_blob = first_op_data;
    247   } else {
    248     ASSERT_TRUE(BzipCompress(first_op_data, &first_op_blob));
    249   }
    250   first_op.set_data_offset(0);
    251   first_op.set_data_length(first_op_blob.size());
    252   blob_data.insert(blob_data.end(), first_op_blob.begin(), first_op_blob.end());
    253   AnnotatedOperation first_aop;
    254   first_aop.op = first_op;
    255   first_aop.name = "first";
    256   aops.push_back(first_aop);
    257 
    258   InstallOperation second_op;
    259   second_op.set_type(orig_type);
    260   *(second_op.add_dst_extents()) = ExtentForRange(first_op_num_blocks,
    261                                                   second_op_num_blocks);
    262   brillo::Blob second_op_data(part_data.begin() + first_op_size,
    263                                 part_data.begin() + total_op_size);
    264   brillo::Blob second_op_blob;
    265   if (orig_type == InstallOperation::REPLACE) {
    266     second_op_blob = second_op_data;
    267   } else {
    268     ASSERT_TRUE(BzipCompress(second_op_data, &second_op_blob));
    269   }
    270   second_op.set_data_offset(first_op_blob.size());
    271   second_op.set_data_length(second_op_blob.size());
    272   blob_data.insert(blob_data.end(), second_op_blob.begin(),
    273                    second_op_blob.end());
    274   AnnotatedOperation second_aop;
    275   second_aop.op = second_op;
    276   second_aop.name = "second";
    277   aops.push_back(second_aop);
    278 
    279   // Create the data file.
    280   string data_path;
    281   EXPECT_TRUE(utils::MakeTempFile(
    282       "MergeReplaceOrReplaceBzTest_data.XXXXXX", &data_path, nullptr));
    283   ScopedPathUnlinker data_path_unlinker(data_path);
    284   int data_fd = open(data_path.c_str(), O_RDWR, 000);
    285   EXPECT_GE(data_fd, 0);
    286   ScopedFdCloser data_fd_closer(&data_fd);
    287   EXPECT_TRUE(utils::WriteFile(data_path.c_str(), blob_data.data(),
    288                                blob_data.size()));
    289   off_t data_file_size = blob_data.size();
    290   BlobFileWriter blob_file(data_fd, &data_file_size);
    291 
    292   // Merge the operations.
    293   PayloadVersion version(kChromeOSMajorPayloadVersion,
    294                          kSourceMinorPayloadVersion);
    295   EXPECT_TRUE(
    296       ABGenerator::MergeOperations(&aops, version, 5, part_path, &blob_file));
    297 
    298   // Check the result.
    299   InstallOperation_Type expected_op_type =
    300       compressible ? InstallOperation::REPLACE_BZ : InstallOperation::REPLACE;
    301   EXPECT_EQ(1U, aops.size());
    302   InstallOperation new_op = aops[0].op;
    303   EXPECT_EQ(expected_op_type, new_op.type());
    304   EXPECT_FALSE(new_op.has_src_length());
    305   EXPECT_FALSE(new_op.has_dst_length());
    306   EXPECT_EQ(1, new_op.dst_extents().size());
    307   EXPECT_TRUE(ExtentEquals(new_op.dst_extents(0), 0, total_op_num_blocks));
    308   EXPECT_EQ("first,second", aops[0].name);
    309 
    310   // Check to see if the blob pointed to in the new extent has what we expect.
    311   brillo::Blob expected_data(part_data.begin(),
    312                                part_data.begin() + total_op_size);
    313   brillo::Blob expected_blob;
    314   if (compressible) {
    315     ASSERT_TRUE(BzipCompress(expected_data, &expected_blob));
    316   } else {
    317     expected_blob = expected_data;
    318   }
    319   ASSERT_EQ(expected_blob.size(), new_op.data_length());
    320   ASSERT_EQ(blob_data.size() + expected_blob.size(),
    321             static_cast<size_t>(data_file_size));
    322   brillo::Blob new_op_blob(new_op.data_length());
    323   ssize_t bytes_read;
    324   ASSERT_TRUE(utils::PReadAll(data_fd,
    325                               new_op_blob.data(),
    326                               new_op.data_length(),
    327                               new_op.data_offset(),
    328                               &bytes_read));
    329   ASSERT_EQ(static_cast<ssize_t>(new_op.data_length()), bytes_read);
    330   EXPECT_EQ(expected_blob, new_op_blob);
    331 }
    332 
    333 }  // namespace
    334 
    335 class ABGeneratorTest : public ::testing::Test {};
    336 
    337 TEST_F(ABGeneratorTest, SplitSourceCopyTest) {
    338   InstallOperation op;
    339   op.set_type(InstallOperation::SOURCE_COPY);
    340   *(op.add_src_extents()) = ExtentForRange(2, 3);
    341   *(op.add_src_extents()) = ExtentForRange(6, 1);
    342   *(op.add_src_extents()) = ExtentForRange(8, 4);
    343   *(op.add_dst_extents()) = ExtentForRange(10, 2);
    344   *(op.add_dst_extents()) = ExtentForRange(14, 3);
    345   *(op.add_dst_extents()) = ExtentForRange(18, 3);
    346 
    347   AnnotatedOperation aop;
    348   aop.op = op;
    349   aop.name = "SplitSourceCopyTestOp";
    350   vector<AnnotatedOperation> result_ops;
    351   EXPECT_TRUE(ABGenerator::SplitSourceCopy(aop, &result_ops));
    352   EXPECT_EQ(3U, result_ops.size());
    353 
    354   EXPECT_EQ("SplitSourceCopyTestOp:0", result_ops[0].name);
    355   InstallOperation first_op = result_ops[0].op;
    356   EXPECT_EQ(InstallOperation::SOURCE_COPY, first_op.type());
    357   EXPECT_FALSE(first_op.has_src_length());
    358   EXPECT_EQ(1, first_op.src_extents().size());
    359   EXPECT_EQ(2U, first_op.src_extents(0).start_block());
    360   EXPECT_EQ(2U, first_op.src_extents(0).num_blocks());
    361   EXPECT_FALSE(first_op.has_dst_length());
    362   EXPECT_EQ(1, first_op.dst_extents().size());
    363   EXPECT_EQ(10U, first_op.dst_extents(0).start_block());
    364   EXPECT_EQ(2U, first_op.dst_extents(0).num_blocks());
    365 
    366   EXPECT_EQ("SplitSourceCopyTestOp:1", result_ops[1].name);
    367   InstallOperation second_op = result_ops[1].op;
    368   EXPECT_EQ(InstallOperation::SOURCE_COPY, second_op.type());
    369   EXPECT_FALSE(second_op.has_src_length());
    370   EXPECT_EQ(3, second_op.src_extents().size());
    371   EXPECT_EQ(4U, second_op.src_extents(0).start_block());
    372   EXPECT_EQ(1U, second_op.src_extents(0).num_blocks());
    373   EXPECT_EQ(6U, second_op.src_extents(1).start_block());
    374   EXPECT_EQ(1U, second_op.src_extents(1).num_blocks());
    375   EXPECT_EQ(8U, second_op.src_extents(2).start_block());
    376   EXPECT_EQ(1U, second_op.src_extents(2).num_blocks());
    377   EXPECT_FALSE(second_op.has_dst_length());
    378   EXPECT_EQ(1, second_op.dst_extents().size());
    379   EXPECT_EQ(14U, second_op.dst_extents(0).start_block());
    380   EXPECT_EQ(3U, second_op.dst_extents(0).num_blocks());
    381 
    382   EXPECT_EQ("SplitSourceCopyTestOp:2", result_ops[2].name);
    383   InstallOperation third_op = result_ops[2].op;
    384   EXPECT_EQ(InstallOperation::SOURCE_COPY, third_op.type());
    385   EXPECT_FALSE(third_op.has_src_length());
    386   EXPECT_EQ(1, third_op.src_extents().size());
    387   EXPECT_EQ(9U, third_op.src_extents(0).start_block());
    388   EXPECT_EQ(3U, third_op.src_extents(0).num_blocks());
    389   EXPECT_FALSE(third_op.has_dst_length());
    390   EXPECT_EQ(1, third_op.dst_extents().size());
    391   EXPECT_EQ(18U, third_op.dst_extents(0).start_block());
    392   EXPECT_EQ(3U, third_op.dst_extents(0).num_blocks());
    393 }
    394 
    395 TEST_F(ABGeneratorTest, SplitReplaceTest) {
    396   TestSplitReplaceOrReplaceBzOperation(InstallOperation::REPLACE, false);
    397 }
    398 
    399 TEST_F(ABGeneratorTest, SplitReplaceIntoReplaceBzTest) {
    400   TestSplitReplaceOrReplaceBzOperation(InstallOperation::REPLACE, true);
    401 }
    402 
    403 TEST_F(ABGeneratorTest, SplitReplaceBzTest) {
    404   TestSplitReplaceOrReplaceBzOperation(InstallOperation::REPLACE_BZ, true);
    405 }
    406 
    407 TEST_F(ABGeneratorTest, SplitReplaceBzIntoReplaceTest) {
    408   TestSplitReplaceOrReplaceBzOperation(InstallOperation::REPLACE_BZ, false);
    409 }
    410 
    411 TEST_F(ABGeneratorTest, SortOperationsByDestinationTest) {
    412   vector<AnnotatedOperation> aops;
    413   // One operation with multiple destination extents.
    414   InstallOperation first_op;
    415   *(first_op.add_dst_extents()) = ExtentForRange(6, 1);
    416   *(first_op.add_dst_extents()) = ExtentForRange(10, 2);
    417   AnnotatedOperation first_aop;
    418   first_aop.op = first_op;
    419   first_aop.name = "first";
    420   aops.push_back(first_aop);
    421 
    422   // One with no destination extent. Should end up at the end of the vector.
    423   InstallOperation second_op;
    424   AnnotatedOperation second_aop;
    425   second_aop.op = second_op;
    426   second_aop.name = "second";
    427   aops.push_back(second_aop);
    428 
    429   // One with one destination extent.
    430   InstallOperation third_op;
    431   *(third_op.add_dst_extents()) = ExtentForRange(3, 2);
    432   AnnotatedOperation third_aop;
    433   third_aop.op = third_op;
    434   third_aop.name = "third";
    435   aops.push_back(third_aop);
    436 
    437   ABGenerator::SortOperationsByDestination(&aops);
    438   EXPECT_EQ(3U, aops.size());
    439   EXPECT_EQ(third_aop.name, aops[0].name);
    440   EXPECT_EQ(first_aop.name, aops[1].name);
    441   EXPECT_EQ(second_aop.name, aops[2].name);
    442 }
    443 
    444 TEST_F(ABGeneratorTest, MergeSourceCopyOperationsTest) {
    445   vector<AnnotatedOperation> aops;
    446   InstallOperation first_op;
    447   first_op.set_type(InstallOperation::SOURCE_COPY);
    448   *(first_op.add_src_extents()) = ExtentForRange(1, 1);
    449   *(first_op.add_dst_extents()) = ExtentForRange(6, 1);
    450   AnnotatedOperation first_aop;
    451   first_aop.op = first_op;
    452   first_aop.name = "1";
    453   aops.push_back(first_aop);
    454 
    455   InstallOperation second_op;
    456   second_op.set_type(InstallOperation::SOURCE_COPY);
    457   *(second_op.add_src_extents()) = ExtentForRange(2, 2);
    458   *(second_op.add_src_extents()) = ExtentForRange(8, 2);
    459   *(second_op.add_dst_extents()) = ExtentForRange(7, 3);
    460   *(second_op.add_dst_extents()) = ExtentForRange(11, 1);
    461   AnnotatedOperation second_aop;
    462   second_aop.op = second_op;
    463   second_aop.name = "2";
    464   aops.push_back(second_aop);
    465 
    466   InstallOperation third_op;
    467   third_op.set_type(InstallOperation::SOURCE_COPY);
    468   *(third_op.add_src_extents()) = ExtentForRange(11, 1);
    469   *(third_op.add_dst_extents()) = ExtentForRange(12, 1);
    470   AnnotatedOperation third_aop;
    471   third_aop.op = third_op;
    472   third_aop.name = "3";
    473   aops.push_back(third_aop);
    474 
    475   BlobFileWriter blob_file(0, nullptr);
    476   PayloadVersion version(kChromeOSMajorPayloadVersion,
    477                          kSourceMinorPayloadVersion);
    478   EXPECT_TRUE(ABGenerator::MergeOperations(&aops, version, 5, "", &blob_file));
    479 
    480   EXPECT_EQ(1U, aops.size());
    481   InstallOperation first_result_op = aops[0].op;
    482   EXPECT_EQ(InstallOperation::SOURCE_COPY, first_result_op.type());
    483   EXPECT_FALSE(first_result_op.has_src_length());
    484   EXPECT_EQ(3, first_result_op.src_extents().size());
    485   EXPECT_TRUE(ExtentEquals(first_result_op.src_extents(0), 1, 3));
    486   EXPECT_TRUE(ExtentEquals(first_result_op.src_extents(1), 8, 2));
    487   EXPECT_TRUE(ExtentEquals(first_result_op.src_extents(2), 11, 1));
    488   EXPECT_FALSE(first_result_op.has_dst_length());
    489   EXPECT_EQ(2, first_result_op.dst_extents().size());
    490   EXPECT_TRUE(ExtentEquals(first_result_op.dst_extents(0), 6, 4));
    491   EXPECT_TRUE(ExtentEquals(first_result_op.dst_extents(1), 11, 2));
    492   EXPECT_EQ(aops[0].name, "1,2,3");
    493 }
    494 
    495 TEST_F(ABGeneratorTest, MergeReplaceOperationsTest) {
    496   TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE, false);
    497 }
    498 
    499 TEST_F(ABGeneratorTest, MergeReplaceOperationsToReplaceBzTest) {
    500   TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE, true);
    501 }
    502 
    503 TEST_F(ABGeneratorTest, MergeReplaceBzOperationsTest) {
    504   TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE_BZ, true);
    505 }
    506 
    507 TEST_F(ABGeneratorTest, MergeReplaceBzOperationsToReplaceTest) {
    508   TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE_BZ, false);
    509 }
    510 
    511 TEST_F(ABGeneratorTest, NoMergeOperationsTest) {
    512   // Test to make sure we don't merge operations that shouldn't be merged.
    513   vector<AnnotatedOperation> aops;
    514   InstallOperation first_op;
    515   first_op.set_type(InstallOperation::ZERO);
    516   *(first_op.add_dst_extents()) = ExtentForRange(0, 1);
    517   AnnotatedOperation first_aop;
    518   first_aop.op = first_op;
    519   aops.push_back(first_aop);
    520 
    521   // Should merge with first, except op types don't match...
    522   InstallOperation second_op;
    523   second_op.set_type(InstallOperation::REPLACE);
    524   *(second_op.add_dst_extents()) = ExtentForRange(1, 2);
    525   second_op.set_data_length(2 * kBlockSize);
    526   AnnotatedOperation second_aop;
    527   second_aop.op = second_op;
    528   aops.push_back(second_aop);
    529 
    530   // Should merge with second, except it would exceed chunk size...
    531   InstallOperation third_op;
    532   third_op.set_type(InstallOperation::REPLACE);
    533   *(third_op.add_dst_extents()) = ExtentForRange(3, 3);
    534   third_op.set_data_length(3 * kBlockSize);
    535   AnnotatedOperation third_aop;
    536   third_aop.op = third_op;
    537   aops.push_back(third_aop);
    538 
    539   // Should merge with third, except they aren't contiguous...
    540   InstallOperation fourth_op;
    541   fourth_op.set_type(InstallOperation::REPLACE);
    542   *(fourth_op.add_dst_extents()) = ExtentForRange(7, 2);
    543   fourth_op.set_data_length(2 * kBlockSize);
    544   AnnotatedOperation fourth_aop;
    545   fourth_aop.op = fourth_op;
    546   aops.push_back(fourth_aop);
    547 
    548   BlobFileWriter blob_file(0, nullptr);
    549   PayloadVersion version(kChromeOSMajorPayloadVersion,
    550                          kSourceMinorPayloadVersion);
    551   EXPECT_TRUE(ABGenerator::MergeOperations(&aops, version, 4, "", &blob_file));
    552 
    553   // No operations were merged, the number of ops is the same.
    554   EXPECT_EQ(4U, aops.size());
    555 }
    556 
    557 TEST_F(ABGeneratorTest, AddSourceHashTest) {
    558   vector<AnnotatedOperation> aops;
    559   InstallOperation first_op;
    560   first_op.set_type(InstallOperation::SOURCE_COPY);
    561   first_op.set_src_length(kBlockSize);
    562   *(first_op.add_src_extents()) = ExtentForRange(0, 1);
    563   AnnotatedOperation first_aop;
    564   first_aop.op = first_op;
    565   aops.push_back(first_aop);
    566 
    567   InstallOperation second_op;
    568   second_op.set_type(InstallOperation::REPLACE);
    569   AnnotatedOperation second_aop;
    570   second_aop.op = second_op;
    571   aops.push_back(second_aop);
    572 
    573   string src_part_path;
    574   EXPECT_TRUE(utils::MakeTempFile("AddSourceHashTest_src_part.XXXXXX",
    575                                   &src_part_path, nullptr));
    576   ScopedPathUnlinker src_part_path_unlinker(src_part_path);
    577   brillo::Blob src_data(kBlockSize);
    578   test_utils::FillWithData(&src_data);
    579   ASSERT_TRUE(utils::WriteFile(src_part_path.c_str(), src_data.data(),
    580                                src_data.size()));
    581 
    582   EXPECT_TRUE(ABGenerator::AddSourceHash(&aops, src_part_path));
    583 
    584   EXPECT_TRUE(aops[0].op.has_src_sha256_hash());
    585   EXPECT_FALSE(aops[1].op.has_src_sha256_hash());
    586   brillo::Blob expected_hash;
    587   EXPECT_TRUE(HashCalculator::RawHashOfData(src_data, &expected_hash));
    588   brillo::Blob result_hash(aops[0].op.src_sha256_hash().begin(),
    589                            aops[0].op.src_sha256_hash().end());
    590   EXPECT_EQ(expected_hash, result_hash);
    591 }
    592 
    593 }  // namespace chromeos_update_engine
    594