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