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.
8 #include "base/basictypes.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
;
44 typedef storage::FileSystemOperation::FileEntryList FileEntryList
;
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
{
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"));
68 class TestValidator
: public storage::CopyOrMoveFileValidator
{
70 explicit TestValidator(bool pre_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
));
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
;
118 void RecordProgressCallback(std::vector
<ProgressRecord
>* records
,
119 storage::FileSystemOperation::CopyProgressType type
,
120 const FileSystemURL
& source_url
,
121 const FileSystemURL
& dest_url
,
123 ProgressRecord record
;
125 record
.source_url
= source_url
;
126 record
.dest_url
= dest_url
;
128 records
->push_back(record
);
131 void RecordFileProgressCallback(std::vector
<int64
>* records
,
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
;
143 class ScopedThreadStopper
{
145 ScopedThreadStopper(base::Thread
* thread
) : thread_(thread
) {
148 ~ScopedThreadStopper() {
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());
159 bool is_valid() const { return thread_
; }
162 base::Thread
* thread_
;
163 DISALLOW_COPY_AND_ASSIGN(ScopedThreadStopper
);
168 class CopyOrMoveOperationTestHelper
{
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();
187 void SetUpNoValidator() {
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();
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_
);
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());
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(
232 storage::FileSystemTypeToQuotaStorageType(src_type_
),
234 quota_manager_
->SetQuota(
236 storage::FileSystemTypeToQuotaStorageType(dest_type_
),
240 int64
GetSourceUsage() {
242 GetUsageAndQuota(src_type_
, &usage
, NULL
);
246 int64
GetDestUsage() {
248 GetUsageAndQuota(dest_type_
, &usage
, NULL
);
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(
290 root
.virtual_path().Append(test_case
.path
));
291 if (test_case
.is_directory
)
292 result
= CreateDirectory(url
);
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
)
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
) {
309 base::FilePath(test_cases
[i
].path
).NormalizePathSeparators()] =
313 std::queue
<FileSystemURL
> directories
;
314 FileEntryList entries
;
315 directories
.push(root
);
316 while (!directories
.empty()) {
317 FileSystemURL dir
= directories
.front();
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(
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
);
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(),
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
)
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(),
378 void GetUsageAndQuota(storage::FileSystemType type
,
381 storage::QuotaStatusCode status
= AsyncFileTestHelper::GetUsageAndQuota(
382 quota_manager_
.get(), origin_
, type
, usage
, quota
);
383 ASSERT_EQ(storage::kQuotaStatusOk
, status
);
387 base::ScopedTempDir base_
;
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
);
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
;
417 ASSERT_EQ(base::File::FILE_OK
, helper
.Copy(src
, dest
));
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
);
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
;
446 ASSERT_EQ(base::File::FILE_OK
, helper
.Move(src
, dest
));
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
);
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
;
475 ASSERT_EQ(base::File::FILE_OK
, helper
.Copy(src
, dest
));
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
);
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
;
504 ASSERT_EQ(base::File::FILE_OK
, helper
.Move(src
, dest
));
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
);
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
;
537 ASSERT_EQ(base::File::FILE_OK
,
538 helper
.CopyWithProgress(
540 AsyncFileTestHelper::CopyProgressCallback()));
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
);
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
;
577 ASSERT_EQ(base::File::FILE_OK
, helper
.Move(src
, dest
));
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
);
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
));
612 helper
.Move(src
, dest
);
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
,
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
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
);
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())
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
);
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
,
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
));
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]);
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
,
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
));
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]);
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
,
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(
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
));
868 EXPECT_EQ(base::File::FILE_ERROR_ABORT
, error
);
871 } // namespace content