1 // 2 // Copyright (C) 2011 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 17 #include "update_engine/payload_consumer/download_action.h" 18 19 #include <gmock/gmock.h> 20 #include <gtest/gtest.h> 21 22 #include <memory> 23 #include <string> 24 #include <utility> 25 #include <vector> 26 27 #include <base/bind.h> 28 #include <base/files/file_path.h> 29 #include <base/files/file_util.h> 30 #include <base/location.h> 31 #include <base/strings/stringprintf.h> 32 #include <brillo/message_loops/fake_message_loop.h> 33 #include <brillo/message_loops/message_loop.h> 34 35 #include "update_engine/common/action_pipe.h" 36 #include "update_engine/common/hash_calculator.h" 37 #include "update_engine/common/mock_http_fetcher.h" 38 #include "update_engine/common/mock_prefs.h" 39 #include "update_engine/common/test_utils.h" 40 #include "update_engine/common/utils.h" 41 #include "update_engine/fake_p2p_manager_configuration.h" 42 #include "update_engine/fake_system_state.h" 43 #include "update_engine/mock_file_writer.h" 44 #include "update_engine/payload_consumer/mock_download_action.h" 45 #include "update_engine/update_manager/fake_update_manager.h" 46 47 namespace chromeos_update_engine { 48 49 using base::FilePath; 50 using base::ReadFileToString; 51 using base::WriteFile; 52 using std::string; 53 using std::unique_ptr; 54 using test_utils::ScopedTempFile; 55 using testing::_; 56 using testing::AtLeast; 57 using testing::InSequence; 58 using testing::Return; 59 using testing::SetArgPointee; 60 61 class DownloadActionTest : public ::testing::Test {}; 62 63 namespace { 64 65 class DownloadActionTestProcessorDelegate : public ActionProcessorDelegate { 66 public: 67 DownloadActionTestProcessorDelegate() 68 : processing_done_called_(false), expected_code_(ErrorCode::kSuccess) {} 69 ~DownloadActionTestProcessorDelegate() override { 70 EXPECT_TRUE(processing_done_called_); 71 } 72 void ProcessingDone(const ActionProcessor* processor, 73 ErrorCode code) override { 74 brillo::MessageLoop::current()->BreakLoop(); 75 brillo::Blob found_data; 76 ASSERT_TRUE(utils::ReadFile(path_, &found_data)); 77 if (expected_code_ != ErrorCode::kDownloadWriteError) { 78 ASSERT_EQ(expected_data_.size(), found_data.size()); 79 for (unsigned i = 0; i < expected_data_.size(); i++) { 80 EXPECT_EQ(expected_data_[i], found_data[i]); 81 } 82 } 83 processing_done_called_ = true; 84 } 85 86 void ActionCompleted(ActionProcessor* processor, 87 AbstractAction* action, 88 ErrorCode code) override { 89 const string type = action->Type(); 90 if (type == DownloadAction::StaticType()) { 91 EXPECT_EQ(expected_code_, code); 92 p2p_file_id_ = static_cast<DownloadAction*>(action)->p2p_file_id(); 93 } else { 94 EXPECT_EQ(ErrorCode::kSuccess, code); 95 } 96 } 97 98 string path_; 99 brillo::Blob expected_data_; 100 bool processing_done_called_; 101 ErrorCode expected_code_; 102 string p2p_file_id_; 103 }; 104 105 class TestDirectFileWriter : public DirectFileWriter { 106 public: 107 TestDirectFileWriter() : fail_write_(0), current_write_(0) {} 108 void set_fail_write(int fail_write) { fail_write_ = fail_write; } 109 110 virtual bool Write(const void* bytes, size_t count) { 111 if (++current_write_ == fail_write_) { 112 return false; 113 } 114 return DirectFileWriter::Write(bytes, count); 115 } 116 117 private: 118 // If positive, fail on the |fail_write_| call to Write. 119 int fail_write_; 120 int current_write_; 121 }; 122 123 void StartProcessorInRunLoop(ActionProcessor* processor, 124 MockHttpFetcher* http_fetcher) { 125 processor->StartProcessing(); 126 http_fetcher->SetOffset(1); 127 } 128 129 void TestWithData(const brillo::Blob& data, 130 int fail_write, 131 bool use_download_delegate) { 132 brillo::FakeMessageLoop loop(nullptr); 133 loop.SetAsCurrent(); 134 FakeSystemState fake_system_state; 135 136 // TODO(adlr): see if we need a different file for build bots 137 ScopedTempFile output_temp_file; 138 TestDirectFileWriter writer; 139 EXPECT_EQ( 140 0, writer.Open(output_temp_file.path().c_str(), O_WRONLY | O_CREAT, 0)); 141 writer.set_fail_write(fail_write); 142 143 uint64_t size = data.size() - 1; 144 InstallPlan install_plan; 145 install_plan.payloads.push_back( 146 {.size = size, .type = InstallPayloadType::kDelta}); 147 // We pull off the first byte from data and seek past it. 148 EXPECT_TRUE(HashCalculator::RawHashOfBytes( 149 &data[1], data.size() - 1, &install_plan.payloads[0].hash)); 150 install_plan.source_slot = 0; 151 install_plan.target_slot = 1; 152 // We mark both slots as bootable. Only the target slot should be unbootable 153 // after the download starts. 154 fake_system_state.fake_boot_control()->SetSlotBootable( 155 install_plan.source_slot, true); 156 fake_system_state.fake_boot_control()->SetSlotBootable( 157 install_plan.target_slot, true); 158 auto feeder_action = std::make_unique<ObjectFeederAction<InstallPlan>>(); 159 feeder_action->set_obj(install_plan); 160 MockPrefs prefs; 161 MockHttpFetcher* http_fetcher = 162 new MockHttpFetcher(data.data(), data.size(), nullptr); 163 // takes ownership of passed in HttpFetcher 164 auto download_action = 165 std::make_unique<DownloadAction>(&prefs, 166 fake_system_state.boot_control(), 167 fake_system_state.hardware(), 168 &fake_system_state, 169 http_fetcher, 170 false /* interactive */); 171 download_action->SetTestFileWriter(&writer); 172 BondActions(feeder_action.get(), download_action.get()); 173 MockDownloadActionDelegate download_delegate; 174 if (use_download_delegate) { 175 InSequence s; 176 download_action->set_delegate(&download_delegate); 177 if (data.size() > kMockHttpFetcherChunkSize) 178 EXPECT_CALL(download_delegate, 179 BytesReceived(_, kMockHttpFetcherChunkSize, _)); 180 EXPECT_CALL(download_delegate, BytesReceived(_, _, _)).Times(AtLeast(1)); 181 EXPECT_CALL(download_delegate, DownloadComplete()) 182 .Times(fail_write == 0 ? 1 : 0); 183 } 184 DownloadActionTestProcessorDelegate delegate; 185 delegate.expected_code_ = 186 (fail_write > 0) ? ErrorCode::kDownloadWriteError : ErrorCode::kSuccess; 187 delegate.expected_data_ = brillo::Blob(data.begin() + 1, data.end()); 188 delegate.path_ = output_temp_file.path(); 189 ActionProcessor processor; 190 processor.set_delegate(&delegate); 191 processor.EnqueueAction(std::move(feeder_action)); 192 processor.EnqueueAction(std::move(download_action)); 193 194 loop.PostTask(FROM_HERE, 195 base::Bind(&StartProcessorInRunLoop, &processor, http_fetcher)); 196 loop.Run(); 197 EXPECT_FALSE(loop.PendingTasks()); 198 199 EXPECT_TRUE(fake_system_state.fake_boot_control()->IsSlotBootable( 200 install_plan.source_slot)); 201 EXPECT_FALSE(fake_system_state.fake_boot_control()->IsSlotBootable( 202 install_plan.target_slot)); 203 } 204 } // namespace 205 206 TEST(DownloadActionTest, SimpleTest) { 207 brillo::Blob small; 208 const char* foo = "foo"; 209 small.insert(small.end(), foo, foo + strlen(foo)); 210 TestWithData(small, 211 0, // fail_write 212 true); // use_download_delegate 213 } 214 215 TEST(DownloadActionTest, LargeTest) { 216 brillo::Blob big(5 * kMockHttpFetcherChunkSize); 217 char c = '0'; 218 for (unsigned int i = 0; i < big.size(); i++) { 219 big[i] = c; 220 c = ('9' == c) ? '0' : c + 1; 221 } 222 TestWithData(big, 223 0, // fail_write 224 true); // use_download_delegate 225 } 226 227 TEST(DownloadActionTest, FailWriteTest) { 228 brillo::Blob big(5 * kMockHttpFetcherChunkSize); 229 char c = '0'; 230 for (unsigned int i = 0; i < big.size(); i++) { 231 big[i] = c; 232 c = ('9' == c) ? '0' : c + 1; 233 } 234 TestWithData(big, 235 2, // fail_write 236 true); // use_download_delegate 237 } 238 239 TEST(DownloadActionTest, NoDownloadDelegateTest) { 240 brillo::Blob small; 241 const char* foo = "foofoo"; 242 small.insert(small.end(), foo, foo + strlen(foo)); 243 TestWithData(small, 244 0, // fail_write 245 false); // use_download_delegate 246 } 247 248 TEST(DownloadActionTest, MultiPayloadProgressTest) { 249 std::vector<brillo::Blob> payload_datas; 250 // the first payload must be the largest, as it's the actual payload used by 251 // the MockHttpFetcher for all downloaded data. 252 payload_datas.emplace_back(4 * kMockHttpFetcherChunkSize + 256); 253 payload_datas.emplace_back(2 * kMockHttpFetcherChunkSize); 254 brillo::FakeMessageLoop loop(nullptr); 255 loop.SetAsCurrent(); 256 FakeSystemState fake_system_state; 257 EXPECT_CALL(*fake_system_state.mock_payload_state(), NextPayload()) 258 .WillOnce(Return(true)); 259 260 MockFileWriter mock_file_writer; 261 EXPECT_CALL(mock_file_writer, Close()).WillRepeatedly(Return(0)); 262 EXPECT_CALL(mock_file_writer, Write(_, _, _)) 263 .WillRepeatedly( 264 DoAll(SetArgPointee<2>(ErrorCode::kSuccess), Return(true))); 265 266 InstallPlan install_plan; 267 uint64_t total_expected_download_size{0}; 268 for (const auto& data : payload_datas) { 269 uint64_t size = data.size(); 270 install_plan.payloads.push_back( 271 {.size = size, .type = InstallPayloadType::kFull}); 272 total_expected_download_size += size; 273 } 274 auto feeder_action = std::make_unique<ObjectFeederAction<InstallPlan>>(); 275 feeder_action->set_obj(install_plan); 276 MockPrefs prefs; 277 MockHttpFetcher* http_fetcher = new MockHttpFetcher( 278 payload_datas[0].data(), payload_datas[0].size(), nullptr); 279 // takes ownership of passed in HttpFetcher 280 auto download_action = 281 std::make_unique<DownloadAction>(&prefs, 282 fake_system_state.boot_control(), 283 fake_system_state.hardware(), 284 &fake_system_state, 285 http_fetcher, 286 false /* interactive */); 287 download_action->SetTestFileWriter(&mock_file_writer); 288 BondActions(feeder_action.get(), download_action.get()); 289 MockDownloadActionDelegate download_delegate; 290 { 291 InSequence s; 292 download_action->set_delegate(&download_delegate); 293 // these are hand-computed based on the payloads specified above 294 EXPECT_CALL(download_delegate, 295 BytesReceived(kMockHttpFetcherChunkSize, 296 kMockHttpFetcherChunkSize, 297 total_expected_download_size)); 298 EXPECT_CALL(download_delegate, 299 BytesReceived(kMockHttpFetcherChunkSize, 300 kMockHttpFetcherChunkSize * 2, 301 total_expected_download_size)); 302 EXPECT_CALL(download_delegate, 303 BytesReceived(kMockHttpFetcherChunkSize, 304 kMockHttpFetcherChunkSize * 3, 305 total_expected_download_size)); 306 EXPECT_CALL(download_delegate, 307 BytesReceived(kMockHttpFetcherChunkSize, 308 kMockHttpFetcherChunkSize * 4, 309 total_expected_download_size)); 310 EXPECT_CALL(download_delegate, 311 BytesReceived(256, 312 kMockHttpFetcherChunkSize * 4 + 256, 313 total_expected_download_size)); 314 EXPECT_CALL(download_delegate, 315 BytesReceived(kMockHttpFetcherChunkSize, 316 kMockHttpFetcherChunkSize * 5 + 256, 317 total_expected_download_size)); 318 EXPECT_CALL(download_delegate, 319 BytesReceived(kMockHttpFetcherChunkSize, 320 total_expected_download_size, 321 total_expected_download_size)); 322 } 323 ActionProcessor processor; 324 processor.EnqueueAction(std::move(feeder_action)); 325 processor.EnqueueAction(std::move(download_action)); 326 327 loop.PostTask( 328 FROM_HERE, 329 base::Bind( 330 [](ActionProcessor* processor) { processor->StartProcessing(); }, 331 base::Unretained(&processor))); 332 loop.Run(); 333 EXPECT_FALSE(loop.PendingTasks()); 334 } 335 336 namespace { 337 class TerminateEarlyTestProcessorDelegate : public ActionProcessorDelegate { 338 public: 339 void ProcessingStopped(const ActionProcessor* processor) { 340 brillo::MessageLoop::current()->BreakLoop(); 341 } 342 }; 343 344 void TerminateEarlyTestStarter(ActionProcessor* processor) { 345 processor->StartProcessing(); 346 CHECK(processor->IsRunning()); 347 processor->StopProcessing(); 348 } 349 350 void TestTerminateEarly(bool use_download_delegate) { 351 brillo::FakeMessageLoop loop(nullptr); 352 loop.SetAsCurrent(); 353 354 brillo::Blob data(kMockHttpFetcherChunkSize + kMockHttpFetcherChunkSize / 2); 355 memset(data.data(), 0, data.size()); 356 357 ScopedTempFile temp_file; 358 { 359 DirectFileWriter writer; 360 EXPECT_EQ(0, writer.Open(temp_file.path().c_str(), O_WRONLY | O_CREAT, 0)); 361 362 // takes ownership of passed in HttpFetcher 363 auto feeder_action = std::make_unique<ObjectFeederAction<InstallPlan>>(); 364 InstallPlan install_plan; 365 install_plan.payloads.resize(1); 366 feeder_action->set_obj(install_plan); 367 FakeSystemState fake_system_state_; 368 MockPrefs prefs; 369 auto download_action = std::make_unique<DownloadAction>( 370 &prefs, 371 fake_system_state_.boot_control(), 372 fake_system_state_.hardware(), 373 &fake_system_state_, 374 new MockHttpFetcher(data.data(), data.size(), nullptr), 375 false /* interactive */); 376 download_action->SetTestFileWriter(&writer); 377 MockDownloadActionDelegate download_delegate; 378 if (use_download_delegate) { 379 download_action->set_delegate(&download_delegate); 380 EXPECT_CALL(download_delegate, BytesReceived(_, _, _)).Times(0); 381 } 382 TerminateEarlyTestProcessorDelegate delegate; 383 ActionProcessor processor; 384 processor.set_delegate(&delegate); 385 BondActions(feeder_action.get(), download_action.get()); 386 processor.EnqueueAction(std::move(feeder_action)); 387 processor.EnqueueAction(std::move(download_action)); 388 389 loop.PostTask(FROM_HERE, 390 base::Bind(&TerminateEarlyTestStarter, &processor)); 391 loop.Run(); 392 EXPECT_FALSE(loop.PendingTasks()); 393 } 394 395 // 1 or 0 chunks should have come through 396 const off_t resulting_file_size(utils::FileSize(temp_file.path())); 397 EXPECT_GE(resulting_file_size, 0); 398 if (resulting_file_size != 0) 399 EXPECT_EQ(kMockHttpFetcherChunkSize, 400 static_cast<size_t>(resulting_file_size)); 401 } 402 403 } // namespace 404 405 TEST(DownloadActionTest, TerminateEarlyTest) { 406 TestTerminateEarly(true); 407 } 408 409 TEST(DownloadActionTest, TerminateEarlyNoDownloadDelegateTest) { 410 TestTerminateEarly(false); 411 } 412 413 class DownloadActionTestAction; 414 415 template <> 416 class ActionTraits<DownloadActionTestAction> { 417 public: 418 typedef InstallPlan OutputObjectType; 419 typedef InstallPlan InputObjectType; 420 }; 421 422 // This is a simple Action class for testing. 423 class DownloadActionTestAction : public Action<DownloadActionTestAction> { 424 public: 425 DownloadActionTestAction() = default; 426 typedef InstallPlan InputObjectType; 427 typedef InstallPlan OutputObjectType; 428 ActionPipe<InstallPlan>* in_pipe() { return in_pipe_.get(); } 429 ActionPipe<InstallPlan>* out_pipe() { return out_pipe_.get(); } 430 ActionProcessor* processor() { return processor_; } 431 void PerformAction() { 432 ASSERT_TRUE(HasInputObject()); 433 EXPECT_TRUE(expected_input_object_ == GetInputObject()); 434 ASSERT_TRUE(processor()); 435 processor()->ActionComplete(this, ErrorCode::kSuccess); 436 } 437 static std::string StaticType() { return "DownloadActionTestAction"; } 438 string Type() const { return StaticType(); } 439 InstallPlan expected_input_object_; 440 }; 441 442 namespace { 443 // This class is an ActionProcessorDelegate that simply terminates the 444 // run loop when the ActionProcessor has completed processing. It's used 445 // only by the test PassObjectOutTest. 446 class PassObjectOutTestProcessorDelegate : public ActionProcessorDelegate { 447 public: 448 void ProcessingDone(const ActionProcessor* processor, 449 ErrorCode code) override { 450 brillo::MessageLoop::current()->BreakLoop(); 451 } 452 void ActionCompleted(ActionProcessor* processor, 453 AbstractAction* action, 454 ErrorCode code) override { 455 if (action->Type() == DownloadActionTestAction::StaticType()) { 456 did_test_action_run_ = true; 457 } 458 } 459 460 bool did_test_action_run_ = false; 461 }; 462 463 } // namespace 464 465 TEST(DownloadActionTest, PassObjectOutTest) { 466 brillo::FakeMessageLoop loop(nullptr); 467 loop.SetAsCurrent(); 468 469 DirectFileWriter writer; 470 EXPECT_EQ(0, writer.Open("/dev/null", O_WRONLY | O_CREAT, 0)); 471 472 // takes ownership of passed in HttpFetcher 473 InstallPlan install_plan; 474 install_plan.payloads.push_back({.size = 1}); 475 EXPECT_TRUE( 476 HashCalculator::RawHashOfData({'x'}, &install_plan.payloads[0].hash)); 477 auto feeder_action = std::make_unique<ObjectFeederAction<InstallPlan>>(); 478 feeder_action->set_obj(install_plan); 479 MockPrefs prefs; 480 FakeSystemState fake_system_state_; 481 auto download_action = 482 std::make_unique<DownloadAction>(&prefs, 483 fake_system_state_.boot_control(), 484 fake_system_state_.hardware(), 485 &fake_system_state_, 486 new MockHttpFetcher("x", 1, nullptr), 487 false /* interactive */); 488 download_action->SetTestFileWriter(&writer); 489 490 auto test_action = std::make_unique<DownloadActionTestAction>(); 491 test_action->expected_input_object_ = install_plan; 492 BondActions(feeder_action.get(), download_action.get()); 493 BondActions(download_action.get(), test_action.get()); 494 495 ActionProcessor processor; 496 PassObjectOutTestProcessorDelegate delegate; 497 processor.set_delegate(&delegate); 498 processor.EnqueueAction(std::move(feeder_action)); 499 processor.EnqueueAction(std::move(download_action)); 500 processor.EnqueueAction(std::move(test_action)); 501 502 loop.PostTask( 503 FROM_HERE, 504 base::Bind( 505 [](ActionProcessor* processor) { processor->StartProcessing(); }, 506 base::Unretained(&processor))); 507 loop.Run(); 508 EXPECT_FALSE(loop.PendingTasks()); 509 510 EXPECT_EQ(true, delegate.did_test_action_run_); 511 } 512 513 // Test fixture for P2P tests. 514 class P2PDownloadActionTest : public testing::Test { 515 protected: 516 P2PDownloadActionTest() 517 : start_at_offset_(0), fake_um_(fake_system_state_.fake_clock()) {} 518 519 ~P2PDownloadActionTest() override {} 520 521 // Derived from testing::Test. 522 void SetUp() override { loop_.SetAsCurrent(); } 523 524 // Derived from testing::Test. 525 void TearDown() override { EXPECT_FALSE(loop_.PendingTasks()); } 526 527 // To be called by tests to setup the download. The 528 // |starting_offset| parameter is for where to resume. 529 void SetupDownload(off_t starting_offset) { 530 start_at_offset_ = starting_offset; 531 // Prepare data 10 kB of data. 532 data_.clear(); 533 for (unsigned int i = 0; i < 10 * 1000; i++) 534 data_ += 'a' + (i % 25); 535 536 // Setup p2p. 537 FakeP2PManagerConfiguration* test_conf = new FakeP2PManagerConfiguration(); 538 p2p_manager_.reset(P2PManager::Construct(test_conf, 539 nullptr, 540 &fake_um_, 541 "cros_au", 542 3, 543 base::TimeDelta::FromDays(5))); 544 fake_system_state_.set_p2p_manager(p2p_manager_.get()); 545 } 546 547 // To be called by tests to perform the download. The 548 // |use_p2p_to_share| parameter is used to indicate whether the 549 // payload should be shared via p2p. 550 void StartDownload(bool use_p2p_to_share) { 551 EXPECT_CALL(*fake_system_state_.mock_payload_state(), 552 GetUsingP2PForSharing()) 553 .WillRepeatedly(Return(use_p2p_to_share)); 554 555 ScopedTempFile output_temp_file; 556 TestDirectFileWriter writer; 557 EXPECT_EQ( 558 0, writer.Open(output_temp_file.path().c_str(), O_WRONLY | O_CREAT, 0)); 559 InstallPlan install_plan; 560 install_plan.payloads.push_back( 561 {.size = data_.length(), 562 .hash = {'1', '2', '3', '4', 'h', 'a', 's', 'h'}}); 563 auto feeder_action = std::make_unique<ObjectFeederAction<InstallPlan>>(); 564 feeder_action->set_obj(install_plan); 565 MockPrefs prefs; 566 // Note that DownloadAction takes ownership of the passed in HttpFetcher. 567 auto download_action = std::make_unique<DownloadAction>( 568 &prefs, 569 fake_system_state_.boot_control(), 570 fake_system_state_.hardware(), 571 &fake_system_state_, 572 new MockHttpFetcher(data_.c_str(), data_.length(), nullptr), 573 false /* interactive */); 574 auto http_fetcher = download_action->http_fetcher(); 575 download_action->SetTestFileWriter(&writer); 576 BondActions(feeder_action.get(), download_action.get()); 577 delegate_.expected_data_ = 578 brillo::Blob(data_.begin() + start_at_offset_, data_.end()); 579 delegate_.path_ = output_temp_file.path(); 580 processor_.set_delegate(&delegate_); 581 processor_.EnqueueAction(std::move(feeder_action)); 582 processor_.EnqueueAction(std::move(download_action)); 583 584 loop_.PostTask( 585 FROM_HERE, 586 base::Bind( 587 [](P2PDownloadActionTest* action_test, HttpFetcher* http_fetcher) { 588 action_test->processor_.StartProcessing(); 589 http_fetcher->SetOffset(action_test->start_at_offset_); 590 }, 591 base::Unretained(this), 592 base::Unretained(http_fetcher))); 593 loop_.Run(); 594 } 595 596 // Mainloop used to make StartDownload() synchronous. 597 brillo::FakeMessageLoop loop_{nullptr}; 598 599 // Delegate that is passed to the ActionProcessor. 600 DownloadActionTestProcessorDelegate delegate_; 601 602 // The P2PManager used in the test. 603 unique_ptr<P2PManager> p2p_manager_; 604 605 // The ActionProcessor used for running the actions. 606 ActionProcessor processor_; 607 608 // A fake system state. 609 FakeSystemState fake_system_state_; 610 611 // The data being downloaded. 612 string data_; 613 614 private: 615 // The requested starting offset passed to SetupDownload(). 616 off_t start_at_offset_; 617 618 chromeos_update_manager::FakeUpdateManager fake_um_; 619 }; 620 621 TEST_F(P2PDownloadActionTest, IsWrittenTo) { 622 SetupDownload(0); // starting_offset 623 StartDownload(true); // use_p2p_to_share 624 625 // Check the p2p file and its content matches what was sent. 626 string file_id = delegate_.p2p_file_id_; 627 EXPECT_NE("", file_id); 628 EXPECT_EQ(static_cast<int>(data_.length()), 629 p2p_manager_->FileGetSize(file_id)); 630 EXPECT_EQ(static_cast<int>(data_.length()), 631 p2p_manager_->FileGetExpectedSize(file_id)); 632 string p2p_file_contents; 633 EXPECT_TRUE( 634 ReadFileToString(p2p_manager_->FileGetPath(file_id), &p2p_file_contents)); 635 EXPECT_EQ(data_, p2p_file_contents); 636 } 637 638 TEST_F(P2PDownloadActionTest, DeleteIfHoleExists) { 639 SetupDownload(1000); // starting_offset 640 StartDownload(true); // use_p2p_to_share 641 642 // DownloadAction should convey that the file is not being shared. 643 // and that we don't have any p2p files. 644 EXPECT_EQ(delegate_.p2p_file_id_, ""); 645 EXPECT_EQ(p2p_manager_->CountSharedFiles(), 0); 646 } 647 648 TEST_F(P2PDownloadActionTest, CanAppend) { 649 SetupDownload(1000); // starting_offset 650 651 // Prepare the file with existing data before starting to write to 652 // it via DownloadAction. 653 string file_id = utils::CalculateP2PFileId( 654 {'1', '2', '3', '4', 'h', 'a', 's', 'h'}, data_.length()); 655 ASSERT_TRUE(p2p_manager_->FileShare(file_id, data_.length())); 656 string existing_data; 657 for (unsigned int i = 0; i < 1000; i++) 658 existing_data += '0' + (i % 10); 659 ASSERT_EQ( 660 WriteFile( 661 p2p_manager_->FileGetPath(file_id), existing_data.c_str(), 1000), 662 1000); 663 664 StartDownload(true); // use_p2p_to_share 665 666 // DownloadAction should convey the same file_id and the file should 667 // have the expected size. 668 EXPECT_EQ(delegate_.p2p_file_id_, file_id); 669 EXPECT_EQ(static_cast<ssize_t>(data_.length()), 670 p2p_manager_->FileGetSize(file_id)); 671 EXPECT_EQ(static_cast<ssize_t>(data_.length()), 672 p2p_manager_->FileGetExpectedSize(file_id)); 673 string p2p_file_contents; 674 // Check that the first 1000 bytes wasn't touched and that we 675 // appended the remaining as appropriate. 676 EXPECT_TRUE( 677 ReadFileToString(p2p_manager_->FileGetPath(file_id), &p2p_file_contents)); 678 EXPECT_EQ(existing_data, p2p_file_contents.substr(0, 1000)); 679 EXPECT_EQ(data_.substr(1000), p2p_file_contents.substr(1000)); 680 } 681 682 TEST_F(P2PDownloadActionTest, DeletePartialP2PFileIfResumingWithoutP2P) { 683 SetupDownload(1000); // starting_offset 684 685 // Prepare the file with all existing data before starting to write 686 // to it via DownloadAction. 687 string file_id = utils::CalculateP2PFileId( 688 {'1', '2', '3', '4', 'h', 'a', 's', 'h'}, data_.length()); 689 ASSERT_TRUE(p2p_manager_->FileShare(file_id, data_.length())); 690 string existing_data; 691 for (unsigned int i = 0; i < 1000; i++) 692 existing_data += '0' + (i % 10); 693 ASSERT_EQ( 694 WriteFile( 695 p2p_manager_->FileGetPath(file_id), existing_data.c_str(), 1000), 696 1000); 697 698 // Check that the file is there. 699 EXPECT_EQ(1000, p2p_manager_->FileGetSize(file_id)); 700 EXPECT_EQ(1, p2p_manager_->CountSharedFiles()); 701 702 StartDownload(false); // use_p2p_to_share 703 704 // DownloadAction should have deleted the p2p file. Check that it's gone. 705 EXPECT_EQ(-1, p2p_manager_->FileGetSize(file_id)); 706 EXPECT_EQ(0, p2p_manager_->CountSharedFiles()); 707 } 708 709 } // namespace chromeos_update_engine 710