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_
;
118 class MockSyncMessageFilter
: public IPC::SyncMessageFilter
{
120 MockSyncMessageFilter()
121 : SyncMessageFilter(nullptr, false /* is_channel_send_thread_safe */) {}
124 ~MockSyncMessageFilter() override
{}
129 class WebIDBCursorImplTest
: public testing::Test
{
131 WebIDBCursorImplTest() {
132 null_key_
.assignNull();
133 thread_safe_sender_
= new ThreadSafeSender(
134 base::ThreadTaskRunnerHandle::Get(), new MockSyncMessageFilter
);
136 make_scoped_ptr(new MockDispatcher(thread_safe_sender_
.get()));
140 base::MessageLoop message_loop_
;
142 scoped_refptr
<ThreadSafeSender
> thread_safe_sender_
;
143 scoped_ptr
<MockDispatcher
> dispatcher_
;
146 DISALLOW_COPY_AND_ASSIGN(WebIDBCursorImplTest
);
149 TEST_F(WebIDBCursorImplTest
, PrefetchTest
) {
150 const int64 transaction_id
= 1;
152 WebIDBCursorImpl
cursor(WebIDBCursorImpl::kInvalidCursorId
,
154 thread_safe_sender_
.get());
156 // Call continue() until prefetching should kick in.
157 int continue_calls
= 0;
158 EXPECT_EQ(dispatcher_
->continue_calls(), 0);
159 for (int i
= 0; i
< WebIDBCursorImpl::kPrefetchContinueThreshold
; ++i
) {
160 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
161 EXPECT_EQ(++continue_calls
, dispatcher_
->continue_calls());
162 EXPECT_EQ(0, dispatcher_
->prefetch_calls());
165 // Do enough repetitions to verify that the count grows each time,
166 // but not so many that the maximum limit is hit.
167 const int kPrefetchRepetitions
= 5;
169 int expected_key
= 0;
170 int last_prefetch_count
= 0;
171 for (int repetitions
= 0; repetitions
< kPrefetchRepetitions
;
173 // Initiate the prefetch
174 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
175 EXPECT_EQ(continue_calls
, dispatcher_
->continue_calls());
176 EXPECT_EQ(repetitions
+ 1, dispatcher_
->prefetch_calls());
178 // Verify that the requested count has increased since last time.
179 int prefetch_count
= dispatcher_
->last_prefetch_count();
180 EXPECT_GT(prefetch_count
, last_prefetch_count
);
181 last_prefetch_count
= prefetch_count
;
183 // Fill the prefetch cache as requested.
184 std::vector
<IndexedDBKey
> keys
;
185 std::vector
<IndexedDBKey
> primary_keys(prefetch_count
);
186 std::vector
<WebData
> values(prefetch_count
);
187 std::vector
<WebVector
<WebBlobInfo
> > blob_info
;
188 for (int i
= 0; i
< prefetch_count
; ++i
) {
189 keys
.push_back(IndexedDBKey(expected_key
+ i
, WebIDBKeyTypeNumber
));
191 WebVector
<WebBlobInfo
>(static_cast<size_t>(expected_key
+ i
)));
193 cursor
.SetPrefetchData(keys
, primary_keys
, values
, blob_info
);
195 // Note that the real dispatcher would call cursor->CachedContinue()
196 // immediately after cursor->SetPrefetchData() to service the request
197 // that initiated the prefetch.
199 // Verify that the cache is used for subsequent continue() calls.
200 for (int i
= 0; i
< prefetch_count
; ++i
) {
202 WebVector
<WebBlobInfo
> web_blob_info
;
203 cursor
.continueFunction(
204 null_key_
, new MockContinueCallbacks(&key
, &web_blob_info
));
205 EXPECT_EQ(continue_calls
, dispatcher_
->continue_calls());
206 EXPECT_EQ(repetitions
+ 1, dispatcher_
->prefetch_calls());
208 EXPECT_EQ(WebIDBKeyTypeNumber
, key
.type());
209 EXPECT_EQ(expected_key
, static_cast<int>(web_blob_info
.size()));
210 EXPECT_EQ(expected_key
++, key
.number());
215 EXPECT_EQ(dispatcher_
->destroyed_cursor_id(),
216 WebIDBCursorImpl::kInvalidCursorId
);
219 TEST_F(WebIDBCursorImplTest
, AdvancePrefetchTest
) {
220 const int64 transaction_id
= 1;
221 WebIDBCursorImpl
cursor(WebIDBCursorImpl::kInvalidCursorId
,
223 thread_safe_sender_
.get());
225 // Call continue() until prefetching should kick in.
226 EXPECT_EQ(0, dispatcher_
->continue_calls());
227 for (int i
= 0; i
< WebIDBCursorImpl::kPrefetchContinueThreshold
; ++i
) {
228 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
230 EXPECT_EQ(0, dispatcher_
->prefetch_calls());
232 // Initiate the prefetch
233 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
235 EXPECT_EQ(1, dispatcher_
->prefetch_calls());
236 EXPECT_EQ(static_cast<int>(WebIDBCursorImpl::kPrefetchContinueThreshold
),
237 dispatcher_
->continue_calls());
238 EXPECT_EQ(0, dispatcher_
->advance_calls());
240 const int prefetch_count
= dispatcher_
->last_prefetch_count();
242 // Fill the prefetch cache as requested.
243 int expected_key
= 0;
244 std::vector
<IndexedDBKey
> keys
;
245 std::vector
<IndexedDBKey
> primary_keys(prefetch_count
);
246 std::vector
<WebData
> values(prefetch_count
);
247 std::vector
<WebVector
<WebBlobInfo
> > blob_info
;
248 for (int i
= 0; i
< prefetch_count
; ++i
) {
249 keys
.push_back(IndexedDBKey(expected_key
+ i
, WebIDBKeyTypeNumber
));
251 WebVector
<WebBlobInfo
>(static_cast<size_t>(expected_key
+ i
)));
253 cursor
.SetPrefetchData(keys
, primary_keys
, values
, blob_info
);
255 // Note that the real dispatcher would call cursor->CachedContinue()
256 // immediately after cursor->SetPrefetchData() to service the request
257 // that initiated the prefetch.
259 // Need at least this many in the cache for the test steps.
260 ASSERT_GE(prefetch_count
, 5);
262 // IDBCursor.continue()
264 cursor
.continueFunction(null_key_
, new MockContinueCallbacks(&key
));
265 EXPECT_EQ(0, key
.number());
267 // IDBCursor.advance(1)
268 cursor
.advance(1, new MockContinueCallbacks(&key
));
269 EXPECT_EQ(1, key
.number());
271 // IDBCursor.continue()
272 cursor
.continueFunction(null_key_
, new MockContinueCallbacks(&key
));
273 EXPECT_EQ(2, key
.number());
275 // IDBCursor.advance(2)
276 cursor
.advance(2, new MockContinueCallbacks(&key
));
277 EXPECT_EQ(4, key
.number());
279 EXPECT_EQ(0, dispatcher_
->advance_calls());
281 // IDBCursor.advance(lots) - beyond the fetched amount
282 cursor
.advance(WebIDBCursorImpl::kMaxPrefetchAmount
,
283 new MockContinueCallbacks(&key
));
284 EXPECT_EQ(1, dispatcher_
->advance_calls());
285 EXPECT_EQ(1, dispatcher_
->prefetch_calls());
286 EXPECT_EQ(static_cast<int>(WebIDBCursorImpl::kPrefetchContinueThreshold
),
287 dispatcher_
->continue_calls());
290 TEST_F(WebIDBCursorImplTest
, PrefetchReset
) {
291 const int64 transaction_id
= 1;
292 WebIDBCursorImpl
cursor(WebIDBCursorImpl::kInvalidCursorId
,
294 thread_safe_sender_
.get());
296 // Call continue() until prefetching should kick in.
297 int continue_calls
= 0;
298 EXPECT_EQ(dispatcher_
->continue_calls(), 0);
299 for (int i
= 0; i
< WebIDBCursorImpl::kPrefetchContinueThreshold
; ++i
) {
300 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
301 EXPECT_EQ(++continue_calls
, dispatcher_
->continue_calls());
302 EXPECT_EQ(0, dispatcher_
->prefetch_calls());
305 // Initiate the prefetch
306 cursor
.continueFunction(null_key_
, new MockContinueCallbacks());
307 EXPECT_EQ(continue_calls
, dispatcher_
->continue_calls());
308 EXPECT_EQ(1, dispatcher_
->prefetch_calls());
309 EXPECT_EQ(0, dispatcher_
->reset_calls());
312 cursor
.ResetPrefetchCache();
314 // No reset should have been sent since nothing has been received yet.
315 EXPECT_EQ(0, dispatcher_
->reset_calls());
317 // Fill the prefetch cache as requested.
318 int prefetch_count
= dispatcher_
->last_prefetch_count();
319 std::vector
<IndexedDBKey
> keys(prefetch_count
);
320 std::vector
<IndexedDBKey
> primary_keys(prefetch_count
);
321 std::vector
<WebData
> values(prefetch_count
);
322 std::vector
<WebVector
<WebBlobInfo
> > blob_info(prefetch_count
);
323 cursor
.SetPrefetchData(keys
, primary_keys
, values
, blob_info
);
325 // No reset should have been sent since prefetch data hasn't been used.
326 EXPECT_EQ(0, dispatcher_
->reset_calls());
328 // The real dispatcher would call cursor->CachedContinue(), so do that:
329 scoped_ptr
<WebIDBCallbacks
> callbacks(new MockContinueCallbacks());
330 cursor
.CachedContinue(callbacks
.get());
332 // Now the cursor should have reset the rest of the cache.
333 EXPECT_EQ(1, dispatcher_
->reset_calls());
334 EXPECT_EQ(1, dispatcher_
->last_used_count());
337 } // namespace content