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