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/thread_task_runner_handle.h"
7 #include "base/values.h"
8 #include "content/child/indexed_db/indexed_db_dispatcher.h"
9 #include "content/child/indexed_db/indexed_db_key_builders.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 "ipc/ipc_sync_message_filter.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "third_party/WebKit/public/platform/WebData.h"
16 #include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBCallbacks.h"
18 using blink::WebBlobInfo
;
20 using blink::WebIDBCallbacks
;
21 using blink::WebIDBDatabase
;
22 using blink::WebIDBKey
;
23 using blink::WebIDBKeyTypeNumber
;
24 using blink::WebVector
;
30 class MockDispatcher
: public IndexedDBDispatcher
{
32 explicit MockDispatcher(ThreadSafeSender
* thread_safe_sender
)
33 : IndexedDBDispatcher(thread_safe_sender
),
35 last_prefetch_count_(0),
40 destroyed_cursor_id_(0) {}
42 void RequestIDBCursorPrefetch(int n
,
43 WebIDBCallbacks
* callbacks
,
44 int32 ipc_cursor_id
) override
{
46 last_prefetch_count_
= n
;
47 callbacks_
.reset(callbacks
);
50 void RequestIDBCursorPrefetchReset(int used_prefetches
,
51 int unused_prefetches
,
52 int32 ipc_cursor_id
) override
{
54 last_used_count_
= used_prefetches
;
57 void RequestIDBCursorAdvance(unsigned long count
,
58 WebIDBCallbacks
* callbacks
,
60 int64 transaction_id
) override
{
62 callbacks_
.reset(callbacks
);
65 void RequestIDBCursorContinue(const IndexedDBKey
& key
,
66 const IndexedDBKey
& primary_key
,
67 WebIDBCallbacks
* callbacks
,
69 int64 transaction_id
) override
{
71 callbacks_
.reset(callbacks
);
74 void CursorDestroyed(int32 ipc_cursor_id
) override
{
75 destroyed_cursor_id_
= ipc_cursor_id
;
78 int prefetch_calls() { return prefetch_calls_
; }
79 int last_prefetch_count() { return last_prefetch_count_
; }
80 int reset_calls() { return reset_calls_
; }
81 int last_used_count() { return last_used_count_
; }
82 int advance_calls() { return advance_calls_
; }
83 int continue_calls() { return continue_calls_
; }
84 int32
destroyed_cursor_id() { return destroyed_cursor_id_
; }
88 int last_prefetch_count_
;
93 int32 destroyed_cursor_id_
;
94 scoped_ptr
<WebIDBCallbacks
> callbacks_
;
97 class MockContinueCallbacks
: public WebIDBCallbacks
{
99 MockContinueCallbacks(IndexedDBKey
* key
= 0,
100 WebVector
<WebBlobInfo
>* webBlobInfo
= 0)
101 : key_(key
), web_blob_info_(webBlobInfo
) {}
103 void onSuccess(const WebIDBKey
& key
,
104 const WebIDBKey
& primaryKey
,
105 const WebData
& value
,
106 const WebVector
<WebBlobInfo
>& webBlobInfo
) override
{
108 *key_
= IndexedDBKeyBuilder::Build(key
);
110 *web_blob_info_
= webBlobInfo
;
115 WebVector
<WebBlobInfo
>* web_blob_info_
;
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::ThreadTaskRunnerHandle::Get(), sync_message_filter_
.get());
128 make_scoped_ptr(new MockDispatcher(thread_safe_sender_
.get()));
132 base::MessageLoop message_loop_
;
134 scoped_refptr
<ThreadSafeSender
> thread_safe_sender_
;
135 scoped_ptr
<MockDispatcher
> dispatcher_
;
138 scoped_refptr
<IPC::SyncMessageFilter
> sync_message_filter_
;
140 DISALLOW_COPY_AND_ASSIGN(WebIDBCursorImplTest
);
143 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
;
167 // Initiate the prefetch
168 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
169 EXPECT_EQ(continue_calls
, dispatcher_
->continue_calls());
170 EXPECT_EQ(repetitions
+ 1, dispatcher_
->prefetch_calls());
172 // Verify that the requested count has increased since last time.
173 int prefetch_count
= dispatcher_
->last_prefetch_count();
174 EXPECT_GT(prefetch_count
, last_prefetch_count
);
175 last_prefetch_count
= prefetch_count
;
177 // Fill the prefetch cache as requested.
178 std::vector
<IndexedDBKey
> keys
;
179 std::vector
<IndexedDBKey
> primary_keys(prefetch_count
);
180 std::vector
<WebData
> values(prefetch_count
);
181 std::vector
<WebVector
<WebBlobInfo
> > blob_info
;
182 for (int i
= 0; i
< prefetch_count
; ++i
) {
183 keys
.push_back(IndexedDBKey(expected_key
+ i
, WebIDBKeyTypeNumber
));
185 WebVector
<WebBlobInfo
>(static_cast<size_t>(expected_key
+ i
)));
187 cursor
.SetPrefetchData(keys
, primary_keys
, values
, blob_info
);
189 // Note that the real dispatcher would call cursor->CachedContinue()
190 // immediately after cursor->SetPrefetchData() to service the request
191 // that initiated the prefetch.
193 // Verify that the cache is used for subsequent continue() calls.
194 for (int i
= 0; i
< prefetch_count
; ++i
) {
196 WebVector
<WebBlobInfo
> web_blob_info
;
197 cursor
.continueFunction(
198 null_key_
, new MockContinueCallbacks(&key
, &web_blob_info
));
199 EXPECT_EQ(continue_calls
, dispatcher_
->continue_calls());
200 EXPECT_EQ(repetitions
+ 1, dispatcher_
->prefetch_calls());
202 EXPECT_EQ(WebIDBKeyTypeNumber
, key
.type());
203 EXPECT_EQ(expected_key
, static_cast<int>(web_blob_info
.size()));
204 EXPECT_EQ(expected_key
++, key
.number());
209 EXPECT_EQ(dispatcher_
->destroyed_cursor_id(),
210 WebIDBCursorImpl::kInvalidCursorId
);
213 TEST_F(WebIDBCursorImplTest
, AdvancePrefetchTest
) {
214 const int64 transaction_id
= 1;
215 WebIDBCursorImpl
cursor(WebIDBCursorImpl::kInvalidCursorId
,
217 thread_safe_sender_
.get());
219 // Call continue() until prefetching should kick in.
220 EXPECT_EQ(0, dispatcher_
->continue_calls());
221 for (int i
= 0; i
< WebIDBCursorImpl::kPrefetchContinueThreshold
; ++i
) {
222 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
224 EXPECT_EQ(0, dispatcher_
->prefetch_calls());
226 // Initiate the prefetch
227 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
229 EXPECT_EQ(1, dispatcher_
->prefetch_calls());
230 EXPECT_EQ(static_cast<int>(WebIDBCursorImpl::kPrefetchContinueThreshold
),
231 dispatcher_
->continue_calls());
232 EXPECT_EQ(0, dispatcher_
->advance_calls());
234 const int prefetch_count
= dispatcher_
->last_prefetch_count();
236 // Fill the prefetch cache as requested.
237 int expected_key
= 0;
238 std::vector
<IndexedDBKey
> keys
;
239 std::vector
<IndexedDBKey
> primary_keys(prefetch_count
);
240 std::vector
<WebData
> values(prefetch_count
);
241 std::vector
<WebVector
<WebBlobInfo
> > blob_info
;
242 for (int i
= 0; i
< prefetch_count
; ++i
) {
243 keys
.push_back(IndexedDBKey(expected_key
+ i
, WebIDBKeyTypeNumber
));
245 WebVector
<WebBlobInfo
>(static_cast<size_t>(expected_key
+ i
)));
247 cursor
.SetPrefetchData(keys
, primary_keys
, values
, blob_info
);
249 // Note that the real dispatcher would call cursor->CachedContinue()
250 // immediately after cursor->SetPrefetchData() to service the request
251 // that initiated the prefetch.
253 // Need at least this many in the cache for the test steps.
254 ASSERT_GE(prefetch_count
, 5);
256 // IDBCursor.continue()
258 cursor
.continueFunction(null_key_
, new MockContinueCallbacks(&key
));
259 EXPECT_EQ(0, key
.number());
261 // IDBCursor.advance(1)
262 cursor
.advance(1, new MockContinueCallbacks(&key
));
263 EXPECT_EQ(1, key
.number());
265 // IDBCursor.continue()
266 cursor
.continueFunction(null_key_
, new MockContinueCallbacks(&key
));
267 EXPECT_EQ(2, key
.number());
269 // IDBCursor.advance(2)
270 cursor
.advance(2, new MockContinueCallbacks(&key
));
271 EXPECT_EQ(4, key
.number());
273 EXPECT_EQ(0, dispatcher_
->advance_calls());
275 // IDBCursor.advance(lots) - beyond the fetched amount
276 cursor
.advance(WebIDBCursorImpl::kMaxPrefetchAmount
,
277 new MockContinueCallbacks(&key
));
278 EXPECT_EQ(1, dispatcher_
->advance_calls());
279 EXPECT_EQ(1, dispatcher_
->prefetch_calls());
280 EXPECT_EQ(static_cast<int>(WebIDBCursorImpl::kPrefetchContinueThreshold
),
281 dispatcher_
->continue_calls());
284 TEST_F(WebIDBCursorImplTest
, PrefetchReset
) {
285 const int64 transaction_id
= 1;
286 WebIDBCursorImpl
cursor(WebIDBCursorImpl::kInvalidCursorId
,
288 thread_safe_sender_
.get());
290 // Call continue() until prefetching should kick in.
291 int continue_calls
= 0;
292 EXPECT_EQ(dispatcher_
->continue_calls(), 0);
293 for (int i
= 0; i
< WebIDBCursorImpl::kPrefetchContinueThreshold
; ++i
) {
294 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
295 EXPECT_EQ(++continue_calls
, dispatcher_
->continue_calls());
296 EXPECT_EQ(0, dispatcher_
->prefetch_calls());
299 // Initiate the prefetch
300 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
301 EXPECT_EQ(continue_calls
, dispatcher_
->continue_calls());
302 EXPECT_EQ(1, dispatcher_
->prefetch_calls());
303 EXPECT_EQ(0, dispatcher_
->reset_calls());
306 cursor
.ResetPrefetchCache();
308 // No reset should have been sent since nothing has been received yet.
309 EXPECT_EQ(0, dispatcher_
->reset_calls());
311 // Fill the prefetch cache as requested.
312 int prefetch_count
= dispatcher_
->last_prefetch_count();
313 std::vector
<IndexedDBKey
> keys(prefetch_count
);
314 std::vector
<IndexedDBKey
> primary_keys(prefetch_count
);
315 std::vector
<WebData
> values(prefetch_count
);
316 std::vector
<WebVector
<WebBlobInfo
> > blob_info(prefetch_count
);
317 cursor
.SetPrefetchData(keys
, primary_keys
, values
, blob_info
);
319 // No reset should have been sent since prefetch data hasn't been used.
320 EXPECT_EQ(0, dispatcher_
->reset_calls());
322 // The real dispatcher would call cursor->CachedContinue(), so do that:
323 scoped_ptr
<WebIDBCallbacks
> callbacks(new MockContinueCallbacks());
324 cursor
.CachedContinue(callbacks
.get());
326 // Now the cursor should have reset the rest of the cache.
327 EXPECT_EQ(1, dispatcher_
->reset_calls());
328 EXPECT_EQ(1, dispatcher_
->last_used_count());
331 } // namespace content