indexed_db_backing_store_unittest.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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 "content/browser/indexed_db/indexed_db_backing_store.h"
6
7#include "base/file_util.h"
8#include "base/files/scoped_temp_dir.h"
9#include "base/logging.h"
10#include "base/strings/string16.h"
11#include "base/strings/utf_string_conversions.h"
12#include "content/browser/indexed_db/indexed_db_factory.h"
13#include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
14#include "testing/gtest/include/gtest/gtest.h"
15#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h"
16#include "third_party/WebKit/public/platform/WebData.h"
17
18using WebKit::WebSecurityOrigin;
19using WebKit::WebIDBKey;
20
21namespace content {
22
23namespace {
24
25class IndexedDBBackingStoreTest : public testing::Test {
26 public:
27  IndexedDBBackingStoreTest() {}
28  virtual void SetUp() {
29    string16 file_identifier;
30    backing_store_ = IndexedDBBackingStore::OpenInMemory(file_identifier);
31
32    // useful keys and values during tests
33    const char raw_value1[] = "value1";
34
35    const char raw_value2[] = "value2";
36    const char raw_value3[] = "value3";
37    m_value1.insert(
38        m_value1.end(), &raw_value1[0], &raw_value1[0] + sizeof(raw_value1));
39    m_value2.insert(
40        m_value2.end(), &raw_value2[0], &raw_value2[0] + sizeof(raw_value2));
41    m_value3.insert(
42        m_value3.end(), &raw_value3[0], &raw_value3[0] + sizeof(raw_value3));
43    m_key1 = IndexedDBKey(99, WebIDBKey::NumberType);
44    m_key2 = IndexedDBKey(ASCIIToUTF16("key2"));
45    m_key3 = IndexedDBKey(ASCIIToUTF16("key3"));
46  }
47
48 protected:
49  scoped_refptr<IndexedDBBackingStore> backing_store_;
50
51  // Sample keys and values that are consistent.
52  IndexedDBKey m_key1;
53  IndexedDBKey m_key2;
54  IndexedDBKey m_key3;
55  std::vector<char> m_value1;
56  std::vector<char> m_value2;
57  std::vector<char> m_value3;
58};
59
60TEST_F(IndexedDBBackingStoreTest, PutGetConsistency) {
61  {
62    IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
63    transaction1.begin();
64    IndexedDBBackingStore::RecordIdentifier record;
65    bool ok = backing_store_->PutRecord(
66        &transaction1, 1, 1, m_key1, m_value1, &record);
67    EXPECT_TRUE(ok);
68    transaction1.Commit();
69  }
70
71  {
72    IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
73    transaction2.begin();
74    std::vector<char> result_value;
75    bool ok =
76        backing_store_->GetRecord(&transaction2, 1, 1, m_key1, &result_value);
77    transaction2.Commit();
78    EXPECT_TRUE(ok);
79    EXPECT_EQ(m_value1, result_value);
80  }
81}
82
83// Make sure that using very high ( more than 32 bit ) values for database_id
84// and object_store_id still work.
85TEST_F(IndexedDBBackingStoreTest, HighIds) {
86  const int64 high_database_id = 1ULL << 35;
87  const int64 high_object_store_id = 1ULL << 39;
88  // index_ids are capped at 32 bits for storage purposes.
89  const int64 high_index_id = 1ULL << 29;
90
91  const int64 invalid_high_index_id = 1ULL << 37;
92
93  const IndexedDBKey& index_key = m_key2;
94  std::vector<char> index_key_raw;
95  EncodeIDBKey(index_key, &index_key_raw);
96  {
97    IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
98    transaction1.begin();
99    IndexedDBBackingStore::RecordIdentifier record;
100    bool ok = backing_store_->PutRecord(&transaction1,
101                                        high_database_id,
102                                        high_object_store_id,
103                                        m_key1,
104                                        m_value1,
105                                        &record);
106    EXPECT_TRUE(ok);
107
108    ok = backing_store_->PutIndexDataForRecord(&transaction1,
109                                               high_database_id,
110                                               high_object_store_id,
111                                               invalid_high_index_id,
112                                               index_key,
113                                               record);
114    EXPECT_FALSE(ok);
115
116    ok = backing_store_->PutIndexDataForRecord(&transaction1,
117                                               high_database_id,
118                                               high_object_store_id,
119                                               high_index_id,
120                                               index_key,
121                                               record);
122    EXPECT_TRUE(ok);
123
124    ok = transaction1.Commit();
125    EXPECT_TRUE(ok);
126  }
127
128  {
129    IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
130    transaction2.begin();
131    std::vector<char> result_value;
132    bool ok = backing_store_->GetRecord(&transaction2,
133                                        high_database_id,
134                                        high_object_store_id,
135                                        m_key1,
136                                        &result_value);
137    EXPECT_TRUE(ok);
138    EXPECT_EQ(m_value1, result_value);
139
140    scoped_ptr<IndexedDBKey> new_primary_key;
141    ok = backing_store_->GetPrimaryKeyViaIndex(&transaction2,
142                                               high_database_id,
143                                               high_object_store_id,
144                                               invalid_high_index_id,
145                                               index_key,
146                                               &new_primary_key);
147    EXPECT_FALSE(ok);
148
149    ok = backing_store_->GetPrimaryKeyViaIndex(&transaction2,
150                                               high_database_id,
151                                               high_object_store_id,
152                                               high_index_id,
153                                               index_key,
154                                               &new_primary_key);
155    EXPECT_TRUE(ok);
156    EXPECT_TRUE(new_primary_key->IsEqual(m_key1));
157
158    ok = transaction2.Commit();
159    EXPECT_TRUE(ok);
160  }
161}
162
163// Make sure that other invalid ids do not crash.
164TEST_F(IndexedDBBackingStoreTest, InvalidIds) {
165  // valid ids for use when testing invalid ids
166  const int64 database_id = 1;
167  const int64 object_store_id = 1;
168  const int64 index_id = kMinimumIndexId;
169  const int64 invalid_low_index_id = 19;  // index_ids must be > kMinimumIndexId
170
171  std::vector<char> result_value;
172
173  IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
174  transaction1.begin();
175
176  IndexedDBBackingStore::RecordIdentifier record;
177  bool ok = backing_store_->PutRecord(&transaction1,
178                                      database_id,
179                                      KeyPrefix::kInvalidId,
180                                      m_key1,
181                                      m_value1,
182                                      &record);
183  EXPECT_FALSE(ok);
184  ok = backing_store_->PutRecord(
185      &transaction1, database_id, 0, m_key1, m_value1, &record);
186  EXPECT_FALSE(ok);
187  ok = backing_store_->PutRecord(&transaction1,
188                                 KeyPrefix::kInvalidId,
189                                 object_store_id,
190                                 m_key1,
191                                 m_value1,
192                                 &record);
193  EXPECT_FALSE(ok);
194  ok = backing_store_->PutRecord(
195      &transaction1, 0, object_store_id, m_key1, m_value1, &record);
196  EXPECT_FALSE(ok);
197
198  ok = backing_store_->GetRecord(
199      &transaction1, database_id, KeyPrefix::kInvalidId, m_key1, &result_value);
200  EXPECT_FALSE(ok);
201  ok = backing_store_->GetRecord(
202      &transaction1, database_id, 0, m_key1, &result_value);
203  EXPECT_FALSE(ok);
204  ok = backing_store_->GetRecord(&transaction1,
205                                 KeyPrefix::kInvalidId,
206                                 object_store_id,
207                                 m_key1,
208                                 &result_value);
209  EXPECT_FALSE(ok);
210  ok = backing_store_->GetRecord(
211      &transaction1, 0, object_store_id, m_key1, &result_value);
212  EXPECT_FALSE(ok);
213
214  scoped_ptr<IndexedDBKey> new_primary_key;
215  ok = backing_store_->GetPrimaryKeyViaIndex(&transaction1,
216                                             database_id,
217                                             object_store_id,
218                                             KeyPrefix::kInvalidId,
219                                             m_key1,
220                                             &new_primary_key);
221  EXPECT_FALSE(ok);
222  ok = backing_store_->GetPrimaryKeyViaIndex(&transaction1,
223                                             database_id,
224                                             object_store_id,
225                                             invalid_low_index_id,
226                                             m_key1,
227                                             &new_primary_key);
228  EXPECT_FALSE(ok);
229  ok = backing_store_->GetPrimaryKeyViaIndex(
230      &transaction1, database_id, object_store_id, 0, m_key1, &new_primary_key);
231  EXPECT_FALSE(ok);
232
233  ok = backing_store_->GetPrimaryKeyViaIndex(&transaction1,
234                                             KeyPrefix::kInvalidId,
235                                             object_store_id,
236                                             index_id,
237                                             m_key1,
238                                             &new_primary_key);
239  EXPECT_FALSE(ok);
240  ok = backing_store_->GetPrimaryKeyViaIndex(&transaction1,
241                                             database_id,
242                                             KeyPrefix::kInvalidId,
243                                             index_id,
244                                             m_key1,
245                                             &new_primary_key);
246  EXPECT_FALSE(ok);
247}
248
249TEST_F(IndexedDBBackingStoreTest, CreateDatabase) {
250  const string16 database_name(ASCIIToUTF16("db1"));
251  int64 database_id;
252  const string16 version(ASCIIToUTF16("old_string_version"));
253  const int64 int_version = 9;
254
255  const int64 object_store_id = 99;
256  const string16 object_store_name(ASCIIToUTF16("object_store1"));
257  const bool auto_increment = true;
258  const IndexedDBKeyPath object_store_key_path(
259      ASCIIToUTF16("object_store_key"));
260
261  const int64 index_id = 999;
262  const string16 index_name(ASCIIToUTF16("index1"));
263  const bool unique = true;
264  const bool multi_entry = true;
265  const IndexedDBKeyPath index_key_path(ASCIIToUTF16("index_key"));
266
267  {
268    bool ok = backing_store_->CreateIDBDatabaseMetaData(
269        database_name, version, int_version, &database_id);
270    EXPECT_TRUE(ok);
271    EXPECT_GT(database_id, 0);
272
273    IndexedDBBackingStore::Transaction transaction(backing_store_.get());
274    transaction.begin();
275
276    ok = backing_store_->CreateObjectStore(&transaction,
277                                           database_id,
278                                           object_store_id,
279                                           object_store_name,
280                                           object_store_key_path,
281                                           auto_increment);
282    EXPECT_TRUE(ok);
283
284    ok = backing_store_->CreateIndex(&transaction,
285                                     database_id,
286                                     object_store_id,
287                                     index_id,
288                                     index_name,
289                                     index_key_path,
290                                     unique,
291                                     multi_entry);
292    EXPECT_TRUE(ok);
293
294    ok = transaction.Commit();
295    EXPECT_TRUE(ok);
296  }
297
298  {
299    IndexedDBDatabaseMetadata database;
300    bool found;
301    bool ok = backing_store_->GetIDBDatabaseMetaData(
302        database_name, &database, &found);
303    EXPECT_TRUE(ok);
304    EXPECT_TRUE(found);
305
306    // database.name is not filled in by the implementation.
307    EXPECT_EQ(version, database.version);
308    EXPECT_EQ(int_version, database.int_version);
309    EXPECT_EQ(database_id, database.id);
310
311    ok = backing_store_->GetObjectStores(database.id, &database.object_stores);
312    EXPECT_TRUE(ok);
313
314    EXPECT_EQ(1UL, database.object_stores.size());
315    IndexedDBObjectStoreMetadata object_store =
316        database.object_stores[object_store_id];
317    EXPECT_EQ(object_store_name, object_store.name);
318    EXPECT_EQ(object_store_key_path, object_store.key_path);
319    EXPECT_EQ(auto_increment, object_store.auto_increment);
320
321    EXPECT_EQ(1UL, object_store.indexes.size());
322    IndexedDBIndexMetadata index = object_store.indexes[index_id];
323    EXPECT_EQ(index_name, index.name);
324    EXPECT_EQ(index_key_path, index.key_path);
325    EXPECT_EQ(unique, index.unique);
326    EXPECT_EQ(multi_entry, index.multi_entry);
327  }
328}
329
330class MockIDBFactory : public IndexedDBFactory {
331 public:
332  static scoped_refptr<MockIDBFactory> Create() {
333    return make_scoped_refptr(new MockIDBFactory());
334  }
335
336  scoped_refptr<IndexedDBBackingStore> TestOpenBackingStore(
337      const WebSecurityOrigin& origin,
338      const base::FilePath& data_directory) {
339    return OpenBackingStore(origin.databaseIdentifier(), data_directory);
340  }
341
342 private:
343  virtual ~MockIDBFactory() {}
344};
345
346TEST(IndexedDBFactoryTest, BackingStoreLifetime) {
347  WebSecurityOrigin origin1 =
348      WebSecurityOrigin::createFromString("http://localhost:81");
349  WebSecurityOrigin origin2 =
350      WebSecurityOrigin::createFromString("http://localhost:82");
351
352  scoped_refptr<MockIDBFactory> factory = MockIDBFactory::Create();
353
354  base::ScopedTempDir temp_directory;
355  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
356  scoped_refptr<IndexedDBBackingStore> disk_store1 =
357      factory->TestOpenBackingStore(origin1, temp_directory.path());
358  EXPECT_TRUE(disk_store1->HasOneRef());
359
360  scoped_refptr<IndexedDBBackingStore> disk_store2 =
361      factory->TestOpenBackingStore(origin1, temp_directory.path());
362  EXPECT_EQ(disk_store1.get(), disk_store2.get());
363  EXPECT_FALSE(disk_store2->HasOneRef());
364
365  scoped_refptr<IndexedDBBackingStore> disk_store3 =
366      factory->TestOpenBackingStore(origin2, temp_directory.path());
367  EXPECT_TRUE(disk_store3->HasOneRef());
368  EXPECT_FALSE(disk_store1->HasOneRef());
369
370  disk_store2 = NULL;
371  EXPECT_TRUE(disk_store1->HasOneRef());
372}
373
374TEST(IndexedDBFactoryTest, MemoryBackingStoreLifetime) {
375  WebSecurityOrigin origin1 =
376      WebSecurityOrigin::createFromString("http://localhost:81");
377  WebSecurityOrigin origin2 =
378      WebSecurityOrigin::createFromString("http://localhost:82");
379
380  scoped_refptr<MockIDBFactory> factory = MockIDBFactory::Create();
381  scoped_refptr<IndexedDBBackingStore> mem_store1 =
382      factory->TestOpenBackingStore(origin1, base::FilePath());
383  EXPECT_FALSE(mem_store1->HasOneRef());  // mem_store1 and factory
384
385  scoped_refptr<IndexedDBBackingStore> mem_store2 =
386      factory->TestOpenBackingStore(origin1, base::FilePath());
387  EXPECT_EQ(mem_store1.get(), mem_store2.get());
388  EXPECT_FALSE(mem_store1->HasOneRef());  // mem_store1, 2 and factory
389  EXPECT_FALSE(mem_store2->HasOneRef());  // mem_store1, 2 and factory
390
391  scoped_refptr<IndexedDBBackingStore> mem_store3 =
392      factory->TestOpenBackingStore(origin2, base::FilePath());
393  EXPECT_FALSE(mem_store1->HasOneRef());  // mem_store1, 2 and factory
394  EXPECT_FALSE(mem_store3->HasOneRef());  // mem_store3 and factory
395
396  factory = NULL;
397  EXPECT_FALSE(mem_store1->HasOneRef());  // mem_store1 and 2
398  EXPECT_FALSE(mem_store2->HasOneRef());  // mem_store1 and 2
399  EXPECT_TRUE(mem_store3->HasOneRef());
400
401  mem_store2 = NULL;
402  EXPECT_TRUE(mem_store1->HasOneRef());
403}
404
405TEST(IndexedDBFactoryTest, RejectLongOrigins)
406{
407  base::ScopedTempDir temp_directory;
408  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
409  const base::FilePath base_path = temp_directory.path();
410  scoped_refptr<MockIDBFactory> factory = MockIDBFactory::Create();
411
412  int limit = file_util::GetMaximumPathComponentLength(base_path);
413  EXPECT_GT(limit, 0);
414
415  std::string origin(limit + 1, 'x');
416  WebSecurityOrigin too_long_origin =
417      WebSecurityOrigin::createFromString(WebKit::WebString::fromUTF8(
418          std::string("http://" + origin + ":81/").c_str()));
419  scoped_refptr<IndexedDBBackingStore> diskStore1 =
420      factory->TestOpenBackingStore(too_long_origin, base_path);
421  EXPECT_FALSE(diskStore1);
422
423  WebSecurityOrigin ok_origin =
424      WebSecurityOrigin::createFromString("http://someorigin.com:82/");
425  scoped_refptr<IndexedDBBackingStore> diskStore2 =
426      factory->TestOpenBackingStore(ok_origin, base_path);
427  EXPECT_TRUE(diskStore2);
428}
429
430}  // namespace
431
432}  // namespace content
433