Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(170)

Side by Side Diff: content/browser/download/download_file_unittest.cc

Issue 319603003: [Downloads] Retry renames after transient failures. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Prepare to reland after XP test fix. Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « content/browser/download/download_file_impl.cc ('k') | content/browser/download/download_interrupt_reasons_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698