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