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 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. 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. 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 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 386 TEST_F(ABGeneratorTest, SplitReplaceTest) { 387 TestSplitReplaceOrReplaceBzOperation(InstallOperation::REPLACE, false); 388 } 389 390 TEST_F(ABGeneratorTest, SplitReplaceIntoReplaceBzTest) { 391 TestSplitReplaceOrReplaceBzOperation(InstallOperation::REPLACE, true); 392 } 393 394 TEST_F(ABGeneratorTest, SplitReplaceBzTest) { 395 TestSplitReplaceOrReplaceBzOperation(InstallOperation::REPLACE_BZ, true); 396 } 397 398 TEST_F(ABGeneratorTest, SplitReplaceBzIntoReplaceTest) { 399 TestSplitReplaceOrReplaceBzOperation(InstallOperation::REPLACE_BZ, false); 400 } 401 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 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 486 TEST_F(ABGeneratorTest, MergeReplaceOperationsTest) { 487 TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE, false); 488 } 489 490 TEST_F(ABGeneratorTest, MergeReplaceOperationsToReplaceBzTest) { 491 TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE, true); 492 } 493 494 TEST_F(ABGeneratorTest, MergeReplaceBzOperationsTest) { 495 TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE_BZ, true); 496 } 497 498 TEST_F(ABGeneratorTest, MergeReplaceBzOperationsToReplaceTest) { 499 TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE_BZ, false); 500 } 501 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 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