OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/file_util.h" | 5 #include "base/file_util.h" |
6 #include "base/files/file.h" | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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, | |
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. | |
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 | |
Randy Smith (Not in Mondays)
2014/06/12 22:10:30
nit: in between.
asanka
2014/06/17 21:40:57
Done.
| |
585 // succeed. | |
Randy Smith (Not in Mondays)
2014/06/12 22:10:30
Suggestion: I had a hard time groking the threadin
asanka
2014/06/17 21:40:57
Added comments as suggested. Hopefully it's more r
| |
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 Loading... | |
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 |
OLD | NEW |