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/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
;
42 typedef storage::FileSystemOperation::FileEntryList FileEntryList
;
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
{
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"));
66 class TestValidator
: public storage::CopyOrMoveFileValidator
{
68 explicit TestValidator(bool pre_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
));
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
;
116 void RecordProgressCallback(std::vector
<ProgressRecord
>* records
,
117 storage::FileSystemOperation::CopyProgressType type
,
118 const FileSystemURL
& source_url
,
119 const FileSystemURL
& dest_url
,
121 ProgressRecord record
;
123 record
.source_url
= source_url
;
124 record
.dest_url
= dest_url
;
126 records
->push_back(record
);
129 void RecordFileProgressCallback(std::vector
<int64
>* records
,
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
;
141 class ScopedThreadStopper
{
143 ScopedThreadStopper(base::Thread
* thread
) : thread_(thread
) {
146 ~ScopedThreadStopper() {
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());
157 bool is_valid() const { return thread_
; }
160 base::Thread
* thread_
;
161 DISALLOW_COPY_AND_ASSIGN(ScopedThreadStopper
);
166 class CopyOrMoveOperationTestHelper
{
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();
185 void SetUpNoValidator() {
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();
194 new MockQuotaManager(false /* is_incognito */,
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_
);
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());
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(
231 storage::FileSystemTypeToQuotaStorageType(src_type_
),
233 quota_manager_
->SetQuota(
235 storage::FileSystemTypeToQuotaStorageType(dest_type_
),
239 int64
GetSourceUsage() {
241 GetUsageAndQuota(src_type_
, &usage
, NULL
);
245 int64
GetDestUsage() {
247 GetUsageAndQuota(dest_type_
, &usage
, NULL
);
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(
289 root
.virtual_path().Append(test_case
.path
));
290 if (test_case
.is_directory
)
291 result
= CreateDirectory(url
);
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
)
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
) {
308 base::FilePath(test_cases
[i
].path
).NormalizePathSeparators()] =
312 std::queue
<FileSystemURL
> directories
;
313 FileEntryList entries
;
314 directories
.push(root
);
315 while (!directories
.empty()) {
316 FileSystemURL dir
= directories
.front();
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(
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
);
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(),
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
)
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(),
377 void GetUsageAndQuota(storage::FileSystemType type
,
380 storage::QuotaStatusCode status
= AsyncFileTestHelper::GetUsageAndQuota(
381 quota_manager_
.get(), origin_
, type
, usage
, quota
);
382 ASSERT_EQ(storage::kQuotaStatusOk
, status
);
386 base::ScopedTempDir base_
;
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
);
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
;
416 ASSERT_EQ(base::File::FILE_OK
, helper
.Copy(src
, dest
));
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
);
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
;
445 ASSERT_EQ(base::File::FILE_OK
, helper
.Move(src
, dest
));
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
);
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
;
474 ASSERT_EQ(base::File::FILE_OK
, helper
.Copy(src
, dest
));
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
);
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
;
503 ASSERT_EQ(base::File::FILE_OK
, helper
.Move(src
, dest
));
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
);
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
;
536 ASSERT_EQ(base::File::FILE_OK
,
537 helper
.CopyWithProgress(
539 AsyncFileTestHelper::CopyProgressCallback()));
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
);
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
;
576 ASSERT_EQ(base::File::FILE_OK
, helper
.Move(src
, dest
));
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
);
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
));
611 helper
.Move(src
, dest
);
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
,
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
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
);
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())
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
);
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
,
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
));
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]);
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
,
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
));
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]);
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
,
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(
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
));
867 EXPECT_EQ(base::File::FILE_ERROR_ABORT
, error
);
870 } // namespace content