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