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/message_loop/message_loop_proxy.h"
7 #include "base/values.h"
8 #include "content/child/indexed_db/indexed_db_dispatcher.h"
9 #include "content/child/indexed_db/webidbcursor_impl.h"
10 #include "content/child/thread_safe_sender.h"
11 #include "content/common/indexed_db/indexed_db_key.h"
12 #include "content/common/indexed_db/indexed_db_key_range.h"
13 #include "content/common/indexed_db/indexed_db_messages.h"
14 #include "ipc/ipc_sync_message_filter.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "third_party/WebKit/public/platform/WebBlobInfo.h"
17 #include "third_party/WebKit/public/platform/WebData.h"
18 #include "third_party/WebKit/public/platform/WebIDBCallbacks.h"
19 #include "third_party/WebKit/public/web/WebHeap.h"
21 using blink::WebBlobInfo
;
23 using blink::WebIDBCallbacks
;
24 using blink::WebIDBCursor
;
25 using blink::WebIDBDatabase
;
26 using blink::WebIDBDatabaseError
;
27 using blink::WebIDBKey
;
28 using blink::WebVector
;
33 class MockCallbacks
: public WebIDBCallbacks
{
35 MockCallbacks() : error_seen_(false) {}
37 virtual void onError(const WebIDBDatabaseError
&) { error_seen_
= true; }
39 bool error_seen() const { return error_seen_
; }
44 DISALLOW_COPY_AND_ASSIGN(MockCallbacks
);
47 class MockDispatcher
: public IndexedDBDispatcher
{
49 explicit MockDispatcher(ThreadSafeSender
* sender
)
50 : IndexedDBDispatcher(sender
) {}
52 bool Send(IPC::Message
* msg
) override
{
58 DISALLOW_COPY_AND_ASSIGN(MockDispatcher
);
63 class IndexedDBDispatcherTest
: public testing::Test
{
65 IndexedDBDispatcherTest()
66 : message_loop_proxy_(base::MessageLoopProxy::current()),
67 sync_message_filter_(new IPC::SyncMessageFilter(NULL
)),
68 thread_safe_sender_(new ThreadSafeSender(message_loop_proxy_
.get(),
69 sync_message_filter_
.get())) {}
71 void TearDown() override
{ blink::WebHeap::collectAllGarbageForTesting(); }
74 scoped_refptr
<base::MessageLoopProxy
> message_loop_proxy_
;
75 scoped_refptr
<IPC::SyncMessageFilter
> sync_message_filter_
;
76 scoped_refptr
<ThreadSafeSender
> thread_safe_sender_
;
79 DISALLOW_COPY_AND_ASSIGN(IndexedDBDispatcherTest
);
82 TEST_F(IndexedDBDispatcherTest
, ValueSizeTest
) {
83 const std::vector
<char> data(kMaxIDBValueSizeInBytes
+ 1);
84 const WebData
value(&data
.front(), data
.size());
85 const WebVector
<WebBlobInfo
> web_blob_info
;
86 const int32 ipc_dummy_id
= -1;
87 const int64 transaction_id
= 1;
88 const int64 object_store_id
= 2;
90 MockCallbacks callbacks
;
91 IndexedDBDispatcher
dispatcher(thread_safe_sender_
.get());
92 IndexedDBKey
key(0, blink::WebIDBKeyTypeNumber
);
93 dispatcher
.RequestIDBDatabasePut(ipc_dummy_id
,
99 blink::WebIDBPutModeAddOrUpdate
,
101 WebVector
<long long>(),
102 WebVector
<WebVector
<WebIDBKey
> >());
104 EXPECT_TRUE(callbacks
.error_seen());
107 TEST_F(IndexedDBDispatcherTest
, KeyAndValueSizeTest
) {
108 const size_t kKeySize
= 1024 * 1024;
110 const std::vector
<char> data(kMaxIDBValueSizeInBytes
- kKeySize
);
111 const WebData
value(&data
.front(), data
.size());
112 const WebVector
<WebBlobInfo
> web_blob_info
;
113 const IndexedDBKey
key(
114 base::string16(kKeySize
/ sizeof(base::string16::value_type
), 'x'));
116 const int32 ipc_dummy_id
= -1;
117 const int64 transaction_id
= 1;
118 const int64 object_store_id
= 2;
120 MockCallbacks callbacks
;
121 IndexedDBDispatcher
dispatcher(thread_safe_sender_
.get());
122 dispatcher
.RequestIDBDatabasePut(ipc_dummy_id
,
128 blink::WebIDBPutModeAddOrUpdate
,
130 WebVector
<long long>(),
131 WebVector
<WebVector
<WebIDBKey
> >());
133 EXPECT_TRUE(callbacks
.error_seen());
138 class CursorCallbacks
: public WebIDBCallbacks
{
140 explicit CursorCallbacks(scoped_ptr
<WebIDBCursor
>* cursor
)
143 virtual void onSuccess(const WebData
&,
144 const WebVector
<WebBlobInfo
>&) override
{}
145 virtual void onSuccess(WebIDBCursor
* cursor
,
146 const WebIDBKey
& key
,
147 const WebIDBKey
& primaryKey
,
148 const WebData
& value
,
149 const WebVector
<WebBlobInfo
>&) override
{
150 cursor_
->reset(cursor
);
154 scoped_ptr
<WebIDBCursor
>* cursor_
;
156 DISALLOW_COPY_AND_ASSIGN(CursorCallbacks
);
161 TEST_F(IndexedDBDispatcherTest
, CursorTransactionId
) {
162 const int32 ipc_database_id
= -1;
163 const int64 transaction_id
= 1234;
164 const int64 object_store_id
= 2;
165 const int32 index_id
= 3;
166 const blink::WebIDBCursorDirection direction
=
167 blink::WebIDBCursorDirectionNext
;
168 const bool key_only
= false;
170 MockDispatcher
dispatcher(thread_safe_sender_
.get());
172 // First case: successful cursor open.
174 scoped_ptr
<WebIDBCursor
> cursor
;
175 EXPECT_EQ(0UL, dispatcher
.cursor_transaction_ids_
.size());
177 // Make a cursor request. This should record the transaction id.
178 dispatcher
.RequestIDBDatabaseOpenCursor(ipc_database_id
,
185 blink::WebIDBTaskTypeNormal
,
186 new CursorCallbacks(&cursor
));
188 // Verify that the transaction id was captured.
189 EXPECT_EQ(1UL, dispatcher
.cursor_transaction_ids_
.size());
190 EXPECT_FALSE(cursor
.get());
192 int32 ipc_callbacks_id
= dispatcher
.cursor_transaction_ids_
.begin()->first
;
194 IndexedDBMsg_CallbacksSuccessIDBCursor_Params params
;
195 params
.ipc_thread_id
= dispatcher
.CurrentWorkerId();
196 params
.ipc_callbacks_id
= ipc_callbacks_id
;
198 // Now simululate the cursor response.
199 params
.ipc_cursor_id
= WebIDBCursorImpl::kInvalidCursorId
;
200 dispatcher
.OnSuccessOpenCursor(params
);
202 EXPECT_EQ(0UL, dispatcher
.cursor_transaction_ids_
.size());
204 EXPECT_TRUE(cursor
.get());
206 WebIDBCursorImpl
* impl
= static_cast<WebIDBCursorImpl
*>(cursor
.get());
208 // This is the primary expectation of this test: the transaction id was
209 // applied to the cursor.
210 EXPECT_EQ(transaction_id
, impl
->transaction_id());
213 // Second case: null cursor (no data in range)
215 scoped_ptr
<WebIDBCursor
> cursor
;
216 EXPECT_EQ(0UL, dispatcher
.cursor_transaction_ids_
.size());
218 // Make a cursor request. This should record the transaction id.
219 dispatcher
.RequestIDBDatabaseOpenCursor(ipc_database_id
,
226 blink::WebIDBTaskTypeNormal
,
227 new CursorCallbacks(&cursor
));
229 // Verify that the transaction id was captured.
230 EXPECT_EQ(1UL, dispatcher
.cursor_transaction_ids_
.size());
231 EXPECT_FALSE(cursor
.get());
233 int32 ipc_callbacks_id
= dispatcher
.cursor_transaction_ids_
.begin()->first
;
235 // Now simululate a "null cursor" response.
236 IndexedDBMsg_CallbacksSuccessValue_Params params
;
237 params
.ipc_thread_id
= dispatcher
.CurrentWorkerId();
238 params
.ipc_callbacks_id
= ipc_callbacks_id
;
239 dispatcher
.OnSuccessValue(params
);
241 // Ensure the map result was deleted.
242 EXPECT_EQ(0UL, dispatcher
.cursor_transaction_ids_
.size());
243 EXPECT_FALSE(cursor
.get());
249 class MockCursor
: public WebIDBCursorImpl
{
251 MockCursor(int32 ipc_cursor_id
,
252 int64 transaction_id
,
253 ThreadSafeSender
* thread_safe_sender
)
254 : WebIDBCursorImpl(ipc_cursor_id
, transaction_id
, thread_safe_sender
),
257 // This method is virtual so it can be overridden in unit tests.
258 void ResetPrefetchCache() override
{ ++reset_count_
; }
260 int reset_count() const { return reset_count_
; }
265 DISALLOW_COPY_AND_ASSIGN(MockCursor
);
270 TEST_F(IndexedDBDispatcherTest
, CursorReset
) {
271 scoped_ptr
<WebIDBCursor
> cursor
;
272 MockDispatcher
dispatcher(thread_safe_sender_
.get());
274 const int32 ipc_database_id
= 0;
275 const int32 object_store_id
= 0;
276 const int32 index_id
= 0;
277 const bool key_only
= false;
278 const int cursor1_ipc_id
= 1;
279 const int cursor2_ipc_id
= 2;
280 const int other_cursor_ipc_id
= 2;
281 const int cursor1_transaction_id
= 1;
282 const int cursor2_transaction_id
= 2;
283 const int other_transaction_id
= 3;
285 scoped_ptr
<MockCursor
> cursor1(
286 new MockCursor(WebIDBCursorImpl::kInvalidCursorId
,
287 cursor1_transaction_id
,
288 thread_safe_sender_
.get()));
290 scoped_ptr
<MockCursor
> cursor2(
291 new MockCursor(WebIDBCursorImpl::kInvalidCursorId
,
292 cursor2_transaction_id
,
293 thread_safe_sender_
.get()));
295 dispatcher
.cursors_
[cursor1_ipc_id
] = cursor1
.get();
296 dispatcher
.cursors_
[cursor2_ipc_id
] = cursor2
.get();
298 EXPECT_EQ(0, cursor1
->reset_count());
299 EXPECT_EQ(0, cursor2
->reset_count());
301 // Other transaction:
302 dispatcher
.RequestIDBDatabaseGet(ipc_database_id
,
303 other_transaction_id
,
308 new MockCallbacks());
310 EXPECT_EQ(0, cursor1
->reset_count());
311 EXPECT_EQ(0, cursor2
->reset_count());
314 dispatcher
.RequestIDBDatabaseGet(ipc_database_id
,
315 cursor1_transaction_id
,
320 new MockCallbacks());
322 EXPECT_EQ(1, cursor1
->reset_count());
323 EXPECT_EQ(0, cursor2
->reset_count());
325 // Same transaction and same cursor:
326 dispatcher
.RequestIDBCursorContinue(IndexedDBKey(),
330 cursor1_transaction_id
);
332 EXPECT_EQ(1, cursor1
->reset_count());
333 EXPECT_EQ(0, cursor2
->reset_count());
335 // Same transaction and different cursor:
336 dispatcher
.RequestIDBCursorContinue(IndexedDBKey(),
340 cursor1_transaction_id
);
342 EXPECT_EQ(2, cursor1
->reset_count());
343 EXPECT_EQ(0, cursor2
->reset_count());
349 } // namespace content