• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ExtentEquals(const Extent & ext,uint64_t start_block,uint64_t num_blocks)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.
TestSplitReplaceOrReplaceBzOperation(InstallOperation_Type orig_type,bool compressible)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.
TestMergeReplaceOrReplaceBzOperations(InstallOperation_Type orig_type,bool compressible)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 
TEST_F(ABGeneratorTest,SplitSourceCopyTest)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 
TEST_F(ABGeneratorTest,SplitReplaceTest)395 TEST_F(ABGeneratorTest, SplitReplaceTest) {
396   TestSplitReplaceOrReplaceBzOperation(InstallOperation::REPLACE, false);
397 }
398 
TEST_F(ABGeneratorTest,SplitReplaceIntoReplaceBzTest)399 TEST_F(ABGeneratorTest, SplitReplaceIntoReplaceBzTest) {
400   TestSplitReplaceOrReplaceBzOperation(InstallOperation::REPLACE, true);
401 }
402 
TEST_F(ABGeneratorTest,SplitReplaceBzTest)403 TEST_F(ABGeneratorTest, SplitReplaceBzTest) {
404   TestSplitReplaceOrReplaceBzOperation(InstallOperation::REPLACE_BZ, true);
405 }
406 
TEST_F(ABGeneratorTest,SplitReplaceBzIntoReplaceTest)407 TEST_F(ABGeneratorTest, SplitReplaceBzIntoReplaceTest) {
408   TestSplitReplaceOrReplaceBzOperation(InstallOperation::REPLACE_BZ, false);
409 }
410 
TEST_F(ABGeneratorTest,SortOperationsByDestinationTest)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 
TEST_F(ABGeneratorTest,MergeSourceCopyOperationsTest)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 
TEST_F(ABGeneratorTest,MergeReplaceOperationsTest)501 TEST_F(ABGeneratorTest, MergeReplaceOperationsTest) {
502   TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE, false);
503 }
504 
TEST_F(ABGeneratorTest,MergeReplaceOperationsToReplaceBzTest)505 TEST_F(ABGeneratorTest, MergeReplaceOperationsToReplaceBzTest) {
506   TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE, true);
507 }
508 
TEST_F(ABGeneratorTest,MergeReplaceBzOperationsTest)509 TEST_F(ABGeneratorTest, MergeReplaceBzOperationsTest) {
510   TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE_BZ, true);
511 }
512 
TEST_F(ABGeneratorTest,MergeReplaceBzOperationsToReplaceTest)513 TEST_F(ABGeneratorTest, MergeReplaceBzOperationsToReplaceTest) {
514   TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE_BZ, false);
515 }
516 
TEST_F(ABGeneratorTest,NoMergeOperationsTest)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 
TEST_F(ABGeneratorTest,AddSourceHashTest)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