aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorTianjie Xu2017-12-05 13:04:17 -0600
committerTianjie Xu2018-02-06 18:16:49 -0600
commit284752e2bc2daf93778d317c47bc202c668e3d89 (patch)
tree8342606c8d5f7c74e53828936444e609434fba6a /tests
parentbded087f7de69fc352c5860659e2db4478b30bdd (diff)
downloadplatform-bootable-recovery-284752e2bc2daf93778d317c47bc202c668e3d89.tar.gz
platform-bootable-recovery-284752e2bc2daf93778d317c47bc202c668e3d89.tar.xz
platform-bootable-recovery-284752e2bc2daf93778d317c47bc202c668e3d89.zip
Log the last command to cache
When performing an update, save the index and cmdline of the current command into the last command file if this command writes to the stash either explicitly of implicitly. This mitigates the overhead to update the last command file for every command. I ran a simple test on angler and the time to update 1000 times is ~2.3 seconds. Upon resuming an update, read the saved index first; then 1. In verification mode, check if all commands before the saved index have already produced the expected target blocks. If not, delete the last command file so that we will later resume the update from the start of the transfer list. 2. In update mode, skip all commands before the saved index. Therefore, we can avoid deleting stashes with duplicate id unintentionally; and also speed up the update. If an update succeeds or is unresumable, delete the last command file. Bug: 69858743 Test: Unittest passed, apply a failed update with invalid cmd on angler and check the last_command content, apply a failed update with invalid source hash and last_command is deleted. Change-Id: Ib60ba1e3c6d111d9f33097759b17dbcef97a37bf
Diffstat (limited to 'tests')
-rw-r--r--tests/component/updater_test.cpp217
1 files changed, 217 insertions, 0 deletions
diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp
index d9d01d42..448fe493 100644
--- a/tests/component/updater_test.cpp
+++ b/tests/component/updater_test.cpp
@@ -707,3 +707,220 @@ TEST_F(UpdaterTest, brotli_new_data) {
707 ASSERT_EQ(0, fclose(updater_info.cmd_pipe)); 707 ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
708 CloseArchive(handle); 708 CloseArchive(handle);
709} 709}
710
711TEST_F(UpdaterTest, last_command_update) {
712 TemporaryFile temp_file;
713 last_command_file = temp_file.path;
714
715 std::string block1 = std::string(4096, '1');
716 std::string block2 = std::string(4096, '2');
717 std::string block3 = std::string(4096, '3');
718 std::string block1_hash = get_sha1(block1);
719 std::string block2_hash = get_sha1(block2);
720 std::string block3_hash = get_sha1(block3);
721
722 // Compose the transfer list to fail the first update.
723 std::vector<std::string> transfer_list_fail = {
724 "4",
725 "2",
726 "0",
727 "2",
728 "stash " + block1_hash + " 2,0,1",
729 "move " + block1_hash + " 2,1,2 1 2,0,1",
730 "stash " + block3_hash + " 2,2,3",
731 "fail",
732 };
733
734 // Mimic a resumed update with the same transfer commands.
735 std::vector<std::string> transfer_list_continue = {
736 "4",
737 "2",
738 "0",
739 "2",
740 "stash " + block1_hash + " 2,0,1",
741 "move " + block1_hash + " 2,1,2 1 2,0,1",
742 "stash " + block3_hash + " 2,2,3",
743 "move " + block1_hash + " 2,2,3 1 2,0,1",
744 };
745
746 std::unordered_map<std::string, std::string> entries = {
747 { "new_data", "" },
748 { "patch_data", "" },
749 { "transfer_list_fail", android::base::Join(transfer_list_fail, '\n') },
750 { "transfer_list_continue", android::base::Join(transfer_list_continue, '\n') },
751 };
752
753 // Build the update package.
754 TemporaryFile zip_file;
755 BuildUpdatePackage(entries, zip_file.release());
756
757 MemMapping map;
758 ASSERT_TRUE(map.MapFile(zip_file.path));
759 ZipArchiveHandle handle;
760 ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle));
761
762 // Set up the handler, command_pipe, patch offset & length.
763 UpdaterInfo updater_info;
764 updater_info.package_zip = handle;
765 TemporaryFile temp_pipe;
766 updater_info.cmd_pipe = fdopen(temp_pipe.release(), "wbe");
767 updater_info.package_zip_addr = map.addr;
768 updater_info.package_zip_len = map.length;
769
770 std::string src_content = block1 + block2 + block3;
771 TemporaryFile update_file;
772 ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path));
773 std::string script =
774 "block_image_update(\"" + std::string(update_file.path) +
775 R"(", package_extract_file("transfer_list_fail"), "new_data", "patch_data"))";
776 expect("", script.c_str(), kNoCause, &updater_info);
777
778 // Expect last_command to contain the last stash command.
779 std::string last_command_content;
780 ASSERT_TRUE(android::base::ReadFileToString(last_command_file.c_str(), &last_command_content));
781 EXPECT_EQ("2\nstash " + block3_hash + " 2,2,3", last_command_content);
782 std::string updated_contents;
783 ASSERT_TRUE(android::base::ReadFileToString(update_file.path, &updated_contents));
784 ASSERT_EQ(block1 + block1 + block3, updated_contents);
785
786 // Resume the update, expect the first 'move' to be skipped but the second 'move' to be executed.
787 ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path));
788 std::string script_second_update =
789 "block_image_update(\"" + std::string(update_file.path) +
790 R"(", package_extract_file("transfer_list_continue"), "new_data", "patch_data"))";
791 expect("t", script_second_update.c_str(), kNoCause, &updater_info);
792 ASSERT_TRUE(android::base::ReadFileToString(update_file.path, &updated_contents));
793 ASSERT_EQ(block1 + block2 + block1, updated_contents);
794
795 ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
796 CloseArchive(handle);
797}
798
799TEST_F(UpdaterTest, last_command_update_unresumable) {
800 TemporaryFile temp_file;
801 last_command_file = temp_file.path;
802
803 std::string block1 = std::string(4096, '1');
804 std::string block2 = std::string(4096, '2');
805 std::string block1_hash = get_sha1(block1);
806 std::string block2_hash = get_sha1(block2);
807
808 // Construct an unresumable update with source blocks mismatch.
809 std::vector<std::string> transfer_list_unresumable = {
810 "4", "2", "0", "2", "stash " + block1_hash + " 2,0,1", "move " + block2_hash + " 2,1,2 1 2,0,1",
811 };
812
813 std::unordered_map<std::string, std::string> entries = {
814 { "new_data", "" },
815 { "patch_data", "" },
816 { "transfer_list_unresumable", android::base::Join(transfer_list_unresumable, '\n') },
817 };
818
819 // Build the update package.
820 TemporaryFile zip_file;
821 BuildUpdatePackage(entries, zip_file.release());
822
823 MemMapping map;
824 ASSERT_TRUE(map.MapFile(zip_file.path));
825 ZipArchiveHandle handle;
826 ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle));
827
828 // Set up the handler, command_pipe, patch offset & length.
829 UpdaterInfo updater_info;
830 updater_info.package_zip = handle;
831 TemporaryFile temp_pipe;
832 updater_info.cmd_pipe = fdopen(temp_pipe.release(), "wbe");
833 updater_info.package_zip_addr = map.addr;
834 updater_info.package_zip_len = map.length;
835
836 // Set up the last_command_file
837 ASSERT_TRUE(
838 android::base::WriteStringToFile("0\nstash " + block1_hash + " 2,0,1", last_command_file));
839
840 // The last_command_file will be deleted if the update encounters an unresumable failure
841 // later.
842 std::string src_content = block1 + block1;
843 TemporaryFile update_file;
844 ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path));
845 std::string script =
846 "block_image_update(\"" + std::string(update_file.path) +
847 R"(", package_extract_file("transfer_list_unresumable"), "new_data", "patch_data"))";
848 expect("", script.c_str(), kNoCause, &updater_info);
849 ASSERT_EQ(-1, access(last_command_file.c_str(), R_OK));
850
851 ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
852 CloseArchive(handle);
853}
854
855TEST_F(UpdaterTest, last_command_verify) {
856 TemporaryFile temp_file;
857 last_command_file = temp_file.path;
858
859 std::string block1 = std::string(4096, '1');
860 std::string block2 = std::string(4096, '2');
861 std::string block3 = std::string(4096, '3');
862 std::string block1_hash = get_sha1(block1);
863 std::string block2_hash = get_sha1(block2);
864 std::string block3_hash = get_sha1(block3);
865
866 std::vector<std::string> transfer_list_verify = {
867 "4",
868 "2",
869 "0",
870 "2",
871 "stash " + block1_hash + " 2,0,1",
872 "move " + block1_hash + " 2,0,1 1 2,0,1",
873 "move " + block1_hash + " 2,1,2 1 2,0,1",
874 "stash " + block3_hash + " 2,2,3",
875 };
876
877 std::unordered_map<std::string, std::string> entries = {
878 { "new_data", "" },
879 { "patch_data", "" },
880 { "transfer_list_verify", android::base::Join(transfer_list_verify, '\n') },
881 };
882
883 // Build the update package.
884 TemporaryFile zip_file;
885 BuildUpdatePackage(entries, zip_file.release());
886
887 MemMapping map;
888 ASSERT_TRUE(map.MapFile(zip_file.path));
889 ZipArchiveHandle handle;
890 ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle));
891
892 // Set up the handler, command_pipe, patch offset & length.
893 UpdaterInfo updater_info;
894 updater_info.package_zip = handle;
895 TemporaryFile temp_pipe;
896 updater_info.cmd_pipe = fdopen(temp_pipe.release(), "wbe");
897 updater_info.package_zip_addr = map.addr;
898 updater_info.package_zip_len = map.length;
899
900 std::string src_content = block1 + block1 + block3;
901 TemporaryFile update_file;
902 ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path));
903
904 ASSERT_TRUE(
905 android::base::WriteStringToFile("2\nstash " + block3_hash + " 2,2,3", last_command_file));
906
907 // Expect the verification to succeed and the last_command_file is intact.
908 std::string script_verify =
909 "block_image_verify(\"" + std::string(update_file.path) +
910 R"(", package_extract_file("transfer_list_verify"), "new_data","patch_data"))";
911 expect("t", script_verify.c_str(), kNoCause, &updater_info);
912
913 std::string last_command_content;
914 ASSERT_TRUE(android::base::ReadFileToString(last_command_file.c_str(), &last_command_content));
915 EXPECT_EQ("2\nstash " + block3_hash + " 2,2,3", last_command_content);
916
917 // Expect the verification to succeed but last_command_file to be deleted; because the target
918 // blocks don't have the expected contents for the second move command.
919 src_content = block1 + block2 + block3;
920 ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path));
921 expect("t", script_verify.c_str(), kNoCause, &updater_info);
922 ASSERT_EQ(-1, access(last_command_file.c_str(), R_OK));
923
924 ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
925 CloseArchive(handle);
926}