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