Cast: Skip receiver log messages with time delta that can't be encoded.
[chromium-blink-merge.git] / content / browser / fileapi / copy_or_move_operation_delegate_unittest.cc
blobcdbc55318b2440ec6681293d2604b6173d3d6322
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/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/public/test/async_file_test_helper.h"
16 #include "content/public/test/test_file_system_backend.h"
17 #include "content/public/test/test_file_system_context.h"
18 #include "content/test/fileapi_test_file_set.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 #include "webkit/browser/blob/file_stream_reader.h"
21 #include "webkit/browser/fileapi/copy_or_move_file_validator.h"
22 #include "webkit/browser/fileapi/copy_or_move_operation_delegate.h"
23 #include "webkit/browser/fileapi/file_stream_writer.h"
24 #include "webkit/browser/fileapi/file_system_backend.h"
25 #include "webkit/browser/fileapi/file_system_context.h"
26 #include "webkit/browser/fileapi/file_system_operation.h"
27 #include "webkit/browser/fileapi/file_system_url.h"
28 #include "webkit/browser/quota/mock_quota_manager.h"
29 #include "webkit/browser/quota/mock_quota_manager_proxy.h"
30 #include "webkit/browser/quota/quota_manager.h"
31 #include "webkit/common/fileapi/file_system_util.h"
33 using content::AsyncFileTestHelper;
34 using fileapi::CopyOrMoveOperationDelegate;
35 using fileapi::FileStreamWriter;
36 using fileapi::FileSystemOperation;
37 using fileapi::FileSystemType;
38 using fileapi::FileSystemURL;
40 namespace content {
42 typedef fileapi::FileSystemOperation::FileEntryList FileEntryList;
44 namespace {
46 void ExpectOk(const GURL& origin_url,
47 const std::string& name,
48 base::File::Error error) {
49 ASSERT_EQ(base::File::FILE_OK, error);
52 class TestValidatorFactory : public fileapi::CopyOrMoveFileValidatorFactory {
53 public:
54 // A factory that creates validators that accept everything or nothing.
55 TestValidatorFactory() {}
56 virtual ~TestValidatorFactory() {}
58 virtual fileapi::CopyOrMoveFileValidator* CreateCopyOrMoveFileValidator(
59 const FileSystemURL& /*src_url*/,
60 const base::FilePath& /*platform_path*/) OVERRIDE {
61 // Move arg management to TestValidator?
62 return new TestValidator(true, true, std::string("2"));
65 private:
66 class TestValidator : public fileapi::CopyOrMoveFileValidator {
67 public:
68 explicit TestValidator(bool pre_copy_valid,
69 bool post_copy_valid,
70 const std::string& reject_string)
71 : result_(pre_copy_valid ? base::File::FILE_OK :
72 base::File::FILE_ERROR_SECURITY),
73 write_result_(post_copy_valid ? base::File::FILE_OK :
74 base::File::FILE_ERROR_SECURITY),
75 reject_string_(reject_string) {
77 virtual ~TestValidator() {}
79 virtual 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 virtual void StartPostWriteValidation(
87 const base::FilePath& dest_platform_path,
88 const ResultCallback& result_callback) OVERRIDE {
89 base::File::Error result = write_result_;
90 std::string unsafe = dest_platform_path.BaseName().AsUTF8Unsafe();
91 if (unsafe.find(reject_string_) != std::string::npos) {
92 result = base::File::FILE_ERROR_SECURITY;
94 // Post the result since a real validator must do work asynchronously.
95 base::MessageLoop::current()->PostTask(
96 FROM_HERE, base::Bind(result_callback, result));
99 private:
100 base::File::Error result_;
101 base::File::Error write_result_;
102 std::string reject_string_;
104 DISALLOW_COPY_AND_ASSIGN(TestValidator);
108 // Records CopyProgressCallback invocations.
109 struct ProgressRecord {
110 fileapi::FileSystemOperation::CopyProgressType type;
111 FileSystemURL source_url;
112 FileSystemURL dest_url;
113 int64 size;
116 void RecordProgressCallback(std::vector<ProgressRecord>* records,
117 fileapi::FileSystemOperation::CopyProgressType type,
118 const FileSystemURL& source_url,
119 const FileSystemURL& dest_url,
120 int64 size) {
121 ProgressRecord record;
122 record.type = type;
123 record.source_url = source_url;
124 record.dest_url = dest_url;
125 record.size = size;
126 records->push_back(record);
129 void RecordFileProgressCallback(std::vector<int64>* records,
130 int64 progress) {
131 records->push_back(progress);
134 void AssignAndQuit(base::RunLoop* run_loop,
135 base::File::Error* result_out,
136 base::File::Error result) {
137 *result_out = result;
138 run_loop->Quit();
141 class ScopedThreadStopper {
142 public:
143 ScopedThreadStopper(base::Thread* thread) : thread_(thread) {
146 ~ScopedThreadStopper() {
147 if (thread_) {
148 // Give another chance for deleted streams to perform Close.
149 base::RunLoop run_loop;
150 thread_->message_loop_proxy()->PostTaskAndReply(
151 FROM_HERE, base::Bind(&base::DoNothing), run_loop.QuitClosure());
152 run_loop.Run();
153 thread_->Stop();
157 bool is_valid() const { return thread_; }
159 private:
160 base::Thread* thread_;
161 DISALLOW_COPY_AND_ASSIGN(ScopedThreadStopper);
164 } // namespace
166 class CopyOrMoveOperationTestHelper {
167 public:
168 CopyOrMoveOperationTestHelper(
169 const GURL& origin,
170 FileSystemType src_type,
171 FileSystemType dest_type)
172 : origin_(origin),
173 src_type_(src_type),
174 dest_type_(dest_type) {}
176 ~CopyOrMoveOperationTestHelper() {
177 file_system_context_ = NULL;
178 quota_manager_proxy_->SimulateQuotaManagerDestroyed();
179 quota_manager_ = NULL;
180 quota_manager_proxy_ = NULL;
181 base::RunLoop().RunUntilIdle();
184 void SetUp() {
185 SetUp(true, true);
188 void SetUpNoValidator() {
189 SetUp(true, false);
192 void SetUp(bool require_copy_or_move_validator,
193 bool init_copy_or_move_validator) {
194 ASSERT_TRUE(base_.CreateUniqueTempDir());
195 base::FilePath base_dir = base_.path();
196 quota_manager_ =
197 new quota::MockQuotaManager(false /* is_incognito */,
198 base_dir,
199 base::MessageLoopProxy::current().get(),
200 base::MessageLoopProxy::current().get(),
201 NULL /* special storage policy */);
202 quota_manager_proxy_ = new quota::MockQuotaManagerProxy(
203 quota_manager_.get(), base::MessageLoopProxy::current().get());
204 file_system_context_ =
205 CreateFileSystemContextForTesting(quota_manager_proxy_.get(), base_dir);
207 // Prepare the origin's root directory.
208 fileapi::FileSystemBackend* backend =
209 file_system_context_->GetFileSystemBackend(src_type_);
210 backend->ResolveURL(
211 FileSystemURL::CreateForTest(origin_, src_type_, base::FilePath()),
212 fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
213 base::Bind(&ExpectOk));
214 backend = file_system_context_->GetFileSystemBackend(dest_type_);
215 if (dest_type_ == fileapi::kFileSystemTypeTest) {
216 TestFileSystemBackend* test_backend =
217 static_cast<TestFileSystemBackend*>(backend);
218 scoped_ptr<fileapi::CopyOrMoveFileValidatorFactory> factory(
219 new TestValidatorFactory);
220 test_backend->set_require_copy_or_move_validator(
221 require_copy_or_move_validator);
222 if (init_copy_or_move_validator)
223 test_backend->InitializeCopyOrMoveFileValidatorFactory(factory.Pass());
225 backend->ResolveURL(
226 FileSystemURL::CreateForTest(origin_, dest_type_, base::FilePath()),
227 fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
228 base::Bind(&ExpectOk));
229 base::RunLoop().RunUntilIdle();
231 // Grant relatively big quota initially.
232 quota_manager_->SetQuota(
233 origin_,
234 fileapi::FileSystemTypeToQuotaStorageType(src_type_),
235 1024 * 1024);
236 quota_manager_->SetQuota(
237 origin_,
238 fileapi::FileSystemTypeToQuotaStorageType(dest_type_),
239 1024 * 1024);
242 int64 GetSourceUsage() {
243 int64 usage = 0;
244 GetUsageAndQuota(src_type_, &usage, NULL);
245 return usage;
248 int64 GetDestUsage() {
249 int64 usage = 0;
250 GetUsageAndQuota(dest_type_, &usage, NULL);
251 return usage;
254 FileSystemURL SourceURL(const std::string& path) {
255 return file_system_context_->CreateCrackedFileSystemURL(
256 origin_, src_type_, base::FilePath::FromUTF8Unsafe(path));
259 FileSystemURL DestURL(const std::string& path) {
260 return file_system_context_->CreateCrackedFileSystemURL(
261 origin_, dest_type_, base::FilePath::FromUTF8Unsafe(path));
264 base::File::Error Copy(const FileSystemURL& src,
265 const FileSystemURL& dest) {
266 return AsyncFileTestHelper::Copy(file_system_context_.get(), src, dest);
269 base::File::Error CopyWithProgress(
270 const FileSystemURL& src,
271 const FileSystemURL& dest,
272 const AsyncFileTestHelper::CopyProgressCallback& progress_callback) {
273 return AsyncFileTestHelper::CopyWithProgress(
274 file_system_context_.get(), src, dest, progress_callback);
277 base::File::Error Move(const FileSystemURL& src,
278 const FileSystemURL& dest) {
279 return AsyncFileTestHelper::Move(file_system_context_.get(), src, dest);
282 base::File::Error SetUpTestCaseFiles(
283 const FileSystemURL& root,
284 const FileSystemTestCaseRecord* const test_cases,
285 size_t test_case_size) {
286 base::File::Error result = base::File::FILE_ERROR_FAILED;
287 for (size_t i = 0; i < test_case_size; ++i) {
288 const FileSystemTestCaseRecord& test_case = test_cases[i];
289 FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL(
290 root.origin(),
291 root.mount_type(),
292 root.virtual_path().Append(test_case.path));
293 if (test_case.is_directory)
294 result = CreateDirectory(url);
295 else
296 result = CreateFile(url, test_case.data_file_size);
297 EXPECT_EQ(base::File::FILE_OK, result) << url.DebugString();
298 if (result != base::File::FILE_OK)
299 return result;
301 return result;
304 void VerifyTestCaseFiles(
305 const FileSystemURL& root,
306 const FileSystemTestCaseRecord* const test_cases,
307 size_t test_case_size) {
308 std::map<base::FilePath, const FileSystemTestCaseRecord*> test_case_map;
309 for (size_t i = 0; i < test_case_size; ++i) {
310 test_case_map[
311 base::FilePath(test_cases[i].path).NormalizePathSeparators()] =
312 &test_cases[i];
315 std::queue<FileSystemURL> directories;
316 FileEntryList entries;
317 directories.push(root);
318 while (!directories.empty()) {
319 FileSystemURL dir = directories.front();
320 directories.pop();
321 ASSERT_EQ(base::File::FILE_OK, ReadDirectory(dir, &entries));
322 for (size_t i = 0; i < entries.size(); ++i) {
323 FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL(
324 dir.origin(),
325 dir.mount_type(),
326 dir.virtual_path().Append(entries[i].name));
327 base::FilePath relative;
328 root.virtual_path().AppendRelativePath(url.virtual_path(), &relative);
329 relative = relative.NormalizePathSeparators();
330 ASSERT_TRUE(ContainsKey(test_case_map, relative));
331 if (entries[i].is_directory) {
332 EXPECT_TRUE(test_case_map[relative]->is_directory);
333 directories.push(url);
334 } else {
335 EXPECT_FALSE(test_case_map[relative]->is_directory);
336 EXPECT_TRUE(FileExists(url, test_case_map[relative]->data_file_size));
338 test_case_map.erase(relative);
341 EXPECT_TRUE(test_case_map.empty());
342 std::map<base::FilePath,
343 const FileSystemTestCaseRecord*>::const_iterator it;
344 for (it = test_case_map.begin(); it != test_case_map.end(); ++it) {
345 LOG(ERROR) << "Extra entry: " << it->first.LossyDisplayName();
349 base::File::Error ReadDirectory(const FileSystemURL& url,
350 FileEntryList* entries) {
351 return AsyncFileTestHelper::ReadDirectory(
352 file_system_context_.get(), url, entries);
355 base::File::Error CreateDirectory(const FileSystemURL& url) {
356 return AsyncFileTestHelper::CreateDirectory(file_system_context_.get(),
357 url);
360 base::File::Error CreateFile(const FileSystemURL& url, size_t size) {
361 base::File::Error result =
362 AsyncFileTestHelper::CreateFile(file_system_context_.get(), url);
363 if (result != base::File::FILE_OK)
364 return result;
365 return AsyncFileTestHelper::TruncateFile(
366 file_system_context_.get(), url, size);
369 bool FileExists(const FileSystemURL& url, int64 expected_size) {
370 return AsyncFileTestHelper::FileExists(
371 file_system_context_.get(), url, expected_size);
374 bool DirectoryExists(const FileSystemURL& url) {
375 return AsyncFileTestHelper::DirectoryExists(file_system_context_.get(),
376 url);
379 private:
380 void GetUsageAndQuota(FileSystemType type, int64* usage, int64* quota) {
381 quota::QuotaStatusCode status = AsyncFileTestHelper::GetUsageAndQuota(
382 quota_manager_.get(), origin_, type, usage, quota);
383 ASSERT_EQ(quota::kQuotaStatusOk, status);
386 private:
387 base::ScopedTempDir base_;
389 const GURL origin_;
390 const FileSystemType src_type_;
391 const FileSystemType dest_type_;
393 base::MessageLoopForIO message_loop_;
394 scoped_refptr<fileapi::FileSystemContext> file_system_context_;
395 scoped_refptr<quota::MockQuotaManagerProxy> quota_manager_proxy_;
396 scoped_refptr<quota::MockQuotaManager> quota_manager_;
398 DISALLOW_COPY_AND_ASSIGN(CopyOrMoveOperationTestHelper);
401 TEST(LocalFileSystemCopyOrMoveOperationTest, CopySingleFile) {
402 CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
403 fileapi::kFileSystemTypeTemporary,
404 fileapi::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 fileapi::kFileSystemTypeTemporary,
433 fileapi::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 fileapi::kFileSystemTypeTemporary,
462 fileapi::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 fileapi::kFileSystemTypeTemporary,
491 fileapi::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 fileapi::kFileSystemTypeTemporary,
520 fileapi::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 fileapi::kFileSystemTypeTemporary,
560 fileapi::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 fileapi::kFileSystemTypeTemporary,
598 fileapi::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 fileapi::kFileSystemTypeTemporary,
631 fileapi::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 fileapi::kFileSystemTypeTemporary,
649 fileapi::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 const char kTestData[] = "abcdefghijklmnopqrstuvwxyz0123456789";
722 file_util::WriteFile(source_path, kTestData,
723 arraysize(kTestData) - 1); // Exclude trailing '\0'.
725 base::FilePath dest_path = temp_dir.path().AppendASCII("dest");
726 // LocalFileWriter requires the file exists. So create an empty file here.
727 file_util::WriteFile(dest_path, "", 0);
729 base::MessageLoopForIO message_loop;
730 base::Thread file_thread("file_thread");
731 ASSERT_TRUE(file_thread.Start());
732 ScopedThreadStopper thread_stopper(&file_thread);
733 ASSERT_TRUE(thread_stopper.is_valid());
735 scoped_refptr<base::MessageLoopProxy> task_runner =
736 file_thread.message_loop_proxy();
738 scoped_ptr<webkit_blob::FileStreamReader> reader(
739 webkit_blob::FileStreamReader::CreateForLocalFile(
740 task_runner.get(), source_path, 0, base::Time()));
742 scoped_ptr<FileStreamWriter> writer(
743 FileStreamWriter::CreateForLocalFile(task_runner.get(), dest_path, 0));
745 std::vector<int64> progress;
746 CopyOrMoveOperationDelegate::StreamCopyHelper helper(
747 reader.Pass(), writer.Pass(),
748 false, // don't need flush
749 10, // buffer size
750 base::Bind(&RecordFileProgressCallback, base::Unretained(&progress)),
751 base::TimeDelta()); // For testing, we need all the progress.
753 base::File::Error error = base::File::FILE_ERROR_FAILED;
754 base::RunLoop run_loop;
755 helper.Run(base::Bind(&AssignAndQuit, &run_loop, &error));
756 run_loop.Run();
758 EXPECT_EQ(base::File::FILE_OK, error);
759 ASSERT_EQ(5U, progress.size());
760 EXPECT_EQ(0, progress[0]);
761 EXPECT_EQ(10, progress[1]);
762 EXPECT_EQ(20, progress[2]);
763 EXPECT_EQ(30, progress[3]);
764 EXPECT_EQ(36, progress[4]);
766 std::string content;
767 ASSERT_TRUE(base::ReadFileToString(dest_path, &content));
768 EXPECT_EQ(kTestData, content);
771 TEST(LocalFileSystemCopyOrMoveOperationTest, StreamCopyHelperWithFlush) {
772 // Testing the same configuration as StreamCopyHelper, but with |need_flush|
773 // parameter set to true. Since it is hard to test that the flush is indeed
774 // taking place, this test just only verifies that the file is correctly
775 // written with or without the flag.
776 base::ScopedTempDir temp_dir;
777 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
778 base::FilePath source_path = temp_dir.path().AppendASCII("source");
779 const char kTestData[] = "abcdefghijklmnopqrstuvwxyz0123456789";
780 file_util::WriteFile(source_path, kTestData,
781 arraysize(kTestData) - 1); // Exclude trailing '\0'.
783 base::FilePath dest_path = temp_dir.path().AppendASCII("dest");
784 // LocalFileWriter requires the file exists. So create an empty file here.
785 file_util::WriteFile(dest_path, "", 0);
787 base::MessageLoopForIO message_loop;
788 base::Thread file_thread("file_thread");
789 ASSERT_TRUE(file_thread.Start());
790 ScopedThreadStopper thread_stopper(&file_thread);
791 ASSERT_TRUE(thread_stopper.is_valid());
793 scoped_refptr<base::MessageLoopProxy> task_runner =
794 file_thread.message_loop_proxy();
796 scoped_ptr<webkit_blob::FileStreamReader> reader(
797 webkit_blob::FileStreamReader::CreateForLocalFile(
798 task_runner.get(), source_path, 0, base::Time()));
800 scoped_ptr<FileStreamWriter> writer(
801 FileStreamWriter::CreateForLocalFile(task_runner.get(), dest_path, 0));
803 std::vector<int64> progress;
804 CopyOrMoveOperationDelegate::StreamCopyHelper helper(
805 reader.Pass(), writer.Pass(),
806 true, // need flush
807 10, // buffer size
808 base::Bind(&RecordFileProgressCallback, base::Unretained(&progress)),
809 base::TimeDelta()); // For testing, we need all the progress.
811 base::File::Error error = base::File::FILE_ERROR_FAILED;
812 base::RunLoop run_loop;
813 helper.Run(base::Bind(&AssignAndQuit, &run_loop, &error));
814 run_loop.Run();
816 EXPECT_EQ(base::File::FILE_OK, error);
817 ASSERT_EQ(5U, progress.size());
818 EXPECT_EQ(0, progress[0]);
819 EXPECT_EQ(10, progress[1]);
820 EXPECT_EQ(20, progress[2]);
821 EXPECT_EQ(30, progress[3]);
822 EXPECT_EQ(36, progress[4]);
824 std::string content;
825 ASSERT_TRUE(base::ReadFileToString(dest_path, &content));
826 EXPECT_EQ(kTestData, content);
829 TEST(LocalFileSystemCopyOrMoveOperationTest, StreamCopyHelper_Cancel) {
830 base::ScopedTempDir temp_dir;
831 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
832 base::FilePath source_path = temp_dir.path().AppendASCII("source");
833 const char kTestData[] = "abcdefghijklmnopqrstuvwxyz0123456789";
834 file_util::WriteFile(source_path, kTestData,
835 arraysize(kTestData) - 1); // Exclude trailing '\0'.
837 base::FilePath dest_path = temp_dir.path().AppendASCII("dest");
838 // LocalFileWriter requires the file exists. So create an empty file here.
839 file_util::WriteFile(dest_path, "", 0);
841 base::MessageLoopForIO message_loop;
842 base::Thread file_thread("file_thread");
843 ASSERT_TRUE(file_thread.Start());
844 ScopedThreadStopper thread_stopper(&file_thread);
845 ASSERT_TRUE(thread_stopper.is_valid());
847 scoped_refptr<base::MessageLoopProxy> task_runner =
848 file_thread.message_loop_proxy();
850 scoped_ptr<webkit_blob::FileStreamReader> reader(
851 webkit_blob::FileStreamReader::CreateForLocalFile(
852 task_runner.get(), source_path, 0, base::Time()));
854 scoped_ptr<FileStreamWriter> writer(
855 FileStreamWriter::CreateForLocalFile(task_runner.get(), dest_path, 0));
857 std::vector<int64> progress;
858 CopyOrMoveOperationDelegate::StreamCopyHelper helper(
859 reader.Pass(), writer.Pass(),
860 false, // need_flush
861 10, // buffer size
862 base::Bind(&RecordFileProgressCallback, base::Unretained(&progress)),
863 base::TimeDelta()); // For testing, we need all the progress.
865 // Call Cancel() later.
866 base::MessageLoopProxy::current()->PostTask(
867 FROM_HERE,
868 base::Bind(&CopyOrMoveOperationDelegate::StreamCopyHelper::Cancel,
869 base::Unretained(&helper)));
871 base::File::Error error = base::File::FILE_ERROR_FAILED;
872 base::RunLoop run_loop;
873 helper.Run(base::Bind(&AssignAndQuit, &run_loop, &error));
874 run_loop.Run();
876 EXPECT_EQ(base::File::FILE_ERROR_ABORT, error);
879 } // namespace content