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