1// Copyright (c) 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 <algorithm>
6#include <cstring>
7#include <string>
8
9#include "base/files/file.h"
10#include "base/files/file_path.h"
11#include "base/files/scoped_temp_dir.h"
12#include "base/strings/string16.h"
13#include "base/strings/string_piece.h"
14#include "content/browser/indexed_db/leveldb/leveldb_comparator.h"
15#include "content/browser/indexed_db/leveldb/leveldb_database.h"
16#include "content/browser/indexed_db/leveldb/leveldb_iterator.h"
17#include "content/browser/indexed_db/leveldb/leveldb_transaction.h"
18#include "testing/gtest/include/gtest/gtest.h"
19#include "third_party/leveldatabase/env_chromium.h"
20#include "third_party/leveldatabase/env_idb.h"
21
22namespace content {
23
24namespace {
25
26class SimpleComparator : public LevelDBComparator {
27 public:
28  virtual int Compare(const base::StringPiece& a,
29                      const base::StringPiece& b) const OVERRIDE {
30    size_t len = std::min(a.size(), b.size());
31    return memcmp(a.begin(), b.begin(), len);
32  }
33  virtual const char* Name() const OVERRIDE { return "temp_comparator"; }
34};
35
36}  // namespace
37
38TEST(LevelDBDatabaseTest, CorruptionTest) {
39  base::ScopedTempDir temp_directory;
40  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
41
42  const std::string key("key");
43  const std::string value("value");
44  std::string put_value;
45  std::string got_value;
46  SimpleComparator comparator;
47
48  scoped_ptr<LevelDBDatabase> leveldb;
49  LevelDBDatabase::Open(temp_directory.path(), &comparator, &leveldb);
50  EXPECT_TRUE(leveldb);
51  put_value = value;
52  leveldb::Status status = leveldb->Put(key, &put_value);
53  EXPECT_TRUE(status.ok());
54  leveldb.Pass();
55  EXPECT_FALSE(leveldb);
56
57  LevelDBDatabase::Open(temp_directory.path(), &comparator, &leveldb);
58  EXPECT_TRUE(leveldb);
59  bool found = false;
60  status = leveldb->Get(key, &got_value, &found);
61  EXPECT_TRUE(status.ok());
62  EXPECT_TRUE(found);
63  EXPECT_EQ(value, got_value);
64  leveldb.Pass();
65  EXPECT_FALSE(leveldb);
66
67  base::FilePath file_path = temp_directory.path().AppendASCII("CURRENT");
68  base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_WRITE);
69  file.SetLength(0);
70  file.Close();
71
72  status = LevelDBDatabase::Open(temp_directory.path(), &comparator, &leveldb);
73  EXPECT_FALSE(leveldb);
74  EXPECT_FALSE(status.ok());
75
76  status = LevelDBDatabase::Destroy(temp_directory.path());
77  EXPECT_TRUE(status.ok());
78
79  status = LevelDBDatabase::Open(temp_directory.path(), &comparator, &leveldb);
80  EXPECT_TRUE(status.ok());
81  EXPECT_TRUE(leveldb);
82  status = leveldb->Get(key, &got_value, &found);
83  EXPECT_TRUE(status.ok());
84  EXPECT_FALSE(found);
85}
86
87TEST(LevelDBDatabaseTest, Transaction) {
88  base::ScopedTempDir temp_directory;
89  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
90
91  const std::string key("key");
92  std::string got_value;
93  std::string put_value;
94  SimpleComparator comparator;
95
96  scoped_ptr<LevelDBDatabase> leveldb;
97  LevelDBDatabase::Open(temp_directory.path(), &comparator, &leveldb);
98  EXPECT_TRUE(leveldb);
99
100  const std::string old_value("value");
101  put_value = old_value;
102  leveldb::Status status = leveldb->Put(key, &put_value);
103  EXPECT_TRUE(status.ok());
104
105  scoped_refptr<LevelDBTransaction> transaction =
106      new LevelDBTransaction(leveldb.get());
107
108  const std::string new_value("new value");
109  put_value = new_value;
110  status = leveldb->Put(key, &put_value);
111  EXPECT_TRUE(status.ok());
112
113  bool found = false;
114  status = transaction->Get(key, &got_value, &found);
115  EXPECT_TRUE(status.ok());
116  EXPECT_TRUE(found);
117  EXPECT_EQ(comparator.Compare(got_value, old_value), 0);
118
119  found = false;
120  status = leveldb->Get(key, &got_value, &found);
121  EXPECT_TRUE(status.ok());
122  EXPECT_TRUE(found);
123  EXPECT_EQ(comparator.Compare(got_value, new_value), 0);
124
125  const std::string added_key("added key");
126  const std::string added_value("added value");
127  put_value = added_value;
128  status = leveldb->Put(added_key, &put_value);
129  EXPECT_TRUE(status.ok());
130
131  status = leveldb->Get(added_key, &got_value, &found);
132  EXPECT_TRUE(status.ok());
133  EXPECT_TRUE(found);
134  EXPECT_EQ(comparator.Compare(got_value, added_value), 0);
135
136  status = transaction->Get(added_key, &got_value, &found);
137  EXPECT_TRUE(status.ok());
138  EXPECT_FALSE(found);
139
140  const std::string another_key("another key");
141  const std::string another_value("another value");
142  put_value = another_value;
143  transaction->Put(another_key, &put_value);
144
145  status = transaction->Get(another_key, &got_value, &found);
146  EXPECT_TRUE(status.ok());
147  EXPECT_TRUE(found);
148  EXPECT_EQ(comparator.Compare(got_value, another_value), 0);
149}
150
151TEST(LevelDBDatabaseTest, TransactionIterator) {
152  base::ScopedTempDir temp_directory;
153  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
154
155  const std::string key1("key1");
156  const std::string value1("value1");
157  const std::string key2("key2");
158  const std::string value2("value2");
159  std::string put_value;
160  SimpleComparator comparator;
161
162  scoped_ptr<LevelDBDatabase> leveldb;
163  LevelDBDatabase::Open(temp_directory.path(), &comparator, &leveldb);
164  EXPECT_TRUE(leveldb);
165
166  put_value = value1;
167  leveldb::Status s = leveldb->Put(key1, &put_value);
168  EXPECT_TRUE(s.ok());
169  put_value = value2;
170  s = leveldb->Put(key2, &put_value);
171  EXPECT_TRUE(s.ok());
172
173  scoped_refptr<LevelDBTransaction> transaction =
174      new LevelDBTransaction(leveldb.get());
175
176  s = leveldb->Remove(key2);
177  EXPECT_TRUE(s.ok());
178
179  scoped_ptr<LevelDBIterator> it = transaction->CreateIterator();
180
181  it->Seek(std::string());
182
183  EXPECT_TRUE(it->IsValid());
184  EXPECT_EQ(comparator.Compare(it->Key(), key1), 0);
185  EXPECT_EQ(comparator.Compare(it->Value(), value1), 0);
186
187  it->Next();
188
189  EXPECT_TRUE(it->IsValid());
190  EXPECT_EQ(comparator.Compare(it->Key(), key2), 0);
191  EXPECT_EQ(comparator.Compare(it->Value(), value2), 0);
192
193  it->Next();
194
195  EXPECT_FALSE(it->IsValid());
196}
197
198TEST(LevelDBDatabaseTest, TransactionCommitTest) {
199  base::ScopedTempDir temp_directory;
200  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
201
202  const std::string key1("key1");
203  const std::string key2("key2");
204  const std::string value1("value1");
205  const std::string value2("value2");
206  const std::string value3("value3");
207
208  std::string put_value;
209  std::string got_value;
210  SimpleComparator comparator;
211  bool found;
212
213  scoped_ptr<LevelDBDatabase> leveldb;
214  LevelDBDatabase::Open(temp_directory.path(), &comparator, &leveldb);
215  EXPECT_TRUE(leveldb);
216
217  scoped_refptr<LevelDBTransaction> transaction =
218      new LevelDBTransaction(leveldb.get());
219
220  put_value = value1;
221  transaction->Put(key1, &put_value);
222
223  put_value = value2;
224  transaction->Put(key2, &put_value);
225
226  put_value = value3;
227  transaction->Put(key2, &put_value);
228
229  leveldb::Status status = transaction->Commit();
230  EXPECT_TRUE(status.ok());
231
232  status = leveldb->Get(key1, &got_value, &found);
233  EXPECT_TRUE(status.ok());
234  EXPECT_TRUE(found);
235  EXPECT_EQ(value1, got_value);
236
237  status = leveldb->Get(key2, &got_value, &found);
238  EXPECT_TRUE(status.ok());
239  EXPECT_TRUE(found);
240  EXPECT_EQ(value3, got_value);
241}
242
243TEST(LevelDB, Locking) {
244  base::ScopedTempDir temp_directory;
245  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
246
247  leveldb::Env* env = leveldb::IDBEnv();
248  base::FilePath file = temp_directory.path().AppendASCII("LOCK");
249  leveldb::FileLock* lock;
250  leveldb::Status status = env->LockFile(file.AsUTF8Unsafe(), &lock);
251  EXPECT_TRUE(status.ok());
252
253  status = env->UnlockFile(lock);
254  EXPECT_TRUE(status.ok());
255
256  status = env->LockFile(file.AsUTF8Unsafe(), &lock);
257  EXPECT_TRUE(status.ok());
258
259  leveldb::FileLock* lock2;
260  status = env->LockFile(file.AsUTF8Unsafe(), &lock2);
261  EXPECT_FALSE(status.ok());
262
263  status = env->UnlockFile(lock);
264  EXPECT_TRUE(status.ok());
265}
266
267}  // namespace content
268