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 void OnBlocked(int64 existing_version
) override
{ blocked_called_
= true; }
162 void OnSuccess(int64 result
) override
{ success_called_
= true; }
164 bool blocked_called() const { return blocked_called_
; }
165 bool success_called() const { return success_called_
; }
168 ~MockDeleteCallbacks() override
{}
170 bool blocked_called_
;
171 bool success_called_
;
173 DISALLOW_COPY_AND_ASSIGN(MockDeleteCallbacks
);
176 TEST(IndexedDBDatabaseTest
, PendingDelete
) {
177 scoped_refptr
<IndexedDBFakeBackingStore
> backing_store
=
178 new IndexedDBFakeBackingStore();
179 EXPECT_TRUE(backing_store
->HasOneRef()); // local
181 scoped_refptr
<MockIndexedDBFactory
> factory
= new MockIndexedDBFactory();
183 scoped_refptr
<IndexedDBDatabase
> db
=
184 IndexedDBDatabase::Create(ASCIIToUTF16("db"),
187 IndexedDBDatabase::Identifier(),
190 EXPECT_FALSE(backing_store
->HasOneRef()); // local and db
192 scoped_refptr
<MockIndexedDBCallbacks
> request1(new MockIndexedDBCallbacks());
193 scoped_refptr
<MockIndexedDBDatabaseCallbacks
> callbacks1(
194 new MockIndexedDBDatabaseCallbacks());
195 const int64 transaction_id1
= 1;
196 IndexedDBPendingConnection
connection(
201 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION
);
202 db
->OpenConnection(connection
);
204 EXPECT_FALSE(backing_store
->HasOneRef()); // local and db
206 scoped_refptr
<MockDeleteCallbacks
> request2(new MockDeleteCallbacks());
207 db
->DeleteDatabase(request2
);
209 EXPECT_FALSE(request2
->blocked_called());
210 db
->VersionChangeIgnored();
211 EXPECT_TRUE(request2
->blocked_called());
213 EXPECT_FALSE(backing_store
->HasOneRef()); // local and db
215 db
->Close(request1
->connection(), true /* forced */);
217 EXPECT_FALSE(db
->backing_store());
218 EXPECT_TRUE(backing_store
->HasOneRef()); // local
219 EXPECT_TRUE(request2
->success_called());
222 void DummyOperation(IndexedDBTransaction
* transaction
) {
225 class IndexedDBDatabaseOperationTest
: public testing::Test
{
227 IndexedDBDatabaseOperationTest()
228 : commit_success_(leveldb::Status::OK()),
229 factory_(new MockIndexedDBFactory()) {}
231 void SetUp() override
{
232 backing_store_
= new IndexedDBFakeBackingStore();
234 db_
= IndexedDBDatabase::Create(ASCIIToUTF16("db"),
235 backing_store_
.get(),
237 IndexedDBDatabase::Identifier(),
241 request_
= new MockIndexedDBCallbacks();
242 callbacks_
= new MockIndexedDBDatabaseCallbacks();
243 const int64 transaction_id
= 1;
244 db_
->OpenConnection(IndexedDBPendingConnection(
249 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION
));
250 EXPECT_EQ(IndexedDBDatabaseMetadata::NO_INT_VERSION
,
251 db_
->metadata().int_version
);
253 transaction_
= new IndexedDBTransaction(
256 std::set
<int64
>() /*scope*/,
257 blink::WebIDBTransactionModeVersionChange
,
259 new IndexedDBFakeBackingStore::FakeTransaction(commit_success_
));
260 db_
->TransactionCreated(transaction_
.get());
262 // Add a dummy task which takes the place of the VersionChangeOperation
263 // which kicks off the upgrade. This ensures that the transaction has
264 // processed at least one task before the CreateObjectStore call.
265 transaction_
->ScheduleTask(base::Bind(&DummyOperation
));
268 void RunPostedTasks() { base::RunLoop().RunUntilIdle(); }
271 scoped_refptr
<IndexedDBFakeBackingStore
> backing_store_
;
272 scoped_refptr
<IndexedDBDatabase
> db_
;
273 scoped_refptr
<MockIndexedDBCallbacks
> request_
;
274 scoped_refptr
<MockIndexedDBDatabaseCallbacks
> callbacks_
;
275 scoped_refptr
<IndexedDBTransaction
> transaction_
;
277 leveldb::Status commit_success_
;
280 base::MessageLoop message_loop_
;
281 scoped_refptr
<MockIndexedDBFactory
> factory_
;
283 DISALLOW_COPY_AND_ASSIGN(IndexedDBDatabaseOperationTest
);
286 TEST_F(IndexedDBDatabaseOperationTest
, CreateObjectStore
) {
287 EXPECT_EQ(0ULL, db_
->metadata().object_stores
.size());
288 const int64 store_id
= 1001;
289 db_
->CreateObjectStore(transaction_
->id(),
291 ASCIIToUTF16("store"),
293 false /*auto_increment*/);
294 EXPECT_EQ(1ULL, db_
->metadata().object_stores
.size());
296 transaction_
->Commit();
297 EXPECT_EQ(1ULL, db_
->metadata().object_stores
.size());
300 TEST_F(IndexedDBDatabaseOperationTest
, CreateIndex
) {
301 EXPECT_EQ(0ULL, db_
->metadata().object_stores
.size());
302 const int64 store_id
= 1001;
303 db_
->CreateObjectStore(transaction_
->id(),
305 ASCIIToUTF16("store"),
307 false /*auto_increment*/);
308 EXPECT_EQ(1ULL, db_
->metadata().object_stores
.size());
309 const int64 index_id
= 2002;
310 db_
->CreateIndex(transaction_
->id(),
313 ASCIIToUTF16("index"),
316 false /*multi_entry*/);
319 db_
->metadata().object_stores
.find(store_id
)->second
.indexes
.size());
321 transaction_
->Commit();
322 EXPECT_EQ(1ULL, db_
->metadata().object_stores
.size());
325 db_
->metadata().object_stores
.find(store_id
)->second
.indexes
.size());
328 class IndexedDBDatabaseOperationAbortTest
329 : public IndexedDBDatabaseOperationTest
{
331 IndexedDBDatabaseOperationAbortTest() {
332 commit_success_
= leveldb::Status::NotFound("Bummer.");
336 DISALLOW_COPY_AND_ASSIGN(IndexedDBDatabaseOperationAbortTest
);
339 TEST_F(IndexedDBDatabaseOperationAbortTest
, CreateObjectStore
) {
340 EXPECT_EQ(0ULL, db_
->metadata().object_stores
.size());
341 const int64 store_id
= 1001;
342 db_
->CreateObjectStore(transaction_
->id(),
344 ASCIIToUTF16("store"),
346 false /*auto_increment*/);
347 EXPECT_EQ(1ULL, db_
->metadata().object_stores
.size());
349 transaction_
->Commit();
350 EXPECT_EQ(0ULL, db_
->metadata().object_stores
.size());
353 TEST_F(IndexedDBDatabaseOperationAbortTest
, CreateIndex
) {
354 EXPECT_EQ(0ULL, db_
->metadata().object_stores
.size());
355 const int64 store_id
= 1001;
356 db_
->CreateObjectStore(transaction_
->id(),
358 ASCIIToUTF16("store"),
360 false /*auto_increment*/);
361 EXPECT_EQ(1ULL, db_
->metadata().object_stores
.size());
362 const int64 index_id
= 2002;
363 db_
->CreateIndex(transaction_
->id(),
366 ASCIIToUTF16("index"),
369 false /*multi_entry*/);
372 db_
->metadata().object_stores
.find(store_id
)->second
.indexes
.size());
374 transaction_
->Commit();
375 EXPECT_EQ(0ULL, db_
->metadata().object_stores
.size());
378 TEST_F(IndexedDBDatabaseOperationTest
, CreatePutDelete
) {
379 EXPECT_EQ(0ULL, db_
->metadata().object_stores
.size());
380 const int64 store_id
= 1001;
382 // Creation is synchronous.
383 db_
->CreateObjectStore(transaction_
->id(),
385 ASCIIToUTF16("store"),
387 false /*auto_increment*/);
388 EXPECT_EQ(1ULL, db_
->metadata().object_stores
.size());
391 // Put is asynchronous
392 IndexedDBValue
value("value1", std::vector
<IndexedDBBlobInfo
>());
393 ScopedVector
<storage::BlobDataHandle
> handles
;
394 scoped_ptr
<IndexedDBKey
> key(new IndexedDBKey("key"));
395 std::vector
<IndexedDBDatabase::IndexKeys
> index_keys
;
396 scoped_refptr
<MockIndexedDBCallbacks
> request(
397 new MockIndexedDBCallbacks(false));
398 db_
->Put(transaction_
->id(),
403 blink::WebIDBPutModeAddOnly
,
407 // Deletion is asynchronous.
408 db_
->DeleteObjectStore(transaction_
->id(),
410 EXPECT_EQ(1ULL, db_
->metadata().object_stores
.size());
412 // This will execute the Put then Delete.
414 EXPECT_EQ(0ULL, db_
->metadata().object_stores
.size());
416 transaction_
->Commit(); // Cleans up the object hierarchy.
419 } // namespace content