Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / browser / fileapi / copy_or_move_operation_delegate_unittest.cc
blobbbcae168c8a8c2f579f7d4295f4dfdcf07350e65
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/location.h"
13 #include "base/run_loop.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/stl_util.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "content/browser/quota/mock_quota_manager.h"
18 #include "content/browser/quota/mock_quota_manager_proxy.h"
19 #include "content/public/test/async_file_test_helper.h"
20 #include "content/public/test/test_file_system_backend.h"
21 #include "content/public/test/test_file_system_context.h"
22 #include "content/test/fileapi_test_file_set.h"
23 #include "storage/browser/fileapi/copy_or_move_file_validator.h"
24 #include "storage/browser/fileapi/copy_or_move_operation_delegate.h"
25 #include "storage/browser/fileapi/file_stream_reader.h"
26 #include "storage/browser/fileapi/file_stream_writer.h"
27 #include "storage/browser/fileapi/file_system_backend.h"
28 #include "storage/browser/fileapi/file_system_context.h"
29 #include "storage/browser/fileapi/file_system_operation.h"
30 #include "storage/browser/fileapi/file_system_url.h"
31 #include "storage/browser/quota/quota_manager.h"
32 #include "storage/common/fileapi/file_system_mount_option.h"
33 #include "storage/common/fileapi/file_system_util.h"
34 #include "testing/gtest/include/gtest/gtest.h"
36 using content::AsyncFileTestHelper;
37 using storage::CopyOrMoveOperationDelegate;
38 using storage::FileStreamWriter;
39 using storage::FileSystemOperation;
40 using storage::FileSystemURL;
42 namespace content {
44 typedef storage::FileSystemOperation::FileEntryList FileEntryList;
46 namespace {
48 void ExpectOk(const GURL& origin_url,
49 const std::string& name,
50 base::File::Error error) {
51 ASSERT_EQ(base::File::FILE_OK, error);
54 class TestValidatorFactory : public storage::CopyOrMoveFileValidatorFactory {
55 public:
56 // A factory that creates validators that accept everything or nothing.
57 TestValidatorFactory() {}
58 ~TestValidatorFactory() override {}
60 storage::CopyOrMoveFileValidator* CreateCopyOrMoveFileValidator(
61 const FileSystemURL& /*src_url*/,
62 const base::FilePath& /*platform_path*/) override {
63 // Move arg management to TestValidator?
64 return new TestValidator(true, true, std::string("2"));
67 private:
68 class TestValidator : public storage::CopyOrMoveFileValidator {
69 public:
70 explicit TestValidator(bool pre_copy_valid,
71 bool post_copy_valid,
72 const std::string& reject_string)
73 : result_(pre_copy_valid ? base::File::FILE_OK :
74 base::File::FILE_ERROR_SECURITY),
75 write_result_(post_copy_valid ? base::File::FILE_OK :
76 base::File::FILE_ERROR_SECURITY),
77 reject_string_(reject_string) {
79 ~TestValidator() override {}
81 void StartPreWriteValidation(
82 const ResultCallback& result_callback) override {
83 // Post the result since a real validator must do work asynchronously.
84 base::ThreadTaskRunnerHandle::Get()->PostTask(
85 FROM_HERE, base::Bind(result_callback, result_));
88 void StartPostWriteValidation(
89 const base::FilePath& dest_platform_path,
90 const ResultCallback& result_callback) override {
91 base::File::Error result = write_result_;
92 std::string unsafe = dest_platform_path.BaseName().AsUTF8Unsafe();
93 if (unsafe.find(reject_string_) != std::string::npos) {
94 result = base::File::FILE_ERROR_SECURITY;
96 // Post the result since a real validator must do work asynchronously.
97 base::ThreadTaskRunnerHandle::Get()->PostTask(
98 FROM_HERE, base::Bind(result_callback, result));
101 private:
102 base::File::Error result_;
103 base::File::Error write_result_;
104 std::string reject_string_;
106 DISALLOW_COPY_AND_ASSIGN(TestValidator);
110 // Records CopyProgressCallback invocations.
111 struct ProgressRecord {
112 storage::FileSystemOperation::CopyProgressType type;
113 FileSystemURL source_url;
114 FileSystemURL dest_url;
115 int64 size;
118 void RecordProgressCallback(std::vector<ProgressRecord>* records,
119 storage::FileSystemOperation::CopyProgressType type,
120 const FileSystemURL& source_url,
121 const FileSystemURL& dest_url,
122 int64 size) {
123 ProgressRecord record;
124 record.type = type;
125 record.source_url = source_url;
126 record.dest_url = dest_url;
127 record.size = size;
128 records->push_back(record);
131 void RecordFileProgressCallback(std::vector<int64>* records,
132 int64 progress) {
133 records->push_back(progress);
136 void AssignAndQuit(base::RunLoop* run_loop,
137 base::File::Error* result_out,
138 base::File::Error result) {
139 *result_out = result;
140 run_loop->Quit();
143 class ScopedThreadStopper {
144 public:
145 ScopedThreadStopper(base::Thread* thread) : thread_(thread) {
148 ~ScopedThreadStopper() {
149 if (thread_) {
150 // Give another chance for deleted streams to perform Close.
151 base::RunLoop run_loop;
152 thread_->task_runner()->PostTaskAndReply(
153 FROM_HERE, base::Bind(&base::DoNothing), run_loop.QuitClosure());
154 run_loop.Run();
155 thread_->Stop();
159 bool is_valid() const { return thread_; }
161 private:
162 base::Thread* thread_;
163 DISALLOW_COPY_AND_ASSIGN(ScopedThreadStopper);
166 } // namespace
168 class CopyOrMoveOperationTestHelper {
169 public:
170 CopyOrMoveOperationTestHelper(const GURL& origin,
171 storage::FileSystemType src_type,
172 storage::FileSystemType dest_type)
173 : origin_(origin), src_type_(src_type), dest_type_(dest_type) {}
175 ~CopyOrMoveOperationTestHelper() {
176 file_system_context_ = NULL;
177 quota_manager_proxy_->SimulateQuotaManagerDestroyed();
178 quota_manager_ = NULL;
179 quota_manager_proxy_ = NULL;
180 base::RunLoop().RunUntilIdle();
183 void SetUp() {
184 SetUp(true, true);
187 void SetUpNoValidator() {
188 SetUp(true, false);
191 void SetUp(bool require_copy_or_move_validator,
192 bool init_copy_or_move_validator) {
193 ASSERT_TRUE(base_.CreateUniqueTempDir());
194 base::FilePath base_dir = base_.path();
195 quota_manager_ =
196 new MockQuotaManager(false /* is_incognito */, base_dir,
197 base::ThreadTaskRunnerHandle::Get().get(),
198 base::ThreadTaskRunnerHandle::Get().get(),
199 NULL /* special storage policy */);
200 quota_manager_proxy_ = new MockQuotaManagerProxy(
201 quota_manager_.get(), base::ThreadTaskRunnerHandle::Get().get());
202 file_system_context_ =
203 CreateFileSystemContextForTesting(quota_manager_proxy_.get(), base_dir);
205 // Prepare the origin's root directory.
206 storage::FileSystemBackend* backend =
207 file_system_context_->GetFileSystemBackend(src_type_);
208 backend->ResolveURL(
209 FileSystemURL::CreateForTest(origin_, src_type_, base::FilePath()),
210 storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
211 base::Bind(&ExpectOk));
212 backend = file_system_context_->GetFileSystemBackend(dest_type_);
213 if (dest_type_ == storage::kFileSystemTypeTest) {
214 TestFileSystemBackend* test_backend =
215 static_cast<TestFileSystemBackend*>(backend);
216 scoped_ptr<storage::CopyOrMoveFileValidatorFactory> factory(
217 new TestValidatorFactory);
218 test_backend->set_require_copy_or_move_validator(
219 require_copy_or_move_validator);
220 if (init_copy_or_move_validator)
221 test_backend->InitializeCopyOrMoveFileValidatorFactory(factory.Pass());
223 backend->ResolveURL(
224 FileSystemURL::CreateForTest(origin_, dest_type_, base::FilePath()),
225 storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
226 base::Bind(&ExpectOk));
227 base::RunLoop().RunUntilIdle();
229 // Grant relatively big quota initially.
230 quota_manager_->SetQuota(
231 origin_,
232 storage::FileSystemTypeToQuotaStorageType(src_type_),
233 1024 * 1024);
234 quota_manager_->SetQuota(
235 origin_,
236 storage::FileSystemTypeToQuotaStorageType(dest_type_),
237 1024 * 1024);
240 int64 GetSourceUsage() {
241 int64 usage = 0;
242 GetUsageAndQuota(src_type_, &usage, NULL);
243 return usage;
246 int64 GetDestUsage() {
247 int64 usage = 0;
248 GetUsageAndQuota(dest_type_, &usage, NULL);
249 return usage;
252 FileSystemURL SourceURL(const std::string& path) {
253 return file_system_context_->CreateCrackedFileSystemURL(
254 origin_, src_type_, base::FilePath::FromUTF8Unsafe(path));
257 FileSystemURL DestURL(const std::string& path) {
258 return file_system_context_->CreateCrackedFileSystemURL(
259 origin_, dest_type_, base::FilePath::FromUTF8Unsafe(path));
262 base::File::Error Copy(const FileSystemURL& src,
263 const FileSystemURL& dest) {
264 return AsyncFileTestHelper::Copy(file_system_context_.get(), src, dest);
267 base::File::Error CopyWithProgress(
268 const FileSystemURL& src,
269 const FileSystemURL& dest,
270 const AsyncFileTestHelper::CopyProgressCallback& progress_callback) {
271 return AsyncFileTestHelper::CopyWithProgress(
272 file_system_context_.get(), src, dest, progress_callback);
275 base::File::Error Move(const FileSystemURL& src,
276 const FileSystemURL& dest) {
277 return AsyncFileTestHelper::Move(file_system_context_.get(), src, dest);
280 base::File::Error SetUpTestCaseFiles(
281 const FileSystemURL& root,
282 const FileSystemTestCaseRecord* const test_cases,
283 size_t test_case_size) {
284 base::File::Error result = base::File::FILE_ERROR_FAILED;
285 for (size_t i = 0; i < test_case_size; ++i) {
286 const FileSystemTestCaseRecord& test_case = test_cases[i];
287 FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL(
288 root.origin(),
289 root.mount_type(),
290 root.virtual_path().Append(test_case.path));
291 if (test_case.is_directory)
292 result = CreateDirectory(url);
293 else
294 result = CreateFile(url, test_case.data_file_size);
295 EXPECT_EQ(base::File::FILE_OK, result) << url.DebugString();
296 if (result != base::File::FILE_OK)
297 return result;
299 return result;
302 void VerifyTestCaseFiles(
303 const FileSystemURL& root,
304 const FileSystemTestCaseRecord* const test_cases,
305 size_t test_case_size) {
306 std::map<base::FilePath, const FileSystemTestCaseRecord*> test_case_map;
307 for (size_t i = 0; i < test_case_size; ++i) {
308 test_case_map[
309 base::FilePath(test_cases[i].path).NormalizePathSeparators()] =
310 &test_cases[i];
313 std::queue<FileSystemURL> directories;
314 FileEntryList entries;
315 directories.push(root);
316 while (!directories.empty()) {
317 FileSystemURL dir = directories.front();
318 directories.pop();
319 ASSERT_EQ(base::File::FILE_OK, ReadDirectory(dir, &entries));
320 for (size_t i = 0; i < entries.size(); ++i) {
321 FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL(
322 dir.origin(),
323 dir.mount_type(),
324 dir.virtual_path().Append(entries[i].name));
325 base::FilePath relative;
326 root.virtual_path().AppendRelativePath(url.virtual_path(), &relative);
327 relative = relative.NormalizePathSeparators();
328 ASSERT_TRUE(ContainsKey(test_case_map, relative));
329 if (entries[i].is_directory) {
330 EXPECT_TRUE(test_case_map[relative]->is_directory);
331 directories.push(url);
332 } else {
333 EXPECT_FALSE(test_case_map[relative]->is_directory);
334 EXPECT_TRUE(FileExists(url, test_case_map[relative]->data_file_size));
336 test_case_map.erase(relative);
339 EXPECT_TRUE(test_case_map.empty());
340 std::map<base::FilePath,
341 const FileSystemTestCaseRecord*>::const_iterator it;
342 for (it = test_case_map.begin(); it != test_case_map.end(); ++it) {
343 LOG(ERROR) << "Extra entry: " << it->first.LossyDisplayName();
347 base::File::Error ReadDirectory(const FileSystemURL& url,
348 FileEntryList* entries) {
349 return AsyncFileTestHelper::ReadDirectory(
350 file_system_context_.get(), url, entries);
353 base::File::Error CreateDirectory(const FileSystemURL& url) {
354 return AsyncFileTestHelper::CreateDirectory(file_system_context_.get(),
355 url);
358 base::File::Error CreateFile(const FileSystemURL& url, size_t size) {
359 base::File::Error result =
360 AsyncFileTestHelper::CreateFile(file_system_context_.get(), url);
361 if (result != base::File::FILE_OK)
362 return result;
363 return AsyncFileTestHelper::TruncateFile(
364 file_system_context_.get(), url, size);
367 bool FileExists(const FileSystemURL& url, int64 expected_size) {
368 return AsyncFileTestHelper::FileExists(
369 file_system_context_.get(), url, expected_size);
372 bool DirectoryExists(const FileSystemURL& url) {
373 return AsyncFileTestHelper::DirectoryExists(file_system_context_.get(),
374 url);
377 private:
378 void GetUsageAndQuota(storage::FileSystemType type,
379 int64* usage,
380 int64* quota) {
381 storage::QuotaStatusCode status = AsyncFileTestHelper::GetUsageAndQuota(
382 quota_manager_.get(), origin_, type, usage, quota);
383 ASSERT_EQ(storage::kQuotaStatusOk, status);
386 private:
387 base::ScopedTempDir base_;
389 const GURL origin_;
390 const storage::FileSystemType src_type_;
391 const storage::FileSystemType dest_type_;
393 base::MessageLoopForIO message_loop_;
394 scoped_refptr<storage::FileSystemContext> file_system_context_;
395 scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
396 scoped_refptr<MockQuotaManager> quota_manager_;
398 DISALLOW_COPY_AND_ASSIGN(CopyOrMoveOperationTestHelper);
401 TEST(LocalFileSystemCopyOrMoveOperationTest, CopySingleFile) {
402 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
403 storage::kFileSystemTypeTemporary,
404 storage::kFileSystemTypePersistent);
405 helper.SetUp();
407 FileSystemURL src = helper.SourceURL("a");
408 FileSystemURL dest = helper.DestURL("b");
409 int64 src_initial_usage = helper.GetSourceUsage();
410 int64 dest_initial_usage = helper.GetDestUsage();
412 // Set up a source file.
413 ASSERT_EQ(base::File::FILE_OK, helper.CreateFile(src, 10));
414 int64 src_increase = helper.GetSourceUsage() - src_initial_usage;
416 // Copy it.
417 ASSERT_EQ(base::File::FILE_OK, helper.Copy(src, dest));
419 // Verify.
420 ASSERT_TRUE(helper.FileExists(src, 10));
421 ASSERT_TRUE(helper.FileExists(dest, 10));
423 int64 src_new_usage = helper.GetSourceUsage();
424 ASSERT_EQ(src_initial_usage + src_increase, src_new_usage);
426 int64 dest_increase = helper.GetDestUsage() - dest_initial_usage;
427 ASSERT_EQ(src_increase, dest_increase);
430 TEST(LocalFileSystemCopyOrMoveOperationTest, MoveSingleFile) {
431 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
432 storage::kFileSystemTypeTemporary,
433 storage::kFileSystemTypePersistent);
434 helper.SetUp();
436 FileSystemURL src = helper.SourceURL("a");
437 FileSystemURL dest = helper.DestURL("b");
438 int64 src_initial_usage = helper.GetSourceUsage();
439 int64 dest_initial_usage = helper.GetDestUsage();
441 // Set up a source file.
442 ASSERT_EQ(base::File::FILE_OK, helper.CreateFile(src, 10));
443 int64 src_increase = helper.GetSourceUsage() - src_initial_usage;
445 // Move it.
446 ASSERT_EQ(base::File::FILE_OK, helper.Move(src, dest));
448 // Verify.
449 ASSERT_FALSE(helper.FileExists(src, AsyncFileTestHelper::kDontCheckSize));
450 ASSERT_TRUE(helper.FileExists(dest, 10));
452 int64 src_new_usage = helper.GetSourceUsage();
453 ASSERT_EQ(src_initial_usage, src_new_usage);
455 int64 dest_increase = helper.GetDestUsage() - dest_initial_usage;
456 ASSERT_EQ(src_increase, dest_increase);
459 TEST(LocalFileSystemCopyOrMoveOperationTest, CopySingleDirectory) {
460 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
461 storage::kFileSystemTypeTemporary,
462 storage::kFileSystemTypePersistent);
463 helper.SetUp();
465 FileSystemURL src = helper.SourceURL("a");
466 FileSystemURL dest = helper.DestURL("b");
467 int64 src_initial_usage = helper.GetSourceUsage();
468 int64 dest_initial_usage = helper.GetDestUsage();
470 // Set up a source directory.
471 ASSERT_EQ(base::File::FILE_OK, helper.CreateDirectory(src));
472 int64 src_increase = helper.GetSourceUsage() - src_initial_usage;
474 // Copy it.
475 ASSERT_EQ(base::File::FILE_OK, helper.Copy(src, dest));
477 // Verify.
478 ASSERT_TRUE(helper.DirectoryExists(src));
479 ASSERT_TRUE(helper.DirectoryExists(dest));
481 int64 src_new_usage = helper.GetSourceUsage();
482 ASSERT_EQ(src_initial_usage + src_increase, src_new_usage);
484 int64 dest_increase = helper.GetDestUsage() - dest_initial_usage;
485 ASSERT_EQ(src_increase, dest_increase);
488 TEST(LocalFileSystemCopyOrMoveOperationTest, MoveSingleDirectory) {
489 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
490 storage::kFileSystemTypeTemporary,
491 storage::kFileSystemTypePersistent);
492 helper.SetUp();
494 FileSystemURL src = helper.SourceURL("a");
495 FileSystemURL dest = helper.DestURL("b");
496 int64 src_initial_usage = helper.GetSourceUsage();
497 int64 dest_initial_usage = helper.GetDestUsage();
499 // Set up a source directory.
500 ASSERT_EQ(base::File::FILE_OK, helper.CreateDirectory(src));
501 int64 src_increase = helper.GetSourceUsage() - src_initial_usage;
503 // Move it.
504 ASSERT_EQ(base::File::FILE_OK, helper.Move(src, dest));
506 // Verify.
507 ASSERT_FALSE(helper.DirectoryExists(src));
508 ASSERT_TRUE(helper.DirectoryExists(dest));
510 int64 src_new_usage = helper.GetSourceUsage();
511 ASSERT_EQ(src_initial_usage, src_new_usage);
513 int64 dest_increase = helper.GetDestUsage() - dest_initial_usage;
514 ASSERT_EQ(src_increase, dest_increase);
517 TEST(LocalFileSystemCopyOrMoveOperationTest, CopyDirectory) {
518 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
519 storage::kFileSystemTypeTemporary,
520 storage::kFileSystemTypePersistent);
521 helper.SetUp();
523 FileSystemURL src = helper.SourceURL("a");
524 FileSystemURL dest = helper.DestURL("b");
525 int64 src_initial_usage = helper.GetSourceUsage();
526 int64 dest_initial_usage = helper.GetDestUsage();
528 // Set up a source directory.
529 ASSERT_EQ(base::File::FILE_OK, helper.CreateDirectory(src));
530 ASSERT_EQ(base::File::FILE_OK,
531 helper.SetUpTestCaseFiles(src,
532 kRegularFileSystemTestCases,
533 kRegularFileSystemTestCaseSize));
534 int64 src_increase = helper.GetSourceUsage() - src_initial_usage;
536 // Copy it.
537 ASSERT_EQ(base::File::FILE_OK,
538 helper.CopyWithProgress(
539 src, dest,
540 AsyncFileTestHelper::CopyProgressCallback()));
542 // Verify.
543 ASSERT_TRUE(helper.DirectoryExists(src));
544 ASSERT_TRUE(helper.DirectoryExists(dest));
546 helper.VerifyTestCaseFiles(dest,
547 kRegularFileSystemTestCases,
548 kRegularFileSystemTestCaseSize);
550 int64 src_new_usage = helper.GetSourceUsage();
551 ASSERT_EQ(src_initial_usage + src_increase, src_new_usage);
553 int64 dest_increase = helper.GetDestUsage() - dest_initial_usage;
554 ASSERT_EQ(src_increase, dest_increase);
557 TEST(LocalFileSystemCopyOrMoveOperationTest, MoveDirectory) {
558 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
559 storage::kFileSystemTypeTemporary,
560 storage::kFileSystemTypePersistent);
561 helper.SetUp();
563 FileSystemURL src = helper.SourceURL("a");
564 FileSystemURL dest = helper.DestURL("b");
565 int64 src_initial_usage = helper.GetSourceUsage();
566 int64 dest_initial_usage = helper.GetDestUsage();
568 // Set up a source directory.
569 ASSERT_EQ(base::File::FILE_OK, helper.CreateDirectory(src));
570 ASSERT_EQ(base::File::FILE_OK,
571 helper.SetUpTestCaseFiles(src,
572 kRegularFileSystemTestCases,
573 kRegularFileSystemTestCaseSize));
574 int64 src_increase = helper.GetSourceUsage() - src_initial_usage;
576 // Move it.
577 ASSERT_EQ(base::File::FILE_OK, helper.Move(src, dest));
579 // Verify.
580 ASSERT_FALSE(helper.DirectoryExists(src));
581 ASSERT_TRUE(helper.DirectoryExists(dest));
583 helper.VerifyTestCaseFiles(dest,
584 kRegularFileSystemTestCases,
585 kRegularFileSystemTestCaseSize);
587 int64 src_new_usage = helper.GetSourceUsage();
588 ASSERT_EQ(src_initial_usage, src_new_usage);
590 int64 dest_increase = helper.GetDestUsage() - dest_initial_usage;
591 ASSERT_EQ(src_increase, dest_increase);
594 TEST(LocalFileSystemCopyOrMoveOperationTest,
595 MoveDirectoryFailPostWriteValidation) {
596 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
597 storage::kFileSystemTypeTemporary,
598 storage::kFileSystemTypeTest);
599 helper.SetUp();
601 FileSystemURL src = helper.SourceURL("a");
602 FileSystemURL dest = helper.DestURL("b");
604 // Set up a source directory.
605 ASSERT_EQ(base::File::FILE_OK, helper.CreateDirectory(src));
606 ASSERT_EQ(base::File::FILE_OK,
607 helper.SetUpTestCaseFiles(src,
608 kRegularFileSystemTestCases,
609 kRegularFileSystemTestCaseSize));
611 // Move it.
612 helper.Move(src, dest);
614 // Verify.
615 ASSERT_TRUE(helper.DirectoryExists(src));
616 ASSERT_TRUE(helper.DirectoryExists(dest));
618 FileSystemTestCaseRecord kMoveDirResultCases[] = {
619 {false, FILE_PATH_LITERAL("file 0"), 38},
620 {false, FILE_PATH_LITERAL("file 3"), 0},
623 helper.VerifyTestCaseFiles(dest,
624 kMoveDirResultCases,
625 arraysize(kMoveDirResultCases));
628 TEST(LocalFileSystemCopyOrMoveOperationTest, CopySingleFileNoValidator) {
629 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
630 storage::kFileSystemTypeTemporary,
631 storage::kFileSystemTypeTest);
632 helper.SetUpNoValidator();
634 FileSystemURL src = helper.SourceURL("a");
635 FileSystemURL dest = helper.DestURL("b");
637 // Set up a source file.
638 ASSERT_EQ(base::File::FILE_OK, helper.CreateFile(src, 10));
640 // The copy attempt should fail with a security error -- getting
641 // the factory returns a security error, and the copy operation must
642 // respect that.
643 ASSERT_EQ(base::File::FILE_ERROR_SECURITY, helper.Copy(src, dest));
646 TEST(LocalFileSystemCopyOrMoveOperationTest, ProgressCallback) {
647 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
648 storage::kFileSystemTypeTemporary,
649 storage::kFileSystemTypePersistent);
650 helper.SetUp();
652 FileSystemURL src = helper.SourceURL("a");
653 FileSystemURL dest = helper.DestURL("b");
655 // Set up a source directory.
656 ASSERT_EQ(base::File::FILE_OK, helper.CreateDirectory(src));
657 ASSERT_EQ(base::File::FILE_OK,
658 helper.SetUpTestCaseFiles(src,
659 kRegularFileSystemTestCases,
660 kRegularFileSystemTestCaseSize));
662 std::vector<ProgressRecord> records;
663 ASSERT_EQ(base::File::FILE_OK,
664 helper.CopyWithProgress(src, dest,
665 base::Bind(&RecordProgressCallback,
666 base::Unretained(&records))));
668 // Verify progress callback.
669 for (size_t i = 0; i < kRegularFileSystemTestCaseSize; ++i) {
670 const FileSystemTestCaseRecord& test_case = kRegularFileSystemTestCases[i];
672 FileSystemURL src_url = helper.SourceURL(
673 std::string("a/") + base::FilePath(test_case.path).AsUTF8Unsafe());
674 FileSystemURL dest_url = helper.DestURL(
675 std::string("b/") + base::FilePath(test_case.path).AsUTF8Unsafe());
677 // Find the first and last progress record.
678 size_t begin_index = records.size();
679 size_t end_index = records.size();
680 for (size_t j = 0; j < records.size(); ++j) {
681 if (records[j].source_url == src_url) {
682 if (begin_index == records.size())
683 begin_index = j;
684 end_index = j;
688 // The record should be found.
689 ASSERT_NE(begin_index, records.size());
690 ASSERT_NE(end_index, records.size());
691 ASSERT_NE(begin_index, end_index);
693 EXPECT_EQ(FileSystemOperation::BEGIN_COPY_ENTRY,
694 records[begin_index].type);
695 EXPECT_FALSE(records[begin_index].dest_url.is_valid());
696 EXPECT_EQ(FileSystemOperation::END_COPY_ENTRY, records[end_index].type);
697 EXPECT_EQ(dest_url, records[end_index].dest_url);
699 if (test_case.is_directory) {
700 // For directory copy, the progress shouldn't be interlaced.
701 EXPECT_EQ(begin_index + 1, end_index);
702 } else {
703 // PROGRESS event's size should be assending order.
704 int64 current_size = 0;
705 for (size_t j = begin_index + 1; j < end_index; ++j) {
706 if (records[j].source_url == src_url) {
707 EXPECT_EQ(FileSystemOperation::PROGRESS, records[j].type);
708 EXPECT_FALSE(records[j].dest_url.is_valid());
709 EXPECT_GE(records[j].size, current_size);
710 current_size = records[j].size;
717 TEST(LocalFileSystemCopyOrMoveOperationTest, StreamCopyHelper) {
718 base::ScopedTempDir temp_dir;
719 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
720 base::FilePath source_path = temp_dir.path().AppendASCII("source");
721 base::FilePath dest_path = temp_dir.path().AppendASCII("dest");
722 const char kTestData[] = "abcdefghijklmnopqrstuvwxyz0123456789";
723 base::WriteFile(source_path, kTestData,
724 arraysize(kTestData) - 1); // Exclude trailing '\0'.
726 base::MessageLoopForIO message_loop;
727 base::Thread file_thread("file_thread");
728 ASSERT_TRUE(file_thread.Start());
729 ScopedThreadStopper thread_stopper(&file_thread);
730 ASSERT_TRUE(thread_stopper.is_valid());
732 scoped_refptr<base::SingleThreadTaskRunner> task_runner =
733 file_thread.task_runner();
735 scoped_ptr<storage::FileStreamReader> reader(
736 storage::FileStreamReader::CreateForLocalFile(
737 task_runner.get(), source_path, 0, base::Time()));
739 scoped_ptr<FileStreamWriter> writer(FileStreamWriter::CreateForLocalFile(
740 task_runner.get(), dest_path, 0, FileStreamWriter::CREATE_NEW_FILE));
742 std::vector<int64> progress;
743 CopyOrMoveOperationDelegate::StreamCopyHelper helper(
744 reader.Pass(), writer.Pass(),
745 storage::FlushPolicy::NO_FLUSH_ON_COMPLETION,
746 10, // buffer size
747 base::Bind(&RecordFileProgressCallback, base::Unretained(&progress)),
748 base::TimeDelta()); // For testing, we need all the progress.
750 base::File::Error error = base::File::FILE_ERROR_FAILED;
751 base::RunLoop run_loop;
752 helper.Run(base::Bind(&AssignAndQuit, &run_loop, &error));
753 run_loop.Run();
755 EXPECT_EQ(base::File::FILE_OK, error);
756 ASSERT_EQ(5U, progress.size());
757 EXPECT_EQ(0, progress[0]);
758 EXPECT_EQ(10, progress[1]);
759 EXPECT_EQ(20, progress[2]);
760 EXPECT_EQ(30, progress[3]);
761 EXPECT_EQ(36, progress[4]);
763 std::string content;
764 ASSERT_TRUE(base::ReadFileToString(dest_path, &content));
765 EXPECT_EQ(kTestData, content);
768 TEST(LocalFileSystemCopyOrMoveOperationTest, StreamCopyHelperWithFlush) {
769 // Testing the same configuration as StreamCopyHelper, but with |need_flush|
770 // parameter set to true. Since it is hard to test that the flush is indeed
771 // taking place, this test just only verifies that the file is correctly
772 // written with or without the flag.
773 base::ScopedTempDir temp_dir;
774 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
775 base::FilePath source_path = temp_dir.path().AppendASCII("source");
776 base::FilePath dest_path = temp_dir.path().AppendASCII("dest");
777 const char kTestData[] = "abcdefghijklmnopqrstuvwxyz0123456789";
778 base::WriteFile(source_path, kTestData,
779 arraysize(kTestData) - 1); // Exclude trailing '\0'.
782 base::MessageLoopForIO message_loop;
783 base::Thread file_thread("file_thread");
784 ASSERT_TRUE(file_thread.Start());
785 ScopedThreadStopper thread_stopper(&file_thread);
786 ASSERT_TRUE(thread_stopper.is_valid());
788 scoped_refptr<base::SingleThreadTaskRunner> task_runner =
789 file_thread.task_runner();
791 scoped_ptr<storage::FileStreamReader> reader(
792 storage::FileStreamReader::CreateForLocalFile(
793 task_runner.get(), source_path, 0, base::Time()));
795 scoped_ptr<FileStreamWriter> writer(FileStreamWriter::CreateForLocalFile(
796 task_runner.get(), dest_path, 0, FileStreamWriter::CREATE_NEW_FILE));
798 std::vector<int64> progress;
799 CopyOrMoveOperationDelegate::StreamCopyHelper helper(
800 reader.Pass(), writer.Pass(),
801 storage::FlushPolicy::NO_FLUSH_ON_COMPLETION,
802 10, // buffer size
803 base::Bind(&RecordFileProgressCallback, base::Unretained(&progress)),
804 base::TimeDelta()); // For testing, we need all the progress.
806 base::File::Error error = base::File::FILE_ERROR_FAILED;
807 base::RunLoop run_loop;
808 helper.Run(base::Bind(&AssignAndQuit, &run_loop, &error));
809 run_loop.Run();
811 EXPECT_EQ(base::File::FILE_OK, error);
812 ASSERT_EQ(5U, progress.size());
813 EXPECT_EQ(0, progress[0]);
814 EXPECT_EQ(10, progress[1]);
815 EXPECT_EQ(20, progress[2]);
816 EXPECT_EQ(30, progress[3]);
817 EXPECT_EQ(36, progress[4]);
819 std::string content;
820 ASSERT_TRUE(base::ReadFileToString(dest_path, &content));
821 EXPECT_EQ(kTestData, content);
824 TEST(LocalFileSystemCopyOrMoveOperationTest, StreamCopyHelper_Cancel) {
825 base::ScopedTempDir temp_dir;
826 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
827 base::FilePath source_path = temp_dir.path().AppendASCII("source");
828 base::FilePath dest_path = temp_dir.path().AppendASCII("dest");
829 const char kTestData[] = "abcdefghijklmnopqrstuvwxyz0123456789";
830 base::WriteFile(source_path, kTestData,
831 arraysize(kTestData) - 1); // Exclude trailing '\0'.
833 base::MessageLoopForIO message_loop;
834 base::Thread file_thread("file_thread");
835 ASSERT_TRUE(file_thread.Start());
836 ScopedThreadStopper thread_stopper(&file_thread);
837 ASSERT_TRUE(thread_stopper.is_valid());
839 scoped_refptr<base::SingleThreadTaskRunner> task_runner =
840 file_thread.task_runner();
842 scoped_ptr<storage::FileStreamReader> reader(
843 storage::FileStreamReader::CreateForLocalFile(
844 task_runner.get(), source_path, 0, base::Time()));
846 scoped_ptr<FileStreamWriter> writer(FileStreamWriter::CreateForLocalFile(
847 task_runner.get(), dest_path, 0, FileStreamWriter::CREATE_NEW_FILE));
849 std::vector<int64> progress;
850 CopyOrMoveOperationDelegate::StreamCopyHelper helper(
851 reader.Pass(), writer.Pass(),
852 storage::FlushPolicy::NO_FLUSH_ON_COMPLETION,
853 10, // buffer size
854 base::Bind(&RecordFileProgressCallback, base::Unretained(&progress)),
855 base::TimeDelta()); // For testing, we need all the progress.
857 // Call Cancel() later.
858 base::ThreadTaskRunnerHandle::Get()->PostTask(
859 FROM_HERE,
860 base::Bind(&CopyOrMoveOperationDelegate::StreamCopyHelper::Cancel,
861 base::Unretained(&helper)));
863 base::File::Error error = base::File::FILE_ERROR_FAILED;
864 base::RunLoop run_loop;
865 helper.Run(base::Bind(&AssignAndQuit, &run_loop, &error));
866 run_loop.Run();
868 EXPECT_EQ(base::File::FILE_ERROR_ABORT, error);
871 } // namespace content