Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / indexed_db / indexed_db_transaction_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_transaction.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "content/browser/indexed_db/indexed_db_fake_backing_store.h"
12 #include "content/browser/indexed_db/mock_indexed_db_database_callbacks.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace content {
16
17 class IndexedDBTransactionTest : public testing::Test {
18  public:
19   IndexedDBTransactionTest() {
20     backing_store_ = new IndexedDBFakeBackingStore();
21     CreateDB();
22   }
23
24   void CreateDB() {
25     // DB is created here instead of the constructor to workaround a
26     // "peculiarity of C++". More info at
27     // https://code.google.com/p/googletest/wiki/FAQ#My_compiler_complains_that_a_constructor_(or_destructor)_cannot
28     IndexedDBFactory* factory = NULL;
29     leveldb::Status s;
30     db_ = IndexedDBDatabase::Create(base::ASCIIToUTF16("db"),
31                                     backing_store_,
32                                     factory,
33                                     IndexedDBDatabase::Identifier(),
34                                     &s);
35     ASSERT_TRUE(s.ok());
36   }
37
38   void RunPostedTasks() { message_loop_.RunUntilIdle(); }
39   void DummyOperation(IndexedDBTransaction* transaction) {}
40
41  protected:
42   scoped_refptr<IndexedDBFakeBackingStore> backing_store_;
43   scoped_refptr<IndexedDBDatabase> db_;
44
45  private:
46   base::MessageLoop message_loop_;
47
48   DISALLOW_COPY_AND_ASSIGN(IndexedDBTransactionTest);
49 };
50
51 class IndexedDBTransactionTestMode : public IndexedDBTransactionTest,
52   public testing::WithParamInterface<indexed_db::TransactionMode> {
53  public:
54   IndexedDBTransactionTestMode() {}
55  private:
56   DISALLOW_COPY_AND_ASSIGN(IndexedDBTransactionTestMode);
57 };
58
59 TEST_F(IndexedDBTransactionTest, Timeout) {
60   const int64 id = 0;
61   const std::set<int64> scope;
62   const bool commit_success = true;
63   scoped_refptr<IndexedDBTransaction> transaction = new IndexedDBTransaction(
64       id,
65       new MockIndexedDBDatabaseCallbacks(),
66       scope,
67       indexed_db::TRANSACTION_READ_WRITE,
68       db_,
69       new IndexedDBFakeBackingStore::FakeTransaction(commit_success));
70   db_->TransactionCreated(transaction);
71
72   // No conflicting transactions, so coordinator will start it immediately:
73   EXPECT_EQ(IndexedDBTransaction::STARTED, transaction->state());
74   EXPECT_FALSE(transaction->IsTimeoutTimerRunning());
75   EXPECT_EQ(0, transaction->diagnostics().tasks_scheduled);
76   EXPECT_EQ(0, transaction->diagnostics().tasks_completed);
77
78   // Schedule a task - timer won't be started until it's processed.
79   transaction->ScheduleTask(base::Bind(
80       &IndexedDBTransactionTest::DummyOperation, base::Unretained(this)));
81   EXPECT_FALSE(transaction->IsTimeoutTimerRunning());
82   EXPECT_EQ(1, transaction->diagnostics().tasks_scheduled);
83   EXPECT_EQ(0, transaction->diagnostics().tasks_completed);
84
85   RunPostedTasks();
86   EXPECT_TRUE(transaction->IsTimeoutTimerRunning());
87
88   transaction->Timeout();
89   EXPECT_EQ(IndexedDBTransaction::FINISHED, transaction->state());
90   EXPECT_FALSE(transaction->IsTimeoutTimerRunning());
91   EXPECT_EQ(1, transaction->diagnostics().tasks_scheduled);
92   EXPECT_EQ(1, transaction->diagnostics().tasks_completed);
93
94   // This task will be ignored.
95   transaction->ScheduleTask(base::Bind(
96       &IndexedDBTransactionTest::DummyOperation, base::Unretained(this)));
97   EXPECT_EQ(IndexedDBTransaction::FINISHED, transaction->state());
98   EXPECT_FALSE(transaction->IsTimeoutTimerRunning());
99   EXPECT_EQ(1, transaction->diagnostics().tasks_scheduled);
100   EXPECT_EQ(1, transaction->diagnostics().tasks_completed);
101 }
102
103 TEST_F(IndexedDBTransactionTest, NoTimeoutReadOnly) {
104   const int64 id = 0;
105   const std::set<int64> scope;
106   const bool commit_success = true;
107   scoped_refptr<IndexedDBTransaction> transaction = new IndexedDBTransaction(
108       id,
109       new MockIndexedDBDatabaseCallbacks(),
110       scope,
111       indexed_db::TRANSACTION_READ_ONLY,
112       db_,
113       new IndexedDBFakeBackingStore::FakeTransaction(commit_success));
114   db_->TransactionCreated(transaction);
115
116   // No conflicting transactions, so coordinator will start it immediately:
117   EXPECT_EQ(IndexedDBTransaction::STARTED, transaction->state());
118   EXPECT_FALSE(transaction->IsTimeoutTimerRunning());
119
120   // Schedule a task - timer won't be started until it's processed.
121   transaction->ScheduleTask(base::Bind(
122       &IndexedDBTransactionTest::DummyOperation, base::Unretained(this)));
123   EXPECT_FALSE(transaction->IsTimeoutTimerRunning());
124
125   // Transaction is read-only, so no need to time it out.
126   RunPostedTasks();
127   EXPECT_FALSE(transaction->IsTimeoutTimerRunning());
128
129   // Clean up to avoid leaks.
130   transaction->Abort();
131   EXPECT_EQ(IndexedDBTransaction::FINISHED, transaction->state());
132   EXPECT_FALSE(transaction->IsTimeoutTimerRunning());
133 }
134
135 class AbortObserver {
136  public:
137   AbortObserver() : abort_task_called_(false) {}
138
139   void AbortTask(IndexedDBTransaction* transaction) {
140     abort_task_called_ = true;
141   }
142
143   bool abort_task_called() const { return abort_task_called_; }
144
145  private:
146   bool abort_task_called_;
147   DISALLOW_COPY_AND_ASSIGN(AbortObserver);
148 };
149
150 TEST_P(IndexedDBTransactionTestMode, ScheduleNormalTask) {
151   const int64 id = 0;
152   const std::set<int64> scope;
153   const bool commit_failure = false;
154   scoped_refptr<IndexedDBTransaction> transaction = new IndexedDBTransaction(
155       id,
156       new MockIndexedDBDatabaseCallbacks(),
157       scope,
158       GetParam(),
159       db_,
160       new IndexedDBFakeBackingStore::FakeTransaction(commit_failure));
161
162   EXPECT_FALSE(transaction->HasPendingTasks());
163   EXPECT_TRUE(transaction->IsTaskQueueEmpty());
164   EXPECT_TRUE(transaction->task_queue_.empty());
165   EXPECT_TRUE(transaction->preemptive_task_queue_.empty());
166   EXPECT_EQ(0, transaction->diagnostics().tasks_scheduled);
167   EXPECT_EQ(0, transaction->diagnostics().tasks_completed);
168
169   db_->TransactionCreated(transaction);
170
171   EXPECT_FALSE(transaction->HasPendingTasks());
172   EXPECT_TRUE(transaction->IsTaskQueueEmpty());
173   EXPECT_TRUE(transaction->task_queue_.empty());
174   EXPECT_TRUE(transaction->preemptive_task_queue_.empty());
175
176   transaction->ScheduleTask(
177       IndexedDBDatabase::NORMAL_TASK,
178       base::Bind(&IndexedDBTransactionTest::DummyOperation,
179                  base::Unretained(this)));
180
181   EXPECT_EQ(1, transaction->diagnostics().tasks_scheduled);
182   EXPECT_EQ(0, transaction->diagnostics().tasks_completed);
183
184   EXPECT_TRUE(transaction->HasPendingTasks());
185   EXPECT_FALSE(transaction->IsTaskQueueEmpty());
186   EXPECT_FALSE(transaction->task_queue_.empty());
187   EXPECT_TRUE(transaction->preemptive_task_queue_.empty());
188
189   // Pump the message loop so that the transaction completes all pending tasks,
190   // otherwise it will defer the commit.
191   base::MessageLoop::current()->RunUntilIdle();
192   EXPECT_FALSE(transaction->HasPendingTasks());
193   EXPECT_TRUE(transaction->IsTaskQueueEmpty());
194   EXPECT_TRUE(transaction->task_queue_.empty());
195   EXPECT_TRUE(transaction->preemptive_task_queue_.empty());
196   EXPECT_EQ(IndexedDBTransaction::STARTED, transaction->state());
197   EXPECT_EQ(1, transaction->diagnostics().tasks_scheduled);
198   EXPECT_EQ(1, transaction->diagnostics().tasks_completed);
199
200   transaction->Commit();
201
202   EXPECT_EQ(IndexedDBTransaction::FINISHED, transaction->state());
203   EXPECT_FALSE(transaction->HasPendingTasks());
204   EXPECT_FALSE(transaction->IsTimeoutTimerRunning());
205   EXPECT_TRUE(transaction->IsTaskQueueEmpty());
206   EXPECT_TRUE(transaction->task_queue_.empty());
207   EXPECT_TRUE(transaction->preemptive_task_queue_.empty());
208   EXPECT_EQ(1, transaction->diagnostics().tasks_scheduled);
209   EXPECT_EQ(1, transaction->diagnostics().tasks_completed);
210 }
211
212 TEST_F(IndexedDBTransactionTest, SchedulePreemptiveTask) {
213   const int64 id = 0;
214   const std::set<int64> scope;
215   const bool commit_failure = false;
216   scoped_refptr<IndexedDBTransaction> transaction = new IndexedDBTransaction(
217       id,
218       new MockIndexedDBDatabaseCallbacks(),
219       scope,
220       indexed_db::TRANSACTION_VERSION_CHANGE,
221       db_,
222       new IndexedDBFakeBackingStore::FakeTransaction(commit_failure));
223
224   EXPECT_FALSE(transaction->HasPendingTasks());
225   EXPECT_TRUE(transaction->IsTaskQueueEmpty());
226   EXPECT_TRUE(transaction->task_queue_.empty());
227   EXPECT_TRUE(transaction->preemptive_task_queue_.empty());
228   EXPECT_EQ(0, transaction->diagnostics().tasks_scheduled);
229   EXPECT_EQ(0, transaction->diagnostics().tasks_completed);
230
231   db_->TransactionCreated(transaction);
232
233   EXPECT_FALSE(transaction->HasPendingTasks());
234   EXPECT_TRUE(transaction->IsTaskQueueEmpty());
235   EXPECT_TRUE(transaction->task_queue_.empty());
236   EXPECT_TRUE(transaction->preemptive_task_queue_.empty());
237
238   transaction->ScheduleTask(
239       IndexedDBDatabase::PREEMPTIVE_TASK,
240       base::Bind(&IndexedDBTransactionTest::DummyOperation,
241                  base::Unretained(this)));
242   transaction->AddPreemptiveEvent();
243
244   EXPECT_TRUE(transaction->HasPendingTasks());
245   EXPECT_FALSE(transaction->IsTaskQueueEmpty());
246   EXPECT_TRUE(transaction->task_queue_.empty());
247   EXPECT_FALSE(transaction->preemptive_task_queue_.empty());
248
249   // Pump the message loop so that the transaction completes all pending tasks,
250   // otherwise it will defer the commit.
251   base::MessageLoop::current()->RunUntilIdle();
252   EXPECT_TRUE(transaction->HasPendingTasks());
253   EXPECT_TRUE(transaction->IsTaskQueueEmpty());
254   EXPECT_TRUE(transaction->task_queue_.empty());
255   EXPECT_TRUE(transaction->preemptive_task_queue_.empty());
256   EXPECT_EQ(IndexedDBTransaction::STARTED, transaction->state());
257   EXPECT_EQ(0, transaction->diagnostics().tasks_scheduled);
258   EXPECT_EQ(0, transaction->diagnostics().tasks_completed);
259
260   transaction->DidCompletePreemptiveEvent();
261   transaction->Commit();
262
263   EXPECT_EQ(IndexedDBTransaction::FINISHED, transaction->state());
264   EXPECT_FALSE(transaction->HasPendingTasks());
265   EXPECT_FALSE(transaction->IsTimeoutTimerRunning());
266   EXPECT_TRUE(transaction->IsTaskQueueEmpty());
267   EXPECT_TRUE(transaction->task_queue_.empty());
268   EXPECT_TRUE(transaction->preemptive_task_queue_.empty());
269   EXPECT_EQ(0, transaction->diagnostics().tasks_scheduled);
270   EXPECT_EQ(0, transaction->diagnostics().tasks_completed);
271 }
272
273 TEST_P(IndexedDBTransactionTestMode, AbortTasks) {
274   const int64 id = 0;
275   const std::set<int64> scope;
276   const bool commit_failure = false;
277   scoped_refptr<IndexedDBTransaction> transaction = new IndexedDBTransaction(
278       id,
279       new MockIndexedDBDatabaseCallbacks(),
280       scope,
281       GetParam(),
282       db_,
283       new IndexedDBFakeBackingStore::FakeTransaction(commit_failure));
284   db_->TransactionCreated(transaction);
285
286   AbortObserver observer;
287   transaction->ScheduleTask(
288       base::Bind(&IndexedDBTransactionTest::DummyOperation,
289                  base::Unretained(this)),
290       base::Bind(&AbortObserver::AbortTask, base::Unretained(&observer)));
291
292   // Pump the message loop so that the transaction completes all pending tasks,
293   // otherwise it will defer the commit.
294   base::MessageLoop::current()->RunUntilIdle();
295
296   EXPECT_FALSE(observer.abort_task_called());
297   transaction->Commit();
298   EXPECT_TRUE(observer.abort_task_called());
299   EXPECT_EQ(IndexedDBTransaction::FINISHED, transaction->state());
300   EXPECT_FALSE(transaction->IsTimeoutTimerRunning());
301 }
302
303 TEST_P(IndexedDBTransactionTestMode, AbortPreemptive) {
304   const int64 id = 0;
305   const std::set<int64> scope;
306   const bool commit_success = true;
307   scoped_refptr<IndexedDBTransaction> transaction = new IndexedDBTransaction(
308       id,
309       new MockIndexedDBDatabaseCallbacks(),
310       scope,
311       GetParam(),
312       db_,
313       new IndexedDBFakeBackingStore::FakeTransaction(commit_success));
314   db_->TransactionCreated(transaction);
315
316   // No conflicting transactions, so coordinator will start it immediately:
317   EXPECT_EQ(IndexedDBTransaction::STARTED, transaction->state());
318   EXPECT_FALSE(transaction->IsTimeoutTimerRunning());
319
320   transaction->ScheduleTask(
321       IndexedDBDatabase::PREEMPTIVE_TASK,
322       base::Bind(&IndexedDBTransactionTest::DummyOperation,
323                  base::Unretained(this)));
324   EXPECT_EQ(0, transaction->pending_preemptive_events_);
325   transaction->AddPreemptiveEvent();
326   EXPECT_EQ(1, transaction->pending_preemptive_events_);
327
328   RunPostedTasks();
329
330   transaction->Abort();
331   EXPECT_EQ(IndexedDBTransaction::FINISHED, transaction->state());
332   EXPECT_FALSE(transaction->IsTimeoutTimerRunning());
333   EXPECT_EQ(0, transaction->pending_preemptive_events_);
334   EXPECT_TRUE(transaction->preemptive_task_queue_.empty());
335   EXPECT_TRUE(transaction->task_queue_.empty());
336   EXPECT_FALSE(transaction->HasPendingTasks());
337   EXPECT_EQ(transaction->diagnostics().tasks_completed,
338             transaction->diagnostics().tasks_scheduled);
339   EXPECT_FALSE(transaction->should_process_queue_);
340   EXPECT_TRUE(transaction->backing_store_transaction_begun_);
341   EXPECT_TRUE(transaction->used_);
342   EXPECT_FALSE(transaction->commit_pending_);
343
344   // This task will be ignored.
345   transaction->ScheduleTask(base::Bind(
346       &IndexedDBTransactionTest::DummyOperation, base::Unretained(this)));
347   EXPECT_EQ(IndexedDBTransaction::FINISHED, transaction->state());
348   EXPECT_FALSE(transaction->IsTimeoutTimerRunning());
349   EXPECT_FALSE(transaction->HasPendingTasks());
350   EXPECT_EQ(transaction->diagnostics().tasks_completed,
351             transaction->diagnostics().tasks_scheduled);
352 }
353
354 static const indexed_db::TransactionMode kTestModes[] = {
355   indexed_db::TRANSACTION_READ_ONLY,
356   indexed_db::TRANSACTION_READ_WRITE,
357   indexed_db::TRANSACTION_VERSION_CHANGE
358 };
359
360 INSTANTIATE_TEST_CASE_P(IndexedDBTransactions,
361                         IndexedDBTransactionTestMode,
362                         ::testing::ValuesIn(kTestModes));
363
364 }  // namespace content