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"
20 using blink::WebBlobInfo
;
22 using blink::WebIDBCallbacks
;
23 using blink::WebIDBCursor
;
24 using blink::WebIDBDatabase
;
25 using blink::WebIDBDatabaseError
;
26 using blink::WebIDBKey
;
27 using blink::WebVector
;
32 class MockCallbacks
: public WebIDBCallbacks
{
34 MockCallbacks() : error_seen_(false) {}
36 virtual void onError(const WebIDBDatabaseError
&) { error_seen_
= true; }
38 bool error_seen() const { return error_seen_
; }
43 DISALLOW_COPY_AND_ASSIGN(MockCallbacks
);
46 class MockDispatcher
: public IndexedDBDispatcher
{
48 explicit MockDispatcher(ThreadSafeSender
* sender
)
49 : IndexedDBDispatcher(sender
) {}
51 virtual bool Send(IPC::Message
* msg
) OVERRIDE
{
57 DISALLOW_COPY_AND_ASSIGN(MockDispatcher
);
62 class IndexedDBDispatcherTest
: public testing::Test
{
64 IndexedDBDispatcherTest()
65 : message_loop_proxy_(base::MessageLoopProxy::current()),
66 sync_message_filter_(new IPC::SyncMessageFilter(NULL
)),
67 thread_safe_sender_(new ThreadSafeSender(message_loop_proxy_
.get(),
68 sync_message_filter_
.get())) {}
71 scoped_refptr
<base::MessageLoopProxy
> message_loop_proxy_
;
72 scoped_refptr
<IPC::SyncMessageFilter
> sync_message_filter_
;
73 scoped_refptr
<ThreadSafeSender
> thread_safe_sender_
;
76 DISALLOW_COPY_AND_ASSIGN(IndexedDBDispatcherTest
);
79 TEST_F(IndexedDBDispatcherTest
, ValueSizeTest
) {
80 const std::vector
<char> data(kMaxIDBValueSizeInBytes
+ 1);
81 const WebData
value(&data
.front(), data
.size());
82 const WebVector
<WebBlobInfo
> web_blob_info
;
83 const int32 ipc_dummy_id
= -1;
84 const int64 transaction_id
= 1;
85 const int64 object_store_id
= 2;
87 MockCallbacks callbacks
;
88 IndexedDBDispatcher
dispatcher(thread_safe_sender_
.get());
89 IndexedDBKey
key(0, blink::WebIDBKeyTypeNumber
);
90 dispatcher
.RequestIDBDatabasePut(ipc_dummy_id
,
96 blink::WebIDBPutModeAddOrUpdate
,
98 WebVector
<long long>(),
99 WebVector
<WebVector
<WebIDBKey
> >());
101 EXPECT_TRUE(callbacks
.error_seen());
104 TEST_F(IndexedDBDispatcherTest
, KeyAndValueSizeTest
) {
105 const size_t kKeySize
= 1024 * 1024;
107 const std::vector
<char> data(kMaxIDBValueSizeInBytes
- kKeySize
);
108 const WebData
value(&data
.front(), data
.size());
109 const WebVector
<WebBlobInfo
> web_blob_info
;
110 const IndexedDBKey
key(
111 base::string16(kKeySize
/ sizeof(base::string16::value_type
), 'x'));
113 const int32 ipc_dummy_id
= -1;
114 const int64 transaction_id
= 1;
115 const int64 object_store_id
= 2;
117 MockCallbacks callbacks
;
118 IndexedDBDispatcher
dispatcher(thread_safe_sender_
.get());
119 dispatcher
.RequestIDBDatabasePut(ipc_dummy_id
,
125 blink::WebIDBPutModeAddOrUpdate
,
127 WebVector
<long long>(),
128 WebVector
<WebVector
<WebIDBKey
> >());
130 EXPECT_TRUE(callbacks
.error_seen());
135 class CursorCallbacks
: public WebIDBCallbacks
{
137 explicit CursorCallbacks(scoped_ptr
<WebIDBCursor
>* cursor
)
140 virtual void onSuccess(const WebData
&,
141 const WebVector
<WebBlobInfo
>&) OVERRIDE
{}
142 virtual void onSuccess(WebIDBCursor
* cursor
,
143 const WebIDBKey
& key
,
144 const WebIDBKey
& primaryKey
,
145 const WebData
& value
,
146 const WebVector
<WebBlobInfo
>&) OVERRIDE
{
147 cursor_
->reset(cursor
);
151 scoped_ptr
<WebIDBCursor
>* cursor_
;
153 DISALLOW_COPY_AND_ASSIGN(CursorCallbacks
);
158 TEST_F(IndexedDBDispatcherTest
, CursorTransactionId
) {
159 const int32 ipc_database_id
= -1;
160 const int64 transaction_id
= 1234;
161 const int64 object_store_id
= 2;
162 const int32 index_id
= 3;
163 const blink::WebIDBCursorDirection direction
=
164 blink::WebIDBCursorDirectionNext
;
165 const bool key_only
= false;
167 MockDispatcher
dispatcher(thread_safe_sender_
.get());
169 // First case: successful cursor open.
171 scoped_ptr
<WebIDBCursor
> cursor
;
172 EXPECT_EQ(0UL, dispatcher
.cursor_transaction_ids_
.size());
174 // Make a cursor request. This should record the transaction id.
175 dispatcher
.RequestIDBDatabaseOpenCursor(ipc_database_id
,
182 blink::WebIDBTaskTypeNormal
,
183 new CursorCallbacks(&cursor
));
185 // Verify that the transaction id was captured.
186 EXPECT_EQ(1UL, dispatcher
.cursor_transaction_ids_
.size());
187 EXPECT_FALSE(cursor
.get());
189 int32 ipc_callbacks_id
= dispatcher
.cursor_transaction_ids_
.begin()->first
;
191 IndexedDBMsg_CallbacksSuccessIDBCursor_Params params
;
192 params
.ipc_thread_id
= dispatcher
.CurrentWorkerId();
193 params
.ipc_callbacks_id
= ipc_callbacks_id
;
195 // Now simululate the cursor response.
196 params
.ipc_cursor_id
= WebIDBCursorImpl::kInvalidCursorId
;
197 dispatcher
.OnSuccessOpenCursor(params
);
199 EXPECT_EQ(0UL, dispatcher
.cursor_transaction_ids_
.size());
201 EXPECT_TRUE(cursor
.get());
203 WebIDBCursorImpl
* impl
= static_cast<WebIDBCursorImpl
*>(cursor
.get());
205 // This is the primary expectation of this test: the transaction id was
206 // applied to the cursor.
207 EXPECT_EQ(transaction_id
, impl
->transaction_id());
210 // Second case: null cursor (no data in range)
212 scoped_ptr
<WebIDBCursor
> cursor
;
213 EXPECT_EQ(0UL, dispatcher
.cursor_transaction_ids_
.size());
215 // Make a cursor request. This should record the transaction id.
216 dispatcher
.RequestIDBDatabaseOpenCursor(ipc_database_id
,
223 blink::WebIDBTaskTypeNormal
,
224 new CursorCallbacks(&cursor
));
226 // Verify that the transaction id was captured.
227 EXPECT_EQ(1UL, dispatcher
.cursor_transaction_ids_
.size());
228 EXPECT_FALSE(cursor
.get());
230 int32 ipc_callbacks_id
= dispatcher
.cursor_transaction_ids_
.begin()->first
;
232 // Now simululate a "null cursor" response.
233 IndexedDBMsg_CallbacksSuccessValue_Params params
;
234 params
.ipc_thread_id
= dispatcher
.CurrentWorkerId();
235 params
.ipc_callbacks_id
= ipc_callbacks_id
;
236 dispatcher
.OnSuccessValue(params
);
238 // Ensure the map result was deleted.
239 EXPECT_EQ(0UL, dispatcher
.cursor_transaction_ids_
.size());
240 EXPECT_FALSE(cursor
.get());
246 class MockCursor
: public WebIDBCursorImpl
{
248 MockCursor(int32 ipc_cursor_id
,
249 int64 transaction_id
,
250 ThreadSafeSender
* thread_safe_sender
)
251 : WebIDBCursorImpl(ipc_cursor_id
, transaction_id
, thread_safe_sender
),
254 // This method is virtual so it can be overridden in unit tests.
255 virtual void ResetPrefetchCache() OVERRIDE
{ ++reset_count_
; }
257 int reset_count() const { return reset_count_
; }
262 DISALLOW_COPY_AND_ASSIGN(MockCursor
);
267 TEST_F(IndexedDBDispatcherTest
, CursorReset
) {
268 scoped_ptr
<WebIDBCursor
> cursor
;
269 MockDispatcher
dispatcher(thread_safe_sender_
.get());
271 const int32 ipc_database_id
= 0;
272 const int32 object_store_id
= 0;
273 const int32 index_id
= 0;
274 const bool key_only
= false;
275 const int cursor1_ipc_id
= 1;
276 const int cursor2_ipc_id
= 2;
277 const int other_cursor_ipc_id
= 2;
278 const int cursor1_transaction_id
= 1;
279 const int cursor2_transaction_id
= 2;
280 const int other_transaction_id
= 3;
282 scoped_ptr
<MockCursor
> cursor1(
283 new MockCursor(WebIDBCursorImpl::kInvalidCursorId
,
284 cursor1_transaction_id
,
285 thread_safe_sender_
.get()));
287 scoped_ptr
<MockCursor
> cursor2(
288 new MockCursor(WebIDBCursorImpl::kInvalidCursorId
,
289 cursor2_transaction_id
,
290 thread_safe_sender_
.get()));
292 dispatcher
.cursors_
[cursor1_ipc_id
] = cursor1
.get();
293 dispatcher
.cursors_
[cursor2_ipc_id
] = cursor2
.get();
295 EXPECT_EQ(0, cursor1
->reset_count());
296 EXPECT_EQ(0, cursor2
->reset_count());
298 // Other transaction:
299 dispatcher
.RequestIDBDatabaseGet(ipc_database_id
,
300 other_transaction_id
,
305 new MockCallbacks());
307 EXPECT_EQ(0, cursor1
->reset_count());
308 EXPECT_EQ(0, cursor2
->reset_count());
311 dispatcher
.RequestIDBDatabaseGet(ipc_database_id
,
312 cursor1_transaction_id
,
317 new MockCallbacks());
319 EXPECT_EQ(1, cursor1
->reset_count());
320 EXPECT_EQ(0, cursor2
->reset_count());
322 // Same transaction and same cursor:
323 dispatcher
.RequestIDBCursorContinue(IndexedDBKey(),
327 cursor1_transaction_id
);
329 EXPECT_EQ(1, cursor1
->reset_count());
330 EXPECT_EQ(0, cursor2
->reset_count());
332 // Same transaction and different cursor:
333 dispatcher
.RequestIDBCursorContinue(IndexedDBKey(),
337 cursor1_transaction_id
);
339 EXPECT_EQ(2, cursor1
->reset_count());
340 EXPECT_EQ(0, cursor2
->reset_count());
346 } // namespace content