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 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
{
108 *key_
= IndexedDBKeyBuilder::Build(key
);
110 *webBlobInfo_
= webBlobInfo
;
115 WebVector
<WebBlobInfo
>* webBlobInfo_
;
120 class WebIDBCursorImplTest
: public testing::Test
{
122 WebIDBCursorImplTest() {
123 null_key_
.assignNull();
124 sync_message_filter_
= new IPC::SyncMessageFilter(NULL
);
125 thread_safe_sender_
= new ThreadSafeSender(
126 base::MessageLoopProxy::current(), sync_message_filter_
.get());
128 make_scoped_ptr(new MockDispatcher(thread_safe_sender_
.get()));
133 scoped_refptr
<ThreadSafeSender
> thread_safe_sender_
;
134 scoped_ptr
<MockDispatcher
> dispatcher_
;
137 scoped_refptr
<IPC::SyncMessageFilter
> sync_message_filter_
;
139 DISALLOW_COPY_AND_ASSIGN(WebIDBCursorImplTest
);
142 TEST_F(WebIDBCursorImplTest
, PrefetchTest
) {
144 const int64 transaction_id
= 1;
146 WebIDBCursorImpl
cursor(WebIDBCursorImpl::kInvalidCursorId
,
148 thread_safe_sender_
.get());
150 // Call continue() until prefetching should kick in.
151 int continue_calls
= 0;
152 EXPECT_EQ(dispatcher_
->continue_calls(), 0);
153 for (int i
= 0; i
< WebIDBCursorImpl::kPrefetchContinueThreshold
; ++i
) {
154 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
155 EXPECT_EQ(++continue_calls
, dispatcher_
->continue_calls());
156 EXPECT_EQ(0, dispatcher_
->prefetch_calls());
159 // Do enough repetitions to verify that the count grows each time,
160 // but not so many that the maximum limit is hit.
161 const int kPrefetchRepetitions
= 5;
163 int expected_key
= 0;
164 int last_prefetch_count
= 0;
165 for (int repetitions
= 0; repetitions
< kPrefetchRepetitions
;
168 // Initiate the prefetch
169 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
170 EXPECT_EQ(continue_calls
, dispatcher_
->continue_calls());
171 EXPECT_EQ(repetitions
+ 1, dispatcher_
->prefetch_calls());
173 // Verify that the requested count has increased since last time.
174 int prefetch_count
= dispatcher_
->last_prefetch_count();
175 EXPECT_GT(prefetch_count
, last_prefetch_count
);
176 last_prefetch_count
= prefetch_count
;
178 // Fill the prefetch cache as requested.
179 std::vector
<IndexedDBKey
> keys
;
180 std::vector
<IndexedDBKey
> primary_keys(prefetch_count
);
181 std::vector
<WebData
> values(prefetch_count
);
182 std::vector
<WebVector
<WebBlobInfo
> > blob_info
;
183 for (int i
= 0; i
< prefetch_count
; ++i
) {
184 keys
.push_back(IndexedDBKey(expected_key
+ i
, WebIDBKeyTypeNumber
));
186 WebVector
<WebBlobInfo
>(static_cast<size_t>(expected_key
+ i
)));
188 cursor
.SetPrefetchData(keys
, primary_keys
, values
, blob_info
);
190 // Note that the real dispatcher would call cursor->CachedContinue()
191 // immediately after cursor->SetPrefetchData() to service the request
192 // that initiated the prefetch.
194 // Verify that the cache is used for subsequent continue() calls.
195 for (int i
= 0; i
< prefetch_count
; ++i
) {
197 WebVector
<WebBlobInfo
> web_blob_info
;
198 cursor
.continueFunction(
199 null_key_
, new MockContinueCallbacks(&key
, &web_blob_info
));
200 EXPECT_EQ(continue_calls
, dispatcher_
->continue_calls());
201 EXPECT_EQ(repetitions
+ 1, dispatcher_
->prefetch_calls());
203 EXPECT_EQ(WebIDBKeyTypeNumber
, key
.type());
204 EXPECT_EQ(expected_key
, static_cast<int>(web_blob_info
.size()));
205 EXPECT_EQ(expected_key
++, key
.number());
210 EXPECT_EQ(dispatcher_
->destroyed_cursor_id(),
211 WebIDBCursorImpl::kInvalidCursorId
);
214 TEST_F(WebIDBCursorImplTest
, AdvancePrefetchTest
) {
216 const int64 transaction_id
= 1;
217 WebIDBCursorImpl
cursor(WebIDBCursorImpl::kInvalidCursorId
,
219 thread_safe_sender_
.get());
221 // Call continue() until prefetching should kick in.
222 EXPECT_EQ(0, dispatcher_
->continue_calls());
223 for (int i
= 0; i
< WebIDBCursorImpl::kPrefetchContinueThreshold
; ++i
) {
224 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
226 EXPECT_EQ(0, dispatcher_
->prefetch_calls());
228 // Initiate the prefetch
229 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
231 EXPECT_EQ(1, dispatcher_
->prefetch_calls());
232 EXPECT_EQ(static_cast<int>(WebIDBCursorImpl::kPrefetchContinueThreshold
),
233 dispatcher_
->continue_calls());
234 EXPECT_EQ(0, dispatcher_
->advance_calls());
236 const int prefetch_count
= dispatcher_
->last_prefetch_count();
238 // Fill the prefetch cache as requested.
239 int expected_key
= 0;
240 std::vector
<IndexedDBKey
> keys
;
241 std::vector
<IndexedDBKey
> primary_keys(prefetch_count
);
242 std::vector
<WebData
> values(prefetch_count
);
243 std::vector
<WebVector
<WebBlobInfo
> > blob_info
;
244 for (int i
= 0; i
< prefetch_count
; ++i
) {
245 keys
.push_back(IndexedDBKey(expected_key
+ i
, WebIDBKeyTypeNumber
));
247 WebVector
<WebBlobInfo
>(static_cast<size_t>(expected_key
+ i
)));
249 cursor
.SetPrefetchData(keys
, primary_keys
, values
, blob_info
);
251 // Note that the real dispatcher would call cursor->CachedContinue()
252 // immediately after cursor->SetPrefetchData() to service the request
253 // that initiated the prefetch.
255 // Need at least this many in the cache for the test steps.
256 ASSERT_GE(prefetch_count
, 5);
258 // IDBCursor.continue()
260 cursor
.continueFunction(null_key_
, new MockContinueCallbacks(&key
));
261 EXPECT_EQ(0, key
.number());
263 // IDBCursor.advance(1)
264 cursor
.advance(1, new MockContinueCallbacks(&key
));
265 EXPECT_EQ(1, key
.number());
267 // IDBCursor.continue()
268 cursor
.continueFunction(null_key_
, new MockContinueCallbacks(&key
));
269 EXPECT_EQ(2, key
.number());
271 // IDBCursor.advance(2)
272 cursor
.advance(2, new MockContinueCallbacks(&key
));
273 EXPECT_EQ(4, key
.number());
275 EXPECT_EQ(0, dispatcher_
->advance_calls());
277 // IDBCursor.advance(lots) - beyond the fetched amount
278 cursor
.advance(WebIDBCursorImpl::kMaxPrefetchAmount
,
279 new MockContinueCallbacks(&key
));
280 EXPECT_EQ(1, dispatcher_
->advance_calls());
281 EXPECT_EQ(1, dispatcher_
->prefetch_calls());
282 EXPECT_EQ(static_cast<int>(WebIDBCursorImpl::kPrefetchContinueThreshold
),
283 dispatcher_
->continue_calls());
286 TEST_F(WebIDBCursorImplTest
, PrefetchReset
) {
287 const int64 transaction_id
= 1;
288 WebIDBCursorImpl
cursor(WebIDBCursorImpl::kInvalidCursorId
,
290 thread_safe_sender_
.get());
292 // Call continue() until prefetching should kick in.
293 int continue_calls
= 0;
294 EXPECT_EQ(dispatcher_
->continue_calls(), 0);
295 for (int i
= 0; i
< WebIDBCursorImpl::kPrefetchContinueThreshold
; ++i
) {
296 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
297 EXPECT_EQ(++continue_calls
, dispatcher_
->continue_calls());
298 EXPECT_EQ(0, dispatcher_
->prefetch_calls());
301 // Initiate the prefetch
302 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
303 EXPECT_EQ(continue_calls
, dispatcher_
->continue_calls());
304 EXPECT_EQ(1, dispatcher_
->prefetch_calls());
305 EXPECT_EQ(0, dispatcher_
->reset_calls());
308 cursor
.ResetPrefetchCache();
310 // No reset should have been sent since nothing has been received yet.
311 EXPECT_EQ(0, dispatcher_
->reset_calls());
313 // Fill the prefetch cache as requested.
314 int prefetch_count
= dispatcher_
->last_prefetch_count();
315 std::vector
<IndexedDBKey
> keys(prefetch_count
);
316 std::vector
<IndexedDBKey
> primary_keys(prefetch_count
);
317 std::vector
<WebData
> values(prefetch_count
);
318 std::vector
<WebVector
<WebBlobInfo
> > blob_info(prefetch_count
);
319 cursor
.SetPrefetchData(keys
, primary_keys
, values
, blob_info
);
321 // No reset should have been sent since prefetch data hasn't been used.
322 EXPECT_EQ(0, dispatcher_
->reset_calls());
324 // The real dispatcher would call cursor->CachedContinue(), so do that:
325 scoped_ptr
<WebIDBCallbacks
> callbacks(new MockContinueCallbacks());
326 cursor
.CachedContinue(callbacks
.get());
328 // Now the cursor should have reset the rest of the cache.
329 EXPECT_EQ(1, dispatcher_
->reset_calls());
330 EXPECT_EQ(1, dispatcher_
->last_used_count());
333 } // namespace content