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/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
;
41 typedef storage::FileSystemOperation::FileEntryList FileEntryList
;
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
{
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"));
65 class TestValidator
: public storage::CopyOrMoveFileValidator
{
67 explicit TestValidator(bool pre_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
));
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
;
115 void RecordProgressCallback(std::vector
<ProgressRecord
>* records
,
116 storage::FileSystemOperation::CopyProgressType type
,
117 const FileSystemURL
& source_url
,
118 const FileSystemURL
& dest_url
,
120 ProgressRecord record
;
122 record
.source_url
= source_url
;
123 record
.dest_url
= dest_url
;
125 records
->push_back(record
);
128 void RecordFileProgressCallback(std::vector
<int64
>* records
,
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
;
140 class ScopedThreadStopper
{
142 ScopedThreadStopper(base::Thread
* thread
) : thread_(thread
) {
145 ~ScopedThreadStopper() {
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());
156 bool is_valid() const { return thread_
; }
159 base::Thread
* thread_
;
160 DISALLOW_COPY_AND_ASSIGN(ScopedThreadStopper
);
165 class CopyOrMoveOperationTestHelper
{
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();
184 void SetUpNoValidator() {
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();
193 new MockQuotaManager(false /* is_incognito */,
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_
);
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());
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(
230 storage::FileSystemTypeToQuotaStorageType(src_type_
),
232 quota_manager_
->SetQuota(
234 storage::FileSystemTypeToQuotaStorageType(dest_type_
),
238 int64
GetSourceUsage() {
240 GetUsageAndQuota(src_type_
, &usage
, NULL
);
244 int64
GetDestUsage() {
246 GetUsageAndQuota(dest_type_
, &usage
, NULL
);
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(
288 root
.virtual_path().Append(test_case
.path
));
289 if (test_case
.is_directory
)
290 result
= CreateDirectory(url
);
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
)
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
) {
307 base::FilePath(test_cases
[i
].path
).NormalizePathSeparators()] =
311 std::queue
<FileSystemURL
> directories
;
312 FileEntryList entries
;
313 directories
.push(root
);
314 while (!directories
.empty()) {
315 FileSystemURL dir
= directories
.front();
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(
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
);
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(),
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
)
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(),
376 void GetUsageAndQuota(storage::FileSystemType type
,
379 storage::QuotaStatusCode status
= AsyncFileTestHelper::GetUsageAndQuota(
380 quota_manager_
.get(), origin_
, type
, usage
, quota
);
381 ASSERT_EQ(storage::kQuotaStatusOk
, status
);
385 base::ScopedTempDir base_
;
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
);
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
;
415 ASSERT_EQ(base::File::FILE_OK
, helper
.Copy(src
, dest
));
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
);
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
;
444 ASSERT_EQ(base::File::FILE_OK
, helper
.Move(src
, dest
));
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
);
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
;
473 ASSERT_EQ(base::File::FILE_OK
, helper
.Copy(src
, dest
));
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
);
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
;
502 ASSERT_EQ(base::File::FILE_OK
, helper
.Move(src
, dest
));
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
);
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
;
535 ASSERT_EQ(base::File::FILE_OK
,
536 helper
.CopyWithProgress(
538 AsyncFileTestHelper::CopyProgressCallback()));
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
);
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
;
575 ASSERT_EQ(base::File::FILE_OK
, helper
.Move(src
, dest
));
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
);
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
));
610 helper
.Move(src
, dest
);
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
,
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
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
);
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())
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
);
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
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
));
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]);
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(),
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
));
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]);
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(),
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(
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
));
866 EXPECT_EQ(base::File::FILE_ERROR_ABORT
, error
);
869 } // namespace content