Add remoting and PPAPI tests to GN build
[chromium-blink-merge.git] / content / browser / fileapi / copy_or_move_operation_delegate_unittest.cc
blob451353d1cd91e7bfe12797da0cef158340157a96
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/files/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 "storage/browser/fileapi/copy_or_move_file_validator.h"
22 #include "storage/browser/fileapi/copy_or_move_operation_delegate.h"
23 #include "storage/browser/fileapi/file_stream_reader.h"
24 #include "storage/browser/fileapi/file_stream_writer.h"
25 #include "storage/browser/fileapi/file_system_backend.h"
26 #include "storage/browser/fileapi/file_system_context.h"
27 #include "storage/browser/fileapi/file_system_operation.h"
28 #include "storage/browser/fileapi/file_system_url.h"
29 #include "storage/browser/quota/quota_manager.h"
30 #include "storage/common/fileapi/file_system_mount_option.h"
31 #include "storage/common/fileapi/file_system_util.h"
32 #include "testing/gtest/include/gtest/gtest.h"
34 using content::AsyncFileTestHelper;
35 using storage::CopyOrMoveOperationDelegate;
36 using storage::FileStreamWriter;
37 using storage::FileSystemOperation;
38 using storage::FileSystemURL;
40 namespace content {
42 typedef storage::FileSystemOperation::FileEntryList FileEntryList;
44 namespace {
46 void ExpectOk(const GURL& origin_url,
47 const std::string& name,
48 base::File::Error error) {
49 ASSERT_EQ(base::File::FILE_OK, error);
52 class TestValidatorFactory : public storage::CopyOrMoveFileValidatorFactory {
53 public:
54 // A factory that creates validators that accept everything or nothing.
55 TestValidatorFactory() {}
56 ~TestValidatorFactory() override {}
58 storage::CopyOrMoveFileValidator* CreateCopyOrMoveFileValidator(
59 const FileSystemURL& /*src_url*/,
60 const base::FilePath& /*platform_path*/) override {
61 // Move arg management to TestValidator?
62 return new TestValidator(true, true, std::string("2"));
65 private:
66 class TestValidator : public storage::CopyOrMoveFileValidator {
67 public:
68 explicit TestValidator(bool pre_copy_valid,
69 bool post_copy_valid,
70 const std::string& reject_string)
71 : result_(pre_copy_valid ? base::File::FILE_OK :
72 base::File::FILE_ERROR_SECURITY),
73 write_result_(post_copy_valid ? base::File::FILE_OK :
74 base::File::FILE_ERROR_SECURITY),
75 reject_string_(reject_string) {
77 ~TestValidator() override {}
79 void StartPreWriteValidation(
80 const ResultCallback& result_callback) override {
81 // Post the result since a real validator must do work asynchronously.
82 base::MessageLoop::current()->PostTask(
83 FROM_HERE, base::Bind(result_callback, result_));
86 void StartPostWriteValidation(
87 const base::FilePath& dest_platform_path,
88 const ResultCallback& result_callback) override {
89 base::File::Error result = write_result_;
90 std::string unsafe = dest_platform_path.BaseName().AsUTF8Unsafe();
91 if (unsafe.find(reject_string_) != std::string::npos) {
92 result = base::File::FILE_ERROR_SECURITY;
94 // Post the result since a real validator must do work asynchronously.
95 base::MessageLoop::current()->PostTask(
96 FROM_HERE, base::Bind(result_callback, result));
99 private:
100 base::File::Error result_;
101 base::File::Error write_result_;
102 std::string reject_string_;
104 DISALLOW_COPY_AND_ASSIGN(TestValidator);
108 // Records CopyProgressCallback invocations.
109 struct ProgressRecord {
110 storage::FileSystemOperation::CopyProgressType type;
111 FileSystemURL source_url;
112 FileSystemURL dest_url;
113 int64 size;
116 void RecordProgressCallback(std::vector<ProgressRecord>* records,
117 storage::FileSystemOperation::CopyProgressType type,
118 const FileSystemURL& source_url,
119 const FileSystemURL& dest_url,
120 int64 size) {
121 ProgressRecord record;
122 record.type = type;
123 record.source_url = source_url;
124 record.dest_url = dest_url;
125 record.size = size;
126 records->push_back(record);
129 void RecordFileProgressCallback(std::vector<int64>* records,
130 int64 progress) {
131 records->push_back(progress);
134 void AssignAndQuit(base::RunLoop* run_loop,
135 base::File::Error* result_out,
136 base::File::Error result) {
137 *result_out = result;
138 run_loop->Quit();
141 class ScopedThreadStopper {
142 public:
143 ScopedThreadStopper(base::Thread* thread) : thread_(thread) {
146 ~ScopedThreadStopper() {
147 if (thread_) {
148 // Give another chance for deleted streams to perform Close.
149 base::RunLoop run_loop;
150 thread_->message_loop_proxy()->PostTaskAndReply(
151 FROM_HERE, base::Bind(&base::DoNothing), run_loop.QuitClosure());
152 run_loop.Run();
153 thread_->Stop();
157 bool is_valid() const { return thread_; }
159 private:
160 base::Thread* thread_;
161 DISALLOW_COPY_AND_ASSIGN(ScopedThreadStopper);
164 } // namespace
166 class CopyOrMoveOperationTestHelper {
167 public:
168 CopyOrMoveOperationTestHelper(const GURL& origin,
169 storage::FileSystemType src_type,
170 storage::FileSystemType dest_type)
171 : origin_(origin), src_type_(src_type), dest_type_(dest_type) {}
173 ~CopyOrMoveOperationTestHelper() {
174 file_system_context_ = NULL;
175 quota_manager_proxy_->SimulateQuotaManagerDestroyed();
176 quota_manager_ = NULL;
177 quota_manager_proxy_ = NULL;
178 base::RunLoop().RunUntilIdle();
181 void SetUp() {
182 SetUp(true, true);
185 void SetUpNoValidator() {
186 SetUp(true, false);
189 void SetUp(bool require_copy_or_move_validator,
190 bool init_copy_or_move_validator) {
191 ASSERT_TRUE(base_.CreateUniqueTempDir());
192 base::FilePath base_dir = base_.path();
193 quota_manager_ =
194 new MockQuotaManager(false /* is_incognito */,
195 base_dir,
196 base::MessageLoopProxy::current().get(),
197 base::MessageLoopProxy::current().get(),
198 NULL /* special storage policy */);
199 quota_manager_proxy_ = new MockQuotaManagerProxy(
200 quota_manager_.get(), base::MessageLoopProxy::current().get());
201 file_system_context_ =
202 CreateFileSystemContextForTesting(quota_manager_proxy_.get(), base_dir);
204 // Prepare the origin's root directory.
205 storage::FileSystemBackend* backend =
206 file_system_context_->GetFileSystemBackend(src_type_);
207 backend->ResolveURL(
208 FileSystemURL::CreateForTest(origin_, src_type_, base::FilePath()),
209 storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
210 base::Bind(&ExpectOk));
211 backend = file_system_context_->GetFileSystemBackend(dest_type_);
212 if (dest_type_ == storage::kFileSystemTypeTest) {
213 TestFileSystemBackend* test_backend =
214 static_cast<TestFileSystemBackend*>(backend);
215 scoped_ptr<storage::CopyOrMoveFileValidatorFactory> factory(
216 new TestValidatorFactory);
217 test_backend->set_require_copy_or_move_validator(
218 require_copy_or_move_validator);
219 if (init_copy_or_move_validator)
220 test_backend->InitializeCopyOrMoveFileValidatorFactory(factory.Pass());
222 backend->ResolveURL(
223 FileSystemURL::CreateForTest(origin_, dest_type_, base::FilePath()),
224 storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
225 base::Bind(&ExpectOk));
226 base::RunLoop().RunUntilIdle();
228 // Grant relatively big quota initially.
229 quota_manager_->SetQuota(
230 origin_,
231 storage::FileSystemTypeToQuotaStorageType(src_type_),
232 1024 * 1024);
233 quota_manager_->SetQuota(
234 origin_,
235 storage::FileSystemTypeToQuotaStorageType(dest_type_),
236 1024 * 1024);
239 int64 GetSourceUsage() {
240 int64 usage = 0;
241 GetUsageAndQuota(src_type_, &usage, NULL);
242 return usage;
245 int64 GetDestUsage() {
246 int64 usage = 0;
247 GetUsageAndQuota(dest_type_, &usage, NULL);
248 return usage;
251 FileSystemURL SourceURL(const std::string& path) {
252 return file_system_context_->CreateCrackedFileSystemURL(
253 origin_, src_type_, base::FilePath::FromUTF8Unsafe(path));
256 FileSystemURL DestURL(const std::string& path) {
257 return file_system_context_->CreateCrackedFileSystemURL(
258 origin_, dest_type_, base::FilePath::FromUTF8Unsafe(path));
261 base::File::Error Copy(const FileSystemURL& src,
262 const FileSystemURL& dest) {
263 return AsyncFileTestHelper::Copy(file_system_context_.get(), src, dest);
266 base::File::Error CopyWithProgress(
267 const FileSystemURL& src,
268 const FileSystemURL& dest,
269 const AsyncFileTestHelper::CopyProgressCallback& progress_callback) {
270 return AsyncFileTestHelper::CopyWithProgress(
271 file_system_context_.get(), src, dest, progress_callback);
274 base::File::Error Move(const FileSystemURL& src,
275 const FileSystemURL& dest) {
276 return AsyncFileTestHelper::Move(file_system_context_.get(), src, dest);
279 base::File::Error SetUpTestCaseFiles(
280 const FileSystemURL& root,
281 const FileSystemTestCaseRecord* const test_cases,
282 size_t test_case_size) {
283 base::File::Error result = base::File::FILE_ERROR_FAILED;
284 for (size_t i = 0; i < test_case_size; ++i) {
285 const FileSystemTestCaseRecord& test_case = test_cases[i];
286 FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL(
287 root.origin(),
288 root.mount_type(),
289 root.virtual_path().Append(test_case.path));
290 if (test_case.is_directory)
291 result = CreateDirectory(url);
292 else
293 result = CreateFile(url, test_case.data_file_size);
294 EXPECT_EQ(base::File::FILE_OK, result) << url.DebugString();
295 if (result != base::File::FILE_OK)
296 return result;
298 return result;
301 void VerifyTestCaseFiles(
302 const FileSystemURL& root,
303 const FileSystemTestCaseRecord* const test_cases,
304 size_t test_case_size) {
305 std::map<base::FilePath, const FileSystemTestCaseRecord*> test_case_map;
306 for (size_t i = 0; i < test_case_size; ++i) {
307 test_case_map[
308 base::FilePath(test_cases[i].path).NormalizePathSeparators()] =
309 &test_cases[i];
312 std::queue<FileSystemURL> directories;
313 FileEntryList entries;
314 directories.push(root);
315 while (!directories.empty()) {
316 FileSystemURL dir = directories.front();
317 directories.pop();
318 ASSERT_EQ(base::File::FILE_OK, ReadDirectory(dir, &entries));
319 for (size_t i = 0; i < entries.size(); ++i) {
320 FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL(
321 dir.origin(),
322 dir.mount_type(),
323 dir.virtual_path().Append(entries[i].name));
324 base::FilePath relative;
325 root.virtual_path().AppendRelativePath(url.virtual_path(), &relative);
326 relative = relative.NormalizePathSeparators();
327 ASSERT_TRUE(ContainsKey(test_case_map, relative));
328 if (entries[i].is_directory) {
329 EXPECT_TRUE(test_case_map[relative]->is_directory);
330 directories.push(url);
331 } else {
332 EXPECT_FALSE(test_case_map[relative]->is_directory);
333 EXPECT_TRUE(FileExists(url, test_case_map[relative]->data_file_size));
335 test_case_map.erase(relative);
338 EXPECT_TRUE(test_case_map.empty());
339 std::map<base::FilePath,
340 const FileSystemTestCaseRecord*>::const_iterator it;
341 for (it = test_case_map.begin(); it != test_case_map.end(); ++it) {
342 LOG(ERROR) << "Extra entry: " << it->first.LossyDisplayName();
346 base::File::Error ReadDirectory(const FileSystemURL& url,
347 FileEntryList* entries) {
348 return AsyncFileTestHelper::ReadDirectory(
349 file_system_context_.get(), url, entries);
352 base::File::Error CreateDirectory(const FileSystemURL& url) {
353 return AsyncFileTestHelper::CreateDirectory(file_system_context_.get(),
354 url);
357 base::File::Error CreateFile(const FileSystemURL& url, size_t size) {
358 base::File::Error result =
359 AsyncFileTestHelper::CreateFile(file_system_context_.get(), url);
360 if (result != base::File::FILE_OK)
361 return result;
362 return AsyncFileTestHelper::TruncateFile(
363 file_system_context_.get(), url, size);
366 bool FileExists(const FileSystemURL& url, int64 expected_size) {
367 return AsyncFileTestHelper::FileExists(
368 file_system_context_.get(), url, expected_size);
371 bool DirectoryExists(const FileSystemURL& url) {
372 return AsyncFileTestHelper::DirectoryExists(file_system_context_.get(),
373 url);
376 private:
377 void GetUsageAndQuota(storage::FileSystemType type,
378 int64* usage,
379 int64* quota) {
380 storage::QuotaStatusCode status = AsyncFileTestHelper::GetUsageAndQuota(
381 quota_manager_.get(), origin_, type, usage, quota);
382 ASSERT_EQ(storage::kQuotaStatusOk, status);
385 private:
386 base::ScopedTempDir base_;
388 const GURL origin_;
389 const storage::FileSystemType src_type_;
390 const storage::FileSystemType dest_type_;
392 base::MessageLoopForIO message_loop_;
393 scoped_refptr<storage::FileSystemContext> file_system_context_;
394 scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
395 scoped_refptr<MockQuotaManager> quota_manager_;
397 DISALLOW_COPY_AND_ASSIGN(CopyOrMoveOperationTestHelper);
400 TEST(LocalFileSystemCopyOrMoveOperationTest, CopySingleFile) {
401 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
402 storage::kFileSystemTypeTemporary,
403 storage::kFileSystemTypePersistent);
404 helper.SetUp();
406 FileSystemURL src = helper.SourceURL("a");
407 FileSystemURL dest = helper.DestURL("b");
408 int64 src_initial_usage = helper.GetSourceUsage();
409 int64 dest_initial_usage = helper.GetDestUsage();
411 // Set up a source file.
412 ASSERT_EQ(base::File::FILE_OK, helper.CreateFile(src, 10));
413 int64 src_increase = helper.GetSourceUsage() - src_initial_usage;
415 // Copy it.
416 ASSERT_EQ(base::File::FILE_OK, helper.Copy(src, dest));
418 // Verify.
419 ASSERT_TRUE(helper.FileExists(src, 10));
420 ASSERT_TRUE(helper.FileExists(dest, 10));
422 int64 src_new_usage = helper.GetSourceUsage();
423 ASSERT_EQ(src_initial_usage + src_increase, src_new_usage);
425 int64 dest_increase = helper.GetDestUsage() - dest_initial_usage;
426 ASSERT_EQ(src_increase, dest_increase);
429 TEST(LocalFileSystemCopyOrMoveOperationTest, MoveSingleFile) {
430 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
431 storage::kFileSystemTypeTemporary,
432 storage::kFileSystemTypePersistent);
433 helper.SetUp();
435 FileSystemURL src = helper.SourceURL("a");
436 FileSystemURL dest = helper.DestURL("b");
437 int64 src_initial_usage = helper.GetSourceUsage();
438 int64 dest_initial_usage = helper.GetDestUsage();
440 // Set up a source file.
441 ASSERT_EQ(base::File::FILE_OK, helper.CreateFile(src, 10));
442 int64 src_increase = helper.GetSourceUsage() - src_initial_usage;
444 // Move it.
445 ASSERT_EQ(base::File::FILE_OK, helper.Move(src, dest));
447 // Verify.
448 ASSERT_FALSE(helper.FileExists(src, AsyncFileTestHelper::kDontCheckSize));
449 ASSERT_TRUE(helper.FileExists(dest, 10));
451 int64 src_new_usage = helper.GetSourceUsage();
452 ASSERT_EQ(src_initial_usage, src_new_usage);
454 int64 dest_increase = helper.GetDestUsage() - dest_initial_usage;
455 ASSERT_EQ(src_increase, dest_increase);
458 TEST(LocalFileSystemCopyOrMoveOperationTest, CopySingleDirectory) {
459 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
460 storage::kFileSystemTypeTemporary,
461 storage::kFileSystemTypePersistent);
462 helper.SetUp();
464 FileSystemURL src = helper.SourceURL("a");
465 FileSystemURL dest = helper.DestURL("b");
466 int64 src_initial_usage = helper.GetSourceUsage();
467 int64 dest_initial_usage = helper.GetDestUsage();
469 // Set up a source directory.
470 ASSERT_EQ(base::File::FILE_OK, helper.CreateDirectory(src));
471 int64 src_increase = helper.GetSourceUsage() - src_initial_usage;
473 // Copy it.
474 ASSERT_EQ(base::File::FILE_OK, helper.Copy(src, dest));
476 // Verify.
477 ASSERT_TRUE(helper.DirectoryExists(src));
478 ASSERT_TRUE(helper.DirectoryExists(dest));
480 int64 src_new_usage = helper.GetSourceUsage();
481 ASSERT_EQ(src_initial_usage + src_increase, src_new_usage);
483 int64 dest_increase = helper.GetDestUsage() - dest_initial_usage;
484 ASSERT_EQ(src_increase, dest_increase);
487 TEST(LocalFileSystemCopyOrMoveOperationTest, MoveSingleDirectory) {
488 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
489 storage::kFileSystemTypeTemporary,
490 storage::kFileSystemTypePersistent);
491 helper.SetUp();
493 FileSystemURL src = helper.SourceURL("a");
494 FileSystemURL dest = helper.DestURL("b");
495 int64 src_initial_usage = helper.GetSourceUsage();
496 int64 dest_initial_usage = helper.GetDestUsage();
498 // Set up a source directory.
499 ASSERT_EQ(base::File::FILE_OK, helper.CreateDirectory(src));
500 int64 src_increase = helper.GetSourceUsage() - src_initial_usage;
502 // Move it.
503 ASSERT_EQ(base::File::FILE_OK, helper.Move(src, dest));
505 // Verify.
506 ASSERT_FALSE(helper.DirectoryExists(src));
507 ASSERT_TRUE(helper.DirectoryExists(dest));
509 int64 src_new_usage = helper.GetSourceUsage();
510 ASSERT_EQ(src_initial_usage, src_new_usage);
512 int64 dest_increase = helper.GetDestUsage() - dest_initial_usage;
513 ASSERT_EQ(src_increase, dest_increase);
516 TEST(LocalFileSystemCopyOrMoveOperationTest, CopyDirectory) {
517 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
518 storage::kFileSystemTypeTemporary,
519 storage::kFileSystemTypePersistent);
520 helper.SetUp();
522 FileSystemURL src = helper.SourceURL("a");
523 FileSystemURL dest = helper.DestURL("b");
524 int64 src_initial_usage = helper.GetSourceUsage();
525 int64 dest_initial_usage = helper.GetDestUsage();
527 // Set up a source directory.
528 ASSERT_EQ(base::File::FILE_OK, helper.CreateDirectory(src));
529 ASSERT_EQ(base::File::FILE_OK,
530 helper.SetUpTestCaseFiles(src,
531 kRegularFileSystemTestCases,
532 kRegularFileSystemTestCaseSize));
533 int64 src_increase = helper.GetSourceUsage() - src_initial_usage;
535 // Copy it.
536 ASSERT_EQ(base::File::FILE_OK,
537 helper.CopyWithProgress(
538 src, dest,
539 AsyncFileTestHelper::CopyProgressCallback()));
541 // Verify.
542 ASSERT_TRUE(helper.DirectoryExists(src));
543 ASSERT_TRUE(helper.DirectoryExists(dest));
545 helper.VerifyTestCaseFiles(dest,
546 kRegularFileSystemTestCases,
547 kRegularFileSystemTestCaseSize);
549 int64 src_new_usage = helper.GetSourceUsage();
550 ASSERT_EQ(src_initial_usage + src_increase, src_new_usage);
552 int64 dest_increase = helper.GetDestUsage() - dest_initial_usage;
553 ASSERT_EQ(src_increase, dest_increase);
556 TEST(LocalFileSystemCopyOrMoveOperationTest, MoveDirectory) {
557 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
558 storage::kFileSystemTypeTemporary,
559 storage::kFileSystemTypePersistent);
560 helper.SetUp();
562 FileSystemURL src = helper.SourceURL("a");
563 FileSystemURL dest = helper.DestURL("b");
564 int64 src_initial_usage = helper.GetSourceUsage();
565 int64 dest_initial_usage = helper.GetDestUsage();
567 // Set up a source directory.
568 ASSERT_EQ(base::File::FILE_OK, helper.CreateDirectory(src));
569 ASSERT_EQ(base::File::FILE_OK,
570 helper.SetUpTestCaseFiles(src,
571 kRegularFileSystemTestCases,
572 kRegularFileSystemTestCaseSize));
573 int64 src_increase = helper.GetSourceUsage() - src_initial_usage;
575 // Move it.
576 ASSERT_EQ(base::File::FILE_OK, helper.Move(src, dest));
578 // Verify.
579 ASSERT_FALSE(helper.DirectoryExists(src));
580 ASSERT_TRUE(helper.DirectoryExists(dest));
582 helper.VerifyTestCaseFiles(dest,
583 kRegularFileSystemTestCases,
584 kRegularFileSystemTestCaseSize);
586 int64 src_new_usage = helper.GetSourceUsage();
587 ASSERT_EQ(src_initial_usage, src_new_usage);
589 int64 dest_increase = helper.GetDestUsage() - dest_initial_usage;
590 ASSERT_EQ(src_increase, dest_increase);
593 TEST(LocalFileSystemCopyOrMoveOperationTest,
594 MoveDirectoryFailPostWriteValidation) {
595 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
596 storage::kFileSystemTypeTemporary,
597 storage::kFileSystemTypeTest);
598 helper.SetUp();
600 FileSystemURL src = helper.SourceURL("a");
601 FileSystemURL dest = helper.DestURL("b");
603 // Set up a source directory.
604 ASSERT_EQ(base::File::FILE_OK, helper.CreateDirectory(src));
605 ASSERT_EQ(base::File::FILE_OK,
606 helper.SetUpTestCaseFiles(src,
607 kRegularFileSystemTestCases,
608 kRegularFileSystemTestCaseSize));
610 // Move it.
611 helper.Move(src, dest);
613 // Verify.
614 ASSERT_TRUE(helper.DirectoryExists(src));
615 ASSERT_TRUE(helper.DirectoryExists(dest));
617 FileSystemTestCaseRecord kMoveDirResultCases[] = {
618 {false, FILE_PATH_LITERAL("file 0"), 38},
619 {false, FILE_PATH_LITERAL("file 3"), 0},
622 helper.VerifyTestCaseFiles(dest,
623 kMoveDirResultCases,
624 arraysize(kMoveDirResultCases));
627 TEST(LocalFileSystemCopyOrMoveOperationTest, CopySingleFileNoValidator) {
628 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
629 storage::kFileSystemTypeTemporary,
630 storage::kFileSystemTypeTest);
631 helper.SetUpNoValidator();
633 FileSystemURL src = helper.SourceURL("a");
634 FileSystemURL dest = helper.DestURL("b");
636 // Set up a source file.
637 ASSERT_EQ(base::File::FILE_OK, helper.CreateFile(src, 10));
639 // The copy attempt should fail with a security error -- getting
640 // the factory returns a security error, and the copy operation must
641 // respect that.
642 ASSERT_EQ(base::File::FILE_ERROR_SECURITY, helper.Copy(src, dest));
645 TEST(LocalFileSystemCopyOrMoveOperationTest, ProgressCallback) {
646 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
647 storage::kFileSystemTypeTemporary,
648 storage::kFileSystemTypePersistent);
649 helper.SetUp();
651 FileSystemURL src = helper.SourceURL("a");
652 FileSystemURL dest = helper.DestURL("b");
654 // Set up a source directory.
655 ASSERT_EQ(base::File::FILE_OK, helper.CreateDirectory(src));
656 ASSERT_EQ(base::File::FILE_OK,
657 helper.SetUpTestCaseFiles(src,
658 kRegularFileSystemTestCases,
659 kRegularFileSystemTestCaseSize));
661 std::vector<ProgressRecord> records;
662 ASSERT_EQ(base::File::FILE_OK,
663 helper.CopyWithProgress(src, dest,
664 base::Bind(&RecordProgressCallback,
665 base::Unretained(&records))));
667 // Verify progress callback.
668 for (size_t i = 0; i < kRegularFileSystemTestCaseSize; ++i) {
669 const FileSystemTestCaseRecord& test_case = kRegularFileSystemTestCases[i];
671 FileSystemURL src_url = helper.SourceURL(
672 std::string("a/") + base::FilePath(test_case.path).AsUTF8Unsafe());
673 FileSystemURL dest_url = helper.DestURL(
674 std::string("b/") + base::FilePath(test_case.path).AsUTF8Unsafe());
676 // Find the first and last progress record.
677 size_t begin_index = records.size();
678 size_t end_index = records.size();
679 for (size_t j = 0; j < records.size(); ++j) {
680 if (records[j].source_url == src_url) {
681 if (begin_index == records.size())
682 begin_index = j;
683 end_index = j;
687 // The record should be found.
688 ASSERT_NE(begin_index, records.size());
689 ASSERT_NE(end_index, records.size());
690 ASSERT_NE(begin_index, end_index);
692 EXPECT_EQ(FileSystemOperation::BEGIN_COPY_ENTRY,
693 records[begin_index].type);
694 EXPECT_FALSE(records[begin_index].dest_url.is_valid());
695 EXPECT_EQ(FileSystemOperation::END_COPY_ENTRY, records[end_index].type);
696 EXPECT_EQ(dest_url, records[end_index].dest_url);
698 if (test_case.is_directory) {
699 // For directory copy, the progress shouldn't be interlaced.
700 EXPECT_EQ(begin_index + 1, end_index);
701 } else {
702 // PROGRESS event's size should be assending order.
703 int64 current_size = 0;
704 for (size_t j = begin_index + 1; j < end_index; ++j) {
705 if (records[j].source_url == src_url) {
706 EXPECT_EQ(FileSystemOperation::PROGRESS, records[j].type);
707 EXPECT_FALSE(records[j].dest_url.is_valid());
708 EXPECT_GE(records[j].size, current_size);
709 current_size = records[j].size;
716 TEST(LocalFileSystemCopyOrMoveOperationTest, StreamCopyHelper) {
717 base::ScopedTempDir temp_dir;
718 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
719 base::FilePath source_path = temp_dir.path().AppendASCII("source");
720 base::FilePath dest_path = temp_dir.path().AppendASCII("dest");
721 const char kTestData[] = "abcdefghijklmnopqrstuvwxyz0123456789";
722 base::WriteFile(source_path, kTestData,
723 arraysize(kTestData) - 1); // Exclude trailing '\0'.
725 base::MessageLoopForIO message_loop;
726 base::Thread file_thread("file_thread");
727 ASSERT_TRUE(file_thread.Start());
728 ScopedThreadStopper thread_stopper(&file_thread);
729 ASSERT_TRUE(thread_stopper.is_valid());
731 scoped_refptr<base::MessageLoopProxy> task_runner =
732 file_thread.message_loop_proxy();
734 scoped_ptr<storage::FileStreamReader> reader(
735 storage::FileStreamReader::CreateForLocalFile(
736 task_runner.get(), source_path, 0, base::Time()));
738 scoped_ptr<FileStreamWriter> writer(FileStreamWriter::CreateForLocalFile(
739 task_runner.get(), dest_path, 0, FileStreamWriter::CREATE_NEW_FILE));
741 std::vector<int64> progress;
742 CopyOrMoveOperationDelegate::StreamCopyHelper helper(
743 reader.Pass(), writer.Pass(),
744 storage::FlushPolicy::NO_FLUSH_ON_COMPLETION,
745 10, // buffer size
746 base::Bind(&RecordFileProgressCallback, base::Unretained(&progress)),
747 base::TimeDelta()); // For testing, we need all the progress.
749 base::File::Error error = base::File::FILE_ERROR_FAILED;
750 base::RunLoop run_loop;
751 helper.Run(base::Bind(&AssignAndQuit, &run_loop, &error));
752 run_loop.Run();
754 EXPECT_EQ(base::File::FILE_OK, error);
755 ASSERT_EQ(5U, progress.size());
756 EXPECT_EQ(0, progress[0]);
757 EXPECT_EQ(10, progress[1]);
758 EXPECT_EQ(20, progress[2]);
759 EXPECT_EQ(30, progress[3]);
760 EXPECT_EQ(36, progress[4]);
762 std::string content;
763 ASSERT_TRUE(base::ReadFileToString(dest_path, &content));
764 EXPECT_EQ(kTestData, content);
767 TEST(LocalFileSystemCopyOrMoveOperationTest, StreamCopyHelperWithFlush) {
768 // Testing the same configuration as StreamCopyHelper, but with |need_flush|
769 // parameter set to true. Since it is hard to test that the flush is indeed
770 // taking place, this test just only verifies that the file is correctly
771 // written with or without the flag.
772 base::ScopedTempDir temp_dir;
773 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
774 base::FilePath source_path = temp_dir.path().AppendASCII("source");
775 base::FilePath dest_path = temp_dir.path().AppendASCII("dest");
776 const char kTestData[] = "abcdefghijklmnopqrstuvwxyz0123456789";
777 base::WriteFile(source_path, kTestData,
778 arraysize(kTestData) - 1); // Exclude trailing '\0'.
781 base::MessageLoopForIO message_loop;
782 base::Thread file_thread("file_thread");
783 ASSERT_TRUE(file_thread.Start());
784 ScopedThreadStopper thread_stopper(&file_thread);
785 ASSERT_TRUE(thread_stopper.is_valid());
787 scoped_refptr<base::MessageLoopProxy> task_runner =
788 file_thread.message_loop_proxy();
790 scoped_ptr<storage::FileStreamReader> reader(
791 storage::FileStreamReader::CreateForLocalFile(
792 task_runner.get(), source_path, 0, base::Time()));
794 scoped_ptr<FileStreamWriter> writer(FileStreamWriter::CreateForLocalFile(
795 task_runner.get(), dest_path, 0, FileStreamWriter::CREATE_NEW_FILE));
797 std::vector<int64> progress;
798 CopyOrMoveOperationDelegate::StreamCopyHelper helper(
799 reader.Pass(), writer.Pass(),
800 storage::FlushPolicy::NO_FLUSH_ON_COMPLETION,
801 10, // buffer size
802 base::Bind(&RecordFileProgressCallback, base::Unretained(&progress)),
803 base::TimeDelta()); // For testing, we need all the progress.
805 base::File::Error error = base::File::FILE_ERROR_FAILED;
806 base::RunLoop run_loop;
807 helper.Run(base::Bind(&AssignAndQuit, &run_loop, &error));
808 run_loop.Run();
810 EXPECT_EQ(base::File::FILE_OK, error);
811 ASSERT_EQ(5U, progress.size());
812 EXPECT_EQ(0, progress[0]);
813 EXPECT_EQ(10, progress[1]);
814 EXPECT_EQ(20, progress[2]);
815 EXPECT_EQ(30, progress[3]);
816 EXPECT_EQ(36, progress[4]);
818 std::string content;
819 ASSERT_TRUE(base::ReadFileToString(dest_path, &content));
820 EXPECT_EQ(kTestData, content);
823 TEST(LocalFileSystemCopyOrMoveOperationTest, StreamCopyHelper_Cancel) {
824 base::ScopedTempDir temp_dir;
825 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
826 base::FilePath source_path = temp_dir.path().AppendASCII("source");
827 base::FilePath dest_path = temp_dir.path().AppendASCII("dest");
828 const char kTestData[] = "abcdefghijklmnopqrstuvwxyz0123456789";
829 base::WriteFile(source_path, kTestData,
830 arraysize(kTestData) - 1); // Exclude trailing '\0'.
832 base::MessageLoopForIO message_loop;
833 base::Thread file_thread("file_thread");
834 ASSERT_TRUE(file_thread.Start());
835 ScopedThreadStopper thread_stopper(&file_thread);
836 ASSERT_TRUE(thread_stopper.is_valid());
838 scoped_refptr<base::MessageLoopProxy> task_runner =
839 file_thread.message_loop_proxy();
841 scoped_ptr<storage::FileStreamReader> reader(
842 storage::FileStreamReader::CreateForLocalFile(
843 task_runner.get(), source_path, 0, base::Time()));
845 scoped_ptr<FileStreamWriter> writer(FileStreamWriter::CreateForLocalFile(
846 task_runner.get(), dest_path, 0, FileStreamWriter::CREATE_NEW_FILE));
848 std::vector<int64> progress;
849 CopyOrMoveOperationDelegate::StreamCopyHelper helper(
850 reader.Pass(), writer.Pass(),
851 storage::FlushPolicy::NO_FLUSH_ON_COMPLETION,
852 10, // buffer size
853 base::Bind(&RecordFileProgressCallback, base::Unretained(&progress)),
854 base::TimeDelta()); // For testing, we need all the progress.
856 // Call Cancel() later.
857 base::MessageLoopProxy::current()->PostTask(
858 FROM_HERE,
859 base::Bind(&CopyOrMoveOperationDelegate::StreamCopyHelper::Cancel,
860 base::Unretained(&helper)));
862 base::File::Error error = base::File::FILE_ERROR_FAILED;
863 base::RunLoop run_loop;
864 helper.Run(base::Bind(&AssignAndQuit, &run_loop, &error));
865 run_loop.Run();
867 EXPECT_EQ(base::File::FILE_ERROR_ABORT, error);
870 } // namespace content