Index: trunk/src/content/browser/download/download_file_unittest.cc |
=================================================================== |
--- trunk/src/content/browser/download/download_file_unittest.cc (revision 278536) |
+++ trunk/src/content/browser/download/download_file_unittest.cc (working copy) |
@@ -3,9 +3,7 @@ |
// found in the LICENSE file. |
#include "base/file_util.h" |
-#include "base/files/file.h" |
#include "base/message_loop/message_loop.h" |
-#include "base/run_loop.h" |
#include "base/strings/string_number_conversions.h" |
#include "base/test/test_file_util.h" |
#include "content/browser/browser_thread_impl.h" |
@@ -61,48 +59,6 @@ |
MATCHER(IsNullCallback, "") { return (arg.is_null()); } |
-typedef void (DownloadFile::*DownloadFileRenameMethodType)( |
- const base::FilePath&, |
- const DownloadFile::RenameCompletionCallback&); |
- |
-// This is a test DownloadFileImpl that has no retry delay and, on Posix, |
-// retries renames failed due to ACCESS_DENIED. |
-class TestDownloadFileImpl : public DownloadFileImpl { |
- public: |
- TestDownloadFileImpl(scoped_ptr<DownloadSaveInfo> save_info, |
- const base::FilePath& default_downloads_directory, |
- const GURL& url, |
- const GURL& referrer_url, |
- bool calculate_hash, |
- scoped_ptr<ByteStreamReader> stream, |
- const net::BoundNetLog& bound_net_log, |
- base::WeakPtr<DownloadDestinationObserver> observer) |
- : DownloadFileImpl(save_info.Pass(), |
- default_downloads_directory, |
- url, |
- referrer_url, |
- calculate_hash, |
- stream.Pass(), |
- bound_net_log, |
- observer) {} |
- |
- protected: |
- virtual base::TimeDelta GetRetryDelayForFailedRename( |
- int attempt_count) OVERRIDE { |
- return base::TimeDelta::FromMilliseconds(0); |
- } |
- |
-#if !defined(OS_WIN) |
- // On Posix, we don't encounter transient errors during renames, except |
- // possibly EAGAIN, which is difficult to replicate reliably. So we resort to |
- // simulating a transient error using ACCESS_DENIED instead. |
- virtual bool ShouldRetryFailedRename( |
- DownloadInterruptReason reason) OVERRIDE { |
- return reason == DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED; |
- } |
-#endif |
-}; |
- |
} // namespace |
class DownloadFileTest : public testing::Test { |
@@ -148,15 +104,15 @@ |
} |
// Mock calls to this function are forwarded here. |
- void RegisterCallback(const base::Closure& sink_callback) { |
+ void RegisterCallback(base::Closure sink_callback) { |
sink_callback_ = sink_callback; |
} |
- void SetInterruptReasonCallback(const base::Closure& closure, |
+ void SetInterruptReasonCallback(bool* was_called, |
DownloadInterruptReason* reason_p, |
DownloadInterruptReason reason) { |
+ *was_called = true; |
*reason_p = reason; |
- closure.Run(); |
} |
bool CreateDownloadFile(int offset, bool calculate_hash) { |
@@ -172,29 +128,30 @@ |
.RetiresOnSaturation(); |
scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo()); |
- scoped_ptr<TestDownloadFileImpl> download_file_impl( |
- new TestDownloadFileImpl(save_info.Pass(), |
- base::FilePath(), |
- GURL(), // Source |
- GURL(), // Referrer |
- calculate_hash, |
- scoped_ptr<ByteStreamReader>(input_stream_), |
- net::BoundNetLog(), |
- observer_factory_.GetWeakPtr())); |
- download_file_impl->SetClientGuid("12345678-ABCD-1234-DCBA-123456789ABC"); |
- download_file_ = download_file_impl.PassAs<DownloadFile>(); |
+ download_file_.reset( |
+ new DownloadFileImpl(save_info.Pass(), |
+ base::FilePath(), |
+ GURL(), // Source |
+ GURL(), // Referrer |
+ calculate_hash, |
+ scoped_ptr<ByteStreamReader>(input_stream_), |
+ net::BoundNetLog(), |
+ observer_factory_.GetWeakPtr())); |
+ download_file_->SetClientGuid( |
+ "12345678-ABCD-1234-DCBA-123456789ABC"); |
EXPECT_CALL(*input_stream_, Read(_, _)) |
.WillOnce(Return(ByteStreamReader::STREAM_EMPTY)) |
.RetiresOnSaturation(); |
base::WeakPtrFactory<DownloadFileTest> weak_ptr_factory(this); |
- DownloadInterruptReason result = DOWNLOAD_INTERRUPT_REASON_NONE; |
- base::RunLoop loop_runner; |
+ bool called = false; |
+ DownloadInterruptReason result; |
download_file_->Initialize(base::Bind( |
&DownloadFileTest::SetInterruptReasonCallback, |
- weak_ptr_factory.GetWeakPtr(), loop_runner.QuitClosure(), &result)); |
- loop_runner.Run(); |
+ weak_ptr_factory.GetWeakPtr(), &called, &result)); |
+ loop_.RunUntilIdle(); |
+ EXPECT_TRUE(called); |
::testing::Mock::VerifyAndClearExpectations(input_stream_); |
return result == DOWNLOAD_INTERRUPT_REASON_NONE; |
@@ -286,36 +243,42 @@ |
DownloadInterruptReason RenameAndUniquify( |
const base::FilePath& full_path, |
base::FilePath* result_path_p) { |
- return InvokeRenameMethodAndWaitForCallback( |
- &DownloadFile::RenameAndUniquify, full_path, result_path_p); |
+ base::WeakPtrFactory<DownloadFileTest> weak_ptr_factory(this); |
+ DownloadInterruptReason result_reason(DOWNLOAD_INTERRUPT_REASON_NONE); |
+ bool callback_was_called(false); |
+ base::FilePath result_path; |
+ |
+ download_file_->RenameAndUniquify( |
+ full_path, base::Bind(&DownloadFileTest::SetRenameResult, |
+ weak_ptr_factory.GetWeakPtr(), |
+ &callback_was_called, |
+ &result_reason, result_path_p)); |
+ loop_.RunUntilIdle(); |
+ |
+ EXPECT_TRUE(callback_was_called); |
+ return result_reason; |
} |
DownloadInterruptReason RenameAndAnnotate( |
const base::FilePath& full_path, |
base::FilePath* result_path_p) { |
- return InvokeRenameMethodAndWaitForCallback( |
- &DownloadFile::RenameAndAnnotate, full_path, result_path_p); |
- } |
- |
- protected: |
- DownloadInterruptReason InvokeRenameMethodAndWaitForCallback( |
- DownloadFileRenameMethodType method, |
- const base::FilePath& full_path, |
- base::FilePath* result_path_p) { |
+ base::WeakPtrFactory<DownloadFileTest> weak_ptr_factory(this); |
DownloadInterruptReason result_reason(DOWNLOAD_INTERRUPT_REASON_NONE); |
+ bool callback_was_called(false); |
base::FilePath result_path; |
- base::RunLoop loop_runner; |
- ((*download_file_).*method)(full_path, |
- base::Bind(&DownloadFileTest::SetRenameResult, |
- base::Unretained(this), |
- loop_runner.QuitClosure(), |
- &result_reason, |
- result_path_p)); |
- loop_runner.Run(); |
+ download_file_->RenameAndAnnotate( |
+ full_path, base::Bind(&DownloadFileTest::SetRenameResult, |
+ weak_ptr_factory.GetWeakPtr(), |
+ &callback_was_called, |
+ &result_reason, result_path_p)); |
+ loop_.RunUntilIdle(); |
+ |
+ EXPECT_TRUE(callback_was_called); |
return result_reason; |
} |
+ protected: |
scoped_ptr<StrictMock<MockDownloadDestinationObserver> > observer_; |
base::WeakPtrFactory<DownloadDestinationObserver> observer_factory_; |
@@ -337,16 +300,17 @@ |
base::MessageLoop loop_; |
private: |
- void SetRenameResult(const base::Closure& closure, |
+ void SetRenameResult(bool* called_p, |
DownloadInterruptReason* reason_p, |
base::FilePath* result_path_p, |
DownloadInterruptReason reason, |
const base::FilePath& result_path) { |
+ if (called_p) |
+ *called_p = true; |
if (reason_p) |
*reason_p = reason; |
if (result_path_p) |
*result_path_p = result_path; |
- closure.Run(); |
} |
// UI thread. |
@@ -358,33 +322,6 @@ |
std::string expected_data_; |
}; |
-// DownloadFile::RenameAndAnnotate and DownloadFile::RenameAndUniquify have a |
-// considerable amount of functional overlap. In order to re-use test logic, we |
-// are going to introduce this value parameterized test fixture. It will take a |
-// DownloadFileRenameMethodType value which can be either of the two rename |
-// methods. |
-class DownloadFileTestWithRename |
- : public DownloadFileTest, |
- public ::testing::WithParamInterface<DownloadFileRenameMethodType> { |
- protected: |
- DownloadInterruptReason InvokeSelectedRenameMethod( |
- const base::FilePath& full_path, |
- base::FilePath* result_path_p) { |
- return InvokeRenameMethodAndWaitForCallback( |
- GetParam(), full_path, result_path_p); |
- } |
-}; |
- |
-// And now instantiate all DownloadFileTestWithRename tests using both |
-// DownloadFile rename methods. Each test of the form |
-// DownloadFileTestWithRename.<FooTest> will be instantiated once with |
-// RenameAndAnnotate as the value parameter and once with RenameAndUniquify as |
-// the value parameter. |
-INSTANTIATE_TEST_CASE_P(DownloadFile, |
- DownloadFileTestWithRename, |
- ::testing::Values(&DownloadFile::RenameAndAnnotate, |
- &DownloadFile::RenameAndUniquify)); |
- |
const char* DownloadFileTest::kTestData1 = |
"Let's write some data to the file!\n"; |
const char* DownloadFileTest::kTestData2 = "Writing more data.\n"; |
@@ -398,7 +335,7 @@ |
// Rename the file before any data is downloaded, after some has, after it all |
// has, and after it's closed. |
-TEST_P(DownloadFileTestWithRename, RenameFileFinal) { |
+TEST_F(DownloadFileTest, RenameFileFinal) { |
ASSERT_TRUE(CreateDownloadFile(0, true)); |
base::FilePath initial_path(download_file_->FullPath()); |
EXPECT_TRUE(base::PathExists(initial_path)); |
@@ -406,11 +343,12 @@ |
base::FilePath path_2(initial_path.InsertBeforeExtensionASCII("_2")); |
base::FilePath path_3(initial_path.InsertBeforeExtensionASCII("_3")); |
base::FilePath path_4(initial_path.InsertBeforeExtensionASCII("_4")); |
+ base::FilePath path_5(initial_path.InsertBeforeExtensionASCII("_5")); |
base::FilePath output_path; |
// Rename the file before downloading any data. |
EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, |
- InvokeSelectedRenameMethod(path_1, &output_path)); |
+ RenameAndUniquify(path_1, &output_path)); |
base::FilePath renamed_path = download_file_->FullPath(); |
EXPECT_EQ(path_1, renamed_path); |
EXPECT_EQ(path_1, output_path); |
@@ -425,7 +363,7 @@ |
// Rename the file after downloading some data. |
EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, |
- InvokeSelectedRenameMethod(path_2, &output_path)); |
+ RenameAndUniquify(path_2, &output_path)); |
renamed_path = download_file_->FullPath(); |
EXPECT_EQ(path_2, renamed_path); |
EXPECT_EQ(path_2, output_path); |
@@ -439,7 +377,7 @@ |
// Rename the file after downloading all the data. |
EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, |
- InvokeSelectedRenameMethod(path_3, &output_path)); |
+ RenameAndUniquify(path_3, &output_path)); |
renamed_path = download_file_->FullPath(); |
EXPECT_EQ(path_3, renamed_path); |
EXPECT_EQ(path_3, output_path); |
@@ -456,7 +394,7 @@ |
// Rename the file after downloading all the data and closing the file. |
EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, |
- InvokeSelectedRenameMethod(path_4, &output_path)); |
+ RenameAndUniquify(path_4, &output_path)); |
renamed_path = download_file_->FullPath(); |
EXPECT_EQ(path_4, renamed_path); |
EXPECT_EQ(path_4, output_path); |
@@ -469,42 +407,29 @@ |
EXPECT_TRUE(download_file_->GetHash(&hash)); |
EXPECT_EQ(kDataHash, base::HexEncode(hash.data(), hash.size())); |
- DestroyDownloadFile(0); |
-} |
- |
-// Test to make sure the rename overwrites when requested. This is separate from |
-// the above test because it only applies to RenameAndAnnotate(). |
-// RenameAndUniquify() doesn't overwrite by design. |
-TEST_F(DownloadFileTest, RenameOverwrites) { |
- ASSERT_TRUE(CreateDownloadFile(0, true)); |
- base::FilePath initial_path(download_file_->FullPath()); |
- EXPECT_TRUE(base::PathExists(initial_path)); |
- base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1")); |
- |
- ASSERT_FALSE(base::PathExists(path_1)); |
+ // Check that a rename with overwrite to an existing file succeeds. |
+ std::string file_contents; |
+ ASSERT_FALSE(base::PathExists(path_5)); |
static const char file_data[] = "xyzzy"; |
- ASSERT_EQ(static_cast<int>(sizeof(file_data)), |
- base::WriteFile(path_1, file_data, sizeof(file_data))); |
- ASSERT_TRUE(base::PathExists(path_1)); |
+ ASSERT_EQ(static_cast<int>(sizeof(file_data) - 1), |
+ base::WriteFile(path_5, file_data, sizeof(file_data) - 1)); |
+ ASSERT_TRUE(base::PathExists(path_5)); |
+ EXPECT_TRUE(base::ReadFileToString(path_5, &file_contents)); |
+ EXPECT_EQ(std::string(file_data), file_contents); |
- base::FilePath new_path; |
EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, |
- RenameAndAnnotate(path_1, &new_path)); |
- EXPECT_EQ(path_1.value(), new_path.value()); |
+ RenameAndAnnotate(path_5, &output_path)); |
+ EXPECT_EQ(path_5, output_path); |
- std::string file_contents; |
- ASSERT_TRUE(base::ReadFileToString(new_path, &file_contents)); |
+ file_contents = ""; |
+ EXPECT_TRUE(base::ReadFileToString(path_5, &file_contents)); |
EXPECT_NE(std::string(file_data), file_contents); |
- FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); |
- loop_.RunUntilIdle(); |
DestroyDownloadFile(0); |
} |
// Test to make sure the rename uniquifies if we aren't overwriting |
-// and there's a file where we're aiming. As above, not a |
-// DownloadFileTestWithRename test because this only applies to |
-// RenameAndUniquify(). |
+// and there's a file where we're aiming. |
TEST_F(DownloadFileTest, RenameUniquifies) { |
ASSERT_TRUE(CreateDownloadFile(0, true)); |
base::FilePath initial_path(download_file_->FullPath()); |
@@ -526,35 +451,16 @@ |
DestroyDownloadFile(0); |
} |
-// Test that RenameAndUniquify doesn't try to uniquify in the case where the |
-// target filename is the same as the current filename. |
-TEST_F(DownloadFileTest, RenameRecognizesSelfConflict) { |
- ASSERT_TRUE(CreateDownloadFile(0, true)); |
- base::FilePath initial_path(download_file_->FullPath()); |
- EXPECT_TRUE(base::PathExists(initial_path)); |
- |
- base::FilePath new_path; |
- EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, |
- RenameAndUniquify(initial_path, &new_path)); |
- EXPECT_TRUE(base::PathExists(initial_path)); |
- |
- FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); |
- loop_.RunUntilIdle(); |
- DestroyDownloadFile(0); |
- EXPECT_EQ(initial_path.value(), new_path.value()); |
-} |
- |
// Test to make sure we get the proper error on failure. |
-TEST_P(DownloadFileTestWithRename, RenameError) { |
+TEST_F(DownloadFileTest, RenameError) { |
ASSERT_TRUE(CreateDownloadFile(0, true)); |
base::FilePath initial_path(download_file_->FullPath()); |
// Create a subdirectory. |
- base::FilePath target_dir( |
- initial_path.DirName().Append(FILE_PATH_LITERAL("TargetDir"))); |
- ASSERT_FALSE(base::DirectoryExists(target_dir)); |
- ASSERT_TRUE(base::CreateDirectory(target_dir)); |
- base::FilePath target_path(target_dir.Append(initial_path.BaseName())); |
+ base::FilePath tempdir( |
+ initial_path.DirName().Append(FILE_PATH_LITERAL("tempdir"))); |
+ ASSERT_TRUE(base::CreateDirectory(tempdir)); |
+ base::FilePath target_path(tempdir.Append(initial_path.BaseName())); |
// Targets |
base::FilePath target_path_suffixed( |
@@ -564,13 +470,13 @@ |
// Make the directory unwritable and try to rename within it. |
{ |
- file_util::PermissionRestorer restorer(target_dir); |
- ASSERT_TRUE(file_util::MakeFileUnwritable(target_dir)); |
+ file_util::PermissionRestorer restorer(tempdir); |
+ ASSERT_TRUE(file_util::MakeFileUnwritable(tempdir)); |
// Expect nulling out of further processing. |
EXPECT_CALL(*input_stream_, RegisterCallback(IsNullCallback())); |
EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED, |
- InvokeSelectedRenameMethod(target_path, NULL)); |
+ RenameAndAnnotate(target_path, NULL)); |
EXPECT_FALSE(base::PathExists(target_path_suffixed)); |
} |
@@ -579,98 +485,6 @@ |
DestroyDownloadFile(0); |
} |
-namespace { |
- |
-void TestRenameCompletionCallback(const base::Closure& closure, |
- bool* did_run_callback, |
- DownloadInterruptReason interrupt_reason, |
- const base::FilePath& new_path) { |
- EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason); |
- *did_run_callback = true; |
- closure.Run(); |
-} |
- |
-} // namespace |
- |
-// Test that the retry logic works. This test assumes that DownloadFileImpl will |
-// post tasks to the current message loop (acting as the FILE thread) |
-// asynchronously to retry the renames. We will stuff RunLoop::QuitClosures() |
-// in between the retry tasks to stagger them and then allow the rename to |
-// succeed. |
-// |
-// Note that there is only one queue of tasks to run, and that is in the tests' |
-// base::MessageLoop::current(). Each RunLoop processes that queue until it sees |
-// a QuitClosure() targeted at itself, at which point it stops processing. |
-TEST_P(DownloadFileTestWithRename, RenameWithErrorRetry) { |
- ASSERT_TRUE(CreateDownloadFile(0, true)); |
- base::FilePath initial_path(download_file_->FullPath()); |
- |
- // Create a subdirectory. |
- base::FilePath target_dir( |
- initial_path.DirName().Append(FILE_PATH_LITERAL("TargetDir"))); |
- ASSERT_FALSE(base::DirectoryExists(target_dir)); |
- ASSERT_TRUE(base::CreateDirectory(target_dir)); |
- base::FilePath target_path(target_dir.Append(initial_path.BaseName())); |
- |
- bool did_run_callback = false; |
- |
- // Each RunLoop can be used the run the MessageLoop until the corresponding |
- // QuitClosure() is run. This one is used to produce the QuitClosure() that |
- // will be run when the entire rename operation is complete. |
- base::RunLoop succeeding_run; |
- { |
- // (Scope for the base::File or file_util::PermissionRestorer below.) |
-#if defined(OS_WIN) |
- // On Windows we test with an actual transient error, a sharing violation. |
- // The rename will fail because we are holding the file open for READ. On |
- // Posix this doesn't cause a failure. |
- base::File locked_file(initial_path, |
- base::File::FLAG_OPEN | base::File::FLAG_READ); |
- ASSERT_TRUE(locked_file.IsValid()); |
-#else |
- // Simulate a transient failure by revoking write permission for target_dir. |
- // The TestDownloadFileImpl class treats this error as transient even though |
- // DownloadFileImpl itself doesn't. |
- file_util::PermissionRestorer restore_permissions_for(target_dir); |
- ASSERT_TRUE(file_util::MakeFileUnwritable(target_dir)); |
-#endif |
- |
- // The Rename() should fail here and enqueue a retry task without invoking |
- // the completion callback. |
- ((*download_file_).*GetParam())(target_path, |
- base::Bind(&TestRenameCompletionCallback, |
- succeeding_run.QuitClosure(), |
- &did_run_callback)); |
- EXPECT_FALSE(did_run_callback); |
- |
- base::RunLoop first_failing_run; |
- // Queue the QuitClosure() on the MessageLoop now. Any tasks queued by the |
- // Rename() will be in front of the QuitClosure(). Running the message loop |
- // now causes the just the first retry task to be run. The rename still |
- // fails, so another retry task would get queued behind the QuitClosure(). |
- base::MessageLoop::current()->PostTask(FROM_HERE, |
- first_failing_run.QuitClosure()); |
- first_failing_run.Run(); |
- EXPECT_FALSE(did_run_callback); |
- |
- // Running another loop should have the same effect as the above as long as |
- // kMaxRenameRetries is greater than 2. |
- base::RunLoop second_failing_run; |
- base::MessageLoop::current()->PostTask(FROM_HERE, |
- second_failing_run.QuitClosure()); |
- second_failing_run.Run(); |
- EXPECT_FALSE(did_run_callback); |
- } |
- |
- // This time the QuitClosure from succeeding_run should get executed. |
- succeeding_run.Run(); |
- EXPECT_TRUE(did_run_callback); |
- |
- FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true); |
- loop_.RunUntilIdle(); |
- DestroyDownloadFile(0); |
-} |
- |
// Various tests of the StreamActive method. |
TEST_F(DownloadFileTest, StreamEmptySuccess) { |
ASSERT_TRUE(CreateDownloadFile(0, true)); |