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(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. 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. 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 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 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.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 501 TEST_F(ABGeneratorTest, MergeReplaceOperationsTest) { 502 TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE, false); 503 } 504 505 TEST_F(ABGeneratorTest, MergeReplaceOperationsToReplaceBzTest) { 506 TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE, true); 507 } 508 509 TEST_F(ABGeneratorTest, MergeReplaceBzOperationsTest) { 510 TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE_BZ, true); 511 } 512 513 TEST_F(ABGeneratorTest, MergeReplaceBzOperationsToReplaceTest) { 514 TestMergeReplaceOrReplaceBzOperations(InstallOperation::REPLACE_BZ, false); 515 } 516 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 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