syncable_file_system_unittest.cc revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
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 "base/stl_util.h"
6#include "chrome/browser/sync_file_system/local/canned_syncable_file_system.h"
7#include "chrome/browser/sync_file_system/local/local_file_change_tracker.h"
8#include "chrome/browser/sync_file_system/local/local_file_sync_context.h"
9#include "chrome/browser/sync_file_system/local/sync_file_system_backend.h"
10#include "chrome/browser/sync_file_system/syncable_file_system_util.h"
11#include "content/public/test/sandbox_file_system_test_helper.h"
12#include "content/public/test/test_browser_thread_bundle.h"
13#include "testing/gtest/include/gtest/gtest.h"
14#include "webkit/browser/fileapi/async_file_test_helper.h"
15#include "webkit/browser/fileapi/file_system_context.h"
16#include "webkit/browser/fileapi/file_system_operation_context.h"
17#include "webkit/browser/fileapi/isolated_context.h"
18#include "webkit/browser/quota/quota_manager.h"
19#include "webkit/common/fileapi/file_system_types.h"
20#include "webkit/common/quota/quota_types.h"
21
22using base::PlatformFileError;
23using fileapi::FileSystemContext;
24using fileapi::FileSystemOperationContext;
25using fileapi::FileSystemURL;
26using fileapi::FileSystemURLSet;
27using fileapi::SandboxFileSystemTestHelper;
28using quota::QuotaManager;
29using quota::QuotaStatusCode;
30
31namespace sync_file_system {
32
33class SyncableFileSystemTest : public testing::Test {
34 public:
35  SyncableFileSystemTest()
36      : file_system_(GURL("http://example.com/"),
37                     base::MessageLoopProxy::current().get(),
38                     base::MessageLoopProxy::current().get()),
39        weak_factory_(this) {}
40
41  virtual void SetUp() {
42    ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
43
44    file_system_.SetUp();
45
46    sync_context_ =
47        new LocalFileSyncContext(data_dir_.path(),
48                                 base::MessageLoopProxy::current().get(),
49                                 base::MessageLoopProxy::current().get());
50    ASSERT_EQ(
51        sync_file_system::SYNC_STATUS_OK,
52        file_system_.MaybeInitializeFileSystemContext(sync_context_.get()));
53  }
54
55  virtual void TearDown() {
56    if (sync_context_.get())
57      sync_context_->ShutdownOnUIThread();
58    sync_context_ = NULL;
59
60    file_system_.TearDown();
61
62    // Make sure we don't leave the external filesystem.
63    // (CannedSyncableFileSystem::TearDown does not do this as there may be
64    // multiple syncable file systems registered for the name)
65    RevokeSyncableFileSystem();
66  }
67
68 protected:
69  void VerifyAndClearChange(const FileSystemURL& url,
70                            const FileChange& expected_change) {
71    SCOPED_TRACE(testing::Message() << url.DebugString() <<
72                 " expecting:" << expected_change.DebugString());
73    // Get the changes for URL and verify.
74    FileChangeList changes;
75    change_tracker()->GetChangesForURL(url, &changes);
76    ASSERT_EQ(1U, changes.size());
77    SCOPED_TRACE(testing::Message() << url.DebugString() <<
78                 " actual:" << changes.DebugString());
79    EXPECT_EQ(expected_change, changes.front());
80
81    // Clear the URL from the change tracker.
82    change_tracker()->ClearChangesForURL(url);
83  }
84
85  FileSystemURL URL(const std::string& path) {
86    return file_system_.URL(path);
87  }
88
89  FileSystemContext* file_system_context() {
90    return file_system_.file_system_context();
91  }
92
93  LocalFileChangeTracker* change_tracker() {
94    return file_system_.backend()->change_tracker();
95  }
96
97  ScopedEnableSyncFSDirectoryOperation enable_directory_operation_;
98
99  base::ScopedTempDir data_dir_;
100  content::TestBrowserThreadBundle thread_bundle_;
101  CannedSyncableFileSystem file_system_;
102
103 private:
104  scoped_refptr<LocalFileSyncContext> sync_context_;
105
106  base::WeakPtrFactory<SyncableFileSystemTest> weak_factory_;
107
108  DISALLOW_COPY_AND_ASSIGN(SyncableFileSystemTest);
109};
110
111// Brief combined testing. Just see if all the sandbox feature works.
112TEST_F(SyncableFileSystemTest, SyncableLocalSandboxCombined) {
113  // Opens a syncable file system.
114  EXPECT_EQ(base::PLATFORM_FILE_OK,
115            file_system_.OpenFileSystem());
116
117  // Do some operations.
118  EXPECT_EQ(base::PLATFORM_FILE_OK,
119            file_system_.CreateDirectory(URL("dir")));
120  EXPECT_EQ(base::PLATFORM_FILE_OK,
121            file_system_.CreateFile(URL("dir/foo")));
122
123  const int64 kOriginalQuota = QuotaManager::kSyncableStorageDefaultHostQuota;
124
125  const int64 kQuota = 12345 * 1024;
126  QuotaManager::kSyncableStorageDefaultHostQuota = kQuota;
127  int64 usage, quota;
128  EXPECT_EQ(quota::kQuotaStatusOk,
129            file_system_.GetUsageAndQuota(&usage, &quota));
130
131  // Returned quota must be what we overrode. Usage must be greater than 0
132  // as creating a file or directory consumes some space.
133  EXPECT_EQ(kQuota, quota);
134  EXPECT_GT(usage, 0);
135
136  // Truncate to extend an existing file and see if the usage reflects it.
137  const int64 kFileSizeToExtend = 333;
138  EXPECT_EQ(base::PLATFORM_FILE_OK,
139            file_system_.CreateFile(URL("dir/foo")));
140
141  EXPECT_EQ(base::PLATFORM_FILE_OK,
142            file_system_.TruncateFile(URL("dir/foo"), kFileSizeToExtend));
143
144  int64 new_usage;
145  EXPECT_EQ(quota::kQuotaStatusOk,
146            file_system_.GetUsageAndQuota(&new_usage, &quota));
147  EXPECT_EQ(kFileSizeToExtend, new_usage - usage);
148
149  // Shrink the quota to the current usage, try to extend the file further
150  // and see if it fails.
151  QuotaManager::kSyncableStorageDefaultHostQuota = new_usage;
152  EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE,
153            file_system_.TruncateFile(URL("dir/foo"), kFileSizeToExtend + 1));
154
155  usage = new_usage;
156  EXPECT_EQ(quota::kQuotaStatusOk,
157            file_system_.GetUsageAndQuota(&new_usage, &quota));
158  EXPECT_EQ(usage, new_usage);
159
160  // Deletes the file system.
161  EXPECT_EQ(base::PLATFORM_FILE_OK,
162            file_system_.DeleteFileSystem());
163
164  // Now the usage must be zero.
165  EXPECT_EQ(quota::kQuotaStatusOk,
166            file_system_.GetUsageAndQuota(&usage, &quota));
167  EXPECT_EQ(0, usage);
168
169  // Restore the system default quota.
170  QuotaManager::kSyncableStorageDefaultHostQuota = kOriginalQuota;
171}
172
173// Combined testing with LocalFileChangeTracker.
174TEST_F(SyncableFileSystemTest, ChangeTrackerSimple) {
175  EXPECT_EQ(base::PLATFORM_FILE_OK,
176            file_system_.OpenFileSystem());
177
178  const char kPath0[] = "dir a";
179  const char kPath1[] = "dir a/dir";   // child of kPath0
180  const char kPath2[] = "dir a/file";  // child of kPath0
181  const char kPath3[] = "dir b";
182
183  // Do some operations.
184  EXPECT_EQ(base::PLATFORM_FILE_OK,
185            file_system_.CreateDirectory(URL(kPath0)));  // Creates a dir.
186  EXPECT_EQ(base::PLATFORM_FILE_OK,
187            file_system_.CreateDirectory(URL(kPath1)));  // Creates another.
188  EXPECT_EQ(base::PLATFORM_FILE_OK,
189            file_system_.CreateFile(URL(kPath2)));       // Creates a file.
190  EXPECT_EQ(base::PLATFORM_FILE_OK,
191            file_system_.TruncateFile(URL(kPath2), 1));  // Modifies the file.
192  EXPECT_EQ(base::PLATFORM_FILE_OK,
193            file_system_.TruncateFile(URL(kPath2), 2));  // Modifies it again.
194
195  FileSystemURLSet urls;
196  file_system_.GetChangedURLsInTracker(&urls);
197
198  EXPECT_EQ(3U, urls.size());
199  EXPECT_TRUE(ContainsKey(urls, URL(kPath0)));
200  EXPECT_TRUE(ContainsKey(urls, URL(kPath1)));
201  EXPECT_TRUE(ContainsKey(urls, URL(kPath2)));
202
203  VerifyAndClearChange(URL(kPath0),
204                       FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
205                                  sync_file_system::SYNC_FILE_TYPE_DIRECTORY));
206  VerifyAndClearChange(URL(kPath1),
207                       FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
208                                  sync_file_system::SYNC_FILE_TYPE_DIRECTORY));
209  VerifyAndClearChange(URL(kPath2),
210                       FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
211                                  sync_file_system::SYNC_FILE_TYPE_FILE));
212
213  // Creates and removes a same directory.
214  EXPECT_EQ(base::PLATFORM_FILE_OK,
215            file_system_.CreateDirectory(URL(kPath3)));
216  EXPECT_EQ(base::PLATFORM_FILE_OK,
217            file_system_.Remove(URL(kPath3), false /* recursive */));
218
219  // The changes will be offset.
220  urls.clear();
221  file_system_.GetChangedURLsInTracker(&urls);
222  EXPECT_TRUE(urls.empty());
223
224  // Recursively removes the kPath0 directory.
225  EXPECT_EQ(base::PLATFORM_FILE_OK,
226            file_system_.Remove(URL(kPath0), true /* recursive */));
227
228  urls.clear();
229  file_system_.GetChangedURLsInTracker(&urls);
230
231  // kPath0 and its all chidren (kPath1 and kPath2) must have been deleted.
232  EXPECT_EQ(3U, urls.size());
233  EXPECT_TRUE(ContainsKey(urls, URL(kPath0)));
234  EXPECT_TRUE(ContainsKey(urls, URL(kPath1)));
235  EXPECT_TRUE(ContainsKey(urls, URL(kPath2)));
236
237  VerifyAndClearChange(URL(kPath0),
238                       FileChange(FileChange::FILE_CHANGE_DELETE,
239                                  sync_file_system::SYNC_FILE_TYPE_DIRECTORY));
240  VerifyAndClearChange(URL(kPath1),
241                       FileChange(FileChange::FILE_CHANGE_DELETE,
242                                  sync_file_system::SYNC_FILE_TYPE_DIRECTORY));
243  VerifyAndClearChange(URL(kPath2),
244                       FileChange(FileChange::FILE_CHANGE_DELETE,
245                                  sync_file_system::SYNC_FILE_TYPE_FILE));
246}
247
248// Make sure directory operation is disabled (when it's configured so).
249TEST_F(SyncableFileSystemTest, DisableDirectoryOperations) {
250  bool was_enabled = IsSyncFSDirectoryOperationEnabled();
251  SetEnableSyncFSDirectoryOperation(false);
252  EXPECT_EQ(base::PLATFORM_FILE_OK,
253            file_system_.OpenFileSystem());
254
255  // Try some directory operations (which should fail).
256  EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION,
257            file_system_.CreateDirectory(URL("dir")));
258
259  // Set up another (non-syncable) local file system.
260  SandboxFileSystemTestHelper other_file_system_(
261      GURL("http://foo.com/"), fileapi::kFileSystemTypeTemporary);
262  other_file_system_.SetUp(file_system_.file_system_context());
263
264  // Create directory '/a' and file '/a/b' in the other file system.
265  const FileSystemURL kSrcDir = other_file_system_.CreateURLFromUTF8("/a");
266  const FileSystemURL kSrcChild = other_file_system_.CreateURLFromUTF8("/a/b");
267
268  EXPECT_EQ(base::PLATFORM_FILE_OK,
269            fileapi::AsyncFileTestHelper::CreateDirectory(
270                other_file_system_.file_system_context(), kSrcDir));
271  EXPECT_EQ(base::PLATFORM_FILE_OK,
272            fileapi::AsyncFileTestHelper::CreateFile(
273                other_file_system_.file_system_context(), kSrcChild));
274
275  // Now try copying the directory into the syncable file system, which should
276  // fail if directory operation is disabled. (http://crbug.com/161442)
277  EXPECT_NE(base::PLATFORM_FILE_OK,
278            file_system_.Copy(kSrcDir, URL("dest")));
279
280  other_file_system_.TearDown();
281  SetEnableSyncFSDirectoryOperation(was_enabled);
282}
283
284}  // namespace sync_file_system
285