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_transaction.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"
17 class IndexedDBTransactionTest
: public testing::Test
{
19 IndexedDBTransactionTest() {
20 IndexedDBFactory
* factory
= NULL
;
21 backing_store_
= new IndexedDBFakeBackingStore();
22 db_
= IndexedDBDatabase::Create(base::ASCIIToUTF16("db"),
25 IndexedDBDatabase::Identifier());
28 void RunPostedTasks() { message_loop_
.RunUntilIdle(); }
29 void DummyOperation(IndexedDBTransaction
* transaction
) {}
32 scoped_refptr
<IndexedDBFakeBackingStore
> backing_store_
;
33 scoped_refptr
<IndexedDBDatabase
> db_
;
36 base::MessageLoop message_loop_
;
38 DISALLOW_COPY_AND_ASSIGN(IndexedDBTransactionTest
);
41 class IndexedDBTransactionTestMode
: public IndexedDBTransactionTest
,
42 public testing::WithParamInterface
<indexed_db::TransactionMode
> {
44 IndexedDBTransactionTestMode() {}
46 DISALLOW_COPY_AND_ASSIGN(IndexedDBTransactionTestMode
);
49 TEST_F(IndexedDBTransactionTest
, Timeout
) {
51 const std::set
<int64
> scope
;
52 const bool commit_success
= true;
53 scoped_refptr
<IndexedDBTransaction
> transaction
= new IndexedDBTransaction(
55 new MockIndexedDBDatabaseCallbacks(),
57 indexed_db::TRANSACTION_READ_WRITE
,
59 new IndexedDBFakeBackingStore::FakeTransaction(commit_success
));
60 db_
->TransactionCreated(transaction
);
62 // No conflicting transactions, so coordinator will start it immediately:
63 EXPECT_EQ(IndexedDBTransaction::STARTED
, transaction
->state());
64 EXPECT_FALSE(transaction
->IsTimeoutTimerRunning());
66 // Schedule a task - timer won't be started until it's processed.
67 transaction
->ScheduleTask(base::Bind(
68 &IndexedDBTransactionTest::DummyOperation
, base::Unretained(this)));
69 EXPECT_FALSE(transaction
->IsTimeoutTimerRunning());
72 EXPECT_TRUE(transaction
->IsTimeoutTimerRunning());
74 // Abort should cancel the timer.
76 EXPECT_EQ(IndexedDBTransaction::FINISHED
, transaction
->state());
77 EXPECT_FALSE(transaction
->IsTimeoutTimerRunning());
79 // This task will be ignored.
80 transaction
->ScheduleTask(base::Bind(
81 &IndexedDBTransactionTest::DummyOperation
, base::Unretained(this)));
82 EXPECT_EQ(IndexedDBTransaction::FINISHED
, transaction
->state());
83 EXPECT_FALSE(transaction
->IsTimeoutTimerRunning());
86 TEST_F(IndexedDBTransactionTest
, NoTimeoutReadOnly
) {
88 const std::set
<int64
> scope
;
89 const bool commit_success
= true;
90 scoped_refptr
<IndexedDBTransaction
> transaction
= new IndexedDBTransaction(
92 new MockIndexedDBDatabaseCallbacks(),
94 indexed_db::TRANSACTION_READ_ONLY
,
96 new IndexedDBFakeBackingStore::FakeTransaction(commit_success
));
97 db_
->TransactionCreated(transaction
);
99 // No conflicting transactions, so coordinator will start it immediately:
100 EXPECT_EQ(IndexedDBTransaction::STARTED
, transaction
->state());
101 EXPECT_FALSE(transaction
->IsTimeoutTimerRunning());
103 // Schedule a task - timer won't be started until it's processed.
104 transaction
->ScheduleTask(base::Bind(
105 &IndexedDBTransactionTest::DummyOperation
, base::Unretained(this)));
106 EXPECT_FALSE(transaction
->IsTimeoutTimerRunning());
108 // Transaction is read-only, so no need to time it out.
110 EXPECT_FALSE(transaction
->IsTimeoutTimerRunning());
112 // Clean up to avoid leaks.
113 transaction
->Abort();
114 EXPECT_EQ(IndexedDBTransaction::FINISHED
, transaction
->state());
115 EXPECT_FALSE(transaction
->IsTimeoutTimerRunning());
118 class AbortObserver
{
120 AbortObserver() : abort_task_called_(false) {}
122 void AbortTask(IndexedDBTransaction
* transaction
) {
123 abort_task_called_
= true;
126 bool abort_task_called() const { return abort_task_called_
; }
129 bool abort_task_called_
;
130 DISALLOW_COPY_AND_ASSIGN(AbortObserver
);
133 TEST_P(IndexedDBTransactionTestMode
, AbortTasks
) {
135 const std::set
<int64
> scope
;
136 const bool commit_failure
= false;
137 scoped_refptr
<IndexedDBTransaction
> transaction
= new IndexedDBTransaction(
139 new MockIndexedDBDatabaseCallbacks(),
143 new IndexedDBFakeBackingStore::FakeTransaction(commit_failure
));
144 db_
->TransactionCreated(transaction
);
146 AbortObserver observer
;
147 transaction
->ScheduleTask(
148 base::Bind(&IndexedDBTransactionTest::DummyOperation
,
149 base::Unretained(this)),
150 base::Bind(&AbortObserver::AbortTask
, base::Unretained(&observer
)));
152 // Pump the message loop so that the transaction completes all pending tasks,
153 // otherwise it will defer the commit.
154 base::MessageLoop::current()->RunUntilIdle();
156 EXPECT_FALSE(observer
.abort_task_called());
157 transaction
->Commit();
158 EXPECT_TRUE(observer
.abort_task_called());
159 EXPECT_EQ(IndexedDBTransaction::FINISHED
, transaction
->state());
160 EXPECT_FALSE(transaction
->IsTimeoutTimerRunning());
163 TEST_P(IndexedDBTransactionTestMode
, AbortPreemptive
) {
165 const std::set
<int64
> scope
;
166 const bool commit_success
= true;
167 scoped_refptr
<IndexedDBTransaction
> transaction
= new IndexedDBTransaction(
169 new MockIndexedDBDatabaseCallbacks(),
173 new IndexedDBFakeBackingStore::FakeTransaction(commit_success
));
174 db_
->TransactionCreated(transaction
);
176 // No conflicting transactions, so coordinator will start it immediately:
177 EXPECT_EQ(IndexedDBTransaction::STARTED
, transaction
->state());
178 EXPECT_FALSE(transaction
->IsTimeoutTimerRunning());
180 transaction
->ScheduleTask(
181 IndexedDBDatabase::PREEMPTIVE_TASK
,
182 base::Bind(&IndexedDBTransactionTest::DummyOperation
,
183 base::Unretained(this)));
184 EXPECT_EQ(0, transaction
->pending_preemptive_events_
);
185 transaction
->AddPreemptiveEvent();
186 EXPECT_EQ(1, transaction
->pending_preemptive_events_
);
190 transaction
->Abort();
191 EXPECT_EQ(IndexedDBTransaction::FINISHED
, transaction
->state());
192 EXPECT_FALSE(transaction
->IsTimeoutTimerRunning());
193 EXPECT_EQ(0, transaction
->pending_preemptive_events_
);
194 EXPECT_TRUE(transaction
->preemptive_task_queue_
.empty());
195 EXPECT_TRUE(transaction
->task_queue_
.empty());
196 EXPECT_FALSE(transaction
->HasPendingTasks());
197 EXPECT_EQ(transaction
->diagnostics().tasks_completed
,
198 transaction
->diagnostics().tasks_scheduled
);
199 EXPECT_FALSE(transaction
->should_process_queue_
);
200 EXPECT_TRUE(transaction
->backing_store_transaction_begun_
);
201 EXPECT_TRUE(transaction
->used_
);
202 EXPECT_FALSE(transaction
->commit_pending_
);
204 // This task will be ignored.
205 transaction
->ScheduleTask(base::Bind(
206 &IndexedDBTransactionTest::DummyOperation
, base::Unretained(this)));
207 EXPECT_EQ(IndexedDBTransaction::FINISHED
, transaction
->state());
208 EXPECT_FALSE(transaction
->IsTimeoutTimerRunning());
209 EXPECT_FALSE(transaction
->HasPendingTasks());
210 EXPECT_EQ(transaction
->diagnostics().tasks_completed
,
211 transaction
->diagnostics().tasks_scheduled
);
214 static const indexed_db::TransactionMode kTestModes
[] = {
215 indexed_db::TRANSACTION_READ_ONLY
,
216 indexed_db::TRANSACTION_READ_WRITE
,
217 indexed_db::TRANSACTION_VERSION_CHANGE
220 INSTANTIATE_TEST_CASE_P(IndexedDBTransactions
,
221 IndexedDBTransactionTestMode
,
222 ::testing::ValuesIn(kTestModes
));
224 } // namespace content