OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/indexed_db/indexed_db_backing_store.h" | 5 #include "content/browser/indexed_db/indexed_db_backing_store.h" |
6 | 6 |
| 7 #include "base/callback.h" |
| 8 #include "base/file_util.h" |
| 9 #include "base/files/scoped_temp_dir.h" |
7 #include "base/logging.h" | 10 #include "base/logging.h" |
8 #include "base/strings/string16.h" | 11 #include "base/strings/string16.h" |
9 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
| 13 #include "base/task_runner.h" |
| 14 #include "base/test/test_simple_task_runner.h" |
| 15 #include "content/browser/indexed_db/indexed_db_context_impl.h" |
10 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h" | 16 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h" |
11 #include "content/browser/indexed_db/indexed_db_value.h" | 17 #include "content/browser/indexed_db/indexed_db_value.h" |
| 18 #include "content/public/test/mock_special_storage_policy.h" |
| 19 #include "net/url_request/url_request_test_util.h" |
12 #include "testing/gtest/include/gtest/gtest.h" | 20 #include "testing/gtest/include/gtest/gtest.h" |
13 #include "third_party/WebKit/public/platform/WebIDBTypes.h" | 21 #include "third_party/WebKit/public/platform/WebIDBTypes.h" |
| 22 #include "webkit/browser/blob/blob_data_handle.h" |
| 23 #include "webkit/browser/quota/special_storage_policy.h" |
14 | 24 |
15 using base::ASCIIToUTF16; | 25 using base::ASCIIToUTF16; |
16 | 26 |
17 namespace content { | 27 namespace content { |
18 | 28 |
19 namespace { | 29 namespace { |
20 | 30 |
| 31 class Comparator : public LevelDBComparator { |
| 32 public: |
| 33 virtual int Compare(const base::StringPiece& a, |
| 34 const base::StringPiece& b) const OVERRIDE { |
| 35 return content::Compare(a, b, false /*index_keys*/); |
| 36 } |
| 37 virtual const char* Name() const OVERRIDE { return "idb_cmp1"; } |
| 38 }; |
| 39 |
| 40 class DefaultLevelDBFactory : public LevelDBFactory { |
| 41 public: |
| 42 virtual leveldb::Status OpenLevelDB(const base::FilePath& file_name, |
| 43 const LevelDBComparator* comparator, |
| 44 scoped_ptr<LevelDBDatabase>* db, |
| 45 bool* is_disk_full) OVERRIDE { |
| 46 return LevelDBDatabase::Open(file_name, comparator, db, is_disk_full); |
| 47 } |
| 48 virtual leveldb::Status DestroyLevelDB( |
| 49 const base::FilePath& file_name) OVERRIDE { |
| 50 return LevelDBDatabase::Destroy(file_name); |
| 51 } |
| 52 }; |
| 53 |
| 54 class TestableIndexedDBBackingStore : public IndexedDBBackingStore { |
| 55 public: |
| 56 static scoped_refptr<TestableIndexedDBBackingStore> Open( |
| 57 IndexedDBFactory* indexed_db_factory, |
| 58 const GURL& origin_url, |
| 59 const base::FilePath& path_base, |
| 60 net::URLRequestContext* request_context, |
| 61 LevelDBFactory* leveldb_factory, |
| 62 base::TaskRunner* task_runner) { |
| 63 DCHECK(!path_base.empty()); |
| 64 |
| 65 scoped_ptr<LevelDBComparator> comparator(new Comparator()); |
| 66 |
| 67 if (!base::CreateDirectory(path_base)) |
| 68 return scoped_refptr<TestableIndexedDBBackingStore>(); |
| 69 |
| 70 const base::FilePath file_path = path_base.AppendASCII("test_db_path"); |
| 71 const base::FilePath blob_path = path_base.AppendASCII("test_blob_path"); |
| 72 |
| 73 scoped_ptr<LevelDBDatabase> db; |
| 74 bool is_disk_full = false; |
| 75 leveldb::Status status = leveldb_factory->OpenLevelDB( |
| 76 file_path, comparator.get(), &db, &is_disk_full); |
| 77 |
| 78 if (!db || !status.ok()) |
| 79 return scoped_refptr<TestableIndexedDBBackingStore>(); |
| 80 |
| 81 scoped_refptr<TestableIndexedDBBackingStore> backing_store( |
| 82 new TestableIndexedDBBackingStore(indexed_db_factory, |
| 83 origin_url, |
| 84 blob_path, |
| 85 request_context, |
| 86 db.Pass(), |
| 87 comparator.Pass(), |
| 88 task_runner)); |
| 89 |
| 90 if (!backing_store->SetUpMetadata()) |
| 91 return scoped_refptr<TestableIndexedDBBackingStore>(); |
| 92 |
| 93 return backing_store; |
| 94 } |
| 95 |
| 96 const std::vector<IndexedDBBackingStore::Transaction::WriteDescriptor>& |
| 97 writes() const { |
| 98 return writes_; |
| 99 } |
| 100 void ClearWrites() { writes_.clear(); } |
| 101 const std::vector<int64>& removals() const { return removals_; } |
| 102 void ClearRemovals() { removals_.clear(); } |
| 103 |
| 104 protected: |
| 105 virtual ~TestableIndexedDBBackingStore() {} |
| 106 |
| 107 virtual bool WriteBlobFile( |
| 108 int64 database_id, |
| 109 const Transaction::WriteDescriptor& descriptor, |
| 110 Transaction::ChainedBlobWriter* chained_blob_writer) OVERRIDE { |
| 111 if (KeyPrefix::IsValidDatabaseId(database_id_)) { |
| 112 if (database_id_ != database_id) { |
| 113 return false; |
| 114 } |
| 115 } else { |
| 116 database_id_ = database_id; |
| 117 } |
| 118 writes_.push_back(descriptor); |
| 119 task_runner()->PostTask( |
| 120 FROM_HERE, |
| 121 base::Bind(&Transaction::ChainedBlobWriter::ReportWriteCompletion, |
| 122 chained_blob_writer, |
| 123 true, |
| 124 1)); |
| 125 return true; |
| 126 } |
| 127 |
| 128 virtual bool RemoveBlobFile(int64 database_id, int64 key) OVERRIDE { |
| 129 if (database_id_ != database_id || |
| 130 !KeyPrefix::IsValidDatabaseId(database_id)) { |
| 131 return false; |
| 132 } |
| 133 removals_.push_back(key); |
| 134 return true; |
| 135 } |
| 136 |
| 137 // Timers don't play nicely with unit tests. |
| 138 virtual void StartJournalCleaningTimer() OVERRIDE { |
| 139 CleanPrimaryJournalIgnoreReturn(); |
| 140 } |
| 141 |
| 142 private: |
| 143 TestableIndexedDBBackingStore(IndexedDBFactory* indexed_db_factory, |
| 144 const GURL& origin_url, |
| 145 const base::FilePath& blob_path, |
| 146 net::URLRequestContext* request_context, |
| 147 scoped_ptr<LevelDBDatabase> db, |
| 148 scoped_ptr<LevelDBComparator> comparator, |
| 149 base::TaskRunner* task_runner) |
| 150 : IndexedDBBackingStore(indexed_db_factory, |
| 151 origin_url, |
| 152 blob_path, |
| 153 request_context, |
| 154 db.Pass(), |
| 155 comparator.Pass(), |
| 156 task_runner), |
| 157 database_id_(0) {} |
| 158 |
| 159 int64 database_id_; |
| 160 std::vector<Transaction::WriteDescriptor> writes_; |
| 161 std::vector<int64> removals_; |
| 162 }; |
| 163 |
| 164 class TestIDBFactory : public IndexedDBFactory { |
| 165 public: |
| 166 TestIDBFactory(IndexedDBContextImpl* idb_context) |
| 167 : IndexedDBFactory(idb_context) {} |
| 168 |
| 169 scoped_refptr<TestableIndexedDBBackingStore> OpenBackingStoreForTest( |
| 170 const GURL& origin, |
| 171 net::URLRequestContext* url_request_context) { |
| 172 blink::WebIDBDataLoss data_loss; |
| 173 std::string data_loss_reason; |
| 174 bool disk_full; |
| 175 scoped_refptr<IndexedDBBackingStore> backing_store = |
| 176 OpenBackingStore(origin, |
| 177 context()->data_path(), |
| 178 url_request_context, |
| 179 &data_loss, |
| 180 &data_loss_reason, |
| 181 &disk_full); |
| 182 scoped_refptr<TestableIndexedDBBackingStore> testable_store = |
| 183 static_cast<TestableIndexedDBBackingStore*>(backing_store.get()); |
| 184 return testable_store; |
| 185 } |
| 186 |
| 187 protected: |
| 188 virtual ~TestIDBFactory() {} |
| 189 |
| 190 virtual scoped_refptr<IndexedDBBackingStore> OpenBackingStoreHelper( |
| 191 const GURL& origin_url, |
| 192 const base::FilePath& data_directory, |
| 193 net::URLRequestContext* request_context, |
| 194 blink::WebIDBDataLoss* data_loss, |
| 195 std::string* data_loss_message, |
| 196 bool* disk_full, |
| 197 bool first_time) OVERRIDE { |
| 198 DefaultLevelDBFactory leveldb_factory; |
| 199 return TestableIndexedDBBackingStore::Open(this, |
| 200 origin_url, |
| 201 data_directory, |
| 202 request_context, |
| 203 &leveldb_factory, |
| 204 context()->TaskRunner()); |
| 205 } |
| 206 }; |
| 207 |
21 class IndexedDBBackingStoreTest : public testing::Test { | 208 class IndexedDBBackingStoreTest : public testing::Test { |
22 public: | 209 public: |
23 IndexedDBBackingStoreTest() {} | 210 IndexedDBBackingStoreTest() {} |
24 virtual void SetUp() { | 211 virtual void SetUp() { |
25 const GURL origin("http://localhost:81"); | 212 const GURL origin("http://localhost:81"); |
| 213 task_runner_ = new base::TestSimpleTaskRunner(); |
| 214 special_storage_policy_ = new MockSpecialStoragePolicy(); |
| 215 special_storage_policy_->SetAllUnlimited(true); |
| 216 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| 217 idb_context_ = new IndexedDBContextImpl( |
| 218 temp_dir_.path(), special_storage_policy_, NULL, task_runner_); |
| 219 idb_factory_ = new TestIDBFactory(idb_context_); |
26 backing_store_ = | 220 backing_store_ = |
27 IndexedDBBackingStore::OpenInMemory(origin, NULL /* task_runner */); | 221 idb_factory_->OpenBackingStoreForTest(origin, &url_request_context_); |
28 | 222 |
29 // useful keys and values during tests | 223 // useful keys and values during tests |
30 m_value1 = IndexedDBValue("value1", std::vector<IndexedDBBlobInfo>()); | 224 m_value1 = IndexedDBValue("value1", std::vector<IndexedDBBlobInfo>()); |
31 m_value2 = IndexedDBValue("value2", std::vector<IndexedDBBlobInfo>()); | 225 m_value2 = IndexedDBValue("value2", std::vector<IndexedDBBlobInfo>()); |
32 | 226 |
| 227 m_blob_info.push_back( |
| 228 IndexedDBBlobInfo("uuid 3", base::UTF8ToUTF16("blob type"), 1)); |
| 229 m_blob_info.push_back( |
| 230 IndexedDBBlobInfo("uuid 4", |
| 231 base::FilePath(FILE_PATH_LITERAL("path/to/file")), |
| 232 base::UTF8ToUTF16("file name"), |
| 233 base::UTF8ToUTF16("file type"))); |
| 234 m_value3 = IndexedDBValue("value3", m_blob_info); |
| 235 |
33 m_key1 = IndexedDBKey(99, blink::WebIDBKeyTypeNumber); | 236 m_key1 = IndexedDBKey(99, blink::WebIDBKeyTypeNumber); |
34 m_key2 = IndexedDBKey(ASCIIToUTF16("key2")); | 237 m_key2 = IndexedDBKey(ASCIIToUTF16("key2")); |
| 238 m_key3 = IndexedDBKey(ASCIIToUTF16("key3")); |
| 239 } |
| 240 |
| 241 // This just checks the data that survive getting stored and recalled, e.g. |
| 242 // the file path and UUID will change and thus aren't verified. |
| 243 bool CheckBlobInfoMatches(const std::vector<IndexedDBBlobInfo>& reads) const { |
| 244 if (m_blob_info.size() != reads.size()) |
| 245 return false; |
| 246 for (size_t i = 0; i < m_blob_info.size(); ++i) { |
| 247 const IndexedDBBlobInfo& a = m_blob_info[i]; |
| 248 const IndexedDBBlobInfo& b = reads[i]; |
| 249 if (a.is_file() != b.is_file()) |
| 250 return false; |
| 251 if (a.type() != b.type()) |
| 252 return false; |
| 253 if (a.is_file()) { |
| 254 if (a.file_name() != b.file_name()) |
| 255 return false; |
| 256 } else { |
| 257 if (a.size() != b.size()) |
| 258 return false; |
| 259 } |
| 260 } |
| 261 return true; |
| 262 } |
| 263 |
| 264 bool CheckBlobReadsMatchWrites( |
| 265 const std::vector<IndexedDBBlobInfo>& reads) const { |
| 266 if (backing_store_->writes().size() != reads.size()) |
| 267 return false; |
| 268 std::set<int64> ids; |
| 269 for (size_t i = 0; i < backing_store_->writes().size(); ++i) |
| 270 ids.insert(backing_store_->writes()[i].key()); |
| 271 if (ids.size() != backing_store_->writes().size()) |
| 272 return false; |
| 273 for (size_t i = 0; i < reads.size(); ++i) { |
| 274 if (ids.count(reads[i].key()) != 1) |
| 275 return false; |
| 276 } |
| 277 return true; |
| 278 } |
| 279 |
| 280 bool CheckBlobWrites() const { |
| 281 if (backing_store_->writes().size() != m_blob_info.size()) |
| 282 return false; |
| 283 for (size_t i = 0; i < backing_store_->writes().size(); ++i) { |
| 284 const IndexedDBBackingStore::Transaction::WriteDescriptor& desc = |
| 285 backing_store_->writes()[i]; |
| 286 const IndexedDBBlobInfo& info = m_blob_info[i]; |
| 287 if (desc.is_file() != info.is_file()) |
| 288 return false; |
| 289 if (desc.is_file()) { |
| 290 if (desc.file_path() != info.file_path()) |
| 291 return false; |
| 292 } else { |
| 293 if (desc.url() != GURL("blob:uuid/" + info.uuid())) |
| 294 return false; |
| 295 } |
| 296 } |
| 297 return true; |
| 298 } |
| 299 |
| 300 bool CheckBlobRemovals() const { |
| 301 if (backing_store_->removals().size() != backing_store_->writes().size()) |
| 302 return false; |
| 303 for (size_t i = 0; i < backing_store_->writes().size(); ++i) |
| 304 if (backing_store_->writes()[i].key() != backing_store_->removals()[i]) |
| 305 return false; |
| 306 return true; |
35 } | 307 } |
36 | 308 |
37 protected: | 309 protected: |
38 scoped_refptr<IndexedDBBackingStore> backing_store_; | 310 base::ScopedTempDir temp_dir_; |
| 311 scoped_refptr<base::TestSimpleTaskRunner> task_runner_; |
| 312 scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_; |
| 313 scoped_refptr<IndexedDBContextImpl> idb_context_; |
| 314 scoped_refptr<TestIDBFactory> idb_factory_; |
| 315 net::TestURLRequestContext url_request_context_; |
| 316 |
| 317 scoped_refptr<TestableIndexedDBBackingStore> backing_store_; |
39 | 318 |
40 // Sample keys and values that are consistent. | 319 // Sample keys and values that are consistent. |
41 IndexedDBKey m_key1; | 320 IndexedDBKey m_key1; |
42 IndexedDBKey m_key2; | 321 IndexedDBKey m_key2; |
| 322 IndexedDBKey m_key3; |
43 IndexedDBValue m_value1; | 323 IndexedDBValue m_value1; |
44 IndexedDBValue m_value2; | 324 IndexedDBValue m_value2; |
| 325 IndexedDBValue m_value3; |
| 326 std::vector<IndexedDBBlobInfo> m_blob_info; |
45 | 327 |
46 private: | 328 private: |
47 DISALLOW_COPY_AND_ASSIGN(IndexedDBBackingStoreTest); | 329 DISALLOW_COPY_AND_ASSIGN(IndexedDBBackingStoreTest); |
48 }; | 330 }; |
49 | 331 |
| 332 class TestCallback : public IndexedDBBackingStore::BlobWriteCallback { |
| 333 public: |
| 334 TestCallback() : called(false), succeeded(false) {} |
| 335 virtual void Run(bool succeeded_in) OVERRIDE { |
| 336 called = true; |
| 337 succeeded = succeeded_in; |
| 338 } |
| 339 bool called; |
| 340 bool succeeded; |
| 341 |
| 342 protected: |
| 343 virtual ~TestCallback() {} |
| 344 }; |
| 345 |
50 TEST_F(IndexedDBBackingStoreTest, PutGetConsistency) { | 346 TEST_F(IndexedDBBackingStoreTest, PutGetConsistency) { |
51 { | 347 { |
52 IndexedDBBackingStore::Transaction transaction1(backing_store_); | 348 IndexedDBBackingStore::Transaction transaction1(backing_store_); |
53 transaction1.Begin(); | 349 transaction1.Begin(); |
54 ScopedVector<webkit_blob::BlobDataHandle> handles; | 350 ScopedVector<webkit_blob::BlobDataHandle> handles; |
55 IndexedDBBackingStore::RecordIdentifier record; | 351 IndexedDBBackingStore::RecordIdentifier record; |
56 leveldb::Status s = backing_store_->PutRecord( | 352 leveldb::Status s = backing_store_->PutRecord( |
57 &transaction1, 1, 1, m_key1, m_value1, &handles, &record); | 353 &transaction1, 1, 1, m_key1, m_value1, &handles, &record); |
58 EXPECT_TRUE(s.ok()); | 354 EXPECT_TRUE(s.ok()); |
59 transaction1.Commit(); | 355 scoped_refptr<TestCallback> callback(new TestCallback()); |
| 356 EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok()); |
| 357 EXPECT_TRUE(callback->called); |
| 358 EXPECT_TRUE(callback->succeeded); |
| 359 EXPECT_TRUE(transaction1.CommitPhaseTwo().ok()); |
60 } | 360 } |
61 | 361 |
62 { | 362 { |
63 IndexedDBBackingStore::Transaction transaction2(backing_store_); | 363 IndexedDBBackingStore::Transaction transaction2(backing_store_); |
64 transaction2.Begin(); | 364 transaction2.Begin(); |
65 IndexedDBValue result_value; | 365 IndexedDBValue result_value; |
66 leveldb::Status s = | 366 EXPECT_TRUE( |
67 backing_store_->GetRecord(&transaction2, 1, 1, m_key1, &result_value); | 367 backing_store_->GetRecord(&transaction2, 1, 1, m_key1, &result_value) |
68 transaction2.Commit(); | 368 .ok()); |
69 EXPECT_TRUE(s.ok()); | 369 scoped_refptr<TestCallback> callback(new TestCallback()); |
| 370 EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok()); |
| 371 EXPECT_TRUE(callback->called); |
| 372 EXPECT_TRUE(callback->succeeded); |
| 373 EXPECT_TRUE(transaction2.CommitPhaseTwo().ok()); |
70 EXPECT_EQ(m_value1.bits, result_value.bits); | 374 EXPECT_EQ(m_value1.bits, result_value.bits); |
71 } | 375 } |
72 } | 376 } |
73 | 377 |
| 378 TEST_F(IndexedDBBackingStoreTest, PutGetConsistencyWithBlobs) { |
| 379 { |
| 380 IndexedDBBackingStore::Transaction transaction1(backing_store_); |
| 381 transaction1.Begin(); |
| 382 ScopedVector<webkit_blob::BlobDataHandle> handles; |
| 383 IndexedDBBackingStore::RecordIdentifier record; |
| 384 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, |
| 385 1, |
| 386 1, |
| 387 m_key3, |
| 388 m_value3, |
| 389 &handles, |
| 390 &record).ok()); |
| 391 scoped_refptr<TestCallback> callback(new TestCallback()); |
| 392 EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok()); |
| 393 task_runner_->RunUntilIdle(); |
| 394 EXPECT_TRUE(CheckBlobWrites()); |
| 395 EXPECT_TRUE(callback->called); |
| 396 EXPECT_TRUE(callback->succeeded); |
| 397 EXPECT_TRUE(transaction1.CommitPhaseTwo().ok()); |
| 398 } |
| 399 |
| 400 { |
| 401 IndexedDBBackingStore::Transaction transaction2(backing_store_); |
| 402 transaction2.Begin(); |
| 403 IndexedDBValue result_value; |
| 404 EXPECT_TRUE( |
| 405 backing_store_->GetRecord(&transaction2, 1, 1, m_key3, &result_value) |
| 406 .ok()); |
| 407 scoped_refptr<TestCallback> callback(new TestCallback()); |
| 408 EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok()); |
| 409 EXPECT_TRUE(callback->called); |
| 410 EXPECT_TRUE(callback->succeeded); |
| 411 EXPECT_TRUE(transaction2.CommitPhaseTwo().ok()); |
| 412 EXPECT_EQ(m_value3.bits, result_value.bits); |
| 413 EXPECT_TRUE(CheckBlobInfoMatches(result_value.blob_info)); |
| 414 EXPECT_TRUE(CheckBlobReadsMatchWrites(result_value.blob_info)); |
| 415 } |
| 416 |
| 417 { |
| 418 IndexedDBBackingStore::Transaction transaction3(backing_store_); |
| 419 transaction3.Begin(); |
| 420 IndexedDBValue result_value; |
| 421 EXPECT_TRUE(backing_store_->DeleteRange(&transaction3, |
| 422 1, |
| 423 1, |
| 424 IndexedDBKeyRange(m_key3)).ok()); |
| 425 scoped_refptr<TestCallback> callback(new TestCallback()); |
| 426 EXPECT_TRUE(transaction3.CommitPhaseOne(callback).ok()); |
| 427 task_runner_->RunUntilIdle(); |
| 428 EXPECT_TRUE(callback->called); |
| 429 EXPECT_TRUE(callback->succeeded); |
| 430 EXPECT_TRUE(transaction3.CommitPhaseTwo().ok()); |
| 431 EXPECT_TRUE(CheckBlobRemovals()); |
| 432 } |
| 433 } |
| 434 |
| 435 TEST_F(IndexedDBBackingStoreTest, DeleteRange) { |
| 436 IndexedDBKey key0 = IndexedDBKey(ASCIIToUTF16("key0")); |
| 437 IndexedDBKey key1 = IndexedDBKey(ASCIIToUTF16("key1")); |
| 438 IndexedDBKey key2 = IndexedDBKey(ASCIIToUTF16("key2")); |
| 439 IndexedDBKey key3 = IndexedDBKey(ASCIIToUTF16("key3")); |
| 440 IndexedDBBlobInfo blob0("uuid 0", base::UTF8ToUTF16("type 0"), 1); |
| 441 IndexedDBBlobInfo blob1("uuid 1", base::UTF8ToUTF16("type 1"), 1); |
| 442 IndexedDBBlobInfo blob2("uuid 2", base::UTF8ToUTF16("type 2"), 1); |
| 443 IndexedDBBlobInfo blob3("uuid 3", base::UTF8ToUTF16("type 3"), 1); |
| 444 IndexedDBKeyRange ranges[] = {IndexedDBKeyRange(key1, key2, false, false), |
| 445 IndexedDBKeyRange(key1, key2, false, false), |
| 446 IndexedDBKeyRange(key0, key2, true, false), |
| 447 IndexedDBKeyRange(key1, key3, false, true), |
| 448 IndexedDBKeyRange(key0, key3, true, true)}; |
| 449 |
| 450 for (unsigned i = 0; i < sizeof(ranges) / sizeof(IndexedDBKeyRange); ++i) { |
| 451 backing_store_->ClearWrites(); |
| 452 backing_store_->ClearRemovals(); |
| 453 |
| 454 { |
| 455 std::vector<IndexedDBBlobInfo> blob_info0, blob_info1, blob_info2, |
| 456 blob_info3; |
| 457 blob_info0.push_back(blob0); |
| 458 blob_info1.push_back(blob1); |
| 459 blob_info2.push_back(blob2); |
| 460 blob_info3.push_back(blob3); |
| 461 IndexedDBValue value0 = IndexedDBValue("value0", blob_info0); |
| 462 IndexedDBValue value1 = IndexedDBValue("value1", blob_info1); |
| 463 IndexedDBValue value2 = IndexedDBValue("value2", blob_info2); |
| 464 IndexedDBValue value3 = IndexedDBValue("value3", blob_info3); |
| 465 IndexedDBBackingStore::Transaction transaction1(backing_store_); |
| 466 transaction1.Begin(); |
| 467 ScopedVector<webkit_blob::BlobDataHandle> handles; |
| 468 IndexedDBBackingStore::RecordIdentifier record; |
| 469 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, |
| 470 1, |
| 471 i + 1, |
| 472 key0, |
| 473 value0, |
| 474 &handles, |
| 475 &record).ok()); |
| 476 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, |
| 477 1, |
| 478 i + 1, |
| 479 key1, |
| 480 value1, |
| 481 &handles, |
| 482 &record).ok()); |
| 483 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, |
| 484 1, |
| 485 i + 1, |
| 486 key2, |
| 487 value2, |
| 488 &handles, |
| 489 &record).ok()); |
| 490 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, |
| 491 1, |
| 492 i + 1, |
| 493 key3, |
| 494 value3, |
| 495 &handles, |
| 496 &record).ok()); |
| 497 scoped_refptr<TestCallback> callback(new TestCallback()); |
| 498 EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok()); |
| 499 task_runner_->RunUntilIdle(); |
| 500 EXPECT_TRUE(callback->called); |
| 501 EXPECT_TRUE(callback->succeeded); |
| 502 EXPECT_TRUE(transaction1.CommitPhaseTwo().ok()); |
| 503 } |
| 504 |
| 505 { |
| 506 IndexedDBBackingStore::Transaction transaction2(backing_store_); |
| 507 transaction2.Begin(); |
| 508 IndexedDBValue result_value; |
| 509 EXPECT_TRUE( |
| 510 backing_store_->DeleteRange(&transaction2, 1, i + 1, ranges[i]).ok()); |
| 511 scoped_refptr<TestCallback> callback(new TestCallback()); |
| 512 EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok()); |
| 513 task_runner_->RunUntilIdle(); |
| 514 EXPECT_TRUE(callback->called); |
| 515 EXPECT_TRUE(callback->succeeded); |
| 516 EXPECT_TRUE(transaction2.CommitPhaseTwo().ok()); |
| 517 EXPECT_EQ(2UL, backing_store_->removals().size()); |
| 518 EXPECT_EQ(backing_store_->writes()[1].key(), |
| 519 backing_store_->removals()[0]); |
| 520 EXPECT_EQ(backing_store_->writes()[2].key(), |
| 521 backing_store_->removals()[1]); |
| 522 } |
| 523 } |
| 524 } |
| 525 |
| 526 TEST_F(IndexedDBBackingStoreTest, DeleteRangeEmptyRange) { |
| 527 IndexedDBKey key0 = IndexedDBKey(ASCIIToUTF16("key0")); |
| 528 IndexedDBKey key1 = IndexedDBKey(ASCIIToUTF16("key1")); |
| 529 IndexedDBKey key2 = IndexedDBKey(ASCIIToUTF16("key2")); |
| 530 IndexedDBKey key3 = IndexedDBKey(ASCIIToUTF16("key3")); |
| 531 IndexedDBKey key4 = IndexedDBKey(ASCIIToUTF16("key4")); |
| 532 IndexedDBBlobInfo blob0("uuid 0", base::UTF8ToUTF16("type 0"), 1); |
| 533 IndexedDBBlobInfo blob1("uuid 1", base::UTF8ToUTF16("type 1"), 1); |
| 534 IndexedDBBlobInfo blob2("uuid 2", base::UTF8ToUTF16("type 2"), 1); |
| 535 IndexedDBBlobInfo blob3("uuid 3", base::UTF8ToUTF16("type 3"), 1); |
| 536 IndexedDBKeyRange ranges[] = {IndexedDBKeyRange(key3, key4, true, false), |
| 537 IndexedDBKeyRange(key2, key1, false, false), |
| 538 IndexedDBKeyRange(key2, key1, true, true)}; |
| 539 |
| 540 for (unsigned i = 0; i < sizeof(ranges) / sizeof(IndexedDBKeyRange); ++i) { |
| 541 backing_store_->ClearWrites(); |
| 542 backing_store_->ClearRemovals(); |
| 543 |
| 544 { |
| 545 std::vector<IndexedDBBlobInfo> blob_info0, blob_info1, blob_info2, |
| 546 blob_info3; |
| 547 blob_info0.push_back(blob0); |
| 548 blob_info1.push_back(blob1); |
| 549 blob_info2.push_back(blob2); |
| 550 blob_info3.push_back(blob3); |
| 551 IndexedDBValue value0 = IndexedDBValue("value0", blob_info0); |
| 552 IndexedDBValue value1 = IndexedDBValue("value1", blob_info1); |
| 553 IndexedDBValue value2 = IndexedDBValue("value2", blob_info2); |
| 554 IndexedDBValue value3 = IndexedDBValue("value3", blob_info3); |
| 555 IndexedDBBackingStore::Transaction transaction1(backing_store_); |
| 556 transaction1.Begin(); |
| 557 ScopedVector<webkit_blob::BlobDataHandle> handles; |
| 558 IndexedDBBackingStore::RecordIdentifier record; |
| 559 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, |
| 560 1, |
| 561 i + 1, |
| 562 key0, |
| 563 value0, |
| 564 &handles, |
| 565 &record).ok()); |
| 566 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, |
| 567 1, |
| 568 i + 1, |
| 569 key1, |
| 570 value1, |
| 571 &handles, |
| 572 &record).ok()); |
| 573 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, |
| 574 1, |
| 575 i + 1, |
| 576 key2, |
| 577 value2, |
| 578 &handles, |
| 579 &record).ok()); |
| 580 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, |
| 581 1, |
| 582 i + 1, |
| 583 key3, |
| 584 value3, |
| 585 &handles, |
| 586 &record).ok()); |
| 587 scoped_refptr<TestCallback> callback(new TestCallback()); |
| 588 EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok()); |
| 589 task_runner_->RunUntilIdle(); |
| 590 EXPECT_TRUE(callback->called); |
| 591 EXPECT_TRUE(callback->succeeded); |
| 592 EXPECT_TRUE(transaction1.CommitPhaseTwo().ok()); |
| 593 } |
| 594 |
| 595 { |
| 596 IndexedDBBackingStore::Transaction transaction2(backing_store_); |
| 597 transaction2.Begin(); |
| 598 IndexedDBValue result_value; |
| 599 EXPECT_TRUE( |
| 600 backing_store_->DeleteRange(&transaction2, 1, i + 1, ranges[i]).ok()); |
| 601 scoped_refptr<TestCallback> callback(new TestCallback()); |
| 602 EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok()); |
| 603 task_runner_->RunUntilIdle(); |
| 604 EXPECT_TRUE(callback->called); |
| 605 EXPECT_TRUE(callback->succeeded); |
| 606 EXPECT_TRUE(transaction2.CommitPhaseTwo().ok()); |
| 607 EXPECT_EQ(0UL, backing_store_->removals().size()); |
| 608 } |
| 609 } |
| 610 } |
| 611 |
| 612 TEST_F(IndexedDBBackingStoreTest, LiveBlobJournal) { |
| 613 { |
| 614 IndexedDBBackingStore::Transaction transaction1(backing_store_); |
| 615 transaction1.Begin(); |
| 616 ScopedVector<webkit_blob::BlobDataHandle> handles; |
| 617 IndexedDBBackingStore::RecordIdentifier record; |
| 618 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, |
| 619 1, |
| 620 1, |
| 621 m_key3, |
| 622 m_value3, |
| 623 &handles, |
| 624 &record).ok()); |
| 625 scoped_refptr<TestCallback> callback(new TestCallback()); |
| 626 EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok()); |
| 627 task_runner_->RunUntilIdle(); |
| 628 EXPECT_TRUE(CheckBlobWrites()); |
| 629 EXPECT_TRUE(callback->called); |
| 630 EXPECT_TRUE(callback->succeeded); |
| 631 EXPECT_TRUE(transaction1.CommitPhaseTwo().ok()); |
| 632 } |
| 633 |
| 634 IndexedDBValue read_result_value; |
| 635 { |
| 636 IndexedDBBackingStore::Transaction transaction2(backing_store_); |
| 637 transaction2.Begin(); |
| 638 EXPECT_TRUE( |
| 639 backing_store_->GetRecord( |
| 640 &transaction2, 1, 1, m_key3, &read_result_value) |
| 641 .ok()); |
| 642 scoped_refptr<TestCallback> callback(new TestCallback()); |
| 643 EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok()); |
| 644 EXPECT_TRUE(callback->called); |
| 645 EXPECT_TRUE(callback->succeeded); |
| 646 EXPECT_TRUE(transaction2.CommitPhaseTwo().ok()); |
| 647 EXPECT_EQ(m_value3.bits, read_result_value.bits); |
| 648 EXPECT_TRUE(CheckBlobInfoMatches(read_result_value.blob_info)); |
| 649 EXPECT_TRUE(CheckBlobReadsMatchWrites(read_result_value.blob_info)); |
| 650 for (size_t i = 0; i < read_result_value.blob_info.size(); ++i) { |
| 651 read_result_value.blob_info[i].mark_used_callback().Run(); |
| 652 } |
| 653 } |
| 654 |
| 655 { |
| 656 IndexedDBBackingStore::Transaction transaction3(backing_store_); |
| 657 transaction3.Begin(); |
| 658 EXPECT_TRUE(backing_store_->DeleteRange(&transaction3, |
| 659 1, |
| 660 1, |
| 661 IndexedDBKeyRange(m_key3)).ok()); |
| 662 scoped_refptr<TestCallback> callback(new TestCallback()); |
| 663 EXPECT_TRUE(transaction3.CommitPhaseOne(callback).ok()); |
| 664 task_runner_->RunUntilIdle(); |
| 665 EXPECT_TRUE(callback->called); |
| 666 EXPECT_TRUE(callback->succeeded); |
| 667 EXPECT_TRUE(transaction3.CommitPhaseTwo().ok()); |
| 668 EXPECT_EQ(0U, backing_store_->removals().size()); |
| 669 for (size_t i = 0; i < read_result_value.blob_info.size(); ++i) { |
| 670 read_result_value.blob_info[i].release_callback().Run( |
| 671 read_result_value.blob_info[i].file_path()); |
| 672 } |
| 673 task_runner_->RunUntilIdle(); |
| 674 EXPECT_NE(0U, backing_store_->removals().size()); |
| 675 EXPECT_TRUE(CheckBlobRemovals()); |
| 676 } |
| 677 } |
| 678 |
74 // Make sure that using very high ( more than 32 bit ) values for database_id | 679 // Make sure that using very high ( more than 32 bit ) values for database_id |
75 // and object_store_id still work. | 680 // and object_store_id still work. |
76 TEST_F(IndexedDBBackingStoreTest, HighIds) { | 681 TEST_F(IndexedDBBackingStoreTest, HighIds) { |
77 const int64 high_database_id = 1ULL << 35; | 682 const int64 high_database_id = 1ULL << 35; |
78 const int64 high_object_store_id = 1ULL << 39; | 683 const int64 high_object_store_id = 1ULL << 39; |
79 // index_ids are capped at 32 bits for storage purposes. | 684 // index_ids are capped at 32 bits for storage purposes. |
80 const int64 high_index_id = 1ULL << 29; | 685 const int64 high_index_id = 1ULL << 29; |
81 | 686 |
82 const int64 invalid_high_index_id = 1ULL << 37; | 687 const int64 invalid_high_index_id = 1ULL << 37; |
83 | 688 |
(...skipping 23 matching lines...) Expand all Loading... |
107 EXPECT_FALSE(s.ok()); | 712 EXPECT_FALSE(s.ok()); |
108 | 713 |
109 s = backing_store_->PutIndexDataForRecord(&transaction1, | 714 s = backing_store_->PutIndexDataForRecord(&transaction1, |
110 high_database_id, | 715 high_database_id, |
111 high_object_store_id, | 716 high_object_store_id, |
112 high_index_id, | 717 high_index_id, |
113 index_key, | 718 index_key, |
114 record); | 719 record); |
115 EXPECT_TRUE(s.ok()); | 720 EXPECT_TRUE(s.ok()); |
116 | 721 |
117 s = transaction1.Commit(); | 722 scoped_refptr<TestCallback> callback(new TestCallback()); |
| 723 s = transaction1.CommitPhaseOne(callback); |
| 724 EXPECT_TRUE(s.ok()); |
| 725 EXPECT_TRUE(callback->called); |
| 726 EXPECT_TRUE(callback->succeeded); |
| 727 s = transaction1.CommitPhaseTwo(); |
118 EXPECT_TRUE(s.ok()); | 728 EXPECT_TRUE(s.ok()); |
119 } | 729 } |
120 | 730 |
121 { | 731 { |
122 IndexedDBBackingStore::Transaction transaction2(backing_store_); | 732 IndexedDBBackingStore::Transaction transaction2(backing_store_); |
123 transaction2.Begin(); | 733 transaction2.Begin(); |
124 IndexedDBValue result_value; | 734 IndexedDBValue result_value; |
125 leveldb::Status s = backing_store_->GetRecord(&transaction2, | 735 leveldb::Status s = backing_store_->GetRecord(&transaction2, |
126 high_database_id, | 736 high_database_id, |
127 high_object_store_id, | 737 high_object_store_id, |
(...skipping 13 matching lines...) Expand all Loading... |
141 | 751 |
142 s = backing_store_->GetPrimaryKeyViaIndex(&transaction2, | 752 s = backing_store_->GetPrimaryKeyViaIndex(&transaction2, |
143 high_database_id, | 753 high_database_id, |
144 high_object_store_id, | 754 high_object_store_id, |
145 high_index_id, | 755 high_index_id, |
146 index_key, | 756 index_key, |
147 &new_primary_key); | 757 &new_primary_key); |
148 EXPECT_TRUE(s.ok()); | 758 EXPECT_TRUE(s.ok()); |
149 EXPECT_TRUE(new_primary_key->Equals(m_key1)); | 759 EXPECT_TRUE(new_primary_key->Equals(m_key1)); |
150 | 760 |
151 s = transaction2.Commit(); | 761 scoped_refptr<TestCallback> callback(new TestCallback()); |
| 762 s = transaction2.CommitPhaseOne(callback); |
| 763 EXPECT_TRUE(s.ok()); |
| 764 EXPECT_TRUE(callback->called); |
| 765 EXPECT_TRUE(callback->succeeded); |
| 766 s = transaction2.CommitPhaseTwo(); |
152 EXPECT_TRUE(s.ok()); | 767 EXPECT_TRUE(s.ok()); |
153 } | 768 } |
154 } | 769 } |
155 | 770 |
156 // Make sure that other invalid ids do not crash. | 771 // Make sure that other invalid ids do not crash. |
157 TEST_F(IndexedDBBackingStoreTest, InvalidIds) { | 772 TEST_F(IndexedDBBackingStoreTest, InvalidIds) { |
158 // valid ids for use when testing invalid ids | 773 // valid ids for use when testing invalid ids |
159 const int64 database_id = 1; | 774 const int64 database_id = 1; |
160 const int64 object_store_id = 1; | 775 const int64 object_store_id = 1; |
161 const int64 index_id = kMinimumIndexId; | 776 const int64 index_id = kMinimumIndexId; |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
280 s = backing_store_->CreateIndex(&transaction, | 895 s = backing_store_->CreateIndex(&transaction, |
281 database_id, | 896 database_id, |
282 object_store_id, | 897 object_store_id, |
283 index_id, | 898 index_id, |
284 index_name, | 899 index_name, |
285 index_key_path, | 900 index_key_path, |
286 unique, | 901 unique, |
287 multi_entry); | 902 multi_entry); |
288 EXPECT_TRUE(s.ok()); | 903 EXPECT_TRUE(s.ok()); |
289 | 904 |
290 s = transaction.Commit(); | 905 scoped_refptr<TestCallback> callback(new TestCallback()); |
| 906 s = transaction.CommitPhaseOne(callback); |
| 907 EXPECT_TRUE(s.ok()); |
| 908 EXPECT_TRUE(callback->called); |
| 909 EXPECT_TRUE(callback->succeeded); |
| 910 s = transaction.CommitPhaseTwo(); |
291 EXPECT_TRUE(s.ok()); | 911 EXPECT_TRUE(s.ok()); |
292 } | 912 } |
293 | 913 |
294 { | 914 { |
295 IndexedDBDatabaseMetadata database; | 915 IndexedDBDatabaseMetadata database; |
296 bool found; | 916 bool found; |
297 leveldb::Status s = backing_store_->GetIDBDatabaseMetaData( | 917 leveldb::Status s = backing_store_->GetIDBDatabaseMetaData( |
298 database_name, &database, &found); | 918 database_name, &database, &found); |
299 EXPECT_TRUE(s.ok()); | 919 EXPECT_TRUE(s.ok()); |
300 EXPECT_TRUE(found); | 920 EXPECT_TRUE(found); |
(...skipping 18 matching lines...) Expand all Loading... |
319 EXPECT_EQ(index_name, index.name); | 939 EXPECT_EQ(index_name, index.name); |
320 EXPECT_EQ(index_key_path, index.key_path); | 940 EXPECT_EQ(index_key_path, index.key_path); |
321 EXPECT_EQ(unique, index.unique); | 941 EXPECT_EQ(unique, index.unique); |
322 EXPECT_EQ(multi_entry, index.multi_entry); | 942 EXPECT_EQ(multi_entry, index.multi_entry); |
323 } | 943 } |
324 } | 944 } |
325 | 945 |
326 } // namespace | 946 } // namespace |
327 | 947 |
328 } // namespace content | 948 } // namespace content |
OLD | NEW |