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