Roll src/third_party/WebKit 9301d6f:4619053 (svn 201058:201059)
[chromium-blink-merge.git] / content / child / indexed_db / indexed_db_dispatcher_unittest.cc
blobc89aeded1ad372451d1ededb04d3125193f78955
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/single_thread_task_runner.h"
7 #include "base/thread_task_runner_handle.h"
8 #include "base/values.h"
9 #include "content/child/indexed_db/indexed_db_dispatcher.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 "content/common/indexed_db/indexed_db_key_range.h"
14 #include "content/common/indexed_db/indexed_db_messages.h"
15 #include "ipc/ipc_sync_message_filter.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "third_party/WebKit/public/platform/WebBlobInfo.h"
18 #include "third_party/WebKit/public/platform/WebData.h"
19 #include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBCallbacks.h"
20 #include "third_party/WebKit/public/web/WebHeap.h"
22 using blink::WebBlobInfo;
23 using blink::WebData;
24 using blink::WebIDBCallbacks;
25 using blink::WebIDBCursor;
26 using blink::WebIDBDatabase;
27 using blink::WebIDBDatabaseError;
28 using blink::WebIDBKey;
29 using blink::WebIDBValue;
30 using blink::WebVector;
32 namespace content {
33 namespace {
35 class MockCallbacks : public WebIDBCallbacks {
36 public:
37 MockCallbacks() : error_seen_(false) {}
39 virtual void onError(const WebIDBDatabaseError&) { error_seen_ = true; }
41 bool error_seen() const { return error_seen_; }
43 private:
44 bool error_seen_;
46 DISALLOW_COPY_AND_ASSIGN(MockCallbacks);
49 class MockDispatcher : public IndexedDBDispatcher {
50 public:
51 explicit MockDispatcher(ThreadSafeSender* sender)
52 : IndexedDBDispatcher(sender) {}
54 bool Send(IPC::Message* msg) override {
55 delete msg;
56 return true;
59 private:
60 DISALLOW_COPY_AND_ASSIGN(MockDispatcher);
63 class MockSyncMessageFilter : public IPC::SyncMessageFilter {
64 public:
65 MockSyncMessageFilter()
66 : SyncMessageFilter(nullptr, false /* is_channel_send_thread_safe */) {}
68 private:
69 ~MockSyncMessageFilter() override {}
72 } // namespace
74 class IndexedDBDispatcherTest : public testing::Test {
75 public:
76 IndexedDBDispatcherTest()
77 : thread_safe_sender_(new ThreadSafeSender(
78 base::ThreadTaskRunnerHandle::Get(), new MockSyncMessageFilter)) {}
80 void TearDown() override { blink::WebHeap::collectAllGarbageForTesting(); }
82 protected:
83 base::MessageLoop message_loop_;
84 scoped_refptr<ThreadSafeSender> thread_safe_sender_;
86 private:
87 DISALLOW_COPY_AND_ASSIGN(IndexedDBDispatcherTest);
90 TEST_F(IndexedDBDispatcherTest, ValueSizeTest) {
91 // For testing use a much smaller maximum size to prevent allocating >100 MB
92 // of memory, which crashes on memory-constrained systems.
93 const size_t kMaxValueSizeForTesting = 10 * 1024 * 1024; // 10 MB
95 const std::vector<char> data(kMaxValueSizeForTesting + 1);
96 const WebData value(&data.front(), data.size());
97 const WebVector<WebBlobInfo> web_blob_info;
98 const int32 ipc_dummy_id = -1;
99 const int64 transaction_id = 1;
100 const int64 object_store_id = 2;
102 MockCallbacks callbacks;
103 IndexedDBDispatcher dispatcher(thread_safe_sender_.get());
104 dispatcher.max_put_value_size_ = kMaxValueSizeForTesting;
105 IndexedDBKey key(0, blink::WebIDBKeyTypeNumber);
106 dispatcher.RequestIDBDatabasePut(ipc_dummy_id,
107 transaction_id,
108 object_store_id,
109 value,
110 web_blob_info,
111 key,
112 blink::WebIDBPutModeAddOrUpdate,
113 &callbacks,
114 WebVector<long long>(),
115 WebVector<WebVector<WebIDBKey> >());
117 EXPECT_TRUE(callbacks.error_seen());
120 TEST_F(IndexedDBDispatcherTest, KeyAndValueSizeTest) {
121 // For testing use a much smaller maximum size to prevent allocating >100 MB
122 // of memory, which crashes on memory-constrained systems.
123 const size_t kMaxValueSizeForTesting = 10 * 1024 * 1024; // 10 MB
124 const size_t kKeySize = 1024 * 1024;
126 const std::vector<char> data(kMaxValueSizeForTesting - kKeySize);
127 const WebData value(&data.front(), data.size());
128 const WebVector<WebBlobInfo> web_blob_info;
129 const IndexedDBKey key(
130 base::string16(kKeySize / sizeof(base::string16::value_type), 'x'));
132 const int32 ipc_dummy_id = -1;
133 const int64 transaction_id = 1;
134 const int64 object_store_id = 2;
136 MockCallbacks callbacks;
137 IndexedDBDispatcher dispatcher(thread_safe_sender_.get());
138 dispatcher.max_put_value_size_ = kMaxValueSizeForTesting;
139 dispatcher.RequestIDBDatabasePut(ipc_dummy_id,
140 transaction_id,
141 object_store_id,
142 value,
143 web_blob_info,
144 key,
145 blink::WebIDBPutModeAddOrUpdate,
146 &callbacks,
147 WebVector<long long>(),
148 WebVector<WebVector<WebIDBKey> >());
150 EXPECT_TRUE(callbacks.error_seen());
153 namespace {
155 class CursorCallbacks : public WebIDBCallbacks {
156 public:
157 explicit CursorCallbacks(scoped_ptr<WebIDBCursor>* cursor)
158 : cursor_(cursor) {}
160 void onSuccess(const WebIDBValue&) override {}
161 void onSuccess(WebIDBCursor* cursor,
162 const WebIDBKey& key,
163 const WebIDBKey& primaryKey,
164 const WebData& value,
165 const WebVector<WebBlobInfo>&) override {
166 cursor_->reset(cursor);
169 private:
170 scoped_ptr<WebIDBCursor>* cursor_;
172 DISALLOW_COPY_AND_ASSIGN(CursorCallbacks);
175 } // namespace
177 TEST_F(IndexedDBDispatcherTest, CursorTransactionId) {
178 const int32 ipc_database_id = -1;
179 const int64 transaction_id = 1234;
180 const int64 object_store_id = 2;
181 const int32 index_id = 3;
182 const blink::WebIDBCursorDirection direction =
183 blink::WebIDBCursorDirectionNext;
184 const bool key_only = false;
186 MockDispatcher dispatcher(thread_safe_sender_.get());
188 // First case: successful cursor open.
190 scoped_ptr<WebIDBCursor> cursor;
191 EXPECT_EQ(0UL, dispatcher.cursor_transaction_ids_.size());
193 // Make a cursor request. This should record the transaction id.
194 dispatcher.RequestIDBDatabaseOpenCursor(ipc_database_id,
195 transaction_id,
196 object_store_id,
197 index_id,
198 IndexedDBKeyRange(),
199 direction,
200 key_only,
201 blink::WebIDBTaskTypeNormal,
202 new CursorCallbacks(&cursor));
204 // Verify that the transaction id was captured.
205 EXPECT_EQ(1UL, dispatcher.cursor_transaction_ids_.size());
206 EXPECT_FALSE(cursor.get());
208 int32 ipc_callbacks_id = dispatcher.cursor_transaction_ids_.begin()->first;
210 IndexedDBMsg_CallbacksSuccessIDBCursor_Params params;
211 params.ipc_thread_id = dispatcher.CurrentWorkerId();
212 params.ipc_callbacks_id = ipc_callbacks_id;
214 // Now simululate the cursor response.
215 params.ipc_cursor_id = WebIDBCursorImpl::kInvalidCursorId;
216 dispatcher.OnSuccessOpenCursor(params);
218 EXPECT_EQ(0UL, dispatcher.cursor_transaction_ids_.size());
220 EXPECT_TRUE(cursor.get());
222 WebIDBCursorImpl* impl = static_cast<WebIDBCursorImpl*>(cursor.get());
224 // This is the primary expectation of this test: the transaction id was
225 // applied to the cursor.
226 EXPECT_EQ(transaction_id, impl->transaction_id());
229 // Second case: null cursor (no data in range)
231 scoped_ptr<WebIDBCursor> cursor;
232 EXPECT_EQ(0UL, dispatcher.cursor_transaction_ids_.size());
234 // Make a cursor request. This should record the transaction id.
235 dispatcher.RequestIDBDatabaseOpenCursor(ipc_database_id,
236 transaction_id,
237 object_store_id,
238 index_id,
239 IndexedDBKeyRange(),
240 direction,
241 key_only,
242 blink::WebIDBTaskTypeNormal,
243 new CursorCallbacks(&cursor));
245 // Verify that the transaction id was captured.
246 EXPECT_EQ(1UL, dispatcher.cursor_transaction_ids_.size());
247 EXPECT_FALSE(cursor.get());
249 int32 ipc_callbacks_id = dispatcher.cursor_transaction_ids_.begin()->first;
251 // Now simululate a "null cursor" response.
252 IndexedDBMsg_CallbacksSuccessValue_Params params;
253 params.ipc_thread_id = dispatcher.CurrentWorkerId();
254 params.ipc_callbacks_id = ipc_callbacks_id;
255 dispatcher.OnSuccessValue(params);
257 // Ensure the map result was deleted.
258 EXPECT_EQ(0UL, dispatcher.cursor_transaction_ids_.size());
259 EXPECT_FALSE(cursor.get());
263 namespace {
265 class MockCursor : public WebIDBCursorImpl {
266 public:
267 MockCursor(int32 ipc_cursor_id,
268 int64 transaction_id,
269 ThreadSafeSender* thread_safe_sender)
270 : WebIDBCursorImpl(ipc_cursor_id, transaction_id, thread_safe_sender),
271 reset_count_(0) {}
273 // This method is virtual so it can be overridden in unit tests.
274 void ResetPrefetchCache() override { ++reset_count_; }
276 int reset_count() const { return reset_count_; }
278 private:
279 int reset_count_;
281 DISALLOW_COPY_AND_ASSIGN(MockCursor);
284 } // namespace
286 TEST_F(IndexedDBDispatcherTest, CursorReset) {
287 scoped_ptr<WebIDBCursor> cursor;
288 MockDispatcher dispatcher(thread_safe_sender_.get());
290 const int32 ipc_database_id = 0;
291 const int32 object_store_id = 0;
292 const int32 index_id = 0;
293 const bool key_only = false;
294 const int cursor1_ipc_id = 1;
295 const int cursor2_ipc_id = 2;
296 const int other_cursor_ipc_id = 2;
297 const int cursor1_transaction_id = 1;
298 const int cursor2_transaction_id = 2;
299 const int other_transaction_id = 3;
301 scoped_ptr<MockCursor> cursor1(
302 new MockCursor(WebIDBCursorImpl::kInvalidCursorId,
303 cursor1_transaction_id,
304 thread_safe_sender_.get()));
306 scoped_ptr<MockCursor> cursor2(
307 new MockCursor(WebIDBCursorImpl::kInvalidCursorId,
308 cursor2_transaction_id,
309 thread_safe_sender_.get()));
311 dispatcher.cursors_[cursor1_ipc_id] = cursor1.get();
312 dispatcher.cursors_[cursor2_ipc_id] = cursor2.get();
314 EXPECT_EQ(0, cursor1->reset_count());
315 EXPECT_EQ(0, cursor2->reset_count());
317 // Other transaction:
318 dispatcher.RequestIDBDatabaseGet(ipc_database_id,
319 other_transaction_id,
320 object_store_id,
321 index_id,
322 IndexedDBKeyRange(),
323 key_only,
324 new MockCallbacks());
326 EXPECT_EQ(0, cursor1->reset_count());
327 EXPECT_EQ(0, cursor2->reset_count());
329 // Same transaction:
330 dispatcher.RequestIDBDatabaseGet(ipc_database_id,
331 cursor1_transaction_id,
332 object_store_id,
333 index_id,
334 IndexedDBKeyRange(),
335 key_only,
336 new MockCallbacks());
338 EXPECT_EQ(1, cursor1->reset_count());
339 EXPECT_EQ(0, cursor2->reset_count());
341 // Same transaction and same cursor:
342 dispatcher.RequestIDBCursorContinue(IndexedDBKey(),
343 IndexedDBKey(),
344 new MockCallbacks(),
345 cursor1_ipc_id,
346 cursor1_transaction_id);
348 EXPECT_EQ(1, cursor1->reset_count());
349 EXPECT_EQ(0, cursor2->reset_count());
351 // Same transaction and different cursor:
352 dispatcher.RequestIDBCursorContinue(IndexedDBKey(),
353 IndexedDBKey(),
354 new MockCallbacks(),
355 other_cursor_ipc_id,
356 cursor1_transaction_id);
358 EXPECT_EQ(2, cursor1->reset_count());
359 EXPECT_EQ(0, cursor2->reset_count());
361 cursor1.reset();
362 cursor2.reset();
365 } // namespace content