Home | History | Annotate | Download | only in appcache
      1 // Copyright (c) 2012 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 <stack>
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/callback.h"
     10 #include "base/file_util.h"
     11 #include "base/files/scoped_temp_dir.h"
     12 #include "base/memory/scoped_ptr.h"
     13 #include "base/message_loop/message_loop.h"
     14 #include "base/synchronization/waitable_event.h"
     15 #include "base/threading/thread.h"
     16 #include "net/base/net_errors.h"
     17 #include "net/base/request_priority.h"
     18 #include "net/http/http_response_headers.h"
     19 #include "net/url_request/url_request_error_job.h"
     20 #include "net/url_request/url_request_job_factory_impl.h"
     21 #include "net/url_request/url_request_test_job.h"
     22 #include "net/url_request/url_request_test_util.h"
     23 #include "testing/gtest/include/gtest/gtest.h"
     24 #include "webkit/browser/appcache/appcache.h"
     25 #include "webkit/browser/appcache/appcache_backend_impl.h"
     26 #include "webkit/browser/appcache/appcache_database.h"
     27 #include "webkit/browser/appcache/appcache_entry.h"
     28 #include "webkit/browser/appcache/appcache_group.h"
     29 #include "webkit/browser/appcache/appcache_host.h"
     30 #include "webkit/browser/appcache/appcache_interceptor.h"
     31 #include "webkit/browser/appcache/appcache_request_handler.h"
     32 #include "webkit/browser/appcache/appcache_service.h"
     33 #include "webkit/browser/appcache/appcache_storage_impl.h"
     34 #include "webkit/browser/quota/quota_manager.h"
     35 
     36 namespace appcache {
     37 
     38 namespace {
     39 
     40 const base::Time kZeroTime;
     41 const GURL kManifestUrl("http://blah/manifest");
     42 const GURL kManifestUrl2("http://blah/manifest2");
     43 const GURL kManifestUrl3("http://blah/manifest3");
     44 const GURL kEntryUrl("http://blah/entry");
     45 const GURL kEntryUrl2("http://blah/entry2");
     46 const GURL kFallbackNamespace("http://blah/fallback_namespace/");
     47 const GURL kFallbackNamespace2("http://blah/fallback_namespace/longer");
     48 const GURL kFallbackTestUrl("http://blah/fallback_namespace/longer/test");
     49 const GURL kOnlineNamespace("http://blah/online_namespace");
     50 const GURL kOnlineNamespaceWithinFallback(
     51     "http://blah/fallback_namespace/online/");
     52 const GURL kInterceptNamespace("http://blah/intercept_namespace/");
     53 const GURL kInterceptNamespace2("http://blah/intercept_namespace/longer/");
     54 const GURL kInterceptTestUrl("http://blah/intercept_namespace/longer/test");
     55 const GURL kInterceptPatternNamespace("http://blah/intercept_pattern/*/bar");
     56 const GURL kInterceptPatternTestPositiveUrl(
     57     "http://blah/intercept_pattern/foo/bar");
     58 const GURL kInterceptPatternTestNegativeUrl(
     59     "http://blah/intercept_pattern/foo/not_bar");
     60 const GURL kFallbackPatternNamespace("http://blah/fallback_pattern/*/bar");
     61 const GURL kFallbackPatternTestPositiveUrl(
     62     "http://blah/fallback_pattern/foo/bar");
     63 const GURL kFallbackPatternTestNegativeUrl(
     64     "http://blah/fallback_pattern/foo/not_bar");
     65 const GURL kOrigin(kManifestUrl.GetOrigin());
     66 
     67 const int kManifestEntryIdOffset = 100;
     68 const int kFallbackEntryIdOffset = 1000;
     69 
     70 const GURL kDefaultEntryUrl("http://blah/makecacheandgroup_default_entry");
     71 const int kDefaultEntrySize = 10;
     72 const int kDefaultEntryIdOffset = 12345;
     73 
     74 const int kMockQuota = 5000;
     75 
     76 // The Reinitialize test needs some http accessible resources to run,
     77 // we mock stuff inprocess for that.
     78 class MockHttpServer {
     79  public:
     80   static GURL GetMockUrl(const std::string& path) {
     81     return GURL("http://mockhost/" + path);
     82   }
     83 
     84   static net::URLRequestJob* CreateJob(
     85       net::URLRequest* request, net::NetworkDelegate* network_delegate) {
     86     if (request->url().host() != "mockhost")
     87       return new net::URLRequestErrorJob(request, network_delegate, -100);
     88 
     89     std::string headers, body;
     90     GetMockResponse(request->url().path(), &headers, &body);
     91     return new net::URLRequestTestJob(
     92         request, network_delegate, headers, body, true);
     93   }
     94 
     95  private:
     96   static void GetMockResponse(const std::string& path,
     97                               std::string* headers,
     98                               std::string* body) {
     99     const char manifest_headers[] =
    100         "HTTP/1.1 200 OK\0"
    101         "Content-type: text/cache-manifest\0"
    102         "\0";
    103     const char page_headers[] =
    104         "HTTP/1.1 200 OK\0"
    105         "Content-type: text/html\0"
    106         "\0";
    107     const char not_found_headers[] =
    108         "HTTP/1.1 404 NOT FOUND\0"
    109         "\0";
    110 
    111     if (path == "/manifest") {
    112       (*headers) = std::string(manifest_headers, arraysize(manifest_headers));
    113       (*body) = "CACHE MANIFEST\n";
    114     } else if (path == "/empty.html") {
    115       (*headers) = std::string(page_headers, arraysize(page_headers));
    116       (*body) = "";
    117     } else {
    118       (*headers) = std::string(not_found_headers,
    119                                arraysize(not_found_headers));
    120       (*body) = "";
    121     }
    122   }
    123 };
    124 
    125 class MockHttpServerJobFactory
    126     : public net::URLRequestJobFactory::ProtocolHandler {
    127  public:
    128   virtual net::URLRequestJob* MaybeCreateJob(
    129       net::URLRequest* request,
    130       net::NetworkDelegate* network_delegate) const OVERRIDE {
    131     return MockHttpServer::CreateJob(request, network_delegate);
    132   }
    133 };
    134 
    135 class IOThread : public base::Thread {
    136  public:
    137   explicit IOThread(const char* name)
    138       : base::Thread(name) {
    139   }
    140 
    141   virtual ~IOThread() {
    142     Stop();
    143   }
    144 
    145   net::URLRequestContext* request_context() {
    146     return request_context_.get();
    147   }
    148 
    149   virtual void Init() OVERRIDE {
    150     scoped_ptr<net::URLRequestJobFactoryImpl> factory(
    151         new net::URLRequestJobFactoryImpl());
    152     factory->SetProtocolHandler("http", new MockHttpServerJobFactory);
    153     job_factory_ = factory.Pass();
    154     request_context_.reset(new net::TestURLRequestContext());
    155     request_context_->set_job_factory(job_factory_.get());
    156     AppCacheInterceptor::EnsureRegistered();
    157   }
    158 
    159   virtual void CleanUp() OVERRIDE {
    160     request_context_.reset();
    161     job_factory_.reset();
    162   }
    163 
    164  private:
    165   scoped_ptr<net::URLRequestJobFactory> job_factory_;
    166   scoped_ptr<net::URLRequestContext> request_context_;
    167 };
    168 
    169 scoped_ptr<IOThread> io_thread;
    170 scoped_ptr<base::Thread> db_thread;
    171 
    172 }  // namespace
    173 
    174 class AppCacheStorageImplTest : public testing::Test {
    175  public:
    176   class MockStorageDelegate : public AppCacheStorage::Delegate {
    177    public:
    178     explicit MockStorageDelegate(AppCacheStorageImplTest* test)
    179         : loaded_cache_id_(0), stored_group_success_(false),
    180           would_exceed_quota_(false), obsoleted_success_(false),
    181           found_cache_id_(kNoCacheId), test_(test) {
    182     }
    183 
    184     virtual void OnCacheLoaded(AppCache* cache, int64 cache_id) OVERRIDE {
    185       loaded_cache_ = cache;
    186       loaded_cache_id_ = cache_id;
    187       test_->ScheduleNextTask();
    188     }
    189 
    190     virtual void OnGroupLoaded(AppCacheGroup* group,
    191                                const GURL& manifest_url) OVERRIDE {
    192       loaded_group_ = group;
    193       loaded_manifest_url_ = manifest_url;
    194       loaded_groups_newest_cache_ = group ? group->newest_complete_cache()
    195                                           : NULL;
    196       test_->ScheduleNextTask();
    197     }
    198 
    199     virtual void OnGroupAndNewestCacheStored(
    200         AppCacheGroup* group, AppCache* newest_cache, bool success,
    201         bool would_exceed_quota) OVERRIDE {
    202       stored_group_ = group;
    203       stored_group_success_ = success;
    204       would_exceed_quota_ = would_exceed_quota;
    205       test_->ScheduleNextTask();
    206     }
    207 
    208     virtual void OnGroupMadeObsolete(AppCacheGroup* group,
    209                                      bool success) OVERRIDE {
    210       obsoleted_group_ = group;
    211       obsoleted_success_ = success;
    212       test_->ScheduleNextTask();
    213     }
    214 
    215     virtual void OnMainResponseFound(const GURL& url,
    216                                      const AppCacheEntry& entry,
    217                                      const GURL& namespace_entry_url,
    218                                      const AppCacheEntry& fallback_entry,
    219                                      int64 cache_id,
    220                                      int64 group_id,
    221                                      const GURL& manifest_url) OVERRIDE {
    222       found_url_ = url;
    223       found_entry_ = entry;
    224       found_namespace_entry_url_ = namespace_entry_url;
    225       found_fallback_entry_ = fallback_entry;
    226       found_cache_id_ = cache_id;
    227       found_group_id_ = group_id;
    228       found_manifest_url_ = manifest_url;
    229       test_->ScheduleNextTask();
    230     }
    231 
    232     scoped_refptr<AppCache> loaded_cache_;
    233     int64 loaded_cache_id_;
    234     scoped_refptr<AppCacheGroup> loaded_group_;
    235     GURL loaded_manifest_url_;
    236     scoped_refptr<AppCache> loaded_groups_newest_cache_;
    237     scoped_refptr<AppCacheGroup> stored_group_;
    238     bool stored_group_success_;
    239     bool would_exceed_quota_;
    240     scoped_refptr<AppCacheGroup> obsoleted_group_;
    241     bool obsoleted_success_;
    242     GURL found_url_;
    243     AppCacheEntry found_entry_;
    244     GURL found_namespace_entry_url_;
    245     AppCacheEntry found_fallback_entry_;
    246     int64 found_cache_id_;
    247     int64 found_group_id_;
    248     GURL found_manifest_url_;
    249     AppCacheStorageImplTest* test_;
    250   };
    251 
    252   class MockQuotaManager : public quota::QuotaManager {
    253    public:
    254     MockQuotaManager()
    255         : QuotaManager(true /* is_incognito */,
    256                        base::FilePath(),
    257                        io_thread->message_loop_proxy().get(),
    258                        db_thread->message_loop_proxy().get(),
    259                        NULL),
    260           async_(false) {}
    261 
    262     virtual void GetUsageAndQuota(
    263         const GURL& origin,
    264         quota::StorageType type,
    265         const GetUsageAndQuotaCallback& callback) OVERRIDE {
    266       EXPECT_EQ(kOrigin, origin);
    267       EXPECT_EQ(quota::kStorageTypeTemporary, type);
    268       if (async_) {
    269         base::MessageLoop::current()->PostTask(
    270             FROM_HERE,
    271             base::Bind(&MockQuotaManager::CallCallback,
    272                        base::Unretained(this),
    273                        callback));
    274         return;
    275       }
    276       CallCallback(callback);
    277     }
    278 
    279     void CallCallback(const GetUsageAndQuotaCallback& callback) {
    280       callback.Run(quota::kQuotaStatusOk, 0, kMockQuota);
    281     }
    282 
    283     bool async_;
    284 
    285    protected:
    286     virtual ~MockQuotaManager() {}
    287   };
    288 
    289   class MockQuotaManagerProxy : public quota::QuotaManagerProxy {
    290    public:
    291     MockQuotaManagerProxy()
    292         : QuotaManagerProxy(NULL, NULL),
    293           notify_storage_accessed_count_(0),
    294           notify_storage_modified_count_(0),
    295           last_delta_(0),
    296           mock_manager_(new MockQuotaManager) {
    297       manager_ = mock_manager_.get();
    298     }
    299 
    300     virtual void NotifyStorageAccessed(quota::QuotaClient::ID client_id,
    301                                        const GURL& origin,
    302                                        quota::StorageType type) OVERRIDE {
    303       EXPECT_EQ(quota::QuotaClient::kAppcache, client_id);
    304       EXPECT_EQ(quota::kStorageTypeTemporary, type);
    305       ++notify_storage_accessed_count_;
    306       last_origin_ = origin;
    307     }
    308 
    309     virtual void NotifyStorageModified(quota::QuotaClient::ID client_id,
    310                                        const GURL& origin,
    311                                        quota::StorageType type,
    312                                        int64 delta) OVERRIDE {
    313       EXPECT_EQ(quota::QuotaClient::kAppcache, client_id);
    314       EXPECT_EQ(quota::kStorageTypeTemporary, type);
    315       ++notify_storage_modified_count_;
    316       last_origin_ = origin;
    317       last_delta_ = delta;
    318     }
    319 
    320     // Not needed for our tests.
    321     virtual void RegisterClient(quota::QuotaClient* client) OVERRIDE {}
    322     virtual void NotifyOriginInUse(const GURL& origin) OVERRIDE {}
    323     virtual void NotifyOriginNoLongerInUse(const GURL& origin) OVERRIDE {}
    324     virtual void SetUsageCacheEnabled(quota::QuotaClient::ID client_id,
    325                                       const GURL& origin,
    326                                       quota::StorageType type,
    327                                       bool enabled) OVERRIDE {}
    328     virtual void GetUsageAndQuota(
    329         base::SequencedTaskRunner* original_task_runner,
    330         const GURL& origin,
    331         quota::StorageType type,
    332         const GetUsageAndQuotaCallback& callback) OVERRIDE {}
    333 
    334     int notify_storage_accessed_count_;
    335     int notify_storage_modified_count_;
    336     GURL last_origin_;
    337     int last_delta_;
    338     scoped_refptr<MockQuotaManager> mock_manager_;
    339 
    340    protected:
    341     virtual ~MockQuotaManagerProxy() {}
    342   };
    343 
    344   template <class Method>
    345   void RunMethod(Method method) {
    346     (this->*method)();
    347   }
    348 
    349   // Helper callback to run a test on our io_thread. The io_thread is spun up
    350   // once and reused for all tests.
    351   template <class Method>
    352   void MethodWrapper(Method method) {
    353     SetUpTest();
    354 
    355     // Ensure InitTask execution prior to conducting a test.
    356     FlushDbThreadTasks();
    357 
    358     // We also have to wait for InitTask completion call to be performed
    359     // on the IO thread prior to running the test. Its guaranteed to be
    360     // queued by this time.
    361     base::MessageLoop::current()->PostTask(
    362         FROM_HERE,
    363         base::Bind(&AppCacheStorageImplTest::RunMethod<Method>,
    364                    base::Unretained(this),
    365                    method));
    366   }
    367 
    368   static void SetUpTestCase() {
    369     // We start both threads as TYPE_IO because we also use the db_thead
    370     // for the disk_cache which needs to be of TYPE_IO.
    371     base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
    372     io_thread.reset(new IOThread("AppCacheTest.IOThread"));
    373     ASSERT_TRUE(io_thread->StartWithOptions(options));
    374     db_thread.reset(new base::Thread("AppCacheTest::DBThread"));
    375     ASSERT_TRUE(db_thread->StartWithOptions(options));
    376   }
    377 
    378   static void TearDownTestCase() {
    379     io_thread.reset(NULL);
    380     db_thread.reset(NULL);
    381   }
    382 
    383   // Test harness --------------------------------------------------
    384 
    385   AppCacheStorageImplTest() {
    386   }
    387 
    388   template <class Method>
    389   void RunTestOnIOThread(Method method) {
    390     test_finished_event_ .reset(new base::WaitableEvent(false, false));
    391     io_thread->message_loop()->PostTask(
    392         FROM_HERE, base::Bind(&AppCacheStorageImplTest::MethodWrapper<Method>,
    393                               base::Unretained(this), method));
    394     test_finished_event_->Wait();
    395   }
    396 
    397   void SetUpTest() {
    398     DCHECK(base::MessageLoop::current() == io_thread->message_loop());
    399     service_.reset(new AppCacheService(NULL));
    400     service_->Initialize(
    401         base::FilePath(), db_thread->message_loop_proxy().get(), NULL);
    402     mock_quota_manager_proxy_ = new MockQuotaManagerProxy();
    403     service_->quota_manager_proxy_ = mock_quota_manager_proxy_;
    404     delegate_.reset(new MockStorageDelegate(this));
    405   }
    406 
    407   void TearDownTest() {
    408     DCHECK(base::MessageLoop::current() == io_thread->message_loop());
    409     storage()->CancelDelegateCallbacks(delegate());
    410     group_ = NULL;
    411     cache_ = NULL;
    412     cache2_ = NULL;
    413     mock_quota_manager_proxy_ = NULL;
    414     delegate_.reset();
    415     service_.reset();
    416     FlushDbThreadTasks();
    417   }
    418 
    419   void TestFinished() {
    420     // We unwind the stack prior to finishing up to let stack
    421     // based objects get deleted.
    422     DCHECK(base::MessageLoop::current() == io_thread->message_loop());
    423     base::MessageLoop::current()->PostTask(
    424         FROM_HERE,
    425         base::Bind(&AppCacheStorageImplTest::TestFinishedUnwound,
    426                    base::Unretained(this)));
    427   }
    428 
    429   void TestFinishedUnwound() {
    430     TearDownTest();
    431     test_finished_event_->Signal();
    432   }
    433 
    434   void PushNextTask(const base::Closure& task) {
    435     task_stack_.push(task);
    436   }
    437 
    438   void ScheduleNextTask() {
    439     DCHECK(base::MessageLoop::current() == io_thread->message_loop());
    440     if (task_stack_.empty()) {
    441       return;
    442     }
    443     base::MessageLoop::current()->PostTask(FROM_HERE, task_stack_.top());
    444     task_stack_.pop();
    445   }
    446 
    447   static void SignalEvent(base::WaitableEvent* event) {
    448     event->Signal();
    449   }
    450 
    451   void FlushDbThreadTasks() {
    452     // We pump a task thru the db thread to ensure any tasks previously
    453     // scheduled on that thread have been performed prior to return.
    454     base::WaitableEvent event(false, false);
    455     db_thread->message_loop()->PostTask(
    456         FROM_HERE, base::Bind(&AppCacheStorageImplTest::SignalEvent, &event));
    457     event.Wait();
    458   }
    459 
    460   // LoadCache_Miss ----------------------------------------------------
    461 
    462   void LoadCache_Miss() {
    463     // Attempt to load a cache that doesn't exist. Should
    464     // complete asynchronously.
    465     PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadCache_Miss,
    466                             base::Unretained(this)));
    467 
    468     storage()->LoadCache(111, delegate());
    469     EXPECT_NE(111, delegate()->loaded_cache_id_);
    470   }
    471 
    472   void Verify_LoadCache_Miss() {
    473     EXPECT_EQ(111, delegate()->loaded_cache_id_);
    474     EXPECT_FALSE(delegate()->loaded_cache_.get());
    475     EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
    476     EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
    477     TestFinished();
    478   }
    479 
    480   // LoadCache_NearHit -------------------------------------------------
    481 
    482   void LoadCache_NearHit() {
    483     // Attempt to load a cache that is currently in use
    484     // and does not require loading from storage. This
    485     // load should complete syncly.
    486 
    487     // Setup some preconditions. Make an 'unstored' cache for
    488     // us to load. The ctor should put it in the working set.
    489     int64 cache_id = storage()->NewCacheId();
    490     scoped_refptr<AppCache> cache(new AppCache(storage(), cache_id));
    491 
    492     // Conduct the test.
    493     storage()->LoadCache(cache_id, delegate());
    494     EXPECT_EQ(cache_id, delegate()->loaded_cache_id_);
    495     EXPECT_EQ(cache.get(), delegate()->loaded_cache_.get());
    496     EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
    497     EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
    498     TestFinished();
    499   }
    500 
    501   // CreateGroup  --------------------------------------------
    502 
    503   void CreateGroupInEmptyOrigin() {
    504     // Attempt to load a group that doesn't exist, one should
    505     // be created for us, but not stored.
    506 
    507     // Since the origin has no groups, the storage class will respond
    508     // syncly.
    509     storage()->LoadOrCreateGroup(kManifestUrl, delegate());
    510     Verify_CreateGroup();
    511   }
    512 
    513   void CreateGroupInPopulatedOrigin() {
    514     // Attempt to load a group that doesn't exist, one should
    515     // be created for us, but not stored.
    516     PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_CreateGroup,
    517                             base::Unretained(this)));
    518 
    519     // Since the origin has groups, storage class will have to
    520     // consult the database and completion will be async.
    521     storage()->usage_map_[kOrigin] = kDefaultEntrySize;
    522 
    523     storage()->LoadOrCreateGroup(kManifestUrl, delegate());
    524     EXPECT_FALSE(delegate()->loaded_group_.get());
    525   }
    526 
    527   void Verify_CreateGroup() {
    528     EXPECT_EQ(kManifestUrl, delegate()->loaded_manifest_url_);
    529     EXPECT_TRUE(delegate()->loaded_group_.get());
    530     EXPECT_TRUE(delegate()->loaded_group_->HasOneRef());
    531     EXPECT_FALSE(delegate()->loaded_group_->newest_complete_cache());
    532 
    533     // Should not have been stored in the database.
    534     AppCacheDatabase::GroupRecord record;
    535     EXPECT_FALSE(database()->FindGroup(
    536         delegate()->loaded_group_->group_id(), &record));
    537 
    538     EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
    539     EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
    540 
    541     TestFinished();
    542   }
    543 
    544   // LoadGroupAndCache_FarHit  --------------------------------------
    545 
    546   void LoadGroupAndCache_FarHit() {
    547     // Attempt to load a cache that is not currently in use
    548     // and does require loading from disk. This
    549     // load should complete asynchronously.
    550     PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadCache_Far_Hit,
    551                             base::Unretained(this)));
    552 
    553     // Setup some preconditions. Create a group and newest cache that
    554     // appear to be "stored" and "not currently in use".
    555     MakeCacheAndGroup(kManifestUrl, 1, 1, true);
    556     group_ = NULL;
    557     cache_ = NULL;
    558 
    559     // Conduct the cache load test, completes async
    560     storage()->LoadCache(1, delegate());
    561   }
    562 
    563   void Verify_LoadCache_Far_Hit() {
    564     EXPECT_TRUE(delegate()->loaded_cache_.get());
    565     EXPECT_TRUE(delegate()->loaded_cache_->HasOneRef());
    566     EXPECT_EQ(1, delegate()->loaded_cache_id_);
    567 
    568     // The group should also have been loaded.
    569     EXPECT_TRUE(delegate()->loaded_cache_->owning_group());
    570     EXPECT_TRUE(delegate()->loaded_cache_->owning_group()->HasOneRef());
    571     EXPECT_EQ(1, delegate()->loaded_cache_->owning_group()->group_id());
    572 
    573     EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_accessed_count_);
    574     EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
    575 
    576     // Drop things from the working set.
    577     delegate()->loaded_cache_ = NULL;
    578     EXPECT_FALSE(delegate()->loaded_group_.get());
    579 
    580     // Conduct the group load test, also complete asynchronously.
    581     PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadGroup_Far_Hit,
    582                             base::Unretained(this)));
    583 
    584     storage()->LoadOrCreateGroup(kManifestUrl, delegate());
    585   }
    586 
    587   void Verify_LoadGroup_Far_Hit() {
    588     EXPECT_TRUE(delegate()->loaded_group_.get());
    589     EXPECT_EQ(kManifestUrl, delegate()->loaded_manifest_url_);
    590     EXPECT_TRUE(delegate()->loaded_group_->newest_complete_cache());
    591     delegate()->loaded_groups_newest_cache_ = NULL;
    592     EXPECT_TRUE(delegate()->loaded_group_->HasOneRef());
    593     EXPECT_EQ(2, mock_quota_manager_proxy_->notify_storage_accessed_count_);
    594     EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
    595     TestFinished();
    596   }
    597 
    598   // StoreNewGroup  --------------------------------------
    599 
    600   void StoreNewGroup() {
    601     // Store a group and its newest cache. Should complete asynchronously.
    602     PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_StoreNewGroup,
    603                             base::Unretained(this)));
    604 
    605     // Setup some preconditions. Create a group and newest cache that
    606     // appear to be "unstored".
    607     group_ = new AppCacheGroup(
    608         storage(), kManifestUrl, storage()->NewGroupId());
    609     cache_ = new AppCache(storage(), storage()->NewCacheId());
    610     cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, 1,
    611                                               kDefaultEntrySize));
    612     // Hold a ref to the cache simulate the UpdateJob holding that ref,
    613     // and hold a ref to the group to simulate the CacheHost holding that ref.
    614 
    615     // Have the quota manager retrun asynchronously for this test.
    616     mock_quota_manager_proxy_->mock_manager_->async_ = true;
    617 
    618     // Conduct the store test.
    619     storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate());
    620     EXPECT_FALSE(delegate()->stored_group_success_);
    621   }
    622 
    623   void Verify_StoreNewGroup() {
    624     EXPECT_TRUE(delegate()->stored_group_success_);
    625     EXPECT_EQ(group_.get(), delegate()->stored_group_.get());
    626     EXPECT_EQ(cache_.get(), group_->newest_complete_cache());
    627     EXPECT_TRUE(cache_->is_complete());
    628 
    629     // Should have been stored in the database.
    630     AppCacheDatabase::GroupRecord group_record;
    631     AppCacheDatabase::CacheRecord cache_record;
    632     EXPECT_TRUE(database()->FindGroup(group_->group_id(), &group_record));
    633     EXPECT_TRUE(database()->FindCache(cache_->cache_id(), &cache_record));
    634 
    635     // Verify quota bookkeeping
    636     EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
    637     EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
    638     EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
    639     EXPECT_EQ(kDefaultEntrySize, mock_quota_manager_proxy_->last_delta_);
    640 
    641     TestFinished();
    642   }
    643 
    644   // StoreExistingGroup  --------------------------------------
    645 
    646   void StoreExistingGroup() {
    647     // Store a group and its newest cache. Should complete asynchronously.
    648     PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_StoreExistingGroup,
    649                             base::Unretained(this)));
    650 
    651     // Setup some preconditions. Create a group and old complete cache
    652     // that appear to be "stored"
    653     MakeCacheAndGroup(kManifestUrl, 1, 1, true);
    654     EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
    655 
    656     // And a newest unstored complete cache.
    657     cache2_ = new AppCache(storage(), 2);
    658     cache2_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::MASTER, 1,
    659                                                kDefaultEntrySize + 100));
    660 
    661     // Conduct the test.
    662     storage()->StoreGroupAndNewestCache(
    663         group_.get(), cache2_.get(), delegate());
    664     EXPECT_FALSE(delegate()->stored_group_success_);
    665   }
    666 
    667   void Verify_StoreExistingGroup() {
    668     EXPECT_TRUE(delegate()->stored_group_success_);
    669     EXPECT_EQ(group_.get(), delegate()->stored_group_.get());
    670     EXPECT_EQ(cache2_.get(), group_->newest_complete_cache());
    671     EXPECT_TRUE(cache2_->is_complete());
    672 
    673     // The new cache should have been stored in the database.
    674     AppCacheDatabase::GroupRecord group_record;
    675     AppCacheDatabase::CacheRecord cache_record;
    676     EXPECT_TRUE(database()->FindGroup(1, &group_record));
    677     EXPECT_TRUE(database()->FindCache(2, &cache_record));
    678 
    679     // The old cache should have been deleted
    680     EXPECT_FALSE(database()->FindCache(1, &cache_record));
    681 
    682     // Verify quota bookkeeping
    683     EXPECT_EQ(kDefaultEntrySize + 100, storage()->usage_map_[kOrigin]);
    684     EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
    685     EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
    686     EXPECT_EQ(100, mock_quota_manager_proxy_->last_delta_);
    687 
    688     TestFinished();
    689   }
    690 
    691   // StoreExistingGroupExistingCache  -------------------------------
    692 
    693   void StoreExistingGroupExistingCache() {
    694     // Store a group with updates to its existing newest complete cache.
    695     // Setup some preconditions. Create a group and a complete cache that
    696     // appear to be "stored".
    697 
    698     // Setup some preconditions. Create a group and old complete cache
    699     // that appear to be "stored"
    700     MakeCacheAndGroup(kManifestUrl, 1, 1, true);
    701     EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
    702 
    703     // Change the cache.
    704     base::Time now = base::Time::Now();
    705     cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::MASTER, 1, 100));
    706     cache_->set_update_time(now);
    707 
    708     PushNextTask(base::Bind(
    709         &AppCacheStorageImplTest::Verify_StoreExistingGroupExistingCache,
    710         base::Unretained(this), now));
    711 
    712     // Conduct the test.
    713     EXPECT_EQ(cache_, group_->newest_complete_cache());
    714     storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate());
    715     EXPECT_FALSE(delegate()->stored_group_success_);
    716   }
    717 
    718   void Verify_StoreExistingGroupExistingCache(
    719       base::Time expected_update_time) {
    720     EXPECT_TRUE(delegate()->stored_group_success_);
    721     EXPECT_EQ(cache_, group_->newest_complete_cache());
    722 
    723     AppCacheDatabase::CacheRecord cache_record;
    724     EXPECT_TRUE(database()->FindCache(1, &cache_record));
    725     EXPECT_EQ(1, cache_record.cache_id);
    726     EXPECT_EQ(1, cache_record.group_id);
    727     EXPECT_FALSE(cache_record.online_wildcard);
    728     EXPECT_TRUE(expected_update_time == cache_record.update_time);
    729     EXPECT_EQ(100 + kDefaultEntrySize, cache_record.cache_size);
    730 
    731     std::vector<AppCacheDatabase::EntryRecord> entry_records;
    732     EXPECT_TRUE(database()->FindEntriesForCache(1, &entry_records));
    733     EXPECT_EQ(2U, entry_records.size());
    734     if (entry_records[0].url == kDefaultEntryUrl)
    735       entry_records.erase(entry_records.begin());
    736     EXPECT_EQ(1 , entry_records[0].cache_id);
    737     EXPECT_EQ(kEntryUrl, entry_records[0].url);
    738     EXPECT_EQ(AppCacheEntry::MASTER, entry_records[0].flags);
    739     EXPECT_EQ(1, entry_records[0].response_id);
    740     EXPECT_EQ(100, entry_records[0].response_size);
    741 
    742     // Verify quota bookkeeping
    743     EXPECT_EQ(100 + kDefaultEntrySize, storage()->usage_map_[kOrigin]);
    744     EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
    745     EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
    746     EXPECT_EQ(100, mock_quota_manager_proxy_->last_delta_);
    747 
    748     TestFinished();
    749   }
    750 
    751   // FailStoreGroup  --------------------------------------
    752 
    753   void FailStoreGroup() {
    754     // Store a group and its newest cache. Should complete asynchronously.
    755     PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_FailStoreGroup,
    756                             base::Unretained(this)));
    757 
    758     // Setup some preconditions. Create a group and newest cache that
    759     // appear to be "unstored" and big enough to exceed the 5M limit.
    760     const int64 kTooBig = 10 * 1024 * 1024;  // 10M
    761     group_ = new AppCacheGroup(
    762         storage(), kManifestUrl, storage()->NewGroupId());
    763     cache_ = new AppCache(storage(), storage()->NewCacheId());
    764     cache_->AddEntry(kManifestUrl,
    765                      AppCacheEntry(AppCacheEntry::MANIFEST, 1, kTooBig));
    766     // Hold a ref to the cache simulate the UpdateJob holding that ref,
    767     // and hold a ref to the group to simulate the CacheHost holding that ref.
    768 
    769     // Conduct the store test.
    770     storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate());
    771     EXPECT_FALSE(delegate()->stored_group_success_);  // Expected to be async.
    772   }
    773 
    774   void Verify_FailStoreGroup() {
    775     EXPECT_FALSE(delegate()->stored_group_success_);
    776     EXPECT_TRUE(delegate()->would_exceed_quota_);
    777 
    778     // Should not have been stored in the database.
    779     AppCacheDatabase::GroupRecord group_record;
    780     AppCacheDatabase::CacheRecord cache_record;
    781     EXPECT_FALSE(database()->FindGroup(group_->group_id(), &group_record));
    782     EXPECT_FALSE(database()->FindCache(cache_->cache_id(), &cache_record));
    783 
    784     EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
    785     EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
    786 
    787     TestFinished();
    788   }
    789 
    790   // MakeGroupObsolete  -------------------------------
    791 
    792   void MakeGroupObsolete() {
    793     // Make a group obsolete, should complete asynchronously.
    794     PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_MakeGroupObsolete,
    795                             base::Unretained(this)));
    796 
    797     // Setup some preconditions. Create a group and newest cache that
    798     // appears to be "stored" and "currently in use".
    799     MakeCacheAndGroup(kManifestUrl, 1, 1, true);
    800     EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
    801 
    802     // Also insert some related records.
    803     AppCacheDatabase::EntryRecord entry_record;
    804     entry_record.cache_id = 1;
    805     entry_record.flags = AppCacheEntry::FALLBACK;
    806     entry_record.response_id = 1;
    807     entry_record.url = kEntryUrl;
    808     EXPECT_TRUE(database()->InsertEntry(&entry_record));
    809 
    810     AppCacheDatabase::NamespaceRecord fallback_namespace_record;
    811     fallback_namespace_record.cache_id = 1;
    812     fallback_namespace_record.namespace_.target_url = kEntryUrl;
    813     fallback_namespace_record.namespace_.namespace_url = kFallbackNamespace;
    814     fallback_namespace_record.origin = kManifestUrl.GetOrigin();
    815     EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record));
    816 
    817     AppCacheDatabase::OnlineWhiteListRecord online_whitelist_record;
    818     online_whitelist_record.cache_id = 1;
    819     online_whitelist_record.namespace_url = kOnlineNamespace;
    820     EXPECT_TRUE(database()->InsertOnlineWhiteList(&online_whitelist_record));
    821 
    822     // Conduct the test.
    823     storage()->MakeGroupObsolete(group_.get(), delegate());
    824     EXPECT_FALSE(group_->is_obsolete());
    825   }
    826 
    827   void Verify_MakeGroupObsolete() {
    828     EXPECT_TRUE(delegate()->obsoleted_success_);
    829     EXPECT_EQ(group_.get(), delegate()->obsoleted_group_.get());
    830     EXPECT_TRUE(group_->is_obsolete());
    831     EXPECT_TRUE(storage()->usage_map_.empty());
    832 
    833     // The cache and group have been deleted from the database.
    834     AppCacheDatabase::GroupRecord group_record;
    835     AppCacheDatabase::CacheRecord cache_record;
    836     EXPECT_FALSE(database()->FindGroup(1, &group_record));
    837     EXPECT_FALSE(database()->FindCache(1, &cache_record));
    838 
    839     // The related records should have been deleted too.
    840     std::vector<AppCacheDatabase::EntryRecord> entry_records;
    841     database()->FindEntriesForCache(1, &entry_records);
    842     EXPECT_TRUE(entry_records.empty());
    843     std::vector<AppCacheDatabase::NamespaceRecord> intercept_records;
    844     std::vector<AppCacheDatabase::NamespaceRecord> fallback_records;
    845     database()->FindNamespacesForCache(
    846         1, &intercept_records, &fallback_records);
    847     EXPECT_TRUE(fallback_records.empty());
    848     std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelist_records;
    849     database()->FindOnlineWhiteListForCache(1, &whitelist_records);
    850     EXPECT_TRUE(whitelist_records.empty());
    851 
    852     // Verify quota bookkeeping
    853     EXPECT_TRUE(storage()->usage_map_.empty());
    854     EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
    855     EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
    856     EXPECT_EQ(-kDefaultEntrySize, mock_quota_manager_proxy_->last_delta_);
    857 
    858     TestFinished();
    859   }
    860 
    861   // MarkEntryAsForeign  -------------------------------
    862 
    863   void MarkEntryAsForeign() {
    864     // Setup some preconditions. Create a cache with an entry
    865     // in storage and in the working set.
    866     MakeCacheAndGroup(kManifestUrl, 1, 1, true);
    867     cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT));
    868     AppCacheDatabase::EntryRecord entry_record;
    869     entry_record.cache_id = 1;
    870     entry_record.url = kEntryUrl;
    871     entry_record.flags = AppCacheEntry::EXPLICIT;
    872     entry_record.response_id = 0;
    873     EXPECT_TRUE(database()->InsertEntry(&entry_record));
    874     EXPECT_FALSE(cache_->GetEntry(kEntryUrl)->IsForeign());
    875 
    876     // Conduct the test.
    877     storage()->MarkEntryAsForeign(kEntryUrl, 1);
    878 
    879     // The entry in the working set should have been updated syncly.
    880     EXPECT_TRUE(cache_->GetEntry(kEntryUrl)->IsForeign());
    881     EXPECT_TRUE(cache_->GetEntry(kEntryUrl)->IsExplicit());
    882 
    883     // And the entry in storage should also be updated, but that
    884     // happens asynchronously on the db thread.
    885     FlushDbThreadTasks();
    886     AppCacheDatabase::EntryRecord entry_record2;
    887     EXPECT_TRUE(database()->FindEntry(1, kEntryUrl, &entry_record2));
    888     EXPECT_EQ(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN,
    889               entry_record2.flags);
    890     TestFinished();
    891   }
    892 
    893   // MarkEntryAsForeignWithLoadInProgress  -------------------------------
    894 
    895   void MarkEntryAsForeignWithLoadInProgress() {
    896     PushNextTask(base::Bind(
    897        &AppCacheStorageImplTest::Verify_MarkEntryAsForeignWithLoadInProgress,
    898        base::Unretained(this)));
    899 
    900     // Setup some preconditions. Create a cache with an entry
    901     // in storage, but not in the working set.
    902     MakeCacheAndGroup(kManifestUrl, 1, 1, true);
    903     cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT));
    904     AppCacheDatabase::EntryRecord entry_record;
    905     entry_record.cache_id = 1;
    906     entry_record.url = kEntryUrl;
    907     entry_record.flags = AppCacheEntry::EXPLICIT;
    908     entry_record.response_id = 0;
    909     EXPECT_TRUE(database()->InsertEntry(&entry_record));
    910     EXPECT_FALSE(cache_->GetEntry(kEntryUrl)->IsForeign());
    911     EXPECT_TRUE(cache_->HasOneRef());
    912     cache_ = NULL;
    913     group_ = NULL;
    914 
    915     // Conduct the test, start a cache load, and prior to completion
    916     // of that load, mark the entry as foreign.
    917     storage()->LoadCache(1, delegate());
    918     storage()->MarkEntryAsForeign(kEntryUrl, 1);
    919   }
    920 
    921   void Verify_MarkEntryAsForeignWithLoadInProgress() {
    922     EXPECT_EQ(1, delegate()->loaded_cache_id_);
    923     EXPECT_TRUE(delegate()->loaded_cache_.get());
    924 
    925     // The entry in the working set should have been updated upon load.
    926     EXPECT_TRUE(delegate()->loaded_cache_->GetEntry(kEntryUrl)->IsForeign());
    927     EXPECT_TRUE(delegate()->loaded_cache_->GetEntry(kEntryUrl)->IsExplicit());
    928 
    929     // And the entry in storage should also be updated.
    930     FlushDbThreadTasks();
    931     AppCacheDatabase::EntryRecord entry_record;
    932     EXPECT_TRUE(database()->FindEntry(1, kEntryUrl, &entry_record));
    933     EXPECT_EQ(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN,
    934               entry_record.flags);
    935     TestFinished();
    936   }
    937 
    938   // FindNoMainResponse  -------------------------------
    939 
    940   void FindNoMainResponse() {
    941     PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_FindNoMainResponse,
    942                             base::Unretained(this)));
    943 
    944     // Conduct the test.
    945     storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
    946     EXPECT_NE(kEntryUrl, delegate()->found_url_);
    947   }
    948 
    949   void Verify_FindNoMainResponse() {
    950     EXPECT_EQ(kEntryUrl, delegate()->found_url_);
    951     EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
    952     EXPECT_EQ(kNoCacheId, delegate()->found_cache_id_);
    953     EXPECT_EQ(kNoResponseId, delegate()->found_entry_.response_id());
    954     EXPECT_EQ(kNoResponseId, delegate()->found_fallback_entry_.response_id());
    955     EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
    956     EXPECT_EQ(0, delegate()->found_entry_.types());
    957     EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
    958     TestFinished();
    959   }
    960 
    961   // BasicFindMainResponse  -------------------------------
    962 
    963   void BasicFindMainResponseInDatabase() {
    964     BasicFindMainResponse(true);
    965   }
    966 
    967   void BasicFindMainResponseInWorkingSet() {
    968     BasicFindMainResponse(false);
    969   }
    970 
    971   void BasicFindMainResponse(bool drop_from_working_set) {
    972     PushNextTask(base::Bind(
    973         &AppCacheStorageImplTest::Verify_BasicFindMainResponse,
    974         base::Unretained(this)));
    975 
    976     // Setup some preconditions. Create a complete cache with an entry
    977     // in storage.
    978     MakeCacheAndGroup(kManifestUrl, 2, 1, true);
    979     cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, 1));
    980     AppCacheDatabase::EntryRecord entry_record;
    981     entry_record.cache_id = 1;
    982     entry_record.url = kEntryUrl;
    983     entry_record.flags = AppCacheEntry::EXPLICIT;
    984     entry_record.response_id = 1;
    985     EXPECT_TRUE(database()->InsertEntry(&entry_record));
    986 
    987     // Optionally drop the cache/group pair from the working set.
    988     if (drop_from_working_set) {
    989       EXPECT_TRUE(cache_->HasOneRef());
    990       cache_ = NULL;
    991       EXPECT_TRUE(group_->HasOneRef());
    992       group_ = NULL;
    993     }
    994 
    995     // Conduct the test.
    996     storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
    997     EXPECT_NE(kEntryUrl,  delegate()->found_url_);
    998   }
    999 
   1000   void Verify_BasicFindMainResponse() {
   1001     EXPECT_EQ(kEntryUrl, delegate()->found_url_);
   1002     EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
   1003     EXPECT_EQ(1, delegate()->found_cache_id_);
   1004     EXPECT_EQ(2, delegate()->found_group_id_);
   1005     EXPECT_EQ(1, delegate()->found_entry_.response_id());
   1006     EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
   1007     EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
   1008     TestFinished();
   1009   }
   1010 
   1011   // BasicFindMainFallbackResponse  -------------------------------
   1012 
   1013   void BasicFindMainFallbackResponseInDatabase() {
   1014     BasicFindMainFallbackResponse(true);
   1015   }
   1016 
   1017   void BasicFindMainFallbackResponseInWorkingSet() {
   1018     BasicFindMainFallbackResponse(false);
   1019   }
   1020 
   1021   void BasicFindMainFallbackResponse(bool drop_from_working_set) {
   1022     PushNextTask(base::Bind(
   1023         &AppCacheStorageImplTest::Verify_BasicFindMainFallbackResponse,
   1024         base::Unretained(this)));
   1025 
   1026     // Setup some preconditions. Create a complete cache with a
   1027     // fallback namespace and entry.
   1028     MakeCacheAndGroup(kManifestUrl, 2, 1, true);
   1029     cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::FALLBACK, 1));
   1030     cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::FALLBACK, 2));
   1031     cache_->fallback_namespaces_.push_back(
   1032         Namespace(FALLBACK_NAMESPACE, kFallbackNamespace2, kEntryUrl2, false));
   1033     cache_->fallback_namespaces_.push_back(
   1034         Namespace(FALLBACK_NAMESPACE, kFallbackNamespace, kEntryUrl, false));
   1035     AppCacheDatabase::CacheRecord cache_record;
   1036     std::vector<AppCacheDatabase::EntryRecord> entries;
   1037     std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
   1038     std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
   1039     std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
   1040     cache_->ToDatabaseRecords(group_.get(),
   1041                               &cache_record,
   1042                               &entries,
   1043                               &intercepts,
   1044                               &fallbacks,
   1045                               &whitelists);
   1046 
   1047     std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
   1048         entries.begin();
   1049     while (iter != entries.end()) {
   1050       // MakeCacheAndGroup has inserted the default entry record already.
   1051       if (iter->url != kDefaultEntryUrl)
   1052         EXPECT_TRUE(database()->InsertEntry(&(*iter)));
   1053       ++iter;
   1054     }
   1055 
   1056     EXPECT_TRUE(database()->InsertNamespaceRecords(fallbacks));
   1057     EXPECT_TRUE(database()->InsertOnlineWhiteListRecords(whitelists));
   1058     if (drop_from_working_set) {
   1059       EXPECT_TRUE(cache_->HasOneRef());
   1060       cache_ = NULL;
   1061       EXPECT_TRUE(group_->HasOneRef());
   1062       group_ = NULL;
   1063     }
   1064 
   1065     // Conduct the test. The test url is in both fallback namespace urls,
   1066     // but should match the longer of the two.
   1067     storage()->FindResponseForMainRequest(kFallbackTestUrl, GURL(), delegate());
   1068     EXPECT_NE(kFallbackTestUrl, delegate()->found_url_);
   1069   }
   1070 
   1071   void Verify_BasicFindMainFallbackResponse() {
   1072     EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_);
   1073     EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
   1074     EXPECT_EQ(1, delegate()->found_cache_id_);
   1075     EXPECT_EQ(2, delegate()->found_group_id_);
   1076     EXPECT_FALSE(delegate()->found_entry_.has_response_id());
   1077     EXPECT_EQ(2, delegate()->found_fallback_entry_.response_id());
   1078     EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
   1079     EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
   1080     TestFinished();
   1081   }
   1082 
   1083   // BasicFindMainInterceptResponse  -------------------------------
   1084 
   1085   void BasicFindMainInterceptResponseInDatabase() {
   1086     BasicFindMainInterceptResponse(true);
   1087   }
   1088 
   1089   void BasicFindMainInterceptResponseInWorkingSet() {
   1090     BasicFindMainInterceptResponse(false);
   1091   }
   1092 
   1093   void BasicFindMainInterceptResponse(bool drop_from_working_set) {
   1094     PushNextTask(base::Bind(
   1095         &AppCacheStorageImplTest::Verify_BasicFindMainInterceptResponse,
   1096         base::Unretained(this)));
   1097 
   1098     // Setup some preconditions. Create a complete cache with an
   1099     // intercept namespace and entry.
   1100     MakeCacheAndGroup(kManifestUrl, 2, 1, true);
   1101     cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::INTERCEPT, 1));
   1102     cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::INTERCEPT, 2));
   1103     cache_->intercept_namespaces_.push_back(
   1104         Namespace(INTERCEPT_NAMESPACE, kInterceptNamespace2,
   1105                   kEntryUrl2, false));
   1106     cache_->intercept_namespaces_.push_back(
   1107         Namespace(INTERCEPT_NAMESPACE, kInterceptNamespace,
   1108                   kEntryUrl, false));
   1109     AppCacheDatabase::CacheRecord cache_record;
   1110     std::vector<AppCacheDatabase::EntryRecord> entries;
   1111     std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
   1112     std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
   1113     std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
   1114     cache_->ToDatabaseRecords(group_.get(),
   1115                               &cache_record,
   1116                               &entries,
   1117                               &intercepts,
   1118                               &fallbacks,
   1119                               &whitelists);
   1120 
   1121     std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
   1122         entries.begin();
   1123     while (iter != entries.end()) {
   1124       // MakeCacheAndGroup has inserted  the default entry record already
   1125       if (iter->url != kDefaultEntryUrl)
   1126         EXPECT_TRUE(database()->InsertEntry(&(*iter)));
   1127       ++iter;
   1128     }
   1129 
   1130     EXPECT_TRUE(database()->InsertNamespaceRecords(intercepts));
   1131     EXPECT_TRUE(database()->InsertOnlineWhiteListRecords(whitelists));
   1132     if (drop_from_working_set) {
   1133       EXPECT_TRUE(cache_->HasOneRef());
   1134       cache_ = NULL;
   1135       EXPECT_TRUE(group_->HasOneRef());
   1136       group_ = NULL;
   1137     }
   1138 
   1139     // Conduct the test. The test url is in both intercept namespaces,
   1140     // but should match the longer of the two.
   1141     storage()->FindResponseForMainRequest(
   1142         kInterceptTestUrl, GURL(), delegate());
   1143     EXPECT_NE(kInterceptTestUrl, delegate()->found_url_);
   1144   }
   1145 
   1146   void Verify_BasicFindMainInterceptResponse() {
   1147     EXPECT_EQ(kInterceptTestUrl, delegate()->found_url_);
   1148     EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
   1149     EXPECT_EQ(1, delegate()->found_cache_id_);
   1150     EXPECT_EQ(2, delegate()->found_group_id_);
   1151     EXPECT_EQ(2, delegate()->found_entry_.response_id());
   1152     EXPECT_TRUE(delegate()->found_entry_.IsIntercept());
   1153     EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
   1154     EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
   1155     TestFinished();
   1156   }
   1157 
   1158   // FindInterceptPatternMatch ----------------------------------------
   1159 
   1160   void FindInterceptPatternMatchInDatabase() {
   1161     FindInterceptPatternMatch(true);
   1162   }
   1163 
   1164   void FindInterceptPatternMatchInWorkingSet() {
   1165     FindInterceptPatternMatch(false);
   1166   }
   1167 
   1168   void FindInterceptPatternMatch(bool drop_from_working_set) {
   1169     // Setup some preconditions. Create a complete cache with an
   1170     // pattern matching intercept namespace and entry.
   1171     MakeCacheAndGroup(kManifestUrl, 2, 1, true);
   1172     cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::INTERCEPT, 1));
   1173     cache_->intercept_namespaces_.push_back(
   1174         Namespace(INTERCEPT_NAMESPACE, kInterceptPatternNamespace,
   1175                   kEntryUrl, true));
   1176     AppCacheDatabase::CacheRecord cache_record;
   1177     std::vector<AppCacheDatabase::EntryRecord> entries;
   1178     std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
   1179     std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
   1180     std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
   1181     cache_->ToDatabaseRecords(group_.get(),
   1182                               &cache_record,
   1183                               &entries,
   1184                               &intercepts,
   1185                               &fallbacks,
   1186                               &whitelists);
   1187 
   1188     std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
   1189         entries.begin();
   1190     while (iter != entries.end()) {
   1191       // MakeCacheAndGroup has inserted  the default entry record already
   1192       if (iter->url != kDefaultEntryUrl)
   1193         EXPECT_TRUE(database()->InsertEntry(&(*iter)));
   1194       ++iter;
   1195     }
   1196 
   1197     EXPECT_TRUE(database()->InsertNamespaceRecords(intercepts));
   1198     if (drop_from_working_set) {
   1199       EXPECT_TRUE(cache_->HasOneRef());
   1200       cache_ = NULL;
   1201       EXPECT_TRUE(group_->HasOneRef());
   1202       group_ = NULL;
   1203     }
   1204 
   1205     // First test something that does not match the pattern.
   1206     PushNextTask(base::Bind(
   1207         &AppCacheStorageImplTest::Verify_FindInterceptPatternMatchNegative,
   1208         base::Unretained(this)));
   1209     storage()->FindResponseForMainRequest(
   1210         kInterceptPatternTestNegativeUrl, GURL(), delegate());
   1211     EXPECT_EQ(GURL(), delegate()->found_url_);  // Is always async.
   1212   }
   1213 
   1214   void Verify_FindInterceptPatternMatchNegative() {
   1215     EXPECT_EQ(kInterceptPatternTestNegativeUrl, delegate()->found_url_);
   1216     EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
   1217     EXPECT_EQ(kNoCacheId, delegate()->found_cache_id_);
   1218     EXPECT_EQ(kNoResponseId, delegate()->found_entry_.response_id());
   1219     EXPECT_EQ(kNoResponseId, delegate()->found_fallback_entry_.response_id());
   1220     EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
   1221     EXPECT_EQ(0, delegate()->found_entry_.types());
   1222     EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
   1223 
   1224     // Then test something that matches.
   1225     PushNextTask(base::Bind(
   1226         &AppCacheStorageImplTest::Verify_FindInterceptPatternMatchPositive,
   1227         base::Unretained(this)));
   1228     storage()->FindResponseForMainRequest(
   1229         kInterceptPatternTestPositiveUrl, GURL(), delegate());
   1230   }
   1231 
   1232   void Verify_FindInterceptPatternMatchPositive() {
   1233     EXPECT_EQ(kInterceptPatternTestPositiveUrl, delegate()->found_url_);
   1234     EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
   1235     EXPECT_EQ(1, delegate()->found_cache_id_);
   1236     EXPECT_EQ(2, delegate()->found_group_id_);
   1237     EXPECT_EQ(1, delegate()->found_entry_.response_id());
   1238     EXPECT_TRUE(delegate()->found_entry_.IsIntercept());
   1239     EXPECT_EQ(kEntryUrl, delegate()->found_namespace_entry_url_);
   1240     EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
   1241     TestFinished();
   1242   }
   1243 
   1244   // FindFallbackPatternMatch  -------------------------------
   1245 
   1246   void FindFallbackPatternMatchInDatabase() {
   1247     FindFallbackPatternMatch(true);
   1248   }
   1249 
   1250   void FindFallbackPatternMatchInWorkingSet() {
   1251     FindFallbackPatternMatch(false);
   1252   }
   1253 
   1254   void FindFallbackPatternMatch(bool drop_from_working_set) {
   1255     // Setup some preconditions. Create a complete cache with a
   1256     // pattern matching fallback namespace and entry.
   1257     MakeCacheAndGroup(kManifestUrl, 2, 1, true);
   1258     cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::FALLBACK, 1));
   1259     cache_->fallback_namespaces_.push_back(
   1260         Namespace(FALLBACK_NAMESPACE, kFallbackPatternNamespace,
   1261                   kEntryUrl, true));
   1262     AppCacheDatabase::CacheRecord cache_record;
   1263     std::vector<AppCacheDatabase::EntryRecord> entries;
   1264     std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
   1265     std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
   1266     std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
   1267     cache_->ToDatabaseRecords(group_.get(),
   1268                               &cache_record,
   1269                               &entries,
   1270                               &intercepts,
   1271                               &fallbacks,
   1272                               &whitelists);
   1273 
   1274     std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
   1275         entries.begin();
   1276     while (iter != entries.end()) {
   1277       // MakeCacheAndGroup has inserted the default entry record already.
   1278       if (iter->url != kDefaultEntryUrl)
   1279         EXPECT_TRUE(database()->InsertEntry(&(*iter)));
   1280       ++iter;
   1281     }
   1282 
   1283     EXPECT_TRUE(database()->InsertNamespaceRecords(fallbacks));
   1284     if (drop_from_working_set) {
   1285       EXPECT_TRUE(cache_->HasOneRef());
   1286       cache_ = NULL;
   1287       EXPECT_TRUE(group_->HasOneRef());
   1288       group_ = NULL;
   1289     }
   1290 
   1291     // First test something that does not match the pattern.
   1292     PushNextTask(base::Bind(
   1293         &AppCacheStorageImplTest::Verify_FindFallbackPatternMatchNegative,
   1294         base::Unretained(this)));
   1295     storage()->FindResponseForMainRequest(
   1296         kFallbackPatternTestNegativeUrl, GURL(), delegate());
   1297     EXPECT_EQ(GURL(), delegate()->found_url_);  // Is always async.
   1298   }
   1299 
   1300   void Verify_FindFallbackPatternMatchNegative() {
   1301     EXPECT_EQ(kFallbackPatternTestNegativeUrl, delegate()->found_url_);
   1302       EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
   1303       EXPECT_EQ(kNoCacheId, delegate()->found_cache_id_);
   1304       EXPECT_EQ(kNoResponseId, delegate()->found_entry_.response_id());
   1305       EXPECT_EQ(kNoResponseId, delegate()->found_fallback_entry_.response_id());
   1306       EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
   1307       EXPECT_EQ(0, delegate()->found_entry_.types());
   1308       EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
   1309 
   1310       // Then test something that matches.
   1311       PushNextTask(base::Bind(
   1312           &AppCacheStorageImplTest::Verify_FindFallbackPatternMatchPositive,
   1313           base::Unretained(this)));
   1314       storage()->FindResponseForMainRequest(
   1315           kFallbackPatternTestPositiveUrl, GURL(), delegate());
   1316   }
   1317 
   1318   void Verify_FindFallbackPatternMatchPositive() {
   1319     EXPECT_EQ(kFallbackPatternTestPositiveUrl, delegate()->found_url_);
   1320     EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
   1321     EXPECT_EQ(1, delegate()->found_cache_id_);
   1322     EXPECT_EQ(2, delegate()->found_group_id_);
   1323     EXPECT_EQ(1, delegate()->found_fallback_entry_.response_id());
   1324     EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
   1325     EXPECT_EQ(kEntryUrl, delegate()->found_namespace_entry_url_);
   1326     EXPECT_FALSE(delegate()->found_entry_.has_response_id());
   1327     TestFinished();
   1328   }
   1329 
   1330   // FindMainResponseWithMultipleHits  -------------------------------
   1331 
   1332   void FindMainResponseWithMultipleHits() {
   1333     PushNextTask(base::Bind(
   1334         &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits,
   1335         base::Unretained(this)));
   1336 
   1337     // Setup some preconditions, create a few caches with an identical set
   1338     // of entries and fallback namespaces. Only the last one remains in
   1339     // the working set to simulate appearing as "in use".
   1340     MakeMultipleHitCacheAndGroup(kManifestUrl, 1);
   1341     MakeMultipleHitCacheAndGroup(kManifestUrl2, 2);
   1342     MakeMultipleHitCacheAndGroup(kManifestUrl3, 3);
   1343 
   1344     // Conduct the test, we should find the response from the last cache
   1345     // since it's "in use".
   1346     storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
   1347     EXPECT_NE(kEntryUrl, delegate()->found_url_);
   1348   }
   1349 
   1350   void MakeMultipleHitCacheAndGroup(const GURL& manifest_url, int id) {
   1351     MakeCacheAndGroup(manifest_url, id, id, true);
   1352     AppCacheDatabase::EntryRecord entry_record;
   1353 
   1354     // Add an entry for kEntryUrl
   1355     entry_record.cache_id = id;
   1356     entry_record.url = kEntryUrl;
   1357     entry_record.flags = AppCacheEntry::EXPLICIT;
   1358     entry_record.response_id = id;
   1359     EXPECT_TRUE(database()->InsertEntry(&entry_record));
   1360     cache_->AddEntry(
   1361         entry_record.url,
   1362         AppCacheEntry(entry_record.flags, entry_record.response_id));
   1363 
   1364     // Add an entry for the manifestUrl
   1365     entry_record.cache_id = id;
   1366     entry_record.url = manifest_url;
   1367     entry_record.flags = AppCacheEntry::MANIFEST;
   1368     entry_record.response_id = id + kManifestEntryIdOffset;
   1369     EXPECT_TRUE(database()->InsertEntry(&entry_record));
   1370     cache_->AddEntry(
   1371         entry_record.url,
   1372         AppCacheEntry(entry_record.flags, entry_record.response_id));
   1373 
   1374     // Add a fallback entry and namespace
   1375     entry_record.cache_id = id;
   1376     entry_record.url = kEntryUrl2;
   1377     entry_record.flags = AppCacheEntry::FALLBACK;
   1378     entry_record.response_id = id + kFallbackEntryIdOffset;
   1379     EXPECT_TRUE(database()->InsertEntry(&entry_record));
   1380     cache_->AddEntry(
   1381         entry_record.url,
   1382         AppCacheEntry(entry_record.flags, entry_record.response_id));
   1383     AppCacheDatabase::NamespaceRecord fallback_namespace_record;
   1384     fallback_namespace_record.cache_id = id;
   1385     fallback_namespace_record.namespace_.target_url = entry_record.url;
   1386     fallback_namespace_record.namespace_.namespace_url = kFallbackNamespace;
   1387     fallback_namespace_record.origin = manifest_url.GetOrigin();
   1388     EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record));
   1389     cache_->fallback_namespaces_.push_back(
   1390         Namespace(FALLBACK_NAMESPACE, kFallbackNamespace, kEntryUrl2, false));
   1391   }
   1392 
   1393   void Verify_FindMainResponseWithMultipleHits() {
   1394     EXPECT_EQ(kEntryUrl, delegate()->found_url_);
   1395     EXPECT_EQ(kManifestUrl3, delegate()->found_manifest_url_);
   1396     EXPECT_EQ(3, delegate()->found_cache_id_);
   1397     EXPECT_EQ(3, delegate()->found_group_id_);
   1398     EXPECT_EQ(3, delegate()->found_entry_.response_id());
   1399     EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
   1400     EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
   1401 
   1402     // Conduct another test perferring kManifestUrl
   1403     delegate_.reset(new MockStorageDelegate(this));
   1404     PushNextTask(base::Bind(
   1405         &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits2,
   1406         base::Unretained(this)));
   1407     storage()->FindResponseForMainRequest(kEntryUrl, kManifestUrl, delegate());
   1408     EXPECT_NE(kEntryUrl, delegate()->found_url_);
   1409   }
   1410 
   1411   void Verify_FindMainResponseWithMultipleHits2() {
   1412     EXPECT_EQ(kEntryUrl, delegate()->found_url_);
   1413     EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
   1414     EXPECT_EQ(1, delegate()->found_cache_id_);
   1415     EXPECT_EQ(1, delegate()->found_group_id_);
   1416     EXPECT_EQ(1, delegate()->found_entry_.response_id());
   1417     EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
   1418     EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
   1419 
   1420     // Conduct the another test perferring kManifestUrl2
   1421     delegate_.reset(new MockStorageDelegate(this));
   1422     PushNextTask(base::Bind(
   1423         &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits3,
   1424         base::Unretained(this)));
   1425     storage()->FindResponseForMainRequest(kEntryUrl, kManifestUrl2, delegate());
   1426     EXPECT_NE(kEntryUrl, delegate()->found_url_);
   1427   }
   1428 
   1429   void Verify_FindMainResponseWithMultipleHits3() {
   1430     EXPECT_EQ(kEntryUrl, delegate()->found_url_);
   1431     EXPECT_EQ(kManifestUrl2, delegate()->found_manifest_url_);
   1432     EXPECT_EQ(2, delegate()->found_cache_id_);
   1433     EXPECT_EQ(2, delegate()->found_group_id_);
   1434     EXPECT_EQ(2, delegate()->found_entry_.response_id());
   1435     EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
   1436     EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
   1437 
   1438     // Conduct another test with no preferred manifest that hits the fallback.
   1439     delegate_.reset(new MockStorageDelegate(this));
   1440     PushNextTask(base::Bind(
   1441         &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits4,
   1442         base::Unretained(this)));
   1443     storage()->FindResponseForMainRequest(
   1444         kFallbackTestUrl, GURL(), delegate());
   1445     EXPECT_NE(kFallbackTestUrl, delegate()->found_url_);
   1446   }
   1447 
   1448   void Verify_FindMainResponseWithMultipleHits4() {
   1449     EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_);
   1450     EXPECT_EQ(kManifestUrl3, delegate()->found_manifest_url_);
   1451     EXPECT_EQ(3, delegate()->found_cache_id_);
   1452     EXPECT_EQ(3, delegate()->found_group_id_);
   1453     EXPECT_FALSE(delegate()->found_entry_.has_response_id());
   1454     EXPECT_EQ(3 + kFallbackEntryIdOffset,
   1455               delegate()->found_fallback_entry_.response_id());
   1456     EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
   1457     EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
   1458 
   1459     // Conduct another test preferring kManifestUrl2 that hits the fallback.
   1460     delegate_.reset(new MockStorageDelegate(this));
   1461     PushNextTask(base::Bind(
   1462         &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits5,
   1463         base::Unretained(this)));
   1464     storage()->FindResponseForMainRequest(
   1465         kFallbackTestUrl, kManifestUrl2, delegate());
   1466     EXPECT_NE(kFallbackTestUrl, delegate()->found_url_);
   1467   }
   1468 
   1469   void Verify_FindMainResponseWithMultipleHits5() {
   1470     EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_);
   1471     EXPECT_EQ(kManifestUrl2, delegate()->found_manifest_url_);
   1472     EXPECT_EQ(2, delegate()->found_cache_id_);
   1473     EXPECT_EQ(2, delegate()->found_group_id_);
   1474     EXPECT_FALSE(delegate()->found_entry_.has_response_id());
   1475     EXPECT_EQ(2 + kFallbackEntryIdOffset,
   1476               delegate()->found_fallback_entry_.response_id());
   1477     EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
   1478     EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
   1479 
   1480     TestFinished();
   1481   }
   1482 
   1483   // FindMainResponseExclusions  -------------------------------
   1484 
   1485   void FindMainResponseExclusionsInDatabase() {
   1486     FindMainResponseExclusions(true);
   1487   }
   1488 
   1489   void FindMainResponseExclusionsInWorkingSet() {
   1490     FindMainResponseExclusions(false);
   1491   }
   1492 
   1493   void FindMainResponseExclusions(bool drop_from_working_set) {
   1494     // Setup some preconditions. Create a complete cache with a
   1495     // foreign entry, an online namespace, and a second online
   1496     // namespace nested within a fallback namespace.
   1497     MakeCacheAndGroup(kManifestUrl, 1, 1, true);
   1498     cache_->AddEntry(kEntryUrl,
   1499         AppCacheEntry(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN, 1));
   1500     cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::FALLBACK, 2));
   1501     cache_->fallback_namespaces_.push_back(
   1502         Namespace(FALLBACK_NAMESPACE, kFallbackNamespace, kEntryUrl2, false));
   1503     cache_->online_whitelist_namespaces_.push_back(
   1504         Namespace(NETWORK_NAMESPACE, kOnlineNamespace,
   1505                   GURL(), false));
   1506     cache_->online_whitelist_namespaces_.push_back(
   1507         Namespace(NETWORK_NAMESPACE, kOnlineNamespaceWithinFallback,
   1508                   GURL(), false));
   1509 
   1510     AppCacheDatabase::EntryRecord entry_record;
   1511     entry_record.cache_id = 1;
   1512     entry_record.url = kEntryUrl;
   1513     entry_record.flags = AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN;
   1514     entry_record.response_id = 1;
   1515     EXPECT_TRUE(database()->InsertEntry(&entry_record));
   1516     AppCacheDatabase::OnlineWhiteListRecord whitelist_record;
   1517     whitelist_record.cache_id = 1;
   1518     whitelist_record.namespace_url = kOnlineNamespace;
   1519     EXPECT_TRUE(database()->InsertOnlineWhiteList(&whitelist_record));
   1520     AppCacheDatabase::NamespaceRecord fallback_namespace_record;
   1521     fallback_namespace_record.cache_id = 1;
   1522     fallback_namespace_record.namespace_.target_url = kEntryUrl2;
   1523     fallback_namespace_record.namespace_.namespace_url = kFallbackNamespace;
   1524     fallback_namespace_record.origin = kManifestUrl.GetOrigin();
   1525     EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record));
   1526     whitelist_record.cache_id = 1;
   1527     whitelist_record.namespace_url = kOnlineNamespaceWithinFallback;
   1528     EXPECT_TRUE(database()->InsertOnlineWhiteList(&whitelist_record));
   1529     if (drop_from_working_set) {
   1530       cache_ = NULL;
   1531       group_ = NULL;
   1532     }
   1533 
   1534     // We should not find anything for the foreign entry.
   1535     PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_ExclusionNotFound,
   1536                             base::Unretained(this), kEntryUrl, 1));
   1537     storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
   1538   }
   1539 
   1540   void Verify_ExclusionNotFound(GURL expected_url, int phase) {
   1541     EXPECT_EQ(expected_url, delegate()->found_url_);
   1542     EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
   1543     EXPECT_EQ(kNoCacheId, delegate()->found_cache_id_);
   1544     EXPECT_EQ(0, delegate()->found_group_id_);
   1545     EXPECT_EQ(kNoResponseId, delegate()->found_entry_.response_id());
   1546     EXPECT_EQ(kNoResponseId, delegate()->found_fallback_entry_.response_id());
   1547     EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
   1548     EXPECT_EQ(0, delegate()->found_entry_.types());
   1549     EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
   1550 
   1551     if (phase == 1) {
   1552       // We should not find anything for the online namespace.
   1553       PushNextTask(
   1554           base::Bind(&AppCacheStorageImplTest::Verify_ExclusionNotFound,
   1555                      base::Unretained(this), kOnlineNamespace, 2));
   1556       storage()->FindResponseForMainRequest(
   1557           kOnlineNamespace, GURL(), delegate());
   1558       return;
   1559     }
   1560     if (phase == 2) {
   1561       // We should not find anything for the online namespace nested within
   1562       // the fallback namespace.
   1563       PushNextTask(base::Bind(
   1564           &AppCacheStorageImplTest::Verify_ExclusionNotFound,
   1565           base::Unretained(this), kOnlineNamespaceWithinFallback, 3));
   1566       storage()->FindResponseForMainRequest(
   1567           kOnlineNamespaceWithinFallback, GURL(), delegate());
   1568       return;
   1569     }
   1570 
   1571     TestFinished();
   1572   }
   1573 
   1574   // Reinitialize  -------------------------------
   1575   // This test is somewhat of a system integration test.
   1576   // It relies on running a mock http server on our IO thread,
   1577   // and involves other appcache classes to get some code
   1578   // coverage thruout when Reinitialize happens.
   1579 
   1580   class MockServiceObserver : public AppCacheService::Observer {
   1581    public:
   1582     explicit MockServiceObserver(AppCacheStorageImplTest* test)
   1583         : test_(test) {}
   1584 
   1585     virtual void OnServiceReinitialized(
   1586         AppCacheStorageReference* old_storage_ref) OVERRIDE {
   1587       observed_old_storage_ = old_storage_ref;
   1588       test_->ScheduleNextTask();
   1589     }
   1590 
   1591     scoped_refptr<AppCacheStorageReference> observed_old_storage_;
   1592     AppCacheStorageImplTest* test_;
   1593   };
   1594 
   1595   class MockAppCacheFrontend : public AppCacheFrontend {
   1596    public:
   1597     MockAppCacheFrontend() : error_event_was_raised_(false) {}
   1598 
   1599     virtual void OnCacheSelected(
   1600         int host_id, const appcache::AppCacheInfo& info) OVERRIDE {}
   1601     virtual void OnStatusChanged(const std::vector<int>& host_ids,
   1602                                  Status status) OVERRIDE {}
   1603     virtual void OnEventRaised(const std::vector<int>& host_ids,
   1604                                EventID event_id) OVERRIDE {}
   1605     virtual void OnProgressEventRaised(
   1606         const std::vector<int>& host_ids,
   1607         const GURL& url,
   1608         int num_total, int num_complete) OVERRIDE {}
   1609     virtual void OnErrorEventRaised(const std::vector<int>& host_ids,
   1610                                     const std::string& message) OVERRIDE {
   1611       error_event_was_raised_ = true;
   1612     }
   1613     virtual void OnLogMessage(int host_id, LogLevel log_level,
   1614                               const std::string& message) OVERRIDE {}
   1615     virtual void OnContentBlocked(
   1616         int host_id, const GURL& manifest_url) OVERRIDE {}
   1617 
   1618     bool error_event_was_raised_;
   1619   };
   1620 
   1621   void Reinitialize1() {
   1622     Reinitialize(1);
   1623   }
   1624 
   1625   void Reinitialize2() {
   1626     Reinitialize(2);
   1627   }
   1628 
   1629   void Reinitialize(int test_case) {
   1630     // Unlike all of the other tests, this one actually read/write files.
   1631     ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
   1632 
   1633     // Create a corrupt/unopenable disk_cache index file.
   1634     const std::string kCorruptData("deadbeef");
   1635     base::FilePath disk_cache_directory =
   1636         temp_directory_.path().AppendASCII("Cache");
   1637     ASSERT_TRUE(base::CreateDirectory(disk_cache_directory));
   1638     base::FilePath index_file = disk_cache_directory.AppendASCII("index");
   1639     EXPECT_EQ(static_cast<int>(kCorruptData.length()),
   1640               file_util::WriteFile(
   1641                   index_file, kCorruptData.data(), kCorruptData.length()));
   1642 
   1643     // Create records for a degenerate cached manifest that only contains
   1644     // one entry for the manifest file resource.
   1645     if (test_case == 2) {
   1646       AppCacheDatabase db(temp_directory_.path().AppendASCII("Index"));
   1647       GURL manifest_url = MockHttpServer::GetMockUrl("manifest");
   1648 
   1649       AppCacheDatabase::GroupRecord group_record;
   1650       group_record.group_id = 1;
   1651       group_record.manifest_url = manifest_url;
   1652       group_record.origin = manifest_url.GetOrigin();
   1653       EXPECT_TRUE(db.InsertGroup(&group_record));
   1654       AppCacheDatabase::CacheRecord cache_record;
   1655       cache_record.cache_id = 1;
   1656       cache_record.group_id = 1;
   1657       cache_record.online_wildcard = false;
   1658       cache_record.update_time = kZeroTime;
   1659       cache_record.cache_size = kDefaultEntrySize;
   1660       EXPECT_TRUE(db.InsertCache(&cache_record));
   1661       AppCacheDatabase::EntryRecord entry_record;
   1662       entry_record.cache_id = 1;
   1663       entry_record.url = manifest_url;
   1664       entry_record.flags = AppCacheEntry::MANIFEST;
   1665       entry_record.response_id = 1;
   1666       entry_record.response_size = kDefaultEntrySize;
   1667       EXPECT_TRUE(db.InsertEntry(&entry_record));
   1668     }
   1669 
   1670     // Recreate the service to point at the db and corruption on disk.
   1671     service_.reset(new AppCacheService(NULL));
   1672     service_->set_request_context(io_thread->request_context());
   1673     service_->Initialize(
   1674         temp_directory_.path(),
   1675         db_thread->message_loop_proxy().get(),
   1676         db_thread->message_loop_proxy().get());
   1677     mock_quota_manager_proxy_ = new MockQuotaManagerProxy();
   1678     service_->quota_manager_proxy_ = mock_quota_manager_proxy_;
   1679     delegate_.reset(new MockStorageDelegate(this));
   1680 
   1681     // Additional setup to observe reinitailize happens.
   1682     observer_.reset(new MockServiceObserver(this));
   1683     service_->AddObserver(observer_.get());
   1684 
   1685     // We continue after the init task is complete including the callback
   1686     // on the current thread.
   1687     FlushDbThreadTasks();
   1688     base::MessageLoop::current()->PostTask(
   1689         FROM_HERE,
   1690         base::Bind(&AppCacheStorageImplTest::Continue_Reinitialize,
   1691                    base::Unretained(this),
   1692                    test_case));
   1693   }
   1694 
   1695   void Continue_Reinitialize(int test_case) {
   1696     const int kMockProcessId = 1;
   1697     backend_.reset(new AppCacheBackendImpl);
   1698     backend_->Initialize(service_.get(), &frontend_, kMockProcessId);
   1699 
   1700     if (test_case == 1) {
   1701       // Try to create a new appcache, the resulting update job will
   1702       // eventually fail when it gets to disk cache initialization.
   1703       backend_->RegisterHost(1);
   1704       AppCacheHost* host1 = backend_->GetHost(1);
   1705       const GURL kEmptyPageUrl(MockHttpServer::GetMockUrl("empty.html"));
   1706       host1->first_party_url_ = kEmptyPageUrl;
   1707       host1->SelectCache(kEmptyPageUrl,
   1708                          kNoCacheId,
   1709                          MockHttpServer::GetMockUrl("manifest"));
   1710     } else {
   1711       ASSERT_EQ(2, test_case);
   1712       // Try to access the existing cache manifest.
   1713       // The URLRequestJob  will eventually fail when it gets to disk
   1714       // cache initialization.
   1715       backend_->RegisterHost(2);
   1716       AppCacheHost* host2 = backend_->GetHost(2);
   1717       GURL manifest_url = MockHttpServer::GetMockUrl("manifest");
   1718       request_ = service()->request_context()->CreateRequest(
   1719           manifest_url, net::DEFAULT_PRIORITY, NULL);
   1720       AppCacheInterceptor::SetExtraRequestInfo(
   1721           request_.get(), service_.get(),
   1722           backend_->process_id(), host2->host_id(),
   1723           ResourceType::MAIN_FRAME);
   1724       request_->Start();
   1725     }
   1726 
   1727     PushNextTask(base::Bind(
   1728         &AppCacheStorageImplTest::Verify_Reinitialized,
   1729         base::Unretained(this),
   1730         test_case));
   1731   }
   1732 
   1733   void Verify_Reinitialized(int test_case) {
   1734     // Verify we got notified of reinit and a new storage instance is created,
   1735     // and that the old data has been deleted.
   1736     EXPECT_TRUE(observer_->observed_old_storage_.get());
   1737     EXPECT_TRUE(observer_->observed_old_storage_->storage() != storage());
   1738     EXPECT_FALSE(PathExists(
   1739         temp_directory_.path().AppendASCII("Cache").AppendASCII("index")));
   1740     EXPECT_FALSE(PathExists(
   1741         temp_directory_.path().AppendASCII("Index")));
   1742 
   1743     // Verify that the hosts saw appropriate events.
   1744     if (test_case == 1) {
   1745       EXPECT_TRUE(frontend_.error_event_was_raised_);
   1746       AppCacheHost* host1 = backend_->GetHost(1);
   1747       EXPECT_FALSE(host1->associated_cache());
   1748       EXPECT_FALSE(host1->group_being_updated_);
   1749       EXPECT_TRUE(host1->disabled_storage_reference_.get());
   1750     } else {
   1751       ASSERT_EQ(2, test_case);
   1752       AppCacheHost* host2 = backend_->GetHost(2);
   1753       EXPECT_EQ(1, host2->main_resource_cache_->cache_id());
   1754       EXPECT_TRUE(host2->disabled_storage_reference_.get());
   1755     }
   1756 
   1757     // Cleanup and claim victory.
   1758     service_->RemoveObserver(observer_.get());
   1759     request_.reset();
   1760     backend_.reset();
   1761     observer_.reset();
   1762     TestFinished();
   1763   }
   1764 
   1765   // Test case helpers --------------------------------------------------
   1766 
   1767   AppCacheService* service() {
   1768     return service_.get();
   1769   }
   1770 
   1771   AppCacheStorageImpl* storage() {
   1772     return static_cast<AppCacheStorageImpl*>(service()->storage());
   1773   }
   1774 
   1775   AppCacheDatabase* database() {
   1776     return storage()->database_;
   1777   }
   1778 
   1779   MockStorageDelegate* delegate() {
   1780     return delegate_.get();
   1781   }
   1782 
   1783   void MakeCacheAndGroup(
   1784       const GURL& manifest_url, int64 group_id, int64 cache_id,
   1785       bool add_to_database) {
   1786     AppCacheEntry default_entry(
   1787         AppCacheEntry::EXPLICIT, cache_id + kDefaultEntryIdOffset,
   1788         kDefaultEntrySize);
   1789     group_ = new AppCacheGroup(storage(), manifest_url, group_id);
   1790     cache_ = new AppCache(storage(), cache_id);
   1791     cache_->AddEntry(kDefaultEntryUrl, default_entry);
   1792     cache_->set_complete(true);
   1793     group_->AddCache(cache_.get());
   1794     if (add_to_database) {
   1795       AppCacheDatabase::GroupRecord group_record;
   1796       group_record.group_id = group_id;
   1797       group_record.manifest_url = manifest_url;
   1798       group_record.origin = manifest_url.GetOrigin();
   1799       EXPECT_TRUE(database()->InsertGroup(&group_record));
   1800       AppCacheDatabase::CacheRecord cache_record;
   1801       cache_record.cache_id = cache_id;
   1802       cache_record.group_id = group_id;
   1803       cache_record.online_wildcard = false;
   1804       cache_record.update_time = kZeroTime;
   1805       cache_record.cache_size = kDefaultEntrySize;
   1806       EXPECT_TRUE(database()->InsertCache(&cache_record));
   1807       AppCacheDatabase::EntryRecord entry_record;
   1808       entry_record.cache_id = cache_id;
   1809       entry_record.url = kDefaultEntryUrl;
   1810       entry_record.flags = default_entry.types();
   1811       entry_record.response_id = default_entry.response_id();
   1812       entry_record.response_size = default_entry.response_size();
   1813       EXPECT_TRUE(database()->InsertEntry(&entry_record));
   1814 
   1815       storage()->usage_map_[manifest_url.GetOrigin()] =
   1816           default_entry.response_size();
   1817     }
   1818   }
   1819 
   1820   // Data members --------------------------------------------------
   1821 
   1822   scoped_ptr<base::WaitableEvent> test_finished_event_;
   1823   std::stack<base::Closure> task_stack_;
   1824   scoped_ptr<AppCacheService> service_;
   1825   scoped_ptr<MockStorageDelegate> delegate_;
   1826   scoped_refptr<MockQuotaManagerProxy> mock_quota_manager_proxy_;
   1827   scoped_refptr<AppCacheGroup> group_;
   1828   scoped_refptr<AppCache> cache_;
   1829   scoped_refptr<AppCache> cache2_;
   1830 
   1831   // Specifically for the Reinitalize test.
   1832   base::ScopedTempDir temp_directory_;
   1833   scoped_ptr<MockServiceObserver> observer_;
   1834   MockAppCacheFrontend frontend_;
   1835   scoped_ptr<AppCacheBackendImpl> backend_;
   1836   scoped_ptr<net::URLRequest> request_;
   1837 };
   1838 
   1839 
   1840 TEST_F(AppCacheStorageImplTest, LoadCache_Miss) {
   1841   RunTestOnIOThread(&AppCacheStorageImplTest::LoadCache_Miss);
   1842 }
   1843 
   1844 TEST_F(AppCacheStorageImplTest, LoadCache_NearHit) {
   1845   RunTestOnIOThread(&AppCacheStorageImplTest::LoadCache_NearHit);
   1846 }
   1847 
   1848 TEST_F(AppCacheStorageImplTest, CreateGroupInEmptyOrigin) {
   1849   RunTestOnIOThread(&AppCacheStorageImplTest::CreateGroupInEmptyOrigin);
   1850 }
   1851 
   1852 TEST_F(AppCacheStorageImplTest, CreateGroupInPopulatedOrigin) {
   1853   RunTestOnIOThread(&AppCacheStorageImplTest::CreateGroupInPopulatedOrigin);
   1854 }
   1855 
   1856 TEST_F(AppCacheStorageImplTest, LoadGroupAndCache_FarHit) {
   1857   RunTestOnIOThread(&AppCacheStorageImplTest::LoadGroupAndCache_FarHit);
   1858 }
   1859 
   1860 TEST_F(AppCacheStorageImplTest, StoreNewGroup) {
   1861   RunTestOnIOThread(&AppCacheStorageImplTest::StoreNewGroup);
   1862 }
   1863 
   1864 TEST_F(AppCacheStorageImplTest, StoreExistingGroup) {
   1865   RunTestOnIOThread(&AppCacheStorageImplTest::StoreExistingGroup);
   1866 }
   1867 
   1868 TEST_F(AppCacheStorageImplTest, StoreExistingGroupExistingCache) {
   1869   RunTestOnIOThread(&AppCacheStorageImplTest::StoreExistingGroupExistingCache);
   1870 }
   1871 
   1872 TEST_F(AppCacheStorageImplTest, FailStoreGroup) {
   1873   RunTestOnIOThread(&AppCacheStorageImplTest::FailStoreGroup);
   1874 }
   1875 
   1876 TEST_F(AppCacheStorageImplTest, MakeGroupObsolete) {
   1877   RunTestOnIOThread(&AppCacheStorageImplTest::MakeGroupObsolete);
   1878 }
   1879 
   1880 TEST_F(AppCacheStorageImplTest, MarkEntryAsForeign) {
   1881   RunTestOnIOThread(&AppCacheStorageImplTest::MarkEntryAsForeign);
   1882 }
   1883 
   1884 TEST_F(AppCacheStorageImplTest, MarkEntryAsForeignWithLoadInProgress) {
   1885   RunTestOnIOThread(
   1886       &AppCacheStorageImplTest::MarkEntryAsForeignWithLoadInProgress);
   1887 }
   1888 
   1889 TEST_F(AppCacheStorageImplTest, FindNoMainResponse) {
   1890   RunTestOnIOThread(&AppCacheStorageImplTest::FindNoMainResponse);
   1891 }
   1892 
   1893 TEST_F(AppCacheStorageImplTest, BasicFindMainResponseInDatabase) {
   1894   RunTestOnIOThread(
   1895       &AppCacheStorageImplTest::BasicFindMainResponseInDatabase);
   1896 }
   1897 
   1898 TEST_F(AppCacheStorageImplTest, BasicFindMainResponseInWorkingSet) {
   1899   RunTestOnIOThread(
   1900       &AppCacheStorageImplTest::BasicFindMainResponseInWorkingSet);
   1901 }
   1902 
   1903 TEST_F(AppCacheStorageImplTest, BasicFindMainFallbackResponseInDatabase) {
   1904   RunTestOnIOThread(
   1905       &AppCacheStorageImplTest::BasicFindMainFallbackResponseInDatabase);
   1906 }
   1907 
   1908 TEST_F(AppCacheStorageImplTest, BasicFindMainFallbackResponseInWorkingSet) {
   1909   RunTestOnIOThread(
   1910       &AppCacheStorageImplTest::BasicFindMainFallbackResponseInWorkingSet);
   1911 }
   1912 
   1913 TEST_F(AppCacheStorageImplTest, BasicFindMainInterceptResponseInDatabase) {
   1914   RunTestOnIOThread(
   1915       &AppCacheStorageImplTest::BasicFindMainInterceptResponseInDatabase);
   1916 }
   1917 
   1918 TEST_F(AppCacheStorageImplTest, BasicFindMainInterceptResponseInWorkingSet) {
   1919   RunTestOnIOThread(
   1920       &AppCacheStorageImplTest::BasicFindMainInterceptResponseInWorkingSet);
   1921 }
   1922 
   1923 TEST_F(AppCacheStorageImplTest, FindMainResponseWithMultipleHits) {
   1924   RunTestOnIOThread(
   1925       &AppCacheStorageImplTest::FindMainResponseWithMultipleHits);
   1926 }
   1927 
   1928 TEST_F(AppCacheStorageImplTest, FindMainResponseExclusionsInDatabase) {
   1929   RunTestOnIOThread(
   1930       &AppCacheStorageImplTest::FindMainResponseExclusionsInDatabase);
   1931 }
   1932 
   1933 TEST_F(AppCacheStorageImplTest, FindMainResponseExclusionsInWorkingSet) {
   1934   RunTestOnIOThread(
   1935       &AppCacheStorageImplTest::FindMainResponseExclusionsInWorkingSet);
   1936 }
   1937 
   1938 TEST_F(AppCacheStorageImplTest, FindInterceptPatternMatchInWorkingSet) {
   1939   RunTestOnIOThread(
   1940       &AppCacheStorageImplTest::FindInterceptPatternMatchInWorkingSet);
   1941 }
   1942 
   1943 TEST_F(AppCacheStorageImplTest, FindInterceptPatternMatchInDatabase) {
   1944   RunTestOnIOThread(
   1945       &AppCacheStorageImplTest::FindInterceptPatternMatchInDatabase);
   1946 }
   1947 
   1948 TEST_F(AppCacheStorageImplTest, FindFallbackPatternMatchInWorkingSet) {
   1949   RunTestOnIOThread(
   1950       &AppCacheStorageImplTest::FindFallbackPatternMatchInWorkingSet);
   1951 }
   1952 
   1953 TEST_F(AppCacheStorageImplTest, FindFallbackPatternMatchInDatabase) {
   1954   RunTestOnIOThread(
   1955       &AppCacheStorageImplTest::FindFallbackPatternMatchInDatabase);
   1956 }
   1957 
   1958 TEST_F(AppCacheStorageImplTest, Reinitialize1) {
   1959   RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize1);
   1960 }
   1961 
   1962 TEST_F(AppCacheStorageImplTest, Reinitialize2) {
   1963   RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize2);
   1964 }
   1965 
   1966 // That's all folks!
   1967 
   1968 }  // namespace appcache
   1969