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/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