| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "storage/browser/fileapi/recursive_operation_delegate.h" | 5 #include "storage/browser/fileapi/recursive_operation_delegate.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 48 weak_factory_(this) {} | 48 weak_factory_(this) {} |
| 49 ~LoggingRecursiveOperation() override {} | 49 ~LoggingRecursiveOperation() override {} |
| 50 | 50 |
| 51 const std::vector<LogEntry>& log_entries() const { return log_entries_; } | 51 const std::vector<LogEntry>& log_entries() const { return log_entries_; } |
| 52 | 52 |
| 53 // RecursiveOperationDelegate overrides. | 53 // RecursiveOperationDelegate overrides. |
| 54 void Run() override { NOTREACHED(); } | 54 void Run() override { NOTREACHED(); } |
| 55 | 55 |
| 56 void RunRecursively() override { StartRecursiveOperation(root_, callback_); } | 56 void RunRecursively() override { StartRecursiveOperation(root_, callback_); } |
| 57 | 57 |
| 58 void RunRecursivelyWithIgnoringError(const ErrorCallback& error_callback) { |
| 59 StartRecursiveOperationWithIgnoringError(root_, error_callback, callback_); |
| 60 } |
| 61 |
| 58 void ProcessFile(const FileSystemURL& url, | 62 void ProcessFile(const FileSystemURL& url, |
| 59 const StatusCallback& callback) override { | 63 const StatusCallback& callback) override { |
| 60 RecordLogEntry(LogEntry::PROCESS_FILE, url); | 64 RecordLogEntry(LogEntry::PROCESS_FILE, url); |
| 65 |
| 66 if (error_url_.is_valid() && error_url_ == url) { |
| 67 callback.Run(base::File::FILE_ERROR_FAILED); |
| 68 return; |
| 69 } |
| 70 |
| 61 operation_runner()->GetMetadata( | 71 operation_runner()->GetMetadata( |
| 62 url, | 72 url, |
| 63 base::Bind(&LoggingRecursiveOperation::DidGetMetadata, | 73 base::Bind(&LoggingRecursiveOperation::DidGetMetadata, |
| 64 weak_factory_.GetWeakPtr(), callback)); | 74 weak_factory_.GetWeakPtr(), callback)); |
| 65 } | 75 } |
| 66 | 76 |
| 67 void ProcessDirectory(const FileSystemURL& url, | 77 void ProcessDirectory(const FileSystemURL& url, |
| 68 const StatusCallback& callback) override { | 78 const StatusCallback& callback) override { |
| 69 RecordLogEntry(LogEntry::PROCESS_DIRECTORY, url); | 79 RecordLogEntry(LogEntry::PROCESS_DIRECTORY, url); |
| 70 callback.Run(base::File::FILE_OK); | 80 callback.Run(base::File::FILE_OK); |
| 71 } | 81 } |
| 72 | 82 |
| 73 void PostProcessDirectory(const FileSystemURL& url, | 83 void PostProcessDirectory(const FileSystemURL& url, |
| 74 const StatusCallback& callback) override { | 84 const StatusCallback& callback) override { |
| 75 RecordLogEntry(LogEntry::POST_PROCESS_DIRECTORY, url); | 85 RecordLogEntry(LogEntry::POST_PROCESS_DIRECTORY, url); |
| 76 callback.Run(base::File::FILE_OK); | 86 callback.Run(base::File::FILE_OK); |
| 77 } | 87 } |
| 78 | 88 |
| 89 void SetEntryToFail(const FileSystemURL& url) { error_url_ = url; } |
| 90 |
| 79 private: | 91 private: |
| 80 void RecordLogEntry(LogEntry::Type type, const FileSystemURL& url) { | 92 void RecordLogEntry(LogEntry::Type type, const FileSystemURL& url) { |
| 81 LogEntry entry; | 93 LogEntry entry; |
| 82 entry.type = type; | 94 entry.type = type; |
| 83 entry.url = url; | 95 entry.url = url; |
| 84 log_entries_.push_back(entry); | 96 log_entries_.push_back(entry); |
| 85 } | 97 } |
| 86 | 98 |
| 87 void DidGetMetadata(const StatusCallback& callback, | 99 void DidGetMetadata(const StatusCallback& callback, |
| 88 base::File::Error result, | 100 base::File::Error result, |
| 89 const base::File::Info& file_info) { | 101 const base::File::Info& file_info) { |
| 90 if (result != base::File::FILE_OK) { | 102 if (result != base::File::FILE_OK) { |
| 91 callback.Run(result); | 103 callback.Run(result); |
| 92 return; | 104 return; |
| 93 } | 105 } |
| 94 | 106 |
| 95 callback.Run(file_info.is_directory ? | 107 callback.Run(file_info.is_directory ? |
| 96 base::File::FILE_ERROR_NOT_A_FILE : | 108 base::File::FILE_ERROR_NOT_A_FILE : |
| 97 base::File::FILE_OK); | 109 base::File::FILE_OK); |
| 98 } | 110 } |
| 99 | 111 |
| 100 FileSystemURL root_; | 112 FileSystemURL root_; |
| 101 StatusCallback callback_; | 113 StatusCallback callback_; |
| 102 std::vector<LogEntry> log_entries_; | 114 std::vector<LogEntry> log_entries_; |
| 115 FileSystemURL error_url_; |
| 103 | 116 |
| 104 base::WeakPtrFactory<LoggingRecursiveOperation> weak_factory_; | 117 base::WeakPtrFactory<LoggingRecursiveOperation> weak_factory_; |
| 105 DISALLOW_COPY_AND_ASSIGN(LoggingRecursiveOperation); | 118 DISALLOW_COPY_AND_ASSIGN(LoggingRecursiveOperation); |
| 106 }; | 119 }; |
| 107 | 120 |
| 108 void ReportStatus(base::File::Error* out_error, | 121 void ReportStatus(base::File::Error* out_error, |
| 109 base::File::Error error) { | 122 base::File::Error error) { |
| 110 DCHECK(out_error); | 123 DCHECK(out_error); |
| 111 *out_error = error; | 124 *out_error = error; |
| 112 } | 125 } |
| 113 | 126 |
| 127 typedef std::pair<FileSystemURL, base::File::Error> ErrorEntry; |
| 128 |
| 129 void ReportError(std::vector<ErrorEntry>* out_errors, |
| 130 const FileSystemURL& url, |
| 131 base::File::Error error) { |
| 132 DCHECK(out_errors); |
| 133 out_errors->push_back(std::make_pair(url, error)); |
| 134 } |
| 135 |
| 114 // To test the Cancel() during operation, calls Cancel() of |operation| | 136 // To test the Cancel() during operation, calls Cancel() of |operation| |
| 115 // after |counter| times message posting. | 137 // after |counter| times message posting. |
| 116 void CallCancelLater(storage::RecursiveOperationDelegate* operation, | 138 void CallCancelLater(storage::RecursiveOperationDelegate* operation, |
| 117 int counter) { | 139 int counter) { |
| 118 if (counter > 0) { | 140 if (counter > 0) { |
| 119 base::ThreadTaskRunnerHandle::Get()->PostTask( | 141 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 120 FROM_HERE, | 142 FROM_HERE, |
| 121 base::Bind(&CallCancelLater, base::Unretained(operation), counter - 1)); | 143 base::Bind(&CallCancelLater, base::Unretained(operation), counter - 1)); |
| 122 return; | 144 return; |
| 123 } | 145 } |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 269 context->file_system_context(), src_root, | 291 context->file_system_context(), src_root, |
| 270 base::Bind(&ReportStatus, &error))); | 292 base::Bind(&ReportStatus, &error))); |
| 271 operation->RunRecursively(); | 293 operation->RunRecursively(); |
| 272 | 294 |
| 273 // Invoke Cancel(), after 5 times message posting. | 295 // Invoke Cancel(), after 5 times message posting. |
| 274 CallCancelLater(operation.get(), 5); | 296 CallCancelLater(operation.get(), 5); |
| 275 base::RunLoop().RunUntilIdle(); | 297 base::RunLoop().RunUntilIdle(); |
| 276 ASSERT_EQ(base::File::FILE_ERROR_ABORT, error); | 298 ASSERT_EQ(base::File::FILE_ERROR_ABORT, error); |
| 277 } | 299 } |
| 278 | 300 |
| 301 TEST_F(RecursiveOperationDelegateTest, AbortWithError) { |
| 302 FileSystemURL src_root(CreateDirectory("src")); |
| 303 FileSystemURL src_dir1(CreateDirectory("src/dir1")); |
| 304 FileSystemURL src_file1(CreateFile("src/file1")); |
| 305 FileSystemURL src_file2(CreateFile("src/dir1/file2")); |
| 306 FileSystemURL src_file3(CreateFile("src/dir1/file3")); |
| 307 |
| 308 base::File::Error error = base::File::FILE_ERROR_FAILED; |
| 309 scoped_ptr<FileSystemOperationContext> context = NewContext(); |
| 310 scoped_ptr<LoggingRecursiveOperation> operation( |
| 311 new LoggingRecursiveOperation(context->file_system_context(), src_root, |
| 312 base::Bind(&ReportStatus, &error))); |
| 313 operation->SetEntryToFail(src_file1); |
| 314 operation->RunRecursively(); |
| 315 base::RunLoop().RunUntilIdle(); |
| 316 |
| 317 ASSERT_EQ(base::File::FILE_ERROR_FAILED, error); |
| 318 |
| 319 // Confirm that operation has been aborted in the middle. |
| 320 const std::vector<LoggingRecursiveOperation::LogEntry>& log_entries = |
| 321 operation->log_entries(); |
| 322 ASSERT_EQ(3U, log_entries.size()); |
| 323 |
| 324 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE, |
| 325 log_entries[0].type); |
| 326 EXPECT_EQ(src_root, log_entries[0].url); |
| 327 |
| 328 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_DIRECTORY, |
| 329 log_entries[1].type); |
| 330 EXPECT_EQ(src_root, log_entries[1].url); |
| 331 |
| 332 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE, |
| 333 log_entries[2].type); |
| 334 EXPECT_EQ(src_file1, log_entries[2].url); |
| 335 } |
| 336 |
| 337 TEST_F(RecursiveOperationDelegateTest, ContinueWithError) { |
| 338 FileSystemURL src_root(CreateDirectory("src")); |
| 339 FileSystemURL src_dir1(CreateDirectory("src/dir1")); |
| 340 FileSystemURL src_file1(CreateFile("src/file1")); |
| 341 FileSystemURL src_file2(CreateFile("src/dir1/file2")); |
| 342 FileSystemURL src_file3(CreateFile("src/dir1/file3")); |
| 343 |
| 344 base::File::Error error = base::File::FILE_ERROR_FAILED; |
| 345 std::vector<ErrorEntry> errors; |
| 346 scoped_ptr<FileSystemOperationContext> context = NewContext(); |
| 347 scoped_ptr<LoggingRecursiveOperation> operation( |
| 348 new LoggingRecursiveOperation(context->file_system_context(), src_root, |
| 349 base::Bind(&ReportStatus, &error))); |
| 350 operation->SetEntryToFail(src_file1); |
| 351 operation->RunRecursivelyWithIgnoringError(base::Bind(&ReportError, &errors)); |
| 352 base::RunLoop().RunUntilIdle(); |
| 353 |
| 354 // Error code should be base::File::FILE_ERROR_FAILED. |
| 355 ASSERT_EQ(base::File::FILE_ERROR_FAILED, error); |
| 356 |
| 357 // Error callback should be called. |
| 358 ASSERT_EQ(1U, errors.size()); |
| 359 ASSERT_EQ(src_file1, errors[0].first); |
| 360 ASSERT_EQ(base::File::FILE_ERROR_FAILED, errors[0].second); |
| 361 |
| 362 // Confirm that operation continues after the error. |
| 363 const std::vector<LoggingRecursiveOperation::LogEntry>& log_entries = |
| 364 operation->log_entries(); |
| 365 ASSERT_EQ(8U, log_entries.size()); |
| 366 |
| 367 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE, |
| 368 log_entries[0].type); |
| 369 EXPECT_EQ(src_root, log_entries[0].url); |
| 370 |
| 371 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_DIRECTORY, |
| 372 log_entries[1].type); |
| 373 EXPECT_EQ(src_root, log_entries[1].url); |
| 374 |
| 375 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE, |
| 376 log_entries[2].type); |
| 377 EXPECT_EQ(src_file1, log_entries[2].url); |
| 378 |
| 379 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_DIRECTORY, |
| 380 log_entries[3].type); |
| 381 EXPECT_EQ(src_dir1, log_entries[3].url); |
| 382 |
| 383 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE, |
| 384 log_entries[4].type); |
| 385 EXPECT_EQ(src_file3, log_entries[4].url); |
| 386 |
| 387 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE, |
| 388 log_entries[5].type); |
| 389 EXPECT_EQ(src_file2, log_entries[5].url); |
| 390 |
| 391 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::POST_PROCESS_DIRECTORY, |
| 392 log_entries[6].type); |
| 393 EXPECT_EQ(src_dir1, log_entries[6].url); |
| 394 |
| 395 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::POST_PROCESS_DIRECTORY, |
| 396 log_entries[7].type); |
| 397 EXPECT_EQ(src_root, log_entries[7].url); |
| 398 } |
| 399 |
| 279 } // namespace content | 400 } // namespace content |
| OLD | NEW |