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