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 string part_path; 62 EXPECT_TRUE(utils::MakeTempFile( 63 "SplitReplaceOrReplaceBzTest_part.XXXXXX", &part_path, nullptr)); 64 ScopedPathUnlinker part_path_unlinker(part_path); 65 const size_t part_size = part_num_blocks * kBlockSize; 66 brillo::Blob part_data; 67 if (compressible) { 68 part_data.resize(part_size); 69 test_utils::FillWithData(&part_data); 70 } else { 71 std::mt19937 gen(12345); 72 std::uniform_int_distribution<uint8_t> dis(0, 255); 73 for (uint32_t i = 0; i < part_size; i++) 74 part_data.push_back(dis(gen)); 75 } 76 ASSERT_EQ(part_size, part_data.size()); 77 ASSERT_TRUE(utils::WriteFile(part_path.c_str(), part_data.data(), part_size)); 78 79 // Create original operation and blob data. 80 const size_t op_ex1_offset = op_ex1_start_block * kBlockSize; 81 const size_t op_ex1_size = op_ex1_num_blocks * kBlockSize; 82 const size_t op_ex2_offset = op_ex2_start_block * kBlockSize; 83 const size_t op_ex2_size = op_ex2_num_blocks * kBlockSize; 84 InstallOperation op; 85 op.set_type(orig_type); 86 *(op.add_dst_extents()) = ExtentForRange(op_ex1_start_block, 87 op_ex1_num_blocks); 88 *(op.add_dst_extents()) = ExtentForRange(op_ex2_start_block, 89 op_ex2_num_blocks); 90 91 brillo::Blob op_data; 92 op_data.insert(op_data.end(), 93 part_data.begin() + op_ex1_offset, 94 part_data.begin() + op_ex1_offset + op_ex1_size); 95 op_data.insert(op_data.end(), 96 part_data.begin() + op_ex2_offset, 97 part_data.begin() + op_ex2_offset + op_ex2_size); 98 brillo::Blob op_blob; 99 if (orig_type == InstallOperation::REPLACE) { 100 op_blob = op_data; 101 } else { 102 ASSERT_TRUE(BzipCompress(op_data, &op_blob)); 103 } 104 op.set_data_offset(0); 105 op.set_data_length(op_blob.size()); 106 107 AnnotatedOperation aop; 108 aop.op = op; 109 aop.name = "SplitTestOp"; 110 111 // Create the data file. 112 string data_path; 113 EXPECT_TRUE(utils::MakeTempFile( 114 "SplitReplaceOrReplaceBzTest_data.XXXXXX", &data_path, nullptr)); 115 ScopedPathUnlinker data_path_unlinker(data_path); 116 int data_fd = open(data_path.c_str(), O_RDWR, 000); 117 EXPECT_GE(data_fd, 0); 118 ScopedFdCloser data_fd_closer(&data_fd); 119 EXPECT_TRUE(utils::WriteFile(data_path.c_str(), op_blob.data(), 120 op_blob.size())); 121 off_t data_file_size = op_blob.size(); 122 BlobFileWriter blob_file(data_fd, &data_file_size); 123 124 // Split the operation. 125 vector<AnnotatedOperation> result_ops; 126 PayloadVersion version(kChromeOSMajorPayloadVersion, 127 kSourceMinorPayloadVersion); 128 ASSERT_TRUE(ABGenerator::SplitAReplaceOp( 129 version, aop, part_path, &result_ops, &blob_file)); 130 131 // Check the result. 132 InstallOperation_Type expected_type = 133 compressible ? InstallOperation::REPLACE_BZ : InstallOperation::REPLACE; 134 135 ASSERT_EQ(2U, result_ops.size()); 136 137 EXPECT_EQ("SplitTestOp:0", result_ops[0].name); 138 InstallOperation first_op = result_ops[0].op; 139 EXPECT_EQ(expected_type, first_op.type()); 140 EXPECT_FALSE(first_op.has_src_length()); 141 EXPECT_FALSE(first_op.has_dst_length()); 142 EXPECT_EQ(1, first_op.dst_extents().size()); 143 EXPECT_TRUE(ExtentEquals(first_op.dst_extents(0), op_ex1_start_block, 144 op_ex1_num_blocks)); 145 // Obtain the expected blob. 146 brillo::Blob first_expected_data( 147 part_data.begin() + op_ex1_offset, 148 part_data.begin() + op_ex1_offset + op_ex1_size); 149 brillo::Blob first_expected_blob; 150 if (compressible) { 151 ASSERT_TRUE(BzipCompress(first_expected_data, &first_expected_blob)); 152 } else { 153 first_expected_blob = first_expected_data; 154 } 155 EXPECT_EQ(first_expected_blob.size(), first_op.data_length()); 156 // Check that the actual blob matches what's expected. 157 brillo::Blob first_data_blob(first_op.data_length()); 158 ssize_t bytes_read; 159 ASSERT_TRUE(utils::PReadAll(data_fd, 160 first_data_blob.data(), 161 first_op.data_length(), 162 first_op.data_offset(), 163 &bytes_read)); 164 ASSERT_EQ(bytes_read, static_cast<ssize_t>(first_op.data_length())); 165 EXPECT_EQ(first_expected_blob, first_data_blob); 166 167 EXPECT_EQ("SplitTestOp:1", result_ops[1].name); 168 InstallOperation second_op = result_ops[1].op; 169 EXPECT_EQ(expected_type, second_op.type()); 170 EXPECT_FALSE(second_op.has_src_length()); 171 EXPECT_FALSE(second_op.has_dst_length()); 172 EXPECT_EQ(1, second_op.dst_extents().size()); 173 EXPECT_TRUE(ExtentEquals(second_op.dst_extents(0), op_ex2_start_block, 174 op_ex2_num_blocks)); 175 // Obtain the expected blob. 176 brillo::Blob second_expected_data( 177 part_data.begin() + op_ex2_offset, 178 part_data.begin() + op_ex2_offset + op_ex2_size); 179 brillo::Blob second_expected_blob; 180 if (compressible) { 181 ASSERT_TRUE(BzipCompress(second_expected_data, &second_expected_blob)); 182 } else { 183 second_expected_blob = second_expected_data; 184 } 185 EXPECT_EQ(second_expected_blob.size(), second_op.data_length()); 186 // Check that the actual blob matches what's expected. 187 brillo::Blob second_data_blob(second_op.data_length()); 188 ASSERT_TRUE(utils::PReadAll(data_fd, 189 second_data_blob.data(), 190 second_op.data_length(), 191 second_op.data_offset(), 192 &bytes_read)); 193 ASSERT_EQ(bytes_read, static_cast<ssize_t>(second_op.data_length())); 194 EXPECT_EQ(second_expected_blob, second_data_blob); 195 196 // Check relative layout of data blobs. 197 EXPECT_EQ(first_op.data_offset() + first_op.data_length(), 198 second_op.data_offset()); 199 EXPECT_EQ(second_op.data_offset() + second_op.data_length(), data_file_size); 200 // If we split a REPLACE into multiple ones, ensure reuse of preexisting blob. 201 if (!compressible && orig_type == InstallOperation::REPLACE) { 202 EXPECT_EQ(0U, first_op.data_offset()); 203 } 204 } 205 206 // Tests merging of REPLACE/REPLACE_BZ operations. 207 void TestMergeReplaceOrReplaceBzOperations(InstallOperation_Type orig_type, 208 bool compressible) { 209 const size_t first_op_num_blocks = 1; 210 const size_t second_op_num_blocks = 2; 211 const size_t total_op_num_blocks = first_op_num_blocks + second_op_num_blocks; 212 const size_t part_num_blocks = total_op_num_blocks + 2; 213 214 // Create the target partition data. 215 string part_path; 216 EXPECT_TRUE(utils::MakeTempFile( 217 "MergeReplaceOrReplaceBzTest_part.XXXXXX", &part_path, nullptr)); 218 ScopedPathUnlinker part_path_unlinker(part_path); 219 const size_t part_size = part_num_blocks * kBlockSize; 220 brillo::Blob part_data; 221 if (compressible) { 222 part_data.resize(part_size); 223 test_utils::FillWithData(&part_data); 224 } else { 225 std::mt19937 gen(12345); 226 std::uniform_int_distribution<uint8_t> dis(0, 255); 227 for (uint32_t i = 0; i < part_size; i++) 228 part_data.push_back(dis(gen)); 229 } 230 ASSERT_EQ(part_size, part_data.size()); 231 ASSERT_TRUE(utils::WriteFile(part_path.c_str(), part_data.data(), part_size)); 232 233 // Create original operations and blob data. 234 vector<AnnotatedOperation> aops; 235 brillo::Blob blob_data; 236 const size_t total_op_size = total_op_num_blocks * kBlockSize; 237 238 InstallOperation first_op; 239 first_op.set_type(orig_type); 240 const size_t first_op_size = first_op_num_blocks * kBlockSize; 241 *(first_op.add_dst_extents()) = ExtentForRange(0, first_op_num_blocks); 242 brillo::Blob first_op_data(part_data.begin(), 243 part_data.begin() + first_op_size); 244 brillo::Blob first_op_blob; 245 if (orig_type == InstallOperation::REPLACE) { 246 first_op_blob = first_op_data; 247 } else { 248 ASSERT_TRUE(BzipCompress(first_op_data, &first_op_blob)); 249 } 250 first_op.set_data_offset(0); 251 first_op.set_data_length(first_op_blob.size()); 252 blob_data.insert(blob_data.end(), first_op_blob.begin(), first_op_blob.end()); 253 AnnotatedOperation first_aop; 254 first_aop.op = first_op; 255 first_aop.name = "first"; 256 aops.push_back(first_aop); 257 258 InstallOperation second_op; 259 second_op.set_type(orig_type); 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_FALSE(new_op.has_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 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_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 395 TEST_F(ABGeneratorTest, SplitReplaceTest) { 396 TestSplitReplaceOrReplaceBzOperation(InstallOperation::REPLACE, false); 397 } 398 399 TEST_F(ABGeneratorTest, SplitReplaceIntoReplaceBzTest) { 400 TestSplitReplaceOrReplaceBzOperation(InstallOperation::REPLACE, true); 401 } 402 403 TEST_F(ABGeneratorTest, SplitReplaceBzTest) { 404 TestSplitReplaceOrReplaceBzOperation(InstallOperation::REPLACE_BZ, true); 405 } 406 407 TEST_F(ABGeneratorTest, SplitReplaceBzIntoReplaceTest) { 408 TestSplitReplaceOrReplaceBzOperation(InstallOperation::REPLACE_BZ, false); 409 } 410 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 444 TEST_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 495 TEST_F(ABGeneratorTest, MergeReplaceOperationsTest) { 496 TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE, false); 497 } 498 499 TEST_F(ABGeneratorTest, MergeReplaceOperationsToReplaceBzTest) { 500 TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE, true); 501 } 502 503 TEST_F(ABGeneratorTest, MergeReplaceBzOperationsTest) { 504 TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE_BZ, true); 505 } 506 507 TEST_F(ABGeneratorTest, MergeReplaceBzOperationsToReplaceTest) { 508 TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE_BZ, false); 509 } 510 511 TEST_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 557 TEST_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