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/message_loop/message_loop_proxy.h"
7 #include "base/values.h"
8 #include "content/child/indexed_db/indexed_db_dispatcher.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 "content/common/indexed_db/indexed_db_key_range.h"
13 #include "content/common/indexed_db/indexed_db_messages.h"
14 #include "ipc/ipc_sync_message_filter.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "third_party/WebKit/public/platform/WebData.h"
17 #include "third_party/WebKit/public/platform/WebIDBCallbacks.h"
20 using blink::WebIDBCallbacks;
21 using blink::WebIDBCursor;
22 using blink::WebIDBDatabase;
23 using blink::WebIDBDatabaseError;
24 using blink::WebIDBKey;
25 using blink::WebVector;
30 class MockCallbacks : public WebIDBCallbacks {
32 MockCallbacks() : error_seen_(false) {}
34 virtual void onError(const WebIDBDatabaseError&) { error_seen_ = true; }
36 bool error_seen() const { return error_seen_; }
42 class MockDispatcher : public IndexedDBDispatcher {
44 MockDispatcher(ThreadSafeSender* sender) : IndexedDBDispatcher(sender) {}
46 virtual bool Send(IPC::Message* msg) OVERRIDE {
54 class IndexedDBDispatcherTest : public testing::Test {
56 IndexedDBDispatcherTest()
57 : message_loop_proxy_(base::MessageLoopProxy::current()),
58 sync_message_filter_(new IPC::SyncMessageFilter(NULL)),
59 thread_safe_sender_(new ThreadSafeSender(message_loop_proxy_.get(),
60 sync_message_filter_.get())) {}
63 scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
64 scoped_refptr<IPC::SyncMessageFilter> sync_message_filter_;
65 scoped_refptr<ThreadSafeSender> thread_safe_sender_;
68 DISALLOW_COPY_AND_ASSIGN(IndexedDBDispatcherTest);
71 TEST_F(IndexedDBDispatcherTest, ValueSizeTest) {
72 const std::vector<char> data(kMaxIDBValueSizeInBytes + 1);
73 const WebData value(&data.front(), data.size());
74 const int32 ipc_dummy_id = -1;
75 const int64 transaction_id = 1;
76 const int64 object_store_id = 2;
78 MockCallbacks callbacks;
79 IndexedDBDispatcher dispatcher(thread_safe_sender_.get());
80 IndexedDBKey key(0, blink::WebIDBKeyTypeNumber);
81 dispatcher.RequestIDBDatabasePut(ipc_dummy_id,
86 WebIDBDatabase::AddOrUpdate,
88 WebVector<long long>(),
89 WebVector<WebVector<WebIDBKey> >());
91 EXPECT_TRUE(callbacks.error_seen());
96 class CursorCallbacks : public WebIDBCallbacks {
98 CursorCallbacks(scoped_ptr<WebIDBCursor>* cursor) : cursor_(cursor) {}
100 virtual void onSuccess(const WebData&) {}
101 virtual void onSuccess(WebIDBCursor* cursor,
102 const WebIDBKey& key,
103 const WebIDBKey& primaryKey,
104 const WebData& value) {
105 cursor_->reset(cursor);
109 scoped_ptr<WebIDBCursor>* cursor_;
114 TEST_F(IndexedDBDispatcherTest, CursorTransactionId) {
115 const int32 ipc_database_id = -1;
116 const int64 transaction_id = 1234;
117 const int64 object_store_id = 2;
118 const int32 index_id = 3;
119 const WebIDBCursor::Direction direction = WebIDBCursor::Next;
120 const bool key_only = false;
122 MockDispatcher dispatcher(thread_safe_sender_.get());
124 // First case: successful cursor open.
126 scoped_ptr<WebIDBCursor> cursor;
127 EXPECT_EQ(0UL, dispatcher.cursor_transaction_ids_.size());
129 // Make a cursor request. This should record the transaction id.
130 dispatcher.RequestIDBDatabaseOpenCursor(ipc_database_id,
137 blink::WebIDBDatabase::NormalTask,
138 new CursorCallbacks(&cursor));
140 // Verify that the transaction id was captured.
141 EXPECT_EQ(1UL, dispatcher.cursor_transaction_ids_.size());
142 EXPECT_FALSE(cursor.get());
144 int32 ipc_callbacks_id = dispatcher.cursor_transaction_ids_.begin()->first;
146 IndexedDBMsg_CallbacksSuccessIDBCursor_Params params;
147 params.ipc_thread_id = dispatcher.CurrentWorkerId();
148 params.ipc_callbacks_id = ipc_callbacks_id;
150 // Now simululate the cursor response.
151 params.ipc_cursor_id = WebIDBCursorImpl::kInvalidCursorId;
152 dispatcher.OnSuccessOpenCursor(params);
154 EXPECT_EQ(0UL, dispatcher.cursor_transaction_ids_.size());
156 EXPECT_TRUE(cursor.get());
158 WebIDBCursorImpl* impl = static_cast<WebIDBCursorImpl*>(cursor.get());
160 // This is the primary expectation of this test: the transaction id was
161 // applied to the cursor.
162 EXPECT_EQ(transaction_id, impl->transaction_id());
165 // Second case: null cursor (no data in range)
167 scoped_ptr<WebIDBCursor> cursor;
168 EXPECT_EQ(0UL, dispatcher.cursor_transaction_ids_.size());
170 // Make a cursor request. This should record the transaction id.
171 dispatcher.RequestIDBDatabaseOpenCursor(ipc_database_id,
178 blink::WebIDBDatabase::NormalTask,
179 new CursorCallbacks(&cursor));
181 // Verify that the transaction id was captured.
182 EXPECT_EQ(1UL, dispatcher.cursor_transaction_ids_.size());
183 EXPECT_FALSE(cursor.get());
185 int32 ipc_callbacks_id = dispatcher.cursor_transaction_ids_.begin()->first;
187 // Now simululate a "null cursor" response.
188 dispatcher.OnSuccessValue(
189 dispatcher.CurrentWorkerId(), ipc_callbacks_id, std::string());
191 // Ensure the map result was deleted.
192 EXPECT_EQ(0UL, dispatcher.cursor_transaction_ids_.size());
193 EXPECT_FALSE(cursor.get());
199 class MockCursor : public WebIDBCursorImpl {
201 MockCursor(int32 ipc_cursor_id,
202 int64 transaction_id,
203 ThreadSafeSender* thread_safe_sender)
204 : WebIDBCursorImpl(ipc_cursor_id, transaction_id, thread_safe_sender),
207 // This method is virtual so it can be overridden in unit tests.
208 virtual void ResetPrefetchCache() OVERRIDE { ++reset_count_; }
210 int reset_count() const { return reset_count_; }
218 TEST_F(IndexedDBDispatcherTest, CursorReset) {
219 scoped_ptr<WebIDBCursor> cursor;
220 MockDispatcher dispatcher(thread_safe_sender_.get());
222 const int32 ipc_database_id = 0;
223 const int32 object_store_id = 0;
224 const int32 index_id = 0;
225 const bool key_only = false;
226 const int cursor1_ipc_id = 1;
227 const int cursor2_ipc_id = 2;
228 const int other_cursor_ipc_id = 2;
229 const int cursor1_transaction_id = 1;
230 const int cursor2_transaction_id = 2;
231 const int other_transaction_id = 3;
233 scoped_ptr<MockCursor> cursor1(
234 new MockCursor(WebIDBCursorImpl::kInvalidCursorId,
235 cursor1_transaction_id,
236 thread_safe_sender_.get()));
238 scoped_ptr<MockCursor> cursor2(
239 new MockCursor(WebIDBCursorImpl::kInvalidCursorId,
240 cursor2_transaction_id,
241 thread_safe_sender_.get()));
243 dispatcher.cursors_[cursor1_ipc_id] = cursor1.get();
244 dispatcher.cursors_[cursor2_ipc_id] = cursor2.get();
246 EXPECT_EQ(0, cursor1->reset_count());
247 EXPECT_EQ(0, cursor2->reset_count());
249 // Other transaction:
250 dispatcher.RequestIDBDatabaseGet(ipc_database_id,
251 other_transaction_id,
256 new MockCallbacks());
258 EXPECT_EQ(0, cursor1->reset_count());
259 EXPECT_EQ(0, cursor2->reset_count());
262 dispatcher.RequestIDBDatabaseGet(ipc_database_id,
263 cursor1_transaction_id,
268 new MockCallbacks());
270 EXPECT_EQ(1, cursor1->reset_count());
271 EXPECT_EQ(0, cursor2->reset_count());
273 // Same transaction and same cursor:
274 dispatcher.RequestIDBCursorContinue(IndexedDBKey(),
278 cursor1_transaction_id);
280 EXPECT_EQ(1, cursor1->reset_count());
281 EXPECT_EQ(0, cursor2->reset_count());
283 // Same transaction and different cursor:
284 dispatcher.RequestIDBCursorContinue(IndexedDBKey(),
288 cursor1_transaction_id);
290 EXPECT_EQ(2, cursor1->reset_count());
291 EXPECT_EQ(0, cursor2->reset_count());
297 } // namespace content