Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / browser / download / download_file_unittest.cc
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
3 // found in the LICENSE file.
4
5 #include "base/files/file.h"
6 #include "base/files/file_util.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/run_loop.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/test/test_file_util.h"
11 #include "content/browser/browser_thread_impl.h"
12 #include "content/browser/byte_stream.h"
13 #include "content/browser/download/download_create_info.h"
14 #include "content/browser/download/download_file_impl.h"
15 #include "content/browser/download/download_request_handle.h"
16 #include "content/public/browser/download_destination_observer.h"
17 #include "content/public/browser/download_interrupt_reasons.h"
18 #include "content/public/browser/download_manager.h"
19 #include "content/public/test/mock_download_manager.h"
20 #include "net/base/file_stream.h"
21 #include "net/base/mock_file_stream.h"
22 #include "net/base/net_errors.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 using ::testing::_;
27 using ::testing::AnyNumber;
28 using ::testing::DoAll;
29 using ::testing::InSequence;
30 using ::testing::Return;
31 using ::testing::SetArgPointee;
32 using ::testing::StrictMock;
33
34 namespace content {
35 namespace {
36
37 class MockByteStreamReader : public ByteStreamReader {
38  public:
39   MockByteStreamReader() {}
40   ~MockByteStreamReader() {}
41
42   // ByteStream functions
43   MOCK_METHOD2(Read, ByteStreamReader::StreamState(
44       scoped_refptr<net::IOBuffer>*, size_t*));
45   MOCK_CONST_METHOD0(GetStatus, int());
46   MOCK_METHOD1(RegisterCallback, void(const base::Closure&));
47 };
48
49 class MockDownloadDestinationObserver : public DownloadDestinationObserver {
50  public:
51   MOCK_METHOD3(DestinationUpdate, void(int64, int64, const std::string&));
52   MOCK_METHOD1(DestinationError, void(DownloadInterruptReason));
53   MOCK_METHOD1(DestinationCompleted, void(const std::string&));
54
55   // Doesn't override any methods in the base class.  Used to make sure
56   // that the last DestinationUpdate before a Destination{Completed,Error}
57   // had the right values.
58   MOCK_METHOD3(CurrentUpdateStatus,
59                void(int64, int64, const std::string&));
60 };
61
62 MATCHER(IsNullCallback, "") { return (arg.is_null()); }
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   base::TimeDelta GetRetryDelayForFailedRename(int attempt_count) override {
91     return base::TimeDelta::FromMilliseconds(0);
92   }
93
94 #if !defined(OS_WIN)
95   // On Posix, we don't encounter transient errors during renames, except
96   // possibly EAGAIN, which is difficult to replicate reliably. So we resort to
97   // simulating a transient error using ACCESS_DENIED instead.
98   bool ShouldRetryFailedRename(DownloadInterruptReason reason) override {
99     return reason == DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED;
100   }
101 #endif
102 };
103
104 }  // namespace
105
106 class DownloadFileTest : public testing::Test {
107  public:
108
109   static const char* kTestData1;
110   static const char* kTestData2;
111   static const char* kTestData3;
112   static const char* kDataHash;
113   static const uint32 kDummyDownloadId;
114   static const int kDummyChildId;
115   static const int kDummyRequestId;
116
117   DownloadFileTest() :
118       observer_(new StrictMock<MockDownloadDestinationObserver>),
119       observer_factory_(observer_.get()),
120       input_stream_(NULL),
121       bytes_(-1),
122       bytes_per_sec_(-1),
123       hash_state_("xyzzy"),
124       ui_thread_(BrowserThread::UI, &loop_),
125       file_thread_(BrowserThread::FILE, &loop_) {
126   }
127
128   ~DownloadFileTest() override {}
129
130   void SetUpdateDownloadInfo(int64 bytes, int64 bytes_per_sec,
131                              const std::string& hash_state) {
132     bytes_ = bytes;
133     bytes_per_sec_ = bytes_per_sec;
134     hash_state_ = hash_state;
135   }
136
137   void ConfirmUpdateDownloadInfo() {
138     observer_->CurrentUpdateStatus(bytes_, bytes_per_sec_, hash_state_);
139   }
140
141   void SetUp() override {
142     EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _, _))
143         .Times(AnyNumber())
144         .WillRepeatedly(Invoke(this, &DownloadFileTest::SetUpdateDownloadInfo));
145   }
146
147   // Mock calls to this function are forwarded here.
148   void RegisterCallback(const base::Closure& sink_callback) {
149     sink_callback_ = sink_callback;
150   }
151
152   void SetInterruptReasonCallback(const base::Closure& closure,
153                                   DownloadInterruptReason* reason_p,
154                                   DownloadInterruptReason reason) {
155     *reason_p = reason;
156     closure.Run();
157   }
158
159   bool CreateDownloadFile(int offset, bool calculate_hash) {
160     // There can be only one.
161     DCHECK(!download_file_.get());
162
163     input_stream_ = new StrictMock<MockByteStreamReader>();
164
165     // TODO: Need to actually create a function that'll set the variables
166     // based on the inputs from the callback.
167     EXPECT_CALL(*input_stream_, RegisterCallback(_))
168         .WillOnce(Invoke(this, &DownloadFileTest::RegisterCallback))
169         .RetiresOnSaturation();
170
171     scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo());
172     scoped_ptr<TestDownloadFileImpl> download_file_impl(
173         new TestDownloadFileImpl(save_info.Pass(),
174                                  base::FilePath(),
175                                  GURL(),  // Source
176                                  GURL(),  // Referrer
177                                  calculate_hash,
178                                  scoped_ptr<ByteStreamReader>(input_stream_),
179                                  net::BoundNetLog(),
180                                  observer_factory_.GetWeakPtr()));
181     download_file_impl->SetClientGuid("12345678-ABCD-1234-DCBA-123456789ABC");
182     download_file_ = download_file_impl.Pass();
183
184     EXPECT_CALL(*input_stream_, Read(_, _))
185         .WillOnce(Return(ByteStreamReader::STREAM_EMPTY))
186         .RetiresOnSaturation();
187
188     base::WeakPtrFactory<DownloadFileTest> weak_ptr_factory(this);
189     DownloadInterruptReason result = DOWNLOAD_INTERRUPT_REASON_NONE;
190     base::RunLoop loop_runner;
191     download_file_->Initialize(base::Bind(
192         &DownloadFileTest::SetInterruptReasonCallback,
193         weak_ptr_factory.GetWeakPtr(), loop_runner.QuitClosure(), &result));
194     loop_runner.Run();
195
196     ::testing::Mock::VerifyAndClearExpectations(input_stream_);
197     return result == DOWNLOAD_INTERRUPT_REASON_NONE;
198   }
199
200   void DestroyDownloadFile(int offset) {
201     EXPECT_FALSE(download_file_->InProgress());
202
203     // Make sure the data has been properly written to disk.
204     std::string disk_data;
205     EXPECT_TRUE(base::ReadFileToString(download_file_->FullPath(), &disk_data));
206     EXPECT_EQ(expected_data_, disk_data);
207
208     // Make sure the Browser and File threads outlive the DownloadFile
209     // to satisfy thread checks inside it.
210     download_file_.reset();
211   }
212
213   // Setup the stream to do be a data append; don't actually trigger
214   // the callback or do verifications.
215   void SetupDataAppend(const char **data_chunks, size_t num_chunks,
216                        ::testing::Sequence s) {
217     DCHECK(input_stream_);
218     for (size_t i = 0; i < num_chunks; i++) {
219       const char *source_data = data_chunks[i];
220       size_t length = strlen(source_data);
221       scoped_refptr<net::IOBuffer> data = new net::IOBuffer(length);
222       memcpy(data->data(), source_data, length);
223       EXPECT_CALL(*input_stream_, Read(_, _))
224           .InSequence(s)
225           .WillOnce(DoAll(SetArgPointee<0>(data),
226                           SetArgPointee<1>(length),
227                           Return(ByteStreamReader::STREAM_HAS_DATA)))
228           .RetiresOnSaturation();
229       expected_data_ += source_data;
230     }
231   }
232
233   void VerifyStreamAndSize() {
234     ::testing::Mock::VerifyAndClearExpectations(input_stream_);
235     int64 size;
236     EXPECT_TRUE(base::GetFileSize(download_file_->FullPath(), &size));
237     EXPECT_EQ(expected_data_.size(), static_cast<size_t>(size));
238   }
239
240   // TODO(rdsmith): Manage full percentage issues properly.
241   void AppendDataToFile(const char **data_chunks, size_t num_chunks) {
242     ::testing::Sequence s1;
243     SetupDataAppend(data_chunks, num_chunks, s1);
244     EXPECT_CALL(*input_stream_, Read(_, _))
245         .InSequence(s1)
246         .WillOnce(Return(ByteStreamReader::STREAM_EMPTY))
247         .RetiresOnSaturation();
248     sink_callback_.Run();
249     VerifyStreamAndSize();
250   }
251
252   void SetupFinishStream(DownloadInterruptReason interrupt_reason,
253                        ::testing::Sequence s) {
254     EXPECT_CALL(*input_stream_, Read(_, _))
255         .InSequence(s)
256         .WillOnce(Return(ByteStreamReader::STREAM_COMPLETE))
257         .RetiresOnSaturation();
258     EXPECT_CALL(*input_stream_, GetStatus())
259         .InSequence(s)
260         .WillOnce(Return(interrupt_reason))
261         .RetiresOnSaturation();
262     EXPECT_CALL(*input_stream_, RegisterCallback(_))
263         .RetiresOnSaturation();
264   }
265
266   void FinishStream(DownloadInterruptReason interrupt_reason,
267                     bool check_observer) {
268     ::testing::Sequence s1;
269     SetupFinishStream(interrupt_reason, s1);
270     sink_callback_.Run();
271     VerifyStreamAndSize();
272     if (check_observer) {
273       EXPECT_CALL(*(observer_.get()), DestinationCompleted(_));
274       loop_.RunUntilIdle();
275       ::testing::Mock::VerifyAndClearExpectations(observer_.get());
276       EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _, _))
277           .Times(AnyNumber())
278           .WillRepeatedly(Invoke(this,
279                                  &DownloadFileTest::SetUpdateDownloadInfo));
280     }
281   }
282
283   DownloadInterruptReason RenameAndUniquify(
284       const base::FilePath& full_path,
285       base::FilePath* result_path_p) {
286     return InvokeRenameMethodAndWaitForCallback(
287         &DownloadFile::RenameAndUniquify, full_path, result_path_p);
288   }
289
290   DownloadInterruptReason RenameAndAnnotate(
291       const base::FilePath& full_path,
292       base::FilePath* result_path_p) {
293     return InvokeRenameMethodAndWaitForCallback(
294         &DownloadFile::RenameAndAnnotate, full_path, result_path_p);
295   }
296
297   void ExpectPermissionError(DownloadInterruptReason err) {
298     EXPECT_TRUE(err == DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR ||
299                 err == DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED)
300         << "Interrupt reason = " << err;
301   }
302
303  protected:
304   DownloadInterruptReason InvokeRenameMethodAndWaitForCallback(
305       DownloadFileRenameMethodType method,
306       const base::FilePath& full_path,
307       base::FilePath* result_path_p) {
308     DownloadInterruptReason result_reason(DOWNLOAD_INTERRUPT_REASON_NONE);
309     base::FilePath result_path;
310
311     base::RunLoop loop_runner;
312     ((*download_file_).*method)(full_path,
313                                 base::Bind(&DownloadFileTest::SetRenameResult,
314                                            base::Unretained(this),
315                                            loop_runner.QuitClosure(),
316                                            &result_reason,
317                                            result_path_p));
318     loop_runner.Run();
319     return result_reason;
320   }
321
322   scoped_ptr<StrictMock<MockDownloadDestinationObserver> > observer_;
323   base::WeakPtrFactory<DownloadDestinationObserver> observer_factory_;
324
325   // DownloadFile instance we are testing.
326   scoped_ptr<DownloadFile> download_file_;
327
328   // Stream for sending data into the download file.
329   // Owned by download_file_; will be alive for lifetime of download_file_.
330   StrictMock<MockByteStreamReader>* input_stream_;
331
332   // Sink callback data for stream.
333   base::Closure sink_callback_;
334
335   // Latest update sent to the observer.
336   int64 bytes_;
337   int64 bytes_per_sec_;
338   std::string hash_state_;
339
340   base::MessageLoop loop_;
341
342  private:
343   void SetRenameResult(const base::Closure& closure,
344                        DownloadInterruptReason* reason_p,
345                        base::FilePath* result_path_p,
346                        DownloadInterruptReason reason,
347                        const base::FilePath& result_path) {
348     if (reason_p)
349       *reason_p = reason;
350     if (result_path_p)
351       *result_path_p = result_path;
352     closure.Run();
353   }
354
355   // UI thread.
356   BrowserThreadImpl ui_thread_;
357   // File thread to satisfy debug checks in DownloadFile.
358   BrowserThreadImpl file_thread_;
359
360   // Keep track of what data should be saved to the disk file.
361   std::string expected_data_;
362 };
363
364 // DownloadFile::RenameAndAnnotate and DownloadFile::RenameAndUniquify have a
365 // considerable amount of functional overlap. In order to re-use test logic, we
366 // are going to introduce this value parameterized test fixture. It will take a
367 // DownloadFileRenameMethodType value which can be either of the two rename
368 // methods.
369 class DownloadFileTestWithRename
370     : public DownloadFileTest,
371       public ::testing::WithParamInterface<DownloadFileRenameMethodType> {
372  protected:
373   DownloadInterruptReason InvokeSelectedRenameMethod(
374       const base::FilePath& full_path,
375       base::FilePath* result_path_p) {
376     return InvokeRenameMethodAndWaitForCallback(
377         GetParam(), full_path, result_path_p);
378   }
379 };
380
381 // And now instantiate all DownloadFileTestWithRename tests using both
382 // DownloadFile rename methods. Each test of the form
383 // DownloadFileTestWithRename.<FooTest> will be instantiated once with
384 // RenameAndAnnotate as the value parameter and once with RenameAndUniquify as
385 // the value parameter.
386 INSTANTIATE_TEST_CASE_P(DownloadFile,
387                         DownloadFileTestWithRename,
388                         ::testing::Values(&DownloadFile::RenameAndAnnotate,
389                                           &DownloadFile::RenameAndUniquify));
390
391 const char* DownloadFileTest::kTestData1 =
392     "Let's write some data to the file!\n";
393 const char* DownloadFileTest::kTestData2 = "Writing more data.\n";
394 const char* DownloadFileTest::kTestData3 = "Final line.";
395 const char* DownloadFileTest::kDataHash =
396     "CBF68BF10F8003DB86B31343AFAC8C7175BD03FB5FC905650F8C80AF087443A8";
397
398 const uint32 DownloadFileTest::kDummyDownloadId = 23;
399 const int DownloadFileTest::kDummyChildId = 3;
400 const int DownloadFileTest::kDummyRequestId = 67;
401
402 // Rename the file before any data is downloaded, after some has, after it all
403 // has, and after it's closed.
404 TEST_P(DownloadFileTestWithRename, RenameFileFinal) {
405   ASSERT_TRUE(CreateDownloadFile(0, true));
406   base::FilePath initial_path(download_file_->FullPath());
407   EXPECT_TRUE(base::PathExists(initial_path));
408   base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1"));
409   base::FilePath path_2(initial_path.InsertBeforeExtensionASCII("_2"));
410   base::FilePath path_3(initial_path.InsertBeforeExtensionASCII("_3"));
411   base::FilePath path_4(initial_path.InsertBeforeExtensionASCII("_4"));
412   base::FilePath output_path;
413
414   // Rename the file before downloading any data.
415   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
416             InvokeSelectedRenameMethod(path_1, &output_path));
417   base::FilePath renamed_path = download_file_->FullPath();
418   EXPECT_EQ(path_1, renamed_path);
419   EXPECT_EQ(path_1, output_path);
420
421   // Check the files.
422   EXPECT_FALSE(base::PathExists(initial_path));
423   EXPECT_TRUE(base::PathExists(path_1));
424
425   // Download the data.
426   const char* chunks1[] = { kTestData1, kTestData2 };
427   AppendDataToFile(chunks1, 2);
428
429   // Rename the file after downloading some data.
430   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
431             InvokeSelectedRenameMethod(path_2, &output_path));
432   renamed_path = download_file_->FullPath();
433   EXPECT_EQ(path_2, renamed_path);
434   EXPECT_EQ(path_2, output_path);
435
436   // Check the files.
437   EXPECT_FALSE(base::PathExists(path_1));
438   EXPECT_TRUE(base::PathExists(path_2));
439
440   const char* chunks2[] = { kTestData3 };
441   AppendDataToFile(chunks2, 1);
442
443   // Rename the file after downloading all the data.
444   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
445             InvokeSelectedRenameMethod(path_3, &output_path));
446   renamed_path = download_file_->FullPath();
447   EXPECT_EQ(path_3, renamed_path);
448   EXPECT_EQ(path_3, output_path);
449
450   // Check the files.
451   EXPECT_FALSE(base::PathExists(path_2));
452   EXPECT_TRUE(base::PathExists(path_3));
453
454   // Should not be able to get the hash until the file is closed.
455   std::string hash;
456   EXPECT_FALSE(download_file_->GetHash(&hash));
457   FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
458   loop_.RunUntilIdle();
459
460   // Rename the file after downloading all the data and closing the file.
461   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
462             InvokeSelectedRenameMethod(path_4, &output_path));
463   renamed_path = download_file_->FullPath();
464   EXPECT_EQ(path_4, renamed_path);
465   EXPECT_EQ(path_4, output_path);
466
467   // Check the files.
468   EXPECT_FALSE(base::PathExists(path_3));
469   EXPECT_TRUE(base::PathExists(path_4));
470
471   // Check the hash.
472   EXPECT_TRUE(download_file_->GetHash(&hash));
473   EXPECT_EQ(kDataHash, base::HexEncode(hash.data(), hash.size()));
474
475   DestroyDownloadFile(0);
476 }
477
478 // Test to make sure the rename overwrites when requested. This is separate from
479 // the above test because it only applies to RenameAndAnnotate().
480 // RenameAndUniquify() doesn't overwrite by design.
481 TEST_F(DownloadFileTest, RenameOverwrites) {
482   ASSERT_TRUE(CreateDownloadFile(0, true));
483   base::FilePath initial_path(download_file_->FullPath());
484   EXPECT_TRUE(base::PathExists(initial_path));
485   base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1"));
486
487   ASSERT_FALSE(base::PathExists(path_1));
488   static const char file_data[] = "xyzzy";
489   ASSERT_EQ(static_cast<int>(sizeof(file_data)),
490             base::WriteFile(path_1, file_data, sizeof(file_data)));
491   ASSERT_TRUE(base::PathExists(path_1));
492
493   base::FilePath new_path;
494   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
495             RenameAndAnnotate(path_1, &new_path));
496   EXPECT_EQ(path_1.value(), new_path.value());
497
498   std::string file_contents;
499   ASSERT_TRUE(base::ReadFileToString(new_path, &file_contents));
500   EXPECT_NE(std::string(file_data), file_contents);
501
502   FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
503   loop_.RunUntilIdle();
504   DestroyDownloadFile(0);
505 }
506
507 // Test to make sure the rename uniquifies if we aren't overwriting
508 // and there's a file where we're aiming. As above, not a
509 // DownloadFileTestWithRename test because this only applies to
510 // RenameAndUniquify().
511 TEST_F(DownloadFileTest, RenameUniquifies) {
512   ASSERT_TRUE(CreateDownloadFile(0, true));
513   base::FilePath initial_path(download_file_->FullPath());
514   EXPECT_TRUE(base::PathExists(initial_path));
515   base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1"));
516   base::FilePath path_1_suffixed(path_1.InsertBeforeExtensionASCII(" (1)"));
517
518   ASSERT_FALSE(base::PathExists(path_1));
519   static const char file_data[] = "xyzzy";
520   ASSERT_EQ(static_cast<int>(sizeof(file_data)),
521             base::WriteFile(path_1, file_data, sizeof(file_data)));
522   ASSERT_TRUE(base::PathExists(path_1));
523
524   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, RenameAndUniquify(path_1, NULL));
525   EXPECT_TRUE(base::PathExists(path_1_suffixed));
526
527   FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
528   loop_.RunUntilIdle();
529   DestroyDownloadFile(0);
530 }
531
532 // Test that RenameAndUniquify doesn't try to uniquify in the case where the
533 // target filename is the same as the current filename.
534 TEST_F(DownloadFileTest, RenameRecognizesSelfConflict) {
535   ASSERT_TRUE(CreateDownloadFile(0, true));
536   base::FilePath initial_path(download_file_->FullPath());
537   EXPECT_TRUE(base::PathExists(initial_path));
538
539   base::FilePath new_path;
540   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
541             RenameAndUniquify(initial_path, &new_path));
542   EXPECT_TRUE(base::PathExists(initial_path));
543
544   FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
545   loop_.RunUntilIdle();
546   DestroyDownloadFile(0);
547   EXPECT_EQ(initial_path.value(), new_path.value());
548 }
549
550 // Test to make sure we get the proper error on failure.
551 TEST_P(DownloadFileTestWithRename, RenameError) {
552   ASSERT_TRUE(CreateDownloadFile(0, true));
553   base::FilePath initial_path(download_file_->FullPath());
554
555   // Create a subdirectory.
556   base::FilePath target_dir(
557       initial_path.DirName().Append(FILE_PATH_LITERAL("TargetDir")));
558   ASSERT_FALSE(base::DirectoryExists(target_dir));
559   ASSERT_TRUE(base::CreateDirectory(target_dir));
560   base::FilePath target_path(target_dir.Append(initial_path.BaseName()));
561
562   // Targets
563   base::FilePath target_path_suffixed(
564       target_path.InsertBeforeExtensionASCII(" (1)"));
565   ASSERT_FALSE(base::PathExists(target_path));
566   ASSERT_FALSE(base::PathExists(target_path_suffixed));
567
568   // Make the directory unwritable and try to rename within it.
569   {
570     base::FilePermissionRestorer restorer(target_dir);
571     ASSERT_TRUE(base::MakeFileUnwritable(target_dir));
572
573     // Expect nulling out of further processing.
574     EXPECT_CALL(*input_stream_, RegisterCallback(IsNullCallback()));
575     ExpectPermissionError(InvokeSelectedRenameMethod(target_path, NULL));
576     EXPECT_FALSE(base::PathExists(target_path_suffixed));
577   }
578
579   FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
580   loop_.RunUntilIdle();
581   DestroyDownloadFile(0);
582 }
583
584 namespace {
585
586 void TestRenameCompletionCallback(const base::Closure& closure,
587                                   bool* did_run_callback,
588                                   DownloadInterruptReason interrupt_reason,
589                                   const base::FilePath& new_path) {
590   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason);
591   *did_run_callback = true;
592   closure.Run();
593 }
594
595 }  // namespace
596
597 // Test that the retry logic works. This test assumes that DownloadFileImpl will
598 // post tasks to the current message loop (acting as the FILE thread)
599 // asynchronously to retry the renames. We will stuff RunLoop::QuitClosures()
600 // in between the retry tasks to stagger them and then allow the rename to
601 // succeed.
602 //
603 // Note that there is only one queue of tasks to run, and that is in the tests'
604 // base::MessageLoop::current(). Each RunLoop processes that queue until it sees
605 // a QuitClosure() targeted at itself, at which point it stops processing.
606 TEST_P(DownloadFileTestWithRename, RenameWithErrorRetry) {
607   ASSERT_TRUE(CreateDownloadFile(0, true));
608   base::FilePath initial_path(download_file_->FullPath());
609
610   // Create a subdirectory.
611   base::FilePath target_dir(
612       initial_path.DirName().Append(FILE_PATH_LITERAL("TargetDir")));
613   ASSERT_FALSE(base::DirectoryExists(target_dir));
614   ASSERT_TRUE(base::CreateDirectory(target_dir));
615   base::FilePath target_path(target_dir.Append(initial_path.BaseName()));
616
617   bool did_run_callback = false;
618
619   // Each RunLoop can be used the run the MessageLoop until the corresponding
620   // QuitClosure() is run. This one is used to produce the QuitClosure() that
621   // will be run when the entire rename operation is complete.
622   base::RunLoop succeeding_run;
623   {
624     // (Scope for the base::File or base::FilePermissionRestorer below.)
625 #if defined(OS_WIN)
626     // On Windows we test with an actual transient error, a sharing violation.
627     // The rename will fail because we are holding the file open for READ. On
628     // Posix this doesn't cause a failure.
629     base::File locked_file(initial_path,
630                            base::File::FLAG_OPEN | base::File::FLAG_READ);
631     ASSERT_TRUE(locked_file.IsValid());
632 #else
633     // Simulate a transient failure by revoking write permission for target_dir.
634     // The TestDownloadFileImpl class treats this error as transient even though
635     // DownloadFileImpl itself doesn't.
636     base::FilePermissionRestorer restore_permissions_for(target_dir);
637     ASSERT_TRUE(base::MakeFileUnwritable(target_dir));
638 #endif
639
640     // The Rename() should fail here and enqueue a retry task without invoking
641     // the completion callback.
642     ((*download_file_).*GetParam())(target_path,
643                                     base::Bind(&TestRenameCompletionCallback,
644                                                succeeding_run.QuitClosure(),
645                                                &did_run_callback));
646     EXPECT_FALSE(did_run_callback);
647
648     base::RunLoop first_failing_run;
649     // Queue the QuitClosure() on the MessageLoop now. Any tasks queued by the
650     // Rename() will be in front of the QuitClosure(). Running the message loop
651     // now causes the just the first retry task to be run. The rename still
652     // fails, so another retry task would get queued behind the QuitClosure().
653     base::MessageLoop::current()->PostTask(FROM_HERE,
654                                            first_failing_run.QuitClosure());
655     first_failing_run.Run();
656     EXPECT_FALSE(did_run_callback);
657
658     // Running another loop should have the same effect as the above as long as
659     // kMaxRenameRetries is greater than 2.
660     base::RunLoop second_failing_run;
661     base::MessageLoop::current()->PostTask(FROM_HERE,
662                                            second_failing_run.QuitClosure());
663     second_failing_run.Run();
664     EXPECT_FALSE(did_run_callback);
665   }
666
667   // This time the QuitClosure from succeeding_run should get executed.
668   succeeding_run.Run();
669   EXPECT_TRUE(did_run_callback);
670
671   FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
672   loop_.RunUntilIdle();
673   DestroyDownloadFile(0);
674 }
675
676 // Various tests of the StreamActive method.
677 TEST_F(DownloadFileTest, StreamEmptySuccess) {
678   ASSERT_TRUE(CreateDownloadFile(0, true));
679   base::FilePath initial_path(download_file_->FullPath());
680   EXPECT_TRUE(base::PathExists(initial_path));
681
682   // Test that calling the sink_callback_ on an empty stream shouldn't
683   // do anything.
684   AppendDataToFile(NULL, 0);
685
686   // Finish the download this way and make sure we see it on the
687   // observer.
688   EXPECT_CALL(*(observer_.get()), DestinationCompleted(_));
689   FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, false);
690   loop_.RunUntilIdle();
691
692   DestroyDownloadFile(0);
693 }
694
695 TEST_F(DownloadFileTest, StreamEmptyError) {
696   ASSERT_TRUE(CreateDownloadFile(0, true));
697   base::FilePath initial_path(download_file_->FullPath());
698   EXPECT_TRUE(base::PathExists(initial_path));
699
700   // Finish the download in error and make sure we see it on the
701   // observer.
702   EXPECT_CALL(*(observer_.get()),
703               DestinationError(
704                   DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED))
705       .WillOnce(InvokeWithoutArgs(
706           this, &DownloadFileTest::ConfirmUpdateDownloadInfo));
707
708   // If this next EXPECT_CALL fails flakily, it's probably a real failure.
709   // We'll be getting a stream of UpdateDownload calls from the timer, and
710   // the last one may have the correct information even if the failure
711   // doesn't produce an update, as the timer update may have triggered at the
712   // same time.
713   EXPECT_CALL(*(observer_.get()), CurrentUpdateStatus(0, _, _));
714
715   FinishStream(DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, false);
716
717   loop_.RunUntilIdle();
718
719   DestroyDownloadFile(0);
720 }
721
722 TEST_F(DownloadFileTest, StreamNonEmptySuccess) {
723   ASSERT_TRUE(CreateDownloadFile(0, true));
724   base::FilePath initial_path(download_file_->FullPath());
725   EXPECT_TRUE(base::PathExists(initial_path));
726
727   const char* chunks1[] = { kTestData1, kTestData2 };
728   ::testing::Sequence s1;
729   SetupDataAppend(chunks1, 2, s1);
730   SetupFinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, s1);
731   EXPECT_CALL(*(observer_.get()), DestinationCompleted(_));
732   sink_callback_.Run();
733   VerifyStreamAndSize();
734   loop_.RunUntilIdle();
735   DestroyDownloadFile(0);
736 }
737
738 TEST_F(DownloadFileTest, StreamNonEmptyError) {
739   ASSERT_TRUE(CreateDownloadFile(0, true));
740   base::FilePath initial_path(download_file_->FullPath());
741   EXPECT_TRUE(base::PathExists(initial_path));
742
743   const char* chunks1[] = { kTestData1, kTestData2 };
744   ::testing::Sequence s1;
745   SetupDataAppend(chunks1, 2, s1);
746   SetupFinishStream(DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED, s1);
747
748   EXPECT_CALL(*(observer_.get()),
749               DestinationError(
750                   DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED))
751       .WillOnce(InvokeWithoutArgs(
752           this, &DownloadFileTest::ConfirmUpdateDownloadInfo));
753
754   // If this next EXPECT_CALL fails flakily, it's probably a real failure.
755   // We'll be getting a stream of UpdateDownload calls from the timer, and
756   // the last one may have the correct information even if the failure
757   // doesn't produce an update, as the timer update may have triggered at the
758   // same time.
759   EXPECT_CALL(*(observer_.get()),
760               CurrentUpdateStatus(strlen(kTestData1) + strlen(kTestData2),
761                                   _, _));
762
763   sink_callback_.Run();
764   loop_.RunUntilIdle();
765   VerifyStreamAndSize();
766   DestroyDownloadFile(0);
767 }
768
769 // Send some data, wait 3/4s of a second, run the message loop, and
770 // confirm the values the observer received are correct.
771 TEST_F(DownloadFileTest, ConfirmUpdate) {
772   CreateDownloadFile(0, true);
773
774   const char* chunks1[] = { kTestData1, kTestData2 };
775   AppendDataToFile(chunks1, 2);
776
777   // Run the message loops for 750ms and check for results.
778   loop_.PostDelayedTask(FROM_HERE,
779                         base::MessageLoop::QuitClosure(),
780                         base::TimeDelta::FromMilliseconds(750));
781   loop_.Run();
782
783   EXPECT_EQ(static_cast<int64>(strlen(kTestData1) + strlen(kTestData2)),
784             bytes_);
785   EXPECT_EQ(download_file_->GetHashState(), hash_state_);
786
787   FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
788   DestroyDownloadFile(0);
789 }
790
791 }  // namespace content