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.
4
5#include "webkit/browser/fileapi/file_system_operation_impl.h"
6
7#include "base/bind.h"
8#include "base/file_util.h"
9#include "base/files/scoped_temp_dir.h"
10#include "base/logging.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/memory/weak_ptr.h"
13#include "base/run_loop.h"
14#include "base/strings/stringprintf.h"
15#include "content/public/test/sandbox_file_system_test_helper.h"
16#include "testing/gtest/include/gtest/gtest.h"
17#include "url/gurl.h"
18#include "webkit/browser/fileapi/async_file_test_helper.h"
19#include "webkit/browser/fileapi/file_system_context.h"
20#include "webkit/browser/fileapi/file_system_file_util.h"
21#include "webkit/browser/fileapi/file_system_operation_context.h"
22#include "webkit/browser/fileapi/file_system_operation_runner.h"
23#include "webkit/browser/fileapi/mock_file_change_observer.h"
24#include "webkit/browser/fileapi/sandbox_file_system_backend.h"
25#include "webkit/browser/quota/mock_quota_manager.h"
26#include "webkit/browser/quota/quota_manager.h"
27#include "webkit/common/blob/shareable_file_reference.h"
28#include "webkit/common/fileapi/file_system_util.h"
29
30using quota::QuotaManager;
31using quota::QuotaManagerProxy;
32using webkit_blob::ShareableFileReference;
33
34namespace fileapi {
35
36namespace {
37
38const int kFileOperationStatusNotSet = 1;
39
40void AssertFileErrorEq(const tracked_objects::Location& from_here,
41                       base::PlatformFileError expected,
42                       base::PlatformFileError actual) {
43  ASSERT_EQ(expected, actual) << from_here.ToString();
44}
45
46}  // namespace (anonymous)
47
48// Test class for FileSystemOperationImpl.
49class FileSystemOperationImplTest
50    : public testing::Test {
51 public:
52  FileSystemOperationImplTest()
53      : status_(kFileOperationStatusNotSet),
54        weak_factory_(this) {}
55
56 protected:
57  virtual void SetUp() OVERRIDE {
58    EXPECT_TRUE(base_.CreateUniqueTempDir());
59    change_observers_ = MockFileChangeObserver::CreateList(&change_observer_);
60
61    base::FilePath base_dir = base_.path().AppendASCII("filesystem");
62    quota_manager_ =
63        new quota::MockQuotaManager(false /* is_incognito */,
64                                    base_dir,
65                                    base::MessageLoopProxy::current().get(),
66                                    base::MessageLoopProxy::current().get(),
67                                    NULL /* special storage policy */);
68    quota_manager_proxy_ = new quota::MockQuotaManagerProxy(
69        quota_manager(), base::MessageLoopProxy::current().get());
70    sandbox_file_system_.SetUp(base_dir, quota_manager_proxy_.get());
71    sandbox_file_system_.AddFileChangeObserver(&change_observer_);
72  }
73
74  virtual void TearDown() OVERRIDE {
75    // Let the client go away before dropping a ref of the quota manager proxy.
76    quota_manager_proxy()->SimulateQuotaManagerDestroyed();
77    quota_manager_ = NULL;
78    quota_manager_proxy_ = NULL;
79    sandbox_file_system_.TearDown();
80  }
81
82  FileSystemOperationRunner* operation_runner() {
83    return sandbox_file_system_.operation_runner();
84  }
85
86  int status() const { return status_; }
87  const base::PlatformFileInfo& info() const { return info_; }
88  const base::FilePath& path() const { return path_; }
89  const std::vector<DirectoryEntry>& entries() const {
90    return entries_;
91  }
92
93  const ShareableFileReference* shareable_file_ref() const {
94    return shareable_file_ref_.get();
95  }
96
97  quota::MockQuotaManager* quota_manager() {
98    return static_cast<quota::MockQuotaManager*>(quota_manager_.get());
99  }
100
101  quota::MockQuotaManagerProxy* quota_manager_proxy() {
102    return static_cast<quota::MockQuotaManagerProxy*>(
103        quota_manager_proxy_.get());
104  }
105
106 FileSystemFileUtil* file_util() {
107    return sandbox_file_system_.file_util();
108  }
109
110  MockFileChangeObserver* change_observer() {
111    return &change_observer_;
112  }
113
114  scoped_ptr<FileSystemOperationContext> NewContext() {
115    FileSystemOperationContext* context =
116        sandbox_file_system_.NewOperationContext();
117    // Grant enough quota for all test cases.
118    context->set_allowed_bytes_growth(1000000);
119    return make_scoped_ptr(context);
120  }
121
122  FileSystemURL URLForPath(const std::string& path) const {
123    return sandbox_file_system_.CreateURLFromUTF8(path);
124  }
125
126  base::FilePath PlatformPath(const std::string& path) {
127    return sandbox_file_system_.GetLocalPath(
128        base::FilePath::FromUTF8Unsafe(path));
129  }
130
131  bool FileExists(const std::string& path) {
132    return AsyncFileTestHelper::FileExists(
133        sandbox_file_system_.file_system_context(), URLForPath(path),
134        AsyncFileTestHelper::kDontCheckSize);
135  }
136
137  bool DirectoryExists(const std::string& path) {
138    return AsyncFileTestHelper::DirectoryExists(
139        sandbox_file_system_.file_system_context(), URLForPath(path));
140  }
141
142  FileSystemURL CreateFile(const std::string& path) {
143    FileSystemURL url = URLForPath(path);
144    bool created = false;
145    EXPECT_EQ(base::PLATFORM_FILE_OK,
146              file_util()->EnsureFileExists(NewContext().get(),
147                                            url, &created));
148    EXPECT_TRUE(created);
149    return url;
150  }
151
152  FileSystemURL CreateDirectory(const std::string& path) {
153    FileSystemURL url = URLForPath(path);
154    EXPECT_EQ(base::PLATFORM_FILE_OK,
155              file_util()->CreateDirectory(NewContext().get(), url,
156                                           false /* exclusive */, true));
157    return url;
158  }
159
160  int64 GetFileSize(const std::string& path) {
161    base::PlatformFileInfo info;
162    EXPECT_TRUE(base::GetFileInfo(PlatformPath(path), &info));
163    return info.size;
164  }
165
166  // Callbacks for recording test results.
167  FileSystemOperation::StatusCallback RecordStatusCallback() {
168    return base::Bind(&FileSystemOperationImplTest::DidFinish,
169                      weak_factory_.GetWeakPtr());
170  }
171
172  FileSystemOperation::ReadDirectoryCallback
173  RecordReadDirectoryCallback() {
174    return base::Bind(&FileSystemOperationImplTest::DidReadDirectory,
175                      weak_factory_.GetWeakPtr());
176  }
177
178  FileSystemOperation::GetMetadataCallback RecordMetadataCallback() {
179    return base::Bind(&FileSystemOperationImplTest::DidGetMetadata,
180                      weak_factory_.GetWeakPtr());
181  }
182
183  FileSystemOperation::SnapshotFileCallback RecordSnapshotFileCallback() {
184    return base::Bind(&FileSystemOperationImplTest::DidCreateSnapshotFile,
185                      weak_factory_.GetWeakPtr());
186  }
187
188  void DidFinish(base::PlatformFileError status) {
189    status_ = status;
190  }
191
192  void DidReadDirectory(
193      base::PlatformFileError status,
194      const std::vector<DirectoryEntry>& entries,
195      bool /* has_more */) {
196    entries_ = entries;
197    status_ = status;
198  }
199
200  void DidGetMetadata(base::PlatformFileError status,
201                      const base::PlatformFileInfo& info) {
202    info_ = info;
203    status_ = status;
204  }
205
206  void DidCreateSnapshotFile(
207      base::PlatformFileError status,
208      const base::PlatformFileInfo& info,
209      const base::FilePath& platform_path,
210      const scoped_refptr<ShareableFileReference>& shareable_file_ref) {
211    info_ = info;
212    path_ = platform_path;
213    status_ = status;
214    shareable_file_ref_ = shareable_file_ref;
215  }
216
217  int64 GetDataSizeOnDisk() {
218    return sandbox_file_system_.ComputeCurrentOriginUsage() -
219        sandbox_file_system_.ComputeCurrentDirectoryDatabaseUsage();
220  }
221
222  void GetUsageAndQuota(int64* usage, int64* quota) {
223    quota::QuotaStatusCode status =
224        AsyncFileTestHelper::GetUsageAndQuota(quota_manager_.get(),
225                                              sandbox_file_system_.origin(),
226                                              sandbox_file_system_.type(),
227                                              usage,
228                                              quota);
229    base::RunLoop().RunUntilIdle();
230    ASSERT_EQ(quota::kQuotaStatusOk, status);
231  }
232
233  int64 ComputePathCost(const FileSystemURL& url) {
234    int64 base_usage;
235    GetUsageAndQuota(&base_usage, NULL);
236
237    AsyncFileTestHelper::CreateFile(
238        sandbox_file_system_.file_system_context(), url);
239    operation_runner()->Remove(url, false /* recursive */,
240                               base::Bind(&AssertFileErrorEq, FROM_HERE,
241                                          base::PLATFORM_FILE_OK));
242    base::RunLoop().RunUntilIdle();
243    change_observer()->ResetCount();
244
245    int64 total_usage;
246    GetUsageAndQuota(&total_usage, NULL);
247    return total_usage - base_usage;
248  }
249
250  void GrantQuotaForCurrentUsage() {
251    int64 usage;
252    GetUsageAndQuota(&usage, NULL);
253    quota_manager()->SetQuota(sandbox_file_system_.origin(),
254                              sandbox_file_system_.storage_type(),
255                              usage);
256  }
257
258  int64 GetUsage() {
259    int64 usage = 0;
260    GetUsageAndQuota(&usage, NULL);
261    return usage;
262  }
263
264  void AddQuota(int64 quota_delta) {
265    int64 quota;
266    GetUsageAndQuota(NULL, &quota);
267    quota_manager()->SetQuota(sandbox_file_system_.origin(),
268                              sandbox_file_system_.storage_type(),
269                              quota + quota_delta);
270  }
271
272  base::MessageLoop message_loop_;
273  scoped_refptr<QuotaManager> quota_manager_;
274  scoped_refptr<QuotaManagerProxy> quota_manager_proxy_;
275
276  // Common temp base for nondestructive uses.
277  base::ScopedTempDir base_;
278
279  SandboxFileSystemTestHelper sandbox_file_system_;
280
281  // For post-operation status.
282  int status_;
283  base::PlatformFileInfo info_;
284  base::FilePath path_;
285  std::vector<DirectoryEntry> entries_;
286  scoped_refptr<ShareableFileReference> shareable_file_ref_;
287
288  MockFileChangeObserver change_observer_;
289  ChangeObserverList change_observers_;
290
291  base::WeakPtrFactory<FileSystemOperationImplTest> weak_factory_;
292
293  DISALLOW_COPY_AND_ASSIGN(FileSystemOperationImplTest);
294};
295
296TEST_F(FileSystemOperationImplTest, TestMoveFailureSrcDoesntExist) {
297  change_observer()->ResetCount();
298  operation_runner()->Move(URLForPath("a"), URLForPath("b"),
299                           FileSystemOperation::OPTION_NONE,
300                           RecordStatusCallback());
301  base::RunLoop().RunUntilIdle();
302  EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status());
303  EXPECT_TRUE(change_observer()->HasNoChange());
304}
305
306TEST_F(FileSystemOperationImplTest, TestMoveFailureContainsPath) {
307  FileSystemURL src_dir(CreateDirectory("src"));
308  FileSystemURL dest_dir(CreateDirectory("src/dest"));
309
310  operation_runner()->Move(src_dir, dest_dir,
311                           FileSystemOperation::OPTION_NONE,
312                           RecordStatusCallback());
313  base::RunLoop().RunUntilIdle();
314  EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status());
315  EXPECT_TRUE(change_observer()->HasNoChange());
316}
317
318TEST_F(FileSystemOperationImplTest, TestMoveFailureSrcDirExistsDestFile) {
319  // Src exists and is dir. Dest is a file.
320  FileSystemURL src_dir(CreateDirectory("src"));
321  FileSystemURL dest_dir(CreateDirectory("dest"));
322  FileSystemURL dest_file(CreateFile("dest/file"));
323
324  operation_runner()->Move(src_dir, dest_file,
325                           FileSystemOperation::OPTION_NONE,
326                           RecordStatusCallback());
327  base::RunLoop().RunUntilIdle();
328  EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status());
329  EXPECT_TRUE(change_observer()->HasNoChange());
330}
331
332TEST_F(FileSystemOperationImplTest,
333       TestMoveFailureSrcFileExistsDestNonEmptyDir) {
334  // Src exists and is a directory. Dest is a non-empty directory.
335  FileSystemURL src_dir(CreateDirectory("src"));
336  FileSystemURL dest_dir(CreateDirectory("dest"));
337  FileSystemURL dest_file(CreateFile("dest/file"));
338
339  operation_runner()->Move(src_dir, dest_dir,
340                           FileSystemOperation::OPTION_NONE,
341                           RecordStatusCallback());
342  base::RunLoop().RunUntilIdle();
343  EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_EMPTY, status());
344  EXPECT_TRUE(change_observer()->HasNoChange());
345}
346
347TEST_F(FileSystemOperationImplTest, TestMoveFailureSrcFileExistsDestDir) {
348  // Src exists and is a file. Dest is a directory.
349  FileSystemURL src_dir(CreateDirectory("src"));
350  FileSystemURL src_file(CreateFile("src/file"));
351  FileSystemURL dest_dir(CreateDirectory("dest"));
352
353  operation_runner()->Move(src_file, dest_dir,
354                           FileSystemOperation::OPTION_NONE,
355                           RecordStatusCallback());
356  base::RunLoop().RunUntilIdle();
357  EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status());
358  EXPECT_TRUE(change_observer()->HasNoChange());
359}
360
361TEST_F(FileSystemOperationImplTest, TestMoveFailureDestParentDoesntExist) {
362  // Dest. parent path does not exist.
363  FileSystemURL src_dir(CreateDirectory("src"));
364  operation_runner()->Move(src_dir, URLForPath("nonexistent/deset"),
365                           FileSystemOperation::OPTION_NONE,
366                           RecordStatusCallback());
367  base::RunLoop().RunUntilIdle();
368  EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status());
369  EXPECT_TRUE(change_observer()->HasNoChange());
370}
371
372TEST_F(FileSystemOperationImplTest, TestMoveSuccessSrcFileAndOverwrite) {
373  FileSystemURL src_file(CreateFile("src"));
374  FileSystemURL dest_file(CreateFile("dest"));
375
376  operation_runner()->Move(src_file, dest_file,
377                           FileSystemOperation::OPTION_NONE,
378                           RecordStatusCallback());
379  base::RunLoop().RunUntilIdle();
380  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
381  EXPECT_TRUE(FileExists("dest"));
382
383  EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
384  EXPECT_EQ(1, change_observer()->get_and_reset_remove_file_count());
385  EXPECT_TRUE(change_observer()->HasNoChange());
386
387  EXPECT_EQ(1, quota_manager_proxy()->notify_storage_accessed_count());
388}
389
390TEST_F(FileSystemOperationImplTest, TestMoveSuccessSrcFileAndNew) {
391  FileSystemURL src_file(CreateFile("src"));
392
393  operation_runner()->Move(src_file, URLForPath("new"),
394                           FileSystemOperation::OPTION_NONE,
395                           RecordStatusCallback());
396  base::RunLoop().RunUntilIdle();
397  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
398  EXPECT_TRUE(FileExists("new"));
399
400  EXPECT_EQ(1, change_observer()->get_and_reset_create_file_from_count());
401  EXPECT_EQ(1, change_observer()->get_and_reset_remove_file_count());
402  EXPECT_TRUE(change_observer()->HasNoChange());
403}
404
405TEST_F(FileSystemOperationImplTest, TestMoveSuccessSrcDirAndOverwrite) {
406  FileSystemURL src_dir(CreateDirectory("src"));
407  FileSystemURL dest_dir(CreateDirectory("dest"));
408
409  operation_runner()->Move(src_dir, dest_dir,
410                           FileSystemOperation::OPTION_NONE,
411                           RecordStatusCallback());
412  base::RunLoop().RunUntilIdle();
413  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
414  EXPECT_FALSE(DirectoryExists("src"));
415
416  EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count());
417  EXPECT_EQ(2, change_observer()->get_and_reset_remove_directory_count());
418  EXPECT_TRUE(change_observer()->HasNoChange());
419
420  // Make sure we've overwritten but not moved the source under the |dest_dir|.
421  EXPECT_TRUE(DirectoryExists("dest"));
422  EXPECT_FALSE(DirectoryExists("dest/src"));
423}
424
425TEST_F(FileSystemOperationImplTest, TestMoveSuccessSrcDirAndNew) {
426  FileSystemURL src_dir(CreateDirectory("src"));
427  FileSystemURL dest_dir(CreateDirectory("dest"));
428
429  operation_runner()->Move(src_dir, URLForPath("dest/new"),
430                           FileSystemOperation::OPTION_NONE,
431                           RecordStatusCallback());
432  base::RunLoop().RunUntilIdle();
433  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
434  EXPECT_FALSE(DirectoryExists("src"));
435  EXPECT_TRUE(DirectoryExists("dest/new"));
436
437  EXPECT_EQ(1, change_observer()->get_and_reset_remove_directory_count());
438  EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count());
439  EXPECT_TRUE(change_observer()->HasNoChange());
440}
441
442TEST_F(FileSystemOperationImplTest, TestMoveSuccessSrcDirRecursive) {
443  FileSystemURL src_dir(CreateDirectory("src"));
444  CreateDirectory("src/dir");
445  CreateFile("src/dir/sub");
446
447  FileSystemURL dest_dir(CreateDirectory("dest"));
448
449  operation_runner()->Move(src_dir, dest_dir,
450                           FileSystemOperation::OPTION_NONE,
451                           RecordStatusCallback());
452  base::RunLoop().RunUntilIdle();
453  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
454  EXPECT_TRUE(DirectoryExists("dest/dir"));
455  EXPECT_TRUE(FileExists("dest/dir/sub"));
456
457  EXPECT_EQ(3, change_observer()->get_and_reset_remove_directory_count());
458  EXPECT_EQ(2, change_observer()->get_and_reset_create_directory_count());
459  EXPECT_EQ(1, change_observer()->get_and_reset_remove_file_count());
460  EXPECT_EQ(1, change_observer()->get_and_reset_create_file_from_count());
461  EXPECT_TRUE(change_observer()->HasNoChange());
462}
463
464TEST_F(FileSystemOperationImplTest, TestCopyFailureSrcDoesntExist) {
465  operation_runner()->Copy(URLForPath("a"), URLForPath("b"),
466                           FileSystemOperation::OPTION_NONE,
467                           FileSystemOperationRunner::CopyProgressCallback(),
468                           RecordStatusCallback());
469  base::RunLoop().RunUntilIdle();
470  EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status());
471  EXPECT_TRUE(change_observer()->HasNoChange());
472}
473
474TEST_F(FileSystemOperationImplTest, TestCopyFailureContainsPath) {
475  FileSystemURL src_dir(CreateDirectory("src"));
476  FileSystemURL dest_dir(CreateDirectory("src/dir"));
477
478  operation_runner()->Copy(src_dir, dest_dir,
479                           FileSystemOperation::OPTION_NONE,
480                           FileSystemOperationRunner::CopyProgressCallback(),
481                           RecordStatusCallback());
482  base::RunLoop().RunUntilIdle();
483  EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status());
484  EXPECT_TRUE(change_observer()->HasNoChange());
485}
486
487TEST_F(FileSystemOperationImplTest, TestCopyFailureSrcDirExistsDestFile) {
488  // Src exists and is dir. Dest is a file.
489  FileSystemURL src_dir(CreateDirectory("src"));
490  FileSystemURL dest_dir(CreateDirectory("dest"));
491  FileSystemURL dest_file(CreateFile("dest/file"));
492
493  operation_runner()->Copy(src_dir, dest_file,
494                           FileSystemOperation::OPTION_NONE,
495                           FileSystemOperationRunner::CopyProgressCallback(),
496                           RecordStatusCallback());
497  base::RunLoop().RunUntilIdle();
498  EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status());
499  EXPECT_TRUE(change_observer()->HasNoChange());
500}
501
502TEST_F(FileSystemOperationImplTest,
503       TestCopyFailureSrcFileExistsDestNonEmptyDir) {
504  // Src exists and is a directory. Dest is a non-empty directory.
505  FileSystemURL src_dir(CreateDirectory("src"));
506  FileSystemURL dest_dir(CreateDirectory("dest"));
507  FileSystemURL dest_file(CreateFile("dest/file"));
508
509  operation_runner()->Copy(src_dir, dest_dir,
510                           FileSystemOperation::OPTION_NONE,
511                           FileSystemOperationRunner::CopyProgressCallback(),
512                           RecordStatusCallback());
513  base::RunLoop().RunUntilIdle();
514  EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_EMPTY, status());
515  EXPECT_TRUE(change_observer()->HasNoChange());
516}
517
518TEST_F(FileSystemOperationImplTest, TestCopyFailureSrcFileExistsDestDir) {
519  // Src exists and is a file. Dest is a directory.
520  FileSystemURL src_file(CreateFile("src"));
521  FileSystemURL dest_dir(CreateDirectory("dest"));
522
523  operation_runner()->Copy(src_file, dest_dir,
524                           FileSystemOperation::OPTION_NONE,
525                           FileSystemOperationRunner::CopyProgressCallback(),
526                           RecordStatusCallback());
527  base::RunLoop().RunUntilIdle();
528  EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status());
529  EXPECT_TRUE(change_observer()->HasNoChange());
530}
531
532TEST_F(FileSystemOperationImplTest, TestCopyFailureDestParentDoesntExist) {
533  // Dest. parent path does not exist.
534  FileSystemURL src_dir(CreateDirectory("src"));
535
536  operation_runner()->Copy(src_dir, URLForPath("nonexistent/dest"),
537                           FileSystemOperation::OPTION_NONE,
538                           FileSystemOperationRunner::CopyProgressCallback(),
539                           RecordStatusCallback());
540  base::RunLoop().RunUntilIdle();
541  EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status());
542  EXPECT_TRUE(change_observer()->HasNoChange());
543}
544
545TEST_F(FileSystemOperationImplTest, TestCopyFailureByQuota) {
546  FileSystemURL src_dir(CreateDirectory("src"));
547  FileSystemURL src_file(CreateFile("src/file"));
548  FileSystemURL dest_dir(CreateDirectory("dest"));
549  operation_runner()->Truncate(src_file, 6, RecordStatusCallback());
550  base::RunLoop().RunUntilIdle();
551  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
552  EXPECT_EQ(6, GetFileSize("src/file"));
553
554  FileSystemURL dest_file(URLForPath("dest/file"));
555  int64 dest_path_cost = ComputePathCost(dest_file);
556  GrantQuotaForCurrentUsage();
557  AddQuota(6 + dest_path_cost - 1);
558
559  operation_runner()->Copy(src_file, dest_file,
560                           FileSystemOperation::OPTION_NONE,
561                           FileSystemOperationRunner::CopyProgressCallback(),
562                           RecordStatusCallback());
563  base::RunLoop().RunUntilIdle();
564  EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE, status());
565  EXPECT_FALSE(FileExists("dest/file"));
566}
567
568TEST_F(FileSystemOperationImplTest, TestCopySuccessSrcFileAndOverwrite) {
569  FileSystemURL src_file(CreateFile("src"));
570  FileSystemURL dest_file(CreateFile("dest"));
571
572  operation_runner()->Copy(src_file, dest_file,
573                           FileSystemOperation::OPTION_NONE,
574                           FileSystemOperationRunner::CopyProgressCallback(),
575                           RecordStatusCallback());
576  base::RunLoop().RunUntilIdle();
577  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
578  EXPECT_TRUE(FileExists("dest"));
579  EXPECT_EQ(2, quota_manager_proxy()->notify_storage_accessed_count());
580
581  EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
582  EXPECT_TRUE(change_observer()->HasNoChange());
583}
584
585TEST_F(FileSystemOperationImplTest, TestCopySuccessSrcFileAndNew) {
586  FileSystemURL src_file(CreateFile("src"));
587
588  operation_runner()->Copy(src_file, URLForPath("new"),
589                           FileSystemOperation::OPTION_NONE,
590                           FileSystemOperationRunner::CopyProgressCallback(),
591                           RecordStatusCallback());
592  base::RunLoop().RunUntilIdle();
593  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
594  EXPECT_TRUE(FileExists("new"));
595  EXPECT_EQ(2, quota_manager_proxy()->notify_storage_accessed_count());
596
597  EXPECT_EQ(1, change_observer()->get_and_reset_create_file_from_count());
598  EXPECT_TRUE(change_observer()->HasNoChange());
599}
600
601TEST_F(FileSystemOperationImplTest, TestCopySuccessSrcDirAndOverwrite) {
602  FileSystemURL src_dir(CreateDirectory("src"));
603  FileSystemURL dest_dir(CreateDirectory("dest"));
604
605  operation_runner()->Copy(src_dir, dest_dir,
606                           FileSystemOperation::OPTION_NONE,
607                           FileSystemOperationRunner::CopyProgressCallback(),
608                           RecordStatusCallback());
609  base::RunLoop().RunUntilIdle();
610  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
611
612  // Make sure we've overwritten but not copied the source under the |dest_dir|.
613  EXPECT_TRUE(DirectoryExists("dest"));
614  EXPECT_FALSE(DirectoryExists("dest/src"));
615  EXPECT_GE(quota_manager_proxy()->notify_storage_accessed_count(), 3);
616
617  EXPECT_EQ(1, change_observer()->get_and_reset_remove_directory_count());
618  EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count());
619  EXPECT_TRUE(change_observer()->HasNoChange());
620}
621
622TEST_F(FileSystemOperationImplTest, TestCopySuccessSrcDirAndNew) {
623  FileSystemURL src_dir(CreateDirectory("src"));
624  FileSystemURL dest_dir_new(URLForPath("dest"));
625
626  operation_runner()->Copy(src_dir, dest_dir_new,
627                           FileSystemOperation::OPTION_NONE,
628                           FileSystemOperationRunner::CopyProgressCallback(),
629                           RecordStatusCallback());
630  base::RunLoop().RunUntilIdle();
631  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
632  EXPECT_TRUE(DirectoryExists("dest"));
633  EXPECT_GE(quota_manager_proxy()->notify_storage_accessed_count(), 2);
634
635  EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count());
636  EXPECT_TRUE(change_observer()->HasNoChange());
637}
638
639TEST_F(FileSystemOperationImplTest, TestCopySuccessSrcDirRecursive) {
640  FileSystemURL src_dir(CreateDirectory("src"));
641  CreateDirectory("src/dir");
642  CreateFile("src/dir/sub");
643
644  FileSystemURL dest_dir(CreateDirectory("dest"));
645
646  operation_runner()->Copy(src_dir, dest_dir,
647                           FileSystemOperation::OPTION_NONE,
648                           FileSystemOperationRunner::CopyProgressCallback(),
649                           RecordStatusCallback());
650  base::RunLoop().RunUntilIdle();
651
652  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
653  EXPECT_TRUE(DirectoryExists("dest/dir"));
654  EXPECT_TRUE(FileExists("dest/dir/sub"));
655
656  // For recursive copy we may record multiple read access.
657  EXPECT_GE(quota_manager_proxy()->notify_storage_accessed_count(), 1);
658
659  EXPECT_EQ(2, change_observer()->get_and_reset_create_directory_count());
660  EXPECT_EQ(1, change_observer()->get_and_reset_remove_directory_count());
661  EXPECT_EQ(1, change_observer()->get_and_reset_create_file_from_count());
662  EXPECT_TRUE(change_observer()->HasNoChange());
663}
664
665TEST_F(FileSystemOperationImplTest, TestCopyInForeignFileSuccess) {
666  base::FilePath src_local_disk_file_path;
667  base::CreateTemporaryFile(&src_local_disk_file_path);
668  const char test_data[] = "foo";
669  int data_size = ARRAYSIZE_UNSAFE(test_data);
670  file_util::WriteFile(src_local_disk_file_path, test_data, data_size);
671
672  FileSystemURL dest_dir(CreateDirectory("dest"));
673
674  int64 before_usage;
675  GetUsageAndQuota(&before_usage, NULL);
676
677  // Check that the file copied and corresponding usage increased.
678  operation_runner()->CopyInForeignFile(src_local_disk_file_path,
679                                        URLForPath("dest/file"),
680                                        RecordStatusCallback());
681  base::RunLoop().RunUntilIdle();
682
683  EXPECT_EQ(1, change_observer()->create_file_count());
684  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
685  EXPECT_TRUE(FileExists("dest/file"));
686  int64 after_usage;
687  GetUsageAndQuota(&after_usage, NULL);
688  EXPECT_GT(after_usage, before_usage);
689
690  // Compare contents of src and copied file.
691  char buffer[100];
692  EXPECT_EQ(data_size, base::ReadFile(PlatformPath("dest/file"),
693                                      buffer, data_size));
694  for (int i = 0; i < data_size; ++i)
695    EXPECT_EQ(test_data[i], buffer[i]);
696}
697
698TEST_F(FileSystemOperationImplTest, TestCopyInForeignFileFailureByQuota) {
699  base::FilePath src_local_disk_file_path;
700  base::CreateTemporaryFile(&src_local_disk_file_path);
701  const char test_data[] = "foo";
702  file_util::WriteFile(src_local_disk_file_path, test_data,
703                       ARRAYSIZE_UNSAFE(test_data));
704
705  FileSystemURL dest_dir(CreateDirectory("dest"));
706
707  GrantQuotaForCurrentUsage();
708  operation_runner()->CopyInForeignFile(src_local_disk_file_path,
709                                        URLForPath("dest/file"),
710                                        RecordStatusCallback());
711  base::RunLoop().RunUntilIdle();
712
713  EXPECT_FALSE(FileExists("dest/file"));
714  EXPECT_EQ(0, change_observer()->create_file_count());
715  EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE, status());
716}
717
718TEST_F(FileSystemOperationImplTest, TestCreateFileFailure) {
719  // Already existing file and exclusive true.
720  FileSystemURL file(CreateFile("file"));
721  operation_runner()->CreateFile(file, true, RecordStatusCallback());
722  base::RunLoop().RunUntilIdle();
723  EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, status());
724  EXPECT_TRUE(change_observer()->HasNoChange());
725}
726
727TEST_F(FileSystemOperationImplTest, TestCreateFileSuccessFileExists) {
728  // Already existing file and exclusive false.
729  FileSystemURL file(CreateFile("file"));
730  operation_runner()->CreateFile(file, false, RecordStatusCallback());
731  base::RunLoop().RunUntilIdle();
732  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
733  EXPECT_TRUE(FileExists("file"));
734
735  // The file was already there; did nothing.
736  EXPECT_TRUE(change_observer()->HasNoChange());
737}
738
739TEST_F(FileSystemOperationImplTest, TestCreateFileSuccessExclusive) {
740  // File doesn't exist but exclusive is true.
741  operation_runner()->CreateFile(URLForPath("new"), true,
742                                 RecordStatusCallback());
743  base::RunLoop().RunUntilIdle();
744  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
745  EXPECT_TRUE(FileExists("new"));
746  EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count());
747}
748
749TEST_F(FileSystemOperationImplTest, TestCreateFileSuccessFileDoesntExist) {
750  // Non existing file.
751  operation_runner()->CreateFile(URLForPath("nonexistent"), false,
752                                 RecordStatusCallback());
753  base::RunLoop().RunUntilIdle();
754  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
755  EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count());
756}
757
758TEST_F(FileSystemOperationImplTest,
759       TestCreateDirFailureDestParentDoesntExist) {
760  // Dest. parent path does not exist.
761  operation_runner()->CreateDirectory(
762      URLForPath("nonexistent/dir"), false, false,
763      RecordStatusCallback());
764  base::RunLoop().RunUntilIdle();
765  EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status());
766  EXPECT_TRUE(change_observer()->HasNoChange());
767}
768
769TEST_F(FileSystemOperationImplTest, TestCreateDirFailureDirExists) {
770  // Exclusive and dir existing at path.
771  FileSystemURL dir(CreateDirectory("dir"));
772  operation_runner()->CreateDirectory(dir, true, false,
773                                      RecordStatusCallback());
774  base::RunLoop().RunUntilIdle();
775  EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, status());
776  EXPECT_TRUE(change_observer()->HasNoChange());
777}
778
779TEST_F(FileSystemOperationImplTest, TestCreateDirFailureFileExists) {
780  // Exclusive true and file existing at path.
781  FileSystemURL file(CreateFile("file"));
782  operation_runner()->CreateDirectory(file, true, false,
783                                      RecordStatusCallback());
784  base::RunLoop().RunUntilIdle();
785  EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, status());
786  EXPECT_TRUE(change_observer()->HasNoChange());
787}
788
789TEST_F(FileSystemOperationImplTest, TestCreateDirSuccess) {
790  // Dir exists and exclusive is false.
791  FileSystemURL dir(CreateDirectory("dir"));
792  operation_runner()->CreateDirectory(dir, false, false,
793                                      RecordStatusCallback());
794  base::RunLoop().RunUntilIdle();
795  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
796  EXPECT_TRUE(change_observer()->HasNoChange());
797
798  // Dir doesn't exist.
799  operation_runner()->CreateDirectory(URLForPath("new"), false, false,
800                                      RecordStatusCallback());
801  base::RunLoop().RunUntilIdle();
802  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
803  EXPECT_TRUE(DirectoryExists("new"));
804  EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count());
805}
806
807TEST_F(FileSystemOperationImplTest, TestCreateDirSuccessExclusive) {
808  // Dir doesn't exist.
809  operation_runner()->CreateDirectory(URLForPath("new"), true, false,
810                                      RecordStatusCallback());
811  base::RunLoop().RunUntilIdle();
812  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
813  EXPECT_TRUE(DirectoryExists("new"));
814  EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count());
815  EXPECT_TRUE(change_observer()->HasNoChange());
816}
817
818TEST_F(FileSystemOperationImplTest, TestExistsAndMetadataFailure) {
819  operation_runner()->GetMetadata(URLForPath("nonexistent"),
820                                  RecordMetadataCallback());
821  base::RunLoop().RunUntilIdle();
822  EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status());
823
824  operation_runner()->FileExists(URLForPath("nonexistent"),
825                                 RecordStatusCallback());
826  base::RunLoop().RunUntilIdle();
827  EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status());
828
829  operation_runner()->DirectoryExists(URLForPath("nonexistent"),
830                                      RecordStatusCallback());
831  base::RunLoop().RunUntilIdle();
832  EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status());
833  EXPECT_TRUE(change_observer()->HasNoChange());
834}
835
836TEST_F(FileSystemOperationImplTest, TestExistsAndMetadataSuccess) {
837  FileSystemURL dir(CreateDirectory("dir"));
838  FileSystemURL file(CreateFile("dir/file"));
839  int read_access = 0;
840
841  operation_runner()->DirectoryExists(dir, RecordStatusCallback());
842  base::RunLoop().RunUntilIdle();
843  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
844  ++read_access;
845
846  operation_runner()->GetMetadata(dir, RecordMetadataCallback());
847  base::RunLoop().RunUntilIdle();
848  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
849  EXPECT_TRUE(info().is_directory);
850  ++read_access;
851
852  operation_runner()->FileExists(file, RecordStatusCallback());
853  base::RunLoop().RunUntilIdle();
854  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
855  ++read_access;
856
857  operation_runner()->GetMetadata(file, RecordMetadataCallback());
858  base::RunLoop().RunUntilIdle();
859  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
860  EXPECT_FALSE(info().is_directory);
861  ++read_access;
862
863  EXPECT_EQ(read_access,
864            quota_manager_proxy()->notify_storage_accessed_count());
865  EXPECT_TRUE(change_observer()->HasNoChange());
866}
867
868TEST_F(FileSystemOperationImplTest, TestTypeMismatchErrors) {
869  FileSystemURL dir(CreateDirectory("dir"));
870  operation_runner()->FileExists(dir, RecordStatusCallback());
871  base::RunLoop().RunUntilIdle();
872  EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_A_FILE, status());
873
874  FileSystemURL file(CreateFile("file"));
875  operation_runner()->DirectoryExists(file, RecordStatusCallback());
876  base::RunLoop().RunUntilIdle();
877  EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY, status());
878}
879
880TEST_F(FileSystemOperationImplTest, TestReadDirFailure) {
881  // Path doesn't exist
882  operation_runner()->ReadDirectory(URLForPath("nonexistent"),
883                                    RecordReadDirectoryCallback());
884  base::RunLoop().RunUntilIdle();
885  EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status());
886
887  // File exists.
888  FileSystemURL file(CreateFile("file"));
889  operation_runner()->ReadDirectory(file, RecordReadDirectoryCallback());
890  base::RunLoop().RunUntilIdle();
891  EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY, status());
892  EXPECT_TRUE(change_observer()->HasNoChange());
893}
894
895TEST_F(FileSystemOperationImplTest, TestReadDirSuccess) {
896  //      parent_dir
897  //       |       |
898  //  child_dir  child_file
899  // Verify reading parent_dir.
900  FileSystemURL parent_dir(CreateDirectory("dir"));
901  FileSystemURL child_dir(CreateDirectory("dir/child_dir"));
902  FileSystemURL child_file(CreateFile("dir/child_file"));
903
904  operation_runner()->ReadDirectory(parent_dir, RecordReadDirectoryCallback());
905  base::RunLoop().RunUntilIdle();
906  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
907  EXPECT_EQ(2u, entries().size());
908
909  for (size_t i = 0; i < entries().size(); ++i) {
910    if (entries()[i].is_directory)
911      EXPECT_EQ(FILE_PATH_LITERAL("child_dir"), entries()[i].name);
912    else
913      EXPECT_EQ(FILE_PATH_LITERAL("child_file"), entries()[i].name);
914  }
915  EXPECT_EQ(1, quota_manager_proxy()->notify_storage_accessed_count());
916  EXPECT_TRUE(change_observer()->HasNoChange());
917}
918
919TEST_F(FileSystemOperationImplTest, TestRemoveFailure) {
920  // Path doesn't exist.
921  operation_runner()->Remove(URLForPath("nonexistent"), false /* recursive */,
922                             RecordStatusCallback());
923  base::RunLoop().RunUntilIdle();
924  EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status());
925
926  // It's an error to try to remove a non-empty directory if recursive flag
927  // is false.
928  //      parent_dir
929  //       |       |
930  //  child_dir  child_file
931  // Verify deleting parent_dir.
932  FileSystemURL parent_dir(CreateDirectory("dir"));
933  FileSystemURL child_dir(CreateDirectory("dir/child_dir"));
934  FileSystemURL child_file(CreateFile("dir/child_file"));
935
936  operation_runner()->Remove(parent_dir, false /* recursive */,
937                             RecordStatusCallback());
938  base::RunLoop().RunUntilIdle();
939  EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_EMPTY, status());
940  EXPECT_TRUE(change_observer()->HasNoChange());
941}
942
943TEST_F(FileSystemOperationImplTest, TestRemoveSuccess) {
944  FileSystemURL empty_dir(CreateDirectory("empty_dir"));
945  EXPECT_TRUE(DirectoryExists("empty_dir"));
946  operation_runner()->Remove(empty_dir, false /* recursive */,
947                             RecordStatusCallback());
948  base::RunLoop().RunUntilIdle();
949  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
950  EXPECT_FALSE(DirectoryExists("empty_dir"));
951
952  EXPECT_EQ(1, change_observer()->get_and_reset_remove_directory_count());
953  EXPECT_TRUE(change_observer()->HasNoChange());
954}
955
956TEST_F(FileSystemOperationImplTest, TestRemoveSuccessRecursive) {
957  // Removing a non-empty directory with recursive flag == true should be ok.
958  //      parent_dir
959  //       |       |
960  //  child_dir  child_files
961  //       |
962  //  child_files
963  //
964  // Verify deleting parent_dir.
965  FileSystemURL parent_dir(CreateDirectory("dir"));
966  for (int i = 0; i < 8; ++i)
967    CreateFile(base::StringPrintf("dir/file-%d", i));
968  FileSystemURL child_dir(CreateDirectory("dir/child_dir"));
969  for (int i = 0; i < 8; ++i)
970    CreateFile(base::StringPrintf("dir/child_dir/file-%d", i));
971
972  operation_runner()->Remove(parent_dir, true /* recursive */,
973                             RecordStatusCallback());
974  base::RunLoop().RunUntilIdle();
975  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
976  EXPECT_FALSE(DirectoryExists("parent_dir"));
977
978  EXPECT_EQ(2, change_observer()->get_and_reset_remove_directory_count());
979  EXPECT_EQ(16, change_observer()->get_and_reset_remove_file_count());
980  EXPECT_TRUE(change_observer()->HasNoChange());
981}
982
983TEST_F(FileSystemOperationImplTest, TestTruncate) {
984  FileSystemURL file(CreateFile("file"));
985  base::FilePath platform_path = PlatformPath("file");
986
987  char test_data[] = "test data";
988  int data_size = static_cast<int>(sizeof(test_data));
989  EXPECT_EQ(data_size,
990            file_util::WriteFile(platform_path, test_data, data_size));
991
992  // Check that its length is the size of the data written.
993  operation_runner()->GetMetadata(file, RecordMetadataCallback());
994  base::RunLoop().RunUntilIdle();
995  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
996  EXPECT_FALSE(info().is_directory);
997  EXPECT_EQ(data_size, info().size);
998
999  // Extend the file by truncating it.
1000  int length = 17;
1001  operation_runner()->Truncate(file, length, RecordStatusCallback());
1002  base::RunLoop().RunUntilIdle();
1003  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
1004
1005  EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
1006  EXPECT_TRUE(change_observer()->HasNoChange());
1007
1008  // Check that its length is now 17 and that it's all zeroes after the test
1009  // data.
1010  EXPECT_EQ(length, GetFileSize("file"));
1011  char data[100];
1012  EXPECT_EQ(length, base::ReadFile(platform_path, data, length));
1013  for (int i = 0; i < length; ++i) {
1014    if (i < static_cast<int>(sizeof(test_data)))
1015      EXPECT_EQ(test_data[i], data[i]);
1016    else
1017      EXPECT_EQ(0, data[i]);
1018  }
1019
1020  // Shorten the file by truncating it.
1021  length = 3;
1022  operation_runner()->Truncate(file, length, RecordStatusCallback());
1023  base::RunLoop().RunUntilIdle();
1024  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
1025
1026  EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
1027  EXPECT_TRUE(change_observer()->HasNoChange());
1028
1029  // Check that its length is now 3 and that it contains only bits of test data.
1030  EXPECT_EQ(length, GetFileSize("file"));
1031  EXPECT_EQ(length, base::ReadFile(platform_path, data, length));
1032  for (int i = 0; i < length; ++i)
1033    EXPECT_EQ(test_data[i], data[i]);
1034
1035  // Truncate is not a 'read' access.  (Here expected access count is 1
1036  // since we made 1 read access for GetMetadata.)
1037  EXPECT_EQ(1, quota_manager_proxy()->notify_storage_accessed_count());
1038}
1039
1040TEST_F(FileSystemOperationImplTest, TestTruncateFailureByQuota) {
1041  FileSystemURL dir(CreateDirectory("dir"));
1042  FileSystemURL file(CreateFile("dir/file"));
1043
1044  GrantQuotaForCurrentUsage();
1045  AddQuota(10);
1046
1047  operation_runner()->Truncate(file, 10, RecordStatusCallback());
1048  base::RunLoop().RunUntilIdle();
1049  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
1050  EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
1051  EXPECT_TRUE(change_observer()->HasNoChange());
1052
1053  EXPECT_EQ(10, GetFileSize("dir/file"));
1054
1055  operation_runner()->Truncate(file, 11, RecordStatusCallback());
1056  base::RunLoop().RunUntilIdle();
1057  EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE, status());
1058  EXPECT_TRUE(change_observer()->HasNoChange());
1059
1060  EXPECT_EQ(10, GetFileSize("dir/file"));
1061}
1062
1063TEST_F(FileSystemOperationImplTest, TestTouchFile) {
1064  FileSystemURL file(CreateFile("file"));
1065  base::FilePath platform_path = PlatformPath("file");
1066
1067  base::PlatformFileInfo info;
1068  EXPECT_TRUE(base::GetFileInfo(platform_path, &info));
1069  EXPECT_FALSE(info.is_directory);
1070  EXPECT_EQ(0, info.size);
1071  const base::Time last_modified = info.last_modified;
1072  const base::Time last_accessed = info.last_accessed;
1073
1074  const base::Time new_modified_time = base::Time::UnixEpoch();
1075  const base::Time new_accessed_time = new_modified_time +
1076      base::TimeDelta::FromHours(77);
1077  ASSERT_NE(last_modified, new_modified_time);
1078  ASSERT_NE(last_accessed, new_accessed_time);
1079
1080  operation_runner()->TouchFile(file, new_accessed_time, new_modified_time,
1081                                RecordStatusCallback());
1082  base::RunLoop().RunUntilIdle();
1083  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
1084  EXPECT_TRUE(change_observer()->HasNoChange());
1085
1086  EXPECT_TRUE(base::GetFileInfo(platform_path, &info));
1087  // We compare as time_t here to lower our resolution, to avoid false
1088  // negatives caused by conversion to the local filesystem's native
1089  // representation and back.
1090  EXPECT_EQ(new_modified_time.ToTimeT(), info.last_modified.ToTimeT());
1091  EXPECT_EQ(new_accessed_time.ToTimeT(), info.last_accessed.ToTimeT());
1092}
1093
1094TEST_F(FileSystemOperationImplTest, TestCreateSnapshotFile) {
1095  FileSystemURL dir(CreateDirectory("dir"));
1096
1097  // Create a file for the testing.
1098  operation_runner()->DirectoryExists(dir, RecordStatusCallback());
1099  FileSystemURL file(CreateFile("dir/file"));
1100  operation_runner()->FileExists(file, RecordStatusCallback());
1101  base::RunLoop().RunUntilIdle();
1102  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
1103
1104  // See if we can get a 'snapshot' file info for the file.
1105  // Since FileSystemOperationImpl assumes the file exists in the local
1106  // directory it should just returns the same metadata and platform_path
1107  // as the file itself.
1108  operation_runner()->CreateSnapshotFile(file, RecordSnapshotFileCallback());
1109  base::RunLoop().RunUntilIdle();
1110  EXPECT_EQ(base::PLATFORM_FILE_OK, status());
1111  EXPECT_FALSE(info().is_directory);
1112  EXPECT_EQ(PlatformPath("dir/file"), path());
1113  EXPECT_TRUE(change_observer()->HasNoChange());
1114
1115  // The FileSystemOpration implementation does not create a
1116  // shareable file reference.
1117  EXPECT_EQ(NULL, shareable_file_ref());
1118}
1119
1120TEST_F(FileSystemOperationImplTest,
1121       TestMoveSuccessSrcDirRecursiveWithQuota) {
1122  FileSystemURL src(CreateDirectory("src"));
1123  int src_path_cost = GetUsage();
1124
1125  FileSystemURL dest(CreateDirectory("dest"));
1126  FileSystemURL child_file1(CreateFile("src/file1"));
1127  FileSystemURL child_file2(CreateFile("src/file2"));
1128  FileSystemURL child_dir(CreateDirectory("src/dir"));
1129  FileSystemURL grandchild_file1(CreateFile("src/dir/file1"));
1130  FileSystemURL grandchild_file2(CreateFile("src/dir/file2"));
1131
1132  int total_path_cost = GetUsage();
1133  EXPECT_EQ(0, GetDataSizeOnDisk());
1134
1135  operation_runner()->Truncate(
1136      child_file1, 5000,
1137      base::Bind(&AssertFileErrorEq, FROM_HERE, base::PLATFORM_FILE_OK));
1138  operation_runner()->Truncate(
1139      child_file2, 400,
1140      base::Bind(&AssertFileErrorEq, FROM_HERE, base::PLATFORM_FILE_OK));
1141  operation_runner()->Truncate(
1142      grandchild_file1, 30,
1143      base::Bind(&AssertFileErrorEq, FROM_HERE, base::PLATFORM_FILE_OK));
1144  operation_runner()->Truncate(
1145      grandchild_file2, 2,
1146      base::Bind(&AssertFileErrorEq, FROM_HERE, base::PLATFORM_FILE_OK));
1147  base::RunLoop().RunUntilIdle();
1148
1149  const int64 all_file_size = 5000 + 400 + 30 + 2;
1150  EXPECT_EQ(all_file_size, GetDataSizeOnDisk());
1151  EXPECT_EQ(all_file_size + total_path_cost, GetUsage());
1152
1153  operation_runner()->Move(
1154      src, dest, FileSystemOperation::OPTION_NONE,
1155      base::Bind(&AssertFileErrorEq, FROM_HERE, base::PLATFORM_FILE_OK));
1156  base::RunLoop().RunUntilIdle();
1157
1158  EXPECT_FALSE(DirectoryExists("src/dir"));
1159  EXPECT_FALSE(FileExists("src/dir/file2"));
1160  EXPECT_TRUE(DirectoryExists("dest/dir"));
1161  EXPECT_TRUE(FileExists("dest/dir/file2"));
1162
1163  EXPECT_EQ(all_file_size, GetDataSizeOnDisk());
1164  EXPECT_EQ(all_file_size + total_path_cost - src_path_cost,
1165            GetUsage());
1166}
1167
1168TEST_F(FileSystemOperationImplTest,
1169       TestCopySuccessSrcDirRecursiveWithQuota) {
1170  FileSystemURL src(CreateDirectory("src"));
1171  FileSystemURL dest1(CreateDirectory("dest1"));
1172  FileSystemURL dest2(CreateDirectory("dest2"));
1173
1174  int64 usage = GetUsage();
1175  FileSystemURL child_file1(CreateFile("src/file1"));
1176  FileSystemURL child_file2(CreateFile("src/file2"));
1177  FileSystemURL child_dir(CreateDirectory("src/dir"));
1178  int64 child_path_cost = GetUsage() - usage;
1179  usage += child_path_cost;
1180
1181  FileSystemURL grandchild_file1(CreateFile("src/dir/file1"));
1182  FileSystemURL grandchild_file2(CreateFile("src/dir/file2"));
1183  int64 total_path_cost = GetUsage();
1184  int64 grandchild_path_cost = total_path_cost - usage;
1185
1186  EXPECT_EQ(0, GetDataSizeOnDisk());
1187
1188  operation_runner()->Truncate(
1189      child_file1, 8000,
1190      base::Bind(&AssertFileErrorEq, FROM_HERE, base::PLATFORM_FILE_OK));
1191  operation_runner()->Truncate(
1192      child_file2, 700,
1193      base::Bind(&AssertFileErrorEq, FROM_HERE, base::PLATFORM_FILE_OK));
1194  operation_runner()->Truncate(
1195      grandchild_file1, 60,
1196      base::Bind(&AssertFileErrorEq, FROM_HERE, base::PLATFORM_FILE_OK));
1197  operation_runner()->Truncate(
1198      grandchild_file2, 5,
1199      base::Bind(&AssertFileErrorEq, FROM_HERE, base::PLATFORM_FILE_OK));
1200  base::RunLoop().RunUntilIdle();
1201
1202  const int64 child_file_size = 8000 + 700;
1203  const int64 grandchild_file_size = 60 + 5;
1204  const int64 all_file_size = child_file_size + grandchild_file_size;
1205  int64 expected_usage = all_file_size + total_path_cost;
1206
1207  usage = GetUsage();
1208  EXPECT_EQ(all_file_size, GetDataSizeOnDisk());
1209  EXPECT_EQ(expected_usage, usage);
1210
1211  // Copy src to dest1.
1212  operation_runner()->Copy(
1213      src, dest1, FileSystemOperation::OPTION_NONE,
1214      FileSystemOperationRunner::CopyProgressCallback(),
1215      base::Bind(&AssertFileErrorEq, FROM_HERE, base::PLATFORM_FILE_OK));
1216  base::RunLoop().RunUntilIdle();
1217
1218  expected_usage += all_file_size + child_path_cost + grandchild_path_cost;
1219  EXPECT_TRUE(DirectoryExists("src/dir"));
1220  EXPECT_TRUE(FileExists("src/dir/file2"));
1221  EXPECT_TRUE(DirectoryExists("dest1/dir"));
1222  EXPECT_TRUE(FileExists("dest1/dir/file2"));
1223
1224  EXPECT_EQ(2 * all_file_size, GetDataSizeOnDisk());
1225  EXPECT_EQ(expected_usage, GetUsage());
1226
1227  // Copy src/dir to dest2.
1228  operation_runner()->Copy(
1229      child_dir, dest2, FileSystemOperation::OPTION_NONE,
1230      FileSystemOperationRunner::CopyProgressCallback(),
1231      base::Bind(&AssertFileErrorEq, FROM_HERE, base::PLATFORM_FILE_OK));
1232  base::RunLoop().RunUntilIdle();
1233
1234  expected_usage += grandchild_file_size + grandchild_path_cost;
1235  usage = GetUsage();
1236  EXPECT_EQ(2 * child_file_size + 3 * grandchild_file_size,
1237            GetDataSizeOnDisk());
1238  EXPECT_EQ(expected_usage, usage);
1239}
1240
1241}  // namespace fileapi
1242