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_class_factory.h"
18 #include "content/browser/indexed_db/indexed_db_connection.h"
19 #include "content/browser/indexed_db/indexed_db_cursor.h"
20 #include "content/browser/indexed_db/indexed_db_fake_backing_store.h"
21 #include "content/browser/indexed_db/indexed_db_transaction.h"
22 #include "content/browser/indexed_db/indexed_db_value.h"
23 #include "content/browser/indexed_db/mock_indexed_db_callbacks.h"
24 #include "content/browser/indexed_db/mock_indexed_db_database_callbacks.h"
25 #include "content/browser/indexed_db/mock_indexed_db_factory.h"
26 #include "testing/gtest/include/gtest/gtest.h"
28 using base::ASCIIToUTF16
;
31 const int kFakeChildProcessId
= 0;
36 TEST(IndexedDBDatabaseTest
, BackingStoreRetention
) {
37 scoped_refptr
<IndexedDBFakeBackingStore
> backing_store
=
38 new IndexedDBFakeBackingStore();
39 EXPECT_TRUE(backing_store
->HasOneRef());
41 scoped_refptr
<MockIndexedDBFactory
> factory
= new MockIndexedDBFactory();
43 scoped_refptr
<IndexedDBDatabase
> db
=
44 IndexedDBDatabase::Create(ASCIIToUTF16("db"),
47 IndexedDBDatabase::Identifier(),
50 EXPECT_FALSE(backing_store
->HasOneRef()); // local and db
52 EXPECT_TRUE(backing_store
->HasOneRef()); // local
55 TEST(IndexedDBDatabaseTest
, ConnectionLifecycle
) {
56 scoped_refptr
<IndexedDBFakeBackingStore
> backing_store
=
57 new IndexedDBFakeBackingStore();
58 EXPECT_TRUE(backing_store
->HasOneRef()); // local
60 scoped_refptr
<MockIndexedDBFactory
> factory
= new MockIndexedDBFactory();
62 scoped_refptr
<IndexedDBDatabase
> db
=
63 IndexedDBDatabase::Create(ASCIIToUTF16("db"),
66 IndexedDBDatabase::Identifier(),
69 EXPECT_FALSE(backing_store
->HasOneRef()); // local and db
71 scoped_refptr
<MockIndexedDBCallbacks
> request1(new MockIndexedDBCallbacks());
72 scoped_refptr
<MockIndexedDBDatabaseCallbacks
> callbacks1(
73 new MockIndexedDBDatabaseCallbacks());
74 const int64 transaction_id1
= 1;
75 IndexedDBPendingConnection
connection1(
80 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION
);
81 db
->OpenConnection(connection1
);
83 EXPECT_FALSE(backing_store
->HasOneRef()); // db, connection count > 0
85 scoped_refptr
<MockIndexedDBCallbacks
> request2(new MockIndexedDBCallbacks());
86 scoped_refptr
<MockIndexedDBDatabaseCallbacks
> callbacks2(
87 new MockIndexedDBDatabaseCallbacks());
88 const int64 transaction_id2
= 2;
89 IndexedDBPendingConnection
connection2(
94 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION
);
95 db
->OpenConnection(connection2
);
97 EXPECT_FALSE(backing_store
->HasOneRef()); // local and connection
99 request1
->connection()->ForceClose();
100 EXPECT_FALSE(request1
->connection()->IsConnected());
102 EXPECT_FALSE(backing_store
->HasOneRef()); // local and connection
104 request2
->connection()->ForceClose();
105 EXPECT_FALSE(request2
->connection()->IsConnected());
107 EXPECT_TRUE(backing_store
->HasOneRef());
108 EXPECT_FALSE(db
->backing_store());
113 TEST(IndexedDBDatabaseTest
, ForcedClose
) {
114 scoped_refptr
<IndexedDBFakeBackingStore
> backing_store
=
115 new IndexedDBFakeBackingStore();
116 EXPECT_TRUE(backing_store
->HasOneRef());
118 scoped_refptr
<MockIndexedDBFactory
> factory
= new MockIndexedDBFactory();
120 scoped_refptr
<IndexedDBDatabase
> database
=
121 IndexedDBDatabase::Create(ASCIIToUTF16("db"),
124 IndexedDBDatabase::Identifier(),
127 EXPECT_FALSE(backing_store
->HasOneRef()); // local and db
129 scoped_refptr
<MockIndexedDBDatabaseCallbacks
> callbacks(
130 new MockIndexedDBDatabaseCallbacks());
131 scoped_refptr
<MockIndexedDBCallbacks
> request(new MockIndexedDBCallbacks());
132 const int64 upgrade_transaction_id
= 3;
133 IndexedDBPendingConnection
connection(
137 upgrade_transaction_id
,
138 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION
);
139 database
->OpenConnection(connection
);
140 EXPECT_EQ(database
.get(), request
->connection()->database());
142 const int64 transaction_id
= 123;
143 const std::vector
<int64
> scope
;
144 database
->CreateTransaction(transaction_id
,
145 request
->connection(),
147 blink::WebIDBTransactionModeReadOnly
);
149 request
->connection()->ForceClose();
151 EXPECT_TRUE(backing_store
->HasOneRef()); // local
152 EXPECT_TRUE(callbacks
->abort_called());
155 class MockDeleteCallbacks
: public IndexedDBCallbacks
{
157 MockDeleteCallbacks()
158 : IndexedDBCallbacks(NULL
, 0, 0),
159 blocked_called_(false),
160 success_called_(false) {}
162 void OnBlocked(int64 existing_version
) override
{ blocked_called_
= true; }
163 void OnSuccess(int64 result
) override
{ success_called_
= true; }
165 bool blocked_called() const { return blocked_called_
; }
166 bool success_called() const { return success_called_
; }
169 ~MockDeleteCallbacks() override
{}
171 bool blocked_called_
;
172 bool success_called_
;
174 DISALLOW_COPY_AND_ASSIGN(MockDeleteCallbacks
);
177 TEST(IndexedDBDatabaseTest
, PendingDelete
) {
178 scoped_refptr
<IndexedDBFakeBackingStore
> backing_store
=
179 new IndexedDBFakeBackingStore();
180 EXPECT_TRUE(backing_store
->HasOneRef()); // local
182 scoped_refptr
<MockIndexedDBFactory
> factory
= new MockIndexedDBFactory();
184 scoped_refptr
<IndexedDBDatabase
> db
=
185 IndexedDBDatabase::Create(ASCIIToUTF16("db"),
188 IndexedDBDatabase::Identifier(),
191 EXPECT_FALSE(backing_store
->HasOneRef()); // local and db
193 scoped_refptr
<MockIndexedDBCallbacks
> request1(new MockIndexedDBCallbacks());
194 scoped_refptr
<MockIndexedDBDatabaseCallbacks
> callbacks1(
195 new MockIndexedDBDatabaseCallbacks());
196 const int64 transaction_id1
= 1;
197 IndexedDBPendingConnection
connection(
202 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION
);
203 db
->OpenConnection(connection
);
205 EXPECT_FALSE(backing_store
->HasOneRef()); // local and db
207 scoped_refptr
<MockDeleteCallbacks
> request2(new MockDeleteCallbacks());
208 db
->DeleteDatabase(request2
);
210 EXPECT_FALSE(request2
->blocked_called());
211 db
->VersionChangeIgnored();
212 EXPECT_TRUE(request2
->blocked_called());
214 EXPECT_FALSE(backing_store
->HasOneRef()); // local and db
216 db
->Close(request1
->connection(), true /* forced */);
218 EXPECT_FALSE(db
->backing_store());
219 EXPECT_TRUE(backing_store
->HasOneRef()); // local
220 EXPECT_TRUE(request2
->success_called());
223 void DummyOperation(IndexedDBTransaction
* transaction
) {
226 class IndexedDBDatabaseOperationTest
: public testing::Test
{
228 IndexedDBDatabaseOperationTest()
229 : commit_success_(leveldb::Status::OK()),
230 factory_(new MockIndexedDBFactory()) {}
232 void SetUp() override
{
233 backing_store_
= new IndexedDBFakeBackingStore();
235 db_
= IndexedDBDatabase::Create(ASCIIToUTF16("db"),
236 backing_store_
.get(),
238 IndexedDBDatabase::Identifier(),
242 request_
= new MockIndexedDBCallbacks();
243 callbacks_
= new MockIndexedDBDatabaseCallbacks();
244 const int64 transaction_id
= 1;
245 db_
->OpenConnection(IndexedDBPendingConnection(
250 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION
));
251 EXPECT_EQ(IndexedDBDatabaseMetadata::NO_INT_VERSION
,
252 db_
->metadata().int_version
);
254 transaction_
= IndexedDBClassFactory::Get()->CreateIndexedDBTransaction(
255 transaction_id
, callbacks_
, std::set
<int64
>() /*scope*/,
256 blink::WebIDBTransactionModeVersionChange
, db_
.get(),
257 new IndexedDBFakeBackingStore::FakeTransaction(commit_success_
));
258 db_
->TransactionCreated(transaction_
.get());
260 // Add a dummy task which takes the place of the VersionChangeOperation
261 // which kicks off the upgrade. This ensures that the transaction has
262 // processed at least one task before the CreateObjectStore call.
263 transaction_
->ScheduleTask(base::Bind(&DummyOperation
));
266 void RunPostedTasks() { base::RunLoop().RunUntilIdle(); }
269 scoped_refptr
<IndexedDBFakeBackingStore
> backing_store_
;
270 scoped_refptr
<IndexedDBDatabase
> db_
;
271 scoped_refptr
<MockIndexedDBCallbacks
> request_
;
272 scoped_refptr
<MockIndexedDBDatabaseCallbacks
> callbacks_
;
273 scoped_refptr
<IndexedDBTransaction
> transaction_
;
275 leveldb::Status commit_success_
;
278 base::MessageLoop message_loop_
;
279 scoped_refptr
<MockIndexedDBFactory
> factory_
;
281 DISALLOW_COPY_AND_ASSIGN(IndexedDBDatabaseOperationTest
);
284 TEST_F(IndexedDBDatabaseOperationTest
, CreateObjectStore
) {
285 EXPECT_EQ(0ULL, db_
->metadata().object_stores
.size());
286 const int64 store_id
= 1001;
287 db_
->CreateObjectStore(transaction_
->id(),
289 ASCIIToUTF16("store"),
291 false /*auto_increment*/);
292 EXPECT_EQ(1ULL, db_
->metadata().object_stores
.size());
294 transaction_
->Commit();
295 EXPECT_EQ(1ULL, db_
->metadata().object_stores
.size());
298 TEST_F(IndexedDBDatabaseOperationTest
, CreateIndex
) {
299 EXPECT_EQ(0ULL, db_
->metadata().object_stores
.size());
300 const int64 store_id
= 1001;
301 db_
->CreateObjectStore(transaction_
->id(),
303 ASCIIToUTF16("store"),
305 false /*auto_increment*/);
306 EXPECT_EQ(1ULL, db_
->metadata().object_stores
.size());
307 const int64 index_id
= 2002;
308 db_
->CreateIndex(transaction_
->id(),
311 ASCIIToUTF16("index"),
314 false /*multi_entry*/);
317 db_
->metadata().object_stores
.find(store_id
)->second
.indexes
.size());
319 transaction_
->Commit();
320 EXPECT_EQ(1ULL, db_
->metadata().object_stores
.size());
323 db_
->metadata().object_stores
.find(store_id
)->second
.indexes
.size());
326 class IndexedDBDatabaseOperationAbortTest
327 : public IndexedDBDatabaseOperationTest
{
329 IndexedDBDatabaseOperationAbortTest() {
330 commit_success_
= leveldb::Status::NotFound("Bummer.");
334 DISALLOW_COPY_AND_ASSIGN(IndexedDBDatabaseOperationAbortTest
);
337 TEST_F(IndexedDBDatabaseOperationAbortTest
, CreateObjectStore
) {
338 EXPECT_EQ(0ULL, db_
->metadata().object_stores
.size());
339 const int64 store_id
= 1001;
340 db_
->CreateObjectStore(transaction_
->id(),
342 ASCIIToUTF16("store"),
344 false /*auto_increment*/);
345 EXPECT_EQ(1ULL, db_
->metadata().object_stores
.size());
347 transaction_
->Commit();
348 EXPECT_EQ(0ULL, db_
->metadata().object_stores
.size());
351 TEST_F(IndexedDBDatabaseOperationAbortTest
, CreateIndex
) {
352 EXPECT_EQ(0ULL, db_
->metadata().object_stores
.size());
353 const int64 store_id
= 1001;
354 db_
->CreateObjectStore(transaction_
->id(),
356 ASCIIToUTF16("store"),
358 false /*auto_increment*/);
359 EXPECT_EQ(1ULL, db_
->metadata().object_stores
.size());
360 const int64 index_id
= 2002;
361 db_
->CreateIndex(transaction_
->id(),
364 ASCIIToUTF16("index"),
367 false /*multi_entry*/);
370 db_
->metadata().object_stores
.find(store_id
)->second
.indexes
.size());
372 transaction_
->Commit();
373 EXPECT_EQ(0ULL, db_
->metadata().object_stores
.size());
376 TEST_F(IndexedDBDatabaseOperationTest
, CreatePutDelete
) {
377 EXPECT_EQ(0ULL, db_
->metadata().object_stores
.size());
378 const int64 store_id
= 1001;
380 // Creation is synchronous.
381 db_
->CreateObjectStore(transaction_
->id(),
383 ASCIIToUTF16("store"),
385 false /*auto_increment*/);
386 EXPECT_EQ(1ULL, db_
->metadata().object_stores
.size());
389 // Put is asynchronous
390 IndexedDBValue
value("value1", std::vector
<IndexedDBBlobInfo
>());
391 ScopedVector
<storage::BlobDataHandle
> handles
;
392 scoped_ptr
<IndexedDBKey
> key(new IndexedDBKey("key"));
393 std::vector
<IndexedDBDatabase::IndexKeys
> index_keys
;
394 scoped_refptr
<MockIndexedDBCallbacks
> request(
395 new MockIndexedDBCallbacks(false));
396 db_
->Put(transaction_
->id(),
401 blink::WebIDBPutModeAddOnly
,
405 // Deletion is asynchronous.
406 db_
->DeleteObjectStore(transaction_
->id(),
408 EXPECT_EQ(1ULL, db_
->metadata().object_stores
.size());
410 // This will execute the Put then Delete.
412 EXPECT_EQ(0ULL, db_
->metadata().object_stores
.size());
414 transaction_
->Commit(); // Cleans up the object hierarchy.
417 } // namespace content