Home | History | Annotate | Download | only in indexed_db
      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/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 blink::WebBlobInfo;
     18 using blink::WebData;
     19 using blink::WebIDBCallbacks;
     20 using blink::WebIDBDatabase;
     21 using blink::WebIDBKey;
     22 using blink::WebIDBKeyTypeNumber;
     23 using blink::WebVector;
     24 
     25 namespace content {
     26 
     27 namespace {
     28 
     29 class MockDispatcher : public IndexedDBDispatcher {
     30  public:
     31   explicit MockDispatcher(ThreadSafeSender* thread_safe_sender)
     32       : IndexedDBDispatcher(thread_safe_sender),
     33         prefetch_calls_(0),
     34         last_prefetch_count_(0),
     35         reset_calls_(0),
     36         last_used_count_(0),
     37         advance_calls_(0),
     38         continue_calls_(0),
     39         destroyed_cursor_id_(0) {}
     40 
     41   virtual void RequestIDBCursorPrefetch(int n,
     42                                         WebIDBCallbacks* callbacks,
     43                                         int32 ipc_cursor_id) OVERRIDE {
     44     ++prefetch_calls_;
     45     last_prefetch_count_ = n;
     46     callbacks_.reset(callbacks);
     47   }
     48 
     49   virtual void RequestIDBCursorPrefetchReset(int used_prefetches,
     50                                              int unused_prefetches,
     51                                              int32 ipc_cursor_id) OVERRIDE {
     52     ++reset_calls_;
     53     last_used_count_ = used_prefetches;
     54   }
     55 
     56   virtual void RequestIDBCursorAdvance(unsigned long count,
     57                                        WebIDBCallbacks* callbacks,
     58                                        int32 ipc_cursor_id,
     59                                        int64 transaction_id) OVERRIDE {
     60     ++advance_calls_;
     61     callbacks_.reset(callbacks);
     62   }
     63 
     64   virtual void RequestIDBCursorContinue(const IndexedDBKey& key,
     65                                         const IndexedDBKey& primary_key,
     66                                         WebIDBCallbacks* callbacks,
     67                                         int32 ipc_cursor_id,
     68                                         int64 transaction_id) OVERRIDE {
     69     ++continue_calls_;
     70     callbacks_.reset(callbacks);
     71   }
     72 
     73   virtual void CursorDestroyed(int32 ipc_cursor_id) OVERRIDE {
     74     destroyed_cursor_id_ = ipc_cursor_id;
     75   }
     76 
     77   int prefetch_calls() { return prefetch_calls_; }
     78   int last_prefetch_count() { return last_prefetch_count_; }
     79   int reset_calls() { return reset_calls_; }
     80   int last_used_count() { return last_used_count_; }
     81   int advance_calls() { return advance_calls_; }
     82   int continue_calls() { return continue_calls_; }
     83   int32 destroyed_cursor_id() { return destroyed_cursor_id_; }
     84 
     85  private:
     86   int prefetch_calls_;
     87   int last_prefetch_count_;
     88   int reset_calls_;
     89   int last_used_count_;
     90   int advance_calls_;
     91   int continue_calls_;
     92   int32 destroyed_cursor_id_;
     93   scoped_ptr<WebIDBCallbacks> callbacks_;
     94 };
     95 
     96 class MockContinueCallbacks : public WebIDBCallbacks {
     97  public:
     98   MockContinueCallbacks(IndexedDBKey* key = 0,
     99                         WebVector<WebBlobInfo>* webBlobInfo = 0)
    100       : key_(key), webBlobInfo_(webBlobInfo) {}
    101 
    102   virtual void onSuccess(const WebIDBKey& key,
    103                          const WebIDBKey& primaryKey,
    104                          const WebData& value,
    105                          const WebVector<WebBlobInfo>& webBlobInfo) OVERRIDE {
    106     if (key_)
    107       *key_ = IndexedDBKeyBuilder::Build(key);
    108     if (webBlobInfo_)
    109       *webBlobInfo_ = webBlobInfo;
    110   }
    111 
    112  private:
    113   IndexedDBKey* key_;
    114   WebVector<WebBlobInfo>* webBlobInfo_;
    115 };
    116 
    117 }  // namespace
    118 
    119 class WebIDBCursorImplTest : public testing::Test {
    120  public:
    121   WebIDBCursorImplTest() {
    122     null_key_.assignNull();
    123     sync_message_filter_ = new IPC::SyncMessageFilter(NULL);
    124     thread_safe_sender_ = new ThreadSafeSender(
    125         base::MessageLoopProxy::current(), sync_message_filter_.get());
    126     dispatcher_ =
    127         make_scoped_ptr(new MockDispatcher(thread_safe_sender_.get()));
    128   }
    129 
    130  protected:
    131   WebIDBKey null_key_;
    132   scoped_refptr<ThreadSafeSender> thread_safe_sender_;
    133   scoped_ptr<MockDispatcher> dispatcher_;
    134 
    135  private:
    136   scoped_refptr<IPC::SyncMessageFilter> sync_message_filter_;
    137 
    138   DISALLOW_COPY_AND_ASSIGN(WebIDBCursorImplTest);
    139 };
    140 
    141 TEST_F(WebIDBCursorImplTest, PrefetchTest) {
    142   const int64 transaction_id = 1;
    143   {
    144     WebIDBCursorImpl cursor(WebIDBCursorImpl::kInvalidCursorId,
    145                             transaction_id,
    146                             thread_safe_sender_.get());
    147 
    148     // Call continue() until prefetching should kick in.
    149     int continue_calls = 0;
    150     EXPECT_EQ(dispatcher_->continue_calls(), 0);
    151     for (int i = 0; i < WebIDBCursorImpl::kPrefetchContinueThreshold; ++i) {
    152       cursor.continueFunction(null_key_, new MockContinueCallbacks());
    153       EXPECT_EQ(++continue_calls, dispatcher_->continue_calls());
    154       EXPECT_EQ(0, dispatcher_->prefetch_calls());
    155     }
    156 
    157     // Do enough repetitions to verify that the count grows each time,
    158     // but not so many that the maximum limit is hit.
    159     const int kPrefetchRepetitions = 5;
    160 
    161     int expected_key = 0;
    162     int last_prefetch_count = 0;
    163     for (int repetitions = 0; repetitions < kPrefetchRepetitions;
    164          ++repetitions) {
    165       // Initiate the prefetch
    166       cursor.continueFunction(null_key_, new MockContinueCallbacks());
    167       EXPECT_EQ(continue_calls, dispatcher_->continue_calls());
    168       EXPECT_EQ(repetitions + 1, dispatcher_->prefetch_calls());
    169 
    170       // Verify that the requested count has increased since last time.
    171       int prefetch_count = dispatcher_->last_prefetch_count();
    172       EXPECT_GT(prefetch_count, last_prefetch_count);
    173       last_prefetch_count = prefetch_count;
    174 
    175       // Fill the prefetch cache as requested.
    176       std::vector<IndexedDBKey> keys;
    177       std::vector<IndexedDBKey> primary_keys(prefetch_count);
    178       std::vector<WebData> values(prefetch_count);
    179       std::vector<WebVector<WebBlobInfo> > blob_info;
    180       for (int i = 0; i < prefetch_count; ++i) {
    181         keys.push_back(IndexedDBKey(expected_key + i, WebIDBKeyTypeNumber));
    182         blob_info.push_back(
    183             WebVector<WebBlobInfo>(static_cast<size_t>(expected_key + i)));
    184       }
    185       cursor.SetPrefetchData(keys, primary_keys, values, blob_info);
    186 
    187       // Note that the real dispatcher would call cursor->CachedContinue()
    188       // immediately after cursor->SetPrefetchData() to service the request
    189       // that initiated the prefetch.
    190 
    191       // Verify that the cache is used for subsequent continue() calls.
    192       for (int i = 0; i < prefetch_count; ++i) {
    193         IndexedDBKey key;
    194         WebVector<WebBlobInfo> web_blob_info;
    195         cursor.continueFunction(
    196             null_key_, new MockContinueCallbacks(&key, &web_blob_info));
    197         EXPECT_EQ(continue_calls, dispatcher_->continue_calls());
    198         EXPECT_EQ(repetitions + 1, dispatcher_->prefetch_calls());
    199 
    200         EXPECT_EQ(WebIDBKeyTypeNumber, key.type());
    201         EXPECT_EQ(expected_key, static_cast<int>(web_blob_info.size()));
    202         EXPECT_EQ(expected_key++, key.number());
    203       }
    204     }
    205   }
    206 
    207   EXPECT_EQ(dispatcher_->destroyed_cursor_id(),
    208             WebIDBCursorImpl::kInvalidCursorId);
    209 }
    210 
    211 TEST_F(WebIDBCursorImplTest, AdvancePrefetchTest) {
    212   const int64 transaction_id = 1;
    213   WebIDBCursorImpl cursor(WebIDBCursorImpl::kInvalidCursorId,
    214                           transaction_id,
    215                           thread_safe_sender_.get());
    216 
    217   // Call continue() until prefetching should kick in.
    218   EXPECT_EQ(0, dispatcher_->continue_calls());
    219   for (int i = 0; i < WebIDBCursorImpl::kPrefetchContinueThreshold; ++i) {
    220     cursor.continueFunction(null_key_, new MockContinueCallbacks());
    221   }
    222   EXPECT_EQ(0, dispatcher_->prefetch_calls());
    223 
    224   // Initiate the prefetch
    225   cursor.continueFunction(null_key_, new MockContinueCallbacks());
    226 
    227   EXPECT_EQ(1, dispatcher_->prefetch_calls());
    228   EXPECT_EQ(static_cast<int>(WebIDBCursorImpl::kPrefetchContinueThreshold),
    229             dispatcher_->continue_calls());
    230   EXPECT_EQ(0, dispatcher_->advance_calls());
    231 
    232   const int prefetch_count = dispatcher_->last_prefetch_count();
    233 
    234   // Fill the prefetch cache as requested.
    235   int expected_key = 0;
    236   std::vector<IndexedDBKey> keys;
    237   std::vector<IndexedDBKey> primary_keys(prefetch_count);
    238   std::vector<WebData> values(prefetch_count);
    239   std::vector<WebVector<WebBlobInfo> > blob_info;
    240   for (int i = 0; i < prefetch_count; ++i) {
    241     keys.push_back(IndexedDBKey(expected_key + i, WebIDBKeyTypeNumber));
    242     blob_info.push_back(
    243         WebVector<WebBlobInfo>(static_cast<size_t>(expected_key + i)));
    244   }
    245   cursor.SetPrefetchData(keys, primary_keys, values, blob_info);
    246 
    247   // Note that the real dispatcher would call cursor->CachedContinue()
    248   // immediately after cursor->SetPrefetchData() to service the request
    249   // that initiated the prefetch.
    250 
    251   // Need at least this many in the cache for the test steps.
    252   ASSERT_GE(prefetch_count, 5);
    253 
    254   // IDBCursor.continue()
    255   IndexedDBKey key;
    256   cursor.continueFunction(null_key_, new MockContinueCallbacks(&key));
    257   EXPECT_EQ(0, key.number());
    258 
    259   // IDBCursor.advance(1)
    260   cursor.advance(1, new MockContinueCallbacks(&key));
    261   EXPECT_EQ(1, key.number());
    262 
    263   // IDBCursor.continue()
    264   cursor.continueFunction(null_key_, new MockContinueCallbacks(&key));
    265   EXPECT_EQ(2, key.number());
    266 
    267   // IDBCursor.advance(2)
    268   cursor.advance(2, new MockContinueCallbacks(&key));
    269   EXPECT_EQ(4, key.number());
    270 
    271   EXPECT_EQ(0, dispatcher_->advance_calls());
    272 
    273   // IDBCursor.advance(lots) - beyond the fetched amount
    274   cursor.advance(WebIDBCursorImpl::kMaxPrefetchAmount,
    275                  new MockContinueCallbacks(&key));
    276   EXPECT_EQ(1, dispatcher_->advance_calls());
    277   EXPECT_EQ(1, dispatcher_->prefetch_calls());
    278   EXPECT_EQ(static_cast<int>(WebIDBCursorImpl::kPrefetchContinueThreshold),
    279             dispatcher_->continue_calls());
    280 }
    281 
    282 TEST_F(WebIDBCursorImplTest, PrefetchReset) {
    283   const int64 transaction_id = 1;
    284   WebIDBCursorImpl cursor(WebIDBCursorImpl::kInvalidCursorId,
    285                           transaction_id,
    286                           thread_safe_sender_.get());
    287 
    288   // Call continue() until prefetching should kick in.
    289   int continue_calls = 0;
    290   EXPECT_EQ(dispatcher_->continue_calls(), 0);
    291   for (int i = 0; i < WebIDBCursorImpl::kPrefetchContinueThreshold; ++i) {
    292     cursor.continueFunction(null_key_, new MockContinueCallbacks());
    293     EXPECT_EQ(++continue_calls, dispatcher_->continue_calls());
    294     EXPECT_EQ(0, dispatcher_->prefetch_calls());
    295   }
    296 
    297   // Initiate the prefetch
    298   cursor.continueFunction(null_key_, new MockContinueCallbacks());
    299   EXPECT_EQ(continue_calls, dispatcher_->continue_calls());
    300   EXPECT_EQ(1, dispatcher_->prefetch_calls());
    301   EXPECT_EQ(0, dispatcher_->reset_calls());
    302 
    303   // Now invalidate it
    304   cursor.ResetPrefetchCache();
    305 
    306   // No reset should have been sent since nothing has been received yet.
    307   EXPECT_EQ(0, dispatcher_->reset_calls());
    308 
    309   // Fill the prefetch cache as requested.
    310   int prefetch_count = dispatcher_->last_prefetch_count();
    311   std::vector<IndexedDBKey> keys(prefetch_count);
    312   std::vector<IndexedDBKey> primary_keys(prefetch_count);
    313   std::vector<WebData> values(prefetch_count);
    314   std::vector<WebVector<WebBlobInfo> > blob_info(prefetch_count);
    315   cursor.SetPrefetchData(keys, primary_keys, values, blob_info);
    316 
    317   // No reset should have been sent since prefetch data hasn't been used.
    318   EXPECT_EQ(0, dispatcher_->reset_calls());
    319 
    320   // The real dispatcher would call cursor->CachedContinue(), so do that:
    321   scoped_ptr<WebIDBCallbacks> callbacks(new MockContinueCallbacks());
    322   cursor.CachedContinue(callbacks.get());
    323 
    324   // Now the cursor should have reset the rest of the cache.
    325   EXPECT_EQ(1, dispatcher_->reset_calls());
    326   EXPECT_EQ(1, dispatcher_->last_used_count());
    327 }
    328 
    329 }  // namespace content
    330