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 "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/proxy_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" 16 17 using WebKit::WebData; 18 using WebKit::WebIDBCallbacks; 19 using WebKit::WebIDBDatabase; 20 using WebKit::WebIDBKey; 21 using WebKit::WebIDBKeyTypeNumber; 22 23 namespace content { 24 25 namespace { 26 27 class MockDispatcher : public IndexedDBDispatcher { 28 public: 29 MockDispatcher(ThreadSafeSender* thread_safe_sender) 30 : IndexedDBDispatcher(thread_safe_sender), 31 prefetch_calls_(0), 32 last_prefetch_count_(0), 33 continue_calls_(0), 34 destroyed_cursor_id_(0) {} 35 36 virtual void RequestIDBCursorPrefetch(int n, 37 WebIDBCallbacks* callbacks, 38 int32 ipc_cursor_id) OVERRIDE { 39 ++prefetch_calls_; 40 last_prefetch_count_ = n; 41 callbacks_.reset(callbacks); 42 } 43 44 virtual void RequestIDBCursorContinue(const IndexedDBKey&, 45 WebIDBCallbacks* callbacks, 46 int32 ipc_cursor_id) OVERRIDE { 47 ++continue_calls_; 48 callbacks_.reset(callbacks); 49 } 50 51 virtual void CursorDestroyed(int32 ipc_cursor_id) OVERRIDE { 52 destroyed_cursor_id_ = ipc_cursor_id; 53 } 54 55 int prefetch_calls() { return prefetch_calls_; } 56 int continue_calls() { return continue_calls_; } 57 int last_prefetch_count() { return last_prefetch_count_; } 58 int32 destroyed_cursor_id() { return destroyed_cursor_id_; } 59 60 private: 61 int prefetch_calls_; 62 int last_prefetch_count_; 63 int continue_calls_; 64 int32 destroyed_cursor_id_; 65 scoped_ptr<WebIDBCallbacks> callbacks_; 66 }; 67 68 class MockContinueCallbacks : public WebIDBCallbacks { 69 public: 70 MockContinueCallbacks(IndexedDBKey* key = 0) : key_(key) {} 71 72 virtual void onSuccess(const WebIDBKey& key, 73 const WebIDBKey& primaryKey, 74 const WebData& value) { 75 76 if (key_) 77 *key_ = IndexedDBKeyBuilder::Build(key); 78 } 79 80 private: 81 IndexedDBKey* key_; 82 }; 83 84 } // namespace 85 86 TEST(RendererWebIDBCursorImplTest, PrefetchTest) { 87 88 WebIDBKey null_key; 89 null_key.assignNull(); 90 91 scoped_refptr<base::MessageLoopProxy> message_loop_proxy( 92 base::MessageLoopProxy::current()); 93 scoped_refptr<IPC::SyncMessageFilter> sync_message_filter( 94 new IPC::SyncMessageFilter(NULL)); 95 scoped_refptr<ThreadSafeSender> thread_safe_sender(new ThreadSafeSender( 96 message_loop_proxy.get(), sync_message_filter.get())); 97 98 MockDispatcher dispatcher(thread_safe_sender.get()); 99 100 { 101 RendererWebIDBCursorImpl cursor(RendererWebIDBCursorImpl::kInvalidCursorId, 102 thread_safe_sender.get()); 103 104 // Call continue() until prefetching should kick in. 105 int continue_calls = 0; 106 EXPECT_EQ(dispatcher.continue_calls(), 0); 107 for (int i = 0; i < RendererWebIDBCursorImpl::kPrefetchContinueThreshold; 108 ++i) { 109 cursor.continueFunction(null_key, new MockContinueCallbacks()); 110 EXPECT_EQ(++continue_calls, dispatcher.continue_calls()); 111 EXPECT_EQ(0, dispatcher.prefetch_calls()); 112 } 113 114 // Do enough repetitions to verify that the count grows each time, 115 // but not so many that the maximum limit is hit. 116 const int kPrefetchRepetitions = 5; 117 118 int expected_key = 0; 119 int last_prefetch_count = 0; 120 for (int repetitions = 0; repetitions < kPrefetchRepetitions; 121 ++repetitions) { 122 123 // Initiate the prefetch 124 cursor.continueFunction(null_key, new MockContinueCallbacks()); 125 EXPECT_EQ(continue_calls, dispatcher.continue_calls()); 126 EXPECT_EQ(repetitions + 1, dispatcher.prefetch_calls()); 127 128 // Verify that the requested count has increased since last time. 129 int prefetch_count = dispatcher.last_prefetch_count(); 130 EXPECT_GT(prefetch_count, last_prefetch_count); 131 last_prefetch_count = prefetch_count; 132 133 // Fill the prefetch cache as requested. 134 std::vector<IndexedDBKey> keys; 135 std::vector<IndexedDBKey> primary_keys(prefetch_count); 136 std::vector<WebData> values(prefetch_count); 137 for (int i = 0; i < prefetch_count; ++i) { 138 keys.push_back(IndexedDBKey(expected_key + i, WebIDBKeyTypeNumber)); 139 } 140 cursor.SetPrefetchData(keys, primary_keys, values); 141 142 // Note that the real dispatcher would call cursor->CachedContinue() 143 // immediately after cursor->SetPrefetchData() to service the request 144 // that initiated the prefetch. 145 146 // Verify that the cache is used for subsequent continue() calls. 147 for (int i = 0; i < prefetch_count; ++i) { 148 IndexedDBKey key; 149 cursor.continueFunction(null_key, new MockContinueCallbacks(&key)); 150 EXPECT_EQ(continue_calls, dispatcher.continue_calls()); 151 EXPECT_EQ(repetitions + 1, dispatcher.prefetch_calls()); 152 153 EXPECT_EQ(WebIDBKeyTypeNumber, key.type()); 154 EXPECT_EQ(expected_key++, key.number()); 155 } 156 } 157 } 158 159 EXPECT_EQ(dispatcher.destroyed_cursor_id(), 160 RendererWebIDBCursorImpl::kInvalidCursorId); 161 } 162 163 } // namespace content 164