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/values.h"
7 #include "content/child/indexed_db/indexed_db_dispatcher.h"
8 #include "content/child/indexed_db/indexed_db_key_builders.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 "ipc/ipc_sync_message_filter.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "third_party/WebKit/public/platform/WebData.h"
15 #include "third_party/WebKit/public/platform/WebIDBCallbacks.h"
17 using blink::WebBlobInfo
;
19 using blink::WebIDBCallbacks
;
20 using blink::WebIDBDatabase
;
21 using blink::WebIDBKey
;
22 using blink::WebIDBKeyTypeNumber
;
23 using blink::WebVector
;
29 class MockDispatcher
: public IndexedDBDispatcher
{
31 explicit MockDispatcher(ThreadSafeSender
* thread_safe_sender
)
32 : IndexedDBDispatcher(thread_safe_sender
),
34 last_prefetch_count_(0),
39 destroyed_cursor_id_(0) {}
41 virtual void RequestIDBCursorPrefetch(int n
,
42 WebIDBCallbacks
* callbacks
,
43 int32 ipc_cursor_id
) OVERRIDE
{
45 last_prefetch_count_
= n
;
46 callbacks_
.reset(callbacks
);
49 virtual void RequestIDBCursorPrefetchReset(int used_prefetches
,
50 int unused_prefetches
,
51 int32 ipc_cursor_id
) OVERRIDE
{
53 last_used_count_
= used_prefetches
;
56 virtual void RequestIDBCursorAdvance(unsigned long count
,
57 WebIDBCallbacks
* callbacks
,
59 int64 transaction_id
) OVERRIDE
{
61 callbacks_
.reset(callbacks
);
64 virtual void RequestIDBCursorContinue(const IndexedDBKey
& key
,
65 const IndexedDBKey
& primary_key
,
66 WebIDBCallbacks
* callbacks
,
68 int64 transaction_id
) OVERRIDE
{
70 callbacks_
.reset(callbacks
);
73 virtual void CursorDestroyed(int32 ipc_cursor_id
) OVERRIDE
{
74 destroyed_cursor_id_
= ipc_cursor_id
;
77 int prefetch_calls() { return prefetch_calls_
; }
78 int last_prefetch_count() { return last_prefetch_count_
; }
79 int reset_calls() { return reset_calls_
; }
80 int last_used_count() { return last_used_count_
; }
81 int advance_calls() { return advance_calls_
; }
82 int continue_calls() { return continue_calls_
; }
83 int32
destroyed_cursor_id() { return destroyed_cursor_id_
; }
87 int last_prefetch_count_
;
92 int32 destroyed_cursor_id_
;
93 scoped_ptr
<WebIDBCallbacks
> callbacks_
;
96 class MockContinueCallbacks
: public WebIDBCallbacks
{
98 MockContinueCallbacks(IndexedDBKey
* key
= 0,
99 WebVector
<WebBlobInfo
>* webBlobInfo
= 0)
100 : key_(key
), webBlobInfo_(webBlobInfo
) {}
102 virtual void onSuccess(const WebIDBKey
& key
,
103 const WebIDBKey
& primaryKey
,
104 const WebData
& value
,
105 const WebVector
<WebBlobInfo
>& webBlobInfo
) OVERRIDE
{
107 *key_
= IndexedDBKeyBuilder::Build(key
);
109 *webBlobInfo_
= webBlobInfo
;
114 WebVector
<WebBlobInfo
>* webBlobInfo_
;
119 class WebIDBCursorImplTest
: public testing::Test
{
121 WebIDBCursorImplTest() {
122 null_key_
.assignNull();
123 sync_message_filter_
= new IPC::SyncMessageFilter(NULL
);
124 thread_safe_sender_
= new ThreadSafeSender(
125 base::MessageLoopProxy::current(), sync_message_filter_
.get());
127 make_scoped_ptr(new MockDispatcher(thread_safe_sender_
.get()));
132 scoped_refptr
<ThreadSafeSender
> thread_safe_sender_
;
133 scoped_ptr
<MockDispatcher
> dispatcher_
;
136 scoped_refptr
<IPC::SyncMessageFilter
> sync_message_filter_
;
138 DISALLOW_COPY_AND_ASSIGN(WebIDBCursorImplTest
);
141 TEST_F(WebIDBCursorImplTest
, PrefetchTest
) {
142 const int64 transaction_id
= 1;
144 WebIDBCursorImpl
cursor(WebIDBCursorImpl::kInvalidCursorId
,
146 thread_safe_sender_
.get());
148 // Call continue() until prefetching should kick in.
149 int continue_calls
= 0;
150 EXPECT_EQ(dispatcher_
->continue_calls(), 0);
151 for (int i
= 0; i
< WebIDBCursorImpl::kPrefetchContinueThreshold
; ++i
) {
152 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
153 EXPECT_EQ(++continue_calls
, dispatcher_
->continue_calls());
154 EXPECT_EQ(0, dispatcher_
->prefetch_calls());
157 // Do enough repetitions to verify that the count grows each time,
158 // but not so many that the maximum limit is hit.
159 const int kPrefetchRepetitions
= 5;
161 int expected_key
= 0;
162 int last_prefetch_count
= 0;
163 for (int repetitions
= 0; repetitions
< kPrefetchRepetitions
;
165 // Initiate the prefetch
166 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
167 EXPECT_EQ(continue_calls
, dispatcher_
->continue_calls());
168 EXPECT_EQ(repetitions
+ 1, dispatcher_
->prefetch_calls());
170 // Verify that the requested count has increased since last time.
171 int prefetch_count
= dispatcher_
->last_prefetch_count();
172 EXPECT_GT(prefetch_count
, last_prefetch_count
);
173 last_prefetch_count
= prefetch_count
;
175 // Fill the prefetch cache as requested.
176 std::vector
<IndexedDBKey
> keys
;
177 std::vector
<IndexedDBKey
> primary_keys(prefetch_count
);
178 std::vector
<WebData
> values(prefetch_count
);
179 std::vector
<WebVector
<WebBlobInfo
> > blob_info
;
180 for (int i
= 0; i
< prefetch_count
; ++i
) {
181 keys
.push_back(IndexedDBKey(expected_key
+ i
, WebIDBKeyTypeNumber
));
183 WebVector
<WebBlobInfo
>(static_cast<size_t>(expected_key
+ i
)));
185 cursor
.SetPrefetchData(keys
, primary_keys
, values
, blob_info
);
187 // Note that the real dispatcher would call cursor->CachedContinue()
188 // immediately after cursor->SetPrefetchData() to service the request
189 // that initiated the prefetch.
191 // Verify that the cache is used for subsequent continue() calls.
192 for (int i
= 0; i
< prefetch_count
; ++i
) {
194 WebVector
<WebBlobInfo
> web_blob_info
;
195 cursor
.continueFunction(
196 null_key_
, new MockContinueCallbacks(&key
, &web_blob_info
));
197 EXPECT_EQ(continue_calls
, dispatcher_
->continue_calls());
198 EXPECT_EQ(repetitions
+ 1, dispatcher_
->prefetch_calls());
200 EXPECT_EQ(WebIDBKeyTypeNumber
, key
.type());
201 EXPECT_EQ(expected_key
, static_cast<int>(web_blob_info
.size()));
202 EXPECT_EQ(expected_key
++, key
.number());
207 EXPECT_EQ(dispatcher_
->destroyed_cursor_id(),
208 WebIDBCursorImpl::kInvalidCursorId
);
211 TEST_F(WebIDBCursorImplTest
, AdvancePrefetchTest
) {
212 const int64 transaction_id
= 1;
213 WebIDBCursorImpl
cursor(WebIDBCursorImpl::kInvalidCursorId
,
215 thread_safe_sender_
.get());
217 // Call continue() until prefetching should kick in.
218 EXPECT_EQ(0, dispatcher_
->continue_calls());
219 for (int i
= 0; i
< WebIDBCursorImpl::kPrefetchContinueThreshold
; ++i
) {
220 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
222 EXPECT_EQ(0, dispatcher_
->prefetch_calls());
224 // Initiate the prefetch
225 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
227 EXPECT_EQ(1, dispatcher_
->prefetch_calls());
228 EXPECT_EQ(static_cast<int>(WebIDBCursorImpl::kPrefetchContinueThreshold
),
229 dispatcher_
->continue_calls());
230 EXPECT_EQ(0, dispatcher_
->advance_calls());
232 const int prefetch_count
= dispatcher_
->last_prefetch_count();
234 // Fill the prefetch cache as requested.
235 int expected_key
= 0;
236 std::vector
<IndexedDBKey
> keys
;
237 std::vector
<IndexedDBKey
> primary_keys(prefetch_count
);
238 std::vector
<WebData
> values(prefetch_count
);
239 std::vector
<WebVector
<WebBlobInfo
> > blob_info
;
240 for (int i
= 0; i
< prefetch_count
; ++i
) {
241 keys
.push_back(IndexedDBKey(expected_key
+ i
, WebIDBKeyTypeNumber
));
243 WebVector
<WebBlobInfo
>(static_cast<size_t>(expected_key
+ i
)));
245 cursor
.SetPrefetchData(keys
, primary_keys
, values
, blob_info
);
247 // Note that the real dispatcher would call cursor->CachedContinue()
248 // immediately after cursor->SetPrefetchData() to service the request
249 // that initiated the prefetch.
251 // Need at least this many in the cache for the test steps.
252 ASSERT_GE(prefetch_count
, 5);
254 // IDBCursor.continue()
256 cursor
.continueFunction(null_key_
, new MockContinueCallbacks(&key
));
257 EXPECT_EQ(0, key
.number());
259 // IDBCursor.advance(1)
260 cursor
.advance(1, new MockContinueCallbacks(&key
));
261 EXPECT_EQ(1, key
.number());
263 // IDBCursor.continue()
264 cursor
.continueFunction(null_key_
, new MockContinueCallbacks(&key
));
265 EXPECT_EQ(2, key
.number());
267 // IDBCursor.advance(2)
268 cursor
.advance(2, new MockContinueCallbacks(&key
));
269 EXPECT_EQ(4, key
.number());
271 EXPECT_EQ(0, dispatcher_
->advance_calls());
273 // IDBCursor.advance(lots) - beyond the fetched amount
274 cursor
.advance(WebIDBCursorImpl::kMaxPrefetchAmount
,
275 new MockContinueCallbacks(&key
));
276 EXPECT_EQ(1, dispatcher_
->advance_calls());
277 EXPECT_EQ(1, dispatcher_
->prefetch_calls());
278 EXPECT_EQ(static_cast<int>(WebIDBCursorImpl::kPrefetchContinueThreshold
),
279 dispatcher_
->continue_calls());
282 TEST_F(WebIDBCursorImplTest
, PrefetchReset
) {
283 const int64 transaction_id
= 1;
284 WebIDBCursorImpl
cursor(WebIDBCursorImpl::kInvalidCursorId
,
286 thread_safe_sender_
.get());
288 // Call continue() until prefetching should kick in.
289 int continue_calls
= 0;
290 EXPECT_EQ(dispatcher_
->continue_calls(), 0);
291 for (int i
= 0; i
< WebIDBCursorImpl::kPrefetchContinueThreshold
; ++i
) {
292 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
293 EXPECT_EQ(++continue_calls
, dispatcher_
->continue_calls());
294 EXPECT_EQ(0, dispatcher_
->prefetch_calls());
297 // Initiate the prefetch
298 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
299 EXPECT_EQ(continue_calls
, dispatcher_
->continue_calls());
300 EXPECT_EQ(1, dispatcher_
->prefetch_calls());
301 EXPECT_EQ(0, dispatcher_
->reset_calls());
304 cursor
.ResetPrefetchCache();
306 // No reset should have been sent since nothing has been received yet.
307 EXPECT_EQ(0, dispatcher_
->reset_calls());
309 // Fill the prefetch cache as requested.
310 int prefetch_count
= dispatcher_
->last_prefetch_count();
311 std::vector
<IndexedDBKey
> keys(prefetch_count
);
312 std::vector
<IndexedDBKey
> primary_keys(prefetch_count
);
313 std::vector
<WebData
> values(prefetch_count
);
314 std::vector
<WebVector
<WebBlobInfo
> > blob_info(prefetch_count
);
315 cursor
.SetPrefetchData(keys
, primary_keys
, values
, blob_info
);
317 // No reset should have been sent since prefetch data hasn't been used.
318 EXPECT_EQ(0, dispatcher_
->reset_calls());
320 // The real dispatcher would call cursor->CachedContinue(), so do that:
321 scoped_ptr
<WebIDBCallbacks
> callbacks(new MockContinueCallbacks());
322 cursor
.CachedContinue(callbacks
.get());
324 // Now the cursor should have reset the rest of the cache.
325 EXPECT_EQ(1, dispatcher_
->reset_calls());
326 EXPECT_EQ(1, dispatcher_
->last_used_count());
329 } // namespace content