| Kelvin Zhang | 9dd9305 | 2020-07-21 17:31:19 -0400 | [diff] [blame] | 1 | // | 
|  | 2 | // Copyright (C) 2020 The Android Open Source Project | 
|  | 3 | // | 
|  | 4 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 5 | // you may not use this file except in compliance with the License. | 
|  | 6 | // You may obtain a copy of the License at | 
|  | 7 | // | 
|  | 8 | //      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 9 | // | 
|  | 10 | // Unless required by applicable law or agreed to in writing, software | 
|  | 11 | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 13 | // See the License for the specific language governing permissions and | 
|  | 14 | // limitations under the License. | 
|  | 15 | // | 
|  | 16 |  | 
| Kelvin Zhang | ead9fd7 | 2020-12-03 12:57:35 -0500 | [diff] [blame] | 17 | #include <unistd.h> | 
|  | 18 | #include <cstdint> | 
|  | 19 | #include <memory> | 
|  | 20 |  | 
|  | 21 | #include <gmock/gmock.h> | 
| Kelvin Zhang | 9dd9305 | 2020-07-21 17:31:19 -0400 | [diff] [blame] | 22 | #include <gmock/gmock-actions.h> | 
|  | 23 | #include <gmock/gmock-function-mocker.h> | 
|  | 24 | #include <gmock/gmock-spec-builders.h> | 
| Kelvin Zhang | ead9fd7 | 2020-12-03 12:57:35 -0500 | [diff] [blame] | 25 | #include <gtest/gtest.h> | 
| Kelvin Zhang | 9dd9305 | 2020-07-21 17:31:19 -0400 | [diff] [blame] | 26 |  | 
| Kelvin Zhang | 9dd9305 | 2020-07-21 17:31:19 -0400 | [diff] [blame] | 27 | #include "update_engine/common/action_pipe.h" | 
|  | 28 | #include "update_engine/common/boot_control_stub.h" | 
|  | 29 | #include "update_engine/common/constants.h" | 
| Amin Hassani | ec7bc11 | 2020-10-29 16:47:58 -0700 | [diff] [blame] | 30 | #include "update_engine/common/download_action.h" | 
| Kelvin Zhang | ead9fd7 | 2020-12-03 12:57:35 -0500 | [diff] [blame] | 31 | #include "update_engine/common/fake_hardware.h" | 
|  | 32 | #include "update_engine/common/mock_action_processor.h" | 
| Kelvin Zhang | 9dd9305 | 2020-07-21 17:31:19 -0400 | [diff] [blame] | 33 | #include "update_engine/common/mock_http_fetcher.h" | 
|  | 34 | #include "update_engine/common/mock_prefs.h" | 
| Kelvin Zhang | df3c195 | 2021-10-06 18:56:55 -0700 | [diff] [blame] | 35 | #include "update_engine/common/testing_constants.h" | 
| Kelvin Zhang | 9dd9305 | 2020-07-21 17:31:19 -0400 | [diff] [blame] | 36 | #include "update_engine/common/test_utils.h" | 
| Kelvin Zhang | ead9fd7 | 2020-12-03 12:57:35 -0500 | [diff] [blame] | 37 | #include "update_engine/common/utils.h" | 
|  | 38 | #include "update_engine/payload_consumer/install_plan.h" | 
|  | 39 | #include "update_engine/payload_consumer/payload_constants.h" | 
| Kelvin Zhang | 4f28a6c | 2021-01-14 14:04:57 -0500 | [diff] [blame] | 40 | #include "update_engine/payload_generator/annotated_operation.h" | 
| Kelvin Zhang | ead9fd7 | 2020-12-03 12:57:35 -0500 | [diff] [blame] | 41 | #include "update_engine/payload_generator/payload_file.h" | 
|  | 42 | #include "update_engine/payload_generator/payload_signer.h" | 
| Kelvin Zhang | 9dd9305 | 2020-07-21 17:31:19 -0400 | [diff] [blame] | 43 |  | 
|  | 44 | namespace chromeos_update_engine { | 
|  | 45 | using testing::_; | 
|  | 46 | using testing::DoAll; | 
|  | 47 | using testing::Return; | 
|  | 48 | using testing::SetArgPointee; | 
|  | 49 |  | 
|  | 50 | class DownloadActionTest : public ::testing::Test { | 
|  | 51 | public: | 
|  | 52 | static constexpr int64_t METADATA_SIZE = 1024; | 
|  | 53 | static constexpr int64_t SIGNATURE_SIZE = 256; | 
|  | 54 | std::shared_ptr<ActionPipe<InstallPlan>> action_pipe{ | 
|  | 55 | new ActionPipe<InstallPlan>()}; | 
|  | 56 | }; | 
|  | 57 |  | 
|  | 58 | TEST_F(DownloadActionTest, CacheManifestInvalid) { | 
|  | 59 | std::string data(METADATA_SIZE + SIGNATURE_SIZE, '-'); | 
|  | 60 | MockPrefs prefs; | 
|  | 61 | EXPECT_CALL(prefs, GetInt64(kPrefsUpdateStatePayloadIndex, _)) | 
|  | 62 | .WillRepeatedly(DoAll(SetArgPointee<1>(0L), Return(true))); | 
|  | 63 | EXPECT_CALL(prefs, GetInt64(kPrefsManifestMetadataSize, _)) | 
|  | 64 | .WillRepeatedly(DoAll(SetArgPointee<1>(METADATA_SIZE), Return(true))); | 
|  | 65 | EXPECT_CALL(prefs, GetInt64(kPrefsManifestSignatureSize, _)) | 
|  | 66 | .WillRepeatedly(DoAll(SetArgPointee<1>(SIGNATURE_SIZE), Return(true))); | 
|  | 67 | EXPECT_CALL(prefs, GetInt64(kPrefsUpdateStateNextDataOffset, _)) | 
|  | 68 | .WillRepeatedly(DoAll(SetArgPointee<1>(0L), Return(true))); | 
|  | 69 | EXPECT_CALL(prefs, GetString(kPrefsManifestBytes, _)) | 
|  | 70 | .WillRepeatedly(DoAll(SetArgPointee<1>(data), Return(true))); | 
|  | 71 |  | 
|  | 72 | BootControlStub boot_control; | 
|  | 73 | MockHttpFetcher* http_fetcher = | 
|  | 74 | new MockHttpFetcher(data.data(), data.size(), nullptr); | 
|  | 75 | http_fetcher->set_delay(false); | 
|  | 76 | InstallPlan install_plan; | 
|  | 77 | auto& payload = install_plan.payloads.emplace_back(); | 
|  | 78 | install_plan.download_url = "http://fake_url.invalid"; | 
|  | 79 | payload.size = data.size(); | 
|  | 80 | payload.payload_urls.emplace_back("http://fake_url.invalid"); | 
|  | 81 | install_plan.is_resume = true; | 
|  | 82 | action_pipe->set_contents(install_plan); | 
|  | 83 |  | 
|  | 84 | // takes ownership of passed in HttpFetcher | 
| Kelvin Zhang | ead9fd7 | 2020-12-03 12:57:35 -0500 | [diff] [blame] | 85 | auto download_action = std::make_unique<DownloadAction>( | 
|  | 86 | &prefs, &boot_control, nullptr, http_fetcher, false /* interactive */); | 
| Kelvin Zhang | 9dd9305 | 2020-07-21 17:31:19 -0400 | [diff] [blame] | 87 | download_action->set_in_pipe(action_pipe); | 
|  | 88 | MockActionProcessor mock_processor; | 
|  | 89 | download_action->SetProcessor(&mock_processor); | 
|  | 90 | download_action->PerformAction(); | 
|  | 91 | ASSERT_EQ(download_action->http_fetcher()->GetBytesDownloaded(), data.size()); | 
|  | 92 | } | 
|  | 93 |  | 
| Kelvin Zhang | ead9fd7 | 2020-12-03 12:57:35 -0500 | [diff] [blame] | 94 | TEST_F(DownloadActionTest, CacheManifestValid) { | 
|  | 95 | // Create a valid manifest | 
|  | 96 | PayloadGenerationConfig config; | 
|  | 97 | config.version.major = kMaxSupportedMajorPayloadVersion; | 
|  | 98 | config.version.minor = kMaxSupportedMinorPayloadVersion; | 
|  | 99 |  | 
|  | 100 | PayloadFile payload_file; | 
|  | 101 | ASSERT_TRUE(payload_file.Init(config)); | 
|  | 102 | PartitionConfig partition_config{"system"}; | 
|  | 103 | ScopedTempFile partition_file("part-system-XXXXXX", true); | 
|  | 104 | ftruncate(partition_file.fd(), 4096); | 
|  | 105 | partition_config.size = 4096; | 
|  | 106 | partition_config.path = partition_file.path(); | 
|  | 107 | ASSERT_TRUE( | 
|  | 108 | payload_file.AddPartition(partition_config, partition_config, {}, {}, 0)); | 
|  | 109 | ScopedTempFile blob_file("Blob-XXXXXX"); | 
|  | 110 | ScopedTempFile manifest_file("Manifest-XXXXXX"); | 
|  | 111 | uint64_t metadata_size; | 
|  | 112 | std::string private_key = | 
|  | 113 | test_utils::GetBuildArtifactsPath(kUnittestPrivateKeyPath); | 
|  | 114 | payload_file.WritePayload( | 
|  | 115 | manifest_file.path(), blob_file.path(), private_key, &metadata_size); | 
|  | 116 | uint64_t signature_blob_length = 0; | 
|  | 117 | ASSERT_TRUE(PayloadSigner::SignatureBlobLength({private_key}, | 
|  | 118 | &signature_blob_length)); | 
|  | 119 | std::string data; | 
|  | 120 | ASSERT_TRUE(utils::ReadFile(manifest_file.path(), &data)); | 
|  | 121 | data.resize(metadata_size + signature_blob_length); | 
|  | 122 |  | 
|  | 123 | // Setup the prefs so that manifest is cached | 
|  | 124 | MockPrefs prefs; | 
|  | 125 | EXPECT_CALL(prefs, GetInt64(kPrefsUpdateStatePayloadIndex, _)) | 
|  | 126 | .WillRepeatedly(DoAll(SetArgPointee<1>(0L), Return(true))); | 
|  | 127 | EXPECT_CALL(prefs, GetInt64(kPrefsManifestMetadataSize, _)) | 
|  | 128 | .WillRepeatedly(DoAll(SetArgPointee<1>(metadata_size), Return(true))); | 
|  | 129 | EXPECT_CALL(prefs, GetInt64(kPrefsManifestSignatureSize, _)) | 
|  | 130 | .WillRepeatedly( | 
|  | 131 | DoAll(SetArgPointee<1>(signature_blob_length), Return(true))); | 
|  | 132 | EXPECT_CALL(prefs, GetInt64(kPrefsUpdateStateNextDataOffset, _)) | 
|  | 133 | .WillRepeatedly(DoAll(SetArgPointee<1>(0L), Return(true))); | 
|  | 134 | EXPECT_CALL(prefs, GetString(kPrefsManifestBytes, _)) | 
|  | 135 | .WillRepeatedly(DoAll(SetArgPointee<1>(data), Return(true))); | 
|  | 136 | EXPECT_CALL(prefs, GetInt64(kPrefsUpdateStateNextOperation, _)) | 
|  | 137 | .WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(true))); | 
|  | 138 | EXPECT_CALL(prefs, GetInt64(kPrefsUpdateStatePayloadIndex, _)) | 
|  | 139 | .WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(true))); | 
|  | 140 |  | 
|  | 141 | BootControlStub boot_control; | 
|  | 142 | MockHttpFetcher* http_fetcher = | 
|  | 143 | new MockHttpFetcher(data.data(), data.size(), nullptr); | 
|  | 144 | http_fetcher->set_delay(false); | 
|  | 145 | InstallPlan install_plan; | 
|  | 146 | auto& payload = install_plan.payloads.emplace_back(); | 
|  | 147 | install_plan.download_url = "http://fake_url.invalid"; | 
|  | 148 | payload.size = data.size(); | 
|  | 149 | payload.payload_urls.emplace_back("http://fake_url.invalid"); | 
|  | 150 | install_plan.is_resume = true; | 
| Kelvin Zhang | 4f28a6c | 2021-01-14 14:04:57 -0500 | [diff] [blame] | 151 | auto& install_part = install_plan.partitions.emplace_back(); | 
|  | 152 | install_part.source_path = partition_file.path(); | 
|  | 153 | install_part.target_path = partition_file.path(); | 
| Kelvin Zhang | ead9fd7 | 2020-12-03 12:57:35 -0500 | [diff] [blame] | 154 | action_pipe->set_contents(install_plan); | 
|  | 155 |  | 
| Kelvin Zhang | 4f28a6c | 2021-01-14 14:04:57 -0500 | [diff] [blame] | 156 | FakeHardware hardware; | 
| Kelvin Zhang | ead9fd7 | 2020-12-03 12:57:35 -0500 | [diff] [blame] | 157 | // takes ownership of passed in HttpFetcher | 
|  | 158 | auto download_action = std::make_unique<DownloadAction>( | 
| Kelvin Zhang | 4f28a6c | 2021-01-14 14:04:57 -0500 | [diff] [blame] | 159 | &prefs, &boot_control, &hardware, http_fetcher, false /* interactive */); | 
| Kelvin Zhang | ead9fd7 | 2020-12-03 12:57:35 -0500 | [diff] [blame] | 160 |  | 
| Kelvin Zhang | 22b62e4 | 2020-12-14 14:50:40 -0500 | [diff] [blame] | 161 | auto delta_performer = std::make_unique<DeltaPerformer>(&prefs, | 
|  | 162 | &boot_control, | 
|  | 163 | &hardware, | 
|  | 164 | nullptr, | 
|  | 165 | &install_plan, | 
|  | 166 | &payload, | 
|  | 167 | false); | 
|  | 168 | delta_performer->set_public_key_path(kUnittestPublicKeyPath); | 
|  | 169 | download_action->SetTestFileWriter(std::move(delta_performer)); | 
| Kelvin Zhang | ead9fd7 | 2020-12-03 12:57:35 -0500 | [diff] [blame] | 170 | download_action->set_in_pipe(action_pipe); | 
|  | 171 | MockActionProcessor mock_processor; | 
|  | 172 | download_action->SetProcessor(&mock_processor); | 
|  | 173 | download_action->PerformAction(); | 
|  | 174 |  | 
|  | 175 | // Manifest is cached, so no data should be downloaded from http fetcher. | 
|  | 176 | ASSERT_EQ(download_action->http_fetcher()->GetBytesDownloaded(), 0UL); | 
|  | 177 | } | 
| Kelvin Zhang | 9dd9305 | 2020-07-21 17:31:19 -0400 | [diff] [blame] | 178 | }  // namespace chromeos_update_engine |