diff options
author | Tianjie Xu | 2017-10-20 16:11:20 -0500 |
---|---|---|
committer | android-build-merger | 2017-10-20 16:11:20 -0500 |
commit | 85fca1fc57dc0d67ee7417a106d03a1996690c10 (patch) | |
tree | cf5670c73c771763f045047217059e635da57795 /tests/component | |
parent | 9bc56553dd63b3f8fa6662f03c75a825c79ff6f4 (diff) | |
parent | 9831ef389b3beaa7a8d23cc77d76888a3021a2f9 (diff) | |
download | platform-bootable-recovery-85fca1fc57dc0d67ee7417a106d03a1996690c10.tar.gz platform-bootable-recovery-85fca1fc57dc0d67ee7417a106d03a1996690c10.tar.xz platform-bootable-recovery-85fca1fc57dc0d67ee7417a106d03a1996690c10.zip |
Merge "Finish the new data receiver when update fails"
am: 9831ef389b
Change-Id: I62be2406eede1f9e02ee4ca45ffca6fd2283ef0a
Diffstat (limited to 'tests/component')
-rw-r--r-- | tests/component/updater_test.cpp | 220 |
1 files changed, 133 insertions, 87 deletions
diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp index e6aec4ad..266657d3 100644 --- a/tests/component/updater_test.cpp +++ b/tests/component/updater_test.cpp | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <algorithm> | 23 | #include <algorithm> |
24 | #include <memory> | 24 | #include <memory> |
25 | #include <string> | 25 | #include <string> |
26 | #include <unordered_map> | ||
26 | #include <vector> | 27 | #include <vector> |
27 | 28 | ||
28 | #include <android-base/file.h> | 29 | #include <android-base/file.h> |
@@ -74,6 +75,23 @@ static void expect(const char* expected, const char* expr_str, CauseCode cause_c | |||
74 | ASSERT_EQ(cause_code, state.cause_code); | 75 | ASSERT_EQ(cause_code, state.cause_code); |
75 | } | 76 | } |
76 | 77 | ||
78 | static void BuildUpdatePackage(const std::unordered_map<std::string, std::string>& entries, | ||
79 | int fd) { | ||
80 | FILE* zip_file_ptr = fdopen(fd, "wb"); | ||
81 | ZipWriter zip_writer(zip_file_ptr); | ||
82 | |||
83 | for (const auto& entry : entries) { | ||
84 | ASSERT_EQ(0, zip_writer.StartEntry(entry.first.c_str(), 0)); | ||
85 | if (!entry.second.empty()) { | ||
86 | ASSERT_EQ(0, zip_writer.WriteBytes(entry.second.data(), entry.second.size())); | ||
87 | } | ||
88 | ASSERT_EQ(0, zip_writer.FinishEntry()); | ||
89 | } | ||
90 | |||
91 | ASSERT_EQ(0, zip_writer.Finish()); | ||
92 | ASSERT_EQ(0, fclose(zip_file_ptr)); | ||
93 | } | ||
94 | |||
77 | static std::string get_sha1(const std::string& content) { | 95 | static std::string get_sha1(const std::string& content) { |
78 | uint8_t digest[SHA_DIGEST_LENGTH]; | 96 | uint8_t digest[SHA_DIGEST_LENGTH]; |
79 | SHA1(reinterpret_cast<const uint8_t*>(content.c_str()), content.size(), digest); | 97 | SHA1(reinterpret_cast<const uint8_t*>(content.c_str()), content.size(), digest); |
@@ -420,30 +438,19 @@ TEST_F(UpdaterTest, show_progress) { | |||
420 | ASSERT_EQ(0, fclose(updater_info.cmd_pipe)); | 438 | ASSERT_EQ(0, fclose(updater_info.cmd_pipe)); |
421 | } | 439 | } |
422 | 440 | ||
423 | TEST_F(UpdaterTest, block_image_update) { | 441 | TEST_F(UpdaterTest, block_image_update_patch_data) { |
424 | // Create a zip file with new_data and patch_data. | ||
425 | TemporaryFile zip_file; | ||
426 | FILE* zip_file_ptr = fdopen(zip_file.release(), "wb"); | ||
427 | ZipWriter zip_writer(zip_file_ptr); | ||
428 | |||
429 | // Add a dummy new data. | ||
430 | ASSERT_EQ(0, zip_writer.StartEntry("new_data", 0)); | ||
431 | ASSERT_EQ(0, zip_writer.FinishEntry()); | ||
432 | |||
433 | // Generate and add the patch data. | ||
434 | std::string src_content = std::string(4096, 'a') + std::string(4096, 'c'); | 442 | std::string src_content = std::string(4096, 'a') + std::string(4096, 'c'); |
435 | std::string tgt_content = std::string(4096, 'b') + std::string(4096, 'd'); | 443 | std::string tgt_content = std::string(4096, 'b') + std::string(4096, 'd'); |
444 | |||
445 | // Generate the patch data. | ||
436 | TemporaryFile patch_file; | 446 | TemporaryFile patch_file; |
437 | ASSERT_EQ(0, bsdiff::bsdiff(reinterpret_cast<const uint8_t*>(src_content.data()), | 447 | ASSERT_EQ(0, bsdiff::bsdiff(reinterpret_cast<const uint8_t*>(src_content.data()), |
438 | src_content.size(), reinterpret_cast<const uint8_t*>(tgt_content.data()), | 448 | src_content.size(), reinterpret_cast<const uint8_t*>(tgt_content.data()), |
439 | tgt_content.size(), patch_file.path, nullptr)); | 449 | tgt_content.size(), patch_file.path, nullptr)); |
440 | std::string patch_content; | 450 | std::string patch_content; |
441 | ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch_content)); | 451 | ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch_content)); |
442 | ASSERT_EQ(0, zip_writer.StartEntry("patch_data", 0)); | ||
443 | ASSERT_EQ(0, zip_writer.WriteBytes(patch_content.data(), patch_content.size())); | ||
444 | ASSERT_EQ(0, zip_writer.FinishEntry()); | ||
445 | 452 | ||
446 | // Add two transfer lists. The first one contains a bsdiff; and we expect the update to succeed. | 453 | // Create the transfer list that contains a bsdiff. |
447 | std::string src_hash = get_sha1(src_content); | 454 | std::string src_hash = get_sha1(src_content); |
448 | std::string tgt_hash = get_sha1(tgt_content); | 455 | std::string tgt_hash = get_sha1(tgt_content); |
449 | std::vector<std::string> transfer_list = { | 456 | std::vector<std::string> transfer_list = { |
@@ -456,27 +463,16 @@ TEST_F(UpdaterTest, block_image_update) { | |||
456 | src_hash.c_str(), tgt_hash.c_str(), src_hash.c_str()), | 463 | src_hash.c_str(), tgt_hash.c_str(), src_hash.c_str()), |
457 | "free " + src_hash, | 464 | "free " + src_hash, |
458 | }; | 465 | }; |
459 | ASSERT_EQ(0, zip_writer.StartEntry("transfer_list", 0)); | ||
460 | std::string commands = android::base::Join(transfer_list, '\n'); | ||
461 | ASSERT_EQ(0, zip_writer.WriteBytes(commands.data(), commands.size())); | ||
462 | ASSERT_EQ(0, zip_writer.FinishEntry()); | ||
463 | 466 | ||
464 | // Stash and free some blocks, then fail the 2nd update intentionally. | 467 | std::unordered_map<std::string, std::string> entries = { |
465 | std::vector<std::string> fail_transfer_list = { | 468 | { "new_data", "" }, |
466 | "4", | 469 | { "patch_data", patch_content }, |
467 | "2", | 470 | { "transfer_list", android::base::Join(transfer_list, '\n') }, |
468 | "0", | ||
469 | "2", | ||
470 | "stash " + tgt_hash + " 2,0,2", | ||
471 | "free " + tgt_hash, | ||
472 | "fail", | ||
473 | }; | 471 | }; |
474 | ASSERT_EQ(0, zip_writer.StartEntry("fail_transfer_list", 0)); | 472 | |
475 | std::string fail_commands = android::base::Join(fail_transfer_list, '\n'); | 473 | // Build the update package. |
476 | ASSERT_EQ(0, zip_writer.WriteBytes(fail_commands.data(), fail_commands.size())); | 474 | TemporaryFile zip_file; |
477 | ASSERT_EQ(0, zip_writer.FinishEntry()); | 475 | BuildUpdatePackage(entries, zip_file.release()); |
478 | ASSERT_EQ(0, zip_writer.Finish()); | ||
479 | ASSERT_EQ(0, fclose(zip_file_ptr)); | ||
480 | 476 | ||
481 | MemMapping map; | 477 | MemMapping map; |
482 | ASSERT_TRUE(map.MapFile(zip_file.path)); | 478 | ASSERT_TRUE(map.MapFile(zip_file.path)); |
@@ -491,7 +487,7 @@ TEST_F(UpdaterTest, block_image_update) { | |||
491 | updater_info.package_zip_addr = map.addr; | 487 | updater_info.package_zip_addr = map.addr; |
492 | updater_info.package_zip_len = map.length; | 488 | updater_info.package_zip_len = map.length; |
493 | 489 | ||
494 | // Execute the commands in the 1st transfer list. | 490 | // Execute the commands in the transfer list. |
495 | TemporaryFile update_file; | 491 | TemporaryFile update_file; |
496 | ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path)); | 492 | ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path)); |
497 | std::string script = "block_image_update(\"" + std::string(update_file.path) + | 493 | std::string script = "block_image_update(\"" + std::string(update_file.path) + |
@@ -502,44 +498,98 @@ TEST_F(UpdaterTest, block_image_update) { | |||
502 | ASSERT_TRUE(android::base::ReadFileToString(update_file.path, &updated_content)); | 498 | ASSERT_TRUE(android::base::ReadFileToString(update_file.path, &updated_content)); |
503 | ASSERT_EQ(tgt_hash, get_sha1(updated_content)); | 499 | ASSERT_EQ(tgt_hash, get_sha1(updated_content)); |
504 | 500 | ||
505 | // Expect the 2nd update to fail, but expect the stashed blocks to be freed. | 501 | ASSERT_EQ(0, fclose(updater_info.cmd_pipe)); |
506 | script = "block_image_update(\"" + std::string(update_file.path) + | 502 | CloseArchive(handle); |
507 | R"(", package_extract_file("fail_transfer_list"), "new_data", "patch_data"))"; | 503 | } |
504 | |||
505 | TEST_F(UpdaterTest, block_image_update_fail) { | ||
506 | std::string src_content(4096 * 2, 'e'); | ||
507 | std::string src_hash = get_sha1(src_content); | ||
508 | // Stash and free some blocks, then fail the update intentionally. | ||
509 | std::vector<std::string> transfer_list = { | ||
510 | "4", "2", "0", "2", "stash " + src_hash + " 2,0,2", "free " + src_hash, "fail", | ||
511 | }; | ||
512 | |||
513 | // Add a new data of 10 bytes to test the deadlock. | ||
514 | std::unordered_map<std::string, std::string> entries = { | ||
515 | { "new_data", std::string(10, 0) }, | ||
516 | { "patch_data", "" }, | ||
517 | { "transfer_list", android::base::Join(transfer_list, '\n') }, | ||
518 | }; | ||
519 | |||
520 | // Build the update package. | ||
521 | TemporaryFile zip_file; | ||
522 | BuildUpdatePackage(entries, zip_file.release()); | ||
523 | |||
524 | MemMapping map; | ||
525 | ASSERT_TRUE(map.MapFile(zip_file.path)); | ||
526 | ZipArchiveHandle handle; | ||
527 | ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle)); | ||
528 | |||
529 | // Set up the handler, command_pipe, patch offset & length. | ||
530 | UpdaterInfo updater_info; | ||
531 | updater_info.package_zip = handle; | ||
532 | TemporaryFile temp_pipe; | ||
533 | updater_info.cmd_pipe = fdopen(temp_pipe.release(), "wbe"); | ||
534 | updater_info.package_zip_addr = map.addr; | ||
535 | updater_info.package_zip_len = map.length; | ||
536 | |||
537 | TemporaryFile update_file; | ||
538 | ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path)); | ||
539 | // Expect the stashed blocks to be freed. | ||
540 | std::string script = "block_image_update(\"" + std::string(update_file.path) + | ||
541 | R"(", package_extract_file("transfer_list"), "new_data", "patch_data"))"; | ||
508 | expect("", script.c_str(), kNoCause, &updater_info); | 542 | expect("", script.c_str(), kNoCause, &updater_info); |
509 | // Updater generates the stash name based on the input file name. | 543 | // Updater generates the stash name based on the input file name. |
510 | std::string name_digest = get_sha1(update_file.path); | 544 | std::string name_digest = get_sha1(update_file.path); |
511 | std::string stash_base = "/cache/recovery/" + name_digest; | 545 | std::string stash_base = "/cache/recovery/" + name_digest; |
512 | ASSERT_EQ(0, access(stash_base.c_str(), F_OK)); | 546 | ASSERT_EQ(0, access(stash_base.c_str(), F_OK)); |
513 | ASSERT_EQ(-1, access((stash_base + tgt_hash).c_str(), F_OK)); | 547 | ASSERT_EQ(-1, access((stash_base + src_hash).c_str(), F_OK)); |
514 | ASSERT_EQ(0, rmdir(stash_base.c_str())); | 548 | ASSERT_EQ(0, rmdir(stash_base.c_str())); |
515 | 549 | ||
516 | ASSERT_EQ(0, fclose(updater_info.cmd_pipe)); | 550 | ASSERT_EQ(0, fclose(updater_info.cmd_pipe)); |
517 | CloseArchive(handle); | 551 | CloseArchive(handle); |
518 | } | 552 | } |
519 | 553 | ||
520 | TEST_F(UpdaterTest, new_data_short_write) { | 554 | TEST_F(UpdaterTest, new_data_over_write) { |
521 | // Create a zip file with new_data. | 555 | std::vector<std::string> transfer_list = { |
556 | "4", "1", "0", "0", "new 2,0,1", | ||
557 | }; | ||
558 | |||
559 | // Write 4096 + 100 bytes of new data. | ||
560 | std::unordered_map<std::string, std::string> entries = { | ||
561 | { "new_data", std::string(4196, 0) }, | ||
562 | { "patch_data", "" }, | ||
563 | { "transfer_list", android::base::Join(transfer_list, '\n') }, | ||
564 | }; | ||
565 | |||
566 | // Build the update package. | ||
522 | TemporaryFile zip_file; | 567 | TemporaryFile zip_file; |
523 | FILE* zip_file_ptr = fdopen(zip_file.release(), "wb"); | 568 | BuildUpdatePackage(entries, zip_file.release()); |
524 | ZipWriter zip_writer(zip_file_ptr); | 569 | |
570 | MemMapping map; | ||
571 | ASSERT_TRUE(map.MapFile(zip_file.path)); | ||
572 | ZipArchiveHandle handle; | ||
573 | ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle)); | ||
525 | 574 | ||
526 | // Add the empty new data. | 575 | // Set up the handler, command_pipe, patch offset & length. |
527 | ASSERT_EQ(0, zip_writer.StartEntry("empty_new_data", 0)); | 576 | UpdaterInfo updater_info; |
528 | ASSERT_EQ(0, zip_writer.FinishEntry()); | 577 | updater_info.package_zip = handle; |
529 | // Add the short written new data. | 578 | TemporaryFile temp_pipe; |
530 | ASSERT_EQ(0, zip_writer.StartEntry("short_new_data", 0)); | 579 | updater_info.cmd_pipe = fdopen(temp_pipe.release(), "wbe"); |
531 | std::string new_data_short = std::string(10, 'a'); | 580 | updater_info.package_zip_addr = map.addr; |
532 | ASSERT_EQ(0, zip_writer.WriteBytes(new_data_short.data(), new_data_short.size())); | 581 | updater_info.package_zip_len = map.length; |
533 | ASSERT_EQ(0, zip_writer.FinishEntry()); | ||
534 | // Add the data of exactly one block. | ||
535 | ASSERT_EQ(0, zip_writer.StartEntry("exact_new_data", 0)); | ||
536 | std::string new_data_exact = std::string(4096, 'a'); | ||
537 | ASSERT_EQ(0, zip_writer.WriteBytes(new_data_exact.data(), new_data_exact.size())); | ||
538 | ASSERT_EQ(0, zip_writer.FinishEntry()); | ||
539 | // Add a dummy patch data. | ||
540 | ASSERT_EQ(0, zip_writer.StartEntry("patch_data", 0)); | ||
541 | ASSERT_EQ(0, zip_writer.FinishEntry()); | ||
542 | 582 | ||
583 | TemporaryFile update_file; | ||
584 | std::string script = "block_image_update(\"" + std::string(update_file.path) + | ||
585 | R"(", package_extract_file("transfer_list"), "new_data", "patch_data"))"; | ||
586 | expect("t", script.c_str(), kNoCause, &updater_info); | ||
587 | |||
588 | ASSERT_EQ(0, fclose(updater_info.cmd_pipe)); | ||
589 | CloseArchive(handle); | ||
590 | } | ||
591 | |||
592 | TEST_F(UpdaterTest, new_data_short_write) { | ||
543 | std::vector<std::string> transfer_list = { | 593 | std::vector<std::string> transfer_list = { |
544 | "4", | 594 | "4", |
545 | "1", | 595 | "1", |
@@ -547,12 +597,17 @@ TEST_F(UpdaterTest, new_data_short_write) { | |||
547 | "0", | 597 | "0", |
548 | "new 2,0,1", | 598 | "new 2,0,1", |
549 | }; | 599 | }; |
550 | ASSERT_EQ(0, zip_writer.StartEntry("transfer_list", 0)); | 600 | |
551 | std::string commands = android::base::Join(transfer_list, '\n'); | 601 | std::unordered_map<std::string, std::string> entries = { |
552 | ASSERT_EQ(0, zip_writer.WriteBytes(commands.data(), commands.size())); | 602 | { "empty_new_data", "" }, |
553 | ASSERT_EQ(0, zip_writer.FinishEntry()); | 603 | { "short_new_data", std::string(10, 'a') }, |
554 | ASSERT_EQ(0, zip_writer.Finish()); | 604 | { "exact_new_data", std::string(4096, 'a') }, |
555 | ASSERT_EQ(0, fclose(zip_file_ptr)); | 605 | { "patch_data", "" }, |
606 | { "transfer_list", android::base::Join(transfer_list, '\n') }, | ||
607 | }; | ||
608 | |||
609 | TemporaryFile zip_file; | ||
610 | BuildUpdatePackage(entries, zip_file.release()); | ||
556 | 611 | ||
557 | MemMapping map; | 612 | MemMapping map; |
558 | ASSERT_TRUE(map.MapFile(zip_file.path)); | 613 | ASSERT_TRUE(map.MapFile(zip_file.path)); |
@@ -587,14 +642,6 @@ TEST_F(UpdaterTest, new_data_short_write) { | |||
587 | } | 642 | } |
588 | 643 | ||
589 | TEST_F(UpdaterTest, brotli_new_data) { | 644 | TEST_F(UpdaterTest, brotli_new_data) { |
590 | // Create a zip file with new_data. | ||
591 | TemporaryFile zip_file; | ||
592 | FILE* zip_file_ptr = fdopen(zip_file.release(), "wb"); | ||
593 | ZipWriter zip_writer(zip_file_ptr); | ||
594 | |||
595 | // Add a brotli compressed new data entry. | ||
596 | ASSERT_EQ(0, zip_writer.StartEntry("new.dat.br", 0)); | ||
597 | |||
598 | auto generator = []() { return rand() % 128; }; | 645 | auto generator = []() { return rand() % 128; }; |
599 | // Generate 100 blocks of random data. | 646 | // Generate 100 blocks of random data. |
600 | std::string brotli_new_data; | 647 | std::string brotli_new_data; |
@@ -602,16 +649,12 @@ TEST_F(UpdaterTest, brotli_new_data) { | |||
602 | generate_n(back_inserter(brotli_new_data), 4096 * 100, generator); | 649 | generate_n(back_inserter(brotli_new_data), 4096 * 100, generator); |
603 | 650 | ||
604 | size_t encoded_size = BrotliEncoderMaxCompressedSize(brotli_new_data.size()); | 651 | size_t encoded_size = BrotliEncoderMaxCompressedSize(brotli_new_data.size()); |
605 | std::vector<uint8_t> encoded_data(encoded_size); | 652 | std::string encoded_data(encoded_size, 0); |
606 | ASSERT_TRUE(BrotliEncoderCompress( | 653 | ASSERT_TRUE(BrotliEncoderCompress( |
607 | BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW, BROTLI_DEFAULT_MODE, brotli_new_data.size(), | 654 | BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW, BROTLI_DEFAULT_MODE, brotli_new_data.size(), |
608 | reinterpret_cast<const uint8_t*>(brotli_new_data.data()), &encoded_size, encoded_data.data())); | 655 | reinterpret_cast<const uint8_t*>(brotli_new_data.data()), &encoded_size, |
609 | 656 | reinterpret_cast<uint8_t*>(const_cast<char*>(encoded_data.data())))); | |
610 | ASSERT_EQ(0, zip_writer.WriteBytes(encoded_data.data(), encoded_size)); | 657 | encoded_data.resize(encoded_size); |
611 | ASSERT_EQ(0, zip_writer.FinishEntry()); | ||
612 | // Add a dummy patch data. | ||
613 | ASSERT_EQ(0, zip_writer.StartEntry("patch_data", 0)); | ||
614 | ASSERT_EQ(0, zip_writer.FinishEntry()); | ||
615 | 658 | ||
616 | // Write a few small chunks of new data, then a large chunk, and finally a few small chunks. | 659 | // Write a few small chunks of new data, then a large chunk, and finally a few small chunks. |
617 | // This helps us to catch potential short writes. | 660 | // This helps us to catch potential short writes. |
@@ -627,12 +670,15 @@ TEST_F(UpdaterTest, brotli_new_data) { | |||
627 | "new 2,98,99", | 670 | "new 2,98,99", |
628 | "new 2,99,100", | 671 | "new 2,99,100", |
629 | }; | 672 | }; |
630 | ASSERT_EQ(0, zip_writer.StartEntry("transfer_list", 0)); | 673 | |
631 | std::string commands = android::base::Join(transfer_list, '\n'); | 674 | std::unordered_map<std::string, std::string> entries = { |
632 | ASSERT_EQ(0, zip_writer.WriteBytes(commands.data(), commands.size())); | 675 | { "new.dat.br", std::move(encoded_data) }, |
633 | ASSERT_EQ(0, zip_writer.FinishEntry()); | 676 | { "patch_data", "" }, |
634 | ASSERT_EQ(0, zip_writer.Finish()); | 677 | { "transfer_list", android::base::Join(transfer_list, '\n') }, |
635 | ASSERT_EQ(0, fclose(zip_file_ptr)); | 678 | }; |
679 | |||
680 | TemporaryFile zip_file; | ||
681 | BuildUpdatePackage(entries, zip_file.release()); | ||
636 | 682 | ||
637 | MemMapping map; | 683 | MemMapping map; |
638 | ASSERT_TRUE(map.MapFile(zip_file.path)); | 684 | ASSERT_TRUE(map.MapFile(zip_file.path)); |