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