• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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/WebBlobInfo.h"
17 #include "third_party/WebKit/public/platform/WebData.h"
18 #include "third_party/WebKit/public/platform/WebIDBCallbacks.h"
19 
20 using blink::WebBlobInfo;
21 using blink::WebData;
22 using blink::WebIDBCallbacks;
23 using blink::WebIDBCursor;
24 using blink::WebIDBDatabase;
25 using blink::WebIDBDatabaseError;
26 using blink::WebIDBKey;
27 using blink::WebVector;
28 
29 namespace content {
30 namespace {
31 
32 class MockCallbacks : public WebIDBCallbacks {
33  public:
MockCallbacks()34   MockCallbacks() : error_seen_(false) {}
35 
onError(const WebIDBDatabaseError &)36   virtual void onError(const WebIDBDatabaseError&) { error_seen_ = true; }
37 
error_seen() const38   bool error_seen() const { return error_seen_; }
39 
40  private:
41   bool error_seen_;
42 
43   DISALLOW_COPY_AND_ASSIGN(MockCallbacks);
44 };
45 
46 class MockDispatcher : public IndexedDBDispatcher {
47  public:
MockDispatcher(ThreadSafeSender * sender)48   explicit MockDispatcher(ThreadSafeSender* sender)
49       : IndexedDBDispatcher(sender) {}
50 
Send(IPC::Message * msg)51   virtual bool Send(IPC::Message* msg) OVERRIDE {
52     delete msg;
53     return true;
54   }
55 
56  private:
57   DISALLOW_COPY_AND_ASSIGN(MockDispatcher);
58 };
59 
60 }  // namespace
61 
62 class IndexedDBDispatcherTest : public testing::Test {
63  public:
IndexedDBDispatcherTest()64   IndexedDBDispatcherTest()
65       : message_loop_proxy_(base::MessageLoopProxy::current()),
66         sync_message_filter_(new IPC::SyncMessageFilter(NULL)),
67         thread_safe_sender_(new ThreadSafeSender(message_loop_proxy_.get(),
68                                                  sync_message_filter_.get())) {}
69 
70  protected:
71   scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
72   scoped_refptr<IPC::SyncMessageFilter> sync_message_filter_;
73   scoped_refptr<ThreadSafeSender> thread_safe_sender_;
74 
75  private:
76   DISALLOW_COPY_AND_ASSIGN(IndexedDBDispatcherTest);
77 };
78 
TEST_F(IndexedDBDispatcherTest,ValueSizeTest)79 TEST_F(IndexedDBDispatcherTest, ValueSizeTest) {
80   const std::vector<char> data(kMaxIDBValueSizeInBytes + 1);
81   const WebData value(&data.front(), data.size());
82   const WebVector<WebBlobInfo> web_blob_info;
83   const int32 ipc_dummy_id = -1;
84   const int64 transaction_id = 1;
85   const int64 object_store_id = 2;
86 
87   MockCallbacks callbacks;
88   IndexedDBDispatcher dispatcher(thread_safe_sender_.get());
89   IndexedDBKey key(0, blink::WebIDBKeyTypeNumber);
90   dispatcher.RequestIDBDatabasePut(ipc_dummy_id,
91                                    transaction_id,
92                                    object_store_id,
93                                    value,
94                                    web_blob_info,
95                                    key,
96                                    WebIDBDatabase::AddOrUpdate,
97                                    &callbacks,
98                                    WebVector<long long>(),
99                                    WebVector<WebVector<WebIDBKey> >());
100 
101   EXPECT_TRUE(callbacks.error_seen());
102 }
103 
TEST_F(IndexedDBDispatcherTest,KeyAndValueSizeTest)104 TEST_F(IndexedDBDispatcherTest, KeyAndValueSizeTest) {
105   const size_t kKeySize = 1024 * 1024;
106 
107   const std::vector<char> data(kMaxIDBValueSizeInBytes - kKeySize);
108   const WebData value(&data.front(), data.size());
109   const WebVector<WebBlobInfo> web_blob_info;
110   const IndexedDBKey key(
111       base::string16(kKeySize / sizeof(base::string16::value_type), 'x'));
112 
113   const int32 ipc_dummy_id = -1;
114   const int64 transaction_id = 1;
115   const int64 object_store_id = 2;
116 
117   MockCallbacks callbacks;
118   IndexedDBDispatcher dispatcher(thread_safe_sender_.get());
119   dispatcher.RequestIDBDatabasePut(ipc_dummy_id,
120                                    transaction_id,
121                                    object_store_id,
122                                    value,
123                                    web_blob_info,
124                                    key,
125                                    WebIDBDatabase::AddOrUpdate,
126                                    &callbacks,
127                                    WebVector<long long>(),
128                                    WebVector<WebVector<WebIDBKey> >());
129 
130   EXPECT_TRUE(callbacks.error_seen());
131 }
132 
133 namespace {
134 
135 class CursorCallbacks : public WebIDBCallbacks {
136  public:
CursorCallbacks(scoped_ptr<WebIDBCursor> * cursor)137   explicit CursorCallbacks(scoped_ptr<WebIDBCursor>* cursor)
138       : cursor_(cursor) {}
139 
onSuccess(const WebData &,const WebVector<WebBlobInfo> &)140   virtual void onSuccess(const WebData&,
141                          const WebVector<WebBlobInfo>&) OVERRIDE {}
onSuccess(WebIDBCursor * cursor,const WebIDBKey & key,const WebIDBKey & primaryKey,const WebData & value,const WebVector<WebBlobInfo> &)142   virtual void onSuccess(WebIDBCursor* cursor,
143                          const WebIDBKey& key,
144                          const WebIDBKey& primaryKey,
145                          const WebData& value,
146                          const WebVector<WebBlobInfo>&) OVERRIDE {
147     cursor_->reset(cursor);
148   }
149 
150  private:
151   scoped_ptr<WebIDBCursor>* cursor_;
152 
153   DISALLOW_COPY_AND_ASSIGN(CursorCallbacks);
154 };
155 
156 }  // namespace
157 
TEST_F(IndexedDBDispatcherTest,CursorTransactionId)158 TEST_F(IndexedDBDispatcherTest, CursorTransactionId) {
159   const int32 ipc_database_id = -1;
160   const int64 transaction_id = 1234;
161   const int64 object_store_id = 2;
162   const int32 index_id = 3;
163   const WebIDBCursor::Direction direction = WebIDBCursor::Next;
164   const bool key_only = false;
165 
166   MockDispatcher dispatcher(thread_safe_sender_.get());
167 
168   // First case: successful cursor open.
169   {
170     scoped_ptr<WebIDBCursor> cursor;
171     EXPECT_EQ(0UL, dispatcher.cursor_transaction_ids_.size());
172 
173     // Make a cursor request. This should record the transaction id.
174     dispatcher.RequestIDBDatabaseOpenCursor(ipc_database_id,
175                                             transaction_id,
176                                             object_store_id,
177                                             index_id,
178                                             IndexedDBKeyRange(),
179                                             direction,
180                                             key_only,
181                                             blink::WebIDBDatabase::NormalTask,
182                                             new CursorCallbacks(&cursor));
183 
184     // Verify that the transaction id was captured.
185     EXPECT_EQ(1UL, dispatcher.cursor_transaction_ids_.size());
186     EXPECT_FALSE(cursor.get());
187 
188     int32 ipc_callbacks_id = dispatcher.cursor_transaction_ids_.begin()->first;
189 
190     IndexedDBMsg_CallbacksSuccessIDBCursor_Params params;
191     params.ipc_thread_id = dispatcher.CurrentWorkerId();
192     params.ipc_callbacks_id = ipc_callbacks_id;
193 
194     // Now simululate the cursor response.
195     params.ipc_cursor_id = WebIDBCursorImpl::kInvalidCursorId;
196     dispatcher.OnSuccessOpenCursor(params);
197 
198     EXPECT_EQ(0UL, dispatcher.cursor_transaction_ids_.size());
199 
200     EXPECT_TRUE(cursor.get());
201 
202     WebIDBCursorImpl* impl = static_cast<WebIDBCursorImpl*>(cursor.get());
203 
204     // This is the primary expectation of this test: the transaction id was
205     // applied to the cursor.
206     EXPECT_EQ(transaction_id, impl->transaction_id());
207   }
208 
209   // Second case: null cursor (no data in range)
210   {
211     scoped_ptr<WebIDBCursor> cursor;
212     EXPECT_EQ(0UL, dispatcher.cursor_transaction_ids_.size());
213 
214     // Make a cursor request. This should record the transaction id.
215     dispatcher.RequestIDBDatabaseOpenCursor(ipc_database_id,
216                                             transaction_id,
217                                             object_store_id,
218                                             index_id,
219                                             IndexedDBKeyRange(),
220                                             direction,
221                                             key_only,
222                                             blink::WebIDBDatabase::NormalTask,
223                                             new CursorCallbacks(&cursor));
224 
225     // Verify that the transaction id was captured.
226     EXPECT_EQ(1UL, dispatcher.cursor_transaction_ids_.size());
227     EXPECT_FALSE(cursor.get());
228 
229     int32 ipc_callbacks_id = dispatcher.cursor_transaction_ids_.begin()->first;
230 
231     // Now simululate a "null cursor" response.
232     IndexedDBMsg_CallbacksSuccessValue_Params params;
233     params.ipc_thread_id = dispatcher.CurrentWorkerId();
234     params.ipc_callbacks_id = ipc_callbacks_id;
235     dispatcher.OnSuccessValue(params);
236 
237     // Ensure the map result was deleted.
238     EXPECT_EQ(0UL, dispatcher.cursor_transaction_ids_.size());
239     EXPECT_FALSE(cursor.get());
240   }
241 }
242 
243 namespace {
244 
245 class MockCursor : public WebIDBCursorImpl {
246  public:
MockCursor(int32 ipc_cursor_id,int64 transaction_id,ThreadSafeSender * thread_safe_sender)247   MockCursor(int32 ipc_cursor_id,
248              int64 transaction_id,
249              ThreadSafeSender* thread_safe_sender)
250       : WebIDBCursorImpl(ipc_cursor_id, transaction_id, thread_safe_sender),
251         reset_count_(0) {}
252 
253   // This method is virtual so it can be overridden in unit tests.
ResetPrefetchCache()254   virtual void ResetPrefetchCache() OVERRIDE { ++reset_count_; }
255 
reset_count() const256   int reset_count() const { return reset_count_; }
257 
258  private:
259   int reset_count_;
260 
261   DISALLOW_COPY_AND_ASSIGN(MockCursor);
262 };
263 
264 }  // namespace
265 
TEST_F(IndexedDBDispatcherTest,CursorReset)266 TEST_F(IndexedDBDispatcherTest, CursorReset) {
267   scoped_ptr<WebIDBCursor> cursor;
268   MockDispatcher dispatcher(thread_safe_sender_.get());
269 
270   const int32 ipc_database_id = 0;
271   const int32 object_store_id = 0;
272   const int32 index_id = 0;
273   const bool key_only = false;
274   const int cursor1_ipc_id = 1;
275   const int cursor2_ipc_id = 2;
276   const int other_cursor_ipc_id = 2;
277   const int cursor1_transaction_id = 1;
278   const int cursor2_transaction_id = 2;
279   const int other_transaction_id = 3;
280 
281   scoped_ptr<MockCursor> cursor1(
282       new MockCursor(WebIDBCursorImpl::kInvalidCursorId,
283                      cursor1_transaction_id,
284                      thread_safe_sender_.get()));
285 
286   scoped_ptr<MockCursor> cursor2(
287       new MockCursor(WebIDBCursorImpl::kInvalidCursorId,
288                      cursor2_transaction_id,
289                      thread_safe_sender_.get()));
290 
291   dispatcher.cursors_[cursor1_ipc_id] = cursor1.get();
292   dispatcher.cursors_[cursor2_ipc_id] = cursor2.get();
293 
294   EXPECT_EQ(0, cursor1->reset_count());
295   EXPECT_EQ(0, cursor2->reset_count());
296 
297   // Other transaction:
298   dispatcher.RequestIDBDatabaseGet(ipc_database_id,
299                                    other_transaction_id,
300                                    object_store_id,
301                                    index_id,
302                                    IndexedDBKeyRange(),
303                                    key_only,
304                                    new MockCallbacks());
305 
306   EXPECT_EQ(0, cursor1->reset_count());
307   EXPECT_EQ(0, cursor2->reset_count());
308 
309   // Same transaction:
310   dispatcher.RequestIDBDatabaseGet(ipc_database_id,
311                                    cursor1_transaction_id,
312                                    object_store_id,
313                                    index_id,
314                                    IndexedDBKeyRange(),
315                                    key_only,
316                                    new MockCallbacks());
317 
318   EXPECT_EQ(1, cursor1->reset_count());
319   EXPECT_EQ(0, cursor2->reset_count());
320 
321   // Same transaction and same cursor:
322   dispatcher.RequestIDBCursorContinue(IndexedDBKey(),
323                                       IndexedDBKey(),
324                                       new MockCallbacks(),
325                                       cursor1_ipc_id,
326                                       cursor1_transaction_id);
327 
328   EXPECT_EQ(1, cursor1->reset_count());
329   EXPECT_EQ(0, cursor2->reset_count());
330 
331   // Same transaction and different cursor:
332   dispatcher.RequestIDBCursorContinue(IndexedDBKey(),
333                                       IndexedDBKey(),
334                                       new MockCallbacks(),
335                                       other_cursor_ipc_id,
336                                       cursor1_transaction_id);
337 
338   EXPECT_EQ(2, cursor1->reset_count());
339   EXPECT_EQ(0, cursor2->reset_count());
340 
341   cursor1.reset();
342   cursor2.reset();
343 }
344 
345 }  // namespace content
346