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