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