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