Only allow leveldb to use the minimum amount of file descriptors.
[chromium-blink-merge.git] / chrome / browser / sync_file_system / drive_backend / metadata_database_unittest.cc
blobd8fa77d5c9634df30ea8b3197d99ff7b41d88d8e
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 "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
7 #include "base/bind.h"
8 #include "base/files/scoped_temp_dir.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/message_loop/message_loop_proxy.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "third_party/leveldatabase/src/include/leveldb/db.h"
15 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
17 namespace sync_file_system {
18 namespace drive_backend {
20 typedef MetadataDatabase::FileSet FileSet;
21 typedef MetadataDatabase::FileByFileID FileByFileID;
22 typedef MetadataDatabase::FilesByParent FilesByParent;
23 typedef MetadataDatabase::FileByParentAndTitle FileByParentAndTitle;
24 typedef MetadataDatabase::FileByAppID FileByAppID;
26 namespace {
28 const int64 kInitialChangeID = 1234;
29 const char kSyncRootFolderID[] = "sync_root_folder_id";
31 bool AreEquivalentMessages(const google::protobuf::MessageLite& left,
32 const google::protobuf::MessageLite& right);
33 bool AreEquivalent(const google::protobuf::MessageLite* left,
34 const google::protobuf::MessageLite* right) {
35 return AreEquivalentMessages(*left, *right);
38 template <typename Container>
39 bool AreEquivalentMaps(const Container& left, const Container& right);
40 template <typename Key, typename Value, typename Compare>
41 bool AreEquivalent(const std::map<Key, Value, Compare>& left,
42 const std::map<Key, Value, Compare>& right) {
43 return AreEquivalentMaps(left, right);
46 template <typename Container>
47 bool AreEquivalentSets(const Container& left, const Container& right);
48 template <typename Value, typename Compare>
49 bool AreEquivalent(const std::set<Value, Compare>& left,
50 const std::set<Value, Compare>& right) {
51 return AreEquivalentSets(left, right);
54 bool AreEquivalentMessages(const google::protobuf::MessageLite& left,
55 const google::protobuf::MessageLite& right) {
56 std::string serialized_left;
57 std::string serialized_right;
58 left.SerializeToString(&serialized_left);
59 right.SerializeToString(&serialized_right);
60 return serialized_left == serialized_right;
63 template <typename Container>
64 bool AreEquivalentMaps(const Container& left, const Container& right) {
65 if (left.size() != right.size())
66 return false;
68 typedef typename Container::const_iterator const_iterator;
69 const_iterator left_itr = left.begin();
70 const_iterator right_itr = right.begin();
72 while (left_itr != left.end()) {
73 if (left_itr->first != right_itr->first)
74 return false;
75 if (!AreEquivalent(left_itr->second, right_itr->second))
76 return false;
78 ++left_itr;
79 ++right_itr;
81 return true;
84 template <typename Container>
85 bool AreEquivalentSets(const Container& left, const Container& right) {
86 if (left.size() != right.size())
87 return false;
89 typedef typename Container::const_iterator const_iterator;
90 const_iterator left_itr = left.begin();
91 const_iterator right_itr = right.begin();
92 while (left_itr != left.end()) {
93 if (!AreEquivalent(*left_itr, *right_itr))
94 return false;
95 ++left_itr;
96 ++right_itr;
98 return true;
101 void SyncStatusResultCallback(SyncStatusCode* status_out,
102 SyncStatusCode status) {
103 EXPECT_EQ(SYNC_STATUS_UNKNOWN, *status_out);
104 *status_out = status;
107 void DatabaseCreateResultCallback(SyncStatusCode* status_out,
108 scoped_ptr<MetadataDatabase>* database_out,
109 SyncStatusCode status,
110 scoped_ptr<MetadataDatabase> database) {
111 EXPECT_EQ(SYNC_STATUS_UNKNOWN, *status_out);
112 *status_out = status;
113 *database_out = database.Pass();
116 } // namespace
118 class MetadataDatabaseTest : public testing::Test {
119 public:
120 MetadataDatabaseTest() : next_file_id_number_(1) {}
122 virtual ~MetadataDatabaseTest() {}
124 virtual void SetUp() OVERRIDE {
125 ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
128 virtual void TearDown() OVERRIDE { DropDatabase(); }
130 protected:
131 std::string GenerateFileID() {
132 return "file_id_" + base::Int64ToString(next_file_id_number_++);
135 SyncStatusCode InitializeDatabase() {
136 SyncStatusCode status = SYNC_STATUS_UNKNOWN;
137 MetadataDatabase::Create(base::MessageLoopProxy::current(),
138 database_dir_.path(),
139 base::Bind(&DatabaseCreateResultCallback,
140 &status, &metadata_database_));
141 message_loop_.RunUntilIdle();
142 return status;
145 void DropDatabase() {
146 metadata_database_.reset();
147 message_loop_.RunUntilIdle();
150 MetadataDatabase* metadata_database() { return metadata_database_.get(); }
152 leveldb::DB* db() {
153 if (!metadata_database_)
154 return NULL;
155 return metadata_database_->db_.get();
158 scoped_ptr<leveldb::DB> OpenLevelDB() {
159 leveldb::DB* db = NULL;
160 leveldb::Options options;
161 options.create_if_missing = true;
162 options.max_open_files = 0; // Use minimum.
163 leveldb::Status status =
164 leveldb::DB::Open(options, database_dir_.path().AsUTF8Unsafe(), &db);
165 EXPECT_TRUE(status.ok());
166 return make_scoped_ptr(db);
169 void SetUpServiceMetadata(leveldb::DB* db) {
170 ServiceMetadata service_metadata;
171 service_metadata.set_largest_change_id(kInitialChangeID);
172 service_metadata.set_sync_root_folder_id(kSyncRootFolderID);
173 std::string value;
174 ASSERT_TRUE(service_metadata.SerializeToString(&value));
175 db->Put(leveldb::WriteOptions(), "SERVICE", value);
178 DriveFileMetadata CreateSyncRoot() {
179 DriveFileMetadata metadata;
180 metadata.set_file_id(kSyncRootFolderID);
181 metadata.set_parent_folder_id(std::string());
182 metadata.mutable_synced_details()->set_title("Chrome Syncable FileSystem");
183 metadata.mutable_synced_details()->set_kind(KIND_FOLDER);
184 metadata.set_active(true);
185 metadata.set_dirty(false);
186 return metadata;
189 DriveFileMetadata CreateUnknownFile(const std::string& app_id,
190 const std::string& parent_folder_id) {
191 DriveFileMetadata metadata;
192 metadata.set_file_id(GenerateFileID());
193 metadata.set_parent_folder_id(parent_folder_id);
194 metadata.set_app_id(app_id);
195 metadata.set_is_app_root(
196 !app_id.empty() && parent_folder_id == kSyncRootFolderID);
197 return metadata;
200 DriveFileMetadata CreateFile(const std::string& app_id,
201 const std::string& parent_folder_id,
202 const std::string& title) {
203 DriveFileMetadata file(CreateUnknownFile(app_id, parent_folder_id));
204 file.mutable_synced_details()->add_parent_folder_id(parent_folder_id);
205 file.mutable_synced_details()->set_title(title);
206 file.mutable_synced_details()->set_kind(KIND_FILE);
207 file.set_active(true);
208 file.set_dirty(false);
209 return file;
212 DriveFileMetadata CreateFolder(const std::string& app_id,
213 const std::string& parent_folder_id,
214 const std::string& title) {
215 DriveFileMetadata folder(CreateUnknownFile(app_id, parent_folder_id));
216 folder.mutable_synced_details()->add_parent_folder_id(parent_folder_id);
217 folder.mutable_synced_details()->set_title(title);
218 folder.mutable_synced_details()->set_kind(KIND_FOLDER);
219 folder.set_active(true);
220 folder.set_dirty(false);
221 return folder;
224 leveldb::Status PutFileToDB(leveldb::DB* db, const DriveFileMetadata& file) {
225 std::string key = "FILE: " + file.file_id();
226 std::string value;
227 file.SerializeToString(&value);
228 return db->Put(leveldb::WriteOptions(), key, value);
231 void VerifyReloadConsistency() {
232 scoped_ptr<MetadataDatabase> metadata_database_2;
233 ASSERT_EQ(SYNC_STATUS_OK,
234 MetadataDatabase::CreateForTesting(
235 metadata_database_->db_.Pass(),
236 &metadata_database_2));
237 metadata_database_->db_ = metadata_database_2->db_.Pass();
239 EXPECT_TRUE(AreEquivalent(metadata_database_->file_by_file_id_,
240 metadata_database_2->file_by_file_id_));
241 EXPECT_TRUE(AreEquivalent(metadata_database_->files_by_parent_,
242 metadata_database_2->files_by_parent_));
243 EXPECT_TRUE(AreEquivalent(metadata_database_->app_root_by_app_id_,
244 metadata_database_2->app_root_by_app_id_));
245 EXPECT_TRUE(AreEquivalent(
246 metadata_database_->active_file_by_parent_and_title_,
247 metadata_database_2->active_file_by_parent_and_title_));
248 EXPECT_TRUE(AreEquivalent(metadata_database_->dirty_files_,
249 metadata_database_2->dirty_files_));
252 void VerifyFile(const DriveFileMetadata& file) {
253 DriveFileMetadata file_in_metadata_db;
254 ASSERT_TRUE(metadata_database()->FindFileByFileID(
255 file.file_id(), &file_in_metadata_db));
256 EXPECT_TRUE(AreEquivalentMessages(file, file_in_metadata_db));
259 SyncStatusCode RegisterApp(const std::string& app_id,
260 const std::string& folder_id) {
261 SyncStatusCode status = SYNC_STATUS_UNKNOWN;
262 metadata_database_->RegisterApp(
263 app_id, folder_id,
264 base::Bind(&SyncStatusResultCallback, &status));
265 message_loop_.RunUntilIdle();
266 return status;
269 SyncStatusCode DisableApp(const std::string& app_id) {
270 SyncStatusCode status = SYNC_STATUS_UNKNOWN;
271 metadata_database_->DisableApp(
272 app_id, base::Bind(&SyncStatusResultCallback, &status));
273 message_loop_.RunUntilIdle();
274 return status;
277 SyncStatusCode EnableApp(const std::string& app_id) {
278 SyncStatusCode status = SYNC_STATUS_UNKNOWN;
279 metadata_database_->EnableApp(
280 app_id, base::Bind(&SyncStatusResultCallback, &status));
281 message_loop_.RunUntilIdle();
282 return status;
285 SyncStatusCode UnregisterApp(const std::string& app_id) {
286 SyncStatusCode status = SYNC_STATUS_UNKNOWN;
287 metadata_database_->UnregisterApp(
288 app_id, base::Bind(&SyncStatusResultCallback, &status));
289 message_loop_.RunUntilIdle();
290 return status;
293 private:
294 base::ScopedTempDir database_dir_;
295 base::MessageLoop message_loop_;
297 scoped_ptr<MetadataDatabase> metadata_database_;
299 int64 next_file_id_number_;
301 DISALLOW_COPY_AND_ASSIGN(MetadataDatabaseTest);
304 TEST_F(MetadataDatabaseTest, InitializationTest_Empty) {
305 EXPECT_EQ(SYNC_STATUS_OK, InitializeDatabase());
306 DropDatabase();
307 EXPECT_EQ(SYNC_STATUS_OK, InitializeDatabase());
310 TEST_F(MetadataDatabaseTest, InitializationTest_SimpleTree) {
311 std::string app_id = "app_id";
312 DriveFileMetadata sync_root(CreateSyncRoot());
313 DriveFileMetadata app_root(CreateFolder(app_id, kSyncRootFolderID, app_id));
314 DriveFileMetadata file(CreateFile(app_id, app_root.file_id(), "file"));
315 DriveFileMetadata folder(CreateFolder(app_id, app_root.file_id(), "folder"));
316 DriveFileMetadata file_in_folder(
317 CreateFile(app_id, folder.file_id(), "file_in_folder"));
318 DriveFileMetadata orphaned(CreateUnknownFile(std::string(), "root"));
321 scoped_ptr<leveldb::DB> db = OpenLevelDB();
322 ASSERT_TRUE(db);
323 db->Put(leveldb::WriteOptions(), "VERSION", base::Int64ToString(3));
324 SetUpServiceMetadata(db.get());
326 EXPECT_TRUE(PutFileToDB(db.get(), sync_root).ok());
327 EXPECT_TRUE(PutFileToDB(db.get(), app_root).ok());
328 EXPECT_TRUE(PutFileToDB(db.get(), file).ok());
329 EXPECT_TRUE(PutFileToDB(db.get(), folder).ok());
330 EXPECT_TRUE(PutFileToDB(db.get(), file_in_folder).ok());
331 EXPECT_TRUE(PutFileToDB(db.get(), orphaned).ok());
334 EXPECT_EQ(SYNC_STATUS_OK, InitializeDatabase());
336 VerifyFile(sync_root);
337 VerifyFile(app_root);
338 VerifyFile(file);
339 VerifyFile(folder);
340 VerifyFile(file_in_folder);
341 EXPECT_FALSE(metadata_database()->FindFileByFileID(orphaned.file_id(), NULL));
344 TEST_F(MetadataDatabaseTest, AppManagementTest) {
345 DriveFileMetadata sync_root(CreateSyncRoot());
346 DriveFileMetadata app_root(
347 CreateFolder("app_id", kSyncRootFolderID, "app_id"));
348 DriveFileMetadata folder(
349 CreateFolder(std::string(), kSyncRootFolderID, "folder"));
350 folder.set_active(false);
353 scoped_ptr<leveldb::DB> db = OpenLevelDB();
354 ASSERT_TRUE(db);
355 db->Put(leveldb::WriteOptions(), "VERSION", base::Int64ToString(3));
356 SetUpServiceMetadata(db.get());
358 EXPECT_TRUE(PutFileToDB(db.get(), sync_root).ok());
359 EXPECT_TRUE(PutFileToDB(db.get(), app_root).ok());
360 EXPECT_TRUE(PutFileToDB(db.get(), folder).ok());
363 EXPECT_EQ(SYNC_STATUS_OK, InitializeDatabase());
364 VerifyFile(sync_root);
365 VerifyFile(app_root);
366 VerifyFile(folder);
368 folder.set_app_id("foo");
369 EXPECT_EQ(SYNC_STATUS_OK, RegisterApp(folder.app_id(), folder.file_id()));
371 folder.set_is_app_root(true);
372 folder.set_active(true);
373 folder.set_dirty(true);
374 folder.set_needs_folder_listing(true);
375 VerifyFile(folder);
376 VerifyReloadConsistency();
378 EXPECT_EQ(SYNC_STATUS_OK, DisableApp(folder.app_id()));
379 folder.set_active(false);
380 VerifyFile(folder);
381 VerifyReloadConsistency();
383 EXPECT_EQ(SYNC_STATUS_OK, EnableApp(folder.app_id()));
384 folder.set_active(true);
385 VerifyFile(folder);
386 VerifyReloadConsistency();
388 EXPECT_EQ(SYNC_STATUS_OK, UnregisterApp(folder.app_id()));
389 folder.set_app_id(std::string());
390 folder.set_is_app_root(false);
391 folder.set_active(false);
392 VerifyFile(folder);
393 VerifyReloadConsistency();
396 } // namespace drive_backend
397 } // namespace sync_file_system