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