Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/file_util.h" | 5 #include "base/file_util.h" |
| 6 #include "base/files/file.h" | |
| 6 #include "base/message_loop/message_loop.h" | 7 #include "base/message_loop/message_loop.h" |
| 8 #include "base/run_loop.h" | |
| 7 #include "base/strings/string_number_conversions.h" | 9 #include "base/strings/string_number_conversions.h" |
| 8 #include "base/test/test_file_util.h" | 10 #include "base/test/test_file_util.h" |
| 9 #include "content/browser/browser_thread_impl.h" | 11 #include "content/browser/browser_thread_impl.h" |
| 10 #include "content/browser/byte_stream.h" | 12 #include "content/browser/byte_stream.h" |
| 11 #include "content/browser/download/download_create_info.h" | 13 #include "content/browser/download/download_create_info.h" |
| 12 #include "content/browser/download/download_file_impl.h" | 14 #include "content/browser/download/download_file_impl.h" |
| 13 #include "content/browser/download/download_request_handle.h" | 15 #include "content/browser/download/download_request_handle.h" |
| 14 #include "content/public/browser/download_destination_observer.h" | 16 #include "content/public/browser/download_destination_observer.h" |
| 15 #include "content/public/browser/download_interrupt_reasons.h" | 17 #include "content/public/browser/download_interrupt_reasons.h" |
| 16 #include "content/public/browser/download_manager.h" | 18 #include "content/public/browser/download_manager.h" |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 52 | 54 |
| 53 // Doesn't override any methods in the base class. Used to make sure | 55 // Doesn't override any methods in the base class. Used to make sure |
| 54 // that the last DestinationUpdate before a Destination{Completed,Error} | 56 // that the last DestinationUpdate before a Destination{Completed,Error} |
| 55 // had the right values. | 57 // had the right values. |
| 56 MOCK_METHOD3(CurrentUpdateStatus, | 58 MOCK_METHOD3(CurrentUpdateStatus, |
| 57 void(int64, int64, const std::string&)); | 59 void(int64, int64, const std::string&)); |
| 58 }; | 60 }; |
| 59 | 61 |
| 60 MATCHER(IsNullCallback, "") { return (arg.is_null()); } | 62 MATCHER(IsNullCallback, "") { return (arg.is_null()); } |
| 61 | 63 |
| 64 typedef void (DownloadFile::*DownloadFileRenameMethodType)( | |
| 65 const base::FilePath&, | |
| 66 const DownloadFile::RenameCompletionCallback&); | |
| 67 | |
| 68 // This is a test DownloadFileImpl that has no retry delay and, on Posix, | |
| 69 // retries renames failed due to ACCESS_DENIED. | |
| 70 class TestDownloadFileImpl : public DownloadFileImpl { | |
| 71 public: | |
| 72 TestDownloadFileImpl(scoped_ptr<DownloadSaveInfo> save_info, | |
| 73 const base::FilePath& default_downloads_directory, | |
| 74 const GURL& url, | |
| 75 const GURL& referrer_url, | |
| 76 bool calculate_hash, | |
| 77 scoped_ptr<ByteStreamReader> stream, | |
| 78 const net::BoundNetLog& bound_net_log, | |
| 79 base::WeakPtr<DownloadDestinationObserver> observer) | |
| 80 : DownloadFileImpl(save_info.Pass(), | |
| 81 default_downloads_directory, | |
| 82 url, | |
| 83 referrer_url, | |
| 84 calculate_hash, | |
| 85 stream.Pass(), | |
| 86 bound_net_log, | |
| 87 observer) {} | |
| 88 | |
| 89 protected: | |
| 90 virtual base::TimeDelta GetRetryDelayForFailedRename( | |
| 91 int attempt_count) OVERRIDE { | |
| 92 return base::TimeDelta::FromMilliseconds(0); | |
| 93 } | |
| 94 | |
| 95 #if !defined(OS_WIN) | |
| 96 // On Posix, we don't encounter transient errors during renames, except | |
| 97 // possibly EAGAIN, which is difficult to replicate reliably. So we resort to | |
| 98 // simulating a transient error using ACCESS_DENIED instead. | |
| 99 virtual bool ShouldRetryFailedRename( | |
| 100 DownloadInterruptReason reason) OVERRIDE { | |
| 101 return reason == DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED; | |
| 102 } | |
| 103 #endif | |
| 104 }; | |
| 105 | |
| 62 } // namespace | 106 } // namespace |
| 63 | 107 |
| 64 class DownloadFileTest : public testing::Test { | 108 class DownloadFileTest : public testing::Test { |
| 65 public: | 109 public: |
| 66 | 110 |
| 67 static const char* kTestData1; | 111 static const char* kTestData1; |
| 68 static const char* kTestData2; | 112 static const char* kTestData2; |
| 69 static const char* kTestData3; | 113 static const char* kTestData3; |
| 70 static const char* kDataHash; | 114 static const char* kDataHash; |
| 71 static const uint32 kDummyDownloadId; | 115 static const uint32 kDummyDownloadId; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 97 observer_->CurrentUpdateStatus(bytes_, bytes_per_sec_, hash_state_); | 141 observer_->CurrentUpdateStatus(bytes_, bytes_per_sec_, hash_state_); |
| 98 } | 142 } |
| 99 | 143 |
| 100 virtual void SetUp() { | 144 virtual void SetUp() { |
| 101 EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _, _)) | 145 EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _, _)) |
| 102 .Times(AnyNumber()) | 146 .Times(AnyNumber()) |
| 103 .WillRepeatedly(Invoke(this, &DownloadFileTest::SetUpdateDownloadInfo)); | 147 .WillRepeatedly(Invoke(this, &DownloadFileTest::SetUpdateDownloadInfo)); |
| 104 } | 148 } |
| 105 | 149 |
| 106 // Mock calls to this function are forwarded here. | 150 // Mock calls to this function are forwarded here. |
| 107 void RegisterCallback(base::Closure sink_callback) { | 151 void RegisterCallback(const base::Closure& sink_callback) { |
| 108 sink_callback_ = sink_callback; | 152 sink_callback_ = sink_callback; |
| 109 } | 153 } |
| 110 | 154 |
| 111 void SetInterruptReasonCallback(bool* was_called, | 155 void SetInterruptReasonCallback(const base::Closure& closure, |
| 112 DownloadInterruptReason* reason_p, | 156 DownloadInterruptReason* reason_p, |
| 113 DownloadInterruptReason reason) { | 157 DownloadInterruptReason reason) { |
| 114 *was_called = true; | |
| 115 *reason_p = reason; | 158 *reason_p = reason; |
| 159 closure.Run(); | |
| 116 } | 160 } |
| 117 | 161 |
| 118 bool CreateDownloadFile(int offset, bool calculate_hash) { | 162 bool CreateDownloadFile(int offset, bool calculate_hash) { |
| 119 // There can be only one. | 163 // There can be only one. |
| 120 DCHECK(!download_file_.get()); | 164 DCHECK(!download_file_.get()); |
| 121 | 165 |
| 122 input_stream_ = new StrictMock<MockByteStreamReader>(); | 166 input_stream_ = new StrictMock<MockByteStreamReader>(); |
| 123 | 167 |
| 124 // TODO: Need to actually create a function that'll set the variables | 168 // TODO: Need to actually create a function that'll set the variables |
| 125 // based on the inputs from the callback. | 169 // based on the inputs from the callback. |
| 126 EXPECT_CALL(*input_stream_, RegisterCallback(_)) | 170 EXPECT_CALL(*input_stream_, RegisterCallback(_)) |
| 127 .WillOnce(Invoke(this, &DownloadFileTest::RegisterCallback)) | 171 .WillOnce(Invoke(this, &DownloadFileTest::RegisterCallback)) |
| 128 .RetiresOnSaturation(); | 172 .RetiresOnSaturation(); |
| 129 | 173 |
| 130 scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo()); | 174 scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo()); |
| 131 download_file_.reset( | 175 scoped_ptr<TestDownloadFileImpl> download_file_impl( |
| 132 new DownloadFileImpl(save_info.Pass(), | 176 new TestDownloadFileImpl(save_info.Pass(), |
| 133 base::FilePath(), | 177 base::FilePath(), |
| 134 GURL(), // Source | 178 GURL(), // Source |
| 135 GURL(), // Referrer | 179 GURL(), // Referrer |
| 136 calculate_hash, | 180 calculate_hash, |
| 137 scoped_ptr<ByteStreamReader>(input_stream_), | 181 scoped_ptr<ByteStreamReader>(input_stream_), |
| 138 net::BoundNetLog(), | 182 net::BoundNetLog(), |
| 139 observer_factory_.GetWeakPtr())); | 183 observer_factory_.GetWeakPtr())); |
| 140 download_file_->SetClientGuid( | 184 download_file_impl->SetClientGuid("12345678-ABCD-1234-DCBA-123456789ABC"); |
| 141 "12345678-ABCD-1234-DCBA-123456789ABC"); | 185 download_file_ = download_file_impl.PassAs<DownloadFile>(); |
| 142 | 186 |
| 143 EXPECT_CALL(*input_stream_, Read(_, _)) | 187 EXPECT_CALL(*input_stream_, Read(_, _)) |
| 144 .WillOnce(Return(ByteStreamReader::STREAM_EMPTY)) | 188 .WillOnce(Return(ByteStreamReader::STREAM_EMPTY)) |
| 145 .RetiresOnSaturation(); | 189 .RetiresOnSaturation(); |
| 146 | 190 |
| 147 base::WeakPtrFactory<DownloadFileTest> weak_ptr_factory(this); | 191 base::WeakPtrFactory<DownloadFileTest> weak_ptr_factory(this); |
| 148 bool called = false; | 192 DownloadInterruptReason result = DOWNLOAD_INTERRUPT_REASON_NONE; |
| 149 DownloadInterruptReason result; | 193 base::RunLoop loop_runner; |
| 150 download_file_->Initialize(base::Bind( | 194 download_file_->Initialize(base::Bind( |
| 151 &DownloadFileTest::SetInterruptReasonCallback, | 195 &DownloadFileTest::SetInterruptReasonCallback, |
| 152 weak_ptr_factory.GetWeakPtr(), &called, &result)); | 196 weak_ptr_factory.GetWeakPtr(), loop_runner.QuitClosure(), &result)); |
| 153 loop_.RunUntilIdle(); | 197 loop_runner.Run(); |
| 154 EXPECT_TRUE(called); | |
| 155 | 198 |
| 156 ::testing::Mock::VerifyAndClearExpectations(input_stream_); | 199 ::testing::Mock::VerifyAndClearExpectations(input_stream_); |
| 157 return result == DOWNLOAD_INTERRUPT_REASON_NONE; | 200 return result == DOWNLOAD_INTERRUPT_REASON_NONE; |
| 158 } | 201 } |
| 159 | 202 |
| 160 void DestroyDownloadFile(int offset) { | 203 void DestroyDownloadFile(int offset) { |
| 161 EXPECT_FALSE(download_file_->InProgress()); | 204 EXPECT_FALSE(download_file_->InProgress()); |
| 162 | 205 |
| 163 // Make sure the data has been properly written to disk. | 206 // Make sure the data has been properly written to disk. |
| 164 std::string disk_data; | 207 std::string disk_data; |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 236 EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _, _)) | 279 EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _, _)) |
| 237 .Times(AnyNumber()) | 280 .Times(AnyNumber()) |
| 238 .WillRepeatedly(Invoke(this, | 281 .WillRepeatedly(Invoke(this, |
| 239 &DownloadFileTest::SetUpdateDownloadInfo)); | 282 &DownloadFileTest::SetUpdateDownloadInfo)); |
| 240 } | 283 } |
| 241 } | 284 } |
| 242 | 285 |
| 243 DownloadInterruptReason RenameAndUniquify( | 286 DownloadInterruptReason RenameAndUniquify( |
| 244 const base::FilePath& full_path, | 287 const base::FilePath& full_path, |
| 245 base::FilePath* result_path_p) { | 288 base::FilePath* result_path_p) { |
| 246 base::WeakPtrFactory<DownloadFileTest> weak_ptr_factory(this); | 289 return InvokeRenameMethodAndWaitForCallback( |
| 247 DownloadInterruptReason result_reason(DOWNLOAD_INTERRUPT_REASON_NONE); | 290 &DownloadFile::RenameAndUniquify, full_path, result_path_p); |
| 248 bool callback_was_called(false); | |
| 249 base::FilePath result_path; | |
| 250 | |
| 251 download_file_->RenameAndUniquify( | |
| 252 full_path, base::Bind(&DownloadFileTest::SetRenameResult, | |
| 253 weak_ptr_factory.GetWeakPtr(), | |
| 254 &callback_was_called, | |
| 255 &result_reason, result_path_p)); | |
| 256 loop_.RunUntilIdle(); | |
| 257 | |
| 258 EXPECT_TRUE(callback_was_called); | |
| 259 return result_reason; | |
| 260 } | 291 } |
| 261 | 292 |
| 262 DownloadInterruptReason RenameAndAnnotate( | 293 DownloadInterruptReason RenameAndAnnotate( |
| 263 const base::FilePath& full_path, | 294 const base::FilePath& full_path, |
| 264 base::FilePath* result_path_p) { | 295 base::FilePath* result_path_p) { |
| 265 base::WeakPtrFactory<DownloadFileTest> weak_ptr_factory(this); | 296 return InvokeRenameMethodAndWaitForCallback( |
| 297 &DownloadFile::RenameAndAnnotate, full_path, result_path_p); | |
| 298 } | |
| 299 | |
| 300 protected: | |
| 301 DownloadInterruptReason InvokeRenameMethodAndWaitForCallback( | |
| 302 DownloadFileRenameMethodType method, | |
| 303 const base::FilePath& full_path, | |
| 304 base::FilePath* result_path_p) { | |
| 266 DownloadInterruptReason result_reason(DOWNLOAD_INTERRUPT_REASON_NONE); | 305 DownloadInterruptReason result_reason(DOWNLOAD_INTERRUPT_REASON_NONE); |
| 267 bool callback_was_called(false); | |
| 268 base::FilePath result_path; | 306 base::FilePath result_path; |
| 269 | 307 |
| 270 download_file_->RenameAndAnnotate( | 308 base::RunLoop loop_runner; |
| 271 full_path, base::Bind(&DownloadFileTest::SetRenameResult, | 309 ((*download_file_).*method)(full_path, |
| 272 weak_ptr_factory.GetWeakPtr(), | 310 base::Bind(&DownloadFileTest::SetRenameResult, |
| 273 &callback_was_called, | 311 base::Unretained(this), |
| 274 &result_reason, result_path_p)); | 312 loop_runner.QuitClosure(), |
| 275 loop_.RunUntilIdle(); | 313 &result_reason, |
| 276 | 314 result_path_p)); |
| 277 EXPECT_TRUE(callback_was_called); | 315 loop_runner.Run(); |
| 278 return result_reason; | 316 return result_reason; |
| 279 } | 317 } |
| 280 | 318 |
| 281 protected: | |
| 282 scoped_ptr<StrictMock<MockDownloadDestinationObserver> > observer_; | 319 scoped_ptr<StrictMock<MockDownloadDestinationObserver> > observer_; |
| 283 base::WeakPtrFactory<DownloadDestinationObserver> observer_factory_; | 320 base::WeakPtrFactory<DownloadDestinationObserver> observer_factory_; |
| 284 | 321 |
| 285 // DownloadFile instance we are testing. | 322 // DownloadFile instance we are testing. |
| 286 scoped_ptr<DownloadFile> download_file_; | 323 scoped_ptr<DownloadFile> download_file_; |
| 287 | 324 |
| 288 // Stream for sending data into the download file. | 325 // Stream for sending data into the download file. |
| 289 // Owned by download_file_; will be alive for lifetime of download_file_. | 326 // Owned by download_file_; will be alive for lifetime of download_file_. |
| 290 StrictMock<MockByteStreamReader>* input_stream_; | 327 StrictMock<MockByteStreamReader>* input_stream_; |
| 291 | 328 |
| 292 // Sink callback data for stream. | 329 // Sink callback data for stream. |
| 293 base::Closure sink_callback_; | 330 base::Closure sink_callback_; |
| 294 | 331 |
| 295 // Latest update sent to the observer. | 332 // Latest update sent to the observer. |
| 296 int64 bytes_; | 333 int64 bytes_; |
| 297 int64 bytes_per_sec_; | 334 int64 bytes_per_sec_; |
| 298 std::string hash_state_; | 335 std::string hash_state_; |
| 299 | 336 |
| 300 base::MessageLoop loop_; | 337 base::MessageLoop loop_; |
| 301 | 338 |
| 302 private: | 339 private: |
| 303 void SetRenameResult(bool* called_p, | 340 void SetRenameResult(const base::Closure& closure, |
| 304 DownloadInterruptReason* reason_p, | 341 DownloadInterruptReason* reason_p, |
| 305 base::FilePath* result_path_p, | 342 base::FilePath* result_path_p, |
| 306 DownloadInterruptReason reason, | 343 DownloadInterruptReason reason, |
| 307 const base::FilePath& result_path) { | 344 const base::FilePath& result_path) { |
| 308 if (called_p) | |
| 309 *called_p = true; | |
| 310 if (reason_p) | 345 if (reason_p) |
| 311 *reason_p = reason; | 346 *reason_p = reason; |
| 312 if (result_path_p) | 347 if (result_path_p) |
| 313 *result_path_p = result_path; | 348 *result_path_p = result_path; |
| 349 closure.Run(); | |
| 314 } | 350 } |
| 315 | 351 |
| 316 // UI thread. | 352 // UI thread. |
| 317 BrowserThreadImpl ui_thread_; | 353 BrowserThreadImpl ui_thread_; |
| 318 // File thread to satisfy debug checks in DownloadFile. | 354 // File thread to satisfy debug checks in DownloadFile. |
| 319 BrowserThreadImpl file_thread_; | 355 BrowserThreadImpl file_thread_; |
| 320 | 356 |
| 321 // Keep track of what data should be saved to the disk file. | 357 // Keep track of what data should be saved to the disk file. |
| 322 std::string expected_data_; | 358 std::string expected_data_; |
| 323 }; | 359 }; |
| 324 | 360 |
| 361 class DownloadFileTestWithRename | |
| 362 : public DownloadFileTest, | |
| 363 public ::testing::WithParamInterface<DownloadFileRenameMethodType> { | |
| 364 protected: | |
| 365 DownloadInterruptReason InvokeSelectedRenameMethod( | |
| 366 const base::FilePath& full_path, | |
| 367 base::FilePath* result_path_p) { | |
| 368 return InvokeRenameMethodAndWaitForCallback( | |
| 369 GetParam(), full_path, result_path_p); | |
| 370 } | |
| 371 }; | |
| 372 | |
| 373 INSTANTIATE_TEST_CASE_P(DownloadFile, | |
| 374 DownloadFileTestWithRename, | |
| 375 ::testing::Values(&DownloadFile::RenameAndAnnotate, | |
| 376 &DownloadFile::RenameAndUniquify)); | |
| 377 | |
| 325 const char* DownloadFileTest::kTestData1 = | 378 const char* DownloadFileTest::kTestData1 = |
| 326 "Let's write some data to the file!\n"; | 379 "Let's write some data to the file!\n"; |
| 327 const char* DownloadFileTest::kTestData2 = "Writing more data.\n"; | 380 const char* DownloadFileTest::kTestData2 = "Writing more data.\n"; |
| 328 const char* DownloadFileTest::kTestData3 = "Final line."; | 381 const char* DownloadFileTest::kTestData3 = "Final line."; |
| 329 const char* DownloadFileTest::kDataHash = | 382 const char* DownloadFileTest::kDataHash = |
| 330 "CBF68BF10F8003DB86B31343AFAC8C7175BD03FB5FC905650F8C80AF087443A8"; | 383 "CBF68BF10F8003DB86B31343AFAC8C7175BD03FB5FC905650F8C80AF087443A8"; |
| 331 | 384 |
| 332 const uint32 DownloadFileTest::kDummyDownloadId = 23; | 385 const uint32 DownloadFileTest::kDummyDownloadId = 23; |
| 333 const int DownloadFileTest::kDummyChildId = 3; | 386 const int DownloadFileTest::kDummyChildId = 3; |
| 334 const int DownloadFileTest::kDummyRequestId = 67; | 387 const int DownloadFileTest::kDummyRequestId = 67; |
| 335 | 388 |
| 336 // Rename the file before any data is downloaded, after some has, after it all | 389 // Rename the file before any data is downloaded, after some has, after it all |
| 337 // has, and after it's closed. | 390 // has, and after it's closed. |
| 338 TEST_F(DownloadFileTest, RenameFileFinal) { | 391 TEST_P(DownloadFileTestWithRename, RenameFileFinal) { |
| 339 ASSERT_TRUE(CreateDownloadFile(0, true)); | 392 ASSERT_TRUE(CreateDownloadFile(0, true)); |
| 340 base::FilePath initial_path(download_file_->FullPath()); | 393 base::FilePath initial_path(download_file_->FullPath()); |
| 341 EXPECT_TRUE(base::PathExists(initial_path)); | 394 EXPECT_TRUE(base::PathExists(initial_path)); |
| 342 base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1")); | 395 base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1")); |
| 343 base::FilePath path_2(initial_path.InsertBeforeExtensionASCII("_2")); | 396 base::FilePath path_2(initial_path.InsertBeforeExtensionASCII("_2")); |
| 344 base::FilePath path_3(initial_path.InsertBeforeExtensionASCII("_3")); | 397 base::FilePath path_3(initial_path.InsertBeforeExtensionASCII("_3")); |
| 345 base::FilePath path_4(initial_path.InsertBeforeExtensionASCII("_4")); | 398 base::FilePath path_4(initial_path.InsertBeforeExtensionASCII("_4")); |
| 346 base::FilePath path_5(initial_path.InsertBeforeExtensionASCII("_5")); | |
| 347 base::FilePath output_path; | 399 base::FilePath output_path; |
| 348 | 400 |
| 349 // Rename the file before downloading any data. | 401 // Rename the file before downloading any data. |
| 350 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, | 402 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, |
| 351 RenameAndUniquify(path_1, &output_path)); | 403 InvokeSelectedRenameMethod(path_1, &output_path)); |
| 352 base::FilePath renamed_path = download_file_->FullPath(); | 404 base::FilePath renamed_path = download_file_->FullPath(); |
| 353 EXPECT_EQ(path_1, renamed_path); | 405 EXPECT_EQ(path_1, renamed_path); |
| 354 EXPECT_EQ(path_1, output_path); | 406 EXPECT_EQ(path_1, output_path); |
| 355 | 407 |
| 356 // Check the files. | 408 // Check the files. |
| 357 EXPECT_FALSE(base::PathExists(initial_path)); | 409 EXPECT_FALSE(base::PathExists(initial_path)); |
| 358 EXPECT_TRUE(base::PathExists(path_1)); | 410 EXPECT_TRUE(base::PathExists(path_1)); |
| 359 | 411 |
| 360 // Download the data. | 412 // Download the data. |
| 361 const char* chunks1[] = { kTestData1, kTestData2 }; | 413 const char* chunks1[] = { kTestData1, kTestData2 }; |
| 362 AppendDataToFile(chunks1, 2); | 414 AppendDataToFile(chunks1, 2); |
| 363 | 415 |
| 364 // Rename the file after downloading some data. | 416 // Rename the file after downloading some data. |
| 365 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, | 417 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, |
| 366 RenameAndUniquify(path_2, &output_path)); | 418 InvokeSelectedRenameMethod(path_2, &output_path)); |
| 367 renamed_path = download_file_->FullPath(); | 419 renamed_path = download_file_->FullPath(); |
| 368 EXPECT_EQ(path_2, renamed_path); | 420 EXPECT_EQ(path_2, renamed_path); |
| 369 EXPECT_EQ(path_2, output_path); | 421 EXPECT_EQ(path_2, output_path); |
| 370 | 422 |
| 371 // Check the files. | 423 // Check the files. |
| 372 EXPECT_FALSE(base::PathExists(path_1)); | 424 EXPECT_FALSE(base::PathExists(path_1)); |
| 373 EXPECT_TRUE(base::PathExists(path_2)); | 425 EXPECT_TRUE(base::PathExists(path_2)); |
| 374 | 426 |
| 375 const char* chunks2[] = { kTestData3 }; | 427 const char* chunks2[] = { kTestData3 }; |
| 376 AppendDataToFile(chunks2, 1); | 428 AppendDataToFile(chunks2, 1); |
| 377 | 429 |
| 378 // Rename the file after downloading all the data. | 430 // Rename the file after downloading all the data. |
| 379 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, | 431 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, |
| 380 RenameAndUniquify(path_3, &output_path)); | 432 InvokeSelectedRenameMethod(path_3, &output_path)); |
| 381 renamed_path = download_file_->FullPath(); | 433 renamed_path = download_file_->FullPath(); |
| 382 EXPECT_EQ(path_3, renamed_path); | 434 EXPECT_EQ(path_3, renamed_path); |
| 383 EXPECT_EQ(path_3, output_path); | 435 EXPECT_EQ(path_3, output_path); |
| 384 | 436 |
| 385 // Check the files. | 437 // Check the files. |
| 386 EXPECT_FALSE(base::PathExists(path_2)); | 438 EXPECT_FALSE(base::PathExists(path_2)); |
| 387 EXPECT_TRUE(base::PathExists(path_3)); | 439 EXPECT_TRUE(base::PathExists(path_3)); |
| 388 | 440 |
| 389 // Should not be able to get the hash until the file is closed. | 441 // Should not be able to get the hash until the file is closed. |
| 390 std::string hash; | 442 std::string hash; |
| 391 EXPECT_FALSE(download_file_->GetHash(&hash)); | 443 EXPECT_FALSE(download_file_->GetHash(&hash)); |
| 392 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); | 444 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); |
| 393 loop_.RunUntilIdle(); | 445 loop_.RunUntilIdle(); |
| 394 | 446 |
| 395 // Rename the file after downloading all the data and closing the file. | 447 // Rename the file after downloading all the data and closing the file. |
| 396 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, | 448 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, |
| 397 RenameAndUniquify(path_4, &output_path)); | 449 InvokeSelectedRenameMethod(path_4, &output_path)); |
| 398 renamed_path = download_file_->FullPath(); | 450 renamed_path = download_file_->FullPath(); |
| 399 EXPECT_EQ(path_4, renamed_path); | 451 EXPECT_EQ(path_4, renamed_path); |
| 400 EXPECT_EQ(path_4, output_path); | 452 EXPECT_EQ(path_4, output_path); |
| 401 | 453 |
| 402 // Check the files. | 454 // Check the files. |
| 403 EXPECT_FALSE(base::PathExists(path_3)); | 455 EXPECT_FALSE(base::PathExists(path_3)); |
| 404 EXPECT_TRUE(base::PathExists(path_4)); | 456 EXPECT_TRUE(base::PathExists(path_4)); |
| 405 | 457 |
| 406 // Check the hash. | 458 // Check the hash. |
| 407 EXPECT_TRUE(download_file_->GetHash(&hash)); | 459 EXPECT_TRUE(download_file_->GetHash(&hash)); |
| 408 EXPECT_EQ(kDataHash, base::HexEncode(hash.data(), hash.size())); | 460 EXPECT_EQ(kDataHash, base::HexEncode(hash.data(), hash.size())); |
| 409 | 461 |
| 410 // Check that a rename with overwrite to an existing file succeeds. | |
| 411 std::string file_contents; | |
| 412 ASSERT_FALSE(base::PathExists(path_5)); | |
| 413 static const char file_data[] = "xyzzy"; | |
| 414 ASSERT_EQ(static_cast<int>(sizeof(file_data) - 1), | |
| 415 base::WriteFile(path_5, file_data, sizeof(file_data) - 1)); | |
| 416 ASSERT_TRUE(base::PathExists(path_5)); | |
| 417 EXPECT_TRUE(base::ReadFileToString(path_5, &file_contents)); | |
| 418 EXPECT_EQ(std::string(file_data), file_contents); | |
| 419 | |
| 420 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, | |
| 421 RenameAndAnnotate(path_5, &output_path)); | |
| 422 EXPECT_EQ(path_5, output_path); | |
| 423 | |
| 424 file_contents = ""; | |
| 425 EXPECT_TRUE(base::ReadFileToString(path_5, &file_contents)); | |
| 426 EXPECT_NE(std::string(file_data), file_contents); | |
| 427 | |
| 428 DestroyDownloadFile(0); | 462 DestroyDownloadFile(0); |
| 429 } | 463 } |
| 430 | 464 |
| 465 // Test to make sure the rename overwrites when requested. | |
| 466 TEST_F(DownloadFileTest, RenameOverwrites) { | |
| 467 ASSERT_TRUE(CreateDownloadFile(0, true)); | |
| 468 base::FilePath initial_path(download_file_->FullPath()); | |
| 469 EXPECT_TRUE(base::PathExists(initial_path)); | |
| 470 base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1")); | |
| 471 | |
| 472 ASSERT_FALSE(base::PathExists(path_1)); | |
| 473 static const char file_data[] = "xyzzy"; | |
| 474 ASSERT_EQ(static_cast<int>(sizeof(file_data)), | |
| 475 base::WriteFile(path_1, file_data, sizeof(file_data))); | |
| 476 ASSERT_TRUE(base::PathExists(path_1)); | |
| 477 | |
| 478 base::FilePath new_path; | |
| 479 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, | |
| 480 RenameAndAnnotate(path_1, &new_path)); | |
| 481 EXPECT_EQ(path_1.value(), new_path.value()); | |
| 482 | |
| 483 std::string file_contents; | |
| 484 ASSERT_TRUE(base::ReadFileToString(new_path, &file_contents)); | |
| 485 EXPECT_NE(std::string(file_data), file_contents); | |
| 486 | |
| 487 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); | |
| 488 loop_.RunUntilIdle(); | |
| 489 DestroyDownloadFile(0); | |
| 490 } | |
| 491 | |
| 431 // Test to make sure the rename uniquifies if we aren't overwriting | 492 // Test to make sure the rename uniquifies if we aren't overwriting |
| 432 // and there's a file where we're aiming. | 493 // and there's a file where we're aiming. |
| 433 TEST_F(DownloadFileTest, RenameUniquifies) { | 494 TEST_F(DownloadFileTest, RenameUniquifies) { |
| 434 ASSERT_TRUE(CreateDownloadFile(0, true)); | 495 ASSERT_TRUE(CreateDownloadFile(0, true)); |
| 435 base::FilePath initial_path(download_file_->FullPath()); | 496 base::FilePath initial_path(download_file_->FullPath()); |
| 436 EXPECT_TRUE(base::PathExists(initial_path)); | 497 EXPECT_TRUE(base::PathExists(initial_path)); |
| 437 base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1")); | 498 base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1")); |
| 438 base::FilePath path_1_suffixed(path_1.InsertBeforeExtensionASCII(" (1)")); | 499 base::FilePath path_1_suffixed(path_1.InsertBeforeExtensionASCII(" (1)")); |
| 439 | 500 |
| 440 ASSERT_FALSE(base::PathExists(path_1)); | 501 ASSERT_FALSE(base::PathExists(path_1)); |
| 441 static const char file_data[] = "xyzzy"; | 502 static const char file_data[] = "xyzzy"; |
| 442 ASSERT_EQ(static_cast<int>(sizeof(file_data)), | 503 ASSERT_EQ(static_cast<int>(sizeof(file_data)), |
| 443 base::WriteFile(path_1, file_data, sizeof(file_data))); | 504 base::WriteFile(path_1, file_data, sizeof(file_data))); |
| 444 ASSERT_TRUE(base::PathExists(path_1)); | 505 ASSERT_TRUE(base::PathExists(path_1)); |
| 445 | 506 |
| 446 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, RenameAndUniquify(path_1, NULL)); | 507 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, RenameAndUniquify(path_1, NULL)); |
| 447 EXPECT_TRUE(base::PathExists(path_1_suffixed)); | 508 EXPECT_TRUE(base::PathExists(path_1_suffixed)); |
| 448 | 509 |
| 449 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); | 510 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); |
| 450 loop_.RunUntilIdle(); | 511 loop_.RunUntilIdle(); |
| 451 DestroyDownloadFile(0); | 512 DestroyDownloadFile(0); |
| 452 } | 513 } |
| 453 | 514 |
| 515 // Test that RenameAndUniquify doesn't try to uniquify in the case where the | |
| 516 // target filename is the same as the current filename. | |
| 517 TEST_F(DownloadFileTest, RenameRecognizesSelfConflict) { | |
| 518 ASSERT_TRUE(CreateDownloadFile(0, true)); | |
| 519 base::FilePath initial_path(download_file_->FullPath()); | |
| 520 EXPECT_TRUE(base::PathExists(initial_path)); | |
| 521 | |
| 522 base::FilePath new_path; | |
| 523 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, | |
| 524 RenameAndUniquify(initial_path, &new_path)); | |
| 525 EXPECT_TRUE(base::PathExists(initial_path)); | |
| 526 | |
| 527 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); | |
| 528 loop_.RunUntilIdle(); | |
| 529 DestroyDownloadFile(0); | |
| 530 EXPECT_EQ(initial_path.value(), new_path.value()); | |
| 531 } | |
| 532 | |
| 454 // Test to make sure we get the proper error on failure. | 533 // Test to make sure we get the proper error on failure. |
| 455 TEST_F(DownloadFileTest, RenameError) { | 534 TEST_P(DownloadFileTestWithRename, RenameError) { |
| 456 ASSERT_TRUE(CreateDownloadFile(0, true)); | 535 ASSERT_TRUE(CreateDownloadFile(0, true)); |
| 457 base::FilePath initial_path(download_file_->FullPath()); | 536 base::FilePath initial_path(download_file_->FullPath()); |
| 458 | 537 |
| 459 // Create a subdirectory. | 538 // Create a subdirectory. |
| 460 base::FilePath tempdir( | 539 base::FilePath target_dir( |
| 461 initial_path.DirName().Append(FILE_PATH_LITERAL("tempdir"))); | 540 initial_path.DirName().Append(FILE_PATH_LITERAL("TargetDir"))); |
| 462 ASSERT_TRUE(base::CreateDirectory(tempdir)); | 541 ASSERT_FALSE(base::DirectoryExists(target_dir)); |
| 463 base::FilePath target_path(tempdir.Append(initial_path.BaseName())); | 542 ASSERT_TRUE(base::CreateDirectory(target_dir)); |
| 543 base::FilePath target_path(target_dir.Append(initial_path.BaseName())); | |
| 464 | 544 |
| 465 // Targets | 545 // Targets |
| 466 base::FilePath target_path_suffixed( | 546 base::FilePath target_path_suffixed( |
| 467 target_path.InsertBeforeExtensionASCII(" (1)")); | 547 target_path.InsertBeforeExtensionASCII(" (1)")); |
| 468 ASSERT_FALSE(base::PathExists(target_path)); | 548 ASSERT_FALSE(base::PathExists(target_path)); |
| 469 ASSERT_FALSE(base::PathExists(target_path_suffixed)); | 549 ASSERT_FALSE(base::PathExists(target_path_suffixed)); |
| 470 | 550 |
| 471 // Make the directory unwritable and try to rename within it. | 551 // Make the directory unwritable and try to rename within it. |
| 472 { | 552 { |
| 473 file_util::PermissionRestorer restorer(tempdir); | 553 file_util::PermissionRestorer restorer(target_dir); |
| 474 ASSERT_TRUE(file_util::MakeFileUnwritable(tempdir)); | 554 ASSERT_TRUE(file_util::MakeFileUnwritable(target_dir)); |
| 475 | 555 |
| 476 // Expect nulling out of further processing. | 556 // Expect nulling out of further processing. |
| 477 EXPECT_CALL(*input_stream_, RegisterCallback(IsNullCallback())); | 557 EXPECT_CALL(*input_stream_, RegisterCallback(IsNullCallback())); |
| 478 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED, | 558 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED, |
| 479 RenameAndAnnotate(target_path, NULL)); | 559 InvokeSelectedRenameMethod(target_path, NULL)); |
| 480 EXPECT_FALSE(base::PathExists(target_path_suffixed)); | 560 EXPECT_FALSE(base::PathExists(target_path_suffixed)); |
| 481 } | 561 } |
| 482 | 562 |
| 483 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); | 563 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); |
| 484 loop_.RunUntilIdle(); | 564 loop_.RunUntilIdle(); |
| 485 DestroyDownloadFile(0); | 565 DestroyDownloadFile(0); |
| 486 } | 566 } |
| 487 | 567 |
| 568 namespace { | |
| 569 | |
| 570 void TestRenameCompletionCallback(const base::Closure& closure, | |
| 571 bool* did_run_callback, | |
| 572 DownloadInterruptReason interrupt_reason, | |
| 573 const base::FilePath& new_path) { | |
| 574 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason); | |
| 575 *did_run_callback = true; | |
| 576 closure.Run(); | |
| 577 } | |
| 578 | |
| 579 } // namespace | |
| 580 | |
| 581 // Test that the retry logic works. This test assumes that DownloadFileImpl will | |
| 582 // post tasks to the current message loop (acting as the FILE thread) | |
| 583 // asynchronously to retry the renames. We will stuff RunLoop::QuitClosures() | |
| 584 // inbetween the retry tasks to stagger them and then allow the rename to | |
|
Randy Smith (Not in Mondays)
2014/06/12 22:10:30
nit: in between.
asanka
2014/06/17 21:40:57
Done.
| |
| 585 // succeed. | |
|
Randy Smith (Not in Mondays)
2014/06/12 22:10:30
Suggestion: I had a hard time groking the threadin
asanka
2014/06/17 21:40:57
Added comments as suggested. Hopefully it's more r
| |
| 586 TEST_P(DownloadFileTestWithRename, RenameWithErrorRetry) { | |
| 587 ASSERT_TRUE(CreateDownloadFile(0, true)); | |
| 588 base::FilePath initial_path(download_file_->FullPath()); | |
| 589 | |
| 590 // Create a subdirectory. | |
| 591 base::FilePath target_dir( | |
| 592 initial_path.DirName().Append(FILE_PATH_LITERAL("TargetDir"))); | |
| 593 ASSERT_FALSE(base::DirectoryExists(target_dir)); | |
| 594 ASSERT_TRUE(base::CreateDirectory(target_dir)); | |
| 595 base::FilePath target_path(target_dir.Append(initial_path.BaseName())); | |
| 596 | |
| 597 bool did_run_callback = false; | |
| 598 base::RunLoop succeeding_run; | |
| 599 { | |
| 600 #if defined(OS_WIN) | |
| 601 // On Windows we test with an actual transient error, a sharing violation. | |
| 602 // The rename will fail because we are holding the file open for READ. On | |
| 603 // Posix this doesn't cause a failure. | |
| 604 base::File locked_file(initial_path, | |
| 605 base::File::FLAG_OPEN | base::File::FLAG_READ); | |
| 606 ASSERT_TRUE(locked_file.IsValid()); | |
| 607 #else | |
| 608 // Simulate a transient failure by revoking write permission for target_dir. | |
| 609 // The TestDownloadFileImpl class treats this error as transient even though | |
| 610 // DownloadFileImpl itself doesn't. | |
| 611 file_util::PermissionRestorer restore_permissions_for(target_dir); | |
| 612 ASSERT_TRUE(file_util::MakeFileUnwritable(target_dir)); | |
| 613 #endif | |
| 614 | |
| 615 base::RunLoop first_failing_run; | |
| 616 base::MessageLoop::current()->PostTask(FROM_HERE, | |
| 617 first_failing_run.QuitClosure()); | |
| 618 ((*download_file_).*GetParam())(target_path, | |
| 619 base::Bind(&TestRenameCompletionCallback, | |
| 620 succeeding_run.QuitClosure(), | |
| 621 &did_run_callback)); | |
| 622 EXPECT_FALSE(did_run_callback); | |
| 623 | |
| 624 // This should quit because the QuitClosure() from first_failing_run is run. | |
| 625 // The QuitClosure() from succeeding_run shouldn't be run since | |
| 626 // download_file_ is still retrying the request. | |
| 627 first_failing_run.Run(); | |
| 628 EXPECT_FALSE(did_run_callback); | |
| 629 | |
| 630 // Running another loop should have the same effect as long as | |
| 631 // kMaxRenameRetries is greater than 2. | |
| 632 base::RunLoop second_failing_run; | |
| 633 base::MessageLoop::current()->PostTask(FROM_HERE, | |
| 634 second_failing_run.QuitClosure()); | |
| 635 second_failing_run.Run(); | |
| 636 EXPECT_FALSE(did_run_callback); | |
| 637 } | |
| 638 | |
| 639 // This time the QuitClosure from succeeding_run should get executed since the | |
| 640 // target directory is now writeable. | |
| 641 succeeding_run.Run(); | |
| 642 EXPECT_TRUE(did_run_callback); | |
| 643 | |
| 644 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); | |
| 645 loop_.RunUntilIdle(); | |
| 646 DestroyDownloadFile(0); | |
| 647 } | |
| 648 | |
| 488 // Various tests of the StreamActive method. | 649 // Various tests of the StreamActive method. |
| 489 TEST_F(DownloadFileTest, StreamEmptySuccess) { | 650 TEST_F(DownloadFileTest, StreamEmptySuccess) { |
| 490 ASSERT_TRUE(CreateDownloadFile(0, true)); | 651 ASSERT_TRUE(CreateDownloadFile(0, true)); |
| 491 base::FilePath initial_path(download_file_->FullPath()); | 652 base::FilePath initial_path(download_file_->FullPath()); |
| 492 EXPECT_TRUE(base::PathExists(initial_path)); | 653 EXPECT_TRUE(base::PathExists(initial_path)); |
| 493 | 654 |
| 494 // Test that calling the sink_callback_ on an empty stream shouldn't | 655 // Test that calling the sink_callback_ on an empty stream shouldn't |
| 495 // do anything. | 656 // do anything. |
| 496 AppendDataToFile(NULL, 0); | 657 AppendDataToFile(NULL, 0); |
| 497 | 658 |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 594 | 755 |
| 595 EXPECT_EQ(static_cast<int64>(strlen(kTestData1) + strlen(kTestData2)), | 756 EXPECT_EQ(static_cast<int64>(strlen(kTestData1) + strlen(kTestData2)), |
| 596 bytes_); | 757 bytes_); |
| 597 EXPECT_EQ(download_file_->GetHashState(), hash_state_); | 758 EXPECT_EQ(download_file_->GetHashState(), hash_state_); |
| 598 | 759 |
| 599 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); | 760 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); |
| 600 DestroyDownloadFile(0); | 761 DestroyDownloadFile(0); |
| 601 } | 762 } |
| 602 | 763 |
| 603 } // namespace content | 764 } // namespace content |
| OLD | NEW |