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