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 "base/memory/scoped_ptr.h"
6 #include "base/single_thread_task_runner.h"
7 #include "base/thread_task_runner_handle.h"
8 #include "base/values.h"
9 #include "content/child/indexed_db/indexed_db_dispatcher.h"
10 #include "content/child/indexed_db/webidbcursor_impl.h"
11 #include "content/child/thread_safe_sender.h"
12 #include "content/common/indexed_db/indexed_db_key.h"
13 #include "content/common/indexed_db/indexed_db_key_range.h"
14 #include "content/common/indexed_db/indexed_db_messages.h"
15 #include "ipc/ipc_sync_message_filter.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "third_party/WebKit/public/platform/WebBlobInfo.h"
18 #include "third_party/WebKit/public/platform/WebData.h"
19 #include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBCallbacks.h"
20 #include "third_party/WebKit/public/web/WebHeap.h"
22 using blink::WebBlobInfo
;
24 using blink::WebIDBCallbacks
;
25 using blink::WebIDBCursor
;
26 using blink::WebIDBDatabase
;
27 using blink::WebIDBDatabaseError
;
28 using blink::WebIDBKey
;
29 using blink::WebIDBValue
;
30 using blink::WebVector
;
35 class MockCallbacks
: public WebIDBCallbacks
{
37 MockCallbacks() : error_seen_(false) {}
39 virtual void onError(const WebIDBDatabaseError
&) { error_seen_
= true; }
41 bool error_seen() const { return error_seen_
; }
46 DISALLOW_COPY_AND_ASSIGN(MockCallbacks
);
49 class MockDispatcher
: public IndexedDBDispatcher
{
51 explicit MockDispatcher(ThreadSafeSender
* sender
)
52 : IndexedDBDispatcher(sender
) {}
54 bool Send(IPC::Message
* msg
) override
{
60 DISALLOW_COPY_AND_ASSIGN(MockDispatcher
);
65 class IndexedDBDispatcherTest
: public testing::Test
{
67 IndexedDBDispatcherTest()
68 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
69 sync_message_filter_(new IPC::SyncMessageFilter(NULL
)),
70 thread_safe_sender_(new ThreadSafeSender(task_runner_
.get(),
71 sync_message_filter_
.get())) {}
73 void TearDown() override
{ blink::WebHeap::collectAllGarbageForTesting(); }
76 base::MessageLoop message_loop_
;
77 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner_
;
78 scoped_refptr
<IPC::SyncMessageFilter
> sync_message_filter_
;
79 scoped_refptr
<ThreadSafeSender
> thread_safe_sender_
;
82 DISALLOW_COPY_AND_ASSIGN(IndexedDBDispatcherTest
);
85 TEST_F(IndexedDBDispatcherTest
, ValueSizeTest
) {
86 const std::vector
<char> data(kMaxIDBValueSizeInBytes
+ 1);
87 const WebData
value(&data
.front(), data
.size());
88 const WebVector
<WebBlobInfo
> web_blob_info
;
89 const int32 ipc_dummy_id
= -1;
90 const int64 transaction_id
= 1;
91 const int64 object_store_id
= 2;
93 MockCallbacks callbacks
;
94 IndexedDBDispatcher
dispatcher(thread_safe_sender_
.get());
95 IndexedDBKey
key(0, blink::WebIDBKeyTypeNumber
);
96 dispatcher
.RequestIDBDatabasePut(ipc_dummy_id
,
102 blink::WebIDBPutModeAddOrUpdate
,
104 WebVector
<long long>(),
105 WebVector
<WebVector
<WebIDBKey
> >());
107 EXPECT_TRUE(callbacks
.error_seen());
110 TEST_F(IndexedDBDispatcherTest
, KeyAndValueSizeTest
) {
111 const size_t kKeySize
= 1024 * 1024;
113 const std::vector
<char> data(kMaxIDBValueSizeInBytes
- kKeySize
);
114 const WebData
value(&data
.front(), data
.size());
115 const WebVector
<WebBlobInfo
> web_blob_info
;
116 const IndexedDBKey
key(
117 base::string16(kKeySize
/ sizeof(base::string16::value_type
), 'x'));
119 const int32 ipc_dummy_id
= -1;
120 const int64 transaction_id
= 1;
121 const int64 object_store_id
= 2;
123 MockCallbacks callbacks
;
124 IndexedDBDispatcher
dispatcher(thread_safe_sender_
.get());
125 dispatcher
.RequestIDBDatabasePut(ipc_dummy_id
,
131 blink::WebIDBPutModeAddOrUpdate
,
133 WebVector
<long long>(),
134 WebVector
<WebVector
<WebIDBKey
> >());
136 EXPECT_TRUE(callbacks
.error_seen());
141 class CursorCallbacks
: public WebIDBCallbacks
{
143 explicit CursorCallbacks(scoped_ptr
<WebIDBCursor
>* cursor
)
146 void onSuccess(const WebIDBValue
&) override
{}
147 void onSuccess(WebIDBCursor
* cursor
,
148 const WebIDBKey
& key
,
149 const WebIDBKey
& primaryKey
,
150 const WebData
& value
,
151 const WebVector
<WebBlobInfo
>&) override
{
152 cursor_
->reset(cursor
);
156 scoped_ptr
<WebIDBCursor
>* cursor_
;
158 DISALLOW_COPY_AND_ASSIGN(CursorCallbacks
);
163 TEST_F(IndexedDBDispatcherTest
, CursorTransactionId
) {
164 const int32 ipc_database_id
= -1;
165 const int64 transaction_id
= 1234;
166 const int64 object_store_id
= 2;
167 const int32 index_id
= 3;
168 const blink::WebIDBCursorDirection direction
=
169 blink::WebIDBCursorDirectionNext
;
170 const bool key_only
= false;
172 MockDispatcher
dispatcher(thread_safe_sender_
.get());
174 // First case: successful cursor open.
176 scoped_ptr
<WebIDBCursor
> cursor
;
177 EXPECT_EQ(0UL, dispatcher
.cursor_transaction_ids_
.size());
179 // Make a cursor request. This should record the transaction id.
180 dispatcher
.RequestIDBDatabaseOpenCursor(ipc_database_id
,
187 blink::WebIDBTaskTypeNormal
,
188 new CursorCallbacks(&cursor
));
190 // Verify that the transaction id was captured.
191 EXPECT_EQ(1UL, dispatcher
.cursor_transaction_ids_
.size());
192 EXPECT_FALSE(cursor
.get());
194 int32 ipc_callbacks_id
= dispatcher
.cursor_transaction_ids_
.begin()->first
;
196 IndexedDBMsg_CallbacksSuccessIDBCursor_Params params
;
197 params
.ipc_thread_id
= dispatcher
.CurrentWorkerId();
198 params
.ipc_callbacks_id
= ipc_callbacks_id
;
200 // Now simululate the cursor response.
201 params
.ipc_cursor_id
= WebIDBCursorImpl::kInvalidCursorId
;
202 dispatcher
.OnSuccessOpenCursor(params
);
204 EXPECT_EQ(0UL, dispatcher
.cursor_transaction_ids_
.size());
206 EXPECT_TRUE(cursor
.get());
208 WebIDBCursorImpl
* impl
= static_cast<WebIDBCursorImpl
*>(cursor
.get());
210 // This is the primary expectation of this test: the transaction id was
211 // applied to the cursor.
212 EXPECT_EQ(transaction_id
, impl
->transaction_id());
215 // Second case: null cursor (no data in range)
217 scoped_ptr
<WebIDBCursor
> cursor
;
218 EXPECT_EQ(0UL, dispatcher
.cursor_transaction_ids_
.size());
220 // Make a cursor request. This should record the transaction id.
221 dispatcher
.RequestIDBDatabaseOpenCursor(ipc_database_id
,
228 blink::WebIDBTaskTypeNormal
,
229 new CursorCallbacks(&cursor
));
231 // Verify that the transaction id was captured.
232 EXPECT_EQ(1UL, dispatcher
.cursor_transaction_ids_
.size());
233 EXPECT_FALSE(cursor
.get());
235 int32 ipc_callbacks_id
= dispatcher
.cursor_transaction_ids_
.begin()->first
;
237 // Now simululate a "null cursor" response.
238 IndexedDBMsg_CallbacksSuccessValue_Params params
;
239 params
.ipc_thread_id
= dispatcher
.CurrentWorkerId();
240 params
.ipc_callbacks_id
= ipc_callbacks_id
;
241 dispatcher
.OnSuccessValue(params
);
243 // Ensure the map result was deleted.
244 EXPECT_EQ(0UL, dispatcher
.cursor_transaction_ids_
.size());
245 EXPECT_FALSE(cursor
.get());
251 class MockCursor
: public WebIDBCursorImpl
{
253 MockCursor(int32 ipc_cursor_id
,
254 int64 transaction_id
,
255 ThreadSafeSender
* thread_safe_sender
)
256 : WebIDBCursorImpl(ipc_cursor_id
, transaction_id
, thread_safe_sender
),
259 // This method is virtual so it can be overridden in unit tests.
260 void ResetPrefetchCache() override
{ ++reset_count_
; }
262 int reset_count() const { return reset_count_
; }
267 DISALLOW_COPY_AND_ASSIGN(MockCursor
);
272 TEST_F(IndexedDBDispatcherTest
, CursorReset
) {
273 scoped_ptr
<WebIDBCursor
> cursor
;
274 MockDispatcher
dispatcher(thread_safe_sender_
.get());
276 const int32 ipc_database_id
= 0;
277 const int32 object_store_id
= 0;
278 const int32 index_id
= 0;
279 const bool key_only
= false;
280 const int cursor1_ipc_id
= 1;
281 const int cursor2_ipc_id
= 2;
282 const int other_cursor_ipc_id
= 2;
283 const int cursor1_transaction_id
= 1;
284 const int cursor2_transaction_id
= 2;
285 const int other_transaction_id
= 3;
287 scoped_ptr
<MockCursor
> cursor1(
288 new MockCursor(WebIDBCursorImpl::kInvalidCursorId
,
289 cursor1_transaction_id
,
290 thread_safe_sender_
.get()));
292 scoped_ptr
<MockCursor
> cursor2(
293 new MockCursor(WebIDBCursorImpl::kInvalidCursorId
,
294 cursor2_transaction_id
,
295 thread_safe_sender_
.get()));
297 dispatcher
.cursors_
[cursor1_ipc_id
] = cursor1
.get();
298 dispatcher
.cursors_
[cursor2_ipc_id
] = cursor2
.get();
300 EXPECT_EQ(0, cursor1
->reset_count());
301 EXPECT_EQ(0, cursor2
->reset_count());
303 // Other transaction:
304 dispatcher
.RequestIDBDatabaseGet(ipc_database_id
,
305 other_transaction_id
,
310 new MockCallbacks());
312 EXPECT_EQ(0, cursor1
->reset_count());
313 EXPECT_EQ(0, cursor2
->reset_count());
316 dispatcher
.RequestIDBDatabaseGet(ipc_database_id
,
317 cursor1_transaction_id
,
322 new MockCallbacks());
324 EXPECT_EQ(1, cursor1
->reset_count());
325 EXPECT_EQ(0, cursor2
->reset_count());
327 // Same transaction and same cursor:
328 dispatcher
.RequestIDBCursorContinue(IndexedDBKey(),
332 cursor1_transaction_id
);
334 EXPECT_EQ(1, cursor1
->reset_count());
335 EXPECT_EQ(0, cursor2
->reset_count());
337 // Same transaction and different cursor:
338 dispatcher
.RequestIDBCursorContinue(IndexedDBKey(),
342 cursor1_transaction_id
);
344 EXPECT_EQ(2, cursor1
->reset_count());
345 EXPECT_EQ(0, cursor2
->reset_count());
351 } // namespace content