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, uint64_t start_block, uint64_t num_blocks) {
     46   return ext.start_block() == start_block && ext.num_blocks() == num_blocks;
     47 }
     48 
     49 // Tests splitting of a REPLACE/REPLACE_BZ operation.
     50 void TestSplitReplaceOrReplaceBzOperation(InstallOperation_Type orig_type,
     51                                           bool compressible) {
     52   const size_t op_ex1_start_block = 2;
     53   const size_t op_ex1_num_blocks = 2;
     54   const size_t op_ex2_start_block = 6;
     55   const size_t op_ex2_num_blocks = 1;
     56   const size_t part_num_blocks = 7;
     57 
     58   // Create the target partition data.
     59   string part_path;
     60   EXPECT_TRUE(utils::MakeTempFile(
     61       "SplitReplaceOrReplaceBzTest_part.XXXXXX", &part_path, nullptr));
     62   ScopedPathUnlinker part_path_unlinker(part_path);
     63   const size_t part_size = part_num_blocks * kBlockSize;
     64   brillo::Blob part_data;
     65   if (compressible) {
     66     part_data.resize(part_size);
     67     test_utils::FillWithData(&part_data);
     68   } else {
     69     std::mt19937 gen(12345);
     70     std::uniform_int_distribution<uint8_t> dis(0, 255);
     71     for (uint32_t i = 0; i < part_size; i++)
     72       part_data.push_back(dis(gen));
     73   }
     74   ASSERT_EQ(part_size, part_data.size());
     75   ASSERT_TRUE(utils::WriteFile(part_path.c_str(), part_data.data(), part_size));
     76 
     77   // Create original operation and blob data.
     78   const size_t op_ex1_offset = op_ex1_start_block * kBlockSize;
     79   const size_t op_ex1_size = op_ex1_num_blocks * kBlockSize;
     80   const size_t op_ex2_offset = op_ex2_start_block * kBlockSize;
     81   const size_t op_ex2_size = op_ex2_num_blocks * kBlockSize;
     82   InstallOperation op;
     83   op.set_type(orig_type);
     84   *(op.add_dst_extents()) = ExtentForRange(op_ex1_start_block,
     85                                            op_ex1_num_blocks);
     86   *(op.add_dst_extents()) = ExtentForRange(op_ex2_start_block,
     87                                            op_ex2_num_blocks);
     88   op.set_dst_length(op_ex1_num_blocks + op_ex2_num_blocks);
     89 
     90   brillo::Blob op_data;
     91   op_data.insert(op_data.end(),
     92                  part_data.begin() + op_ex1_offset,
     93                  part_data.begin() + op_ex1_offset + op_ex1_size);
     94   op_data.insert(op_data.end(),
     95                  part_data.begin() + op_ex2_offset,
     96                  part_data.begin() + op_ex2_offset + op_ex2_size);
     97   brillo::Blob op_blob;
     98   if (orig_type == InstallOperation::REPLACE) {
     99     op_blob = op_data;
    100   } else {
    101     ASSERT_TRUE(BzipCompress(op_data, &op_blob));
    102   }
    103   op.set_data_offset(0);
    104   op.set_data_length(op_blob.size());
    105 
    106   AnnotatedOperation aop;
    107   aop.op = op;
    108   aop.name = "SplitTestOp";
    109 
    110   // Create the data file.
    111   string data_path;
    112   EXPECT_TRUE(utils::MakeTempFile(
    113       "SplitReplaceOrReplaceBzTest_data.XXXXXX", &data_path, nullptr));
    114   ScopedPathUnlinker data_path_unlinker(data_path);
    115   int data_fd = open(data_path.c_str(), O_RDWR, 000);
    116   EXPECT_GE(data_fd, 0);
    117   ScopedFdCloser data_fd_closer(&data_fd);
    118   EXPECT_TRUE(utils::WriteFile(data_path.c_str(), op_blob.data(),
    119                                op_blob.size()));
    120   off_t data_file_size = op_blob.size();
    121   BlobFileWriter blob_file(data_fd, &data_file_size);
    122 
    123   // Split the operation.
    124   vector<AnnotatedOperation> result_ops;
    125   PayloadVersion version(kChromeOSMajorPayloadVersion,
    126                          kSourceMinorPayloadVersion);
    127   ASSERT_TRUE(ABGenerator::SplitAReplaceOp(
    128       version, aop, part_path, &result_ops, &blob_file));
    129 
    130   // Check the result.
    131   InstallOperation_Type expected_type =
    132       compressible ? InstallOperation::REPLACE_BZ : InstallOperation::REPLACE;
    133 
    134   ASSERT_EQ(2U, result_ops.size());
    135 
    136   EXPECT_EQ("SplitTestOp:0", result_ops[0].name);
    137   InstallOperation first_op = result_ops[0].op;
    138   EXPECT_EQ(expected_type, first_op.type());
    139   EXPECT_EQ(op_ex1_size, first_op.dst_length());
    140   EXPECT_EQ(1, first_op.dst_extents().size());
    141   EXPECT_TRUE(ExtentEquals(first_op.dst_extents(0), op_ex1_start_block,
    142                            op_ex1_num_blocks));
    143   // Obtain the expected blob.
    144   brillo::Blob first_expected_data(
    145       part_data.begin() + op_ex1_offset,
    146       part_data.begin() + op_ex1_offset + op_ex1_size);
    147   brillo::Blob first_expected_blob;
    148   if (compressible) {
    149     ASSERT_TRUE(BzipCompress(first_expected_data, &first_expected_blob));
    150   } else {
    151     first_expected_blob = first_expected_data;
    152   }
    153   EXPECT_EQ(first_expected_blob.size(), first_op.data_length());
    154   // Check that the actual blob matches what's expected.
    155   brillo::Blob first_data_blob(first_op.data_length());
    156   ssize_t bytes_read;
    157   ASSERT_TRUE(utils::PReadAll(data_fd,
    158                               first_data_blob.data(),
    159                               first_op.data_length(),
    160                               first_op.data_offset(),
    161                               &bytes_read));
    162   ASSERT_EQ(bytes_read, static_cast<ssize_t>(first_op.data_length()));
    163   EXPECT_EQ(first_expected_blob, first_data_blob);
    164 
    165   EXPECT_EQ("SplitTestOp:1", result_ops[1].name);
    166   InstallOperation second_op = result_ops[1].op;
    167   EXPECT_EQ(expected_type, second_op.type());
    168   EXPECT_EQ(op_ex2_size, second_op.dst_length());
    169   EXPECT_EQ(1, second_op.dst_extents().size());
    170   EXPECT_TRUE(ExtentEquals(second_op.dst_extents(0), op_ex2_start_block,
    171                            op_ex2_num_blocks));
    172   // Obtain the expected blob.
    173   brillo::Blob second_expected_data(
    174       part_data.begin() + op_ex2_offset,
    175       part_data.begin() + op_ex2_offset + op_ex2_size);
    176   brillo::Blob second_expected_blob;
    177   if (compressible) {
    178     ASSERT_TRUE(BzipCompress(second_expected_data, &second_expected_blob));
    179   } else {
    180     second_expected_blob = second_expected_data;
    181   }
    182   EXPECT_EQ(second_expected_blob.size(), second_op.data_length());
    183   // Check that the actual blob matches what's expected.
    184   brillo::Blob second_data_blob(second_op.data_length());
    185   ASSERT_TRUE(utils::PReadAll(data_fd,
    186                               second_data_blob.data(),
    187                               second_op.data_length(),
    188                               second_op.data_offset(),
    189                               &bytes_read));
    190   ASSERT_EQ(bytes_read, static_cast<ssize_t>(second_op.data_length()));
    191   EXPECT_EQ(second_expected_blob, second_data_blob);
    192 
    193   // Check relative layout of data blobs.
    194   EXPECT_EQ(first_op.data_offset() + first_op.data_length(),
    195             second_op.data_offset());
    196   EXPECT_EQ(second_op.data_offset() + second_op.data_length(), data_file_size);
    197   // If we split a REPLACE into multiple ones, ensure reuse of preexisting blob.
    198   if (!compressible && orig_type == InstallOperation::REPLACE) {
    199     EXPECT_EQ(0U, first_op.data_offset());
    200   }
    201 }
    202 
    203 // Tests merging of REPLACE/REPLACE_BZ operations.
    204 void TestMergeReplaceOrReplaceBzOperations(InstallOperation_Type orig_type,
    205                                            bool compressible) {
    206   const size_t first_op_num_blocks = 1;
    207   const size_t second_op_num_blocks = 2;
    208   const size_t total_op_num_blocks = first_op_num_blocks + second_op_num_blocks;
    209   const size_t part_num_blocks = total_op_num_blocks + 2;
    210 
    211   // Create the target partition data.
    212   string part_path;
    213   EXPECT_TRUE(utils::MakeTempFile(
    214       "MergeReplaceOrReplaceBzTest_part.XXXXXX", &part_path, nullptr));
    215   ScopedPathUnlinker part_path_unlinker(part_path);
    216   const size_t part_size = part_num_blocks * kBlockSize;
    217   brillo::Blob part_data;
    218   if (compressible) {
    219     part_data.resize(part_size);
    220     test_utils::FillWithData(&part_data);
    221   } else {
    222     std::mt19937 gen(12345);
    223     std::uniform_int_distribution<uint8_t> dis(0, 255);
    224     for (uint32_t i = 0; i < part_size; i++)
    225       part_data.push_back(dis(gen));
    226   }
    227   ASSERT_EQ(part_size, part_data.size());
    228   ASSERT_TRUE(utils::WriteFile(part_path.c_str(), part_data.data(), part_size));
    229 
    230   // Create original operations and blob data.
    231   vector<AnnotatedOperation> aops;
    232   brillo::Blob blob_data;
    233   const size_t total_op_size = total_op_num_blocks * kBlockSize;
    234 
    235   InstallOperation first_op;
    236   first_op.set_type(orig_type);
    237   const size_t first_op_size = first_op_num_blocks * kBlockSize;
    238   first_op.set_dst_length(first_op_size);
    239   *(first_op.add_dst_extents()) = ExtentForRange(0, first_op_num_blocks);
    240   brillo::Blob first_op_data(part_data.begin(),
    241                                part_data.begin() + first_op_size);
    242   brillo::Blob first_op_blob;
    243   if (orig_type == InstallOperation::REPLACE) {
    244     first_op_blob = first_op_data;
    245   } else {
    246     ASSERT_TRUE(BzipCompress(first_op_data, &first_op_blob));
    247   }
    248   first_op.set_data_offset(0);
    249   first_op.set_data_length(first_op_blob.size());
    250   blob_data.insert(blob_data.end(), first_op_blob.begin(), first_op_blob.end());
    251   AnnotatedOperation first_aop;
    252   first_aop.op = first_op;
    253   first_aop.name = "first";
    254   aops.push_back(first_aop);
    255 
    256   InstallOperation second_op;
    257   second_op.set_type(orig_type);
    258   const size_t second_op_size = second_op_num_blocks * kBlockSize;
    259   second_op.set_dst_length(second_op_size);
    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_EQ(total_op_num_blocks * kBlockSize, new_op.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_EQ(kBlockSize * 2, first_op.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_EQ(kBlockSize * 2, first_op.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_EQ(kBlockSize * 3, second_op.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_EQ(kBlockSize * 3, second_op.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_EQ(kBlockSize * 3, third_op.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_EQ(kBlockSize * 3, third_op.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.set_src_length(kBlockSize);
    449   first_op.set_dst_length(kBlockSize);
    450   *(first_op.add_src_extents()) = ExtentForRange(1, 1);
    451   *(first_op.add_dst_extents()) = ExtentForRange(6, 1);
    452   AnnotatedOperation first_aop;
    453   first_aop.op = first_op;
    454   first_aop.name = "1";
    455   aops.push_back(first_aop);
    456 
    457   InstallOperation second_op;
    458   second_op.set_type(InstallOperation::SOURCE_COPY);
    459   second_op.set_src_length(3 * kBlockSize);
    460   second_op.set_dst_length(3 * kBlockSize);
    461   *(second_op.add_src_extents()) = ExtentForRange(2, 2);
    462   *(second_op.add_src_extents()) = ExtentForRange(8, 2);
    463   *(second_op.add_dst_extents()) = ExtentForRange(7, 3);
    464   *(second_op.add_dst_extents()) = ExtentForRange(11, 1);
    465   AnnotatedOperation second_aop;
    466   second_aop.op = second_op;
    467   second_aop.name = "2";
    468   aops.push_back(second_aop);
    469 
    470   InstallOperation third_op;
    471   third_op.set_type(InstallOperation::SOURCE_COPY);
    472   third_op.set_src_length(kBlockSize);
    473   third_op.set_dst_length(kBlockSize);
    474   *(third_op.add_src_extents()) = ExtentForRange(11, 1);
    475   *(third_op.add_dst_extents()) = ExtentForRange(12, 1);
    476   AnnotatedOperation third_aop;
    477   third_aop.op = third_op;
    478   third_aop.name = "3";
    479   aops.push_back(third_aop);
    480 
    481   BlobFileWriter blob_file(0, nullptr);
    482   PayloadVersion version(kChromeOSMajorPayloadVersion,
    483                          kSourceMinorPayloadVersion);
    484   EXPECT_TRUE(ABGenerator::MergeOperations(&aops, version, 5, "", &blob_file));
    485 
    486   EXPECT_EQ(1U, aops.size());
    487   InstallOperation first_result_op = aops[0].op;
    488   EXPECT_EQ(InstallOperation::SOURCE_COPY, first_result_op.type());
    489   EXPECT_EQ(kBlockSize * 5, first_result_op.src_length());
    490   EXPECT_EQ(3, first_result_op.src_extents().size());
    491   EXPECT_TRUE(ExtentEquals(first_result_op.src_extents(0), 1, 3));
    492   EXPECT_TRUE(ExtentEquals(first_result_op.src_extents(1), 8, 2));
    493   EXPECT_TRUE(ExtentEquals(first_result_op.src_extents(2), 11, 1));
    494   EXPECT_EQ(kBlockSize * 5, first_result_op.dst_length());
    495   EXPECT_EQ(2, first_result_op.dst_extents().size());
    496   EXPECT_TRUE(ExtentEquals(first_result_op.dst_extents(0), 6, 4));
    497   EXPECT_TRUE(ExtentEquals(first_result_op.dst_extents(1), 11, 2));
    498   EXPECT_EQ(aops[0].name, "1,2,3");
    499 }
    500 
    501 TEST_F(ABGeneratorTest, MergeReplaceOperationsTest) {
    502   TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE, false);
    503 }
    504 
    505 TEST_F(ABGeneratorTest, MergeReplaceOperationsToReplaceBzTest) {
    506   TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE, true);
    507 }
    508 
    509 TEST_F(ABGeneratorTest, MergeReplaceBzOperationsTest) {
    510   TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE_BZ, true);
    511 }
    512 
    513 TEST_F(ABGeneratorTest, MergeReplaceBzOperationsToReplaceTest) {
    514   TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE_BZ, false);
    515 }
    516 
    517 TEST_F(ABGeneratorTest, NoMergeOperationsTest) {
    518   // Test to make sure we don't merge operations that shouldn't be merged.
    519   vector<AnnotatedOperation> aops;
    520   InstallOperation first_op;
    521   first_op.set_type(InstallOperation::ZERO);
    522   *(first_op.add_dst_extents()) = ExtentForRange(0, 1);
    523   AnnotatedOperation first_aop;
    524   first_aop.op = first_op;
    525   aops.push_back(first_aop);
    526 
    527   // Should merge with first, except op types don't match...
    528   InstallOperation second_op;
    529   second_op.set_type(InstallOperation::REPLACE);
    530   *(second_op.add_dst_extents()) = ExtentForRange(1, 2);
    531   second_op.set_data_length(2 * kBlockSize);
    532   AnnotatedOperation second_aop;
    533   second_aop.op = second_op;
    534   aops.push_back(second_aop);
    535 
    536   // Should merge with second, except it would exceed chunk size...
    537   InstallOperation third_op;
    538   third_op.set_type(InstallOperation::REPLACE);
    539   *(third_op.add_dst_extents()) = ExtentForRange(3, 3);
    540   third_op.set_data_length(3 * kBlockSize);
    541   AnnotatedOperation third_aop;
    542   third_aop.op = third_op;
    543   aops.push_back(third_aop);
    544 
    545   // Should merge with third, except they aren't contiguous...
    546   InstallOperation fourth_op;
    547   fourth_op.set_type(InstallOperation::REPLACE);
    548   *(fourth_op.add_dst_extents()) = ExtentForRange(7, 2);
    549   fourth_op.set_data_length(2 * kBlockSize);
    550   AnnotatedOperation fourth_aop;
    551   fourth_aop.op = fourth_op;
    552   aops.push_back(fourth_aop);
    553 
    554   BlobFileWriter blob_file(0, nullptr);
    555   PayloadVersion version(kChromeOSMajorPayloadVersion,
    556                          kSourceMinorPayloadVersion);
    557   EXPECT_TRUE(ABGenerator::MergeOperations(&aops, version, 4, "", &blob_file));
    558 
    559   // No operations were merged, the number of ops is the same.
    560   EXPECT_EQ(4U, aops.size());
    561 }
    562 
    563 TEST_F(ABGeneratorTest, AddSourceHashTest) {
    564   vector<AnnotatedOperation> aops;
    565   InstallOperation first_op;
    566   first_op.set_type(InstallOperation::SOURCE_COPY);
    567   first_op.set_src_length(kBlockSize);
    568   *(first_op.add_src_extents()) = ExtentForRange(0, 1);
    569   AnnotatedOperation first_aop;
    570   first_aop.op = first_op;
    571   aops.push_back(first_aop);
    572 
    573   InstallOperation second_op;
    574   second_op.set_type(InstallOperation::REPLACE);
    575   AnnotatedOperation second_aop;
    576   second_aop.op = second_op;
    577   aops.push_back(second_aop);
    578 
    579   string src_part_path;
    580   EXPECT_TRUE(utils::MakeTempFile("AddSourceHashTest_src_part.XXXXXX",
    581                                   &src_part_path, nullptr));
    582   ScopedPathUnlinker src_part_path_unlinker(src_part_path);
    583   brillo::Blob src_data(kBlockSize);
    584   test_utils::FillWithData(&src_data);
    585   ASSERT_TRUE(utils::WriteFile(src_part_path.c_str(), src_data.data(),
    586                                src_data.size()));
    587 
    588   EXPECT_TRUE(ABGenerator::AddSourceHash(&aops, src_part_path));
    589 
    590   EXPECT_TRUE(aops[0].op.has_src_sha256_hash());
    591   EXPECT_FALSE(aops[1].op.has_src_sha256_hash());
    592   brillo::Blob expected_hash;
    593   EXPECT_TRUE(HashCalculator::RawHashOfData(src_data, &expected_hash));
    594   brillo::Blob result_hash(aops[0].op.src_sha256_hash().begin(),
    595                            aops[0].op.src_sha256_hash().end());
    596   EXPECT_EQ(expected_hash, result_hash);
    597 }
    598 
    599 }  // namespace chromeos_update_engine
    600