| 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 |