Merge "tests: Refactor the common lines in UpdaterTest." am: faa47854f4
am: 83e341e754

Change-Id: I14a0f04552fdbe0f61e374438107ed845331f5a1
diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp
index 48363a6..d958215 100644
--- a/tests/component/updater_test.cpp
+++ b/tests/component/updater_test.cpp
@@ -27,6 +27,8 @@
 #include <vector>
 
 #include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
@@ -48,7 +50,11 @@
 #include "updater/install.h"
 #include "updater/updater.h"
 
-struct selabel_handle *sehandle = nullptr;
+using PackageEntries = std::unordered_map<std::string, std::string>;
+
+static constexpr size_t kTransferListHeaderLines = 4;
+
+struct selabel_handle* sehandle = nullptr;
 
 static void expect(const char* expected, const char* expr_str, CauseCode cause_code,
                    UpdaterInfo* info = nullptr) {
@@ -76,12 +82,12 @@
   ASSERT_EQ(cause_code, state.cause_code);
 }
 
-static void BuildUpdatePackage(const std::unordered_map<std::string, std::string>& entries,
-                               int fd) {
+static void BuildUpdatePackage(const PackageEntries& entries, int fd) {
   FILE* zip_file_ptr = fdopen(fd, "wb");
   ZipWriter zip_writer(zip_file_ptr);
 
   for (const auto& entry : entries) {
+    // All the entries are written as STORED.
     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()));
@@ -93,6 +99,37 @@
   ASSERT_EQ(0, fclose(zip_file_ptr));
 }
 
+static void RunBlockImageUpdate(bool is_verify, const PackageEntries& entries,
+                                const std::string& image_file, const std::string& result) {
+  CHECK(entries.find("transfer_list") != entries.end());
+
+  // 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;
+
+  std::string new_data = entries.find("new_data.br") != entries.end() ? "new_data.br" : "new_data";
+  std::string script = is_verify ? "block_image_verify" : "block_image_update";
+  script += R"((")" + image_file + R"(", package_extract_file("transfer_list"), ")" + new_data +
+            R"(", "patch_data"))";
+  expect(result.c_str(), script.c_str(), kNoCause, &updater_info);
+
+  ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
+  CloseArchive(handle);
+}
+
 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);
@@ -101,19 +138,30 @@
 
 class UpdaterTest : public ::testing::Test {
  protected:
-  virtual void SetUp() override {
+  void SetUp() override {
     RegisterBuiltins();
     RegisterInstallFunctions();
     RegisterBlockImageFunctions();
 
     Paths::Get().set_cache_temp_source(temp_saved_source_.path);
-    Paths::Get().set_last_command_file(temp_last_command_.path);
     Paths::Get().set_stash_directory_base(temp_stash_base_.path);
+
+    image_file_ = image_temp_file_.path;
+  }
+
+  void TearDown() override {
+    // Clear partition updated marker if any.
+    std::string updated_marker{ temp_stash_base_.path };
+    updated_marker += "/" + get_sha1(image_temp_file_.path) + ".UPDATED";
+    ASSERT_TRUE(android::base::RemoveFileIfExists(updated_marker));
   }
 
   TemporaryFile temp_saved_source_;
-  TemporaryFile temp_last_command_;
   TemporaryDir temp_stash_base_;
+  std::string image_file_;
+
+ private:
+  TemporaryFile image_temp_file_;
 };
 
 TEST_F(UpdaterTest, getprop) {
@@ -453,16 +501,18 @@
 
   // 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));
+  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));
 
   // 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 = {
+  std::vector<std::string> transfer_list{
+    // clang-format off
     "4",
     "2",
     "0",
@@ -471,183 +521,108 @@
     android::base::StringPrintf("bsdiff 0 %zu %s %s 2,0,2 2 - %s:2,0,2", patch_content.size(),
                                 src_hash.c_str(), tgt_hash.c_str(), src_hash.c_str()),
     "free " + src_hash,
+    // clang-format on
   };
 
-  std::unordered_map<std::string, std::string> entries = {
+  PackageEntries entries{
     { "new_data", "" },
     { "patch_data", patch_content },
     { "transfer_list", android::base::Join(transfer_list, '\n') },
   };
 
-  // Build the update package.
-  TemporaryFile zip_file;
-  BuildUpdatePackage(entries, zip_file.release());
+  ASSERT_TRUE(android::base::WriteStringToFile(src_content, image_file_));
 
-  MemMapping map;
-  ASSERT_TRUE(map.MapFile(zip_file.path));
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle));
+  RunBlockImageUpdate(false, entries, image_file_, "t");
 
-  // 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;
-
-  // 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) +
-      R"(", package_extract_file("transfer_list"), "new_data", "patch_data"))";
-  expect("t", script.c_str(), kNoCause, &updater_info);
   // The update_file should be patched correctly.
   std::string updated_content;
-  ASSERT_TRUE(android::base::ReadFileToString(update_file.path, &updated_content));
-  ASSERT_EQ(tgt_hash, get_sha1(updated_content));
-
-  ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
-  CloseArchive(handle);
+  ASSERT_TRUE(android::base::ReadFileToString(image_file_, &updated_content));
+  ASSERT_EQ(tgt_content, updated_content);
 }
 
 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",
+  std::vector<std::string> transfer_list{
+    // clang-format off
+    "4",
+    "2",
+    "0",
+    "2",
+    "stash " + src_hash + " 2,0,2",
+    "free " + src_hash,
+    "fail",
+    // clang-format on
   };
 
   // Add a new data of 10 bytes to test the deadlock.
-  std::unordered_map<std::string, std::string> entries = {
+  PackageEntries 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());
+  ASSERT_TRUE(android::base::WriteStringToFile(src_content, image_file_));
 
-  MemMapping map;
-  ASSERT_TRUE(map.MapFile(zip_file.path));
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle));
+  RunBlockImageUpdate(false, entries, image_file_, "");
 
-  // 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 name_digest = get_sha1(image_file_);
   std::string stash_base = std::string(temp_stash_base_.path) + "/" + name_digest;
   ASSERT_EQ(0, access(stash_base.c_str(), F_OK));
+  // Expect the stashed blocks to be freed.
   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_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;
-  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;
-  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 = {
+  std::vector<std::string> transfer_list{
+    // clang-format off
     "4",
     "1",
     "0",
     "0",
     "new 2,0,1",
+    // clang-format on
   };
 
-  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') },
+  // Write 4096 + 100 bytes of new data.
+  PackageEntries entries{
+    { "new_data", std::string(4196, 0) },
     { "patch_data", "" },
     { "transfer_list", android::base::Join(transfer_list, '\n') },
   };
 
-  TemporaryFile zip_file;
-  BuildUpdatePackage(entries, zip_file.release());
+  RunBlockImageUpdate(false, entries, image_file_, "t");
+}
 
-  MemMapping map;
-  ASSERT_TRUE(map.MapFile(zip_file.path));
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle));
+TEST_F(UpdaterTest, new_data_short_write) {
+  std::vector<std::string> transfer_list{
+    // clang-format off
+    "4",
+    "1",
+    "0",
+    "0",
+    "new 2,0,1",
+    // clang-format on
+  };
 
-  // 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;
+  PackageEntries entries{
+    { "patch_data", "" },
+    { "transfer_list", android::base::Join(transfer_list, '\n') },
+  };
 
   // Updater should report the failure gracefully rather than stuck in deadlock.
-  TemporaryFile update_file;
-  std::string script_empty_data = "block_image_update(\"" + std::string(update_file.path) +
-      R"(", package_extract_file("transfer_list"), "empty_new_data", "patch_data"))";
-  expect("", script_empty_data.c_str(), kNoCause, &updater_info);
+  entries["new_data"] = "";
+  RunBlockImageUpdate(false, entries, image_file_, "");
 
-  std::string script_short_data = "block_image_update(\"" + std::string(update_file.path) +
-      R"(", package_extract_file("transfer_list"), "short_new_data", "patch_data"))";
-  expect("", script_short_data.c_str(), kNoCause, &updater_info);
+  entries["new_data"] = std::string(10, 'a');
+  RunBlockImageUpdate(false, entries, image_file_, "");
 
   // Expect to write 1 block of new data successfully.
-  std::string script_exact_data = "block_image_update(\"" + std::string(update_file.path) +
-      R"(", package_extract_file("transfer_list"), "exact_new_data", "patch_data"))";
-  expect("t", script_exact_data.c_str(), kNoCause, &updater_info);
-
-  ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
-  CloseArchive(handle);
+  entries["new_data"] = std::string(4096, 'a');
+  RunBlockImageUpdate(false, entries, image_file_, "t");
 }
 
 TEST_F(UpdaterTest, brotli_new_data) {
@@ -680,55 +655,30 @@
     "new 2,99,100",
   };
 
-  std::unordered_map<std::string, std::string> entries = {
-    { "new.dat.br", std::move(encoded_data) },
+  PackageEntries entries{
+    { "new_data.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));
-  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(), "wb");
-  updater_info.package_zip_addr = map.addr;
-  updater_info.package_zip_len = map.length;
-
-  // Check if we can decompress the new data correctly.
-  TemporaryFile update_file;
-  std::string script_new_data =
-      "block_image_update(\"" + std::string(update_file.path) +
-      R"(", package_extract_file("transfer_list"), "new.dat.br", "patch_data"))";
-  expect("t", script_new_data.c_str(), kNoCause, &updater_info);
+  RunBlockImageUpdate(false, entries, image_file_, "t");
 
   std::string updated_content;
-  ASSERT_TRUE(android::base::ReadFileToString(update_file.path, &updated_content));
+  ASSERT_TRUE(android::base::ReadFileToString(image_file_, &updated_content));
   ASSERT_EQ(brotli_new_data, updated_content);
-
-  ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
-  CloseArchive(handle);
 }
 
 TEST_F(UpdaterTest, last_command_update) {
-  std::string last_command_file = Paths::Get().last_command_file();
-
-  std::string block1 = std::string(4096, '1');
-  std::string block2 = std::string(4096, '2');
-  std::string block3 = std::string(4096, '3');
+  std::string block1(4096, '1');
+  std::string block2(4096, '2');
+  std::string block3(4096, '3');
   std::string block1_hash = get_sha1(block1);
   std::string block2_hash = get_sha1(block2);
   std::string block3_hash = get_sha1(block3);
 
   // Compose the transfer list to fail the first update.
-  std::vector<std::string> transfer_list_fail = {
+  std::vector<std::string> transfer_list_fail{
+    // clang-format off
     "4",
     "2",
     "0",
@@ -737,10 +687,12 @@
     "move " + block1_hash + " 2,1,2 1 2,0,1",
     "stash " + block3_hash + " 2,2,3",
     "fail",
+    // clang-format on
   };
 
   // Mimic a resumed update with the same transfer commands.
-  std::vector<std::string> transfer_list_continue = {
+  std::vector<std::string> transfer_list_continue{
+    // clang-format off
     "4",
     "2",
     "0",
@@ -749,127 +701,91 @@
     "move " + block1_hash + " 2,1,2 1 2,0,1",
     "stash " + block3_hash + " 2,2,3",
     "move " + block1_hash + " 2,2,3 1 2,0,1",
+    // clang-format on
   };
 
-  std::unordered_map<std::string, std::string> entries = {
+  ASSERT_TRUE(android::base::WriteStringToFile(block1 + block2 + block3, image_file_));
+
+  PackageEntries entries{
     { "new_data", "" },
     { "patch_data", "" },
-    { "transfer_list_fail", android::base::Join(transfer_list_fail, '\n') },
-    { "transfer_list_continue", android::base::Join(transfer_list_continue, '\n') },
+    { "transfer_list", android::base::Join(transfer_list_fail, '\n') },
   };
 
-  // Build the update package.
-  TemporaryFile zip_file;
-  BuildUpdatePackage(entries, zip_file.release());
+  // "2\nstash " + block3_hash + " 2,2,3"
+  std::string last_command_content = "2\n" + transfer_list_fail[kTransferListHeaderLines + 2];
+  TemporaryFile last_command_file;
+  Paths::Get().set_last_command_file(last_command_file.path);
 
-  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;
-
-  std::string src_content = block1 + block2 + block3;
-  TemporaryFile update_file;
-  ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path));
-  std::string script =
-      "block_image_update(\"" + std::string(update_file.path) +
-      R"(", package_extract_file("transfer_list_fail"), "new_data", "patch_data"))";
-  expect("", script.c_str(), kNoCause, &updater_info);
+  RunBlockImageUpdate(false, entries, image_file_, "");
 
   // Expect last_command to contain the last stash command.
-  std::string last_command_content;
-  ASSERT_TRUE(android::base::ReadFileToString(last_command_file.c_str(), &last_command_content));
-  EXPECT_EQ("2\nstash " + block3_hash + " 2,2,3", last_command_content);
+  std::string last_command_actual;
+  ASSERT_TRUE(android::base::ReadFileToString(last_command_file.path, &last_command_actual));
+  EXPECT_EQ(last_command_content, last_command_actual);
+
   std::string updated_contents;
-  ASSERT_TRUE(android::base::ReadFileToString(update_file.path, &updated_contents));
+  ASSERT_TRUE(android::base::ReadFileToString(image_file_, &updated_contents));
   ASSERT_EQ(block1 + block1 + block3, updated_contents);
 
-  // Resume the update, expect the first 'move' to be skipped but the second 'move' to be executed.
-  ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path));
-  std::string script_second_update =
-      "block_image_update(\"" + std::string(update_file.path) +
-      R"(", package_extract_file("transfer_list_continue"), "new_data", "patch_data"))";
-  expect("t", script_second_update.c_str(), kNoCause, &updater_info);
-  ASSERT_TRUE(android::base::ReadFileToString(update_file.path, &updated_contents));
-  ASSERT_EQ(block1 + block2 + block1, updated_contents);
+  // "Resume" the update. Expect the first 'move' to be skipped but the second 'move' to be
+  // executed. Note that we intentionally reset the image file.
+  entries["transfer_list"] = android::base::Join(transfer_list_continue, '\n');
+  ASSERT_TRUE(android::base::WriteStringToFile(block1 + block2 + block3, image_file_));
+  RunBlockImageUpdate(false, entries, image_file_, "t");
 
-  ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
-  CloseArchive(handle);
+  ASSERT_TRUE(android::base::ReadFileToString(image_file_, &updated_contents));
+  ASSERT_EQ(block1 + block2 + block1, updated_contents);
 }
 
 TEST_F(UpdaterTest, last_command_update_unresumable) {
-  std::string last_command_file = Paths::Get().last_command_file();
-
-  std::string block1 = std::string(4096, '1');
-  std::string block2 = std::string(4096, '2');
+  std::string block1(4096, '1');
+  std::string block2(4096, '2');
   std::string block1_hash = get_sha1(block1);
   std::string block2_hash = get_sha1(block2);
 
   // Construct an unresumable update with source blocks mismatch.
-  std::vector<std::string> transfer_list_unresumable = {
-    "4", "2", "0", "2", "stash " + block1_hash + " 2,0,1", "move " + block2_hash + " 2,1,2 1 2,0,1",
+  std::vector<std::string> transfer_list_unresumable{
+    // clang-format off
+    "4",
+    "2",
+    "0",
+    "2",
+    "stash " + block1_hash + " 2,0,1",
+    "move " + block2_hash + " 2,1,2 1 2,0,1",
+    // clang-format on
   };
 
-  std::unordered_map<std::string, std::string> entries = {
+  PackageEntries entries{
     { "new_data", "" },
     { "patch_data", "" },
-    { "transfer_list_unresumable", android::base::Join(transfer_list_unresumable, '\n') },
+    { "transfer_list", android::base::Join(transfer_list_unresumable, '\n') },
   };
 
-  // Build the update package.
-  TemporaryFile zip_file;
-  BuildUpdatePackage(entries, zip_file.release());
+  ASSERT_TRUE(android::base::WriteStringToFile(block1 + block1, image_file_));
 
-  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 last_command_file.
+  TemporaryFile last_command_file;
+  Paths::Get().set_last_command_file(last_command_file.path);
+  std::string last_command_content = "0\n" + transfer_list_unresumable[kTransferListHeaderLines];
+  ASSERT_TRUE(android::base::WriteStringToFile(last_command_content, last_command_file.path));
 
-  // 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;
+  RunBlockImageUpdate(false, entries, image_file_, "");
 
-  // Set up the last_command_file
-  ASSERT_TRUE(
-      android::base::WriteStringToFile("0\nstash " + block1_hash + " 2,0,1", last_command_file));
-
-  // The last_command_file will be deleted if the update encounters an unresumable failure
-  // later.
-  std::string src_content = block1 + block1;
-  TemporaryFile update_file;
-  ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path));
-  std::string script =
-      "block_image_update(\"" + std::string(update_file.path) +
-      R"(", package_extract_file("transfer_list_unresumable"), "new_data", "patch_data"))";
-  expect("", script.c_str(), kNoCause, &updater_info);
-  ASSERT_EQ(-1, access(last_command_file.c_str(), R_OK));
-
-  ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
-  CloseArchive(handle);
+  // The last_command_file will be deleted if the update encounters an unresumable failure later.
+  ASSERT_EQ(-1, access(last_command_file.path, R_OK));
 }
 
 TEST_F(UpdaterTest, last_command_verify) {
-  std::string last_command_file = Paths::Get().last_command_file();
-
-  std::string block1 = std::string(4096, '1');
-  std::string block2 = std::string(4096, '2');
-  std::string block3 = std::string(4096, '3');
+  std::string block1(4096, '1');
+  std::string block2(4096, '2');
+  std::string block3(4096, '3');
   std::string block1_hash = get_sha1(block1);
   std::string block2_hash = get_sha1(block2);
   std::string block3_hash = get_sha1(block3);
 
-  std::vector<std::string> transfer_list_verify = {
+  std::vector<std::string> transfer_list_verify{
+    // clang-format off
     "4",
     "2",
     "0",
@@ -878,55 +794,35 @@
     "move " + block1_hash + " 2,0,1 1 2,0,1",
     "move " + block1_hash + " 2,1,2 1 2,0,1",
     "stash " + block3_hash + " 2,2,3",
+    // clang-format on
   };
 
-  std::unordered_map<std::string, std::string> entries = {
+  PackageEntries entries{
     { "new_data", "" },
     { "patch_data", "" },
-    { "transfer_list_verify", android::base::Join(transfer_list_verify, '\n') },
+    { "transfer_list", android::base::Join(transfer_list_verify, '\n') },
   };
 
-  // Build the update package.
-  TemporaryFile zip_file;
-  BuildUpdatePackage(entries, zip_file.release());
+  ASSERT_TRUE(android::base::WriteStringToFile(block1 + block1 + block3, image_file_));
 
-  MemMapping map;
-  ASSERT_TRUE(map.MapFile(zip_file.path));
-  ZipArchiveHandle handle;
-  ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle));
+  TemporaryFile last_command_file;
+  Paths::Get().set_last_command_file(last_command_file.path);
+  // Last command: "move " + block1_hash + " 2,1,2 1 2,0,1"
+  std::string last_command_content = "2\n" + transfer_list_verify[kTransferListHeaderLines + 2];
 
-  // 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;
+  // First run: expect the verification to succeed and the last_command_file is intact.
+  ASSERT_TRUE(android::base::WriteStringToFile(last_command_content, last_command_file.path));
 
-  std::string src_content = block1 + block1 + block3;
-  TemporaryFile update_file;
-  ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path));
+  RunBlockImageUpdate(true, entries, image_file_, "t");
 
-  ASSERT_TRUE(
-      android::base::WriteStringToFile("2\nstash " + block3_hash + " 2,2,3", last_command_file));
+  std::string last_command_actual;
+  ASSERT_TRUE(android::base::ReadFileToString(last_command_file.path, &last_command_actual));
+  EXPECT_EQ(last_command_content, last_command_actual);
 
-  // Expect the verification to succeed and the last_command_file is intact.
-  std::string script_verify =
-      "block_image_verify(\"" + std::string(update_file.path) +
-      R"(", package_extract_file("transfer_list_verify"), "new_data","patch_data"))";
-  expect("t", script_verify.c_str(), kNoCause, &updater_info);
-
-  std::string last_command_content;
-  ASSERT_TRUE(android::base::ReadFileToString(last_command_file.c_str(), &last_command_content));
-  EXPECT_EQ("2\nstash " + block3_hash + " 2,2,3", last_command_content);
-
-  // Expect the verification to succeed but last_command_file to be deleted; because the target
-  // blocks don't have the expected contents for the second move command.
-  src_content = block1 + block2 + block3;
-  ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path));
-  expect("t", script_verify.c_str(), kNoCause, &updater_info);
-  ASSERT_EQ(-1, access(last_command_file.c_str(), R_OK));
-
-  ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
-  CloseArchive(handle);
+  // Second run with a mismatching block image: expect the verification to succeed but
+  // last_command_file to be deleted; because the target blocks in the last command don't have the
+  // expected contents for the second move command.
+  ASSERT_TRUE(android::base::WriteStringToFile(block1 + block2 + block3, image_file_));
+  RunBlockImageUpdate(true, entries, image_file_, "t");
+  ASSERT_EQ(-1, access(last_command_file.path, R_OK));
 }