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