1 // Copyright 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.
5 #include "content/browser/indexed_db/indexed_db_database.h"
9 #include "base/auto_reset.h"
10 #include "base/logging.h"
11 #include "base/run_loop.h"
12 #include "base/strings/string16.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "content/browser/indexed_db/indexed_db.h"
15 #include "content/browser/indexed_db/indexed_db_backing_store.h"
16 #include "content/browser/indexed_db/indexed_db_callbacks.h"
17 #include "content/browser/indexed_db/indexed_db_connection.h"
18 #include "content/browser/indexed_db/indexed_db_cursor.h"
19 #include "content/browser/indexed_db/indexed_db_fake_backing_store.h"
20 #include "content/browser/indexed_db/indexed_db_transaction.h"
21 #include "content/browser/indexed_db/indexed_db_value.h"
22 #include "content/browser/indexed_db/mock_indexed_db_callbacks.h"
23 #include "content/browser/indexed_db/mock_indexed_db_database_callbacks.h"
24 #include "content/browser/indexed_db/mock_indexed_db_factory.h"
25 #include "testing/gtest/include/gtest/gtest.h"
27 using base::ASCIIToUTF16;
30 const int kFakeChildProcessId = 0;
35 TEST(IndexedDBDatabaseTest, BackingStoreRetention) {
36 scoped_refptr<IndexedDBFakeBackingStore> backing_store =
37 new IndexedDBFakeBackingStore();
38 EXPECT_TRUE(backing_store->HasOneRef());
40 scoped_refptr<MockIndexedDBFactory> factory = new MockIndexedDBFactory();
42 scoped_refptr<IndexedDBDatabase> db =
43 IndexedDBDatabase::Create(ASCIIToUTF16("db"),
46 IndexedDBDatabase::Identifier(),
49 EXPECT_FALSE(backing_store->HasOneRef()); // local and db
51 EXPECT_TRUE(backing_store->HasOneRef()); // local
54 TEST(IndexedDBDatabaseTest, ConnectionLifecycle) {
55 scoped_refptr<IndexedDBFakeBackingStore> backing_store =
56 new IndexedDBFakeBackingStore();
57 EXPECT_TRUE(backing_store->HasOneRef()); // local
59 scoped_refptr<MockIndexedDBFactory> factory = new MockIndexedDBFactory();
61 scoped_refptr<IndexedDBDatabase> db =
62 IndexedDBDatabase::Create(ASCIIToUTF16("db"),
65 IndexedDBDatabase::Identifier(),
68 EXPECT_FALSE(backing_store->HasOneRef()); // local and db
70 scoped_refptr<MockIndexedDBCallbacks> request1(new MockIndexedDBCallbacks());
71 scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks1(
72 new MockIndexedDBDatabaseCallbacks());
73 const int64 transaction_id1 = 1;
74 IndexedDBPendingConnection connection1(
79 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
80 db->OpenConnection(connection1);
82 EXPECT_FALSE(backing_store->HasOneRef()); // db, connection count > 0
84 scoped_refptr<MockIndexedDBCallbacks> request2(new MockIndexedDBCallbacks());
85 scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks2(
86 new MockIndexedDBDatabaseCallbacks());
87 const int64 transaction_id2 = 2;
88 IndexedDBPendingConnection connection2(
93 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
94 db->OpenConnection(connection2);
96 EXPECT_FALSE(backing_store->HasOneRef()); // local and connection
98 request1->connection()->ForceClose();
99 EXPECT_FALSE(request1->connection()->IsConnected());
101 EXPECT_FALSE(backing_store->HasOneRef()); // local and connection
103 request2->connection()->ForceClose();
104 EXPECT_FALSE(request2->connection()->IsConnected());
106 EXPECT_TRUE(backing_store->HasOneRef());
107 EXPECT_FALSE(db->backing_store());
112 TEST(IndexedDBDatabaseTest, ForcedClose) {
113 scoped_refptr<IndexedDBFakeBackingStore> backing_store =
114 new IndexedDBFakeBackingStore();
115 EXPECT_TRUE(backing_store->HasOneRef());
117 scoped_refptr<MockIndexedDBFactory> factory = new MockIndexedDBFactory();
119 scoped_refptr<IndexedDBDatabase> database =
120 IndexedDBDatabase::Create(ASCIIToUTF16("db"),
123 IndexedDBDatabase::Identifier(),
126 EXPECT_FALSE(backing_store->HasOneRef()); // local and db
128 scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks(
129 new MockIndexedDBDatabaseCallbacks());
130 scoped_refptr<MockIndexedDBCallbacks> request(new MockIndexedDBCallbacks());
131 const int64 upgrade_transaction_id = 3;
132 IndexedDBPendingConnection connection(
136 upgrade_transaction_id,
137 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
138 database->OpenConnection(connection);
139 EXPECT_EQ(database.get(), request->connection()->database());
141 const int64 transaction_id = 123;
142 const std::vector<int64> scope;
143 database->CreateTransaction(transaction_id,
144 request->connection(),
146 blink::WebIDBTransactionModeReadOnly);
148 request->connection()->ForceClose();
150 EXPECT_TRUE(backing_store->HasOneRef()); // local
151 EXPECT_TRUE(callbacks->abort_called());
154 class MockDeleteCallbacks : public IndexedDBCallbacks {
156 MockDeleteCallbacks()
157 : IndexedDBCallbacks(NULL, 0, 0),
158 blocked_called_(false),
159 success_called_(false) {}
161 virtual void OnBlocked(int64 existing_version) OVERRIDE {
162 blocked_called_ = true;
164 virtual void OnSuccess(int64 result) OVERRIDE { success_called_ = true; }
166 bool blocked_called() const { return blocked_called_; }
167 bool success_called() const { return success_called_; }
170 virtual ~MockDeleteCallbacks() {}
172 bool blocked_called_;
173 bool success_called_;
175 DISALLOW_COPY_AND_ASSIGN(MockDeleteCallbacks);
178 TEST(IndexedDBDatabaseTest, PendingDelete) {
179 scoped_refptr<IndexedDBFakeBackingStore> backing_store =
180 new IndexedDBFakeBackingStore();
181 EXPECT_TRUE(backing_store->HasOneRef()); // local
183 scoped_refptr<MockIndexedDBFactory> factory = new MockIndexedDBFactory();
185 scoped_refptr<IndexedDBDatabase> db =
186 IndexedDBDatabase::Create(ASCIIToUTF16("db"),
189 IndexedDBDatabase::Identifier(),
192 EXPECT_FALSE(backing_store->HasOneRef()); // local and db
194 scoped_refptr<MockIndexedDBCallbacks> request1(new MockIndexedDBCallbacks());
195 scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks1(
196 new MockIndexedDBDatabaseCallbacks());
197 const int64 transaction_id1 = 1;
198 IndexedDBPendingConnection connection(
203 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
204 db->OpenConnection(connection);
206 EXPECT_FALSE(backing_store->HasOneRef()); // local and db
208 scoped_refptr<MockDeleteCallbacks> request2(new MockDeleteCallbacks());
209 db->DeleteDatabase(request2);
211 EXPECT_FALSE(request2->blocked_called());
212 db->VersionChangeIgnored();
213 EXPECT_TRUE(request2->blocked_called());
215 EXPECT_FALSE(backing_store->HasOneRef()); // local and db
217 db->Close(request1->connection(), true /* forced */);
219 EXPECT_FALSE(db->backing_store());
220 EXPECT_TRUE(backing_store->HasOneRef()); // local
221 EXPECT_TRUE(request2->success_called());
224 void DummyOperation(IndexedDBTransaction* transaction) {
227 class IndexedDBDatabaseOperationTest : public testing::Test {
229 IndexedDBDatabaseOperationTest()
230 : commit_success_(leveldb::Status::OK()),
231 factory_(new MockIndexedDBFactory()) {}
233 virtual void SetUp() {
234 backing_store_ = new IndexedDBFakeBackingStore();
236 db_ = IndexedDBDatabase::Create(ASCIIToUTF16("db"),
237 backing_store_.get(),
239 IndexedDBDatabase::Identifier(),
243 request_ = new MockIndexedDBCallbacks();
244 callbacks_ = new MockIndexedDBDatabaseCallbacks();
245 const int64 transaction_id = 1;
246 db_->OpenConnection(IndexedDBPendingConnection(
251 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION));
252 EXPECT_EQ(IndexedDBDatabaseMetadata::NO_INT_VERSION,
253 db_->metadata().int_version);
255 transaction_ = new IndexedDBTransaction(
258 std::set<int64>() /*scope*/,
259 blink::WebIDBTransactionModeVersionChange,
261 new IndexedDBFakeBackingStore::FakeTransaction(commit_success_));
262 db_->TransactionCreated(transaction_.get());
264 // Add a dummy task which takes the place of the VersionChangeOperation
265 // which kicks off the upgrade. This ensures that the transaction has
266 // processed at least one task before the CreateObjectStore call.
267 transaction_->ScheduleTask(base::Bind(&DummyOperation));
270 void RunPostedTasks() { base::RunLoop().RunUntilIdle(); }
273 scoped_refptr<IndexedDBFakeBackingStore> backing_store_;
274 scoped_refptr<IndexedDBDatabase> db_;
275 scoped_refptr<MockIndexedDBCallbacks> request_;
276 scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks_;
277 scoped_refptr<IndexedDBTransaction> transaction_;
279 leveldb::Status commit_success_;
282 base::MessageLoop message_loop_;
283 scoped_refptr<MockIndexedDBFactory> factory_;
285 DISALLOW_COPY_AND_ASSIGN(IndexedDBDatabaseOperationTest);
288 TEST_F(IndexedDBDatabaseOperationTest, CreateObjectStore) {
289 EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
290 const int64 store_id = 1001;
291 db_->CreateObjectStore(transaction_->id(),
293 ASCIIToUTF16("store"),
295 false /*auto_increment*/);
296 EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
298 transaction_->Commit();
299 EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
302 TEST_F(IndexedDBDatabaseOperationTest, CreateIndex) {
303 EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
304 const int64 store_id = 1001;
305 db_->CreateObjectStore(transaction_->id(),
307 ASCIIToUTF16("store"),
309 false /*auto_increment*/);
310 EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
311 const int64 index_id = 2002;
312 db_->CreateIndex(transaction_->id(),
315 ASCIIToUTF16("index"),
318 false /*multi_entry*/);
321 db_->metadata().object_stores.find(store_id)->second.indexes.size());
323 transaction_->Commit();
324 EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
327 db_->metadata().object_stores.find(store_id)->second.indexes.size());
330 class IndexedDBDatabaseOperationAbortTest
331 : public IndexedDBDatabaseOperationTest {
333 IndexedDBDatabaseOperationAbortTest() {
334 commit_success_ = leveldb::Status::NotFound("Bummer.");
338 DISALLOW_COPY_AND_ASSIGN(IndexedDBDatabaseOperationAbortTest);
341 TEST_F(IndexedDBDatabaseOperationAbortTest, CreateObjectStore) {
342 EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
343 const int64 store_id = 1001;
344 db_->CreateObjectStore(transaction_->id(),
346 ASCIIToUTF16("store"),
348 false /*auto_increment*/);
349 EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
351 transaction_->Commit();
352 EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
355 TEST_F(IndexedDBDatabaseOperationAbortTest, CreateIndex) {
356 EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
357 const int64 store_id = 1001;
358 db_->CreateObjectStore(transaction_->id(),
360 ASCIIToUTF16("store"),
362 false /*auto_increment*/);
363 EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
364 const int64 index_id = 2002;
365 db_->CreateIndex(transaction_->id(),
368 ASCIIToUTF16("index"),
371 false /*multi_entry*/);
374 db_->metadata().object_stores.find(store_id)->second.indexes.size());
376 transaction_->Commit();
377 EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
380 TEST_F(IndexedDBDatabaseOperationTest, CreatePutDelete) {
381 EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
382 const int64 store_id = 1001;
384 // Creation is synchronous.
385 db_->CreateObjectStore(transaction_->id(),
387 ASCIIToUTF16("store"),
389 false /*auto_increment*/);
390 EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
393 // Put is asynchronous
394 IndexedDBValue value("value1", std::vector<IndexedDBBlobInfo>());
395 ScopedVector<storage::BlobDataHandle> handles;
396 scoped_ptr<IndexedDBKey> key(new IndexedDBKey("key"));
397 std::vector<IndexedDBDatabase::IndexKeys> index_keys;
398 scoped_refptr<MockIndexedDBCallbacks> request(
399 new MockIndexedDBCallbacks(false));
400 db_->Put(transaction_->id(),
405 blink::WebIDBPutModeAddOnly,
409 // Deletion is asynchronous.
410 db_->DeleteObjectStore(transaction_->id(),
412 EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
414 // This will execute the Put then Delete.
416 EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
418 transaction_->Commit(); // Cleans up the object hierarchy.
421 } // namespace content