Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / browser / fileapi / copy_or_move_operation_delegate_unittest.cc
blobf16a805b5eef1b950d24d24a50fcfbd037090fb3
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
3 // found in the LICENSE file.
5 #include <map>
6 #include <queue>
8 #include "base/basictypes.h"
9 #include "base/bind.h"
10 #include "base/file_util.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/run_loop.h"
14 #include "base/stl_util.h"
15 #include "content/browser/quota/mock_quota_manager.h"
16 #include "content/browser/quota/mock_quota_manager_proxy.h"
17 #include "content/public/test/async_file_test_helper.h"
18 #include "content/public/test/test_file_system_backend.h"
19 #include "content/public/test/test_file_system_context.h"
20 #include "content/test/fileapi_test_file_set.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 #include "webkit/browser/blob/file_stream_reader.h"
23 #include "webkit/browser/fileapi/copy_or_move_file_validator.h"
24 #include "webkit/browser/fileapi/copy_or_move_operation_delegate.h"
25 #include "webkit/browser/fileapi/file_stream_writer.h"
26 #include "webkit/browser/fileapi/file_system_backend.h"
27 #include "webkit/browser/fileapi/file_system_context.h"
28 #include "webkit/browser/fileapi/file_system_operation.h"
29 #include "webkit/browser/fileapi/file_system_url.h"
30 #include "webkit/browser/quota/quota_manager.h"
31 #include "webkit/common/fileapi/file_system_util.h"
33 using content::AsyncFileTestHelper;
34 using storage::CopyOrMoveOperationDelegate;
35 using storage::FileStreamWriter;
36 using storage::FileSystemOperation;
37 using storage::FileSystemURL;
39 namespace content {
41 typedef storage::FileSystemOperation::FileEntryList FileEntryList;
43 namespace {
45 void ExpectOk(const GURL& origin_url,
46 const std::string& name,
47 base::File::Error error) {
48 ASSERT_EQ(base::File::FILE_OK, error);
51 class TestValidatorFactory : public storage::CopyOrMoveFileValidatorFactory {
52 public:
53 // A factory that creates validators that accept everything or nothing.
54 TestValidatorFactory() {}
55 virtual ~TestValidatorFactory() {}
57 virtual storage::CopyOrMoveFileValidator* CreateCopyOrMoveFileValidator(
58 const FileSystemURL& /*src_url*/,
59 const base::FilePath& /*platform_path*/) OVERRIDE {
60 // Move arg management to TestValidator?
61 return new TestValidator(true, true, std::string("2"));
64 private:
65 class TestValidator : public storage::CopyOrMoveFileValidator {
66 public:
67 explicit TestValidator(bool pre_copy_valid,
68 bool post_copy_valid,
69 const std::string& reject_string)
70 : result_(pre_copy_valid ? base::File::FILE_OK :
71 base::File::FILE_ERROR_SECURITY),
72 write_result_(post_copy_valid ? base::File::FILE_OK :
73 base::File::FILE_ERROR_SECURITY),
74 reject_string_(reject_string) {
76 virtual ~TestValidator() {}
78 virtual void StartPreWriteValidation(
79 const ResultCallback& result_callback) OVERRIDE {
80 // Post the result since a real validator must do work asynchronously.
81 base::MessageLoop::current()->PostTask(
82 FROM_HERE, base::Bind(result_callback, result_));
85 virtual void StartPostWriteValidation(
86 const base::FilePath& dest_platform_path,
87 const ResultCallback& result_callback) OVERRIDE {
88 base::File::Error result = write_result_;
89 std::string unsafe = dest_platform_path.BaseName().AsUTF8Unsafe();
90 if (unsafe.find(reject_string_) != std::string::npos) {
91 result = base::File::FILE_ERROR_SECURITY;
93 // Post the result since a real validator must do work asynchronously.
94 base::MessageLoop::current()->PostTask(
95 FROM_HERE, base::Bind(result_callback, result));
98 private:
99 base::File::Error result_;
100 base::File::Error write_result_;
101 std::string reject_string_;
103 DISALLOW_COPY_AND_ASSIGN(TestValidator);
107 // Records CopyProgressCallback invocations.
108 struct ProgressRecord {
109 storage::FileSystemOperation::CopyProgressType type;
110 FileSystemURL source_url;
111 FileSystemURL dest_url;
112 int64 size;
115 void RecordProgressCallback(std::vector<ProgressRecord>* records,
116 storage::FileSystemOperation::CopyProgressType type,
117 const FileSystemURL& source_url,
118 const FileSystemURL& dest_url,
119 int64 size) {
120 ProgressRecord record;
121 record.type = type;
122 record.source_url = source_url;
123 record.dest_url = dest_url;
124 record.size = size;
125 records->push_back(record);
128 void RecordFileProgressCallback(std::vector<int64>* records,
129 int64 progress) {
130 records->push_back(progress);
133 void AssignAndQuit(base::RunLoop* run_loop,
134 base::File::Error* result_out,
135 base::File::Error result) {
136 *result_out = result;
137 run_loop->Quit();
140 class ScopedThreadStopper {
141 public:
142 ScopedThreadStopper(base::Thread* thread) : thread_(thread) {
145 ~ScopedThreadStopper() {
146 if (thread_) {
147 // Give another chance for deleted streams to perform Close.
148 base::RunLoop run_loop;
149 thread_->message_loop_proxy()->PostTaskAndReply(
150 FROM_HERE, base::Bind(&base::DoNothing), run_loop.QuitClosure());
151 run_loop.Run();
152 thread_->Stop();
156 bool is_valid() const { return thread_; }
158 private:
159 base::Thread* thread_;
160 DISALLOW_COPY_AND_ASSIGN(ScopedThreadStopper);
163 } // namespace
165 class CopyOrMoveOperationTestHelper {
166 public:
167 CopyOrMoveOperationTestHelper(const GURL& origin,
168 storage::FileSystemType src_type,
169 storage::FileSystemType dest_type)
170 : origin_(origin), src_type_(src_type), dest_type_(dest_type) {}
172 ~CopyOrMoveOperationTestHelper() {
173 file_system_context_ = NULL;
174 quota_manager_proxy_->SimulateQuotaManagerDestroyed();
175 quota_manager_ = NULL;
176 quota_manager_proxy_ = NULL;
177 base::RunLoop().RunUntilIdle();
180 void SetUp() {
181 SetUp(true, true);
184 void SetUpNoValidator() {
185 SetUp(true, false);
188 void SetUp(bool require_copy_or_move_validator,
189 bool init_copy_or_move_validator) {
190 ASSERT_TRUE(base_.CreateUniqueTempDir());
191 base::FilePath base_dir = base_.path();
192 quota_manager_ =
193 new MockQuotaManager(false /* is_incognito */,
194 base_dir,
195 base::MessageLoopProxy::current().get(),
196 base::MessageLoopProxy::current().get(),
197 NULL /* special storage policy */);
198 quota_manager_proxy_ = new MockQuotaManagerProxy(
199 quota_manager_.get(), base::MessageLoopProxy::current().get());
200 file_system_context_ =
201 CreateFileSystemContextForTesting(quota_manager_proxy_.get(), base_dir);
203 // Prepare the origin's root directory.
204 storage::FileSystemBackend* backend =
205 file_system_context_->GetFileSystemBackend(src_type_);
206 backend->ResolveURL(
207 FileSystemURL::CreateForTest(origin_, src_type_, base::FilePath()),
208 storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
209 base::Bind(&ExpectOk));
210 backend = file_system_context_->GetFileSystemBackend(dest_type_);
211 if (dest_type_ == storage::kFileSystemTypeTest) {
212 TestFileSystemBackend* test_backend =
213 static_cast<TestFileSystemBackend*>(backend);
214 scoped_ptr<storage::CopyOrMoveFileValidatorFactory> factory(
215 new TestValidatorFactory);
216 test_backend->set_require_copy_or_move_validator(
217 require_copy_or_move_validator);
218 if (init_copy_or_move_validator)
219 test_backend->InitializeCopyOrMoveFileValidatorFactory(factory.Pass());
221 backend->ResolveURL(
222 FileSystemURL::CreateForTest(origin_, dest_type_, base::FilePath()),
223 storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
224 base::Bind(&ExpectOk));
225 base::RunLoop().RunUntilIdle();
227 // Grant relatively big quota initially.
228 quota_manager_->SetQuota(
229 origin_,
230 storage::FileSystemTypeToQuotaStorageType(src_type_),
231 1024 * 1024);
232 quota_manager_->SetQuota(
233 origin_,
234 storage::FileSystemTypeToQuotaStorageType(dest_type_),
235 1024 * 1024);
238 int64 GetSourceUsage() {
239 int64 usage = 0;
240 GetUsageAndQuota(src_type_, &usage, NULL);
241 return usage;
244 int64 GetDestUsage() {
245 int64 usage = 0;
246 GetUsageAndQuota(dest_type_, &usage, NULL);
247 return usage;
250 FileSystemURL SourceURL(const std::string& path) {
251 return file_system_context_->CreateCrackedFileSystemURL(
252 origin_, src_type_, base::FilePath::FromUTF8Unsafe(path));
255 FileSystemURL DestURL(const std::string& path) {
256 return file_system_context_->CreateCrackedFileSystemURL(
257 origin_, dest_type_, base::FilePath::FromUTF8Unsafe(path));
260 base::File::Error Copy(const FileSystemURL& src,
261 const FileSystemURL& dest) {
262 return AsyncFileTestHelper::Copy(file_system_context_.get(), src, dest);
265 base::File::Error CopyWithProgress(
266 const FileSystemURL& src,
267 const FileSystemURL& dest,
268 const AsyncFileTestHelper::CopyProgressCallback& progress_callback) {
269 return AsyncFileTestHelper::CopyWithProgress(
270 file_system_context_.get(), src, dest, progress_callback);
273 base::File::Error Move(const FileSystemURL& src,
274 const FileSystemURL& dest) {
275 return AsyncFileTestHelper::Move(file_system_context_.get(), src, dest);
278 base::File::Error SetUpTestCaseFiles(
279 const FileSystemURL& root,
280 const FileSystemTestCaseRecord* const test_cases,
281 size_t test_case_size) {
282 base::File::Error result = base::File::FILE_ERROR_FAILED;
283 for (size_t i = 0; i < test_case_size; ++i) {
284 const FileSystemTestCaseRecord& test_case = test_cases[i];
285 FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL(
286 root.origin(),
287 root.mount_type(),
288 root.virtual_path().Append(test_case.path));
289 if (test_case.is_directory)
290 result = CreateDirectory(url);
291 else
292 result = CreateFile(url, test_case.data_file_size);
293 EXPECT_EQ(base::File::FILE_OK, result) << url.DebugString();
294 if (result != base::File::FILE_OK)
295 return result;
297 return result;
300 void VerifyTestCaseFiles(
301 const FileSystemURL& root,
302 const FileSystemTestCaseRecord* const test_cases,
303 size_t test_case_size) {
304 std::map<base::FilePath, const FileSystemTestCaseRecord*> test_case_map;
305 for (size_t i = 0; i < test_case_size; ++i) {
306 test_case_map[
307 base::FilePath(test_cases[i].path).NormalizePathSeparators()] =
308 &test_cases[i];
311 std::queue<FileSystemURL> directories;
312 FileEntryList entries;
313 directories.push(root);
314 while (!directories.empty()) {
315 FileSystemURL dir = directories.front();
316 directories.pop();
317 ASSERT_EQ(base::File::FILE_OK, ReadDirectory(dir, &entries));
318 for (size_t i = 0; i < entries.size(); ++i) {
319 FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL(
320 dir.origin(),
321 dir.mount_type(),
322 dir.virtual_path().Append(entries[i].name));
323 base::FilePath relative;
324 root.virtual_path().AppendRelativePath(url.virtual_path(), &relative);
325 relative = relative.NormalizePathSeparators();
326 ASSERT_TRUE(ContainsKey(test_case_map, relative));
327 if (entries[i].is_directory) {
328 EXPECT_TRUE(test_case_map[relative]->is_directory);
329 directories.push(url);
330 } else {
331 EXPECT_FALSE(test_case_map[relative]->is_directory);
332 EXPECT_TRUE(FileExists(url, test_case_map[relative]->data_file_size));
334 test_case_map.erase(relative);
337 EXPECT_TRUE(test_case_map.empty());
338 std::map<base::FilePath,
339 const FileSystemTestCaseRecord*>::const_iterator it;
340 for (it = test_case_map.begin(); it != test_case_map.end(); ++it) {
341 LOG(ERROR) << "Extra entry: " << it->first.LossyDisplayName();
345 base::File::Error ReadDirectory(const FileSystemURL& url,
346 FileEntryList* entries) {
347 return AsyncFileTestHelper::ReadDirectory(
348 file_system_context_.get(), url, entries);
351 base::File::Error CreateDirectory(const FileSystemURL& url) {
352 return AsyncFileTestHelper::CreateDirectory(file_system_context_.get(),
353 url);
356 base::File::Error CreateFile(const FileSystemURL& url, size_t size) {
357 base::File::Error result =
358 AsyncFileTestHelper::CreateFile(file_system_context_.get(), url);
359 if (result != base::File::FILE_OK)
360 return result;
361 return AsyncFileTestHelper::TruncateFile(
362 file_system_context_.get(), url, size);
365 bool FileExists(const FileSystemURL& url, int64 expected_size) {
366 return AsyncFileTestHelper::FileExists(
367 file_system_context_.get(), url, expected_size);
370 bool DirectoryExists(const FileSystemURL& url) {
371 return AsyncFileTestHelper::DirectoryExists(file_system_context_.get(),
372 url);
375 private:
376 void GetUsageAndQuota(storage::FileSystemType type,
377 int64* usage,
378 int64* quota) {
379 storage::QuotaStatusCode status = AsyncFileTestHelper::GetUsageAndQuota(
380 quota_manager_.get(), origin_, type, usage, quota);
381 ASSERT_EQ(storage::kQuotaStatusOk, status);
384 private:
385 base::ScopedTempDir base_;
387 const GURL origin_;
388 const storage::FileSystemType src_type_;
389 const storage::FileSystemType dest_type_;
391 base::MessageLoopForIO message_loop_;
392 scoped_refptr<storage::FileSystemContext> file_system_context_;
393 scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
394 scoped_refptr<MockQuotaManager> quota_manager_;
396 DISALLOW_COPY_AND_ASSIGN(CopyOrMoveOperationTestHelper);
399 TEST(LocalFileSystemCopyOrMoveOperationTest, CopySingleFile) {
400 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
401 storage::kFileSystemTypeTemporary,
402 storage::kFileSystemTypePersistent);
403 helper.SetUp();
405 FileSystemURL src = helper.SourceURL("a");
406 FileSystemURL dest = helper.DestURL("b");
407 int64 src_initial_usage = helper.GetSourceUsage();
408 int64 dest_initial_usage = helper.GetDestUsage();
410 // Set up a source file.
411 ASSERT_EQ(base::File::FILE_OK, helper.CreateFile(src, 10));
412 int64 src_increase = helper.GetSourceUsage() - src_initial_usage;
414 // Copy it.
415 ASSERT_EQ(base::File::FILE_OK, helper.Copy(src, dest));
417 // Verify.
418 ASSERT_TRUE(helper.FileExists(src, 10));
419 ASSERT_TRUE(helper.FileExists(dest, 10));
421 int64 src_new_usage = helper.GetSourceUsage();
422 ASSERT_EQ(src_initial_usage + src_increase, src_new_usage);
424 int64 dest_increase = helper.GetDestUsage() - dest_initial_usage;
425 ASSERT_EQ(src_increase, dest_increase);
428 TEST(LocalFileSystemCopyOrMoveOperationTest, MoveSingleFile) {
429 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
430 storage::kFileSystemTypeTemporary,
431 storage::kFileSystemTypePersistent);
432 helper.SetUp();
434 FileSystemURL src = helper.SourceURL("a");
435 FileSystemURL dest = helper.DestURL("b");
436 int64 src_initial_usage = helper.GetSourceUsage();
437 int64 dest_initial_usage = helper.GetDestUsage();
439 // Set up a source file.
440 ASSERT_EQ(base::File::FILE_OK, helper.CreateFile(src, 10));
441 int64 src_increase = helper.GetSourceUsage() - src_initial_usage;
443 // Move it.
444 ASSERT_EQ(base::File::FILE_OK, helper.Move(src, dest));
446 // Verify.
447 ASSERT_FALSE(helper.FileExists(src, AsyncFileTestHelper::kDontCheckSize));
448 ASSERT_TRUE(helper.FileExists(dest, 10));
450 int64 src_new_usage = helper.GetSourceUsage();
451 ASSERT_EQ(src_initial_usage, src_new_usage);
453 int64 dest_increase = helper.GetDestUsage() - dest_initial_usage;
454 ASSERT_EQ(src_increase, dest_increase);
457 TEST(LocalFileSystemCopyOrMoveOperationTest, CopySingleDirectory) {
458 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
459 storage::kFileSystemTypeTemporary,
460 storage::kFileSystemTypePersistent);
461 helper.SetUp();
463 FileSystemURL src = helper.SourceURL("a");
464 FileSystemURL dest = helper.DestURL("b");
465 int64 src_initial_usage = helper.GetSourceUsage();
466 int64 dest_initial_usage = helper.GetDestUsage();
468 // Set up a source directory.
469 ASSERT_EQ(base::File::FILE_OK, helper.CreateDirectory(src));
470 int64 src_increase = helper.GetSourceUsage() - src_initial_usage;
472 // Copy it.
473 ASSERT_EQ(base::File::FILE_OK, helper.Copy(src, dest));
475 // Verify.
476 ASSERT_TRUE(helper.DirectoryExists(src));
477 ASSERT_TRUE(helper.DirectoryExists(dest));
479 int64 src_new_usage = helper.GetSourceUsage();
480 ASSERT_EQ(src_initial_usage + src_increase, src_new_usage);
482 int64 dest_increase = helper.GetDestUsage() - dest_initial_usage;
483 ASSERT_EQ(src_increase, dest_increase);
486 TEST(LocalFileSystemCopyOrMoveOperationTest, MoveSingleDirectory) {
487 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
488 storage::kFileSystemTypeTemporary,
489 storage::kFileSystemTypePersistent);
490 helper.SetUp();
492 FileSystemURL src = helper.SourceURL("a");
493 FileSystemURL dest = helper.DestURL("b");
494 int64 src_initial_usage = helper.GetSourceUsage();
495 int64 dest_initial_usage = helper.GetDestUsage();
497 // Set up a source directory.
498 ASSERT_EQ(base::File::FILE_OK, helper.CreateDirectory(src));
499 int64 src_increase = helper.GetSourceUsage() - src_initial_usage;
501 // Move it.
502 ASSERT_EQ(base::File::FILE_OK, helper.Move(src, dest));
504 // Verify.
505 ASSERT_FALSE(helper.DirectoryExists(src));
506 ASSERT_TRUE(helper.DirectoryExists(dest));
508 int64 src_new_usage = helper.GetSourceUsage();
509 ASSERT_EQ(src_initial_usage, src_new_usage);
511 int64 dest_increase = helper.GetDestUsage() - dest_initial_usage;
512 ASSERT_EQ(src_increase, dest_increase);
515 TEST(LocalFileSystemCopyOrMoveOperationTest, CopyDirectory) {
516 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
517 storage::kFileSystemTypeTemporary,
518 storage::kFileSystemTypePersistent);
519 helper.SetUp();
521 FileSystemURL src = helper.SourceURL("a");
522 FileSystemURL dest = helper.DestURL("b");
523 int64 src_initial_usage = helper.GetSourceUsage();
524 int64 dest_initial_usage = helper.GetDestUsage();
526 // Set up a source directory.
527 ASSERT_EQ(base::File::FILE_OK, helper.CreateDirectory(src));
528 ASSERT_EQ(base::File::FILE_OK,
529 helper.SetUpTestCaseFiles(src,
530 kRegularFileSystemTestCases,
531 kRegularFileSystemTestCaseSize));
532 int64 src_increase = helper.GetSourceUsage() - src_initial_usage;
534 // Copy it.
535 ASSERT_EQ(base::File::FILE_OK,
536 helper.CopyWithProgress(
537 src, dest,
538 AsyncFileTestHelper::CopyProgressCallback()));
540 // Verify.
541 ASSERT_TRUE(helper.DirectoryExists(src));
542 ASSERT_TRUE(helper.DirectoryExists(dest));
544 helper.VerifyTestCaseFiles(dest,
545 kRegularFileSystemTestCases,
546 kRegularFileSystemTestCaseSize);
548 int64 src_new_usage = helper.GetSourceUsage();
549 ASSERT_EQ(src_initial_usage + src_increase, src_new_usage);
551 int64 dest_increase = helper.GetDestUsage() - dest_initial_usage;
552 ASSERT_EQ(src_increase, dest_increase);
555 TEST(LocalFileSystemCopyOrMoveOperationTest, MoveDirectory) {
556 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
557 storage::kFileSystemTypeTemporary,
558 storage::kFileSystemTypePersistent);
559 helper.SetUp();
561 FileSystemURL src = helper.SourceURL("a");
562 FileSystemURL dest = helper.DestURL("b");
563 int64 src_initial_usage = helper.GetSourceUsage();
564 int64 dest_initial_usage = helper.GetDestUsage();
566 // Set up a source directory.
567 ASSERT_EQ(base::File::FILE_OK, helper.CreateDirectory(src));
568 ASSERT_EQ(base::File::FILE_OK,
569 helper.SetUpTestCaseFiles(src,
570 kRegularFileSystemTestCases,
571 kRegularFileSystemTestCaseSize));
572 int64 src_increase = helper.GetSourceUsage() - src_initial_usage;
574 // Move it.
575 ASSERT_EQ(base::File::FILE_OK, helper.Move(src, dest));
577 // Verify.
578 ASSERT_FALSE(helper.DirectoryExists(src));
579 ASSERT_TRUE(helper.DirectoryExists(dest));
581 helper.VerifyTestCaseFiles(dest,
582 kRegularFileSystemTestCases,
583 kRegularFileSystemTestCaseSize);
585 int64 src_new_usage = helper.GetSourceUsage();
586 ASSERT_EQ(src_initial_usage, src_new_usage);
588 int64 dest_increase = helper.GetDestUsage() - dest_initial_usage;
589 ASSERT_EQ(src_increase, dest_increase);
592 TEST(LocalFileSystemCopyOrMoveOperationTest,
593 MoveDirectoryFailPostWriteValidation) {
594 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
595 storage::kFileSystemTypeTemporary,
596 storage::kFileSystemTypeTest);
597 helper.SetUp();
599 FileSystemURL src = helper.SourceURL("a");
600 FileSystemURL dest = helper.DestURL("b");
602 // Set up a source directory.
603 ASSERT_EQ(base::File::FILE_OK, helper.CreateDirectory(src));
604 ASSERT_EQ(base::File::FILE_OK,
605 helper.SetUpTestCaseFiles(src,
606 kRegularFileSystemTestCases,
607 kRegularFileSystemTestCaseSize));
609 // Move it.
610 helper.Move(src, dest);
612 // Verify.
613 ASSERT_TRUE(helper.DirectoryExists(src));
614 ASSERT_TRUE(helper.DirectoryExists(dest));
616 FileSystemTestCaseRecord kMoveDirResultCases[] = {
617 {false, FILE_PATH_LITERAL("file 0"), 38},
618 {false, FILE_PATH_LITERAL("file 3"), 0},
621 helper.VerifyTestCaseFiles(dest,
622 kMoveDirResultCases,
623 arraysize(kMoveDirResultCases));
626 TEST(LocalFileSystemCopyOrMoveOperationTest, CopySingleFileNoValidator) {
627 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
628 storage::kFileSystemTypeTemporary,
629 storage::kFileSystemTypeTest);
630 helper.SetUpNoValidator();
632 FileSystemURL src = helper.SourceURL("a");
633 FileSystemURL dest = helper.DestURL("b");
635 // Set up a source file.
636 ASSERT_EQ(base::File::FILE_OK, helper.CreateFile(src, 10));
638 // The copy attempt should fail with a security error -- getting
639 // the factory returns a security error, and the copy operation must
640 // respect that.
641 ASSERT_EQ(base::File::FILE_ERROR_SECURITY, helper.Copy(src, dest));
644 TEST(LocalFileSystemCopyOrMoveOperationTest, ProgressCallback) {
645 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
646 storage::kFileSystemTypeTemporary,
647 storage::kFileSystemTypePersistent);
648 helper.SetUp();
650 FileSystemURL src = helper.SourceURL("a");
651 FileSystemURL dest = helper.DestURL("b");
653 // Set up a source directory.
654 ASSERT_EQ(base::File::FILE_OK, helper.CreateDirectory(src));
655 ASSERT_EQ(base::File::FILE_OK,
656 helper.SetUpTestCaseFiles(src,
657 kRegularFileSystemTestCases,
658 kRegularFileSystemTestCaseSize));
660 std::vector<ProgressRecord> records;
661 ASSERT_EQ(base::File::FILE_OK,
662 helper.CopyWithProgress(src, dest,
663 base::Bind(&RecordProgressCallback,
664 base::Unretained(&records))));
666 // Verify progress callback.
667 for (size_t i = 0; i < kRegularFileSystemTestCaseSize; ++i) {
668 const FileSystemTestCaseRecord& test_case = kRegularFileSystemTestCases[i];
670 FileSystemURL src_url = helper.SourceURL(
671 std::string("a/") + base::FilePath(test_case.path).AsUTF8Unsafe());
672 FileSystemURL dest_url = helper.DestURL(
673 std::string("b/") + base::FilePath(test_case.path).AsUTF8Unsafe());
675 // Find the first and last progress record.
676 size_t begin_index = records.size();
677 size_t end_index = records.size();
678 for (size_t j = 0; j < records.size(); ++j) {
679 if (records[j].source_url == src_url) {
680 if (begin_index == records.size())
681 begin_index = j;
682 end_index = j;
686 // The record should be found.
687 ASSERT_NE(begin_index, records.size());
688 ASSERT_NE(end_index, records.size());
689 ASSERT_NE(begin_index, end_index);
691 EXPECT_EQ(FileSystemOperation::BEGIN_COPY_ENTRY,
692 records[begin_index].type);
693 EXPECT_FALSE(records[begin_index].dest_url.is_valid());
694 EXPECT_EQ(FileSystemOperation::END_COPY_ENTRY, records[end_index].type);
695 EXPECT_EQ(dest_url, records[end_index].dest_url);
697 if (test_case.is_directory) {
698 // For directory copy, the progress shouldn't be interlaced.
699 EXPECT_EQ(begin_index + 1, end_index);
700 } else {
701 // PROGRESS event's size should be assending order.
702 int64 current_size = 0;
703 for (size_t j = begin_index + 1; j < end_index; ++j) {
704 if (records[j].source_url == src_url) {
705 EXPECT_EQ(FileSystemOperation::PROGRESS, records[j].type);
706 EXPECT_FALSE(records[j].dest_url.is_valid());
707 EXPECT_GE(records[j].size, current_size);
708 current_size = records[j].size;
715 TEST(LocalFileSystemCopyOrMoveOperationTest, StreamCopyHelper) {
716 base::ScopedTempDir temp_dir;
717 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
718 base::FilePath source_path = temp_dir.path().AppendASCII("source");
719 base::FilePath dest_path = temp_dir.path().AppendASCII("dest");
720 const char kTestData[] = "abcdefghijklmnopqrstuvwxyz0123456789";
721 base::WriteFile(source_path, kTestData,
722 arraysize(kTestData) - 1); // Exclude trailing '\0'.
724 base::MessageLoopForIO message_loop;
725 base::Thread file_thread("file_thread");
726 ASSERT_TRUE(file_thread.Start());
727 ScopedThreadStopper thread_stopper(&file_thread);
728 ASSERT_TRUE(thread_stopper.is_valid());
730 scoped_refptr<base::MessageLoopProxy> task_runner =
731 file_thread.message_loop_proxy();
733 scoped_ptr<storage::FileStreamReader> reader(
734 storage::FileStreamReader::CreateForLocalFile(
735 task_runner.get(), source_path, 0, base::Time()));
737 scoped_ptr<FileStreamWriter> writer(FileStreamWriter::CreateForLocalFile(
738 task_runner.get(), dest_path, 0, FileStreamWriter::CREATE_NEW_FILE));
740 std::vector<int64> progress;
741 CopyOrMoveOperationDelegate::StreamCopyHelper helper(
742 reader.Pass(), writer.Pass(),
743 false, // don't need flush
744 10, // buffer size
745 base::Bind(&RecordFileProgressCallback, base::Unretained(&progress)),
746 base::TimeDelta()); // For testing, we need all the progress.
748 base::File::Error error = base::File::FILE_ERROR_FAILED;
749 base::RunLoop run_loop;
750 helper.Run(base::Bind(&AssignAndQuit, &run_loop, &error));
751 run_loop.Run();
753 EXPECT_EQ(base::File::FILE_OK, error);
754 ASSERT_EQ(5U, progress.size());
755 EXPECT_EQ(0, progress[0]);
756 EXPECT_EQ(10, progress[1]);
757 EXPECT_EQ(20, progress[2]);
758 EXPECT_EQ(30, progress[3]);
759 EXPECT_EQ(36, progress[4]);
761 std::string content;
762 ASSERT_TRUE(base::ReadFileToString(dest_path, &content));
763 EXPECT_EQ(kTestData, content);
766 TEST(LocalFileSystemCopyOrMoveOperationTest, StreamCopyHelperWithFlush) {
767 // Testing the same configuration as StreamCopyHelper, but with |need_flush|
768 // parameter set to true. Since it is hard to test that the flush is indeed
769 // taking place, this test just only verifies that the file is correctly
770 // written with or without the flag.
771 base::ScopedTempDir temp_dir;
772 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
773 base::FilePath source_path = temp_dir.path().AppendASCII("source");
774 base::FilePath dest_path = temp_dir.path().AppendASCII("dest");
775 const char kTestData[] = "abcdefghijklmnopqrstuvwxyz0123456789";
776 base::WriteFile(source_path, kTestData,
777 arraysize(kTestData) - 1); // Exclude trailing '\0'.
780 base::MessageLoopForIO message_loop;
781 base::Thread file_thread("file_thread");
782 ASSERT_TRUE(file_thread.Start());
783 ScopedThreadStopper thread_stopper(&file_thread);
784 ASSERT_TRUE(thread_stopper.is_valid());
786 scoped_refptr<base::MessageLoopProxy> task_runner =
787 file_thread.message_loop_proxy();
789 scoped_ptr<storage::FileStreamReader> reader(
790 storage::FileStreamReader::CreateForLocalFile(
791 task_runner.get(), source_path, 0, base::Time()));
793 scoped_ptr<FileStreamWriter> writer(FileStreamWriter::CreateForLocalFile(
794 task_runner.get(), dest_path, 0, FileStreamWriter::CREATE_NEW_FILE));
796 std::vector<int64> progress;
797 CopyOrMoveOperationDelegate::StreamCopyHelper helper(
798 reader.Pass(), writer.Pass(),
799 true, // need flush
800 10, // buffer size
801 base::Bind(&RecordFileProgressCallback, base::Unretained(&progress)),
802 base::TimeDelta()); // For testing, we need all the progress.
804 base::File::Error error = base::File::FILE_ERROR_FAILED;
805 base::RunLoop run_loop;
806 helper.Run(base::Bind(&AssignAndQuit, &run_loop, &error));
807 run_loop.Run();
809 EXPECT_EQ(base::File::FILE_OK, error);
810 ASSERT_EQ(5U, progress.size());
811 EXPECT_EQ(0, progress[0]);
812 EXPECT_EQ(10, progress[1]);
813 EXPECT_EQ(20, progress[2]);
814 EXPECT_EQ(30, progress[3]);
815 EXPECT_EQ(36, progress[4]);
817 std::string content;
818 ASSERT_TRUE(base::ReadFileToString(dest_path, &content));
819 EXPECT_EQ(kTestData, content);
822 TEST(LocalFileSystemCopyOrMoveOperationTest, StreamCopyHelper_Cancel) {
823 base::ScopedTempDir temp_dir;
824 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
825 base::FilePath source_path = temp_dir.path().AppendASCII("source");
826 base::FilePath dest_path = temp_dir.path().AppendASCII("dest");
827 const char kTestData[] = "abcdefghijklmnopqrstuvwxyz0123456789";
828 base::WriteFile(source_path, kTestData,
829 arraysize(kTestData) - 1); // Exclude trailing '\0'.
831 base::MessageLoopForIO message_loop;
832 base::Thread file_thread("file_thread");
833 ASSERT_TRUE(file_thread.Start());
834 ScopedThreadStopper thread_stopper(&file_thread);
835 ASSERT_TRUE(thread_stopper.is_valid());
837 scoped_refptr<base::MessageLoopProxy> task_runner =
838 file_thread.message_loop_proxy();
840 scoped_ptr<storage::FileStreamReader> reader(
841 storage::FileStreamReader::CreateForLocalFile(
842 task_runner.get(), source_path, 0, base::Time()));
844 scoped_ptr<FileStreamWriter> writer(FileStreamWriter::CreateForLocalFile(
845 task_runner.get(), dest_path, 0, FileStreamWriter::CREATE_NEW_FILE));
847 std::vector<int64> progress;
848 CopyOrMoveOperationDelegate::StreamCopyHelper helper(
849 reader.Pass(), writer.Pass(),
850 false, // need_flush
851 10, // buffer size
852 base::Bind(&RecordFileProgressCallback, base::Unretained(&progress)),
853 base::TimeDelta()); // For testing, we need all the progress.
855 // Call Cancel() later.
856 base::MessageLoopProxy::current()->PostTask(
857 FROM_HERE,
858 base::Bind(&CopyOrMoveOperationDelegate::StreamCopyHelper::Cancel,
859 base::Unretained(&helper)));
861 base::File::Error error = base::File::FILE_ERROR_FAILED;
862 base::RunLoop run_loop;
863 helper.Run(base::Bind(&AssignAndQuit, &run_loop, &error));
864 run_loop.Run();
866 EXPECT_EQ(base::File::FILE_ERROR_ABORT, error);
869 } // namespace content