[MacViews] Show comboboxes with a native NSMenu
[chromium-blink-merge.git] / content / browser / appcache / appcache_storage_impl_unittest.cc
blob669db8c82076cc655f60927e30083136880287e7
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", make_scoped_ptr(new MockHttpServerJobFactory(
167 make_scoped_ptr(new AppCacheInterceptor()))));
168 job_factory_ = factory.Pass();
169 request_context_.reset(new net::TestURLRequestContext());
170 request_context_->set_job_factory(job_factory_.get());
173 void CleanUp() override {
174 request_context_.reset();
175 job_factory_.reset();
178 private:
179 scoped_ptr<net::URLRequestJobFactory> job_factory_;
180 scoped_ptr<net::URLRequestContext> request_context_;
183 scoped_ptr<IOThread> io_thread;
184 scoped_ptr<base::Thread> db_thread;
186 } // namespace
188 class AppCacheStorageImplTest : public testing::Test {
189 public:
190 class MockStorageDelegate : public AppCacheStorage::Delegate {
191 public:
192 explicit MockStorageDelegate(AppCacheStorageImplTest* test)
193 : loaded_cache_id_(0), stored_group_success_(false),
194 would_exceed_quota_(false), obsoleted_success_(false),
195 found_cache_id_(kAppCacheNoCacheId), test_(test) {
198 void OnCacheLoaded(AppCache* cache, int64 cache_id) override {
199 loaded_cache_ = cache;
200 loaded_cache_id_ = cache_id;
201 test_->ScheduleNextTask();
204 void OnGroupLoaded(AppCacheGroup* group,
205 const GURL& manifest_url) override {
206 loaded_group_ = group;
207 loaded_manifest_url_ = manifest_url;
208 loaded_groups_newest_cache_ = group ? group->newest_complete_cache()
209 : NULL;
210 test_->ScheduleNextTask();
213 void OnGroupAndNewestCacheStored(AppCacheGroup* group,
214 AppCache* newest_cache,
215 bool success,
216 bool would_exceed_quota) override {
217 stored_group_ = group;
218 stored_group_success_ = success;
219 would_exceed_quota_ = would_exceed_quota;
220 test_->ScheduleNextTask();
223 void OnGroupMadeObsolete(AppCacheGroup* group,
224 bool success,
225 int response_code) override {
226 obsoleted_group_ = group;
227 obsoleted_success_ = success;
228 test_->ScheduleNextTask();
231 void OnMainResponseFound(const GURL& url,
232 const AppCacheEntry& entry,
233 const GURL& namespace_entry_url,
234 const AppCacheEntry& fallback_entry,
235 int64 cache_id,
236 int64 group_id,
237 const GURL& manifest_url) override {
238 found_url_ = url;
239 found_entry_ = entry;
240 found_namespace_entry_url_ = namespace_entry_url;
241 found_fallback_entry_ = fallback_entry;
242 found_cache_id_ = cache_id;
243 found_group_id_ = group_id;
244 found_manifest_url_ = manifest_url;
245 test_->ScheduleNextTask();
248 scoped_refptr<AppCache> loaded_cache_;
249 int64 loaded_cache_id_;
250 scoped_refptr<AppCacheGroup> loaded_group_;
251 GURL loaded_manifest_url_;
252 scoped_refptr<AppCache> loaded_groups_newest_cache_;
253 scoped_refptr<AppCacheGroup> stored_group_;
254 bool stored_group_success_;
255 bool would_exceed_quota_;
256 scoped_refptr<AppCacheGroup> obsoleted_group_;
257 bool obsoleted_success_;
258 GURL found_url_;
259 AppCacheEntry found_entry_;
260 GURL found_namespace_entry_url_;
261 AppCacheEntry found_fallback_entry_;
262 int64 found_cache_id_;
263 int64 found_group_id_;
264 GURL found_manifest_url_;
265 AppCacheStorageImplTest* test_;
268 class MockQuotaManager : public storage::QuotaManager {
269 public:
270 MockQuotaManager()
271 : QuotaManager(true /* is_incognito */,
272 base::FilePath(),
273 io_thread->task_runner().get(),
274 db_thread->task_runner().get(),
275 NULL),
276 async_(false) {}
278 void GetUsageAndQuota(const GURL& origin,
279 storage::StorageType type,
280 const GetUsageAndQuotaCallback& callback) override {
281 EXPECT_EQ(storage::kStorageTypeTemporary, type);
282 if (async_) {
283 base::ThreadTaskRunnerHandle::Get()->PostTask(
284 FROM_HERE, base::Bind(&MockQuotaManager::CallCallback,
285 base::Unretained(this), callback));
286 return;
288 CallCallback(callback);
291 void CallCallback(const GetUsageAndQuotaCallback& callback) {
292 callback.Run(storage::kQuotaStatusOk, 0, kMockQuota);
295 bool async_;
297 protected:
298 ~MockQuotaManager() override {}
301 class MockQuotaManagerProxy : public storage::QuotaManagerProxy {
302 public:
303 MockQuotaManagerProxy()
304 : QuotaManagerProxy(NULL, NULL),
305 notify_storage_accessed_count_(0),
306 notify_storage_modified_count_(0),
307 last_delta_(0),
308 mock_manager_(new MockQuotaManager) {
309 manager_ = mock_manager_.get();
312 void NotifyStorageAccessed(storage::QuotaClient::ID client_id,
313 const GURL& origin,
314 storage::StorageType type) override {
315 EXPECT_EQ(storage::QuotaClient::kAppcache, client_id);
316 EXPECT_EQ(storage::kStorageTypeTemporary, type);
317 ++notify_storage_accessed_count_;
318 last_origin_ = origin;
321 void NotifyStorageModified(storage::QuotaClient::ID client_id,
322 const GURL& origin,
323 storage::StorageType type,
324 int64 delta) override {
325 EXPECT_EQ(storage::QuotaClient::kAppcache, client_id);
326 EXPECT_EQ(storage::kStorageTypeTemporary, type);
327 ++notify_storage_modified_count_;
328 last_origin_ = origin;
329 last_delta_ = delta;
332 // Not needed for our tests.
333 void RegisterClient(storage::QuotaClient* client) override {}
334 void NotifyOriginInUse(const GURL& origin) override {}
335 void NotifyOriginNoLongerInUse(const GURL& origin) override {}
336 void SetUsageCacheEnabled(storage::QuotaClient::ID client_id,
337 const GURL& origin,
338 storage::StorageType type,
339 bool enabled) override {}
340 void GetUsageAndQuota(base::SequencedTaskRunner* original_task_runner,
341 const GURL& origin,
342 storage::StorageType type,
343 const GetUsageAndQuotaCallback& callback) override {}
345 int notify_storage_accessed_count_;
346 int notify_storage_modified_count_;
347 GURL last_origin_;
348 int last_delta_;
349 scoped_refptr<MockQuotaManager> mock_manager_;
351 protected:
352 ~MockQuotaManagerProxy() override {}
355 template <class Method>
356 void RunMethod(Method method) {
357 (this->*method)();
360 // Helper callback to run a test on our io_thread. The io_thread is spun up
361 // once and reused for all tests.
362 template <class Method>
363 void MethodWrapper(Method method) {
364 SetUpTest();
366 // Ensure InitTask execution prior to conducting a test.
367 FlushDbThreadTasks();
369 // We also have to wait for InitTask completion call to be performed
370 // on the IO thread prior to running the test. Its guaranteed to be
371 // queued by this time.
372 base::ThreadTaskRunnerHandle::Get()->PostTask(
373 FROM_HERE, base::Bind(&AppCacheStorageImplTest::RunMethod<Method>,
374 base::Unretained(this), method));
377 static void SetUpTestCase() {
378 // We start both threads as TYPE_IO because we also use the db_thead
379 // for the disk_cache which needs to be of TYPE_IO.
380 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
381 io_thread.reset(new IOThread("AppCacheTest.IOThread"));
382 ASSERT_TRUE(io_thread->StartWithOptions(options));
383 db_thread.reset(new base::Thread("AppCacheTest::DBThread"));
384 ASSERT_TRUE(db_thread->StartWithOptions(options));
387 static void TearDownTestCase() {
388 io_thread.reset(NULL);
389 db_thread.reset(NULL);
392 // Test harness --------------------------------------------------
394 AppCacheStorageImplTest() {
397 template <class Method>
398 void RunTestOnIOThread(Method method) {
399 test_finished_event_ .reset(new base::WaitableEvent(false, false));
400 io_thread->task_runner()->PostTask(
401 FROM_HERE, base::Bind(&AppCacheStorageImplTest::MethodWrapper<Method>,
402 base::Unretained(this), method));
403 test_finished_event_->Wait();
406 void SetUpTest() {
407 DCHECK(base::MessageLoop::current() == io_thread->message_loop());
408 service_.reset(new AppCacheServiceImpl(NULL));
409 service_->Initialize(base::FilePath(), db_thread->task_runner(), NULL);
410 mock_quota_manager_proxy_ = new MockQuotaManagerProxy();
411 service_->quota_manager_proxy_ = mock_quota_manager_proxy_;
412 delegate_.reset(new MockStorageDelegate(this));
415 void TearDownTest() {
416 DCHECK(base::MessageLoop::current() == io_thread->message_loop());
417 storage()->CancelDelegateCallbacks(delegate());
418 group_ = NULL;
419 cache_ = NULL;
420 cache2_ = NULL;
421 mock_quota_manager_proxy_ = NULL;
422 delegate_.reset();
423 service_.reset();
424 FlushDbThreadTasks();
427 void TestFinished() {
428 // We unwind the stack prior to finishing up to let stack
429 // based objects get deleted.
430 DCHECK(base::MessageLoop::current() == io_thread->message_loop());
431 base::ThreadTaskRunnerHandle::Get()->PostTask(
432 FROM_HERE, base::Bind(&AppCacheStorageImplTest::TestFinishedUnwound,
433 base::Unretained(this)));
436 void TestFinishedUnwound() {
437 TearDownTest();
438 test_finished_event_->Signal();
441 void PushNextTask(const base::Closure& task) {
442 task_stack_.push(task);
445 void ScheduleNextTask() {
446 DCHECK(base::MessageLoop::current() == io_thread->message_loop());
447 if (task_stack_.empty()) {
448 return;
450 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task_stack_.top());
451 task_stack_.pop();
454 static void SignalEvent(base::WaitableEvent* event) {
455 event->Signal();
458 void FlushDbThreadTasks() {
459 // We pump a task thru the db thread to ensure any tasks previously
460 // scheduled on that thread have been performed prior to return.
461 base::WaitableEvent event(false, false);
462 db_thread->task_runner()->PostTask(
463 FROM_HERE, base::Bind(&AppCacheStorageImplTest::SignalEvent, &event));
464 event.Wait();
467 // LoadCache_Miss ----------------------------------------------------
469 void LoadCache_Miss() {
470 // Attempt to load a cache that doesn't exist. Should
471 // complete asynchronously.
472 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadCache_Miss,
473 base::Unretained(this)));
475 storage()->LoadCache(111, delegate());
476 EXPECT_NE(111, delegate()->loaded_cache_id_);
479 void Verify_LoadCache_Miss() {
480 EXPECT_EQ(111, delegate()->loaded_cache_id_);
481 EXPECT_FALSE(delegate()->loaded_cache_.get());
482 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
483 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
484 TestFinished();
487 // LoadCache_NearHit -------------------------------------------------
489 void LoadCache_NearHit() {
490 // Attempt to load a cache that is currently in use
491 // and does not require loading from storage. This
492 // load should complete syncly.
494 // Setup some preconditions. Make an 'unstored' cache for
495 // us to load. The ctor should put it in the working set.
496 int64 cache_id = storage()->NewCacheId();
497 scoped_refptr<AppCache> cache(new AppCache(storage(), cache_id));
499 // Conduct the test.
500 storage()->LoadCache(cache_id, delegate());
501 EXPECT_EQ(cache_id, delegate()->loaded_cache_id_);
502 EXPECT_EQ(cache.get(), delegate()->loaded_cache_.get());
503 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
504 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
505 TestFinished();
508 // CreateGroup --------------------------------------------
510 void CreateGroupInEmptyOrigin() {
511 // Attempt to load a group that doesn't exist, one should
512 // be created for us, but not stored.
514 // Since the origin has no groups, the storage class will respond
515 // syncly.
516 storage()->LoadOrCreateGroup(kManifestUrl, delegate());
517 Verify_CreateGroup();
520 void CreateGroupInPopulatedOrigin() {
521 // Attempt to load a group that doesn't exist, one should
522 // be created for us, but not stored.
523 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_CreateGroup,
524 base::Unretained(this)));
526 // Since the origin has groups, storage class will have to
527 // consult the database and completion will be async.
528 storage()->usage_map_[kOrigin] = kDefaultEntrySize;
530 storage()->LoadOrCreateGroup(kManifestUrl, delegate());
531 EXPECT_FALSE(delegate()->loaded_group_.get());
534 void Verify_CreateGroup() {
535 EXPECT_EQ(kManifestUrl, delegate()->loaded_manifest_url_);
536 EXPECT_TRUE(delegate()->loaded_group_.get());
537 EXPECT_TRUE(delegate()->loaded_group_->HasOneRef());
538 EXPECT_FALSE(delegate()->loaded_group_->newest_complete_cache());
540 // Should not have been stored in the database.
541 AppCacheDatabase::GroupRecord record;
542 EXPECT_FALSE(database()->FindGroup(
543 delegate()->loaded_group_->group_id(), &record));
545 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
546 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
548 TestFinished();
551 // LoadGroupAndCache_FarHit --------------------------------------
553 void LoadGroupAndCache_FarHit() {
554 // Attempt to load a cache that is not currently in use
555 // and does require loading from disk. This
556 // load should complete asynchronously.
557 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadCache_Far_Hit,
558 base::Unretained(this)));
560 // Setup some preconditions. Create a group and newest cache that
561 // appear to be "stored" and "not currently in use".
562 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
563 group_ = NULL;
564 cache_ = NULL;
566 // Conduct the cache load test, completes async
567 storage()->LoadCache(1, delegate());
570 void Verify_LoadCache_Far_Hit() {
571 EXPECT_TRUE(delegate()->loaded_cache_.get());
572 EXPECT_TRUE(delegate()->loaded_cache_->HasOneRef());
573 EXPECT_EQ(1, delegate()->loaded_cache_id_);
575 // The group should also have been loaded.
576 EXPECT_TRUE(delegate()->loaded_cache_->owning_group());
577 EXPECT_TRUE(delegate()->loaded_cache_->owning_group()->HasOneRef());
578 EXPECT_EQ(1, delegate()->loaded_cache_->owning_group()->group_id());
580 EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_accessed_count_);
581 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
583 // Drop things from the working set.
584 delegate()->loaded_cache_ = NULL;
585 EXPECT_FALSE(delegate()->loaded_group_.get());
587 // Conduct the group load test, also complete asynchronously.
588 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadGroup_Far_Hit,
589 base::Unretained(this)));
591 storage()->LoadOrCreateGroup(kManifestUrl, delegate());
594 void Verify_LoadGroup_Far_Hit() {
595 EXPECT_TRUE(delegate()->loaded_group_.get());
596 EXPECT_EQ(kManifestUrl, delegate()->loaded_manifest_url_);
597 EXPECT_TRUE(delegate()->loaded_group_->newest_complete_cache());
598 delegate()->loaded_groups_newest_cache_ = NULL;
599 EXPECT_TRUE(delegate()->loaded_group_->HasOneRef());
600 EXPECT_EQ(2, mock_quota_manager_proxy_->notify_storage_accessed_count_);
601 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
602 TestFinished();
605 // StoreNewGroup --------------------------------------
607 void StoreNewGroup() {
608 // Store a group and its newest cache. Should complete asynchronously.
609 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_StoreNewGroup,
610 base::Unretained(this)));
612 // Setup some preconditions. Create a group and newest cache that
613 // appear to be "unstored".
614 group_ = new AppCacheGroup(
615 storage(), kManifestUrl, storage()->NewGroupId());
616 cache_ = new AppCache(storage(), storage()->NewCacheId());
617 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, 1,
618 kDefaultEntrySize));
619 // Hold a ref to the cache simulate the UpdateJob holding that ref,
620 // and hold a ref to the group to simulate the CacheHost holding that ref.
622 // Have the quota manager retrun asynchronously for this test.
623 mock_quota_manager_proxy_->mock_manager_->async_ = true;
625 // Conduct the store test.
626 storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate());
627 EXPECT_FALSE(delegate()->stored_group_success_);
630 void Verify_StoreNewGroup() {
631 EXPECT_TRUE(delegate()->stored_group_success_);
632 EXPECT_EQ(group_.get(), delegate()->stored_group_.get());
633 EXPECT_EQ(cache_.get(), group_->newest_complete_cache());
634 EXPECT_TRUE(cache_->is_complete());
636 // Should have been stored in the database.
637 AppCacheDatabase::GroupRecord group_record;
638 AppCacheDatabase::CacheRecord cache_record;
639 EXPECT_TRUE(database()->FindGroup(group_->group_id(), &group_record));
640 EXPECT_TRUE(database()->FindCache(cache_->cache_id(), &cache_record));
642 // Verify quota bookkeeping
643 EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
644 EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
645 EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
646 EXPECT_EQ(kDefaultEntrySize, mock_quota_manager_proxy_->last_delta_);
648 TestFinished();
651 // StoreExistingGroup --------------------------------------
653 void StoreExistingGroup() {
654 // Store a group and its newest cache. Should complete asynchronously.
655 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_StoreExistingGroup,
656 base::Unretained(this)));
658 // Setup some preconditions. Create a group and old complete cache
659 // that appear to be "stored"
660 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
661 EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
663 // And a newest unstored complete cache.
664 cache2_ = new AppCache(storage(), 2);
665 cache2_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::MASTER, 1,
666 kDefaultEntrySize + 100));
668 // Conduct the test.
669 storage()->StoreGroupAndNewestCache(
670 group_.get(), cache2_.get(), delegate());
671 EXPECT_FALSE(delegate()->stored_group_success_);
674 void Verify_StoreExistingGroup() {
675 EXPECT_TRUE(delegate()->stored_group_success_);
676 EXPECT_EQ(group_.get(), delegate()->stored_group_.get());
677 EXPECT_EQ(cache2_.get(), group_->newest_complete_cache());
678 EXPECT_TRUE(cache2_->is_complete());
680 // The new cache should have been stored in the database.
681 AppCacheDatabase::GroupRecord group_record;
682 AppCacheDatabase::CacheRecord cache_record;
683 EXPECT_TRUE(database()->FindGroup(1, &group_record));
684 EXPECT_TRUE(database()->FindCache(2, &cache_record));
686 // The old cache should have been deleted
687 EXPECT_FALSE(database()->FindCache(1, &cache_record));
689 // Verify quota bookkeeping
690 EXPECT_EQ(kDefaultEntrySize + 100, storage()->usage_map_[kOrigin]);
691 EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
692 EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
693 EXPECT_EQ(100, mock_quota_manager_proxy_->last_delta_);
695 TestFinished();
698 // StoreExistingGroupExistingCache -------------------------------
700 void StoreExistingGroupExistingCache() {
701 // Store a group with updates to its existing newest complete cache.
702 // Setup some preconditions. Create a group and a complete cache that
703 // appear to be "stored".
705 // Setup some preconditions. Create a group and old complete cache
706 // that appear to be "stored"
707 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
708 EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
710 // Change the cache.
711 base::Time now = base::Time::Now();
712 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::MASTER, 1, 100));
713 cache_->set_update_time(now);
715 PushNextTask(base::Bind(
716 &AppCacheStorageImplTest::Verify_StoreExistingGroupExistingCache,
717 base::Unretained(this), now));
719 // Conduct the test.
720 EXPECT_EQ(cache_.get(), group_->newest_complete_cache());
721 storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate());
722 EXPECT_FALSE(delegate()->stored_group_success_);
725 void Verify_StoreExistingGroupExistingCache(
726 base::Time expected_update_time) {
727 EXPECT_TRUE(delegate()->stored_group_success_);
728 EXPECT_EQ(cache_.get(), group_->newest_complete_cache());
730 AppCacheDatabase::CacheRecord cache_record;
731 EXPECT_TRUE(database()->FindCache(1, &cache_record));
732 EXPECT_EQ(1, cache_record.cache_id);
733 EXPECT_EQ(1, cache_record.group_id);
734 EXPECT_FALSE(cache_record.online_wildcard);
735 EXPECT_TRUE(expected_update_time == cache_record.update_time);
736 EXPECT_EQ(100 + kDefaultEntrySize, cache_record.cache_size);
738 std::vector<AppCacheDatabase::EntryRecord> entry_records;
739 EXPECT_TRUE(database()->FindEntriesForCache(1, &entry_records));
740 EXPECT_EQ(2U, entry_records.size());
741 if (entry_records[0].url == kDefaultEntryUrl)
742 entry_records.erase(entry_records.begin());
743 EXPECT_EQ(1 , entry_records[0].cache_id);
744 EXPECT_EQ(kEntryUrl, entry_records[0].url);
745 EXPECT_EQ(AppCacheEntry::MASTER, entry_records[0].flags);
746 EXPECT_EQ(1, entry_records[0].response_id);
747 EXPECT_EQ(100, entry_records[0].response_size);
749 // Verify quota bookkeeping
750 EXPECT_EQ(100 + kDefaultEntrySize, storage()->usage_map_[kOrigin]);
751 EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
752 EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
753 EXPECT_EQ(100, mock_quota_manager_proxy_->last_delta_);
755 TestFinished();
758 // FailStoreGroup --------------------------------------
760 void FailStoreGroup() {
761 // Store a group and its newest cache. Should complete asynchronously.
762 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_FailStoreGroup,
763 base::Unretained(this)));
765 // Setup some preconditions. Create a group and newest cache that
766 // appear to be "unstored" and big enough to exceed the 5M limit.
767 const int64 kTooBig = 10 * 1024 * 1024; // 10M
768 group_ = new AppCacheGroup(
769 storage(), kManifestUrl, storage()->NewGroupId());
770 cache_ = new AppCache(storage(), storage()->NewCacheId());
771 cache_->AddEntry(kManifestUrl,
772 AppCacheEntry(AppCacheEntry::MANIFEST, 1, kTooBig));
773 // Hold a ref to the cache simulate the UpdateJob holding that ref,
774 // and hold a ref to the group to simulate the CacheHost holding that ref.
776 // Conduct the store test.
777 storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate());
778 EXPECT_FALSE(delegate()->stored_group_success_); // Expected to be async.
781 void Verify_FailStoreGroup() {
782 EXPECT_FALSE(delegate()->stored_group_success_);
783 EXPECT_TRUE(delegate()->would_exceed_quota_);
785 // Should not have been stored in the database.
786 AppCacheDatabase::GroupRecord group_record;
787 AppCacheDatabase::CacheRecord cache_record;
788 EXPECT_FALSE(database()->FindGroup(group_->group_id(), &group_record));
789 EXPECT_FALSE(database()->FindCache(cache_->cache_id(), &cache_record));
791 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
792 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
794 TestFinished();
797 // MakeGroupObsolete -------------------------------
799 void MakeGroupObsolete() {
800 // Make a group obsolete, should complete asynchronously.
801 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_MakeGroupObsolete,
802 base::Unretained(this)));
804 // Setup some preconditions. Create a group and newest cache that
805 // appears to be "stored" and "currently in use".
806 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
807 EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
809 // Also insert some related records.
810 AppCacheDatabase::EntryRecord entry_record;
811 entry_record.cache_id = 1;
812 entry_record.flags = AppCacheEntry::FALLBACK;
813 entry_record.response_id = 1;
814 entry_record.url = kEntryUrl;
815 EXPECT_TRUE(database()->InsertEntry(&entry_record));
817 AppCacheDatabase::NamespaceRecord fallback_namespace_record;
818 fallback_namespace_record.cache_id = 1;
819 fallback_namespace_record.namespace_.target_url = kEntryUrl;
820 fallback_namespace_record.namespace_.namespace_url = kFallbackNamespace;
821 fallback_namespace_record.origin = kManifestUrl.GetOrigin();
822 EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record));
824 AppCacheDatabase::OnlineWhiteListRecord online_whitelist_record;
825 online_whitelist_record.cache_id = 1;
826 online_whitelist_record.namespace_url = kOnlineNamespace;
827 EXPECT_TRUE(database()->InsertOnlineWhiteList(&online_whitelist_record));
829 // Conduct the test.
830 storage()->MakeGroupObsolete(group_.get(), delegate(), 0);
831 EXPECT_FALSE(group_->is_obsolete());
834 void Verify_MakeGroupObsolete() {
835 EXPECT_TRUE(delegate()->obsoleted_success_);
836 EXPECT_EQ(group_.get(), delegate()->obsoleted_group_.get());
837 EXPECT_TRUE(group_->is_obsolete());
838 EXPECT_TRUE(storage()->usage_map_.empty());
840 // The cache and group have been deleted from the database.
841 AppCacheDatabase::GroupRecord group_record;
842 AppCacheDatabase::CacheRecord cache_record;
843 EXPECT_FALSE(database()->FindGroup(1, &group_record));
844 EXPECT_FALSE(database()->FindCache(1, &cache_record));
846 // The related records should have been deleted too.
847 std::vector<AppCacheDatabase::EntryRecord> entry_records;
848 database()->FindEntriesForCache(1, &entry_records);
849 EXPECT_TRUE(entry_records.empty());
850 std::vector<AppCacheDatabase::NamespaceRecord> intercept_records;
851 std::vector<AppCacheDatabase::NamespaceRecord> fallback_records;
852 database()->FindNamespacesForCache(
853 1, &intercept_records, &fallback_records);
854 EXPECT_TRUE(fallback_records.empty());
855 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelist_records;
856 database()->FindOnlineWhiteListForCache(1, &whitelist_records);
857 EXPECT_TRUE(whitelist_records.empty());
859 // Verify quota bookkeeping
860 EXPECT_TRUE(storage()->usage_map_.empty());
861 EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
862 EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
863 EXPECT_EQ(-kDefaultEntrySize, mock_quota_manager_proxy_->last_delta_);
865 TestFinished();
868 // MarkEntryAsForeign -------------------------------
870 void MarkEntryAsForeign() {
871 // Setup some preconditions. Create a cache with an entry
872 // in storage and in the working set.
873 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
874 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT));
875 AppCacheDatabase::EntryRecord entry_record;
876 entry_record.cache_id = 1;
877 entry_record.url = kEntryUrl;
878 entry_record.flags = AppCacheEntry::EXPLICIT;
879 entry_record.response_id = 0;
880 EXPECT_TRUE(database()->InsertEntry(&entry_record));
881 EXPECT_FALSE(cache_->GetEntry(kEntryUrl)->IsForeign());
883 // Conduct the test.
884 storage()->MarkEntryAsForeign(kEntryUrl, 1);
886 // The entry in the working set should have been updated syncly.
887 EXPECT_TRUE(cache_->GetEntry(kEntryUrl)->IsForeign());
888 EXPECT_TRUE(cache_->GetEntry(kEntryUrl)->IsExplicit());
890 // And the entry in storage should also be updated, but that
891 // happens asynchronously on the db thread.
892 FlushDbThreadTasks();
893 AppCacheDatabase::EntryRecord entry_record2;
894 EXPECT_TRUE(database()->FindEntry(1, kEntryUrl, &entry_record2));
895 EXPECT_EQ(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN,
896 entry_record2.flags);
897 TestFinished();
900 // MarkEntryAsForeignWithLoadInProgress -------------------------------
902 void MarkEntryAsForeignWithLoadInProgress() {
903 PushNextTask(base::Bind(
904 &AppCacheStorageImplTest::Verify_MarkEntryAsForeignWithLoadInProgress,
905 base::Unretained(this)));
907 // Setup some preconditions. Create a cache with an entry
908 // in storage, but not in the working set.
909 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
910 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT));
911 AppCacheDatabase::EntryRecord entry_record;
912 entry_record.cache_id = 1;
913 entry_record.url = kEntryUrl;
914 entry_record.flags = AppCacheEntry::EXPLICIT;
915 entry_record.response_id = 0;
916 EXPECT_TRUE(database()->InsertEntry(&entry_record));
917 EXPECT_FALSE(cache_->GetEntry(kEntryUrl)->IsForeign());
918 EXPECT_TRUE(cache_->HasOneRef());
919 cache_ = NULL;
920 group_ = NULL;
922 // Conduct the test, start a cache load, and prior to completion
923 // of that load, mark the entry as foreign.
924 storage()->LoadCache(1, delegate());
925 storage()->MarkEntryAsForeign(kEntryUrl, 1);
928 void Verify_MarkEntryAsForeignWithLoadInProgress() {
929 EXPECT_EQ(1, delegate()->loaded_cache_id_);
930 EXPECT_TRUE(delegate()->loaded_cache_.get());
932 // The entry in the working set should have been updated upon load.
933 EXPECT_TRUE(delegate()->loaded_cache_->GetEntry(kEntryUrl)->IsForeign());
934 EXPECT_TRUE(delegate()->loaded_cache_->GetEntry(kEntryUrl)->IsExplicit());
936 // And the entry in storage should also be updated.
937 FlushDbThreadTasks();
938 AppCacheDatabase::EntryRecord entry_record;
939 EXPECT_TRUE(database()->FindEntry(1, kEntryUrl, &entry_record));
940 EXPECT_EQ(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN,
941 entry_record.flags);
942 TestFinished();
945 // FindNoMainResponse -------------------------------
947 void FindNoMainResponse() {
948 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_FindNoMainResponse,
949 base::Unretained(this)));
951 // Conduct the test.
952 storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
953 EXPECT_NE(kEntryUrl, delegate()->found_url_);
956 void Verify_FindNoMainResponse() {
957 EXPECT_EQ(kEntryUrl, delegate()->found_url_);
958 EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
959 EXPECT_EQ(kAppCacheNoCacheId, delegate()->found_cache_id_);
960 EXPECT_EQ(kAppCacheNoResponseId, delegate()->found_entry_.response_id());
961 EXPECT_EQ(kAppCacheNoResponseId,
962 delegate()->found_fallback_entry_.response_id());
963 EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
964 EXPECT_EQ(0, delegate()->found_entry_.types());
965 EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
966 TestFinished();
969 // BasicFindMainResponse -------------------------------
971 void BasicFindMainResponseInDatabase() {
972 BasicFindMainResponse(true);
975 void BasicFindMainResponseInWorkingSet() {
976 BasicFindMainResponse(false);
979 void BasicFindMainResponse(bool drop_from_working_set) {
980 PushNextTask(base::Bind(
981 &AppCacheStorageImplTest::Verify_BasicFindMainResponse,
982 base::Unretained(this)));
984 // Setup some preconditions. Create a complete cache with an entry
985 // in storage.
986 MakeCacheAndGroup(kManifestUrl, 2, 1, true);
987 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, 1));
988 AppCacheDatabase::EntryRecord entry_record;
989 entry_record.cache_id = 1;
990 entry_record.url = kEntryUrl;
991 entry_record.flags = AppCacheEntry::EXPLICIT;
992 entry_record.response_id = 1;
993 EXPECT_TRUE(database()->InsertEntry(&entry_record));
995 // Optionally drop the cache/group pair from the working set.
996 if (drop_from_working_set) {
997 EXPECT_TRUE(cache_->HasOneRef());
998 cache_ = NULL;
999 EXPECT_TRUE(group_->HasOneRef());
1000 group_ = NULL;
1003 // Conduct the test.
1004 storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
1005 EXPECT_NE(kEntryUrl, delegate()->found_url_);
1008 void Verify_BasicFindMainResponse() {
1009 EXPECT_EQ(kEntryUrl, delegate()->found_url_);
1010 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1011 EXPECT_EQ(1, delegate()->found_cache_id_);
1012 EXPECT_EQ(2, delegate()->found_group_id_);
1013 EXPECT_EQ(1, delegate()->found_entry_.response_id());
1014 EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
1015 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
1016 TestFinished();
1019 // BasicFindMainFallbackResponse -------------------------------
1021 void BasicFindMainFallbackResponseInDatabase() {
1022 BasicFindMainFallbackResponse(true);
1025 void BasicFindMainFallbackResponseInWorkingSet() {
1026 BasicFindMainFallbackResponse(false);
1029 void BasicFindMainFallbackResponse(bool drop_from_working_set) {
1030 PushNextTask(base::Bind(
1031 &AppCacheStorageImplTest::Verify_BasicFindMainFallbackResponse,
1032 base::Unretained(this)));
1034 // Setup some preconditions. Create a complete cache with a
1035 // fallback namespace and entry.
1036 MakeCacheAndGroup(kManifestUrl, 2, 1, true);
1037 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::FALLBACK, 1));
1038 cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::FALLBACK, 2));
1039 cache_->fallback_namespaces_.push_back(
1040 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE,
1041 kFallbackNamespace2,
1042 kEntryUrl2,
1043 false));
1044 cache_->fallback_namespaces_.push_back(
1045 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE,
1046 kFallbackNamespace,
1047 kEntryUrl,
1048 false));
1049 AppCacheDatabase::CacheRecord cache_record;
1050 std::vector<AppCacheDatabase::EntryRecord> entries;
1051 std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
1052 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
1053 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
1054 cache_->ToDatabaseRecords(group_.get(),
1055 &cache_record,
1056 &entries,
1057 &intercepts,
1058 &fallbacks,
1059 &whitelists);
1061 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
1062 entries.begin();
1063 while (iter != entries.end()) {
1064 // MakeCacheAndGroup has inserted the default entry record already.
1065 if (iter->url != kDefaultEntryUrl)
1066 EXPECT_TRUE(database()->InsertEntry(&(*iter)));
1067 ++iter;
1070 EXPECT_TRUE(database()->InsertNamespaceRecords(fallbacks));
1071 EXPECT_TRUE(database()->InsertOnlineWhiteListRecords(whitelists));
1072 if (drop_from_working_set) {
1073 EXPECT_TRUE(cache_->HasOneRef());
1074 cache_ = NULL;
1075 EXPECT_TRUE(group_->HasOneRef());
1076 group_ = NULL;
1079 // Conduct the test. The test url is in both fallback namespace urls,
1080 // but should match the longer of the two.
1081 storage()->FindResponseForMainRequest(kFallbackTestUrl, GURL(), delegate());
1082 EXPECT_NE(kFallbackTestUrl, delegate()->found_url_);
1085 void Verify_BasicFindMainFallbackResponse() {
1086 EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_);
1087 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1088 EXPECT_EQ(1, delegate()->found_cache_id_);
1089 EXPECT_EQ(2, delegate()->found_group_id_);
1090 EXPECT_FALSE(delegate()->found_entry_.has_response_id());
1091 EXPECT_EQ(2, delegate()->found_fallback_entry_.response_id());
1092 EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
1093 EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
1094 TestFinished();
1097 // BasicFindMainInterceptResponse -------------------------------
1099 void BasicFindMainInterceptResponseInDatabase() {
1100 BasicFindMainInterceptResponse(true);
1103 void BasicFindMainInterceptResponseInWorkingSet() {
1104 BasicFindMainInterceptResponse(false);
1107 void BasicFindMainInterceptResponse(bool drop_from_working_set) {
1108 PushNextTask(base::Bind(
1109 &AppCacheStorageImplTest::Verify_BasicFindMainInterceptResponse,
1110 base::Unretained(this)));
1112 // Setup some preconditions. Create a complete cache with an
1113 // intercept namespace and entry.
1114 MakeCacheAndGroup(kManifestUrl, 2, 1, true);
1115 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::INTERCEPT, 1));
1116 cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::INTERCEPT, 2));
1117 cache_->intercept_namespaces_.push_back(
1118 AppCacheNamespace(APPCACHE_INTERCEPT_NAMESPACE, kInterceptNamespace2,
1119 kEntryUrl2, false));
1120 cache_->intercept_namespaces_.push_back(
1121 AppCacheNamespace(APPCACHE_INTERCEPT_NAMESPACE, kInterceptNamespace,
1122 kEntryUrl, false));
1123 AppCacheDatabase::CacheRecord cache_record;
1124 std::vector<AppCacheDatabase::EntryRecord> entries;
1125 std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
1126 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
1127 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
1128 cache_->ToDatabaseRecords(group_.get(),
1129 &cache_record,
1130 &entries,
1131 &intercepts,
1132 &fallbacks,
1133 &whitelists);
1135 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
1136 entries.begin();
1137 while (iter != entries.end()) {
1138 // MakeCacheAndGroup has inserted the default entry record already
1139 if (iter->url != kDefaultEntryUrl)
1140 EXPECT_TRUE(database()->InsertEntry(&(*iter)));
1141 ++iter;
1144 EXPECT_TRUE(database()->InsertNamespaceRecords(intercepts));
1145 EXPECT_TRUE(database()->InsertOnlineWhiteListRecords(whitelists));
1146 if (drop_from_working_set) {
1147 EXPECT_TRUE(cache_->HasOneRef());
1148 cache_ = NULL;
1149 EXPECT_TRUE(group_->HasOneRef());
1150 group_ = NULL;
1153 // Conduct the test. The test url is in both intercept namespaces,
1154 // but should match the longer of the two.
1155 storage()->FindResponseForMainRequest(
1156 kInterceptTestUrl, GURL(), delegate());
1157 EXPECT_NE(kInterceptTestUrl, delegate()->found_url_);
1160 void Verify_BasicFindMainInterceptResponse() {
1161 EXPECT_EQ(kInterceptTestUrl, delegate()->found_url_);
1162 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1163 EXPECT_EQ(1, delegate()->found_cache_id_);
1164 EXPECT_EQ(2, delegate()->found_group_id_);
1165 EXPECT_EQ(2, delegate()->found_entry_.response_id());
1166 EXPECT_TRUE(delegate()->found_entry_.IsIntercept());
1167 EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
1168 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
1169 TestFinished();
1172 // FindInterceptPatternMatch ----------------------------------------
1174 void FindInterceptPatternMatchInDatabase() {
1175 FindInterceptPatternMatch(true);
1178 void FindInterceptPatternMatchInWorkingSet() {
1179 FindInterceptPatternMatch(false);
1182 void FindInterceptPatternMatch(bool drop_from_working_set) {
1183 // Setup some preconditions. Create a complete cache with an
1184 // pattern matching intercept namespace and entry.
1185 MakeCacheAndGroup(kManifestUrl, 2, 1, true);
1186 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::INTERCEPT, 1));
1187 cache_->intercept_namespaces_.push_back(
1188 AppCacheNamespace(APPCACHE_INTERCEPT_NAMESPACE,
1189 kInterceptPatternNamespace, kEntryUrl, true));
1190 AppCacheDatabase::CacheRecord cache_record;
1191 std::vector<AppCacheDatabase::EntryRecord> entries;
1192 std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
1193 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
1194 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
1195 cache_->ToDatabaseRecords(group_.get(),
1196 &cache_record,
1197 &entries,
1198 &intercepts,
1199 &fallbacks,
1200 &whitelists);
1202 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
1203 entries.begin();
1204 while (iter != entries.end()) {
1205 // MakeCacheAndGroup has inserted the default entry record already
1206 if (iter->url != kDefaultEntryUrl)
1207 EXPECT_TRUE(database()->InsertEntry(&(*iter)));
1208 ++iter;
1211 EXPECT_TRUE(database()->InsertNamespaceRecords(intercepts));
1212 if (drop_from_working_set) {
1213 EXPECT_TRUE(cache_->HasOneRef());
1214 cache_ = NULL;
1215 EXPECT_TRUE(group_->HasOneRef());
1216 group_ = NULL;
1219 // First test something that does not match the pattern.
1220 PushNextTask(base::Bind(
1221 &AppCacheStorageImplTest::Verify_FindInterceptPatternMatchNegative,
1222 base::Unretained(this)));
1223 storage()->FindResponseForMainRequest(
1224 kInterceptPatternTestNegativeUrl, GURL(), delegate());
1225 EXPECT_EQ(GURL(), delegate()->found_url_); // Is always async.
1228 void Verify_FindInterceptPatternMatchNegative() {
1229 EXPECT_EQ(kInterceptPatternTestNegativeUrl, delegate()->found_url_);
1230 EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
1231 EXPECT_EQ(kAppCacheNoCacheId, delegate()->found_cache_id_);
1232 EXPECT_EQ(kAppCacheNoResponseId, delegate()->found_entry_.response_id());
1233 EXPECT_EQ(kAppCacheNoResponseId,
1234 delegate()->found_fallback_entry_.response_id());
1235 EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
1236 EXPECT_EQ(0, delegate()->found_entry_.types());
1237 EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
1239 // Then test something that matches.
1240 PushNextTask(base::Bind(
1241 &AppCacheStorageImplTest::Verify_FindInterceptPatternMatchPositive,
1242 base::Unretained(this)));
1243 storage()->FindResponseForMainRequest(
1244 kInterceptPatternTestPositiveUrl, GURL(), delegate());
1247 void Verify_FindInterceptPatternMatchPositive() {
1248 EXPECT_EQ(kInterceptPatternTestPositiveUrl, delegate()->found_url_);
1249 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1250 EXPECT_EQ(1, delegate()->found_cache_id_);
1251 EXPECT_EQ(2, delegate()->found_group_id_);
1252 EXPECT_EQ(1, delegate()->found_entry_.response_id());
1253 EXPECT_TRUE(delegate()->found_entry_.IsIntercept());
1254 EXPECT_EQ(kEntryUrl, delegate()->found_namespace_entry_url_);
1255 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
1256 TestFinished();
1259 // FindFallbackPatternMatch -------------------------------
1261 void FindFallbackPatternMatchInDatabase() {
1262 FindFallbackPatternMatch(true);
1265 void FindFallbackPatternMatchInWorkingSet() {
1266 FindFallbackPatternMatch(false);
1269 void FindFallbackPatternMatch(bool drop_from_working_set) {
1270 // Setup some preconditions. Create a complete cache with a
1271 // pattern matching fallback namespace and entry.
1272 MakeCacheAndGroup(kManifestUrl, 2, 1, true);
1273 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::FALLBACK, 1));
1274 cache_->fallback_namespaces_.push_back(
1275 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE,
1276 kFallbackPatternNamespace, kEntryUrl, true));
1277 AppCacheDatabase::CacheRecord cache_record;
1278 std::vector<AppCacheDatabase::EntryRecord> entries;
1279 std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
1280 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
1281 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
1282 cache_->ToDatabaseRecords(group_.get(),
1283 &cache_record,
1284 &entries,
1285 &intercepts,
1286 &fallbacks,
1287 &whitelists);
1289 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
1290 entries.begin();
1291 while (iter != entries.end()) {
1292 // MakeCacheAndGroup has inserted the default entry record already.
1293 if (iter->url != kDefaultEntryUrl)
1294 EXPECT_TRUE(database()->InsertEntry(&(*iter)));
1295 ++iter;
1298 EXPECT_TRUE(database()->InsertNamespaceRecords(fallbacks));
1299 if (drop_from_working_set) {
1300 EXPECT_TRUE(cache_->HasOneRef());
1301 cache_ = NULL;
1302 EXPECT_TRUE(group_->HasOneRef());
1303 group_ = NULL;
1306 // First test something that does not match the pattern.
1307 PushNextTask(base::Bind(
1308 &AppCacheStorageImplTest::Verify_FindFallbackPatternMatchNegative,
1309 base::Unretained(this)));
1310 storage()->FindResponseForMainRequest(
1311 kFallbackPatternTestNegativeUrl, GURL(), delegate());
1312 EXPECT_EQ(GURL(), delegate()->found_url_); // Is always async.
1315 void Verify_FindFallbackPatternMatchNegative() {
1316 EXPECT_EQ(kFallbackPatternTestNegativeUrl, delegate()->found_url_);
1317 EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
1318 EXPECT_EQ(kAppCacheNoCacheId, delegate()->found_cache_id_);
1319 EXPECT_EQ(kAppCacheNoResponseId, delegate()->found_entry_.response_id());
1320 EXPECT_EQ(kAppCacheNoResponseId,
1321 delegate()->found_fallback_entry_.response_id());
1322 EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
1323 EXPECT_EQ(0, delegate()->found_entry_.types());
1324 EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
1326 // Then test something that matches.
1327 PushNextTask(base::Bind(
1328 &AppCacheStorageImplTest::Verify_FindFallbackPatternMatchPositive,
1329 base::Unretained(this)));
1330 storage()->FindResponseForMainRequest(
1331 kFallbackPatternTestPositiveUrl, GURL(), delegate());
1334 void Verify_FindFallbackPatternMatchPositive() {
1335 EXPECT_EQ(kFallbackPatternTestPositiveUrl, delegate()->found_url_);
1336 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1337 EXPECT_EQ(1, delegate()->found_cache_id_);
1338 EXPECT_EQ(2, delegate()->found_group_id_);
1339 EXPECT_EQ(1, delegate()->found_fallback_entry_.response_id());
1340 EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
1341 EXPECT_EQ(kEntryUrl, delegate()->found_namespace_entry_url_);
1342 EXPECT_FALSE(delegate()->found_entry_.has_response_id());
1343 TestFinished();
1346 // FindMainResponseWithMultipleHits -------------------------------
1348 void FindMainResponseWithMultipleHits() {
1349 PushNextTask(base::Bind(
1350 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits,
1351 base::Unretained(this)));
1353 // Setup some preconditions, create a few caches with an identical set
1354 // of entries and fallback namespaces. Only the last one remains in
1355 // the working set to simulate appearing as "in use".
1356 MakeMultipleHitCacheAndGroup(kManifestUrl, 1);
1357 MakeMultipleHitCacheAndGroup(kManifestUrl2, 2);
1358 MakeMultipleHitCacheAndGroup(kManifestUrl3, 3);
1360 // Conduct the test, we should find the response from the last cache
1361 // since it's "in use".
1362 storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
1363 EXPECT_NE(kEntryUrl, delegate()->found_url_);
1366 void MakeMultipleHitCacheAndGroup(const GURL& manifest_url, int id) {
1367 MakeCacheAndGroup(manifest_url, id, id, true);
1368 AppCacheDatabase::EntryRecord entry_record;
1370 // Add an entry for kEntryUrl
1371 entry_record.cache_id = id;
1372 entry_record.url = kEntryUrl;
1373 entry_record.flags = AppCacheEntry::EXPLICIT;
1374 entry_record.response_id = id;
1375 EXPECT_TRUE(database()->InsertEntry(&entry_record));
1376 cache_->AddEntry(
1377 entry_record.url,
1378 AppCacheEntry(entry_record.flags, entry_record.response_id));
1380 // Add an entry for the manifestUrl
1381 entry_record.cache_id = id;
1382 entry_record.url = manifest_url;
1383 entry_record.flags = AppCacheEntry::MANIFEST;
1384 entry_record.response_id = id + kManifestEntryIdOffset;
1385 EXPECT_TRUE(database()->InsertEntry(&entry_record));
1386 cache_->AddEntry(
1387 entry_record.url,
1388 AppCacheEntry(entry_record.flags, entry_record.response_id));
1390 // Add a fallback entry and namespace
1391 entry_record.cache_id = id;
1392 entry_record.url = kEntryUrl2;
1393 entry_record.flags = AppCacheEntry::FALLBACK;
1394 entry_record.response_id = id + kFallbackEntryIdOffset;
1395 EXPECT_TRUE(database()->InsertEntry(&entry_record));
1396 cache_->AddEntry(
1397 entry_record.url,
1398 AppCacheEntry(entry_record.flags, entry_record.response_id));
1399 AppCacheDatabase::NamespaceRecord fallback_namespace_record;
1400 fallback_namespace_record.cache_id = id;
1401 fallback_namespace_record.namespace_.target_url = entry_record.url;
1402 fallback_namespace_record.namespace_.namespace_url = kFallbackNamespace;
1403 fallback_namespace_record.origin = manifest_url.GetOrigin();
1404 EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record));
1405 cache_->fallback_namespaces_.push_back(
1406 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE,
1407 kFallbackNamespace,
1408 kEntryUrl2,
1409 false));
1412 void Verify_FindMainResponseWithMultipleHits() {
1413 EXPECT_EQ(kEntryUrl, delegate()->found_url_);
1414 EXPECT_EQ(kManifestUrl3, delegate()->found_manifest_url_);
1415 EXPECT_EQ(3, delegate()->found_cache_id_);
1416 EXPECT_EQ(3, delegate()->found_group_id_);
1417 EXPECT_EQ(3, delegate()->found_entry_.response_id());
1418 EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
1419 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
1421 // Conduct another test preferring kManifestUrl
1422 delegate_.reset(new MockStorageDelegate(this));
1423 PushNextTask(base::Bind(
1424 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits2,
1425 base::Unretained(this)));
1426 storage()->FindResponseForMainRequest(kEntryUrl, kManifestUrl, delegate());
1427 EXPECT_NE(kEntryUrl, delegate()->found_url_);
1430 void Verify_FindMainResponseWithMultipleHits2() {
1431 EXPECT_EQ(kEntryUrl, delegate()->found_url_);
1432 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1433 EXPECT_EQ(1, delegate()->found_cache_id_);
1434 EXPECT_EQ(1, delegate()->found_group_id_);
1435 EXPECT_EQ(1, delegate()->found_entry_.response_id());
1436 EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
1437 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
1439 // Conduct the another test preferring kManifestUrl2
1440 delegate_.reset(new MockStorageDelegate(this));
1441 PushNextTask(base::Bind(
1442 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits3,
1443 base::Unretained(this)));
1444 storage()->FindResponseForMainRequest(kEntryUrl, kManifestUrl2, delegate());
1445 EXPECT_NE(kEntryUrl, delegate()->found_url_);
1448 void Verify_FindMainResponseWithMultipleHits3() {
1449 EXPECT_EQ(kEntryUrl, delegate()->found_url_);
1450 EXPECT_EQ(kManifestUrl2, delegate()->found_manifest_url_);
1451 EXPECT_EQ(2, delegate()->found_cache_id_);
1452 EXPECT_EQ(2, delegate()->found_group_id_);
1453 EXPECT_EQ(2, delegate()->found_entry_.response_id());
1454 EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
1455 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
1457 // Conduct another test with no preferred manifest that hits the fallback.
1458 delegate_.reset(new MockStorageDelegate(this));
1459 PushNextTask(base::Bind(
1460 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits4,
1461 base::Unretained(this)));
1462 storage()->FindResponseForMainRequest(
1463 kFallbackTestUrl, GURL(), delegate());
1464 EXPECT_NE(kFallbackTestUrl, delegate()->found_url_);
1467 void Verify_FindMainResponseWithMultipleHits4() {
1468 EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_);
1469 EXPECT_EQ(kManifestUrl3, delegate()->found_manifest_url_);
1470 EXPECT_EQ(3, delegate()->found_cache_id_);
1471 EXPECT_EQ(3, delegate()->found_group_id_);
1472 EXPECT_FALSE(delegate()->found_entry_.has_response_id());
1473 EXPECT_EQ(3 + kFallbackEntryIdOffset,
1474 delegate()->found_fallback_entry_.response_id());
1475 EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
1476 EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
1478 // Conduct another test preferring kManifestUrl2 that hits the fallback.
1479 delegate_.reset(new MockStorageDelegate(this));
1480 PushNextTask(base::Bind(
1481 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits5,
1482 base::Unretained(this)));
1483 storage()->FindResponseForMainRequest(
1484 kFallbackTestUrl, kManifestUrl2, delegate());
1485 EXPECT_NE(kFallbackTestUrl, delegate()->found_url_);
1488 void Verify_FindMainResponseWithMultipleHits5() {
1489 EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_);
1490 EXPECT_EQ(kManifestUrl2, delegate()->found_manifest_url_);
1491 EXPECT_EQ(2, delegate()->found_cache_id_);
1492 EXPECT_EQ(2, delegate()->found_group_id_);
1493 EXPECT_FALSE(delegate()->found_entry_.has_response_id());
1494 EXPECT_EQ(2 + kFallbackEntryIdOffset,
1495 delegate()->found_fallback_entry_.response_id());
1496 EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
1497 EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
1499 TestFinished();
1502 // FindMainResponseExclusions -------------------------------
1504 void FindMainResponseExclusionsInDatabase() {
1505 FindMainResponseExclusions(true);
1508 void FindMainResponseExclusionsInWorkingSet() {
1509 FindMainResponseExclusions(false);
1512 void FindMainResponseExclusions(bool drop_from_working_set) {
1513 // Setup some preconditions. Create a complete cache with a
1514 // foreign entry, an online namespace, and a second online
1515 // namespace nested within a fallback namespace.
1516 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
1517 cache_->AddEntry(kEntryUrl,
1518 AppCacheEntry(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN, 1));
1519 cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::FALLBACK, 2));
1520 cache_->fallback_namespaces_.push_back(
1521 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE,
1522 kFallbackNamespace,
1523 kEntryUrl2,
1524 false));
1525 cache_->online_whitelist_namespaces_.push_back(
1526 AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE, kOnlineNamespace,
1527 GURL(), false));
1528 cache_->online_whitelist_namespaces_.push_back(
1529 AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE,
1530 kOnlineNamespaceWithinFallback, GURL(), false));
1532 AppCacheDatabase::EntryRecord entry_record;
1533 entry_record.cache_id = 1;
1534 entry_record.url = kEntryUrl;
1535 entry_record.flags = AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN;
1536 entry_record.response_id = 1;
1537 EXPECT_TRUE(database()->InsertEntry(&entry_record));
1538 AppCacheDatabase::OnlineWhiteListRecord whitelist_record;
1539 whitelist_record.cache_id = 1;
1540 whitelist_record.namespace_url = kOnlineNamespace;
1541 EXPECT_TRUE(database()->InsertOnlineWhiteList(&whitelist_record));
1542 AppCacheDatabase::NamespaceRecord fallback_namespace_record;
1543 fallback_namespace_record.cache_id = 1;
1544 fallback_namespace_record.namespace_.target_url = kEntryUrl2;
1545 fallback_namespace_record.namespace_.namespace_url = kFallbackNamespace;
1546 fallback_namespace_record.origin = kManifestUrl.GetOrigin();
1547 EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record));
1548 whitelist_record.cache_id = 1;
1549 whitelist_record.namespace_url = kOnlineNamespaceWithinFallback;
1550 EXPECT_TRUE(database()->InsertOnlineWhiteList(&whitelist_record));
1551 if (drop_from_working_set) {
1552 cache_ = NULL;
1553 group_ = NULL;
1556 // We should not find anything for the foreign entry.
1557 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_ExclusionNotFound,
1558 base::Unretained(this), kEntryUrl, 1));
1559 storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
1562 void Verify_ExclusionNotFound(GURL expected_url, int phase) {
1563 EXPECT_EQ(expected_url, delegate()->found_url_);
1564 EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
1565 EXPECT_EQ(kAppCacheNoCacheId, delegate()->found_cache_id_);
1566 EXPECT_EQ(0, delegate()->found_group_id_);
1567 EXPECT_EQ(kAppCacheNoResponseId, delegate()->found_entry_.response_id());
1568 EXPECT_EQ(kAppCacheNoResponseId,
1569 delegate()->found_fallback_entry_.response_id());
1570 EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
1571 EXPECT_EQ(0, delegate()->found_entry_.types());
1572 EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
1574 if (phase == 1) {
1575 // We should not find anything for the online namespace.
1576 PushNextTask(
1577 base::Bind(&AppCacheStorageImplTest::Verify_ExclusionNotFound,
1578 base::Unretained(this), kOnlineNamespace, 2));
1579 storage()->FindResponseForMainRequest(
1580 kOnlineNamespace, GURL(), delegate());
1581 return;
1583 if (phase == 2) {
1584 // We should not find anything for the online namespace nested within
1585 // the fallback namespace.
1586 PushNextTask(base::Bind(
1587 &AppCacheStorageImplTest::Verify_ExclusionNotFound,
1588 base::Unretained(this), kOnlineNamespaceWithinFallback, 3));
1589 storage()->FindResponseForMainRequest(
1590 kOnlineNamespaceWithinFallback, GURL(), delegate());
1591 return;
1594 TestFinished();
1597 // Reinitialize -------------------------------
1598 // These tests are somewhat of a system integration test.
1599 // They rely on running a mock http server on our IO thread,
1600 // and involves other appcache classes to get some code
1601 // coverage thruout when Reinitialize happens.
1603 class MockServiceObserver : public AppCacheServiceImpl::Observer {
1604 public:
1605 explicit MockServiceObserver(AppCacheStorageImplTest* test)
1606 : test_(test) {}
1608 void OnServiceReinitialized(
1609 AppCacheStorageReference* old_storage_ref) override {
1610 observed_old_storage_ = old_storage_ref;
1611 test_->ScheduleNextTask();
1614 scoped_refptr<AppCacheStorageReference> observed_old_storage_;
1615 AppCacheStorageImplTest* test_;
1618 class MockAppCacheFrontend : public AppCacheFrontend {
1619 public:
1620 MockAppCacheFrontend() : error_event_was_raised_(false) {}
1622 void OnCacheSelected(int host_id, const AppCacheInfo& info) override {}
1623 void OnStatusChanged(const std::vector<int>& host_ids,
1624 AppCacheStatus status) override {}
1625 void OnEventRaised(const std::vector<int>& host_ids,
1626 AppCacheEventID event_id) override {}
1627 void OnProgressEventRaised(const std::vector<int>& host_ids,
1628 const GURL& url,
1629 int num_total,
1630 int num_complete) override {}
1631 void OnErrorEventRaised(const std::vector<int>& host_ids,
1632 const AppCacheErrorDetails& details) override {
1633 error_event_was_raised_ = true;
1635 void OnLogMessage(int host_id,
1636 AppCacheLogLevel log_level,
1637 const std::string& message) override {}
1638 void OnContentBlocked(int host_id, const GURL& manifest_url) override {}
1640 bool error_event_was_raised_;
1643 enum ReinitTestCase {
1644 CORRUPT_CACHE_ON_INSTALL,
1645 CORRUPT_CACHE_ON_LOAD_EXISTING,
1646 CORRUPT_SQL_ON_INSTALL
1649 void Reinitialize1() {
1650 // Recover from a corrupt disk cache discovered while
1651 // installing a new appcache.
1652 Reinitialize(CORRUPT_CACHE_ON_INSTALL);
1655 void Reinitialize2() {
1656 // Recover from a corrupt disk cache discovered while
1657 // trying to load a resource from an existing appcache.
1658 Reinitialize(CORRUPT_CACHE_ON_LOAD_EXISTING);
1661 void Reinitialize3() {
1662 // Recover from a corrupt sql database discovered while
1663 // installing a new appcache.
1664 Reinitialize(CORRUPT_SQL_ON_INSTALL);
1667 void Reinitialize(ReinitTestCase test_case) {
1668 // Unlike all of the other tests, this one actually read/write files.
1669 ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
1671 AppCacheDatabase db(temp_directory_.path().AppendASCII("Index"));
1672 EXPECT_TRUE(db.LazyOpen(true));
1674 if (test_case == CORRUPT_CACHE_ON_INSTALL ||
1675 test_case == CORRUPT_CACHE_ON_LOAD_EXISTING) {
1676 // Create a corrupt/unopenable disk_cache index file.
1677 const std::string kCorruptData("deadbeef");
1678 base::FilePath disk_cache_directory =
1679 temp_directory_.path().AppendASCII("Cache");
1680 ASSERT_TRUE(base::CreateDirectory(disk_cache_directory));
1681 base::FilePath index_file = disk_cache_directory.AppendASCII("index");
1682 EXPECT_EQ(static_cast<int>(kCorruptData.length()),
1683 base::WriteFile(
1684 index_file, kCorruptData.data(), kCorruptData.length()));
1687 // Create records for a degenerate cached manifest that only contains
1688 // one entry for the manifest file resource.
1689 if (test_case == CORRUPT_CACHE_ON_LOAD_EXISTING) {
1690 AppCacheDatabase db(temp_directory_.path().AppendASCII("Index"));
1691 GURL manifest_url = MockHttpServer::GetMockUrl("manifest");
1693 AppCacheDatabase::GroupRecord group_record;
1694 group_record.group_id = 1;
1695 group_record.manifest_url = manifest_url;
1696 group_record.origin = manifest_url.GetOrigin();
1697 EXPECT_TRUE(db.InsertGroup(&group_record));
1698 AppCacheDatabase::CacheRecord cache_record;
1699 cache_record.cache_id = 1;
1700 cache_record.group_id = 1;
1701 cache_record.online_wildcard = false;
1702 cache_record.update_time = kZeroTime;
1703 cache_record.cache_size = kDefaultEntrySize;
1704 EXPECT_TRUE(db.InsertCache(&cache_record));
1705 AppCacheDatabase::EntryRecord entry_record;
1706 entry_record.cache_id = 1;
1707 entry_record.url = manifest_url;
1708 entry_record.flags = AppCacheEntry::MANIFEST;
1709 entry_record.response_id = 1;
1710 entry_record.response_size = kDefaultEntrySize;
1711 EXPECT_TRUE(db.InsertEntry(&entry_record));
1714 // Recreate the service to point at the db and corruption on disk.
1715 service_.reset(new AppCacheServiceImpl(NULL));
1716 service_->set_request_context(io_thread->request_context());
1717 service_->Initialize(temp_directory_.path(),
1718 db_thread->task_runner(),
1719 db_thread->task_runner());
1720 mock_quota_manager_proxy_ = new MockQuotaManagerProxy();
1721 service_->quota_manager_proxy_ = mock_quota_manager_proxy_;
1722 delegate_.reset(new MockStorageDelegate(this));
1724 // Additional setup to observe reinitailize happens.
1725 observer_.reset(new MockServiceObserver(this));
1726 service_->AddObserver(observer_.get());
1728 // We continue after the init task is complete including the callback
1729 // on the current thread.
1730 FlushDbThreadTasks();
1731 base::ThreadTaskRunnerHandle::Get()->PostTask(
1732 FROM_HERE, base::Bind(&AppCacheStorageImplTest::Continue_Reinitialize,
1733 base::Unretained(this), test_case));
1736 void Continue_Reinitialize(ReinitTestCase test_case) {
1737 const int kMockProcessId = 1;
1738 backend_.reset(new AppCacheBackendImpl);
1739 backend_->Initialize(service_.get(), &frontend_, kMockProcessId);
1741 if (test_case == CORRUPT_SQL_ON_INSTALL) {
1742 // Break the db file
1743 EXPECT_FALSE(database()->was_corruption_detected());
1744 ASSERT_TRUE(sql::test::CorruptSizeInHeader(
1745 temp_directory_.path().AppendASCII("Index")));
1748 if (test_case == CORRUPT_CACHE_ON_INSTALL ||
1749 test_case == CORRUPT_SQL_ON_INSTALL) {
1750 // Try to create a new appcache, the resulting update job will
1751 // eventually fail when it gets to disk cache initialization.
1752 backend_->RegisterHost(1);
1753 AppCacheHost* host1 = backend_->GetHost(1);
1754 const GURL kEmptyPageUrl(MockHttpServer::GetMockUrl("empty.html"));
1755 host1->first_party_url_ = kEmptyPageUrl;
1756 host1->SelectCache(kEmptyPageUrl,
1757 kAppCacheNoCacheId,
1758 MockHttpServer::GetMockUrl("manifest"));
1759 } else {
1760 ASSERT_EQ(CORRUPT_CACHE_ON_LOAD_EXISTING, test_case);
1761 // Try to access the existing cache manifest.
1762 // The URLRequestJob will eventually fail when it gets to disk
1763 // cache initialization.
1764 backend_->RegisterHost(2);
1765 AppCacheHost* host2 = backend_->GetHost(2);
1766 GURL manifest_url = MockHttpServer::GetMockUrl("manifest");
1767 request_ = service()->request_context()->CreateRequest(
1768 manifest_url, net::DEFAULT_PRIORITY, NULL);
1769 AppCacheInterceptor::SetExtraRequestInfo(
1770 request_.get(), service_.get(),
1771 backend_->process_id(), host2->host_id(),
1772 RESOURCE_TYPE_MAIN_FRAME,
1773 false);
1774 request_->Start();
1777 PushNextTask(base::Bind(
1778 &AppCacheStorageImplTest::Verify_Reinitialized,
1779 base::Unretained(this),
1780 test_case));
1783 void Verify_Reinitialized(ReinitTestCase test_case) {
1784 // Verify we got notified of reinit and a new storage instance is created,
1785 // and that the old data has been deleted.
1786 EXPECT_TRUE(observer_->observed_old_storage_.get());
1787 EXPECT_TRUE(observer_->observed_old_storage_->storage() != storage());
1788 EXPECT_FALSE(PathExists(
1789 temp_directory_.path().AppendASCII("Cache").AppendASCII("index")));
1790 EXPECT_FALSE(PathExists(
1791 temp_directory_.path().AppendASCII("Index")));
1793 if (test_case == CORRUPT_SQL_ON_INSTALL) {
1794 AppCacheStorageImpl* storage = static_cast<AppCacheStorageImpl*>(
1795 observer_->observed_old_storage_->storage());
1796 EXPECT_TRUE(storage->database_->was_corruption_detected());
1799 // Verify that the hosts saw appropriate events.
1800 if (test_case == CORRUPT_CACHE_ON_INSTALL ||
1801 test_case == CORRUPT_SQL_ON_INSTALL) {
1802 EXPECT_TRUE(frontend_.error_event_was_raised_);
1803 AppCacheHost* host1 = backend_->GetHost(1);
1804 EXPECT_FALSE(host1->associated_cache());
1805 EXPECT_FALSE(host1->group_being_updated_.get());
1806 EXPECT_TRUE(host1->disabled_storage_reference_.get());
1807 } else {
1808 ASSERT_EQ(CORRUPT_CACHE_ON_LOAD_EXISTING, test_case);
1809 AppCacheHost* host2 = backend_->GetHost(2);
1810 EXPECT_EQ(1, host2->main_resource_cache_->cache_id());
1811 EXPECT_TRUE(host2->disabled_storage_reference_.get());
1814 // Cleanup and claim victory.
1815 service_->RemoveObserver(observer_.get());
1816 request_.reset();
1817 backend_.reset();
1818 observer_.reset();
1819 TestFinished();
1822 // Test case helpers --------------------------------------------------
1824 AppCacheServiceImpl* service() {
1825 return service_.get();
1828 AppCacheStorageImpl* storage() {
1829 return static_cast<AppCacheStorageImpl*>(service()->storage());
1832 AppCacheDatabase* database() {
1833 return storage()->database_;
1836 MockStorageDelegate* delegate() {
1837 return delegate_.get();
1840 void MakeCacheAndGroup(
1841 const GURL& manifest_url, int64 group_id, int64 cache_id,
1842 bool add_to_database) {
1843 AppCacheEntry default_entry(
1844 AppCacheEntry::EXPLICIT, cache_id + kDefaultEntryIdOffset,
1845 kDefaultEntrySize);
1846 group_ = new AppCacheGroup(storage(), manifest_url, group_id);
1847 cache_ = new AppCache(storage(), cache_id);
1848 cache_->AddEntry(kDefaultEntryUrl, default_entry);
1849 cache_->set_complete(true);
1850 group_->AddCache(cache_.get());
1851 if (add_to_database) {
1852 AppCacheDatabase::GroupRecord group_record;
1853 group_record.group_id = group_id;
1854 group_record.manifest_url = manifest_url;
1855 group_record.origin = manifest_url.GetOrigin();
1856 EXPECT_TRUE(database()->InsertGroup(&group_record));
1857 AppCacheDatabase::CacheRecord cache_record;
1858 cache_record.cache_id = cache_id;
1859 cache_record.group_id = group_id;
1860 cache_record.online_wildcard = false;
1861 cache_record.update_time = kZeroTime;
1862 cache_record.cache_size = kDefaultEntrySize;
1863 EXPECT_TRUE(database()->InsertCache(&cache_record));
1864 AppCacheDatabase::EntryRecord entry_record;
1865 entry_record.cache_id = cache_id;
1866 entry_record.url = kDefaultEntryUrl;
1867 entry_record.flags = default_entry.types();
1868 entry_record.response_id = default_entry.response_id();
1869 entry_record.response_size = default_entry.response_size();
1870 EXPECT_TRUE(database()->InsertEntry(&entry_record));
1872 storage()->usage_map_[manifest_url.GetOrigin()] =
1873 default_entry.response_size();
1877 // Data members --------------------------------------------------
1879 scoped_ptr<base::WaitableEvent> test_finished_event_;
1880 std::stack<base::Closure> task_stack_;
1881 scoped_ptr<AppCacheServiceImpl> service_;
1882 scoped_ptr<MockStorageDelegate> delegate_;
1883 scoped_refptr<MockQuotaManagerProxy> mock_quota_manager_proxy_;
1884 scoped_refptr<AppCacheGroup> group_;
1885 scoped_refptr<AppCache> cache_;
1886 scoped_refptr<AppCache> cache2_;
1888 // Specifically for the Reinitalize test.
1889 base::ScopedTempDir temp_directory_;
1890 scoped_ptr<MockServiceObserver> observer_;
1891 MockAppCacheFrontend frontend_;
1892 scoped_ptr<AppCacheBackendImpl> backend_;
1893 scoped_ptr<net::URLRequest> request_;
1897 TEST_F(AppCacheStorageImplTest, LoadCache_Miss) {
1898 RunTestOnIOThread(&AppCacheStorageImplTest::LoadCache_Miss);
1901 TEST_F(AppCacheStorageImplTest, LoadCache_NearHit) {
1902 RunTestOnIOThread(&AppCacheStorageImplTest::LoadCache_NearHit);
1905 TEST_F(AppCacheStorageImplTest, CreateGroupInEmptyOrigin) {
1906 RunTestOnIOThread(&AppCacheStorageImplTest::CreateGroupInEmptyOrigin);
1909 TEST_F(AppCacheStorageImplTest, CreateGroupInPopulatedOrigin) {
1910 RunTestOnIOThread(&AppCacheStorageImplTest::CreateGroupInPopulatedOrigin);
1913 TEST_F(AppCacheStorageImplTest, LoadGroupAndCache_FarHit) {
1914 RunTestOnIOThread(&AppCacheStorageImplTest::LoadGroupAndCache_FarHit);
1917 TEST_F(AppCacheStorageImplTest, StoreNewGroup) {
1918 RunTestOnIOThread(&AppCacheStorageImplTest::StoreNewGroup);
1921 TEST_F(AppCacheStorageImplTest, StoreExistingGroup) {
1922 RunTestOnIOThread(&AppCacheStorageImplTest::StoreExistingGroup);
1925 TEST_F(AppCacheStorageImplTest, StoreExistingGroupExistingCache) {
1926 RunTestOnIOThread(&AppCacheStorageImplTest::StoreExistingGroupExistingCache);
1929 TEST_F(AppCacheStorageImplTest, FailStoreGroup) {
1930 RunTestOnIOThread(&AppCacheStorageImplTest::FailStoreGroup);
1933 TEST_F(AppCacheStorageImplTest, MakeGroupObsolete) {
1934 RunTestOnIOThread(&AppCacheStorageImplTest::MakeGroupObsolete);
1937 TEST_F(AppCacheStorageImplTest, MarkEntryAsForeign) {
1938 RunTestOnIOThread(&AppCacheStorageImplTest::MarkEntryAsForeign);
1941 TEST_F(AppCacheStorageImplTest, MarkEntryAsForeignWithLoadInProgress) {
1942 RunTestOnIOThread(
1943 &AppCacheStorageImplTest::MarkEntryAsForeignWithLoadInProgress);
1946 TEST_F(AppCacheStorageImplTest, FindNoMainResponse) {
1947 RunTestOnIOThread(&AppCacheStorageImplTest::FindNoMainResponse);
1950 TEST_F(AppCacheStorageImplTest, BasicFindMainResponseInDatabase) {
1951 RunTestOnIOThread(
1952 &AppCacheStorageImplTest::BasicFindMainResponseInDatabase);
1955 TEST_F(AppCacheStorageImplTest, BasicFindMainResponseInWorkingSet) {
1956 RunTestOnIOThread(
1957 &AppCacheStorageImplTest::BasicFindMainResponseInWorkingSet);
1960 TEST_F(AppCacheStorageImplTest, BasicFindMainFallbackResponseInDatabase) {
1961 RunTestOnIOThread(
1962 &AppCacheStorageImplTest::BasicFindMainFallbackResponseInDatabase);
1965 TEST_F(AppCacheStorageImplTest, BasicFindMainFallbackResponseInWorkingSet) {
1966 RunTestOnIOThread(
1967 &AppCacheStorageImplTest::BasicFindMainFallbackResponseInWorkingSet);
1970 TEST_F(AppCacheStorageImplTest, BasicFindMainInterceptResponseInDatabase) {
1971 RunTestOnIOThread(
1972 &AppCacheStorageImplTest::BasicFindMainInterceptResponseInDatabase);
1975 TEST_F(AppCacheStorageImplTest, BasicFindMainInterceptResponseInWorkingSet) {
1976 RunTestOnIOThread(
1977 &AppCacheStorageImplTest::BasicFindMainInterceptResponseInWorkingSet);
1980 TEST_F(AppCacheStorageImplTest, FindMainResponseWithMultipleHits) {
1981 RunTestOnIOThread(
1982 &AppCacheStorageImplTest::FindMainResponseWithMultipleHits);
1985 TEST_F(AppCacheStorageImplTest, FindMainResponseExclusionsInDatabase) {
1986 RunTestOnIOThread(
1987 &AppCacheStorageImplTest::FindMainResponseExclusionsInDatabase);
1990 TEST_F(AppCacheStorageImplTest, FindMainResponseExclusionsInWorkingSet) {
1991 RunTestOnIOThread(
1992 &AppCacheStorageImplTest::FindMainResponseExclusionsInWorkingSet);
1995 TEST_F(AppCacheStorageImplTest, FindInterceptPatternMatchInWorkingSet) {
1996 RunTestOnIOThread(
1997 &AppCacheStorageImplTest::FindInterceptPatternMatchInWorkingSet);
2000 TEST_F(AppCacheStorageImplTest, FindInterceptPatternMatchInDatabase) {
2001 RunTestOnIOThread(
2002 &AppCacheStorageImplTest::FindInterceptPatternMatchInDatabase);
2005 TEST_F(AppCacheStorageImplTest, FindFallbackPatternMatchInWorkingSet) {
2006 RunTestOnIOThread(
2007 &AppCacheStorageImplTest::FindFallbackPatternMatchInWorkingSet);
2010 TEST_F(AppCacheStorageImplTest, FindFallbackPatternMatchInDatabase) {
2011 RunTestOnIOThread(
2012 &AppCacheStorageImplTest::FindFallbackPatternMatchInDatabase);
2015 TEST_F(AppCacheStorageImplTest, Reinitialize1) {
2016 RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize1);
2019 TEST_F(AppCacheStorageImplTest, Reinitialize2) {
2020 RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize2);
2023 TEST_F(AppCacheStorageImplTest, Reinitialize3) {
2024 RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize3);
2027 // That's all folks!
2029 } // namespace content