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/files/file.h" |
5 #include "base/files/file_util.h" | 6 #include "base/files/file_util.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 void ExpectPermissionError(DownloadInterruptReason err) { |
| 301 EXPECT_TRUE(err == DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR || |
| 302 err == DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED) |
| 303 << "Interrupt reason = " << err; |
| 304 } |
| 305 |
| 306 protected: |
| 307 DownloadInterruptReason InvokeRenameMethodAndWaitForCallback( |
| 308 DownloadFileRenameMethodType method, |
| 309 const base::FilePath& full_path, |
| 310 base::FilePath* result_path_p) { |
266 DownloadInterruptReason result_reason(DOWNLOAD_INTERRUPT_REASON_NONE); | 311 DownloadInterruptReason result_reason(DOWNLOAD_INTERRUPT_REASON_NONE); |
267 bool callback_was_called(false); | |
268 base::FilePath result_path; | 312 base::FilePath result_path; |
269 | 313 |
270 download_file_->RenameAndAnnotate( | 314 base::RunLoop loop_runner; |
271 full_path, base::Bind(&DownloadFileTest::SetRenameResult, | 315 ((*download_file_).*method)(full_path, |
272 weak_ptr_factory.GetWeakPtr(), | 316 base::Bind(&DownloadFileTest::SetRenameResult, |
273 &callback_was_called, | 317 base::Unretained(this), |
274 &result_reason, result_path_p)); | 318 loop_runner.QuitClosure(), |
275 loop_.RunUntilIdle(); | 319 &result_reason, |
276 | 320 result_path_p)); |
277 EXPECT_TRUE(callback_was_called); | 321 loop_runner.Run(); |
278 return result_reason; | 322 return result_reason; |
279 } | 323 } |
280 | 324 |
281 protected: | |
282 scoped_ptr<StrictMock<MockDownloadDestinationObserver> > observer_; | 325 scoped_ptr<StrictMock<MockDownloadDestinationObserver> > observer_; |
283 base::WeakPtrFactory<DownloadDestinationObserver> observer_factory_; | 326 base::WeakPtrFactory<DownloadDestinationObserver> observer_factory_; |
284 | 327 |
285 // DownloadFile instance we are testing. | 328 // DownloadFile instance we are testing. |
286 scoped_ptr<DownloadFile> download_file_; | 329 scoped_ptr<DownloadFile> download_file_; |
287 | 330 |
288 // Stream for sending data into the download file. | 331 // Stream for sending data into the download file. |
289 // Owned by download_file_; will be alive for lifetime of download_file_. | 332 // Owned by download_file_; will be alive for lifetime of download_file_. |
290 StrictMock<MockByteStreamReader>* input_stream_; | 333 StrictMock<MockByteStreamReader>* input_stream_; |
291 | 334 |
292 // Sink callback data for stream. | 335 // Sink callback data for stream. |
293 base::Closure sink_callback_; | 336 base::Closure sink_callback_; |
294 | 337 |
295 // Latest update sent to the observer. | 338 // Latest update sent to the observer. |
296 int64 bytes_; | 339 int64 bytes_; |
297 int64 bytes_per_sec_; | 340 int64 bytes_per_sec_; |
298 std::string hash_state_; | 341 std::string hash_state_; |
299 | 342 |
300 base::MessageLoop loop_; | 343 base::MessageLoop loop_; |
301 | 344 |
302 private: | 345 private: |
303 void SetRenameResult(bool* called_p, | 346 void SetRenameResult(const base::Closure& closure, |
304 DownloadInterruptReason* reason_p, | 347 DownloadInterruptReason* reason_p, |
305 base::FilePath* result_path_p, | 348 base::FilePath* result_path_p, |
306 DownloadInterruptReason reason, | 349 DownloadInterruptReason reason, |
307 const base::FilePath& result_path) { | 350 const base::FilePath& result_path) { |
308 if (called_p) | |
309 *called_p = true; | |
310 if (reason_p) | 351 if (reason_p) |
311 *reason_p = reason; | 352 *reason_p = reason; |
312 if (result_path_p) | 353 if (result_path_p) |
313 *result_path_p = result_path; | 354 *result_path_p = result_path; |
| 355 closure.Run(); |
314 } | 356 } |
315 | 357 |
316 // UI thread. | 358 // UI thread. |
317 BrowserThreadImpl ui_thread_; | 359 BrowserThreadImpl ui_thread_; |
318 // File thread to satisfy debug checks in DownloadFile. | 360 // File thread to satisfy debug checks in DownloadFile. |
319 BrowserThreadImpl file_thread_; | 361 BrowserThreadImpl file_thread_; |
320 | 362 |
321 // Keep track of what data should be saved to the disk file. | 363 // Keep track of what data should be saved to the disk file. |
322 std::string expected_data_; | 364 std::string expected_data_; |
323 }; | 365 }; |
324 | 366 |
| 367 // DownloadFile::RenameAndAnnotate and DownloadFile::RenameAndUniquify have a |
| 368 // considerable amount of functional overlap. In order to re-use test logic, we |
| 369 // are going to introduce this value parameterized test fixture. It will take a |
| 370 // DownloadFileRenameMethodType value which can be either of the two rename |
| 371 // methods. |
| 372 class DownloadFileTestWithRename |
| 373 : public DownloadFileTest, |
| 374 public ::testing::WithParamInterface<DownloadFileRenameMethodType> { |
| 375 protected: |
| 376 DownloadInterruptReason InvokeSelectedRenameMethod( |
| 377 const base::FilePath& full_path, |
| 378 base::FilePath* result_path_p) { |
| 379 return InvokeRenameMethodAndWaitForCallback( |
| 380 GetParam(), full_path, result_path_p); |
| 381 } |
| 382 }; |
| 383 |
| 384 // And now instantiate all DownloadFileTestWithRename tests using both |
| 385 // DownloadFile rename methods. Each test of the form |
| 386 // DownloadFileTestWithRename.<FooTest> will be instantiated once with |
| 387 // RenameAndAnnotate as the value parameter and once with RenameAndUniquify as |
| 388 // the value parameter. |
| 389 INSTANTIATE_TEST_CASE_P(DownloadFile, |
| 390 DownloadFileTestWithRename, |
| 391 ::testing::Values(&DownloadFile::RenameAndAnnotate, |
| 392 &DownloadFile::RenameAndUniquify)); |
| 393 |
325 const char* DownloadFileTest::kTestData1 = | 394 const char* DownloadFileTest::kTestData1 = |
326 "Let's write some data to the file!\n"; | 395 "Let's write some data to the file!\n"; |
327 const char* DownloadFileTest::kTestData2 = "Writing more data.\n"; | 396 const char* DownloadFileTest::kTestData2 = "Writing more data.\n"; |
328 const char* DownloadFileTest::kTestData3 = "Final line."; | 397 const char* DownloadFileTest::kTestData3 = "Final line."; |
329 const char* DownloadFileTest::kDataHash = | 398 const char* DownloadFileTest::kDataHash = |
330 "CBF68BF10F8003DB86B31343AFAC8C7175BD03FB5FC905650F8C80AF087443A8"; | 399 "CBF68BF10F8003DB86B31343AFAC8C7175BD03FB5FC905650F8C80AF087443A8"; |
331 | 400 |
332 const uint32 DownloadFileTest::kDummyDownloadId = 23; | 401 const uint32 DownloadFileTest::kDummyDownloadId = 23; |
333 const int DownloadFileTest::kDummyChildId = 3; | 402 const int DownloadFileTest::kDummyChildId = 3; |
334 const int DownloadFileTest::kDummyRequestId = 67; | 403 const int DownloadFileTest::kDummyRequestId = 67; |
335 | 404 |
336 // Rename the file before any data is downloaded, after some has, after it all | 405 // Rename the file before any data is downloaded, after some has, after it all |
337 // has, and after it's closed. | 406 // has, and after it's closed. |
338 TEST_F(DownloadFileTest, RenameFileFinal) { | 407 TEST_P(DownloadFileTestWithRename, RenameFileFinal) { |
339 ASSERT_TRUE(CreateDownloadFile(0, true)); | 408 ASSERT_TRUE(CreateDownloadFile(0, true)); |
340 base::FilePath initial_path(download_file_->FullPath()); | 409 base::FilePath initial_path(download_file_->FullPath()); |
341 EXPECT_TRUE(base::PathExists(initial_path)); | 410 EXPECT_TRUE(base::PathExists(initial_path)); |
342 base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1")); | 411 base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1")); |
343 base::FilePath path_2(initial_path.InsertBeforeExtensionASCII("_2")); | 412 base::FilePath path_2(initial_path.InsertBeforeExtensionASCII("_2")); |
344 base::FilePath path_3(initial_path.InsertBeforeExtensionASCII("_3")); | 413 base::FilePath path_3(initial_path.InsertBeforeExtensionASCII("_3")); |
345 base::FilePath path_4(initial_path.InsertBeforeExtensionASCII("_4")); | 414 base::FilePath path_4(initial_path.InsertBeforeExtensionASCII("_4")); |
346 base::FilePath path_5(initial_path.InsertBeforeExtensionASCII("_5")); | |
347 base::FilePath output_path; | 415 base::FilePath output_path; |
348 | 416 |
349 // Rename the file before downloading any data. | 417 // Rename the file before downloading any data. |
350 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, | 418 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, |
351 RenameAndUniquify(path_1, &output_path)); | 419 InvokeSelectedRenameMethod(path_1, &output_path)); |
352 base::FilePath renamed_path = download_file_->FullPath(); | 420 base::FilePath renamed_path = download_file_->FullPath(); |
353 EXPECT_EQ(path_1, renamed_path); | 421 EXPECT_EQ(path_1, renamed_path); |
354 EXPECT_EQ(path_1, output_path); | 422 EXPECT_EQ(path_1, output_path); |
355 | 423 |
356 // Check the files. | 424 // Check the files. |
357 EXPECT_FALSE(base::PathExists(initial_path)); | 425 EXPECT_FALSE(base::PathExists(initial_path)); |
358 EXPECT_TRUE(base::PathExists(path_1)); | 426 EXPECT_TRUE(base::PathExists(path_1)); |
359 | 427 |
360 // Download the data. | 428 // Download the data. |
361 const char* chunks1[] = { kTestData1, kTestData2 }; | 429 const char* chunks1[] = { kTestData1, kTestData2 }; |
362 AppendDataToFile(chunks1, 2); | 430 AppendDataToFile(chunks1, 2); |
363 | 431 |
364 // Rename the file after downloading some data. | 432 // Rename the file after downloading some data. |
365 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, | 433 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, |
366 RenameAndUniquify(path_2, &output_path)); | 434 InvokeSelectedRenameMethod(path_2, &output_path)); |
367 renamed_path = download_file_->FullPath(); | 435 renamed_path = download_file_->FullPath(); |
368 EXPECT_EQ(path_2, renamed_path); | 436 EXPECT_EQ(path_2, renamed_path); |
369 EXPECT_EQ(path_2, output_path); | 437 EXPECT_EQ(path_2, output_path); |
370 | 438 |
371 // Check the files. | 439 // Check the files. |
372 EXPECT_FALSE(base::PathExists(path_1)); | 440 EXPECT_FALSE(base::PathExists(path_1)); |
373 EXPECT_TRUE(base::PathExists(path_2)); | 441 EXPECT_TRUE(base::PathExists(path_2)); |
374 | 442 |
375 const char* chunks2[] = { kTestData3 }; | 443 const char* chunks2[] = { kTestData3 }; |
376 AppendDataToFile(chunks2, 1); | 444 AppendDataToFile(chunks2, 1); |
377 | 445 |
378 // Rename the file after downloading all the data. | 446 // Rename the file after downloading all the data. |
379 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, | 447 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, |
380 RenameAndUniquify(path_3, &output_path)); | 448 InvokeSelectedRenameMethod(path_3, &output_path)); |
381 renamed_path = download_file_->FullPath(); | 449 renamed_path = download_file_->FullPath(); |
382 EXPECT_EQ(path_3, renamed_path); | 450 EXPECT_EQ(path_3, renamed_path); |
383 EXPECT_EQ(path_3, output_path); | 451 EXPECT_EQ(path_3, output_path); |
384 | 452 |
385 // Check the files. | 453 // Check the files. |
386 EXPECT_FALSE(base::PathExists(path_2)); | 454 EXPECT_FALSE(base::PathExists(path_2)); |
387 EXPECT_TRUE(base::PathExists(path_3)); | 455 EXPECT_TRUE(base::PathExists(path_3)); |
388 | 456 |
389 // Should not be able to get the hash until the file is closed. | 457 // Should not be able to get the hash until the file is closed. |
390 std::string hash; | 458 std::string hash; |
391 EXPECT_FALSE(download_file_->GetHash(&hash)); | 459 EXPECT_FALSE(download_file_->GetHash(&hash)); |
392 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); | 460 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); |
393 loop_.RunUntilIdle(); | 461 loop_.RunUntilIdle(); |
394 | 462 |
395 // Rename the file after downloading all the data and closing the file. | 463 // Rename the file after downloading all the data and closing the file. |
396 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, | 464 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, |
397 RenameAndUniquify(path_4, &output_path)); | 465 InvokeSelectedRenameMethod(path_4, &output_path)); |
398 renamed_path = download_file_->FullPath(); | 466 renamed_path = download_file_->FullPath(); |
399 EXPECT_EQ(path_4, renamed_path); | 467 EXPECT_EQ(path_4, renamed_path); |
400 EXPECT_EQ(path_4, output_path); | 468 EXPECT_EQ(path_4, output_path); |
401 | 469 |
402 // Check the files. | 470 // Check the files. |
403 EXPECT_FALSE(base::PathExists(path_3)); | 471 EXPECT_FALSE(base::PathExists(path_3)); |
404 EXPECT_TRUE(base::PathExists(path_4)); | 472 EXPECT_TRUE(base::PathExists(path_4)); |
405 | 473 |
406 // Check the hash. | 474 // Check the hash. |
407 EXPECT_TRUE(download_file_->GetHash(&hash)); | 475 EXPECT_TRUE(download_file_->GetHash(&hash)); |
408 EXPECT_EQ(kDataHash, base::HexEncode(hash.data(), hash.size())); | 476 EXPECT_EQ(kDataHash, base::HexEncode(hash.data(), hash.size())); |
409 | 477 |
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); | 478 DestroyDownloadFile(0); |
429 } | 479 } |
430 | 480 |
| 481 // Test to make sure the rename overwrites when requested. This is separate from |
| 482 // the above test because it only applies to RenameAndAnnotate(). |
| 483 // RenameAndUniquify() doesn't overwrite by design. |
| 484 TEST_F(DownloadFileTest, RenameOverwrites) { |
| 485 ASSERT_TRUE(CreateDownloadFile(0, true)); |
| 486 base::FilePath initial_path(download_file_->FullPath()); |
| 487 EXPECT_TRUE(base::PathExists(initial_path)); |
| 488 base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1")); |
| 489 |
| 490 ASSERT_FALSE(base::PathExists(path_1)); |
| 491 static const char file_data[] = "xyzzy"; |
| 492 ASSERT_EQ(static_cast<int>(sizeof(file_data)), |
| 493 base::WriteFile(path_1, file_data, sizeof(file_data))); |
| 494 ASSERT_TRUE(base::PathExists(path_1)); |
| 495 |
| 496 base::FilePath new_path; |
| 497 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, |
| 498 RenameAndAnnotate(path_1, &new_path)); |
| 499 EXPECT_EQ(path_1.value(), new_path.value()); |
| 500 |
| 501 std::string file_contents; |
| 502 ASSERT_TRUE(base::ReadFileToString(new_path, &file_contents)); |
| 503 EXPECT_NE(std::string(file_data), file_contents); |
| 504 |
| 505 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); |
| 506 loop_.RunUntilIdle(); |
| 507 DestroyDownloadFile(0); |
| 508 } |
| 509 |
431 // Test to make sure the rename uniquifies if we aren't overwriting | 510 // Test to make sure the rename uniquifies if we aren't overwriting |
432 // and there's a file where we're aiming. | 511 // and there's a file where we're aiming. As above, not a |
| 512 // DownloadFileTestWithRename test because this only applies to |
| 513 // RenameAndUniquify(). |
433 TEST_F(DownloadFileTest, RenameUniquifies) { | 514 TEST_F(DownloadFileTest, RenameUniquifies) { |
434 ASSERT_TRUE(CreateDownloadFile(0, true)); | 515 ASSERT_TRUE(CreateDownloadFile(0, true)); |
435 base::FilePath initial_path(download_file_->FullPath()); | 516 base::FilePath initial_path(download_file_->FullPath()); |
436 EXPECT_TRUE(base::PathExists(initial_path)); | 517 EXPECT_TRUE(base::PathExists(initial_path)); |
437 base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1")); | 518 base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1")); |
438 base::FilePath path_1_suffixed(path_1.InsertBeforeExtensionASCII(" (1)")); | 519 base::FilePath path_1_suffixed(path_1.InsertBeforeExtensionASCII(" (1)")); |
439 | 520 |
440 ASSERT_FALSE(base::PathExists(path_1)); | 521 ASSERT_FALSE(base::PathExists(path_1)); |
441 static const char file_data[] = "xyzzy"; | 522 static const char file_data[] = "xyzzy"; |
442 ASSERT_EQ(static_cast<int>(sizeof(file_data)), | 523 ASSERT_EQ(static_cast<int>(sizeof(file_data)), |
443 base::WriteFile(path_1, file_data, sizeof(file_data))); | 524 base::WriteFile(path_1, file_data, sizeof(file_data))); |
444 ASSERT_TRUE(base::PathExists(path_1)); | 525 ASSERT_TRUE(base::PathExists(path_1)); |
445 | 526 |
446 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, RenameAndUniquify(path_1, NULL)); | 527 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, RenameAndUniquify(path_1, NULL)); |
447 EXPECT_TRUE(base::PathExists(path_1_suffixed)); | 528 EXPECT_TRUE(base::PathExists(path_1_suffixed)); |
448 | 529 |
449 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); | 530 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); |
450 loop_.RunUntilIdle(); | 531 loop_.RunUntilIdle(); |
451 DestroyDownloadFile(0); | 532 DestroyDownloadFile(0); |
452 } | 533 } |
453 | 534 |
| 535 // Test that RenameAndUniquify doesn't try to uniquify in the case where the |
| 536 // target filename is the same as the current filename. |
| 537 TEST_F(DownloadFileTest, RenameRecognizesSelfConflict) { |
| 538 ASSERT_TRUE(CreateDownloadFile(0, true)); |
| 539 base::FilePath initial_path(download_file_->FullPath()); |
| 540 EXPECT_TRUE(base::PathExists(initial_path)); |
| 541 |
| 542 base::FilePath new_path; |
| 543 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, |
| 544 RenameAndUniquify(initial_path, &new_path)); |
| 545 EXPECT_TRUE(base::PathExists(initial_path)); |
| 546 |
| 547 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); |
| 548 loop_.RunUntilIdle(); |
| 549 DestroyDownloadFile(0); |
| 550 EXPECT_EQ(initial_path.value(), new_path.value()); |
| 551 } |
| 552 |
454 // Test to make sure we get the proper error on failure. | 553 // Test to make sure we get the proper error on failure. |
455 TEST_F(DownloadFileTest, RenameError) { | 554 TEST_P(DownloadFileTestWithRename, RenameError) { |
456 ASSERT_TRUE(CreateDownloadFile(0, true)); | 555 ASSERT_TRUE(CreateDownloadFile(0, true)); |
457 base::FilePath initial_path(download_file_->FullPath()); | 556 base::FilePath initial_path(download_file_->FullPath()); |
458 | 557 |
459 // Create a subdirectory. | 558 // Create a subdirectory. |
460 base::FilePath tempdir( | 559 base::FilePath target_dir( |
461 initial_path.DirName().Append(FILE_PATH_LITERAL("tempdir"))); | 560 initial_path.DirName().Append(FILE_PATH_LITERAL("TargetDir"))); |
462 ASSERT_TRUE(base::CreateDirectory(tempdir)); | 561 ASSERT_FALSE(base::DirectoryExists(target_dir)); |
463 base::FilePath target_path(tempdir.Append(initial_path.BaseName())); | 562 ASSERT_TRUE(base::CreateDirectory(target_dir)); |
| 563 base::FilePath target_path(target_dir.Append(initial_path.BaseName())); |
464 | 564 |
465 // Targets | 565 // Targets |
466 base::FilePath target_path_suffixed( | 566 base::FilePath target_path_suffixed( |
467 target_path.InsertBeforeExtensionASCII(" (1)")); | 567 target_path.InsertBeforeExtensionASCII(" (1)")); |
468 ASSERT_FALSE(base::PathExists(target_path)); | 568 ASSERT_FALSE(base::PathExists(target_path)); |
469 ASSERT_FALSE(base::PathExists(target_path_suffixed)); | 569 ASSERT_FALSE(base::PathExists(target_path_suffixed)); |
470 | 570 |
471 // Make the directory unwritable and try to rename within it. | 571 // Make the directory unwritable and try to rename within it. |
472 { | 572 { |
473 base::FilePermissionRestorer restorer(tempdir); | 573 base::FilePermissionRestorer restorer(target_dir); |
474 ASSERT_TRUE(base::MakeFileUnwritable(tempdir)); | 574 ASSERT_TRUE(base::MakeFileUnwritable(target_dir)); |
475 | 575 |
476 // Expect nulling out of further processing. | 576 // Expect nulling out of further processing. |
477 EXPECT_CALL(*input_stream_, RegisterCallback(IsNullCallback())); | 577 EXPECT_CALL(*input_stream_, RegisterCallback(IsNullCallback())); |
478 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED, | 578 ExpectPermissionError(InvokeSelectedRenameMethod(target_path, NULL)); |
479 RenameAndAnnotate(target_path, NULL)); | |
480 EXPECT_FALSE(base::PathExists(target_path_suffixed)); | 579 EXPECT_FALSE(base::PathExists(target_path_suffixed)); |
481 } | 580 } |
482 | 581 |
483 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); | 582 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); |
484 loop_.RunUntilIdle(); | 583 loop_.RunUntilIdle(); |
485 DestroyDownloadFile(0); | 584 DestroyDownloadFile(0); |
486 } | 585 } |
487 | 586 |
| 587 namespace { |
| 588 |
| 589 void TestRenameCompletionCallback(const base::Closure& closure, |
| 590 bool* did_run_callback, |
| 591 DownloadInterruptReason interrupt_reason, |
| 592 const base::FilePath& new_path) { |
| 593 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason); |
| 594 *did_run_callback = true; |
| 595 closure.Run(); |
| 596 } |
| 597 |
| 598 } // namespace |
| 599 |
| 600 // Test that the retry logic works. This test assumes that DownloadFileImpl will |
| 601 // post tasks to the current message loop (acting as the FILE thread) |
| 602 // asynchronously to retry the renames. We will stuff RunLoop::QuitClosures() |
| 603 // in between the retry tasks to stagger them and then allow the rename to |
| 604 // succeed. |
| 605 // |
| 606 // Note that there is only one queue of tasks to run, and that is in the tests' |
| 607 // base::MessageLoop::current(). Each RunLoop processes that queue until it sees |
| 608 // a QuitClosure() targeted at itself, at which point it stops processing. |
| 609 TEST_P(DownloadFileTestWithRename, RenameWithErrorRetry) { |
| 610 ASSERT_TRUE(CreateDownloadFile(0, true)); |
| 611 base::FilePath initial_path(download_file_->FullPath()); |
| 612 |
| 613 // Create a subdirectory. |
| 614 base::FilePath target_dir( |
| 615 initial_path.DirName().Append(FILE_PATH_LITERAL("TargetDir"))); |
| 616 ASSERT_FALSE(base::DirectoryExists(target_dir)); |
| 617 ASSERT_TRUE(base::CreateDirectory(target_dir)); |
| 618 base::FilePath target_path(target_dir.Append(initial_path.BaseName())); |
| 619 |
| 620 bool did_run_callback = false; |
| 621 |
| 622 // Each RunLoop can be used the run the MessageLoop until the corresponding |
| 623 // QuitClosure() is run. This one is used to produce the QuitClosure() that |
| 624 // will be run when the entire rename operation is complete. |
| 625 base::RunLoop succeeding_run; |
| 626 { |
| 627 // (Scope for the base::File or base::FilePermissionRestorer below.) |
| 628 #if defined(OS_WIN) |
| 629 // On Windows we test with an actual transient error, a sharing violation. |
| 630 // The rename will fail because we are holding the file open for READ. On |
| 631 // Posix this doesn't cause a failure. |
| 632 base::File locked_file(initial_path, |
| 633 base::File::FLAG_OPEN | base::File::FLAG_READ); |
| 634 ASSERT_TRUE(locked_file.IsValid()); |
| 635 #else |
| 636 // Simulate a transient failure by revoking write permission for target_dir. |
| 637 // The TestDownloadFileImpl class treats this error as transient even though |
| 638 // DownloadFileImpl itself doesn't. |
| 639 base::FilePermissionRestorer restore_permissions_for(target_dir); |
| 640 ASSERT_TRUE(base::MakeFileUnwritable(target_dir)); |
| 641 #endif |
| 642 |
| 643 // The Rename() should fail here and enqueue a retry task without invoking |
| 644 // the completion callback. |
| 645 ((*download_file_).*GetParam())(target_path, |
| 646 base::Bind(&TestRenameCompletionCallback, |
| 647 succeeding_run.QuitClosure(), |
| 648 &did_run_callback)); |
| 649 EXPECT_FALSE(did_run_callback); |
| 650 |
| 651 base::RunLoop first_failing_run; |
| 652 // Queue the QuitClosure() on the MessageLoop now. Any tasks queued by the |
| 653 // Rename() will be in front of the QuitClosure(). Running the message loop |
| 654 // now causes the just the first retry task to be run. The rename still |
| 655 // fails, so another retry task would get queued behind the QuitClosure(). |
| 656 base::MessageLoop::current()->PostTask(FROM_HERE, |
| 657 first_failing_run.QuitClosure()); |
| 658 first_failing_run.Run(); |
| 659 EXPECT_FALSE(did_run_callback); |
| 660 |
| 661 // Running another loop should have the same effect as the above as long as |
| 662 // kMaxRenameRetries is greater than 2. |
| 663 base::RunLoop second_failing_run; |
| 664 base::MessageLoop::current()->PostTask(FROM_HERE, |
| 665 second_failing_run.QuitClosure()); |
| 666 second_failing_run.Run(); |
| 667 EXPECT_FALSE(did_run_callback); |
| 668 } |
| 669 |
| 670 // This time the QuitClosure from succeeding_run should get executed. |
| 671 succeeding_run.Run(); |
| 672 EXPECT_TRUE(did_run_callback); |
| 673 |
| 674 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); |
| 675 loop_.RunUntilIdle(); |
| 676 DestroyDownloadFile(0); |
| 677 } |
| 678 |
488 // Various tests of the StreamActive method. | 679 // Various tests of the StreamActive method. |
489 TEST_F(DownloadFileTest, StreamEmptySuccess) { | 680 TEST_F(DownloadFileTest, StreamEmptySuccess) { |
490 ASSERT_TRUE(CreateDownloadFile(0, true)); | 681 ASSERT_TRUE(CreateDownloadFile(0, true)); |
491 base::FilePath initial_path(download_file_->FullPath()); | 682 base::FilePath initial_path(download_file_->FullPath()); |
492 EXPECT_TRUE(base::PathExists(initial_path)); | 683 EXPECT_TRUE(base::PathExists(initial_path)); |
493 | 684 |
494 // Test that calling the sink_callback_ on an empty stream shouldn't | 685 // Test that calling the sink_callback_ on an empty stream shouldn't |
495 // do anything. | 686 // do anything. |
496 AppendDataToFile(NULL, 0); | 687 AppendDataToFile(NULL, 0); |
497 | 688 |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
594 | 785 |
595 EXPECT_EQ(static_cast<int64>(strlen(kTestData1) + strlen(kTestData2)), | 786 EXPECT_EQ(static_cast<int64>(strlen(kTestData1) + strlen(kTestData2)), |
596 bytes_); | 787 bytes_); |
597 EXPECT_EQ(download_file_->GetHashState(), hash_state_); | 788 EXPECT_EQ(download_file_->GetHashState(), hash_state_); |
598 | 789 |
599 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); | 790 FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); |
600 DestroyDownloadFile(0); | 791 DestroyDownloadFile(0); |
601 } | 792 } |
602 | 793 |
603 } // namespace content | 794 } // namespace content |
OLD | NEW |