ab_generator_unittest.cc revision 73b18b83ebae881cefa6fb2b0563a0b94c17bcde
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 38using std::string; 39using std::vector; 40 41namespace chromeos_update_engine { 42 43namespace { 44 45bool 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. 50void 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. 204void 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 335class ABGeneratorTest : public ::testing::Test {}; 336 337TEST_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_FALSE(first_op.has_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_FALSE(first_op.has_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_FALSE(second_op.has_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_FALSE(second_op.has_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_FALSE(third_op.has_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_FALSE(third_op.has_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 395TEST_F(ABGeneratorTest, SplitReplaceTest) { 396 TestSplitReplaceOrReplaceBzOperation(InstallOperation::REPLACE, false); 397} 398 399TEST_F(ABGeneratorTest, SplitReplaceIntoReplaceBzTest) { 400 TestSplitReplaceOrReplaceBzOperation(InstallOperation::REPLACE, true); 401} 402 403TEST_F(ABGeneratorTest, SplitReplaceBzTest) { 404 TestSplitReplaceOrReplaceBzOperation(InstallOperation::REPLACE_BZ, true); 405} 406 407TEST_F(ABGeneratorTest, SplitReplaceBzIntoReplaceTest) { 408 TestSplitReplaceOrReplaceBzOperation(InstallOperation::REPLACE_BZ, false); 409} 410 411TEST_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 444TEST_F(ABGeneratorTest, MergeSourceCopyOperationsTest) { 445 vector<AnnotatedOperation> aops; 446 InstallOperation first_op; 447 first_op.set_type(InstallOperation::SOURCE_COPY); 448 *(first_op.add_src_extents()) = ExtentForRange(1, 1); 449 *(first_op.add_dst_extents()) = ExtentForRange(6, 1); 450 AnnotatedOperation first_aop; 451 first_aop.op = first_op; 452 first_aop.name = "1"; 453 aops.push_back(first_aop); 454 455 InstallOperation second_op; 456 second_op.set_type(InstallOperation::SOURCE_COPY); 457 *(second_op.add_src_extents()) = ExtentForRange(2, 2); 458 *(second_op.add_src_extents()) = ExtentForRange(8, 2); 459 *(second_op.add_dst_extents()) = ExtentForRange(7, 3); 460 *(second_op.add_dst_extents()) = ExtentForRange(11, 1); 461 AnnotatedOperation second_aop; 462 second_aop.op = second_op; 463 second_aop.name = "2"; 464 aops.push_back(second_aop); 465 466 InstallOperation third_op; 467 third_op.set_type(InstallOperation::SOURCE_COPY); 468 *(third_op.add_src_extents()) = ExtentForRange(11, 1); 469 *(third_op.add_dst_extents()) = ExtentForRange(12, 1); 470 AnnotatedOperation third_aop; 471 third_aop.op = third_op; 472 third_aop.name = "3"; 473 aops.push_back(third_aop); 474 475 BlobFileWriter blob_file(0, nullptr); 476 PayloadVersion version(kChromeOSMajorPayloadVersion, 477 kSourceMinorPayloadVersion); 478 EXPECT_TRUE(ABGenerator::MergeOperations(&aops, version, 5, "", &blob_file)); 479 480 EXPECT_EQ(1U, aops.size()); 481 InstallOperation first_result_op = aops[0].op; 482 EXPECT_EQ(InstallOperation::SOURCE_COPY, first_result_op.type()); 483 EXPECT_FALSE(first_result_op.has_src_length()); 484 EXPECT_EQ(3, first_result_op.src_extents().size()); 485 EXPECT_TRUE(ExtentEquals(first_result_op.src_extents(0), 1, 3)); 486 EXPECT_TRUE(ExtentEquals(first_result_op.src_extents(1), 8, 2)); 487 EXPECT_TRUE(ExtentEquals(first_result_op.src_extents(2), 11, 1)); 488 EXPECT_FALSE(first_result_op.has_dst_length()); 489 EXPECT_EQ(2, first_result_op.dst_extents().size()); 490 EXPECT_TRUE(ExtentEquals(first_result_op.dst_extents(0), 6, 4)); 491 EXPECT_TRUE(ExtentEquals(first_result_op.dst_extents(1), 11, 2)); 492 EXPECT_EQ(aops[0].name, "1,2,3"); 493} 494 495TEST_F(ABGeneratorTest, MergeReplaceOperationsTest) { 496 TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE, false); 497} 498 499TEST_F(ABGeneratorTest, MergeReplaceOperationsToReplaceBzTest) { 500 TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE, true); 501} 502 503TEST_F(ABGeneratorTest, MergeReplaceBzOperationsTest) { 504 TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE_BZ, true); 505} 506 507TEST_F(ABGeneratorTest, MergeReplaceBzOperationsToReplaceTest) { 508 TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE_BZ, false); 509} 510 511TEST_F(ABGeneratorTest, NoMergeOperationsTest) { 512 // Test to make sure we don't merge operations that shouldn't be merged. 513 vector<AnnotatedOperation> aops; 514 InstallOperation first_op; 515 first_op.set_type(InstallOperation::ZERO); 516 *(first_op.add_dst_extents()) = ExtentForRange(0, 1); 517 AnnotatedOperation first_aop; 518 first_aop.op = first_op; 519 aops.push_back(first_aop); 520 521 // Should merge with first, except op types don't match... 522 InstallOperation second_op; 523 second_op.set_type(InstallOperation::REPLACE); 524 *(second_op.add_dst_extents()) = ExtentForRange(1, 2); 525 second_op.set_data_length(2 * kBlockSize); 526 AnnotatedOperation second_aop; 527 second_aop.op = second_op; 528 aops.push_back(second_aop); 529 530 // Should merge with second, except it would exceed chunk size... 531 InstallOperation third_op; 532 third_op.set_type(InstallOperation::REPLACE); 533 *(third_op.add_dst_extents()) = ExtentForRange(3, 3); 534 third_op.set_data_length(3 * kBlockSize); 535 AnnotatedOperation third_aop; 536 third_aop.op = third_op; 537 aops.push_back(third_aop); 538 539 // Should merge with third, except they aren't contiguous... 540 InstallOperation fourth_op; 541 fourth_op.set_type(InstallOperation::REPLACE); 542 *(fourth_op.add_dst_extents()) = ExtentForRange(7, 2); 543 fourth_op.set_data_length(2 * kBlockSize); 544 AnnotatedOperation fourth_aop; 545 fourth_aop.op = fourth_op; 546 aops.push_back(fourth_aop); 547 548 BlobFileWriter blob_file(0, nullptr); 549 PayloadVersion version(kChromeOSMajorPayloadVersion, 550 kSourceMinorPayloadVersion); 551 EXPECT_TRUE(ABGenerator::MergeOperations(&aops, version, 4, "", &blob_file)); 552 553 // No operations were merged, the number of ops is the same. 554 EXPECT_EQ(4U, aops.size()); 555} 556 557TEST_F(ABGeneratorTest, AddSourceHashTest) { 558 vector<AnnotatedOperation> aops; 559 InstallOperation first_op; 560 first_op.set_type(InstallOperation::SOURCE_COPY); 561 first_op.set_src_length(kBlockSize); 562 *(first_op.add_src_extents()) = ExtentForRange(0, 1); 563 AnnotatedOperation first_aop; 564 first_aop.op = first_op; 565 aops.push_back(first_aop); 566 567 InstallOperation second_op; 568 second_op.set_type(InstallOperation::REPLACE); 569 AnnotatedOperation second_aop; 570 second_aop.op = second_op; 571 aops.push_back(second_aop); 572 573 string src_part_path; 574 EXPECT_TRUE(utils::MakeTempFile("AddSourceHashTest_src_part.XXXXXX", 575 &src_part_path, nullptr)); 576 ScopedPathUnlinker src_part_path_unlinker(src_part_path); 577 brillo::Blob src_data(kBlockSize); 578 test_utils::FillWithData(&src_data); 579 ASSERT_TRUE(utils::WriteFile(src_part_path.c_str(), src_data.data(), 580 src_data.size())); 581 582 EXPECT_TRUE(ABGenerator::AddSourceHash(&aops, src_part_path)); 583 584 EXPECT_TRUE(aops[0].op.has_src_sha256_hash()); 585 EXPECT_FALSE(aops[1].op.has_src_sha256_hash()); 586 brillo::Blob expected_hash; 587 EXPECT_TRUE(HashCalculator::RawHashOfData(src_data, &expected_hash)); 588 brillo::Blob result_hash(aops[0].op.src_sha256_hash().begin(), 589 aops[0].op.src_sha256_hash().end()); 590 EXPECT_EQ(expected_hash, result_hash); 591} 592 593} // namespace chromeos_update_engine 594