1// Copyright 2014 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 "chrome/browser/sync_file_system/drive_backend/leveldb_wrapper.h" 6 7#include <string> 8 9#include "base/files/scoped_temp_dir.h" 10#include "base/logging.h" 11#include "base/strings/string_number_conversions.h" 12#include "testing/gtest/include/gtest/gtest.h" 13#include "third_party/leveldatabase/src/helpers/memenv/memenv.h" 14#include "third_party/leveldatabase/src/include/leveldb/db.h" 15#include "third_party/leveldatabase/src/include/leveldb/env.h" 16 17namespace sync_file_system { 18namespace drive_backend { 19 20struct TestData { 21 const std::string key; 22 const std::string value; 23}; 24 25class LevelDBWrapperTest : public testing::Test { 26 public: 27 virtual ~LevelDBWrapperTest() {} 28 29 virtual void SetUp() OVERRIDE { 30 ASSERT_TRUE(database_dir_.CreateUniqueTempDir()); 31 in_memory_env_.reset(leveldb::NewMemEnv(leveldb::Env::Default())); 32 InitializeLevelDB(); 33 } 34 35 virtual void TearDown() OVERRIDE { 36 db_.reset(); 37 in_memory_env_.reset(); 38 } 39 40 void CreateDefaultDatabase() { 41 leveldb::DB* db = db_->GetLevelDB(); 42 43 // Expected contents are 44 // {"a": "1", "ab": "0", "bb": "3", "d": "4"} 45 const char* keys[] = {"ab", "a", "d", "bb", "d"}; 46 for (size_t i = 0; i < arraysize(keys); ++i) { 47 leveldb::Status status = 48 db->Put(leveldb::WriteOptions(), keys[i], base::Int64ToString(i)); 49 ASSERT_TRUE(status.ok()); 50 } 51 } 52 53 LevelDBWrapper* GetDB() { 54 return db_.get(); 55 } 56 57 void CheckDBContents(const TestData expects[], size_t size) { 58 DCHECK(db_); 59 60 scoped_ptr<LevelDBWrapper::Iterator> itr = db_->NewIterator(); 61 itr->SeekToFirst(); 62 for (size_t i = 0; i < size; ++i) { 63 ASSERT_TRUE(itr->Valid()); 64 EXPECT_EQ(expects[i].key, itr->key().ToString()); 65 EXPECT_EQ(expects[i].value, itr->value().ToString()); 66 itr->Next(); 67 } 68 EXPECT_FALSE(itr->Valid()); 69 } 70 71 private: 72 void InitializeLevelDB() { 73 leveldb::DB* db = NULL; 74 leveldb::Options options; 75 options.create_if_missing = true; 76 options.max_open_files = 0; // Use minimum. 77 options.env = in_memory_env_.get(); 78 leveldb::Status status = 79 leveldb::DB::Open(options, database_dir_.path().AsUTF8Unsafe(), &db); 80 ASSERT_TRUE(status.ok()); 81 82 db_.reset(new LevelDBWrapper(make_scoped_ptr(db))); 83 } 84 85 base::ScopedTempDir database_dir_; 86 scoped_ptr<leveldb::Env> in_memory_env_; 87 scoped_ptr<LevelDBWrapper> db_; 88}; 89 90TEST_F(LevelDBWrapperTest, IteratorTest) { 91 CreateDefaultDatabase(); 92 scoped_ptr<LevelDBWrapper::Iterator> itr = GetDB()->NewIterator(); 93 94 itr->Seek("a"); 95 EXPECT_TRUE(itr->Valid()); 96 EXPECT_EQ("a", itr->key().ToString()); 97 EXPECT_EQ("1", itr->value().ToString()); 98 99 itr->Next(); 100 EXPECT_TRUE(itr->Valid()); 101 EXPECT_EQ("ab", itr->key().ToString()); 102 EXPECT_EQ("0", itr->value().ToString()); 103 104 itr->Seek("b"); 105 EXPECT_TRUE(itr->Valid()); 106 EXPECT_EQ("bb", itr->key().ToString()); 107 EXPECT_EQ("3", itr->value().ToString()); 108 109 itr->Next(); 110 EXPECT_TRUE(itr->Valid()); 111 EXPECT_EQ("d", itr->key().ToString()); 112 EXPECT_EQ("4", itr->value().ToString()); 113 114 itr->Next(); 115 EXPECT_FALSE(itr->Valid()); 116 117 itr->SeekToFirst(); 118 EXPECT_TRUE(itr->Valid()); 119 EXPECT_EQ("a", itr->key().ToString()); 120 EXPECT_EQ("1", itr->value().ToString()); 121 122 itr->Delete(); 123 EXPECT_TRUE(itr->Valid()); 124 EXPECT_EQ("ab", itr->key().ToString()); 125 EXPECT_EQ("0", itr->value().ToString()); 126 127 itr->SeekToFirst(); 128 EXPECT_TRUE(itr->Valid()); 129 EXPECT_EQ("ab", itr->key().ToString()); 130 EXPECT_EQ("0", itr->value().ToString()); 131 132 EXPECT_EQ(0, GetDB()->num_puts()); 133 EXPECT_EQ(1, GetDB()->num_deletes()); 134} 135 136TEST_F(LevelDBWrapperTest, Iterator2Test) { 137 GetDB()->Put("a", "1"); 138 GetDB()->Put("b", "2"); 139 GetDB()->Put("c", "3"); 140 // Keep pending transanctions on memory. 141 142 scoped_ptr<LevelDBWrapper::Iterator> itr = GetDB()->NewIterator(); 143 144 std::string prev_key; 145 std::string prev_value; 146 int loop_counter = 0; 147 for (itr->SeekToFirst(); itr->Valid(); itr->Next()) { 148 ASSERT_NE(prev_key, itr->key().ToString()); 149 ASSERT_NE(prev_value, itr->value().ToString()); 150 prev_key = itr->key().ToString(); 151 prev_value = itr->value().ToString(); 152 ++loop_counter; 153 } 154 EXPECT_EQ(3, loop_counter); 155 EXPECT_EQ("c", prev_key); 156 EXPECT_EQ("3", prev_value); 157 158 EXPECT_EQ(3, GetDB()->num_puts()); 159 EXPECT_EQ(0, GetDB()->num_deletes()); 160} 161 162TEST_F(LevelDBWrapperTest, PutTest) { 163 TestData merged_data[] = {{"a", "1"}, {"aa", "new0"}, {"ab", "0"}, 164 {"bb", "new2"}, {"c", "new1"}, {"d", "4"}}; 165 TestData orig_data[] = {{"a", "1"}, {"ab", "0"}, {"bb", "3"}, {"d", "4"}}; 166 167 CreateDefaultDatabase(); 168 169 // Add pending transactions. 170 GetDB()->Put("aa", "new0"); 171 GetDB()->Put("c", "new1"); 172 GetDB()->Put("bb", "new2"); // Overwrite an entry. 173 174 SCOPED_TRACE("PutTest_Pending"); 175 CheckDBContents(merged_data, arraysize(merged_data)); 176 177 EXPECT_EQ(3, GetDB()->num_puts()); 178 // Remove all pending transactions. 179 GetDB()->Clear(); 180 EXPECT_EQ(0, GetDB()->num_puts()); 181 182 SCOPED_TRACE("PutTest_Clear"); 183 CheckDBContents(orig_data, arraysize(orig_data)); 184 185 // Add pending transactions again, with commiting. 186 GetDB()->Put("aa", "new0"); 187 GetDB()->Put("c", "new1"); 188 GetDB()->Put("bb", "new2"); 189 EXPECT_EQ(3, GetDB()->num_puts()); 190 GetDB()->Commit(); 191 EXPECT_EQ(0, GetDB()->num_puts()); 192 GetDB()->Clear(); // Clear just in case. 193 194 SCOPED_TRACE("PutTest_Commit"); 195 CheckDBContents(merged_data, arraysize(merged_data)); 196} 197 198TEST_F(LevelDBWrapperTest, DeleteTest) { 199 TestData merged_data[] = {{"a", "1"}, {"aa", "new0"}, {"bb", "new2"}, 200 {"d", "4"}}; 201 TestData orig_data[] = {{"a", "1"}, {"ab", "0"}, {"bb", "3"}, {"d", "4"}}; 202 203 CreateDefaultDatabase(); 204 205 // Add pending transactions. 206 GetDB()->Put("aa", "new0"); 207 GetDB()->Put("c", "new1"); 208 GetDB()->Put("bb", "new2"); // Overwrite an entry. 209 GetDB()->Delete("c"); // Remove a pending entry. 210 GetDB()->Delete("ab"); // Remove a committed entry. 211 212 EXPECT_EQ(3, GetDB()->num_puts()); 213 EXPECT_EQ(2, GetDB()->num_deletes()); 214 215 SCOPED_TRACE("DeleteTest_Pending"); 216 CheckDBContents(merged_data, arraysize(merged_data)); 217 218 // Remove all pending transactions. 219 GetDB()->Clear(); 220 221 SCOPED_TRACE("DeleteTest_Clear"); 222 CheckDBContents(orig_data, arraysize(orig_data)); 223 224 // Add pending transactions again, with commiting. 225 GetDB()->Put("aa", "new0"); 226 GetDB()->Put("c", "new1"); 227 GetDB()->Put("bb", "new2"); 228 GetDB()->Delete("c"); 229 GetDB()->Delete("ab"); 230 GetDB()->Commit(); 231 GetDB()->Clear(); 232 233 EXPECT_EQ(0, GetDB()->num_puts()); 234 EXPECT_EQ(0, GetDB()->num_deletes()); 235 236 SCOPED_TRACE("DeleteTest_Commit"); 237 CheckDBContents(merged_data, arraysize(merged_data)); 238} 239 240} // namespace drive_backend 241} // namespace sync_file_system 242