diff options
Diffstat (limited to 'tests/component')
-rw-r--r-- | tests/component/imgdiff_test.cpp | 105 | ||||
-rw-r--r-- | tests/component/install_test.cpp | 26 | ||||
-rw-r--r-- | tests/component/updater_test.cpp | 222 |
3 files changed, 188 insertions, 165 deletions
diff --git a/tests/component/imgdiff_test.cpp b/tests/component/imgdiff_test.cpp index bf591dae4..6de804e06 100644 --- a/tests/component/imgdiff_test.cpp +++ b/tests/component/imgdiff_test.cpp @@ -32,6 +32,8 @@ #include <gtest/gtest.h> #include <ziparchive/zip_writer.h> +#include "common/test_constants.h" + using android::base::get_unaligned; // Sanity check for the given imgdiff patch header. @@ -148,7 +150,7 @@ TEST(ImgdiffTest, image_mode_smoke) { TEST(ImgdiffTest, zip_mode_smoke_store) { // Construct src and tgt zip files. TemporaryFile src_file; - FILE* src_file_ptr = fdopen(src_file.fd, "wb"); + FILE* src_file_ptr = fdopen(src_file.release(), "wb"); ZipWriter src_writer(src_file_ptr); ASSERT_EQ(0, src_writer.StartEntry("file1.txt", 0)); // Store mode. const std::string src_content("abcdefg"); @@ -158,7 +160,7 @@ TEST(ImgdiffTest, zip_mode_smoke_store) { ASSERT_EQ(0, fclose(src_file_ptr)); TemporaryFile tgt_file; - FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb"); + FILE* tgt_file_ptr = fdopen(tgt_file.release(), "wb"); ZipWriter tgt_writer(tgt_file_ptr); ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", 0)); // Store mode. const std::string tgt_content("abcdefgxyz"); @@ -197,7 +199,7 @@ TEST(ImgdiffTest, zip_mode_smoke_store) { TEST(ImgdiffTest, zip_mode_smoke_compressed) { // Construct src and tgt zip files. TemporaryFile src_file; - FILE* src_file_ptr = fdopen(src_file.fd, "wb"); + FILE* src_file_ptr = fdopen(src_file.release(), "wb"); ZipWriter src_writer(src_file_ptr); ASSERT_EQ(0, src_writer.StartEntry("file1.txt", ZipWriter::kCompress)); const std::string src_content("abcdefg"); @@ -207,7 +209,7 @@ TEST(ImgdiffTest, zip_mode_smoke_compressed) { ASSERT_EQ(0, fclose(src_file_ptr)); TemporaryFile tgt_file; - FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb"); + FILE* tgt_file_ptr = fdopen(tgt_file.release(), "wb"); ZipWriter tgt_writer(tgt_file_ptr); ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", ZipWriter::kCompress)); const std::string tgt_content("abcdefgxyz"); @@ -246,7 +248,7 @@ TEST(ImgdiffTest, zip_mode_smoke_compressed) { TEST(ImgdiffTest, zip_mode_smoke_trailer_zeros) { // Construct src and tgt zip files. TemporaryFile src_file; - FILE* src_file_ptr = fdopen(src_file.fd, "wb"); + FILE* src_file_ptr = fdopen(src_file.release(), "wb"); ZipWriter src_writer(src_file_ptr); ASSERT_EQ(0, src_writer.StartEntry("file1.txt", ZipWriter::kCompress)); const std::string src_content("abcdefg"); @@ -256,7 +258,7 @@ TEST(ImgdiffTest, zip_mode_smoke_trailer_zeros) { ASSERT_EQ(0, fclose(src_file_ptr)); TemporaryFile tgt_file; - FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb"); + FILE* tgt_file_ptr = fdopen(tgt_file.release(), "wb"); ZipWriter tgt_writer(tgt_file_ptr); ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", ZipWriter::kCompress)); const std::string tgt_content("abcdefgxyz"); @@ -761,7 +763,7 @@ TEST(ImgdiffTest, zip_mode_store_large_apk) { // 3 blocks 'a' 12 blocks 'd' (exceeds limit) // 3 blocks 'e' TemporaryFile tgt_file; - FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb"); + FILE* tgt_file_ptr = fdopen(tgt_file.release(), "wb"); ZipWriter tgt_writer(tgt_file_ptr); construct_store_entry( { { "a", 3, 'a' }, { "b", 3, 'b' }, { "c", 8, 'c' }, { "d", 12, 'd' }, { "e", 3, 'e' } }, @@ -770,7 +772,7 @@ TEST(ImgdiffTest, zip_mode_store_large_apk) { ASSERT_EQ(0, fclose(tgt_file_ptr)); TemporaryFile src_file; - FILE* src_file_ptr = fdopen(src_file.fd, "wb"); + FILE* src_file_ptr = fdopen(src_file.release(), "wb"); ZipWriter src_writer(src_file_ptr); construct_store_entry({ { "d", 12, 'd' }, { "c", 8, 'c' }, { "b", 3, 'b' }, { "a", 3, 'a' } }, &src_writer); @@ -792,49 +794,26 @@ TEST(ImgdiffTest, zip_mode_store_large_apk) { std::string tgt; ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt)); - // Expect 4 pieces of patch.(Rougly 3'a',3'b'; 8'c'; 10'd'; 2'd'3'e') + // Expect 4 pieces of patch. (Roughly 3'a',3'b'; 8'c'; 10'd'; 2'd'3'e') GenerateAndCheckSplitTarget(debug_dir.path, 4, tgt); } TEST(ImgdiffTest, zip_mode_deflate_large_apk) { - // Generate 50 blocks of random data. - std::string random_data; - random_data.reserve(4096 * 50); - generate_n(back_inserter(random_data), 4096 * 50, []() { return rand() % 256; }); - - // Construct src and tgt zip files with limit = 10 blocks. + // Src and tgt zip files are constructed as follows. // src tgt // 22 blocks, "d" 4 blocks, "a" // 5 blocks, "b" 4 blocks, "b" - // 3 blocks, "a" 7 blocks, "c" (exceeds limit) - // 8 blocks, "c" 20 blocks, "d" (exceeds limit) - // 1 block, "f" 2 blocks, "e" - TemporaryFile tgt_file; - FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb"); - ZipWriter tgt_writer(tgt_file_ptr); - - construct_deflate_entry( - { { "a", 0, 4 }, { "b", 5, 4 }, { "c", 12, 8 }, { "d", 21, 20 }, { "e", 45, 2 }, - { "f", 48, 1 } }, &tgt_writer, random_data); - - ASSERT_EQ(0, tgt_writer.Finish()); - ASSERT_EQ(0, fclose(tgt_file_ptr)); - - TemporaryFile src_file; - FILE* src_file_ptr = fdopen(src_file.fd, "wb"); - ZipWriter src_writer(src_file_ptr); - - construct_deflate_entry( - { { "d", 21, 22 }, { "b", 5, 5 }, { "a", 0, 3 }, { "g", 9, 1 }, { "c", 11, 8 }, - { "f", 45, 1 } }, &src_writer, random_data); - - ASSERT_EQ(0, src_writer.Finish()); - ASSERT_EQ(0, fclose(src_file_ptr)); + // 3 blocks, "a" 8 blocks, "c" (exceeds limit) + // 1 block, "g" 20 blocks, "d" (exceeds limit) + // 8 blocks, "c" 2 blocks, "e" + // 1 block, "f" 1 block , "f" + std::string tgt_path = from_testdata_base("deflate_tgt.zip"); + std::string src_path = from_testdata_base("deflate_src.zip"); ZipModeImage src_image(true, 10 * 4096); ZipModeImage tgt_image(false, 10 * 4096); - ASSERT_TRUE(src_image.Initialize(src_file.path)); - ASSERT_TRUE(tgt_image.Initialize(tgt_file.path)); + ASSERT_TRUE(src_image.Initialize(src_path)); + ASSERT_TRUE(tgt_image.Initialize(tgt_path)); ASSERT_TRUE(ZipModeImage::CheckAndProcessChunks(&tgt_image, &src_image)); src_image.DumpChunks(); @@ -846,11 +825,12 @@ TEST(ImgdiffTest, zip_mode_deflate_large_apk) { ZipModeImage::SplitZipModeImageWithLimit(tgt_image, src_image, &split_tgt_images, &split_src_images, &split_src_ranges); - // src_piece 1: a 3 blocks, b 5 blocks - // src_piece 2: c 8 blocks - // src_piece 3: d-0 10 block - // src_piece 4: d-1 10 blocks - // src_piece 5: e 1 block, CD + // Expected split images with limit = 10 blocks. + // src_piece 0: a 3 blocks, b 5 blocks + // src_piece 1: c 8 blocks + // src_piece 2: d-0 10 block + // src_piece 3: d-1 10 blocks + // src_piece 4: e 1 block, CD ASSERT_EQ(split_tgt_images.size(), split_src_images.size()); ASSERT_EQ(static_cast<size_t>(5), split_tgt_images.size()); @@ -883,24 +863,21 @@ TEST(ImgdiffTest, zip_mode_deflate_large_apk) { ASSERT_EQ("2", android::base::Trim(info_list[0])); ASSERT_EQ("5", android::base::Trim(info_list[1])); - std::vector<size_t> patch_size; + std::string tgt; + ASSERT_TRUE(android::base::ReadFileToString(tgt_path, &tgt)); + ASSERT_EQ(static_cast<size_t>(160385), tgt.size()); + std::vector<std::string> tgt_file_ranges = { + "36864 2,22,31", "32768 2,31,40", "40960 2,0,11", "40960 2,11,21", "8833 4,21,22,40,41", + }; + for (size_t i = 0; i < 5; i++) { - struct stat st = {}; + struct stat st; std::string path = android::base::StringPrintf("%s/patch-%zu", debug_dir.path, i); ASSERT_EQ(0, stat(path.c_str(), &st)); - patch_size.push_back(st.st_size); + ASSERT_EQ(std::to_string(st.st_size) + " " + tgt_file_ranges[i], + android::base::Trim(info_list[i + 2])); } - ASSERT_EQ(std::to_string(patch_size[0]) + " 36864 2,22,31", android::base::Trim(info_list[2])); - ASSERT_EQ(std::to_string(patch_size[1]) + " 32768 2,31,40", android::base::Trim(info_list[3])); - ASSERT_EQ(std::to_string(patch_size[2]) + " 40960 2,0,11", android::base::Trim(info_list[4])); - ASSERT_EQ(std::to_string(patch_size[3]) + " 40960 2,11,21", android::base::Trim(info_list[5])); - ASSERT_EQ(std::to_string(patch_size[4]) + " 8833 4,21,22,40,41", - android::base::Trim(info_list[6])); - - std::string tgt; - ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt)); - GenerateAndCheckSplitTarget(debug_dir.path, 5, tgt); } @@ -911,7 +888,7 @@ TEST(ImgdiffTest, zip_mode_no_match_source) { generate_n(back_inserter(random_data), 4096 * 20, []() { return rand() % 256; }); TemporaryFile tgt_file; - FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb"); + FILE* tgt_file_ptr = fdopen(tgt_file.release(), "wb"); ZipWriter tgt_writer(tgt_file_ptr); construct_deflate_entry({ { "a", 0, 4 }, { "b", 5, 5 }, { "c", 11, 5 } }, &tgt_writer, @@ -922,7 +899,7 @@ TEST(ImgdiffTest, zip_mode_no_match_source) { // We don't have a matching source entry. TemporaryFile src_file; - FILE* src_file_ptr = fdopen(src_file.fd, "wb"); + FILE* src_file_ptr = fdopen(src_file.release(), "wb"); ZipWriter src_writer(src_file_ptr); construct_store_entry({ { "d", 1, 'd' } }, &src_writer); ASSERT_EQ(0, src_writer.Finish()); @@ -954,7 +931,7 @@ TEST(ImgdiffTest, zip_mode_large_enough_limit) { generate_n(back_inserter(random_data), 4096 * 20, []() { return rand() % 256; }); TemporaryFile tgt_file; - FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb"); + FILE* tgt_file_ptr = fdopen(tgt_file.release(), "wb"); ZipWriter tgt_writer(tgt_file_ptr); construct_deflate_entry({ { "a", 0, 10 }, { "b", 10, 5 } }, &tgt_writer, random_data); @@ -964,7 +941,7 @@ TEST(ImgdiffTest, zip_mode_large_enough_limit) { // Construct 10 blocks of source. TemporaryFile src_file; - FILE* src_file_ptr = fdopen(src_file.fd, "wb"); + FILE* src_file_ptr = fdopen(src_file.release(), "wb"); ZipWriter src_writer(src_file_ptr); construct_deflate_entry({ { "a", 1, 10 } }, &src_writer, random_data); ASSERT_EQ(0, src_writer.Finish()); @@ -985,6 +962,6 @@ TEST(ImgdiffTest, zip_mode_large_enough_limit) { std::string tgt; ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt)); - // Expect 1 pieces of patch since limit is larger than the zip file size. + // Expect 1 piece of patch since limit is larger than the zip file size. GenerateAndCheckSplitTarget(debug_dir.path, 1, tgt); } diff --git a/tests/component/install_test.cpp b/tests/component/install_test.cpp index 7bb496066..d19d788e4 100644 --- a/tests/component/install_test.cpp +++ b/tests/component/install_test.cpp @@ -37,7 +37,7 @@ TEST(InstallTest, verify_package_compatibility_no_entry) { TemporaryFile temp_file; - FILE* zip_file = fdopen(temp_file.fd, "w"); + FILE* zip_file = fdopen(temp_file.release(), "w"); ZipWriter writer(zip_file); // The archive must have something to be opened correctly. ASSERT_EQ(0, writer.StartEntry("dummy_entry", 0)); @@ -54,7 +54,7 @@ TEST(InstallTest, verify_package_compatibility_no_entry) { TEST(InstallTest, verify_package_compatibility_invalid_entry) { TemporaryFile temp_file; - FILE* zip_file = fdopen(temp_file.fd, "w"); + FILE* zip_file = fdopen(temp_file.release(), "w"); ZipWriter writer(zip_file); ASSERT_EQ(0, writer.StartEntry("compatibility.zip", 0)); ASSERT_EQ(0, writer.FinishEntry()); @@ -70,7 +70,7 @@ TEST(InstallTest, verify_package_compatibility_invalid_entry) { TEST(InstallTest, read_metadata_from_package_smoke) { TemporaryFile temp_file; - FILE* zip_file = fdopen(temp_file.fd, "w"); + FILE* zip_file = fdopen(temp_file.release(), "w"); ZipWriter writer(zip_file); ASSERT_EQ(0, writer.StartEntry("META-INF/com/android/metadata", kCompressStored)); const std::string content("abcdefg"); @@ -87,7 +87,7 @@ TEST(InstallTest, read_metadata_from_package_smoke) { CloseArchive(zip); TemporaryFile temp_file2; - FILE* zip_file2 = fdopen(temp_file2.fd, "w"); + FILE* zip_file2 = fdopen(temp_file2.release(), "w"); ZipWriter writer2(zip_file2); ASSERT_EQ(0, writer2.StartEntry("META-INF/com/android/metadata", kCompressDeflated)); ASSERT_EQ(0, writer2.WriteBytes(content.data(), content.size())); @@ -104,7 +104,7 @@ TEST(InstallTest, read_metadata_from_package_smoke) { TEST(InstallTest, read_metadata_from_package_no_entry) { TemporaryFile temp_file; - FILE* zip_file = fdopen(temp_file.fd, "w"); + FILE* zip_file = fdopen(temp_file.release(), "w"); ZipWriter writer(zip_file); ASSERT_EQ(0, writer.StartEntry("dummy_entry", kCompressStored)); ASSERT_EQ(0, writer.FinishEntry()); @@ -120,7 +120,7 @@ TEST(InstallTest, read_metadata_from_package_no_entry) { TEST(InstallTest, verify_package_compatibility_with_libvintf_malformed_xml) { TemporaryFile compatibility_zip_file; - FILE* compatibility_zip = fdopen(compatibility_zip_file.fd, "w"); + FILE* compatibility_zip = fdopen(compatibility_zip_file.release(), "w"); ZipWriter compatibility_zip_writer(compatibility_zip); ASSERT_EQ(0, compatibility_zip_writer.StartEntry("system_manifest.xml", kCompressDeflated)); std::string malformed_xml = "malformed"; @@ -130,7 +130,7 @@ TEST(InstallTest, verify_package_compatibility_with_libvintf_malformed_xml) { ASSERT_EQ(0, fclose(compatibility_zip)); TemporaryFile temp_file; - FILE* zip_file = fdopen(temp_file.fd, "w"); + FILE* zip_file = fdopen(temp_file.release(), "w"); ZipWriter writer(zip_file); ASSERT_EQ(0, writer.StartEntry("compatibility.zip", kCompressStored)); std::string compatibility_zip_content; @@ -165,7 +165,7 @@ TEST(InstallTest, verify_package_compatibility_with_libvintf_system_manifest_xml ASSERT_TRUE( android::base::ReadFileToString(system_manifest_xml_path, &system_manifest_xml_content)); TemporaryFile compatibility_zip_file; - FILE* compatibility_zip = fdopen(compatibility_zip_file.fd, "w"); + FILE* compatibility_zip = fdopen(compatibility_zip_file.release(), "w"); ZipWriter compatibility_zip_writer(compatibility_zip); ASSERT_EQ(0, compatibility_zip_writer.StartEntry("system_manifest.xml", kCompressDeflated)); ASSERT_EQ(0, compatibility_zip_writer.WriteBytes(system_manifest_xml_content.data(), @@ -175,7 +175,7 @@ TEST(InstallTest, verify_package_compatibility_with_libvintf_system_manifest_xml ASSERT_EQ(0, fclose(compatibility_zip)); TemporaryFile temp_file; - FILE* zip_file = fdopen(temp_file.fd, "w"); + FILE* zip_file = fdopen(temp_file.release(), "w"); ZipWriter writer(zip_file); ASSERT_EQ(0, writer.StartEntry("compatibility.zip", kCompressStored)); std::string compatibility_zip_content; @@ -202,7 +202,7 @@ TEST(InstallTest, verify_package_compatibility_with_libvintf_system_manifest_xml #ifdef AB_OTA_UPDATER static void VerifyAbUpdateBinaryCommand(const std::string& serialno, bool success = true) { TemporaryFile temp_file; - FILE* zip_file = fdopen(temp_file.fd, "w"); + FILE* zip_file = fdopen(temp_file.release(), "w"); ZipWriter writer(zip_file); ASSERT_EQ(0, writer.StartEntry("payload.bin", kCompressStored)); ASSERT_EQ(0, writer.FinishEntry()); @@ -258,7 +258,7 @@ TEST(InstallTest, update_binary_command_smoke) { VerifyAbUpdateBinaryCommand({}); #else TemporaryFile temp_file; - FILE* zip_file = fdopen(temp_file.fd, "w"); + FILE* zip_file = fdopen(temp_file.release(), "w"); ZipWriter writer(zip_file); static constexpr const char* UPDATE_BINARY_NAME = "META-INF/com/google/android/update-binary"; ASSERT_EQ(0, writer.StartEntry(UPDATE_BINARY_NAME, kCompressStored)); @@ -303,7 +303,7 @@ TEST(InstallTest, update_binary_command_smoke) { TEST(InstallTest, update_binary_command_invalid) { #ifdef AB_OTA_UPDATER TemporaryFile temp_file; - FILE* zip_file = fdopen(temp_file.fd, "w"); + FILE* zip_file = fdopen(temp_file.release(), "w"); ZipWriter writer(zip_file); // Missing payload_properties.txt. ASSERT_EQ(0, writer.StartEntry("payload.bin", kCompressStored)); @@ -334,7 +334,7 @@ TEST(InstallTest, update_binary_command_invalid) { CloseArchive(zip); #else TemporaryFile temp_file; - FILE* zip_file = fdopen(temp_file.fd, "w"); + FILE* zip_file = fdopen(temp_file.release(), "w"); ZipWriter writer(zip_file); // The archive must have something to be opened correctly. ASSERT_EQ(0, writer.StartEntry("dummy_entry", 0)); diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp index e6aec4ad6..d9d01d427 100644 --- a/tests/component/updater_test.cpp +++ b/tests/component/updater_test.cpp @@ -23,6 +23,7 @@ #include <algorithm> #include <memory> #include <string> +#include <unordered_map> #include <vector> #include <android-base/file.h> @@ -32,7 +33,7 @@ #include <android-base/test_utils.h> #include <bootloader_message/bootloader_message.h> #include <brotli/encode.h> -#include <bsdiff.h> +#include <bsdiff/bsdiff.h> #include <gtest/gtest.h> #include <ziparchive/zip_archive.h> #include <ziparchive/zip_writer.h> @@ -74,6 +75,23 @@ static void expect(const char* expected, const char* expr_str, CauseCode cause_c ASSERT_EQ(cause_code, state.cause_code); } +static void BuildUpdatePackage(const std::unordered_map<std::string, std::string>& entries, + int fd) { + FILE* zip_file_ptr = fdopen(fd, "wb"); + ZipWriter zip_writer(zip_file_ptr); + + for (const auto& entry : entries) { + ASSERT_EQ(0, zip_writer.StartEntry(entry.first.c_str(), 0)); + if (!entry.second.empty()) { + ASSERT_EQ(0, zip_writer.WriteBytes(entry.second.data(), entry.second.size())); + } + ASSERT_EQ(0, zip_writer.FinishEntry()); + } + + ASSERT_EQ(0, zip_writer.Finish()); + ASSERT_EQ(0, fclose(zip_file_ptr)); +} + static std::string get_sha1(const std::string& content) { uint8_t digest[SHA_DIGEST_LENGTH]; SHA1(reinterpret_cast<const uint8_t*>(content.c_str()), content.size(), digest); @@ -420,30 +438,19 @@ TEST_F(UpdaterTest, show_progress) { ASSERT_EQ(0, fclose(updater_info.cmd_pipe)); } -TEST_F(UpdaterTest, block_image_update) { - // Create a zip file with new_data and patch_data. - TemporaryFile zip_file; - FILE* zip_file_ptr = fdopen(zip_file.release(), "wb"); - ZipWriter zip_writer(zip_file_ptr); - - // Add a dummy new data. - ASSERT_EQ(0, zip_writer.StartEntry("new_data", 0)); - ASSERT_EQ(0, zip_writer.FinishEntry()); - - // Generate and add the patch data. +TEST_F(UpdaterTest, block_image_update_patch_data) { std::string src_content = std::string(4096, 'a') + std::string(4096, 'c'); std::string tgt_content = std::string(4096, 'b') + std::string(4096, 'd'); + + // Generate the patch data. TemporaryFile patch_file; ASSERT_EQ(0, bsdiff::bsdiff(reinterpret_cast<const uint8_t*>(src_content.data()), src_content.size(), reinterpret_cast<const uint8_t*>(tgt_content.data()), tgt_content.size(), patch_file.path, nullptr)); std::string patch_content; ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch_content)); - ASSERT_EQ(0, zip_writer.StartEntry("patch_data", 0)); - ASSERT_EQ(0, zip_writer.WriteBytes(patch_content.data(), patch_content.size())); - ASSERT_EQ(0, zip_writer.FinishEntry()); - // Add two transfer lists. The first one contains a bsdiff; and we expect the update to succeed. + // Create the transfer list that contains a bsdiff. std::string src_hash = get_sha1(src_content); std::string tgt_hash = get_sha1(tgt_content); std::vector<std::string> transfer_list = { @@ -456,27 +463,16 @@ TEST_F(UpdaterTest, block_image_update) { src_hash.c_str(), tgt_hash.c_str(), src_hash.c_str()), "free " + src_hash, }; - ASSERT_EQ(0, zip_writer.StartEntry("transfer_list", 0)); - std::string commands = android::base::Join(transfer_list, '\n'); - ASSERT_EQ(0, zip_writer.WriteBytes(commands.data(), commands.size())); - ASSERT_EQ(0, zip_writer.FinishEntry()); - // Stash and free some blocks, then fail the 2nd update intentionally. - std::vector<std::string> fail_transfer_list = { - "4", - "2", - "0", - "2", - "stash " + tgt_hash + " 2,0,2", - "free " + tgt_hash, - "fail", + std::unordered_map<std::string, std::string> entries = { + { "new_data", "" }, + { "patch_data", patch_content }, + { "transfer_list", android::base::Join(transfer_list, '\n') }, }; - ASSERT_EQ(0, zip_writer.StartEntry("fail_transfer_list", 0)); - std::string fail_commands = android::base::Join(fail_transfer_list, '\n'); - ASSERT_EQ(0, zip_writer.WriteBytes(fail_commands.data(), fail_commands.size())); - ASSERT_EQ(0, zip_writer.FinishEntry()); - ASSERT_EQ(0, zip_writer.Finish()); - ASSERT_EQ(0, fclose(zip_file_ptr)); + + // Build the update package. + TemporaryFile zip_file; + BuildUpdatePackage(entries, zip_file.release()); MemMapping map; ASSERT_TRUE(map.MapFile(zip_file.path)); @@ -491,7 +487,7 @@ TEST_F(UpdaterTest, block_image_update) { updater_info.package_zip_addr = map.addr; updater_info.package_zip_len = map.length; - // Execute the commands in the 1st transfer list. + // Execute the commands in the transfer list. TemporaryFile update_file; ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path)); std::string script = "block_image_update(\"" + std::string(update_file.path) + @@ -502,44 +498,98 @@ TEST_F(UpdaterTest, block_image_update) { ASSERT_TRUE(android::base::ReadFileToString(update_file.path, &updated_content)); ASSERT_EQ(tgt_hash, get_sha1(updated_content)); - // Expect the 2nd update to fail, but expect the stashed blocks to be freed. - script = "block_image_update(\"" + std::string(update_file.path) + - R"(", package_extract_file("fail_transfer_list"), "new_data", "patch_data"))"; + ASSERT_EQ(0, fclose(updater_info.cmd_pipe)); + CloseArchive(handle); +} + +TEST_F(UpdaterTest, block_image_update_fail) { + std::string src_content(4096 * 2, 'e'); + std::string src_hash = get_sha1(src_content); + // Stash and free some blocks, then fail the update intentionally. + std::vector<std::string> transfer_list = { + "4", "2", "0", "2", "stash " + src_hash + " 2,0,2", "free " + src_hash, "fail", + }; + + // Add a new data of 10 bytes to test the deadlock. + std::unordered_map<std::string, std::string> entries = { + { "new_data", std::string(10, 0) }, + { "patch_data", "" }, + { "transfer_list", android::base::Join(transfer_list, '\n') }, + }; + + // Build the update package. + TemporaryFile zip_file; + BuildUpdatePackage(entries, zip_file.release()); + + MemMapping map; + ASSERT_TRUE(map.MapFile(zip_file.path)); + ZipArchiveHandle handle; + ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle)); + + // Set up the handler, command_pipe, patch offset & length. + UpdaterInfo updater_info; + updater_info.package_zip = handle; + TemporaryFile temp_pipe; + updater_info.cmd_pipe = fdopen(temp_pipe.release(), "wbe"); + updater_info.package_zip_addr = map.addr; + updater_info.package_zip_len = map.length; + + TemporaryFile update_file; + ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path)); + // Expect the stashed blocks to be freed. + std::string script = "block_image_update(\"" + std::string(update_file.path) + + R"(", package_extract_file("transfer_list"), "new_data", "patch_data"))"; expect("", script.c_str(), kNoCause, &updater_info); // Updater generates the stash name based on the input file name. std::string name_digest = get_sha1(update_file.path); std::string stash_base = "/cache/recovery/" + name_digest; ASSERT_EQ(0, access(stash_base.c_str(), F_OK)); - ASSERT_EQ(-1, access((stash_base + tgt_hash).c_str(), F_OK)); + ASSERT_EQ(-1, access((stash_base + src_hash).c_str(), F_OK)); ASSERT_EQ(0, rmdir(stash_base.c_str())); ASSERT_EQ(0, fclose(updater_info.cmd_pipe)); CloseArchive(handle); } -TEST_F(UpdaterTest, new_data_short_write) { - // Create a zip file with new_data. +TEST_F(UpdaterTest, new_data_over_write) { + std::vector<std::string> transfer_list = { + "4", "1", "0", "0", "new 2,0,1", + }; + + // Write 4096 + 100 bytes of new data. + std::unordered_map<std::string, std::string> entries = { + { "new_data", std::string(4196, 0) }, + { "patch_data", "" }, + { "transfer_list", android::base::Join(transfer_list, '\n') }, + }; + + // Build the update package. TemporaryFile zip_file; - FILE* zip_file_ptr = fdopen(zip_file.release(), "wb"); - ZipWriter zip_writer(zip_file_ptr); + BuildUpdatePackage(entries, zip_file.release()); + + MemMapping map; + ASSERT_TRUE(map.MapFile(zip_file.path)); + ZipArchiveHandle handle; + ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle)); - // Add the empty new data. - ASSERT_EQ(0, zip_writer.StartEntry("empty_new_data", 0)); - ASSERT_EQ(0, zip_writer.FinishEntry()); - // Add the short written new data. - ASSERT_EQ(0, zip_writer.StartEntry("short_new_data", 0)); - std::string new_data_short = std::string(10, 'a'); - ASSERT_EQ(0, zip_writer.WriteBytes(new_data_short.data(), new_data_short.size())); - ASSERT_EQ(0, zip_writer.FinishEntry()); - // Add the data of exactly one block. - ASSERT_EQ(0, zip_writer.StartEntry("exact_new_data", 0)); - std::string new_data_exact = std::string(4096, 'a'); - ASSERT_EQ(0, zip_writer.WriteBytes(new_data_exact.data(), new_data_exact.size())); - ASSERT_EQ(0, zip_writer.FinishEntry()); - // Add a dummy patch data. - ASSERT_EQ(0, zip_writer.StartEntry("patch_data", 0)); - ASSERT_EQ(0, zip_writer.FinishEntry()); + // Set up the handler, command_pipe, patch offset & length. + UpdaterInfo updater_info; + updater_info.package_zip = handle; + TemporaryFile temp_pipe; + updater_info.cmd_pipe = fdopen(temp_pipe.release(), "wbe"); + updater_info.package_zip_addr = map.addr; + updater_info.package_zip_len = map.length; + TemporaryFile update_file; + std::string script = "block_image_update(\"" + std::string(update_file.path) + + R"(", package_extract_file("transfer_list"), "new_data", "patch_data"))"; + expect("t", script.c_str(), kNoCause, &updater_info); + + ASSERT_EQ(0, fclose(updater_info.cmd_pipe)); + CloseArchive(handle); +} + +TEST_F(UpdaterTest, new_data_short_write) { std::vector<std::string> transfer_list = { "4", "1", @@ -547,12 +597,17 @@ TEST_F(UpdaterTest, new_data_short_write) { "0", "new 2,0,1", }; - ASSERT_EQ(0, zip_writer.StartEntry("transfer_list", 0)); - std::string commands = android::base::Join(transfer_list, '\n'); - ASSERT_EQ(0, zip_writer.WriteBytes(commands.data(), commands.size())); - ASSERT_EQ(0, zip_writer.FinishEntry()); - ASSERT_EQ(0, zip_writer.Finish()); - ASSERT_EQ(0, fclose(zip_file_ptr)); + + std::unordered_map<std::string, std::string> entries = { + { "empty_new_data", "" }, + { "short_new_data", std::string(10, 'a') }, + { "exact_new_data", std::string(4096, 'a') }, + { "patch_data", "" }, + { "transfer_list", android::base::Join(transfer_list, '\n') }, + }; + + TemporaryFile zip_file; + BuildUpdatePackage(entries, zip_file.release()); MemMapping map; ASSERT_TRUE(map.MapFile(zip_file.path)); @@ -587,14 +642,6 @@ TEST_F(UpdaterTest, new_data_short_write) { } TEST_F(UpdaterTest, brotli_new_data) { - // Create a zip file with new_data. - TemporaryFile zip_file; - FILE* zip_file_ptr = fdopen(zip_file.release(), "wb"); - ZipWriter zip_writer(zip_file_ptr); - - // Add a brotli compressed new data entry. - ASSERT_EQ(0, zip_writer.StartEntry("new.dat.br", 0)); - auto generator = []() { return rand() % 128; }; // Generate 100 blocks of random data. std::string brotli_new_data; @@ -602,16 +649,12 @@ TEST_F(UpdaterTest, brotli_new_data) { generate_n(back_inserter(brotli_new_data), 4096 * 100, generator); size_t encoded_size = BrotliEncoderMaxCompressedSize(brotli_new_data.size()); - std::vector<uint8_t> encoded_data(encoded_size); + std::string encoded_data(encoded_size, 0); ASSERT_TRUE(BrotliEncoderCompress( BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW, BROTLI_DEFAULT_MODE, brotli_new_data.size(), - reinterpret_cast<const uint8_t*>(brotli_new_data.data()), &encoded_size, encoded_data.data())); - - ASSERT_EQ(0, zip_writer.WriteBytes(encoded_data.data(), encoded_size)); - ASSERT_EQ(0, zip_writer.FinishEntry()); - // Add a dummy patch data. - ASSERT_EQ(0, zip_writer.StartEntry("patch_data", 0)); - ASSERT_EQ(0, zip_writer.FinishEntry()); + reinterpret_cast<const uint8_t*>(brotli_new_data.data()), &encoded_size, + reinterpret_cast<uint8_t*>(const_cast<char*>(encoded_data.data())))); + encoded_data.resize(encoded_size); // Write a few small chunks of new data, then a large chunk, and finally a few small chunks. // This helps us to catch potential short writes. @@ -627,12 +670,15 @@ TEST_F(UpdaterTest, brotli_new_data) { "new 2,98,99", "new 2,99,100", }; - ASSERT_EQ(0, zip_writer.StartEntry("transfer_list", 0)); - std::string commands = android::base::Join(transfer_list, '\n'); - ASSERT_EQ(0, zip_writer.WriteBytes(commands.data(), commands.size())); - ASSERT_EQ(0, zip_writer.FinishEntry()); - ASSERT_EQ(0, zip_writer.Finish()); - ASSERT_EQ(0, fclose(zip_file_ptr)); + + std::unordered_map<std::string, std::string> entries = { + { "new.dat.br", std::move(encoded_data) }, + { "patch_data", "" }, + { "transfer_list", android::base::Join(transfer_list, '\n') }, + }; + + TemporaryFile zip_file; + BuildUpdatePackage(entries, zip_file.release()); MemMapping map; ASSERT_TRUE(map.MapFile(zip_file.path)); |