OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "content/child/indexed_db/webidbcursor_impl.h" | |
6 | |
7 #include <stddef.h> | |
8 #include <stdint.h> | |
9 | |
10 #include <memory> | |
11 | |
12 #include "base/macros.h" | |
13 #include "base/memory/ptr_util.h" | |
14 #include "base/threading/thread_task_runner_handle.h" | |
15 #include "base/values.h" | |
16 #include "content/child/indexed_db/indexed_db_dispatcher.h" | |
17 #include "content/child/indexed_db/indexed_db_key_builders.h" | |
18 #include "content/child/indexed_db/mock_webidbcallbacks.h" | |
19 #include "content/child/thread_safe_sender.h" | |
20 #include "content/common/indexed_db/indexed_db_key.h" | |
21 #include "ipc/ipc_sync_message_filter.h" | |
22 #include "testing/gtest/include/gtest/gtest.h" | |
23 #include "third_party/WebKit/public/platform/WebData.h" | |
24 | |
25 using blink::WebBlobInfo; | |
26 using blink::WebData; | |
27 using blink::WebIDBCallbacks; | |
28 using blink::WebIDBKey; | |
29 using blink::WebIDBKeyTypeNumber; | |
30 using blink::WebIDBValue; | |
31 using blink::WebVector; | |
32 using testing::StrictMock; | |
33 | |
34 namespace content { | |
35 | |
36 namespace { | |
37 | |
38 class MockDispatcher : public IndexedDBDispatcher { | |
39 public: | |
40 explicit MockDispatcher(ThreadSafeSender* thread_safe_sender) | |
41 : IndexedDBDispatcher(thread_safe_sender), | |
42 prefetch_calls_(0), | |
43 last_prefetch_count_(0), | |
44 reset_calls_(0), | |
45 last_used_count_(0), | |
46 advance_calls_(0), | |
47 continue_calls_(0), | |
48 destroyed_cursor_id_(0) {} | |
49 | |
50 void RequestIDBCursorPrefetch(int n, | |
51 WebIDBCallbacks* callbacks, | |
52 int32_t ipc_cursor_id) override { | |
53 ++prefetch_calls_; | |
54 last_prefetch_count_ = n; | |
55 callbacks_.reset(callbacks); | |
56 } | |
57 | |
58 void RequestIDBCursorPrefetchReset(int used_prefetches, | |
59 int unused_prefetches, | |
60 int32_t ipc_cursor_id) override { | |
61 ++reset_calls_; | |
62 last_used_count_ = used_prefetches; | |
63 } | |
64 | |
65 void RequestIDBCursorAdvance(unsigned long count, | |
66 WebIDBCallbacks* callbacks, | |
67 int32_t ipc_cursor_id, | |
68 int64_t transaction_id) override { | |
69 ++advance_calls_; | |
70 callbacks_.reset(callbacks); | |
71 } | |
72 | |
73 void RequestIDBCursorContinue(const IndexedDBKey& key, | |
74 const IndexedDBKey& primary_key, | |
75 WebIDBCallbacks* callbacks, | |
76 int32_t ipc_cursor_id, | |
77 int64_t transaction_id) override { | |
78 ++continue_calls_; | |
79 callbacks_.reset(callbacks); | |
80 } | |
81 | |
82 void CursorDestroyed(int32_t ipc_cursor_id) override { | |
83 destroyed_cursor_id_ = ipc_cursor_id; | |
84 } | |
85 | |
86 int prefetch_calls() { return prefetch_calls_; } | |
87 int last_prefetch_count() { return last_prefetch_count_; } | |
88 int reset_calls() { return reset_calls_; } | |
89 int last_used_count() { return last_used_count_; } | |
90 int advance_calls() { return advance_calls_; } | |
91 int continue_calls() { return continue_calls_; } | |
92 int32_t destroyed_cursor_id() { return destroyed_cursor_id_; } | |
93 | |
94 private: | |
95 int prefetch_calls_; | |
96 int last_prefetch_count_; | |
97 int reset_calls_; | |
98 int last_used_count_; | |
99 int advance_calls_; | |
100 int continue_calls_; | |
101 int32_t destroyed_cursor_id_; | |
102 std::unique_ptr<WebIDBCallbacks> callbacks_; | |
103 }; | |
104 | |
105 class MockContinueCallbacks : public StrictMock<MockWebIDBCallbacks> { | |
106 public: | |
107 MockContinueCallbacks(IndexedDBKey* key = 0, | |
108 WebVector<WebBlobInfo>* webBlobInfo = 0) | |
109 : key_(key), web_blob_info_(webBlobInfo) {} | |
110 | |
111 void onSuccess(const WebIDBKey& key, | |
112 const WebIDBKey& primaryKey, | |
113 const WebIDBValue& value) override { | |
114 if (key_) | |
115 *key_ = IndexedDBKeyBuilder::Build(key); | |
116 if (web_blob_info_) | |
117 *web_blob_info_ = value.webBlobInfo; | |
118 } | |
119 | |
120 private: | |
121 IndexedDBKey* key_; | |
122 WebVector<WebBlobInfo>* web_blob_info_; | |
123 }; | |
124 | |
125 class MockSyncMessageFilter : public IPC::SyncMessageFilter { | |
126 public: | |
127 MockSyncMessageFilter() | |
128 : SyncMessageFilter(nullptr, false /* is_channel_send_thread_safe */) {} | |
129 | |
130 private: | |
131 ~MockSyncMessageFilter() override {} | |
132 }; | |
133 | |
134 } // namespace | |
135 | |
136 class WebIDBCursorImplTest : public testing::Test { | |
137 public: | |
138 WebIDBCursorImplTest() { | |
139 null_key_.assignNull(); | |
140 thread_safe_sender_ = new ThreadSafeSender( | |
141 base::ThreadTaskRunnerHandle::Get(), new MockSyncMessageFilter); | |
142 dispatcher_ = | |
143 base::WrapUnique(new MockDispatcher(thread_safe_sender_.get())); | |
144 } | |
145 | |
146 protected: | |
147 base::MessageLoop message_loop_; | |
148 WebIDBKey null_key_; | |
149 scoped_refptr<ThreadSafeSender> thread_safe_sender_; | |
150 std::unique_ptr<MockDispatcher> dispatcher_; | |
151 | |
152 private: | |
153 DISALLOW_COPY_AND_ASSIGN(WebIDBCursorImplTest); | |
154 }; | |
155 | |
156 TEST_F(WebIDBCursorImplTest, PrefetchTest) { | |
157 const int64_t transaction_id = 1; | |
158 { | |
159 WebIDBCursorImpl cursor(WebIDBCursorImpl::kInvalidCursorId, | |
160 transaction_id, | |
161 thread_safe_sender_.get()); | |
162 | |
163 // Call continue() until prefetching should kick in. | |
164 int continue_calls = 0; | |
165 EXPECT_EQ(dispatcher_->continue_calls(), 0); | |
166 for (int i = 0; i < WebIDBCursorImpl::kPrefetchContinueThreshold; ++i) { | |
167 cursor.continueFunction(null_key_, new MockContinueCallbacks()); | |
168 EXPECT_EQ(++continue_calls, dispatcher_->continue_calls()); | |
169 EXPECT_EQ(0, dispatcher_->prefetch_calls()); | |
170 } | |
171 | |
172 // Do enough repetitions to verify that the count grows each time, | |
173 // but not so many that the maximum limit is hit. | |
174 const int kPrefetchRepetitions = 5; | |
175 | |
176 int expected_key = 0; | |
177 int last_prefetch_count = 0; | |
178 for (int repetitions = 0; repetitions < kPrefetchRepetitions; | |
179 ++repetitions) { | |
180 // Initiate the prefetch | |
181 cursor.continueFunction(null_key_, new MockContinueCallbacks()); | |
182 EXPECT_EQ(continue_calls, dispatcher_->continue_calls()); | |
183 EXPECT_EQ(repetitions + 1, dispatcher_->prefetch_calls()); | |
184 | |
185 // Verify that the requested count has increased since last time. | |
186 int prefetch_count = dispatcher_->last_prefetch_count(); | |
187 EXPECT_GT(prefetch_count, last_prefetch_count); | |
188 last_prefetch_count = prefetch_count; | |
189 | |
190 // Fill the prefetch cache as requested. | |
191 std::vector<IndexedDBKey> keys; | |
192 std::vector<IndexedDBKey> primary_keys(prefetch_count); | |
193 std::vector<WebIDBValue> values(prefetch_count); | |
194 for (int i = 0; i < prefetch_count; ++i) { | |
195 keys.push_back(IndexedDBKey(expected_key + i, WebIDBKeyTypeNumber)); | |
196 values[i].webBlobInfo = | |
197 WebVector<WebBlobInfo>(static_cast<size_t>(expected_key + i)); | |
198 } | |
199 cursor.SetPrefetchData(keys, primary_keys, values); | |
200 | |
201 // Note that the real dispatcher would call cursor->CachedContinue() | |
202 // immediately after cursor->SetPrefetchData() to service the request | |
203 // that initiated the prefetch. | |
204 | |
205 // Verify that the cache is used for subsequent continue() calls. | |
206 for (int i = 0; i < prefetch_count; ++i) { | |
207 IndexedDBKey key; | |
208 WebVector<WebBlobInfo> web_blob_info; | |
209 cursor.continueFunction( | |
210 null_key_, new MockContinueCallbacks(&key, &web_blob_info)); | |
211 EXPECT_EQ(continue_calls, dispatcher_->continue_calls()); | |
212 EXPECT_EQ(repetitions + 1, dispatcher_->prefetch_calls()); | |
213 | |
214 EXPECT_EQ(WebIDBKeyTypeNumber, key.type()); | |
215 EXPECT_EQ(expected_key, static_cast<int>(web_blob_info.size())); | |
216 EXPECT_EQ(expected_key++, key.number()); | |
217 } | |
218 } | |
219 } | |
220 | |
221 EXPECT_EQ(dispatcher_->destroyed_cursor_id(), | |
222 WebIDBCursorImpl::kInvalidCursorId); | |
223 } | |
224 | |
225 TEST_F(WebIDBCursorImplTest, AdvancePrefetchTest) { | |
226 const int64_t transaction_id = 1; | |
227 WebIDBCursorImpl cursor(WebIDBCursorImpl::kInvalidCursorId, | |
228 transaction_id, | |
229 thread_safe_sender_.get()); | |
230 | |
231 // Call continue() until prefetching should kick in. | |
232 EXPECT_EQ(0, dispatcher_->continue_calls()); | |
233 for (int i = 0; i < WebIDBCursorImpl::kPrefetchContinueThreshold; ++i) { | |
234 cursor.continueFunction(null_key_, new MockContinueCallbacks()); | |
235 } | |
236 EXPECT_EQ(0, dispatcher_->prefetch_calls()); | |
237 | |
238 // Initiate the prefetch | |
239 cursor.continueFunction(null_key_, new MockContinueCallbacks()); | |
240 | |
241 EXPECT_EQ(1, dispatcher_->prefetch_calls()); | |
242 EXPECT_EQ(static_cast<int>(WebIDBCursorImpl::kPrefetchContinueThreshold), | |
243 dispatcher_->continue_calls()); | |
244 EXPECT_EQ(0, dispatcher_->advance_calls()); | |
245 | |
246 const int prefetch_count = dispatcher_->last_prefetch_count(); | |
247 | |
248 // Fill the prefetch cache as requested. | |
249 int expected_key = 0; | |
250 std::vector<IndexedDBKey> keys; | |
251 std::vector<IndexedDBKey> primary_keys(prefetch_count); | |
252 std::vector<WebIDBValue> values(prefetch_count); | |
253 for (int i = 0; i < prefetch_count; ++i) { | |
254 keys.push_back(IndexedDBKey(expected_key + i, WebIDBKeyTypeNumber)); | |
255 values[i].webBlobInfo = | |
256 WebVector<WebBlobInfo>(static_cast<size_t>(expected_key + i)); | |
257 } | |
258 cursor.SetPrefetchData(keys, primary_keys, values); | |
259 | |
260 // Note that the real dispatcher would call cursor->CachedContinue() | |
261 // immediately after cursor->SetPrefetchData() to service the request | |
262 // that initiated the prefetch. | |
263 | |
264 // Need at least this many in the cache for the test steps. | |
265 ASSERT_GE(prefetch_count, 5); | |
266 | |
267 // IDBCursor.continue() | |
268 IndexedDBKey key; | |
269 cursor.continueFunction(null_key_, new MockContinueCallbacks(&key)); | |
270 EXPECT_EQ(0, key.number()); | |
271 | |
272 // IDBCursor.advance(1) | |
273 cursor.advance(1, new MockContinueCallbacks(&key)); | |
274 EXPECT_EQ(1, key.number()); | |
275 | |
276 // IDBCursor.continue() | |
277 cursor.continueFunction(null_key_, new MockContinueCallbacks(&key)); | |
278 EXPECT_EQ(2, key.number()); | |
279 | |
280 // IDBCursor.advance(2) | |
281 cursor.advance(2, new MockContinueCallbacks(&key)); | |
282 EXPECT_EQ(4, key.number()); | |
283 | |
284 EXPECT_EQ(0, dispatcher_->advance_calls()); | |
285 | |
286 // IDBCursor.advance(lots) - beyond the fetched amount | |
287 cursor.advance(WebIDBCursorImpl::kMaxPrefetchAmount, | |
288 new MockContinueCallbacks(&key)); | |
289 EXPECT_EQ(1, dispatcher_->advance_calls()); | |
290 EXPECT_EQ(1, dispatcher_->prefetch_calls()); | |
291 EXPECT_EQ(static_cast<int>(WebIDBCursorImpl::kPrefetchContinueThreshold), | |
292 dispatcher_->continue_calls()); | |
293 } | |
294 | |
295 TEST_F(WebIDBCursorImplTest, PrefetchReset) { | |
296 const int64_t transaction_id = 1; | |
297 WebIDBCursorImpl cursor(WebIDBCursorImpl::kInvalidCursorId, | |
298 transaction_id, | |
299 thread_safe_sender_.get()); | |
300 | |
301 // Call continue() until prefetching should kick in. | |
302 int continue_calls = 0; | |
303 EXPECT_EQ(dispatcher_->continue_calls(), 0); | |
304 for (int i = 0; i < WebIDBCursorImpl::kPrefetchContinueThreshold; ++i) { | |
305 cursor.continueFunction(null_key_, new MockContinueCallbacks()); | |
306 EXPECT_EQ(++continue_calls, dispatcher_->continue_calls()); | |
307 EXPECT_EQ(0, dispatcher_->prefetch_calls()); | |
308 } | |
309 | |
310 // Initiate the prefetch | |
311 cursor.continueFunction(null_key_, new MockContinueCallbacks()); | |
312 EXPECT_EQ(continue_calls, dispatcher_->continue_calls()); | |
313 EXPECT_EQ(1, dispatcher_->prefetch_calls()); | |
314 EXPECT_EQ(0, dispatcher_->reset_calls()); | |
315 | |
316 // Now invalidate it | |
317 cursor.ResetPrefetchCache(); | |
318 | |
319 // No reset should have been sent since nothing has been received yet. | |
320 EXPECT_EQ(0, dispatcher_->reset_calls()); | |
321 | |
322 // Fill the prefetch cache as requested. | |
323 int prefetch_count = dispatcher_->last_prefetch_count(); | |
324 std::vector<IndexedDBKey> keys(prefetch_count); | |
325 std::vector<IndexedDBKey> primary_keys(prefetch_count); | |
326 std::vector<WebIDBValue> values(prefetch_count); | |
327 cursor.SetPrefetchData(keys, primary_keys, values); | |
328 | |
329 // No reset should have been sent since prefetch data hasn't been used. | |
330 EXPECT_EQ(0, dispatcher_->reset_calls()); | |
331 | |
332 // The real dispatcher would call cursor->CachedContinue(), so do that: | |
333 MockContinueCallbacks callbacks; | |
334 cursor.CachedContinue(&callbacks); | |
335 | |
336 // Now the cursor should have reset the rest of the cache. | |
337 EXPECT_EQ(1, dispatcher_->reset_calls()); | |
338 EXPECT_EQ(1, dispatcher_->last_used_count()); | |
339 } | |
340 | |
341 } // namespace content | |
OLD | NEW |