Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / browser / indexed_db / indexed_db_database_unittest.cc
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.
4
5 #include "content/browser/indexed_db/indexed_db_database.h"
6
7 #include <set>
8
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"
26
27 using base::ASCIIToUTF16;
28
29 namespace {
30 const int kFakeChildProcessId = 0;
31 }
32
33 namespace content {
34
35 TEST(IndexedDBDatabaseTest, BackingStoreRetention) {
36   scoped_refptr<IndexedDBFakeBackingStore> backing_store =
37       new IndexedDBFakeBackingStore();
38   EXPECT_TRUE(backing_store->HasOneRef());
39
40   scoped_refptr<MockIndexedDBFactory> factory = new MockIndexedDBFactory();
41   leveldb::Status s;
42   scoped_refptr<IndexedDBDatabase> db =
43       IndexedDBDatabase::Create(ASCIIToUTF16("db"),
44                                 backing_store.get(),
45                                 factory.get(),
46                                 IndexedDBDatabase::Identifier(),
47                                 &s);
48   ASSERT_TRUE(s.ok());
49   EXPECT_FALSE(backing_store->HasOneRef());  // local and db
50   db = NULL;
51   EXPECT_TRUE(backing_store->HasOneRef());  // local
52 }
53
54 TEST(IndexedDBDatabaseTest, ConnectionLifecycle) {
55   scoped_refptr<IndexedDBFakeBackingStore> backing_store =
56       new IndexedDBFakeBackingStore();
57   EXPECT_TRUE(backing_store->HasOneRef());  // local
58
59   scoped_refptr<MockIndexedDBFactory> factory = new MockIndexedDBFactory();
60   leveldb::Status s;
61   scoped_refptr<IndexedDBDatabase> db =
62       IndexedDBDatabase::Create(ASCIIToUTF16("db"),
63                                 backing_store.get(),
64                                 factory.get(),
65                                 IndexedDBDatabase::Identifier(),
66                                 &s);
67   ASSERT_TRUE(s.ok());
68   EXPECT_FALSE(backing_store->HasOneRef());  // local and db
69
70   scoped_refptr<MockIndexedDBCallbacks> request1(new MockIndexedDBCallbacks());
71   scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks1(
72       new MockIndexedDBDatabaseCallbacks());
73   const int64 transaction_id1 = 1;
74   IndexedDBPendingConnection connection1(
75       request1,
76       callbacks1,
77       kFakeChildProcessId,
78       transaction_id1,
79       IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
80   db->OpenConnection(connection1);
81
82   EXPECT_FALSE(backing_store->HasOneRef());  // db, connection count > 0
83
84   scoped_refptr<MockIndexedDBCallbacks> request2(new MockIndexedDBCallbacks());
85   scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks2(
86       new MockIndexedDBDatabaseCallbacks());
87   const int64 transaction_id2 = 2;
88   IndexedDBPendingConnection connection2(
89       request2,
90       callbacks2,
91       kFakeChildProcessId,
92       transaction_id2,
93       IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
94   db->OpenConnection(connection2);
95
96   EXPECT_FALSE(backing_store->HasOneRef());  // local and connection
97
98   request1->connection()->ForceClose();
99   EXPECT_FALSE(request1->connection()->IsConnected());
100
101   EXPECT_FALSE(backing_store->HasOneRef());  // local and connection
102
103   request2->connection()->ForceClose();
104   EXPECT_FALSE(request2->connection()->IsConnected());
105
106   EXPECT_TRUE(backing_store->HasOneRef());
107   EXPECT_FALSE(db->backing_store());
108
109   db = NULL;
110 }
111
112 TEST(IndexedDBDatabaseTest, ForcedClose) {
113   scoped_refptr<IndexedDBFakeBackingStore> backing_store =
114       new IndexedDBFakeBackingStore();
115   EXPECT_TRUE(backing_store->HasOneRef());
116
117   scoped_refptr<MockIndexedDBFactory> factory = new MockIndexedDBFactory();
118   leveldb::Status s;
119   scoped_refptr<IndexedDBDatabase> database =
120       IndexedDBDatabase::Create(ASCIIToUTF16("db"),
121                                 backing_store.get(),
122                                 factory.get(),
123                                 IndexedDBDatabase::Identifier(),
124                                 &s);
125   ASSERT_TRUE(s.ok());
126   EXPECT_FALSE(backing_store->HasOneRef());  // local and db
127
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(
133       request,
134       callbacks,
135       kFakeChildProcessId,
136       upgrade_transaction_id,
137       IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
138   database->OpenConnection(connection);
139   EXPECT_EQ(database.get(), request->connection()->database());
140
141   const int64 transaction_id = 123;
142   const std::vector<int64> scope;
143   database->CreateTransaction(transaction_id,
144                               request->connection(),
145                               scope,
146                               blink::WebIDBTransactionModeReadOnly);
147
148   request->connection()->ForceClose();
149
150   EXPECT_TRUE(backing_store->HasOneRef());  // local
151   EXPECT_TRUE(callbacks->abort_called());
152 }
153
154 class MockDeleteCallbacks : public IndexedDBCallbacks {
155  public:
156   MockDeleteCallbacks()
157       : IndexedDBCallbacks(NULL, 0, 0),
158         blocked_called_(false),
159         success_called_(false) {}
160
161   virtual void OnBlocked(int64 existing_version) OVERRIDE {
162     blocked_called_ = true;
163   }
164   virtual void OnSuccess(int64 result) OVERRIDE { success_called_ = true; }
165
166   bool blocked_called() const { return blocked_called_; }
167   bool success_called() const { return success_called_; }
168
169  private:
170   virtual ~MockDeleteCallbacks() {}
171
172   bool blocked_called_;
173   bool success_called_;
174
175   DISALLOW_COPY_AND_ASSIGN(MockDeleteCallbacks);
176 };
177
178 TEST(IndexedDBDatabaseTest, PendingDelete) {
179   scoped_refptr<IndexedDBFakeBackingStore> backing_store =
180       new IndexedDBFakeBackingStore();
181   EXPECT_TRUE(backing_store->HasOneRef());  // local
182
183   scoped_refptr<MockIndexedDBFactory> factory = new MockIndexedDBFactory();
184   leveldb::Status s;
185   scoped_refptr<IndexedDBDatabase> db =
186       IndexedDBDatabase::Create(ASCIIToUTF16("db"),
187                                 backing_store.get(),
188                                 factory.get(),
189                                 IndexedDBDatabase::Identifier(),
190                                 &s);
191   ASSERT_TRUE(s.ok());
192   EXPECT_FALSE(backing_store->HasOneRef());  // local and db
193
194   scoped_refptr<MockIndexedDBCallbacks> request1(new MockIndexedDBCallbacks());
195   scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks1(
196       new MockIndexedDBDatabaseCallbacks());
197   const int64 transaction_id1 = 1;
198   IndexedDBPendingConnection connection(
199       request1,
200       callbacks1,
201       kFakeChildProcessId,
202       transaction_id1,
203       IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
204   db->OpenConnection(connection);
205
206   EXPECT_FALSE(backing_store->HasOneRef());  // local and db
207
208   scoped_refptr<MockDeleteCallbacks> request2(new MockDeleteCallbacks());
209   db->DeleteDatabase(request2);
210
211   EXPECT_FALSE(request2->blocked_called());
212   db->VersionChangeIgnored();
213   EXPECT_TRUE(request2->blocked_called());
214
215   EXPECT_FALSE(backing_store->HasOneRef());  // local and db
216
217   db->Close(request1->connection(), true /* forced */);
218
219   EXPECT_FALSE(db->backing_store());
220   EXPECT_TRUE(backing_store->HasOneRef());  // local
221   EXPECT_TRUE(request2->success_called());
222 }
223
224 void DummyOperation(IndexedDBTransaction* transaction) {
225 }
226
227 class IndexedDBDatabaseOperationTest : public testing::Test {
228  public:
229   IndexedDBDatabaseOperationTest()
230       : commit_success_(leveldb::Status::OK()),
231         factory_(new MockIndexedDBFactory()) {}
232
233   virtual void SetUp() {
234     backing_store_ = new IndexedDBFakeBackingStore();
235     leveldb::Status s;
236     db_ = IndexedDBDatabase::Create(ASCIIToUTF16("db"),
237                                     backing_store_.get(),
238                                     factory_.get(),
239                                     IndexedDBDatabase::Identifier(),
240                                     &s);
241     ASSERT_TRUE(s.ok());
242
243     request_ = new MockIndexedDBCallbacks();
244     callbacks_ = new MockIndexedDBDatabaseCallbacks();
245     const int64 transaction_id = 1;
246     db_->OpenConnection(IndexedDBPendingConnection(
247         request_,
248         callbacks_,
249         kFakeChildProcessId,
250         transaction_id,
251         IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION));
252     EXPECT_EQ(IndexedDBDatabaseMetadata::NO_INT_VERSION,
253               db_->metadata().int_version);
254
255     transaction_ = new IndexedDBTransaction(
256         transaction_id,
257         callbacks_,
258         std::set<int64>() /*scope*/,
259         blink::WebIDBTransactionModeVersionChange,
260         db_.get(),
261         new IndexedDBFakeBackingStore::FakeTransaction(commit_success_));
262     db_->TransactionCreated(transaction_.get());
263
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));
268   }
269
270   void RunPostedTasks() { base::RunLoop().RunUntilIdle(); }
271
272  protected:
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_;
278
279   leveldb::Status commit_success_;
280
281  private:
282   base::MessageLoop message_loop_;
283   scoped_refptr<MockIndexedDBFactory> factory_;
284
285   DISALLOW_COPY_AND_ASSIGN(IndexedDBDatabaseOperationTest);
286 };
287
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(),
292                          store_id,
293                          ASCIIToUTF16("store"),
294                          IndexedDBKeyPath(),
295                          false /*auto_increment*/);
296   EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
297   RunPostedTasks();
298   transaction_->Commit();
299   EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
300 }
301
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(),
306                          store_id,
307                          ASCIIToUTF16("store"),
308                          IndexedDBKeyPath(),
309                          false /*auto_increment*/);
310   EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
311   const int64 index_id = 2002;
312   db_->CreateIndex(transaction_->id(),
313                    store_id,
314                    index_id,
315                    ASCIIToUTF16("index"),
316                    IndexedDBKeyPath(),
317                    false /*unique*/,
318                    false /*multi_entry*/);
319   EXPECT_EQ(
320       1ULL,
321       db_->metadata().object_stores.find(store_id)->second.indexes.size());
322   RunPostedTasks();
323   transaction_->Commit();
324   EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
325   EXPECT_EQ(
326       1ULL,
327       db_->metadata().object_stores.find(store_id)->second.indexes.size());
328 }
329
330 class IndexedDBDatabaseOperationAbortTest
331     : public IndexedDBDatabaseOperationTest {
332  public:
333   IndexedDBDatabaseOperationAbortTest() {
334     commit_success_ = leveldb::Status::NotFound("Bummer.");
335   }
336
337  private:
338   DISALLOW_COPY_AND_ASSIGN(IndexedDBDatabaseOperationAbortTest);
339 };
340
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(),
345                          store_id,
346                          ASCIIToUTF16("store"),
347                          IndexedDBKeyPath(),
348                          false /*auto_increment*/);
349   EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
350   RunPostedTasks();
351   transaction_->Commit();
352   EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
353 }
354
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(),
359                          store_id,
360                          ASCIIToUTF16("store"),
361                          IndexedDBKeyPath(),
362                          false /*auto_increment*/);
363   EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
364   const int64 index_id = 2002;
365   db_->CreateIndex(transaction_->id(),
366                    store_id,
367                    index_id,
368                    ASCIIToUTF16("index"),
369                    IndexedDBKeyPath(),
370                    false /*unique*/,
371                    false /*multi_entry*/);
372   EXPECT_EQ(
373       1ULL,
374       db_->metadata().object_stores.find(store_id)->second.indexes.size());
375   RunPostedTasks();
376   transaction_->Commit();
377   EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
378 }
379
380 TEST_F(IndexedDBDatabaseOperationTest, CreatePutDelete) {
381   EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
382   const int64 store_id = 1001;
383
384   // Creation is synchronous.
385   db_->CreateObjectStore(transaction_->id(),
386                          store_id,
387                          ASCIIToUTF16("store"),
388                          IndexedDBKeyPath(),
389                          false /*auto_increment*/);
390   EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
391
392
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(),
401            store_id,
402            &value,
403            &handles,
404            key.Pass(),
405            blink::WebIDBPutModeAddOnly,
406            request,
407            index_keys);
408
409   // Deletion is asynchronous.
410   db_->DeleteObjectStore(transaction_->id(),
411                          store_id);
412   EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
413
414   // This will execute the Put then Delete.
415   RunPostedTasks();
416   EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
417
418   transaction_->Commit();  // Cleans up the object hierarchy.
419 }
420
421 }  // namespace content