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"
18 using blink::WebIDBCallbacks
;
19 using blink::WebIDBDatabase
;
20 using blink::WebIDBKey
;
21 using blink::WebIDBKeyTypeNumber
;
27 class MockDispatcher
: public IndexedDBDispatcher
{
29 MockDispatcher(ThreadSafeSender
* thread_safe_sender
)
30 : IndexedDBDispatcher(thread_safe_sender
),
32 last_prefetch_count_(0),
37 destroyed_cursor_id_(0) {}
39 virtual void RequestIDBCursorPrefetch(int n
,
40 WebIDBCallbacks
* callbacks
,
41 int32 ipc_cursor_id
) OVERRIDE
{
43 last_prefetch_count_
= n
;
44 callbacks_
.reset(callbacks
);
47 virtual void RequestIDBCursorPrefetchReset(int used_prefetches
,
48 int unused_prefetches
,
49 int32 ipc_cursor_id
) OVERRIDE
{
51 last_used_count_
= used_prefetches
;
54 virtual void RequestIDBCursorAdvance(unsigned long count
,
55 WebIDBCallbacks
* callbacks
,
56 int32 ipc_cursor_id
) OVERRIDE
{
58 callbacks_
.reset(callbacks
);
61 virtual void RequestIDBCursorContinue(const IndexedDBKey
& key
,
62 const IndexedDBKey
& primary_key
,
63 WebIDBCallbacks
* callbacks
,
64 int32 ipc_cursor_id
) OVERRIDE
{
66 callbacks_
.reset(callbacks
);
69 virtual void CursorDestroyed(int32 ipc_cursor_id
) OVERRIDE
{
70 destroyed_cursor_id_
= ipc_cursor_id
;
73 int prefetch_calls() { return prefetch_calls_
; }
74 int last_prefetch_count() { return last_prefetch_count_
; }
75 int reset_calls() { return reset_calls_
; }
76 int last_used_count() { return last_used_count_
; }
77 int advance_calls() { return advance_calls_
; }
78 int continue_calls() { return continue_calls_
; }
79 int32
destroyed_cursor_id() { return destroyed_cursor_id_
; }
83 int last_prefetch_count_
;
88 int32 destroyed_cursor_id_
;
89 scoped_ptr
<WebIDBCallbacks
> callbacks_
;
92 class MockContinueCallbacks
: public WebIDBCallbacks
{
94 MockContinueCallbacks(IndexedDBKey
* key
= 0) : key_(key
) {}
96 virtual void onSuccess(const WebIDBKey
& key
,
97 const WebIDBKey
& primaryKey
,
98 const WebData
& value
) {
101 *key_
= IndexedDBKeyBuilder::Build(key
);
110 class WebIDBCursorImplTest
: public testing::Test
{
112 WebIDBCursorImplTest() {
113 null_key_
.assignNull();
114 sync_message_filter_
= new IPC::SyncMessageFilter(NULL
);
115 thread_safe_sender_
= new ThreadSafeSender(
116 base::MessageLoopProxy::current(), sync_message_filter_
.get());
118 make_scoped_ptr(new MockDispatcher(thread_safe_sender_
.get()));
123 scoped_refptr
<ThreadSafeSender
> thread_safe_sender_
;
124 scoped_ptr
<MockDispatcher
> dispatcher_
;
127 scoped_refptr
<IPC::SyncMessageFilter
> sync_message_filter_
;
129 DISALLOW_COPY_AND_ASSIGN(WebIDBCursorImplTest
);
132 TEST_F(WebIDBCursorImplTest
, PrefetchTest
) {
135 WebIDBCursorImpl
cursor(WebIDBCursorImpl::kInvalidCursorId
,
136 thread_safe_sender_
.get());
138 // Call continue() until prefetching should kick in.
139 int continue_calls
= 0;
140 EXPECT_EQ(dispatcher_
->continue_calls(), 0);
141 for (int i
= 0; i
< WebIDBCursorImpl::kPrefetchContinueThreshold
; ++i
) {
142 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
143 EXPECT_EQ(++continue_calls
, dispatcher_
->continue_calls());
144 EXPECT_EQ(0, dispatcher_
->prefetch_calls());
147 // Do enough repetitions to verify that the count grows each time,
148 // but not so many that the maximum limit is hit.
149 const int kPrefetchRepetitions
= 5;
151 int expected_key
= 0;
152 int last_prefetch_count
= 0;
153 for (int repetitions
= 0; repetitions
< kPrefetchRepetitions
;
156 // Initiate the prefetch
157 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
158 EXPECT_EQ(continue_calls
, dispatcher_
->continue_calls());
159 EXPECT_EQ(repetitions
+ 1, dispatcher_
->prefetch_calls());
161 // Verify that the requested count has increased since last time.
162 int prefetch_count
= dispatcher_
->last_prefetch_count();
163 EXPECT_GT(prefetch_count
, last_prefetch_count
);
164 last_prefetch_count
= prefetch_count
;
166 // Fill the prefetch cache as requested.
167 std::vector
<IndexedDBKey
> keys
;
168 std::vector
<IndexedDBKey
> primary_keys(prefetch_count
);
169 std::vector
<WebData
> values(prefetch_count
);
170 for (int i
= 0; i
< prefetch_count
; ++i
) {
171 keys
.push_back(IndexedDBKey(expected_key
+ i
, WebIDBKeyTypeNumber
));
173 cursor
.SetPrefetchData(keys
, primary_keys
, values
);
175 // Note that the real dispatcher would call cursor->CachedContinue()
176 // immediately after cursor->SetPrefetchData() to service the request
177 // that initiated the prefetch.
179 // Verify that the cache is used for subsequent continue() calls.
180 for (int i
= 0; i
< prefetch_count
; ++i
) {
182 cursor
.continueFunction(null_key_
, new MockContinueCallbacks(&key
));
183 EXPECT_EQ(continue_calls
, dispatcher_
->continue_calls());
184 EXPECT_EQ(repetitions
+ 1, dispatcher_
->prefetch_calls());
186 EXPECT_EQ(WebIDBKeyTypeNumber
, key
.type());
187 EXPECT_EQ(expected_key
++, key
.number());
192 EXPECT_EQ(dispatcher_
->destroyed_cursor_id(),
193 WebIDBCursorImpl::kInvalidCursorId
);
196 TEST_F(WebIDBCursorImplTest
, AdvancePrefetchTest
) {
198 WebIDBCursorImpl
cursor(WebIDBCursorImpl::kInvalidCursorId
,
199 thread_safe_sender_
.get());
201 // Call continue() until prefetching should kick in.
202 EXPECT_EQ(0, dispatcher_
->continue_calls());
203 for (int i
= 0; i
< WebIDBCursorImpl::kPrefetchContinueThreshold
; ++i
) {
204 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
206 EXPECT_EQ(0, dispatcher_
->prefetch_calls());
208 // Initiate the prefetch
209 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
211 EXPECT_EQ(1, dispatcher_
->prefetch_calls());
212 EXPECT_EQ(static_cast<int>(WebIDBCursorImpl::kPrefetchContinueThreshold
),
213 dispatcher_
->continue_calls());
214 EXPECT_EQ(0, dispatcher_
->advance_calls());
216 const int prefetch_count
= dispatcher_
->last_prefetch_count();
218 // Fill the prefetch cache as requested.
219 int expected_key
= 0;
220 std::vector
<IndexedDBKey
> keys
;
221 std::vector
<IndexedDBKey
> primary_keys(prefetch_count
);
222 std::vector
<WebData
> values(prefetch_count
);
223 for (int i
= 0; i
< prefetch_count
; ++i
) {
224 keys
.push_back(IndexedDBKey(expected_key
+ i
, WebIDBKeyTypeNumber
));
226 cursor
.SetPrefetchData(keys
, primary_keys
, values
);
228 // Note that the real dispatcher would call cursor->CachedContinue()
229 // immediately after cursor->SetPrefetchData() to service the request
230 // that initiated the prefetch.
232 // Need at least this many in the cache for the test steps.
233 ASSERT_GE(prefetch_count
, 5);
235 // IDBCursor.continue()
237 cursor
.continueFunction(null_key_
, new MockContinueCallbacks(&key
));
238 EXPECT_EQ(0, key
.number());
240 // IDBCursor.advance(1)
241 cursor
.advance(1, new MockContinueCallbacks(&key
));
242 EXPECT_EQ(1, key
.number());
244 // IDBCursor.continue()
245 cursor
.continueFunction(null_key_
, new MockContinueCallbacks(&key
));
246 EXPECT_EQ(2, key
.number());
248 // IDBCursor.advance(2)
249 cursor
.advance(2, new MockContinueCallbacks(&key
));
250 EXPECT_EQ(4, key
.number());
252 EXPECT_EQ(0, dispatcher_
->advance_calls());
254 // IDBCursor.advance(lots) - beyond the fetched amount
255 cursor
.advance(WebIDBCursorImpl::kMaxPrefetchAmount
,
256 new MockContinueCallbacks(&key
));
257 EXPECT_EQ(1, dispatcher_
->advance_calls());
258 EXPECT_EQ(1, dispatcher_
->prefetch_calls());
259 EXPECT_EQ(static_cast<int>(WebIDBCursorImpl::kPrefetchContinueThreshold
),
260 dispatcher_
->continue_calls());
263 TEST_F(WebIDBCursorImplTest
, PrefetchReset
) {
264 WebIDBCursorImpl
cursor(WebIDBCursorImpl::kInvalidCursorId
,
265 thread_safe_sender_
.get());
267 // Call continue() until prefetching should kick in.
268 int continue_calls
= 0;
269 EXPECT_EQ(dispatcher_
->continue_calls(), 0);
270 for (int i
= 0; i
< WebIDBCursorImpl::kPrefetchContinueThreshold
; ++i
) {
271 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
272 EXPECT_EQ(++continue_calls
, dispatcher_
->continue_calls());
273 EXPECT_EQ(0, dispatcher_
->prefetch_calls());
276 // Initiate the prefetch
277 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
278 EXPECT_EQ(continue_calls
, dispatcher_
->continue_calls());
279 EXPECT_EQ(1, dispatcher_
->prefetch_calls());
280 EXPECT_EQ(0, dispatcher_
->reset_calls());
283 cursor
.ResetPrefetchCache();
285 // No reset should have been sent since nothing has been received yet.
286 EXPECT_EQ(0, dispatcher_
->reset_calls());
288 // Fill the prefetch cache as requested.
289 int prefetch_count
= dispatcher_
->last_prefetch_count();
290 std::vector
<IndexedDBKey
> keys(prefetch_count
);
291 std::vector
<IndexedDBKey
> primary_keys(prefetch_count
);
292 std::vector
<WebData
> values(prefetch_count
);
293 cursor
.SetPrefetchData(keys
, primary_keys
, values
);
295 // No reset should have been sent since prefetch data hasn't been used.
296 EXPECT_EQ(0, dispatcher_
->reset_calls());
298 // The real dispatcher would call cursor->CachedContinue(), so do that:
299 scoped_ptr
<WebIDBCallbacks
> callbacks(new MockContinueCallbacks());
300 cursor
.CachedContinue(callbacks
.get());
302 // Now the cursor should have reset the rest of the cache.
303 EXPECT_EQ(1, dispatcher_
->reset_calls());
304 EXPECT_EQ(1, dispatcher_
->last_used_count());
307 } // namespace content