Add unittest for load cache manifest success path am: ead9fd765f

Original change: https://android-review.googlesource.com/c/platform/system/update_engine/+/1518960

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I205db8f04166e99bd8f9ec7639ca85f5fdc315a9
diff --git a/common/download_action.h b/common/download_action.h
index e154856..caa5a7b 100644
--- a/common/download_action.h
+++ b/common/download_action.h
@@ -87,7 +87,7 @@
   std::string Type() const override { return StaticType(); }
 
   // Testing
-  void SetTestFileWriter(FileWriter* writer) { writer_ = writer; }
+  void SetTestFileWriter(DeltaPerformer* writer) { writer_ = writer; }
 
   int GetHTTPResponseCode() { return http_fetcher_->http_response_code(); }
 
@@ -131,8 +131,8 @@
   bool interactive_;
 
   // The FileWriter that downloaded data should be written to. It will
-  // either point to *decompressing_file_writer_ or *delta_performer_.
-  FileWriter* writer_;
+  // either point to a writer for unittest or *delta_performer_.
+  DeltaPerformer* writer_;
 
   std::unique_ptr<DeltaPerformer> delta_performer_;
 
diff --git a/download_action.cc b/download_action.cc
index 076ee2c..0456298 100644
--- a/download_action.cc
+++ b/download_action.cc
@@ -105,11 +105,14 @@
     return false;
   }
 
+  if (writer_ && writer_ != delta_performer_.get()) {
+    LOG(INFO) << "Using writer for test.";
+  }
   ErrorCode error;
   const bool success =
-      delta_performer_->Write(
+      writer_->Write(
           cached_manifest_bytes.data(), cached_manifest_bytes.size(), &error) &&
-      delta_performer_->IsManifestValid();
+      writer_->IsManifestValid();
   if (success) {
     LOG(INFO) << "Successfully parsed cached manifest";
   } else {
@@ -162,9 +165,9 @@
                               manifest_metadata_size + manifest_signature_size);
     }
 
-    // If there're remaining unprocessed data blobs, fetch them. Be careful not
-    // to request data beyond the end of the payload to avoid 416 HTTP response
-    // error codes.
+    // If there're remaining unprocessed data blobs, fetch them. Be careful
+    // not to request data beyond the end of the payload to avoid 416 HTTP
+    // response error codes.
     int64_t next_data_offset = 0;
     prefs_->GetInt64(kPrefsUpdateStateNextDataOffset, &next_data_offset);
     uint64_t resume_offset =
diff --git a/download_action_android_unittest.cc b/download_action_android_unittest.cc
index 7db1c60..c1ad9c2 100644
--- a/download_action_android_unittest.cc
+++ b/download_action_android_unittest.cc
@@ -14,23 +14,30 @@
 // limitations under the License.
 //
 
-#include "common/mock_action_processor.h"
+#include <unistd.h>
+#include <cstdint>
+#include <memory>
+
+#include <gmock/gmock.h>
 #include <gmock/gmock-actions.h>
 #include <gmock/gmock-function-mocker.h>
 #include <gmock/gmock-spec-builders.h>
+#include <gtest/gtest.h>
 
-#include "payload_consumer/install_plan.h"
 #include "update_engine/common/action_pipe.h"
 #include "update_engine/common/boot_control_stub.h"
 #include "update_engine/common/constants.h"
 #include "update_engine/common/download_action.h"
+#include "update_engine/common/fake_hardware.h"
+#include "update_engine/common/mock_action_processor.h"
 #include "update_engine/common/mock_http_fetcher.h"
 #include "update_engine/common/mock_prefs.h"
 #include "update_engine/common/test_utils.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <memory>
+#include "update_engine/common/utils.h"
+#include "update_engine/payload_consumer/install_plan.h"
+#include "update_engine/payload_consumer/payload_constants.h"
+#include "update_engine/payload_generator/payload_file.h"
+#include "update_engine/payload_generator/payload_signer.h"
 
 namespace chromeos_update_engine {
 using testing::_;
@@ -38,6 +45,9 @@
 using testing::Return;
 using testing::SetArgPointee;
 
+extern const char* kUnittestPrivateKeyPath;
+extern const char* kUnittestPublicKeyPath;
+
 class DownloadActionTest : public ::testing::Test {
  public:
   static constexpr int64_t METADATA_SIZE = 1024;
@@ -73,12 +83,8 @@
   action_pipe->set_contents(install_plan);
 
   // takes ownership of passed in HttpFetcher
-  auto download_action =
-      std::make_unique<DownloadAction>(&prefs,
-                                       &boot_control,
-                                       nullptr,
-                                       http_fetcher,
-                                       false /* interactive */);
+  auto download_action = std::make_unique<DownloadAction>(
+      &prefs, &boot_control, nullptr, http_fetcher, false /* interactive */);
   download_action->set_in_pipe(action_pipe);
   MockActionProcessor mock_processor;
   download_action->SetProcessor(&mock_processor);
@@ -86,4 +92,85 @@
   ASSERT_EQ(download_action->http_fetcher()->GetBytesDownloaded(), data.size());
 }
 
+TEST_F(DownloadActionTest, CacheManifestValid) {
+  // Create a valid manifest
+  PayloadGenerationConfig config;
+  config.version.major = kMaxSupportedMajorPayloadVersion;
+  config.version.minor = kMaxSupportedMinorPayloadVersion;
+
+  PayloadFile payload_file;
+  ASSERT_TRUE(payload_file.Init(config));
+  PartitionConfig partition_config{"system"};
+  ScopedTempFile partition_file("part-system-XXXXXX", true);
+  ftruncate(partition_file.fd(), 4096);
+  partition_config.size = 4096;
+  partition_config.path = partition_file.path();
+  ASSERT_TRUE(
+      payload_file.AddPartition(partition_config, partition_config, {}, {}, 0));
+  ScopedTempFile blob_file("Blob-XXXXXX");
+  ScopedTempFile manifest_file("Manifest-XXXXXX");
+  uint64_t metadata_size;
+  std::string private_key =
+      test_utils::GetBuildArtifactsPath(kUnittestPrivateKeyPath);
+  payload_file.WritePayload(
+      manifest_file.path(), blob_file.path(), private_key, &metadata_size);
+  uint64_t signature_blob_length = 0;
+  ASSERT_TRUE(PayloadSigner::SignatureBlobLength({private_key},
+                                                 &signature_blob_length));
+  std::string data;
+  ASSERT_TRUE(utils::ReadFile(manifest_file.path(), &data));
+  data.resize(metadata_size + signature_blob_length);
+
+  // Setup the prefs so that manifest is cached
+  MockPrefs prefs;
+  EXPECT_CALL(prefs, GetInt64(kPrefsUpdateStatePayloadIndex, _))
+      .WillRepeatedly(DoAll(SetArgPointee<1>(0L), Return(true)));
+  EXPECT_CALL(prefs, GetInt64(kPrefsManifestMetadataSize, _))
+      .WillRepeatedly(DoAll(SetArgPointee<1>(metadata_size), Return(true)));
+  EXPECT_CALL(prefs, GetInt64(kPrefsManifestSignatureSize, _))
+      .WillRepeatedly(
+          DoAll(SetArgPointee<1>(signature_blob_length), Return(true)));
+  EXPECT_CALL(prefs, GetInt64(kPrefsUpdateStateNextDataOffset, _))
+      .WillRepeatedly(DoAll(SetArgPointee<1>(0L), Return(true)));
+  EXPECT_CALL(prefs, GetString(kPrefsManifestBytes, _))
+      .WillRepeatedly(DoAll(SetArgPointee<1>(data), Return(true)));
+  EXPECT_CALL(prefs, GetInt64(kPrefsUpdateStateNextOperation, _))
+      .WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(true)));
+  EXPECT_CALL(prefs, GetInt64(kPrefsUpdateStatePayloadIndex, _))
+      .WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(true)));
+
+  BootControlStub boot_control;
+  MockHttpFetcher* http_fetcher =
+      new MockHttpFetcher(data.data(), data.size(), nullptr);
+  http_fetcher->set_delay(false);
+  InstallPlan install_plan;
+  auto& payload = install_plan.payloads.emplace_back();
+  install_plan.download_url = "http://fake_url.invalid";
+  payload.size = data.size();
+  payload.payload_urls.emplace_back("http://fake_url.invalid");
+  install_plan.is_resume = true;
+  action_pipe->set_contents(install_plan);
+
+  // takes ownership of passed in HttpFetcher
+  auto download_action = std::make_unique<DownloadAction>(
+      &prefs, &boot_control, nullptr, http_fetcher, false /* interactive */);
+
+  FakeHardware hardware;
+  DeltaPerformer delta_performer(&prefs,
+                                 &boot_control,
+                                 &hardware,
+                                 nullptr,
+                                 &install_plan,
+                                 &payload,
+                                 false);
+  delta_performer.set_public_key_path(kUnittestPublicKeyPath);
+  download_action->SetTestFileWriter(&delta_performer);
+  download_action->set_in_pipe(action_pipe);
+  MockActionProcessor mock_processor;
+  download_action->SetProcessor(&mock_processor);
+  download_action->PerformAction();
+
+  // Manifest is cached, so no data should be downloaded from http fetcher.
+  ASSERT_EQ(download_action->http_fetcher()->GetBytesDownloaded(), 0UL);
+}
 }  // namespace chromeos_update_engine
diff --git a/payload_consumer/payload_verifier.cc b/payload_consumer/payload_verifier.cc
index 85902c8..8a3ea65 100644
--- a/payload_consumer/payload_verifier.cc
+++ b/payload_consumer/payload_verifier.cc
@@ -172,9 +172,7 @@
       if (padded_hash_data == sig_hash_data) {
         return true;
       }
-    }
-
-    if (key_type == EVP_PKEY_EC) {
+    } else if (key_type == EVP_PKEY_EC) {
       EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(public_key.get());
       TEST_AND_RETURN_FALSE(ec_key != nullptr);
       if (ECDSA_verify(0,
@@ -185,10 +183,10 @@
                        ec_key) == 1) {
         return true;
       }
+    } else {
+      LOG(ERROR) << "Unsupported key type " << key_type;
+      return false;
     }
-
-    LOG(ERROR) << "Unsupported key type " << key_type;
-    return false;
   }
   LOG(INFO) << "Failed to verify the signature with " << public_keys_.size()
             << " keys.";