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

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

Powered by Google App Engine
This is Rietveld 408576698